/* * 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 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() { // The specs restrict items to span at most across 4 bytes, which means // that we can always just byte-align, copy four bytes and then shift and // mask as needed. uint8 *report = fReport->CurrentReport(); if (report == NULL) return B_NO_INIT; memcpy(&fData, report + fByteOffset, fByteCount); fData >>= fShift; fData &= fMask; if (Signed()) { // sign extend if needed. 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); }