1/* 2 * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#ifndef USERLAND_HID 7#include "Driver.h" 8#else 9#include "UserlandHID.h" 10#endif 11 12#include "HIDReportItem.h" 13#include "HIDReport.h" 14 15#include <string.h> 16 17HIDReportItem::HIDReportItem(HIDReport *report, uint32 bitOffset, 18 uint8 bitLength, bool hasData, bool isArray, bool isRelative, 19 uint32 minimum, uint32 maximum, uint32 usage) 20 : fReport(report), 21 fByteOffset(bitOffset / 8), 22 fShift(bitOffset % 8), 23 fMask(~(0xffffffff << bitLength)), 24 fBitCount(bitLength), 25 fByteCount((fShift + fBitCount + 7) / 8), 26 fHasData(hasData), 27 fArray(isArray), 28 fRelative(isRelative), 29 fMinimum(minimum), 30 fMaximum(maximum), 31 fUsage(usage), 32 fData(0), 33 fValid(false) 34{ 35} 36 37 38uint16 39HIDReportItem::UsagePage() 40{ 41 usage_value value; 42 value.u.extended = fUsage; 43 return value.u.s.usage_page; 44} 45 46 47uint16 48HIDReportItem::UsageID() 49{ 50 usage_value value; 51 value.u.extended = fUsage; 52 return value.u.s.usage_id; 53} 54 55 56status_t 57HIDReportItem::Extract() 58{ 59 // The specs restrict items to span at most across 4 bytes, which means 60 // that we can always just byte-align, copy four bytes and then shift and 61 // mask as needed. 62 uint8 *report = fReport->CurrentReport(); 63 if (report == NULL) 64 return B_NO_INIT; 65 66 memcpy(&fData, report + fByteOffset, fByteCount); 67 fData >>= fShift; 68 fData &= fMask; 69 70 if (Signed()) { 71 // sign extend if needed. 72 if ((fData & ~(fMask >> 1)) != 0) 73 fData |= ~fMask; 74 75 fValid = (int32)fData >= (int32)fMinimum 76 && (int32)fData <= (int32)fMaximum; 77 } else 78 fValid = fData >= fMinimum && fData <= fMaximum; 79 80 return B_OK; 81} 82 83 84status_t 85HIDReportItem::Insert() 86{ 87 uint8 *report = fReport->CurrentReport(); 88 if (report == NULL) 89 return B_NO_INIT; 90 91 uint32 value; 92 memcpy(&value, report + fByteOffset, fByteCount); 93 value &= ~(fMask << fShift); 94 95 if (fValid) 96 value |= (fData & fMask) << fShift; 97 98 memcpy(report + fByteOffset, &value, fByteCount); 99 return B_OK; 100} 101 102 103status_t 104HIDReportItem::SetData(uint32 data) 105{ 106 fData = data; 107 108 if (Signed()) { 109 fValid = (int32)fData >= (int32)fMinimum 110 && (int32)fData <= (int32)fMaximum; 111 } else 112 fValid = fData >= fMinimum && fData <= fMaximum; 113 114 return fValid ? B_OK : B_BAD_VALUE; 115} 116 117 118uint32 119HIDReportItem::ScaledData(uint8 scaleToBits, bool toBeSigned) 120{ 121 uint32 source; 122 if (Signed() != toBeSigned) { 123 if (toBeSigned) 124 source = (uint32)((int32)fData - (fMaximum + 1) / 2) & fMask; 125 else 126 source = (uint32)((int32)fData - (int32)fMinimum); 127 } else 128 source = fData & fMask; 129 130 if (fBitCount == scaleToBits) 131 return source; 132 133 int8 shift; 134 uint32 result = 0; 135 do { 136 shift = scaleToBits - fBitCount; 137 if (shift > 0) { 138 result |= source << shift; 139 scaleToBits = shift; 140 } else 141 result |= source >> -shift; 142 143 } while (shift > 0); 144 145 return result; 146} 147 148 149uint32 150HIDReportItem::ScaledRangeData(uint32 minimum, uint32 maximum) 151{ 152 uint64 zeroBasedData; 153 if (Signed()) 154 zeroBasedData = (int32)fData - (int32)fMinimum; 155 else 156 zeroBasedData = fData - fMinimum; 157 158 return zeroBasedData * (maximum - minimum + 1) / (fMaximum - fMinimum + 1) 159 + minimum; 160} 161 162 163float 164HIDReportItem::ScaledFloatData() 165{ 166 if (Signed()) { 167 return (double)((int32)fData - (int32)fMinimum) 168 / (fMaximum - (int32)fMinimum); 169 } 170 171 return (double)(fData - fMinimum) / (fMaximum - fMinimum); 172} 173 174 175void 176HIDReportItem::PrintToStream(uint32 indentLevel) 177{ 178 char indent[indentLevel + 1]; 179 memset(indent, '\t', indentLevel); 180 indent[indentLevel] = 0; 181 182 TRACE_ALWAYS("%sHIDReportItem %p\n", indent, this); 183 TRACE_ALWAYS("%s\tbyte offset: %" B_PRIu32 "\n", indent, fByteOffset); 184 TRACE_ALWAYS("%s\tshift: %u\n", indent, fShift); 185 TRACE_ALWAYS("%s\tmask: 0x%08" B_PRIx32 "\n", indent, fMask); 186 TRACE_ALWAYS("%s\thas data: %s\n", indent, fHasData ? "yes" : "no"); 187 TRACE_ALWAYS("%s\tarray: %s\n", indent, fArray ? "yes" : "no"); 188 TRACE_ALWAYS("%s\trelative: %s\n", indent, fRelative ? "yes" : "no"); 189 TRACE_ALWAYS("%s\tminimum: %" B_PRIu32 "\n", indent, fMinimum); 190 TRACE_ALWAYS("%s\tmaximum: %" B_PRIu32 "\n", indent, fMaximum); 191 TRACE_ALWAYS("%s\tusage : 0x%08" B_PRIx32 "\n", indent, fUsage); 192 193} 194