]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/lufa/LUFA-git/LUFA/Drivers/USB/Class/Common/HIDParser.c
Merge commit 'f6d56675f9f981c5464f0ca7a1fbb0162154e8c5'
[tmk_keyboard.git] / tmk_core / protocol / lufa / LUFA-git / LUFA / Drivers / USB / Class / Common / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2014.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2014 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_ReportItem_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 if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
109 CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
110
111 CurrStateTable->Attributes.Usage.Page = ReportItemData;
112 break;
113
114 case HID_RI_LOGICAL_MINIMUM(0):
115 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
116 break;
117
118 case HID_RI_LOGICAL_MAXIMUM(0):
119 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
120 break;
121
122 case HID_RI_PHYSICAL_MINIMUM(0):
123 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
124 break;
125
126 case HID_RI_PHYSICAL_MAXIMUM(0):
127 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
128 break;
129
130 case HID_RI_UNIT_EXPONENT(0):
131 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
132 break;
133
134 case HID_RI_UNIT(0):
135 CurrStateTable->Attributes.Unit.Type = ReportItemData;
136 break;
137
138 case HID_RI_REPORT_SIZE(0):
139 CurrStateTable->Attributes.BitSize = ReportItemData;
140 break;
141
142 case HID_RI_REPORT_COUNT(0):
143 CurrStateTable->ReportCount = ReportItemData;
144 break;
145
146 case HID_RI_REPORT_ID(0):
147 CurrStateTable->ReportID = ReportItemData;
148
149 if (ParserData->UsingReportIDs)
150 {
151 CurrReportIDInfo = NULL;
152
153 for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
154 {
155 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
156 {
157 CurrReportIDInfo = &ParserData->ReportIDSizes[i];
158 break;
159 }
160 }
161
162 if (CurrReportIDInfo == NULL)
163 {
164 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
165 return HID_PARSE_InsufficientReportIDItems;
166
167 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
168 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
169 }
170 }
171
172 ParserData->UsingReportIDs = true;
173
174 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
175 break;
176
177 case HID_RI_USAGE(0):
178 if (UsageListSize == HID_USAGE_STACK_DEPTH)
179 return HID_PARSE_UsageListOverflow;
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 & (1 << (CurrentBit % 8)))
368 ReportData[CurrentBit / 8] |= BitMask;
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
Imprint / Impressum