]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/lufa/LUFA-git/LUFA/Drivers/USB/Class/Common/HIDParser.c
Merge commit '28203e909e83b1ac6becb45a3eadae23b190df32' into master-core-pull
[max/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