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