Minor documentation cleanups.
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2010 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 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
34
35 #include "HIDParser.h"
36
37 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, 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 = 0;
57
58 ReportData++;
59 ReportSize--;
60
61 switch (HIDReportItem & DATA_SIZE_MASK)
62 {
63 case DATA_SIZE_4:
64 ReportItemData = *((uint32_t*)ReportData);
65 ReportSize -= 4;
66 ReportData += 4;
67 break;
68 case DATA_SIZE_2:
69 ReportItemData = *((uint16_t*)ReportData);
70 ReportSize -= 2;
71 ReportData += 2;
72 break;
73 case DATA_SIZE_1:
74 ReportItemData = *((uint8_t*)ReportData);
75 ReportSize -= 1;
76 ReportData += 1;
77 break;
78 }
79
80 switch (HIDReportItem & (TYPE_MASK | TAG_MASK))
81 {
82 case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
83 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
84 return HID_PARSE_HIDStackOverflow;
85
86 memcpy((CurrStateTable + 1),
87 CurrStateTable,
88 sizeof(HID_ReportItem_t));
89
90 CurrStateTable++;
91 break;
92 case (TYPE_GLOBAL | TAG_GLOBAL_POP):
93 if (CurrStateTable == &StateTable[0])
94 return HID_PARSE_HIDStackUnderflow;
95
96 CurrStateTable--;
97 break;
98 case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
99 CurrStateTable->Attributes.Usage.Page = ReportItemData;
100 break;
101 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
102 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
103 break;
104 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
105 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
106 break;
107 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
108 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
109 break;
110 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
111 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
112 break;
113 case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
114 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
115 break;
116 case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
117 CurrStateTable->Attributes.Unit.Type = ReportItemData;
118 break;
119 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
120 CurrStateTable->Attributes.BitSize = ReportItemData;
121 break;
122 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
123 CurrStateTable->ReportCount = ReportItemData;
124 break;
125 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
126 CurrStateTable->ReportID = ReportItemData;
127
128 if (ParserData->UsingReportIDs)
129 {
130 CurrReportIDInfo = NULL;
131
132 for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
133 {
134 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
135 {
136 CurrReportIDInfo = &ParserData->ReportIDSizes[i];
137 break;
138 }
139 }
140
141 if (CurrReportIDInfo == NULL)
142 {
143 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
144 return HID_PARSE_InsufficientReportIDItems;
145
146 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
147 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
148 }
149 }
150
151 ParserData->UsingReportIDs = true;
152
153 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
154 break;
155 case (TYPE_LOCAL | TAG_LOCAL_USAGE):
156 if (UsageListSize == HID_USAGE_STACK_DEPTH)
157 return HID_PARSE_UsageListOverflow;
158
159 UsageList[UsageListSize++] = ReportItemData;
160 break;
161 case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
162 UsageMinMax.Minimum = ReportItemData;
163 break;
164 case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
165 UsageMinMax.Maximum = ReportItemData;
166 break;
167 case (TYPE_MAIN | TAG_MAIN_COLLECTION):
168 if (CurrCollectionPath == NULL)
169 {
170 CurrCollectionPath = &ParserData->CollectionPaths[0];
171 }
172 else
173 {
174 HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
175
176 CurrCollectionPath = &ParserData->CollectionPaths[1];
177
178 while (CurrCollectionPath->Parent != NULL)
179 {
180 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
181 return HID_PARSE_InsufficientCollectionPaths;
182
183 CurrCollectionPath++;
184 }
185
186 CurrCollectionPath->Parent = ParentCollectionPath;
187 }
188
189 CurrCollectionPath->Type = ReportItemData;
190 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
191
192 if (UsageListSize)
193 {
194 CurrCollectionPath->Usage.Usage = UsageList[0];
195
196 for (uint8_t i = 0; i < UsageListSize; i++)
197 UsageList[i] = UsageList[i + 1];
198
199 UsageListSize--;
200 }
201 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
202 {
203 CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
204 }
205
206 break;
207 case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
208 if (CurrCollectionPath == NULL)
209 return HID_PARSE_UnexpectedEndCollection;
210
211 CurrCollectionPath = CurrCollectionPath->Parent;
212 break;
213 case (TYPE_MAIN | TAG_MAIN_INPUT):
214 case (TYPE_MAIN | TAG_MAIN_OUTPUT):
215 case (TYPE_MAIN | TAG_MAIN_FEATURE):
216 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
217 {
218 HID_ReportItem_t NewReportItem;
219
220 memcpy(&NewReportItem.Attributes,
221 &CurrStateTable->Attributes,
222 sizeof(HID_ReportItem_Attributes_t));
223
224 NewReportItem.ItemFlags = ReportItemData;
225 NewReportItem.CollectionPath = CurrCollectionPath;
226 NewReportItem.ReportID = CurrStateTable->ReportID;
227
228 if (UsageListSize)
229 {
230 NewReportItem.Attributes.Usage.Usage = UsageList[0];
231
232 for (uint8_t i = 0; i < UsageListSize; i++)
233 UsageList[i] = UsageList[i + 1];
234
235 UsageListSize--;
236 }
237 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
238 {
239 NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
240 }
241
242 uint8_t ItemTag = (HIDReportItem & TAG_MASK);
243
244 if (ItemTag == TAG_MAIN_INPUT)
245 NewReportItem.ItemType = REPORT_ITEM_TYPE_In;
246 else if (ItemTag == TAG_MAIN_OUTPUT)
247 NewReportItem.ItemType = REPORT_ITEM_TYPE_Out;
248 else
249 NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature;
250
251 NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
252
253 CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
254
255 if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
256 ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
257
258 if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
259 {
260 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
261 return HID_PARSE_InsufficientReportItems;
262
263 memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
264 &NewReportItem, sizeof(HID_ReportItem_t));
265
266 ParserData->TotalReportItems++;
267 }
268 }
269
270 break;
271 }
272
273 if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)
274 {
275 UsageMinMax.Minimum = 0;
276 UsageMinMax.Maximum = 0;
277 UsageListSize = 0;
278 }
279 }
280
281 if (!(ParserData->TotalReportItems))
282 return HID_PARSE_NoUnfilteredReportItems;
283
284 return HID_PARSE_Successful;
285 }
286
287 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
288 {
289 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
290 uint16_t CurrentBit = ReportItem->BitOffset;
291 uint32_t BitMask = (1 << 0);
292
293 ReportItem->PreviousValue = ReportItem->Value;
294 ReportItem->Value = 0;
295
296 if (ReportItem->ReportID)
297 {
298 if (ReportItem->ReportID != ReportData[0])
299 return false;
300
301 ReportData++;
302 }
303
304 while (DataBitsRem--)
305 {
306 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
307 ReportItem->Value |= BitMask;
308
309 CurrentBit++;
310 BitMask <<= 1;
311 }
312
313 return true;
314 }
315
316 void USB_SetHIDReportItemInfo(uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
317 {
318 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
319 uint16_t CurrentBit = ReportItem->BitOffset;
320 uint32_t BitMask = (1 << 0);
321
322 if (ReportItem->ReportID)
323 {
324 ReportData[0] = ReportItem->ReportID;
325 ReportData++;
326 }
327
328 ReportItem->PreviousValue = ReportItem->Value;
329
330 while (DataBitsRem--)
331 {
332 if (ReportItem->Value & (1 << (CurrentBit % 8)))
333 ReportData[CurrentBit / 8] |= BitMask;
334
335 CurrentBit++;
336 BitMask <<= 1;
337 }
338 }
339
340 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, const uint8_t ReportType)
341 {
342 for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
343 {
344 uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
345
346 if (ParserData->ReportIDSizes[i].ReportID == ReportID)
347 return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));
348 }
349
350 return 0;
351 }
352
353 #endif