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