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