Update LUFA core to be compatible with the AVR-GCC -Wswitch-default warning switch.
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Common / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2012.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2012 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 disclaim 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 case HID_RI_POP(0):
100 if (CurrStateTable == &StateTable[0])
101 return HID_PARSE_HIDStackUnderflow;
102
103 CurrStateTable--;
104 break;
105 case HID_RI_USAGE_PAGE(0):
106 if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
107 CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
108
109 CurrStateTable->Attributes.Usage.Page = ReportItemData;
110 break;
111 case HID_RI_LOGICAL_MINIMUM(0):
112 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
113 break;
114 case HID_RI_LOGICAL_MAXIMUM(0):
115 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
116 break;
117 case HID_RI_PHYSICAL_MINIMUM(0):
118 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
119 break;
120 case HID_RI_PHYSICAL_MAXIMUM(0):
121 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
122 break;
123 case HID_RI_UNIT_EXPONENT(0):
124 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
125 break;
126 case HID_RI_UNIT(0):
127 CurrStateTable->Attributes.Unit.Type = ReportItemData;
128 break;
129 case HID_RI_REPORT_SIZE(0):
130 CurrStateTable->Attributes.BitSize = ReportItemData;
131 break;
132 case HID_RI_REPORT_COUNT(0):
133 CurrStateTable->ReportCount = ReportItemData;
134 break;
135 case HID_RI_REPORT_ID(0):
136 CurrStateTable->ReportID = ReportItemData;
137
138 if (ParserData->UsingReportIDs)
139 {
140 CurrReportIDInfo = NULL;
141
142 for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
143 {
144 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
145 {
146 CurrReportIDInfo = &ParserData->ReportIDSizes[i];
147 break;
148 }
149 }
150
151 if (CurrReportIDInfo == NULL)
152 {
153 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
154 return HID_PARSE_InsufficientReportIDItems;
155
156 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
157 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
158 }
159 }
160
161 ParserData->UsingReportIDs = true;
162
163 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
164 break;
165 case HID_RI_USAGE(0):
166 if (UsageListSize == HID_USAGE_STACK_DEPTH)
167 return HID_PARSE_UsageListOverflow;
168
169 UsageList[UsageListSize++] = ReportItemData;
170 break;
171 case HID_RI_USAGE_MINIMUM(0):
172 UsageMinMax.Minimum = ReportItemData;
173 break;
174 case HID_RI_USAGE_MAXIMUM(0):
175 UsageMinMax.Maximum = ReportItemData;
176 break;
177 case HID_RI_COLLECTION(0):
178 if (CurrCollectionPath == NULL)
179 {
180 CurrCollectionPath = &ParserData->CollectionPaths[0];
181 }
182 else
183 {
184 HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
185
186 CurrCollectionPath = &ParserData->CollectionPaths[1];
187
188 while (CurrCollectionPath->Parent != NULL)
189 {
190 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
191 return HID_PARSE_InsufficientCollectionPaths;
192
193 CurrCollectionPath++;
194 }
195
196 CurrCollectionPath->Parent = ParentCollectionPath;
197 }
198
199 CurrCollectionPath->Type = ReportItemData;
200 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
201
202 if (UsageListSize)
203 {
204 CurrCollectionPath->Usage.Usage = UsageList[0];
205
206 for (uint8_t i = 0; i < UsageListSize; i++)
207 UsageList[i] = UsageList[i + 1];
208
209 UsageListSize--;
210 }
211 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
212 {
213 CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
214 }
215
216 break;
217 case HID_RI_END_COLLECTION(0):
218 if (CurrCollectionPath == NULL)
219 return HID_PARSE_UnexpectedEndCollection;
220
221 CurrCollectionPath = CurrCollectionPath->Parent;
222 break;
223 case HID_RI_INPUT(0):
224 case HID_RI_OUTPUT(0):
225 case HID_RI_FEATURE(0):
226 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
227 {
228 HID_ReportItem_t NewReportItem;
229
230 memcpy(&NewReportItem.Attributes,
231 &CurrStateTable->Attributes,
232 sizeof(HID_ReportItem_Attributes_t));
233
234 NewReportItem.ItemFlags = ReportItemData;
235 NewReportItem.CollectionPath = CurrCollectionPath;
236 NewReportItem.ReportID = CurrStateTable->ReportID;
237
238 if (UsageListSize)
239 {
240 NewReportItem.Attributes.Usage.Usage = UsageList[0];
241
242 for (uint8_t i = 0; i < UsageListSize; i++)
243 UsageList[i] = UsageList[i + 1];
244
245 UsageListSize--;
246 }
247 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
248 {
249 NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
250 }
251
252 uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
253
254 if (ItemTypeTag == HID_RI_INPUT(0))
255 NewReportItem.ItemType = HID_REPORT_ITEM_In;
256 else if (ItemTypeTag == HID_RI_OUTPUT(0))
257 NewReportItem.ItemType = HID_REPORT_ITEM_Out;
258 else
259 NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
260
261 NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
262
263 CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
264
265 ParserData->LargestReportSizeBits = MAX(ParserData->LargestReportSizeBits, CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]);
266
267 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
268 return HID_PARSE_InsufficientReportItems;
269
270 memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
271 &NewReportItem, sizeof(HID_ReportItem_t));
272
273 if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
274 ParserData->TotalReportItems++;
275 }
276
277 break;
278
279 default:
280 break;
281 }
282
283 if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
284 {
285 UsageMinMax.Minimum = 0;
286 UsageMinMax.Maximum = 0;
287 UsageListSize = 0;
288 }
289 }
290
291 if (!(ParserData->TotalReportItems))
292 return HID_PARSE_NoUnfilteredReportItems;
293
294 return HID_PARSE_Successful;
295 }
296
297 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
298 HID_ReportItem_t* const ReportItem)
299 {
300 if (ReportItem == NULL)
301 return false;
302
303 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
304 uint16_t CurrentBit = ReportItem->BitOffset;
305 uint32_t BitMask = (1 << 0);
306
307 if (ReportItem->ReportID)
308 {
309 if (ReportItem->ReportID != ReportData[0])
310 return false;
311
312 ReportData++;
313 }
314
315 ReportItem->PreviousValue = ReportItem->Value;
316 ReportItem->Value = 0;
317
318 while (DataBitsRem--)
319 {
320 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
321 ReportItem->Value |= BitMask;
322
323 CurrentBit++;
324 BitMask <<= 1;
325 }
326
327 return true;
328 }
329
330 void USB_SetHIDReportItemInfo(uint8_t* ReportData,
331 HID_ReportItem_t* const ReportItem)
332 {
333 if (ReportItem == NULL)
334 return;
335
336 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
337 uint16_t CurrentBit = ReportItem->BitOffset;
338 uint32_t BitMask = (1 << 0);
339
340 if (ReportItem->ReportID)
341 {
342 ReportData[0] = ReportItem->ReportID;
343 ReportData++;
344 }
345
346 ReportItem->PreviousValue = ReportItem->Value;
347
348 while (DataBitsRem--)
349 {
350 if (ReportItem->Value & (1 << (CurrentBit % 8)))
351 ReportData[CurrentBit / 8] |= BitMask;
352
353 CurrentBit++;
354 BitMask <<= 1;
355 }
356 }
357
358 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
359 const uint8_t ReportID,
360 const uint8_t ReportType)
361 {
362 for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
363 {
364 uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
365
366 if (ParserData->ReportIDSizes[i].ReportID == ReportID)
367 return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0);
368 }
369
370 return 0;
371 }
372