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 17 HIDReportItem::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 38 uint16 39 HIDReportItem::UsagePage() 40 { 41 usage_value value; 42 value.u.extended = fUsage; 43 return value.u.s.usage_page; 44 } 45 46 47 uint16 48 HIDReportItem::UsageID() 49 { 50 usage_value value; 51 value.u.extended = fUsage; 52 return value.u.s.usage_id; 53 } 54 55 56 status_t 57 HIDReportItem::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 84 status_t 85 HIDReportItem::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 103 status_t 104 HIDReportItem::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 118 uint32 119 HIDReportItem::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 149 uint32 150 HIDReportItem::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 163 float 164 HIDReportItem::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 175 void 176 HIDReportItem::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