66646baff0eb03ab293ddfaa21e9526f93e3081c
[pub/lufa.git] / LUFA / Drivers / USB / Class / Common / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2020.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2020 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all 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 disclaims 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 #define __INCLUDE_FROM_USB_DRIVER
32 #define __INCLUDE_FROM_HID_DRIVER
33 #include "HIDParser.h"
34
35 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,
36 uint16_t ReportSize,
37 HID_ReportInfo_t* const ParserData)
38 {
39 HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH];
40 HID_StateTable_t* CurrStateTable = &StateTable[0];
41 HID_CollectionPath_t* CurrCollectionPath = NULL;
42 HID_ReportSizeInfo_t* CurrReportIDInfo = &ParserData->ReportIDSizes[0];
43 uint16_t UsageList[HID_USAGE_STACK_DEPTH];
44 uint8_t UsageListSize = 0;
45 HID_MinMax_t UsageMinMax = {0, 0};
46
47 memset(ParserData, 0x00, sizeof(HID_ReportInfo_t));
48 memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t));
49 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
50
51 ParserData->TotalDeviceReports = 1;
52
53 while (ReportSize)
54 {
55 uint8_t HIDReportItem = *ReportData;
56 uint32_t ReportItemData;
57
58 ReportData++;
59 ReportSize--;
60
61 switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)
62 {
63 case HID_RI_DATA_BITS_32:
64 ReportItemData = (((uint32_t)ReportData[3] << 24) | ((uint32_t)ReportData[2] << 16) |
65 ((uint16_t)ReportData[1] << 8) | ReportData[0]);
66 ReportSize -= 4;
67 ReportData += 4;
68 break;
69
70 case HID_RI_DATA_BITS_16:
71 ReportItemData = (((uint16_t)ReportData[1] << 8) | (ReportData[0]));
72 ReportSize -= 2;
73 ReportData += 2;
74 break;
75
76 case HID_RI_DATA_BITS_8:
77 ReportItemData = ReportData[0];
78 ReportSize -= 1;
79 ReportData += 1;
80 break;
81
82 default:
83 ReportItemData = 0;
84 break;
85 }
86
87 switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))
88 {
89 case HID_RI_PUSH(0):
90 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
91 return HID_PARSE_HIDStackOverflow;
92
93 memcpy((CurrStateTable + 1),
94 CurrStateTable,
95 sizeof(HID_StateTable_t));
96
97 CurrStateTable++;
98 break;
99
100 case HID_RI_POP(0):
101 if (CurrStateTable == &StateTable[0])
102 return HID_PARSE_HIDStackUnderflow;
103
104 CurrStateTable--;
105 break;
106
107 case HID_RI_USAGE_PAGE(0):
108 CurrStateTable->Attributes.Usage.Page = ReportItemData;
109 break;
110
111 case HID_RI_LOGICAL_MINIMUM(0):
112 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
113 break;
114
115 case HID_RI_LOGICAL_MAXIMUM(0):
116 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
117 break;
118
119 case HID_RI_PHYSICAL_MINIMUM(0):
120 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
121 break;
122
123 case HID_RI_PHYSICAL_MAXIMUM(0):
124 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
125 break;
126
127 case HID_RI_UNIT_EXPONENT(0):
128 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
129 break;
130
131 case HID_RI_UNIT(0):
132 CurrStateTable->Attributes.Unit.Type = ReportItemData;
133 break;
134
135 case HID_RI_REPORT_SIZE(0):
136 CurrStateTable->Attributes.BitSize = ReportItemData;
137 break;
138
139 case HID_RI_REPORT_COUNT(0):
140 CurrStateTable->ReportCount = ReportItemData;
141 break;
142
143 case HID_RI_REPORT_ID(0):
144 CurrStateTable->ReportID = ReportItemData;
145
146 if (ParserData->UsingReportIDs)
147 {
148 CurrReportIDInfo = NULL;
149
150 for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
151 {
152 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
153 {
154 CurrReportIDInfo = &ParserData->ReportIDSizes[i];
155 break;
156 }
157 }
158
159 if (CurrReportIDInfo == NULL)
160 {
161 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
162 return HID_PARSE_InsufficientReportIDItems;
163
164 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
165 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
166 }
167 }
168
169 ParserData->UsingReportIDs = true;
170
171 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
172 break;
173
174 case HID_RI_USAGE(0):
175 if (UsageListSize == HID_USAGE_STACK_DEPTH)
176 return HID_PARSE_UsageListOverflow;
177
178 if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
179 CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
180
181 UsageList[UsageListSize++] = ReportItemData;
182 break;
183
184 case HID_RI_USAGE_MINIMUM(0):
185 UsageMinMax.Minimum = ReportItemData;
186 break;
187
188 case HID_RI_USAGE_MAXIMUM(0):
189 UsageMinMax.Maximum = ReportItemData;
190 break;
191
192 case HID_RI_COLLECTION(0):
193 if (CurrCollectionPath == NULL)
194 {
195 CurrCollectionPath = &ParserData->CollectionPaths[0];
196 }
197 else
198 {
199 HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
200
201 CurrCollectionPath = &ParserData->CollectionPaths[1];
202
203 while (CurrCollectionPath->Parent != NULL)
204 {
205 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
206 return HID_PARSE_InsufficientCollectionPaths;
207
208 CurrCollectionPath++;
209 }
210
211 CurrCollectionPath->Parent = ParentCollectionPath;
212 }
213
214 CurrCollectionPath->Type = ReportItemData;
215 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
216
217 if (UsageListSize)
218 {
219 CurrCollectionPath->Usage.Usage = UsageList[0];
220
221 for (uint8_t i = 1; i < UsageListSize; i++)
222 UsageList[i - 1] = UsageList[i];
223
224 UsageListSize--;
225 }
226 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
227 {
228 CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
229 }
230
231 break;
232
233 case HID_RI_END_COLLECTION(0):
234 if (CurrCollectionPath == NULL)
235 return HID_PARSE_UnexpectedEndCollection;
236
237 CurrCollectionPath = CurrCollectionPath->Parent;
238 break;
239
240 case HID_RI_INPUT(0):
241 case HID_RI_OUTPUT(0):
242 case HID_RI_FEATURE(0):
243 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
244 {
245 HID_ReportItem_t NewReportItem;
246
247 memcpy(&NewReportItem.Attributes,
248 &CurrStateTable->Attributes,
249 sizeof(HID_ReportItem_Attributes_t));
250
251 NewReportItem.ItemFlags = ReportItemData;
252 NewReportItem.CollectionPath = CurrCollectionPath;
253 NewReportItem.ReportID = CurrStateTable->ReportID;
254
255 if (UsageListSize)
256 {
257 NewReportItem.Attributes.Usage.Usage = UsageList[0];
258
259 for (uint8_t i = 1; i < UsageListSize; i++)
260 UsageList[i - 1] = UsageList[i];
261
262 UsageListSize--;
263 }
264 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
265 {
266 NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
267 }
268
269 uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
270
271 if (ItemTypeTag == HID_RI_INPUT(0))
272 NewReportItem.ItemType = HID_REPORT_ITEM_In;
273 else if (ItemTypeTag == HID_RI_OUTPUT(0))
274 NewReportItem.ItemType = HID_REPORT_ITEM_Out;
275 else
276 NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
277
278 NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
279
280 CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
281
282 ParserData->LargestReportSizeBits = MAX(ParserData->LargestReportSizeBits, CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]);
283
284 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
285 return HID_PARSE_InsufficientReportItems;
286
287 memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
288 &NewReportItem, sizeof(HID_ReportItem_t));
289
290 if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
291 ParserData->TotalReportItems++;
292 }
293
294 break;
295
296 default:
297 break;
298 }
299
300 if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
301 {
302 UsageMinMax.Minimum = 0;
303 UsageMinMax.Maximum = 0;
304 UsageListSize = 0;
305 }
306 }
307
308 if (!(ParserData->TotalReportItems))
309 return HID_PARSE_NoUnfilteredReportItems;
310
311 return HID_PARSE_Successful;
312 }
313
314 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
315 HID_ReportItem_t* const ReportItem)
316 {
317 if (ReportItem == NULL)
318 return false;
319
320 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
321 uint16_t CurrentBit = ReportItem->BitOffset;
322 uint32_t BitMask = (1 << 0);
323
324 if (ReportItem->ReportID)
325 {
326 if (ReportItem->ReportID != ReportData[0])
327 return false;
328
329 ReportData++;
330 }
331
332 ReportItem->PreviousValue = ReportItem->Value;
333 ReportItem->Value = 0;
334
335 while (DataBitsRem--)
336 {
337 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
338 ReportItem->Value |= BitMask;
339
340 CurrentBit++;
341 BitMask <<= 1;
342 }
343
344 return true;
345 }
346
347 void USB_SetHIDReportItemInfo(uint8_t* ReportData,
348 HID_ReportItem_t* const ReportItem)
349 {
350 if (ReportItem == NULL)
351 return;
352
353 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
354 uint16_t CurrentBit = ReportItem->BitOffset;
355 uint32_t BitMask = (1 << 0);
356
357 if (ReportItem->ReportID)
358 {
359 ReportData[0] = ReportItem->ReportID;
360 ReportData++;
361 }
362
363 ReportItem->PreviousValue = ReportItem->Value;
364
365 while (DataBitsRem--)
366 {
367 if (ReportItem->Value & BitMask)
368 ReportData[CurrentBit / 8] |= (1 << (CurrentBit % 8));
369
370 CurrentBit++;
371 BitMask <<= 1;
372 }
373 }
374
375 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
376 const uint8_t ReportID,
377 const uint8_t ReportType)
378 {
379 for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
380 {
381 uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
382
383 if (ParserData->ReportIDSizes[i].ReportID == ReportID)
384 return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0);
385 }
386
387 return 0;
388 }
389