xref: /haiku/src/add-ons/kernel/drivers/input/hid_shared/HIDReportItem.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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