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