]> git.sur5r.net Git - freertos/blob
9414c08784c7da2740f058bbbcb0730e43f45476
[freertos] /
1 /*\r
2  * @brief USB Human Interface Device (HID) Class report descriptor parser\r
3  *\r
4  * @note\r
5  * Copyright(C) NXP Semiconductors, 2012\r
6  * Copyright(C) Dean Camera, 2011, 2012\r
7  * All rights reserved.\r
8  *\r
9  * @par\r
10  * Software that is described herein is for illustrative purposes only\r
11  * which provides customers with programming information regarding the\r
12  * LPC products.  This software is supplied "AS IS" without any warranties of\r
13  * any kind, and NXP Semiconductors and its licensor disclaim any and\r
14  * all warranties, express or implied, including all implied warranties of\r
15  * merchantability, fitness for a particular purpose and non-infringement of\r
16  * intellectual property rights.  NXP Semiconductors assumes no responsibility\r
17  * or liability for the use of the software, conveys no license or rights under any\r
18  * patent, copyright, mask work right, or any other intellectual property rights in\r
19  * or to any products. NXP Semiconductors reserves the right to make changes\r
20  * in the software without notification. NXP Semiconductors also makes no\r
21  * representation or warranty that such application will be suitable for the\r
22  * specified use without further testing or modification.\r
23  *\r
24  * @par\r
25  * Permission to use, copy, modify, and distribute this software and its\r
26  * documentation is hereby granted, under NXP Semiconductors' and its\r
27  * licensor's relevant copyrights in the software, without fee, provided that it\r
28  * is used in conjunction with NXP Semiconductors microcontrollers.  This\r
29  * copyright, permission, and disclaimer notice must appear in all copies of\r
30  * this code.\r
31  */\r
32 \r
33 \r
34 #define  __INCLUDE_FROM_USB_DRIVER\r
35 #define  __INCLUDE_FROM_HID_DRIVER\r
36 #include "HIDParser.h"\r
37 \r
38 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,\r
39                              uint16_t ReportSize,\r
40                              HID_ReportInfo_t* const ParserData)\r
41 {\r
42         HID_StateTable_t      StateTable[HID_STATETABLE_STACK_DEPTH];\r
43         HID_StateTable_t*     CurrStateTable          = &StateTable[0];\r
44         HID_CollectionPath_t* CurrCollectionPath      = NULL;\r
45         HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];\r
46         uint16_t              UsageList[HID_USAGE_STACK_DEPTH];\r
47         uint8_t               UsageListSize           = 0;\r
48         HID_MinMax_t          UsageMinMax             = {0, 0};\r
49 \r
50         memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));\r
51         memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));\r
52         memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));\r
53 \r
54         ParserData->TotalDeviceReports = 1;\r
55 \r
56         while (ReportSize)\r
57         {\r
58                 uint8_t  HIDReportItem  = *ReportData;\r
59                 uint32_t ReportItemData = 0;\r
60 \r
61                 ReportData++;\r
62                 ReportSize--;\r
63 \r
64                 switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)\r
65                 {\r
66                         case HID_RI_DATA_BITS_32:\r
67                                 ReportItemData  = le32_to_cpu(*((uint32_t*)ReportData));\r
68                                 ReportSize     -= 4;\r
69                                 ReportData     += 4;\r
70                                 break;\r
71                         case HID_RI_DATA_BITS_16:\r
72                                 ReportItemData  = le16_to_cpu(*((uint16_t*)ReportData));\r
73                                 ReportSize     -= 2;\r
74                                 ReportData     += 2;\r
75                                 break;\r
76                         case HID_RI_DATA_BITS_8:\r
77                                 ReportItemData  = *((uint8_t*)ReportData);\r
78                                 ReportSize     -= 1;\r
79                                 ReportData     += 1;\r
80                                 break;\r
81                 }\r
82 \r
83                 switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))\r
84                 {\r
85                         case HID_RI_PUSH(0):\r
86                                 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])\r
87                                   return HID_PARSE_HIDStackOverflow;\r
88 \r
89                                 memcpy((CurrStateTable + 1),\r
90                                        CurrStateTable,\r
91                                        sizeof(HID_ReportItem_t));\r
92 \r
93                                 CurrStateTable++;\r
94                                 break;\r
95                         case HID_RI_POP(0):\r
96                                 if (CurrStateTable == &StateTable[0])\r
97                                   return HID_PARSE_HIDStackUnderflow;\r
98 \r
99                                 CurrStateTable--;\r
100                                 break;\r
101                         case HID_RI_USAGE_PAGE(0):\r
102                                 if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)\r
103                                   CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);\r
104                                 \r
105                                 CurrStateTable->Attributes.Usage.Page       = ReportItemData;\r
106                                 break;\r
107                         case HID_RI_LOGICAL_MINIMUM(0):\r
108                                 CurrStateTable->Attributes.Logical.Minimum  = ReportItemData;\r
109                                 break;\r
110                         case HID_RI_LOGICAL_MAXIMUM(0):\r
111                                 CurrStateTable->Attributes.Logical.Maximum  = ReportItemData;\r
112                                 break;\r
113                         case HID_RI_PHYSICAL_MINIMUM(0):\r
114                                 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;\r
115                                 break;\r
116                         case HID_RI_PHYSICAL_MAXIMUM(0):\r
117                                 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;\r
118                                 break;\r
119                         case HID_RI_UNIT_EXPONENT(0):\r
120                                 CurrStateTable->Attributes.Unit.Exponent    = ReportItemData;\r
121                                 break;\r
122                         case HID_RI_UNIT(0):\r
123                                 CurrStateTable->Attributes.Unit.Type        = ReportItemData;\r
124                                 break;\r
125                         case HID_RI_REPORT_SIZE(0):\r
126                                 CurrStateTable->Attributes.BitSize          = ReportItemData;\r
127                                 break;\r
128                         case HID_RI_REPORT_COUNT(0):\r
129                                 CurrStateTable->ReportCount                 = ReportItemData;\r
130                                 break;\r
131                         case HID_RI_REPORT_ID(0):\r
132                                 CurrStateTable->ReportID                    = ReportItemData;\r
133 \r
134                                 if (ParserData->UsingReportIDs)\r
135                                 {\r
136                                         CurrReportIDInfo = NULL;\r
137 \r
138                                         for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)\r
139                                         {\r
140                                                 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)\r
141                                                 {\r
142                                                         CurrReportIDInfo = &ParserData->ReportIDSizes[i];\r
143                                                         break;\r
144                                                 }\r
145                                         }\r
146 \r
147                                         if (CurrReportIDInfo == NULL)\r
148                                         {\r
149                                                 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)\r
150                                                   return HID_PARSE_InsufficientReportIDItems;\r
151 \r
152                                                 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];\r
153                                                 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));\r
154                                         }\r
155                                 }\r
156 \r
157                                 ParserData->UsingReportIDs = true;\r
158 \r
159                                 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;\r
160                                 break;\r
161                         case HID_RI_USAGE(0):\r
162                                 if (UsageListSize == HID_USAGE_STACK_DEPTH)\r
163                                   return HID_PARSE_UsageListOverflow;\r
164 \r
165                                 UsageList[UsageListSize++] = ReportItemData;\r
166                                 break;\r
167                         case HID_RI_USAGE_MINIMUM(0):\r
168                                 UsageMinMax.Minimum = ReportItemData;\r
169                                 break;\r
170                         case HID_RI_USAGE_MAXIMUM(0):\r
171                                 UsageMinMax.Maximum = ReportItemData;\r
172                                 break;\r
173                         case HID_RI_COLLECTION(0):\r
174                                 if (CurrCollectionPath == NULL)\r
175                                 {\r
176                                         CurrCollectionPath = &ParserData->CollectionPaths[0];\r
177                                 }\r
178                                 else\r
179                                 {\r
180                                         HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;\r
181 \r
182                                         CurrCollectionPath = &ParserData->CollectionPaths[1];\r
183 \r
184                                         while (CurrCollectionPath->Parent != NULL)\r
185                                         {\r
186                                                 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])\r
187                                                   return HID_PARSE_InsufficientCollectionPaths;\r
188 \r
189                                                 CurrCollectionPath++;\r
190                                         }\r
191 \r
192                                         CurrCollectionPath->Parent = ParentCollectionPath;\r
193                                 }\r
194 \r
195                                 CurrCollectionPath->Type       = ReportItemData;\r
196                                 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;\r
197 \r
198                                 if (UsageListSize)\r
199                                 {\r
200                                         CurrCollectionPath->Usage.Usage = UsageList[0];\r
201 \r
202                                         for (uint8_t i = 0; i < UsageListSize; i++)\r
203                                           UsageList[i] = UsageList[i + 1];\r
204 \r
205                                         UsageListSize--;\r
206                                 }\r
207                                 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)\r
208                                 {\r
209                                         CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;\r
210                                 }\r
211 \r
212                                 break;\r
213                         case HID_RI_END_COLLECTION(0):\r
214                                 if (CurrCollectionPath == NULL)\r
215                                   return HID_PARSE_UnexpectedEndCollection;\r
216 \r
217                                 CurrCollectionPath = CurrCollectionPath->Parent;\r
218                                 break;\r
219                         case HID_RI_INPUT(0):\r
220                         case HID_RI_OUTPUT(0):\r
221                         case HID_RI_FEATURE(0):\r
222                                 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)\r
223                                 {\r
224                                         HID_ReportItem_t NewReportItem;\r
225 \r
226                                         memcpy(&NewReportItem.Attributes,\r
227                                                &CurrStateTable->Attributes,\r
228                                                sizeof(HID_ReportItem_Attributes_t));\r
229 \r
230                                         NewReportItem.ItemFlags      = ReportItemData;\r
231                                         NewReportItem.CollectionPath = CurrCollectionPath;\r
232                                         NewReportItem.ReportID       = CurrStateTable->ReportID;\r
233 \r
234                                         if (UsageListSize)\r
235                                         {\r
236                                                 NewReportItem.Attributes.Usage.Usage = UsageList[0];\r
237 \r
238                                                 for (uint8_t i = 0; i < UsageListSize; i++)\r
239                                                   UsageList[i] = UsageList[i + 1];\r
240 \r
241                                                 UsageListSize--;\r
242                                         }\r
243                                         else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)\r
244                                         {\r
245                                                 NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;\r
246                                         }\r
247 \r
248                                         uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));\r
249 \r
250                                         if (ItemTypeTag == HID_RI_INPUT(0))\r
251                                           NewReportItem.ItemType = HID_REPORT_ITEM_In;\r
252                                         else if (ItemTypeTag == HID_RI_OUTPUT(0))\r
253                                           NewReportItem.ItemType = HID_REPORT_ITEM_Out;\r
254                                         else\r
255                                           NewReportItem.ItemType = HID_REPORT_ITEM_Feature;\r
256 \r
257                                         NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];\r
258 \r
259                                         CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;\r
260 \r
261                                         if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)\r
262                                           ParserData->LargestReportSizeBits = NewReportItem.BitOffset;\r
263 \r
264                                         if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)\r
265                                           return HID_PARSE_InsufficientReportItems;\r
266 \r
267                                         memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],\r
268                                                &NewReportItem, sizeof(HID_ReportItem_t));\r
269 \r
270                                         if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))\r
271                                           ParserData->TotalReportItems++;\r
272                                 }\r
273 \r
274                                 break;\r
275                 }\r
276 \r
277                 if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)\r
278                 {\r
279                         UsageMinMax.Minimum = 0;\r
280                         UsageMinMax.Maximum = 0;\r
281                         UsageListSize       = 0;\r
282                 }\r
283         }\r
284 \r
285         if (!(ParserData->TotalReportItems))\r
286           return HID_PARSE_NoUnfilteredReportItems;\r
287 \r
288         return HID_PARSE_Successful;\r
289 }\r
290 \r
291 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,\r
292                               HID_ReportItem_t* const ReportItem)\r
293 {\r
294         if (ReportItem == NULL)\r
295           return false;\r
296 \r
297         uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;\r
298         uint16_t CurrentBit   = ReportItem->BitOffset;\r
299         uint32_t BitMask      = (1 << 0);\r
300 \r
301         if (ReportItem->ReportID)\r
302         {\r
303                 if (ReportItem->ReportID != ReportData[0])\r
304                   return false;\r
305 \r
306                 ReportData++;\r
307         }\r
308 \r
309         ReportItem->PreviousValue = ReportItem->Value;\r
310         ReportItem->Value = 0;\r
311 \r
312         while (DataBitsRem--)\r
313         {\r
314                 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))\r
315                   ReportItem->Value |= BitMask;\r
316 \r
317                 CurrentBit++;\r
318                 BitMask <<= 1;\r
319         }\r
320 \r
321         return true;\r
322 }\r
323 \r
324 void USB_SetHIDReportItemInfo(uint8_t* ReportData,\r
325                               HID_ReportItem_t* const ReportItem)\r
326 {\r
327         if (ReportItem == NULL)\r
328           return;\r
329 \r
330         uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;\r
331         uint16_t CurrentBit   = ReportItem->BitOffset;\r
332         uint32_t BitMask      = (1 << 0);\r
333 \r
334         if (ReportItem->ReportID)\r
335         {\r
336                 ReportData[0] = ReportItem->ReportID;\r
337                 ReportData++;\r
338         }\r
339 \r
340         ReportItem->PreviousValue = ReportItem->Value;\r
341 \r
342         while (DataBitsRem--)\r
343         {\r
344                 if (ReportItem->Value & (1 << (CurrentBit % 8)))\r
345                   ReportData[CurrentBit / 8] |= BitMask;\r
346 \r
347                 CurrentBit++;\r
348                 BitMask <<= 1;\r
349         }\r
350 }\r
351 \r
352 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,\r
353                               const uint8_t ReportID,\r
354                               const uint8_t ReportType)\r
355 {\r
356         for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)\r
357         {\r
358                 uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];\r
359 \r
360                 if (ParserData->ReportIDSizes[i].ReportID == ReportID)\r
361                   return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0);\r
362         }\r
363 \r
364         return 0;\r
365 }\r