Changed HIDParser to only zero out important values in the Parsed HID Report Item...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #include "../../HighLevel/USBMode.h"
32 #if defined(USB_CAN_BE_HOST)
33
34 #include "HIDParser.h"
35
36 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData)
37 {
38 HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH];
39 HID_StateTable_t* CurrStateTable = &StateTable[0];
40 uint16_t UsageStack[HID_USAGE_STACK_DEPTH];
41 uint8_t UsageStackSize = 0;
42 uint16_t BitOffsetIn = 0;
43 uint16_t BitOffsetOut = 0;
44 #if defined(HID_ENABLE_FEATURE_PROCESSING)
45 uint16_t BitOffsetFeature = 0;
46 #endif
47 HID_CollectionPath_t* CurrCollectionPath = NULL;
48
49 ParserData->TotalReportItems = 0;
50 ParserData->UsingMultipleReports = false;
51
52 for (uint8_t CurrCollection = 0; CurrCollection < HID_MAX_COLLECTIONS; CurrCollection++)
53 ParserData->CollectionPaths[CurrCollection].Parent = NULL;
54
55 memset(&StateTable[0], 0x00, sizeof(HID_StateTable_t));
56
57 while (ReportSize)
58 {
59 uint8_t HIDReportItem = *ReportData;
60 uint32_t ReportItemData = 0;
61
62 ReportData++;
63 ReportSize--;
64
65 switch (HIDReportItem & DATA_SIZE_MASK)
66 {
67 case DATA_SIZE_4:
68 ReportItemData = *((uint32_t*)ReportData);
69 ReportSize -= 4;
70 ReportData += 4;
71 break;
72 case DATA_SIZE_2:
73 ReportItemData = *((uint16_t*)ReportData);
74 ReportSize -= 2;
75 ReportData += 2;
76 break;
77 case DATA_SIZE_1:
78 ReportItemData = *((uint8_t*)ReportData);
79 ReportSize -= 1;
80 ReportData += 1;
81 break;
82 }
83
84 switch (HIDReportItem & (TYPE_MASK | TAG_MASK))
85 {
86 case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
87 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
88 return HID_PARSE_HIDStackOverflow;
89
90 memcpy((CurrStateTable + 1),
91 CurrStateTable,
92 sizeof(HID_ReportItem_t));
93
94 CurrStateTable++;
95 break;
96 case (TYPE_GLOBAL | TAG_GLOBAL_POP):
97 if (CurrStateTable == &StateTable[0])
98 return HID_PARSE_HIDStackUnderflow;
99
100 CurrStateTable--;
101 break;
102 case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
103 CurrStateTable->Attributes.Usage.Page = ReportItemData;
104 break;
105 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
106 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
107 break;
108 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
109 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
110 break;
111 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
112 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
113 break;
114 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
115 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
116 break;
117 case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
118 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
119 break;
120 case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
121 CurrStateTable->Attributes.Unit.Type = ReportItemData;
122 break;
123 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
124 CurrStateTable->Attributes.BitSize = ReportItemData;
125 break;
126 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
127 CurrStateTable->ReportCount = ReportItemData;
128 break;
129 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
130 CurrStateTable->ReportID = ReportItemData;
131 ParserData->UsingMultipleReports = true;
132 BitOffsetIn = 0;
133 BitOffsetOut = 0;
134
135 #if defined(HID_ENABLE_FEATURE_PROCESSING)
136 BitOffsetFeature = 0;
137 #endif
138 break;
139 case (TYPE_LOCAL | TAG_LOCAL_USAGE):
140 if (UsageStackSize == HID_USAGE_STACK_DEPTH)
141 return HID_PARSE_UsageStackOverflow;
142
143 UsageStack[UsageStackSize++] = ReportItemData;
144 break;
145 case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
146 CurrStateTable->Attributes.Usage.MinMax.Minimum = ReportItemData;
147 break;
148 case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
149 CurrStateTable->Attributes.Usage.MinMax.Maximum = ReportItemData;
150 break;
151 case (TYPE_MAIN | TAG_MAIN_COLLECTION):
152 if (CurrCollectionPath == NULL)
153 {
154 CurrCollectionPath = &ParserData->CollectionPaths[0];
155 }
156 else
157 {
158 HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
159
160 CurrCollectionPath = &ParserData->CollectionPaths[1];
161
162 while (CurrCollectionPath->Parent != NULL);
163 {
164 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
165 return HID_PARSE_InsufficientCollectionPaths;
166
167 CurrCollectionPath++;
168 }
169
170 CurrCollectionPath->Parent = ParentCollectionPath;
171 }
172
173 CurrCollectionPath->Type = ReportItemData;
174 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
175
176 if (UsageStackSize)
177 {
178 CurrCollectionPath->Usage.Usage = UsageStack[0];
179
180 for (uint8_t i = 0; i < UsageStackSize; i++)
181 UsageStack[i] = UsageStack[i + 1];
182
183 UsageStackSize--;
184 }
185 else
186 {
187 CurrCollectionPath->Usage.Usage = 0;
188 }
189
190 break;
191 case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
192 if (CurrCollectionPath == NULL)
193 return HID_PARSE_UnexpectedEndCollection;
194
195 CurrCollectionPath = CurrCollectionPath->Parent;
196
197 break;
198 case (TYPE_MAIN | TAG_MAIN_INPUT):
199 case (TYPE_MAIN | TAG_MAIN_OUTPUT):
200 #if defined(HID_ENABLE_FEATURE_PROCESSING)
201 case (TYPE_MAIN | TAG_MAIN_FEATURE):
202 #endif
203 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
204 {
205 HID_ReportItem_t* CurrReportItem = &ParserData->ReportItems[ParserData->TotalReportItems];
206
207 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
208 return HID_PARSE_InsufficientReportItems;
209
210 memcpy(&CurrReportItem->Attributes,
211 &CurrStateTable->Attributes,
212 sizeof(HID_ReportItem_Attributes_t));
213
214 CurrReportItem->ItemFlags = ReportItemData;
215 CurrReportItem->CollectionPath = CurrCollectionPath;
216 CurrReportItem->ReportID = CurrStateTable->ReportID;
217
218 if (UsageStackSize)
219 {
220 CurrReportItem->Attributes.Usage.Usage = UsageStack[0];
221
222 for (uint8_t i = 0; i < UsageStackSize; i++)
223 UsageStack[i] = UsageStack[i + 1];
224
225 UsageStackSize--;
226 }
227 else
228 {
229 CurrReportItem->Attributes.Usage.Usage = 0;
230 }
231
232 switch (HIDReportItem & TAG_MASK)
233 {
234 case TAG_MAIN_INPUT:
235 CurrReportItem->ItemType = REPORT_ITEM_TYPE_In;
236 CurrReportItem->BitOffset = BitOffsetIn;
237
238 BitOffsetIn += CurrStateTable->Attributes.BitSize;
239
240 break;
241 case TAG_MAIN_OUTPUT:
242 CurrReportItem->ItemType = REPORT_ITEM_TYPE_Out;
243 CurrReportItem->BitOffset = BitOffsetOut;
244
245 BitOffsetOut += CurrStateTable->Attributes.BitSize;
246
247 break;
248 #if defined(HID_ENABLE_FEATURE_PROCESSING)
249 case TAG_MAIN_FEATURE:
250 CurrReportItem->ItemType = REPORT_ITEM_TYPE_Feature;
251 CurrReportItem->BitOffset = BitOffsetFeature;
252
253 BitOffsetFeature += CurrStateTable->Attributes.BitSize;
254
255 break;
256 #endif
257 }
258
259 #if defined(HID_INCLUDE_CONSTANT_DATA_ITEMS)
260 ParserData->TotalReportItems++;
261 #else
262 if (!(ReportItemData & IOF_CONSTANT))
263 ParserData->TotalReportItems++;
264 #endif
265 }
266
267 UsageStackSize = 0;
268
269 break;
270 }
271
272 if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)
273 {
274 CurrStateTable->Attributes.Usage.MinMax.Minimum = 0;
275 CurrStateTable->Attributes.Usage.MinMax.Maximum = 0;
276 UsageStackSize = 0;
277 }
278 }
279
280 return HID_PARSE_Successful;
281 }
282
283 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
284 {
285 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
286 uint16_t CurrentBit = ReportItem->BitOffset;
287 uint32_t BitMask = (1 << 0);
288
289 ReportItem->Value = 0;
290
291 if (ReportItem->ReportID)
292 {
293 if (ReportItem->ReportID != ReportData[0])
294 return false;
295
296 ReportData++;
297 }
298
299 while (DataBitsRem--)
300 {
301 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
302 ReportItem->Value |= BitMask;
303
304 CurrentBit++;
305 BitMask <<= 1;
306 }
307
308 return true;
309 }
310
311 void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* ReportItem)
312 {
313 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
314 uint16_t CurrentBit = ReportItem->BitOffset;
315 uint32_t BitMask = (1 << 0);
316
317 if (ReportItem->ReportID)
318 {
319 ReportData[0] = ReportItem->ReportID;
320 ReportData++;
321 }
322
323 while (DataBitsRem--)
324 {
325 if (ReportItem->Value & (1 << (CurrentBit % 8)))
326 ReportData[CurrentBit / 8] |= BitMask;
327
328 CurrentBit++;
329 BitMask <<= 1;
330 }
331 }
332
333 #endif