Add user-filtering to the HID report parser, so that the user code can decide which...
[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 HID_CollectionPath_t* CurrCollectionPath = NULL;
41 uint16_t UsageStack[HID_USAGE_STACK_DEPTH];
42 uint8_t UsageStackSize = 0;
43 uint16_t BitOffsetIn = 0;
44 uint16_t BitOffsetOut = 0;
45 uint16_t BitOffsetFeature = 0;
46
47 ParserData->TotalReportItems = 0;
48 ParserData->UsingMultipleReports = false;
49
50 for (uint8_t CurrCollection = 0; CurrCollection < HID_MAX_COLLECTIONS; CurrCollection++)
51 ParserData->CollectionPaths[CurrCollection].Parent = NULL;
52
53 memset(&StateTable[0], 0x00, sizeof(HID_StateTable_t));
54
55 while (ReportSize)
56 {
57 uint8_t HIDReportItem = *ReportData;
58 uint32_t ReportItemData = 0;
59
60 ReportData++;
61 ReportSize--;
62
63 switch (HIDReportItem & DATA_SIZE_MASK)
64 {
65 case DATA_SIZE_4:
66 ReportItemData = *((uint32_t*)ReportData);
67 ReportSize -= 4;
68 ReportData += 4;
69 break;
70 case DATA_SIZE_2:
71 ReportItemData = *((uint16_t*)ReportData);
72 ReportSize -= 2;
73 ReportData += 2;
74 break;
75 case DATA_SIZE_1:
76 ReportItemData = *((uint8_t*)ReportData);
77 ReportSize -= 1;
78 ReportData += 1;
79 break;
80 }
81
82 switch (HIDReportItem & (TYPE_MASK | TAG_MASK))
83 {
84 case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
85 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
86 return HID_PARSE_HIDStackOverflow;
87
88 memcpy((CurrStateTable + 1),
89 CurrStateTable,
90 sizeof(HID_ReportItem_t));
91
92 CurrStateTable++;
93 break;
94 case (TYPE_GLOBAL | TAG_GLOBAL_POP):
95 if (CurrStateTable == &StateTable[0])
96 return HID_PARSE_HIDStackUnderflow;
97
98 CurrStateTable--;
99 break;
100 case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
101 CurrStateTable->Attributes.Usage.Page = ReportItemData;
102 break;
103 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
104 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
105 break;
106 case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
107 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
108 break;
109 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
110 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
111 break;
112 case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
113 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
114 break;
115 case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
116 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
117 break;
118 case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
119 CurrStateTable->Attributes.Unit.Type = ReportItemData;
120 break;
121 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
122 CurrStateTable->Attributes.BitSize = ReportItemData;
123 break;
124 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
125 CurrStateTable->ReportCount = ReportItemData;
126 break;
127 case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
128 CurrStateTable->ReportID = ReportItemData;
129 ParserData->UsingMultipleReports = true;
130 BitOffsetIn = 0;
131 BitOffsetOut = 0;
132 BitOffsetFeature = 0;
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 case (TYPE_MAIN | TAG_MAIN_FEATURE):
196 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
197 {
198 HID_ReportItem_t NewReportItem;
199
200 memcpy(&NewReportItem.Attributes,
201 &CurrStateTable->Attributes,
202 sizeof(HID_ReportItem_Attributes_t));
203
204 NewReportItem.ItemFlags = ReportItemData;
205 NewReportItem.CollectionPath = CurrCollectionPath;
206 NewReportItem.ReportID = CurrStateTable->ReportID;
207
208 if (UsageStackSize)
209 {
210 NewReportItem.Attributes.Usage.Usage = UsageStack[0];
211
212 for (uint8_t i = 0; i < UsageStackSize; i++)
213 UsageStack[i] = UsageStack[i + 1];
214
215 UsageStackSize--;
216 }
217 else
218 {
219 NewReportItem.Attributes.Usage.Usage = 0;
220 }
221
222 switch (HIDReportItem & TAG_MASK)
223 {
224 case TAG_MAIN_INPUT:
225 NewReportItem.ItemType = REPORT_ITEM_TYPE_In;
226 NewReportItem.BitOffset = BitOffsetIn;
227
228 BitOffsetIn += CurrStateTable->Attributes.BitSize;
229 break;
230 case TAG_MAIN_OUTPUT:
231 NewReportItem.ItemType = REPORT_ITEM_TYPE_Out;
232 NewReportItem.BitOffset = BitOffsetOut;
233
234 BitOffsetOut += CurrStateTable->Attributes.BitSize;
235 break;
236 case TAG_MAIN_FEATURE:
237 NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature;
238 NewReportItem.BitOffset = BitOffsetFeature;
239
240 BitOffsetFeature += CurrStateTable->Attributes.BitSize;
241 break;
242 }
243
244 if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&CurrStateTable->Attributes))
245 {
246 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
247 return HID_PARSE_InsufficientReportItems;
248
249 memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
250 &NewReportItem, sizeof(HID_ReportItem_t));
251
252 ParserData->TotalReportItems++;
253 }
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