* Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch.
* Distributed under the terms of the MIT License.
*/
#ifndef USERLAND_HID
#include "Driver.h"
#else
#include "UserlandHID.h"
#endif
#include "HIDReportItem.h"
#include "HIDReport.h"
#include <string.h>
HIDReportItem::HIDReportItem(HIDReport *report, uint32 bitOffset,
uint8 bitLength, bool hasData, bool isArray, bool isRelative,
uint32 minimum, uint32 maximum, uint32 usage)
: fReport(report),
fByteOffset(bitOffset / 8),
fShift(bitOffset % 8),
fMask(~(0xffffffff << bitLength)),
fBitCount(bitLength),
fByteCount((fShift + fBitCount + 7) / 8),
fHasData(hasData),
fArray(isArray),
fRelative(isRelative),
fMinimum(minimum),
fMaximum(maximum),
fUsage(usage),
fData(0),
fValid(false)
{
}
uint16
HIDReportItem::UsagePage()
{
usage_value value;
value.u.extended = fUsage;
return value.u.s.usage_page;
}
uint16
HIDReportItem::UsageID()
{
usage_value value;
value.u.extended = fUsage;
return value.u.s.usage_id;
}
status_t
HIDReportItem::Extract()
{
uint8 *report = fReport->CurrentReport();
if (report == NULL)
return B_NO_INIT;
memcpy(&fData, report + fByteOffset, fByteCount);
fData >>= fShift;
fData &= fMask;
if (Signed()) {
if ((fData & ~(fMask >> 1)) != 0)
fData |= ~fMask;
fValid = (int32)fData >= (int32)fMinimum
&& (int32)fData <= (int32)fMaximum;
} else
fValid = fData >= fMinimum && fData <= fMaximum;
return B_OK;
}
status_t
HIDReportItem::Insert()
{
uint8 *report = fReport->CurrentReport();
if (report == NULL)
return B_NO_INIT;
uint32 value;
memcpy(&value, report + fByteOffset, fByteCount);
value &= ~(fMask << fShift);
if (fValid)
value |= (fData & fMask) << fShift;
memcpy(report + fByteOffset, &value, fByteCount);
return B_OK;
}
status_t
HIDReportItem::SetData(uint32 data)
{
fData = data;
if (Signed()) {
fValid = (int32)fData >= (int32)fMinimum
&& (int32)fData <= (int32)fMaximum;
} else
fValid = fData >= fMinimum && fData <= fMaximum;
return fValid ? B_OK : B_BAD_VALUE;
}
uint32
HIDReportItem::ScaledData(uint8 scaleToBits, bool toBeSigned)
{
uint32 source;
if (Signed() != toBeSigned) {
if (toBeSigned)
source = (uint32)((int32)fData - (fMaximum + 1) / 2) & fMask;
else
source = (uint32)((int32)fData - (int32)fMinimum);
} else
source = fData & fMask;
if (fBitCount == scaleToBits)
return source;
int8 shift;
uint32 result = 0;
do {
shift = scaleToBits - fBitCount;
if (shift > 0) {
result |= source << shift;
scaleToBits = shift;
} else
result |= source >> -shift;
} while (shift > 0);
return result;
}
uint32
HIDReportItem::ScaledRangeData(uint32 minimum, uint32 maximum)
{
uint64 zeroBasedData;
if (Signed())
zeroBasedData = (int32)fData - (int32)fMinimum;
else
zeroBasedData = fData - fMinimum;
return zeroBasedData * (maximum - minimum + 1) / (fMaximum - fMinimum + 1)
+ minimum;
}
float
HIDReportItem::ScaledFloatData()
{
if (Signed()) {
return (double)((int32)fData - (int32)fMinimum)
/ (fMaximum - (int32)fMinimum);
}
return (double)(fData - fMinimum) / (fMaximum - fMinimum);
}
void
HIDReportItem::PrintToStream(uint32 indentLevel)
{
char indent[indentLevel + 1];
memset(indent, '\t', indentLevel);
indent[indentLevel] = 0;
TRACE_ALWAYS("%sHIDReportItem %p\n", indent, this);
TRACE_ALWAYS("%s\tbyte offset: %" B_PRIu32 "\n", indent, fByteOffset);
TRACE_ALWAYS("%s\tshift: %u\n", indent, fShift);
TRACE_ALWAYS("%s\tmask: 0x%08" B_PRIx32 "\n", indent, fMask);
TRACE_ALWAYS("%s\thas data: %s\n", indent, fHasData ? "yes" : "no");
TRACE_ALWAYS("%s\tarray: %s\n", indent, fArray ? "yes" : "no");
TRACE_ALWAYS("%s\trelative: %s\n", indent, fRelative ? "yes" : "no");
TRACE_ALWAYS("%s\tminimum: %" B_PRIu32 "\n", indent, fMinimum);
TRACE_ALWAYS("%s\tmaximum: %" B_PRIu32 "\n", indent, fMaximum);
TRACE_ALWAYS("%s\tusage : 0x%08" B_PRIx32 "\n", indent, fUsage);
}