widl: Strip last separator in append_namespaces if suffix is NULL.
[wine.git] / dlls / hidclass.sys / descriptor.c
blobc02988494fd0eefb79cb621dd848d1347855fe0b
1 /*
2 * HID descriptor parsing
4 * Copyright (C) 2015 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #define NONAMELESSUNION
25 #include "hid.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(hid);
32 /* Flags that are defined in the document
33 "Device Class Definition for Human Interface Devices" */
34 enum {
35 INPUT_DATA_CONST = 0x01, /* Data (0) | Constant (1) */
36 INPUT_ARRAY_VAR = 0x02, /* Array (0) | Variable (1) */
37 INPUT_ABS_REL = 0x04, /* Absolute (0) | Relative (1) */
38 INPUT_WRAP = 0x08, /* No Wrap (0) | Wrap (1) */
39 INPUT_LINEAR = 0x10, /* Linear (0) | Non Linear (1) */
40 INPUT_PREFSTATE = 0x20, /* Preferred State (0) | No Preferred (1) */
41 INPUT_NULL = 0x40, /* No Null position (0) | Null state(1) */
42 INPUT_VOLATILE = 0x80, /* Non Volatile (0) | Volatile (1) */
43 INPUT_BITFIELD = 0x100 /* Bit Field (0) | Buffered Bytes (1) */
46 enum {
47 TAG_TYPE_MAIN = 0x0,
48 TAG_TYPE_GLOBAL,
49 TAG_TYPE_LOCAL,
50 TAG_TYPE_RESERVED,
53 enum {
54 TAG_MAIN_INPUT = 0x08,
55 TAG_MAIN_OUTPUT = 0x09,
56 TAG_MAIN_FEATURE = 0x0B,
57 TAG_MAIN_COLLECTION = 0x0A,
58 TAG_MAIN_END_COLLECTION = 0x0C
61 enum {
62 TAG_GLOBAL_USAGE_PAGE = 0x0,
63 TAG_GLOBAL_LOGICAL_MINIMUM,
64 TAG_GLOBAL_LOGICAL_MAXIMUM,
65 TAG_GLOBAL_PHYSICAL_MINIMUM,
66 TAG_GLOBAL_PHYSICAL_MAXIMUM,
67 TAG_GLOBAL_UNIT_EXPONENT,
68 TAG_GLOBAL_UNIT,
69 TAG_GLOBAL_REPORT_SIZE,
70 TAG_GLOBAL_REPORT_ID,
71 TAG_GLOBAL_REPORT_COUNT,
72 TAG_GLOBAL_PUSH,
73 TAG_GLOBAL_POP
76 enum {
77 TAG_LOCAL_USAGE = 0x0,
78 TAG_LOCAL_USAGE_MINIMUM,
79 TAG_LOCAL_USAGE_MAXIMUM,
80 TAG_LOCAL_DESIGNATOR_INDEX,
81 TAG_LOCAL_DESIGNATOR_MINIMUM,
82 TAG_LOCAL_DESIGNATOR_MAXIMUM,
83 TAG_LOCAL_STRING_INDEX,
84 TAG_LOCAL_STRING_MINIMUM,
85 TAG_LOCAL_STRING_MAXIMUM,
86 TAG_LOCAL_DELIMITER
90 static const char* const feature_string[] =
91 { "Input", "Output", "Feature" };
93 struct caps {
94 USAGE UsagePage;
95 LONG LogicalMin;
96 LONG LogicalMax;
97 LONG PhysicalMin;
98 LONG PhysicalMax;
99 ULONG UnitsExp;
100 ULONG Units;
101 USHORT BitSize;
102 UCHAR ReportID;
103 USHORT ReportCount;
105 BOOLEAN IsRange;
106 BOOLEAN IsStringRange;
107 BOOLEAN IsDesignatorRange;
108 union {
109 struct {
110 USAGE UsageMin;
111 USAGE UsageMax;
112 USHORT StringMin;
113 USHORT StringMax;
114 USHORT DesignatorMin;
115 USHORT DesignatorMax;
116 } Range;
117 struct {
118 USHORT Usage;
119 USAGE Reserved1;
120 USHORT StringIndex;
121 USHORT Reserved2;
122 USHORT DesignatorIndex;
123 USHORT Reserved3;
124 } NotRange;
125 } DUMMYUNIONNAME;
127 int Delim;
130 struct feature {
131 struct list entry;
132 struct caps caps;
134 HIDP_REPORT_TYPE type;
135 BOOLEAN isData;
136 BOOLEAN isArray;
137 BOOLEAN IsAbsolute;
138 BOOLEAN Wrap;
139 BOOLEAN Linear;
140 BOOLEAN prefState;
141 BOOLEAN HasNull;
142 BOOLEAN Volatile;
143 BOOLEAN BitField;
145 unsigned int index;
146 struct collection *collection;
149 static const char* const collection_string[] = {
150 "Physical",
151 "Application",
152 "Logical",
153 "Report",
154 "Named Array",
155 "Usage Switch",
156 "Usage Modifier",
159 struct collection {
160 struct list entry;
161 struct caps caps;
162 unsigned int index;
163 unsigned int type;
164 struct collection *parent;
165 struct list features;
166 struct list collections;
169 struct caps_stack {
170 struct list entry;
171 struct caps caps;
174 static const char* debugstr_usages(struct caps *caps)
176 if (!caps->IsRange)
177 return wine_dbg_sprintf("[0x%x]", caps->u.NotRange.Usage);
178 else
179 return wine_dbg_sprintf("[0x%x - 0x%x]", caps->u.Range.UsageMin, caps->u.Range.UsageMax);
182 static const char* debugstr_stringindex(struct caps *caps)
184 if (!caps->IsStringRange)
185 return wine_dbg_sprintf("%i", caps->u.NotRange.StringIndex);
186 else
187 return wine_dbg_sprintf("[%i - %i]", caps->u.Range.StringMin, caps->u.Range.StringMax);
190 static const char* debugstr_designatorindex(struct caps *caps)
192 if (!caps->IsDesignatorRange)
193 return wine_dbg_sprintf("%i", caps->u.NotRange.DesignatorIndex);
194 else
195 return wine_dbg_sprintf("[%i - %i]", caps->u.Range.DesignatorMin, caps->u.Range.DesignatorMax);
198 static void debugstr_caps(const char* type, struct caps *caps)
200 if (!caps)
201 return;
202 TRACE("(%s Caps: UsagePage 0x%x; LogicalMin %i; LogicalMax %i; PhysicalMin %i; "
203 "PhysicalMax %i; UnitsExp %i; Units %i; BitSize %i; ReportID %i; ReportCount %i; "
204 "Usage %s; StringIndex %s; DesignatorIndex %s; Delim %i;)\n",
205 type,
206 caps->UsagePage,
207 caps->LogicalMin,
208 caps->LogicalMax,
209 caps->PhysicalMin,
210 caps->PhysicalMax,
211 caps->UnitsExp,
212 caps->Units,
213 caps->BitSize,
214 caps->ReportID,
215 caps->ReportCount,
216 debugstr_usages(caps),
217 debugstr_stringindex(caps),
218 debugstr_designatorindex(caps),
219 caps->Delim);
222 static void debug_feature(struct feature *feature)
224 if (!feature)
225 return;
226 TRACE("[Feature type %s [%i]; %s; %s; %s; %s; %s; %s; %s; %s; %s]\n",
227 feature_string[feature->type],
228 feature->index,
229 (feature->isData)?"Data":"Const",
230 (feature->isArray)?"Array":"Var",
231 (feature->IsAbsolute)?"Abs":"Rel",
232 (feature->Wrap)?"Wrap":"NoWrap",
233 (feature->Linear)?"Linear":"NonLinear",
234 (feature->prefState)?"PrefStat":"NoPrefState",
235 (feature->HasNull)?"HasNull":"NoNull",
236 (feature->Volatile)?"Volatile":"NonVolatile",
237 (feature->BitField)?"BitField":"Buffered");
239 debugstr_caps("Feature", &feature->caps);
242 static void debug_collection(struct collection *collection)
244 struct feature *fentry;
245 struct collection *centry;
246 if (TRACE_ON(hid))
248 TRACE("START Collection %i <<< %s, parent: %p, %i features, %i collections\n",
249 collection->index, collection_string[collection->type], collection->parent,
250 list_count(&collection->features), list_count(&collection->collections));
251 debugstr_caps("Collection", &collection->caps);
252 LIST_FOR_EACH_ENTRY(fentry, &collection->features, struct feature, entry)
253 debug_feature(fentry);
254 LIST_FOR_EACH_ENTRY(centry, &collection->collections, struct collection, entry)
255 debug_collection(centry);
256 TRACE(">>> END Collection %i\n", collection->index);
260 static void debug_print_button_cap(const CHAR * type, WINE_HID_ELEMENT *wine_element)
262 if (!wine_element->caps.button.IsRange)
263 TRACE("%s Button: 0x%x/0x%04x: ReportId %i, startBit %i/1\n" , type,
264 wine_element->caps.button.UsagePage,
265 wine_element->caps.button.u.NotRange.Usage,
266 wine_element->caps.value.ReportID,
267 wine_element->valueStartBit);
268 else
269 TRACE("%s Button: 0x%x/[0x%04x-0x%04x]: ReportId %i, startBit %i/%i\n" ,type,
270 wine_element->caps.button.UsagePage,
271 wine_element->caps.button.u.Range.UsageMin,
272 wine_element->caps.button.u.Range.UsageMax,
273 wine_element->caps.value.ReportID,
274 wine_element->valueStartBit,
275 wine_element->bitCount);
278 static void debug_print_value_cap(const CHAR * type, WINE_HID_ELEMENT *wine_element)
280 TRACE("%s Value: 0x%x/0x%x: ReportId %i, IsAbsolute %i, HasNull %i, "
281 "Bit Size %i, ReportCount %i, UnitsExp %i, Units %i, "
282 "LogicalMin %i, Logical Max %i, PhysicalMin %i, "
283 "PhysicalMax %i -- StartBit %i/%i\n", type,
284 wine_element->caps.value.UsagePage,
285 wine_element->caps.value.u.NotRange.Usage,
286 wine_element->caps.value.ReportID,
287 wine_element->caps.value.IsAbsolute,
288 wine_element->caps.value.HasNull,
289 wine_element->caps.value.BitSize,
290 wine_element->caps.value.ReportCount,
291 wine_element->caps.value.UnitsExp,
292 wine_element->caps.value.Units,
293 wine_element->caps.value.LogicalMin,
294 wine_element->caps.value.LogicalMax,
295 wine_element->caps.value.PhysicalMin,
296 wine_element->caps.value.PhysicalMax,
297 wine_element->valueStartBit,
298 wine_element->bitCount);
301 static void debug_print_element(const CHAR* type, WINE_HID_ELEMENT *wine_element)
303 if (wine_element->ElementType == ButtonElement)
304 debug_print_button_cap(type, wine_element);
305 else if (wine_element->ElementType == ValueElement)
306 debug_print_value_cap(type, wine_element);
307 else
308 TRACE("%s: UNKNOWN\n", type);
311 static void debug_print_report(const char* type, WINE_HIDP_PREPARSED_DATA *data,
312 WINE_HID_REPORT *report)
314 WINE_HID_ELEMENT *elem = HID_ELEMS(data);
315 unsigned int i;
316 TRACE("START Report %i <<< %s report : bitSize: %i elementCount: %i\n",
317 report->reportID,
318 type,
319 report->bitSize,
320 report->elementCount);
321 for (i = 0; i < report->elementCount; i++)
323 debug_print_element(type, &elem[report->elementIdx + i]);
325 TRACE(">>> END Report %i\n",report->reportID);
328 static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data)
330 unsigned int i, end;
331 if (TRACE_ON(hid))
333 TRACE("START PREPARSED Data <<< dwSize: %i Usage: %i, UsagePage: %i, "
334 "InputReportByteLength: %i, tOutputReportByteLength: %i, "
335 "FeatureReportByteLength: %i, NumberLinkCollectionNodes: %i, "
336 "NumberInputButtonCaps: %i, NumberInputValueCaps: %i, "
337 "NumberInputDataIndices: %i, NumberOutputButtonCaps: %i, "
338 "NumberOutputValueCaps: %i, NumberOutputDataIndices: %i, "
339 "NumberFeatureButtonCaps: %i, NumberFeatureValueCaps: %i, "
340 "NumberFeatureDataIndices: %i, reportCount[HidP_Input]: %i, "
341 "reportCount[HidP_Output]: %i, reportCount[HidP_Feature]: %i, "
342 "elementOffset: %i\n",
343 data->dwSize,
344 data->caps.Usage,
345 data->caps.UsagePage,
346 data->caps.InputReportByteLength,
347 data->caps.OutputReportByteLength,
348 data->caps.FeatureReportByteLength,
349 data->caps.NumberLinkCollectionNodes,
350 data->caps.NumberInputButtonCaps,
351 data->caps.NumberInputValueCaps,
352 data->caps.NumberInputDataIndices,
353 data->caps.NumberOutputButtonCaps,
354 data->caps.NumberOutputValueCaps,
355 data->caps.NumberOutputDataIndices,
356 data->caps.NumberFeatureButtonCaps,
357 data->caps.NumberFeatureValueCaps,
358 data->caps.NumberFeatureDataIndices,
359 data->reportCount[HidP_Input],
360 data->reportCount[HidP_Output],
361 data->reportCount[HidP_Feature],
362 data->elementOffset);
364 end = data->reportCount[HidP_Input];
365 for (i = 0; i < end; i++)
367 debug_print_report("INPUT", data, &data->reports[i]);
369 end += data->reportCount[HidP_Output];
370 for (; i < end; i++)
372 debug_print_report("OUTPUT", data, &data->reports[i]);
374 end += data->reportCount[HidP_Feature];
375 for (i = 0; i < end; i++)
377 debug_print_report("FEATURE", data, &data->reports[i]);
379 TRACE(">>> END Preparsed Data\n");
383 static int getValue(int bsize, int source, BOOL allow_negative)
385 int mask = 0xff;
386 int negative = 0x80;
387 int outofrange = 0x100;
388 int value;
389 unsigned int i;
391 if (bsize == 4)
392 return source;
394 for (i = 1; i < bsize; i++)
396 mask = (mask<<8) + 0xff;
397 negative = (negative<<8);
398 outofrange = (outofrange<<8);
400 value = (source&mask);
401 if (allow_negative && value&negative)
402 value = -1 * (outofrange - value);
403 return value;
406 static void parse_io_feature(unsigned int bSize, int itemVal, int bTag,
407 unsigned int *feature_index,
408 struct feature *feature)
410 if (bSize == 0)
412 return;
414 else
416 feature->isData = ((itemVal & INPUT_DATA_CONST) == 0);
417 feature->isArray = ((itemVal & INPUT_ARRAY_VAR) == 0);
418 feature->IsAbsolute = ((itemVal & INPUT_ABS_REL) == 0);
419 feature->Wrap = ((itemVal & INPUT_WRAP) != 0);
420 feature->Linear = ((itemVal & INPUT_LINEAR) == 0);
421 feature->prefState = ((itemVal & INPUT_PREFSTATE) == 0);
422 feature->HasNull = ((itemVal & INPUT_NULL) != 0);
424 if (bTag != TAG_MAIN_INPUT)
426 feature->Volatile = ((itemVal & INPUT_VOLATILE) != 0);
428 if (bSize > 1)
430 feature->BitField = ((itemVal & INPUT_BITFIELD) == 0);
432 feature->index = *feature_index;
433 *feature_index = *feature_index + 1;
437 static void parse_collection(unsigned int bSize, int itemVal,
438 struct collection *collection)
440 if (bSize)
442 collection->type = itemVal;
444 if (itemVal >= 0x07 && itemVal <= 0x7F) {
445 ERR(" (Reserved 0x%x )\n", itemVal);
447 else if (itemVal >= 0x80 && itemVal <= 0xFF) {
448 ERR(" (Vendor Defined 0x%x )\n", itemVal);
453 static void new_caps(struct caps *caps)
455 caps->IsRange = 0;
456 caps->IsStringRange = 0;
457 caps->IsDesignatorRange = 0;
458 caps->u.NotRange.Usage = 0;
461 static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int length,
462 unsigned int *feature_index, unsigned int *collection_index,
463 struct collection *collection, struct caps *caps,
464 struct list *stack)
466 int usages_top = 0;
467 USAGE usages[256];
468 unsigned int i;
470 for (i = index; i < length;)
472 BYTE b0 = descriptor[i++];
473 int bSize = b0 & 0x03;
474 int bType = (b0 >> 2) & 0x03;
475 int bTag = (b0 >> 4) & 0x0F;
477 bSize = (bSize == 3) ? 4 : bSize;
478 if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && bSize == 2 &&
479 i + 2 < length)
481 /* Long data items: Should be unused */
482 ERR("Long Data Item, should be unused\n");
484 else
486 int bSizeActual = 0;
487 int itemVal = 0;
488 unsigned int j;
490 for (j = 0; j < bSize; j++)
492 if (i + j < length)
494 itemVal += descriptor[i + j] << (8 * j);
495 bSizeActual++;
498 TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-1,bType, bTag, bSize, itemVal );
500 if (bType == TAG_TYPE_MAIN)
502 struct feature *feature;
503 switch(bTag)
505 case TAG_MAIN_INPUT:
506 case TAG_MAIN_OUTPUT:
507 case TAG_MAIN_FEATURE:
508 for (j = 0; j < caps->ReportCount; j++)
510 feature = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*feature));
511 list_add_tail(&collection->features, &feature->entry);
512 if (bTag == TAG_MAIN_INPUT)
513 feature->type = HidP_Input;
514 else if (bTag == TAG_MAIN_OUTPUT)
515 feature->type = HidP_Output;
516 else
517 feature->type = HidP_Feature;
518 parse_io_feature(bSize, itemVal, bTag, feature_index, feature);
519 if (j < usages_top)
520 caps->u.NotRange.Usage = usages[j];
521 feature->caps = *caps;
522 feature->caps.ReportCount = 1;
523 feature->collection = collection;
524 if (j+1 >= usages_top)
526 feature->caps.ReportCount += caps->ReportCount - (j + 1);
527 break;
530 usages_top = 0;
531 new_caps(caps);
532 break;
533 case TAG_MAIN_COLLECTION:
535 struct collection *subcollection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct collection));
536 list_add_tail(&collection->collections, &subcollection->entry);
537 subcollection->parent = collection;
538 /* Only set our collection once...
539 We do not properly handle composite devices yet. */
540 if (usages_top)
542 caps->u.NotRange.Usage = usages[usages_top-1];
543 usages_top = 0;
545 if (*collection_index == 0)
546 collection->caps = *caps;
547 subcollection->caps = *caps;
548 subcollection->index = *collection_index;
549 *collection_index = *collection_index + 1;
550 list_init(&subcollection->features);
551 list_init(&subcollection->collections);
552 new_caps(caps);
554 parse_collection(bSize, itemVal, subcollection);
556 i = parse_descriptor(descriptor, i+1, length, feature_index, collection_index, subcollection, caps, stack);
557 continue;
559 case TAG_MAIN_END_COLLECTION:
560 return i;
561 default:
562 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
565 else if (bType == TAG_TYPE_GLOBAL)
567 switch(bTag)
569 case TAG_GLOBAL_USAGE_PAGE:
570 caps->UsagePage = getValue(bSize, itemVal, FALSE);
571 break;
572 case TAG_GLOBAL_LOGICAL_MINIMUM:
573 caps->LogicalMin = getValue(bSize, itemVal, TRUE);
574 break;
575 case TAG_GLOBAL_LOGICAL_MAXIMUM:
576 caps->LogicalMax = getValue(bSize, itemVal, TRUE);
577 break;
578 case TAG_GLOBAL_PHYSICAL_MINIMUM:
579 caps->PhysicalMin = getValue(bSize, itemVal, TRUE);
580 break;
581 case TAG_GLOBAL_PHYSICAL_MAXIMUM:
582 caps->PhysicalMax = getValue(bSize, itemVal, TRUE);
583 break;
584 case TAG_GLOBAL_UNIT_EXPONENT:
585 caps->UnitsExp = getValue(bSize, itemVal, TRUE);
586 break;
587 case TAG_GLOBAL_UNIT:
588 caps->Units = getValue(bSize, itemVal, TRUE);
589 break;
590 case TAG_GLOBAL_REPORT_SIZE:
591 caps->BitSize = getValue(bSize, itemVal, FALSE);
592 break;
593 case TAG_GLOBAL_REPORT_ID:
594 caps->ReportID = getValue(bSize, itemVal, FALSE);
595 break;
596 case TAG_GLOBAL_REPORT_COUNT:
597 caps->ReportCount = getValue(bSize, itemVal, FALSE);
598 break;
599 case TAG_GLOBAL_PUSH:
601 struct caps_stack *saved = HeapAlloc(GetProcessHeap(), 0, sizeof(*saved));
602 saved->caps = *caps;
603 TRACE("Push\n");
604 list_add_tail(stack, &saved->entry);
605 break;
607 case TAG_GLOBAL_POP:
609 struct list *tail;
610 struct caps_stack *saved;
611 TRACE("Pop\n");
612 tail = list_tail(stack);
613 if (tail)
615 saved = LIST_ENTRY(tail, struct caps_stack, entry);
616 *caps = saved->caps;
617 list_remove(tail);
618 HeapFree(GetProcessHeap(), 0, saved);
620 else
621 ERR("Pop but no stack!\n");
622 break;
624 default:
625 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
628 else if (bType == TAG_TYPE_LOCAL)
630 switch(bTag)
632 case TAG_LOCAL_USAGE:
633 if (usages_top == sizeof(usages))
634 ERR("More than 256 individual usages defined\n");
635 else
637 usages[usages_top++] = getValue(bSize, itemVal, FALSE);
638 caps->IsRange = FALSE;
640 break;
641 case TAG_LOCAL_USAGE_MINIMUM:
642 caps->u.Range.UsageMin = getValue(bSize, itemVal, FALSE);
643 caps->IsRange = TRUE;
644 break;
645 case TAG_LOCAL_USAGE_MAXIMUM:
646 caps->u.Range.UsageMax = getValue(bSize, itemVal, FALSE);
647 caps->IsRange = TRUE;
648 break;
649 case TAG_LOCAL_DESIGNATOR_INDEX:
650 caps->u.NotRange.DesignatorIndex = getValue(bSize, itemVal, FALSE);
651 caps->IsDesignatorRange = FALSE;
652 break;
653 case TAG_LOCAL_DESIGNATOR_MINIMUM:
654 caps->u.Range.DesignatorMin = getValue(bSize, itemVal, FALSE);
655 caps->IsDesignatorRange = TRUE;
656 break;
657 case TAG_LOCAL_DESIGNATOR_MAXIMUM:
658 caps->u.Range.DesignatorMax = getValue(bSize, itemVal, FALSE);
659 caps->IsDesignatorRange = TRUE;
660 break;
661 case TAG_LOCAL_STRING_INDEX:
662 caps->u.NotRange.StringIndex = getValue(bSize, itemVal, FALSE);
663 caps->IsStringRange = FALSE;
664 break;
665 case TAG_LOCAL_STRING_MINIMUM:
666 caps->u.Range.StringMin = getValue(bSize, itemVal, FALSE);
667 caps->IsStringRange = TRUE;
668 break;
669 case TAG_LOCAL_STRING_MAXIMUM:
670 caps->u.Range.StringMax = getValue(bSize, itemVal, FALSE);
671 caps->IsStringRange = TRUE;
672 break;
673 case TAG_LOCAL_DELIMITER:
674 caps->Delim = getValue(bSize, itemVal, FALSE);
675 break;
676 default:
677 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
680 else
681 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
683 i += bSize;
686 return i;
689 static void build_elements(WINE_HID_REPORT *wine_report, WINE_HID_ELEMENT *elems,
690 struct feature* feature, USHORT *data_index)
692 WINE_HID_ELEMENT *wine_element = elems + wine_report->elementIdx + wine_report->elementCount;
694 if (!feature->isData)
696 wine_report->bitSize += feature->caps.BitSize * feature->caps.ReportCount;
697 return;
700 wine_element->valueStartBit = wine_report->bitSize;
702 wine_element->bitCount = (feature->caps.BitSize * feature->caps.ReportCount);
703 wine_report->bitSize += wine_element->bitCount;
705 if (feature->caps.BitSize == 1)
707 wine_element->ElementType = ButtonElement;
708 wine_element->caps.button.UsagePage = feature->caps.UsagePage;
709 wine_element->caps.button.ReportID = feature->caps.ReportID;
710 wine_element->caps.button.BitField = feature->BitField;
711 wine_element->caps.button.LinkCollection = feature->collection->index;
712 wine_element->caps.button.LinkUsage = feature->collection->caps.u.NotRange.Usage;
713 wine_element->caps.button.LinkUsagePage = feature->collection->caps.UsagePage;
714 wine_element->caps.button.IsRange = feature->caps.IsRange;
715 wine_element->caps.button.IsStringRange = feature->caps.IsStringRange;
716 wine_element->caps.button.IsDesignatorRange = feature->caps.IsDesignatorRange;
717 wine_element->caps.button.IsAbsolute = feature->IsAbsolute;
718 if (wine_element->caps.button.IsRange)
720 wine_element->caps.button.u.Range.UsageMin = feature->caps.u.Range.UsageMin;
721 wine_element->caps.button.u.Range.UsageMax = feature->caps.u.Range.UsageMax;
722 wine_element->caps.button.u.Range.StringMin = feature->caps.u.Range.StringMin;
723 wine_element->caps.button.u.Range.StringMax = feature->caps.u.Range.StringMax;
724 wine_element->caps.button.u.Range.DesignatorMin = feature->caps.u.Range.DesignatorMin;
725 wine_element->caps.button.u.Range.DesignatorMax = feature->caps.u.Range.DesignatorMax;
726 wine_element->caps.button.u.Range.DataIndexMin = *data_index;
727 wine_element->caps.button.u.Range.DataIndexMax = *data_index + wine_element->bitCount - 1;
728 *data_index = *data_index + wine_element->bitCount;
730 else
732 wine_element->caps.button.u.NotRange.Usage = feature->caps.u.NotRange.Usage;
733 wine_element->caps.button.u.NotRange.Reserved1 = feature->caps.u.NotRange.Usage;
734 wine_element->caps.button.u.NotRange.StringIndex = feature->caps.u.NotRange.StringIndex;
735 wine_element->caps.button.u.NotRange.Reserved2 = feature->caps.u.NotRange.StringIndex;
736 wine_element->caps.button.u.NotRange.DesignatorIndex = feature->caps.u.NotRange.DesignatorIndex;
737 wine_element->caps.button.u.NotRange.Reserved3 = feature->caps.u.NotRange.DesignatorIndex;
738 wine_element->caps.button.u.NotRange.DataIndex = *data_index;
739 wine_element->caps.button.u.NotRange.Reserved4 = *data_index;
740 *data_index = *data_index + 1;
743 else
745 wine_element->ElementType = ValueElement;
746 wine_element->caps.value.UsagePage = feature->caps.UsagePage;
747 wine_element->caps.value.ReportID = feature->caps.ReportID;
748 wine_element->caps.value.BitField = feature->BitField;
749 wine_element->caps.value.LinkCollection = feature->collection->index;
750 wine_element->caps.value.LinkUsage = feature->collection->caps.u.NotRange.Usage;
751 wine_element->caps.value.LinkUsagePage = feature->collection->caps.UsagePage;
752 wine_element->caps.value.IsRange = feature->caps.IsRange;
753 wine_element->caps.value.IsStringRange = feature->caps.IsStringRange;
754 wine_element->caps.value.IsDesignatorRange = feature->caps.IsDesignatorRange;
755 wine_element->caps.value.IsAbsolute = feature->IsAbsolute;
756 wine_element->caps.value.HasNull = feature->HasNull;
757 wine_element->caps.value.BitSize = feature->caps.BitSize;
758 wine_element->caps.value.ReportCount = feature->caps.ReportCount;
759 wine_element->caps.value.UnitsExp = feature->caps.UnitsExp;
760 wine_element->caps.value.Units = feature->caps.Units;
761 wine_element->caps.value.LogicalMin = feature->caps.LogicalMin;
762 wine_element->caps.value.LogicalMax = feature->caps.LogicalMax;
763 wine_element->caps.value.PhysicalMin = feature->caps.PhysicalMin;
764 wine_element->caps.value.PhysicalMax = feature->caps.PhysicalMax;
765 if (wine_element->caps.value.IsRange)
767 wine_element->caps.value.u.Range.UsageMin = feature->caps.u.Range.UsageMin;
768 wine_element->caps.value.u.Range.UsageMax = feature->caps.u.Range.UsageMax;
769 wine_element->caps.value.u.Range.StringMin = feature->caps.u.Range.StringMin;
770 wine_element->caps.value.u.Range.StringMax = feature->caps.u.Range.StringMax;
771 wine_element->caps.value.u.Range.DesignatorMin = feature->caps.u.Range.DesignatorMin;
772 wine_element->caps.value.u.Range.DesignatorMax = feature->caps.u.Range.DesignatorMax;
773 wine_element->caps.value.u.Range.DataIndexMin = *data_index;
774 wine_element->caps.value.u.Range.DataIndexMax = *data_index +
775 (wine_element->caps.value.u.Range.UsageMax -
776 wine_element->caps.value.u.Range.UsageMin);
777 *data_index = *data_index +
778 (wine_element->caps.value.u.Range.UsageMax -
779 wine_element->caps.value.u.Range.UsageMin) + 1;
781 else
783 wine_element->caps.value.u.NotRange.Usage = feature->caps.u.NotRange.Usage;
784 wine_element->caps.value.u.NotRange.Reserved1 = feature->caps.u.NotRange.Usage;
785 wine_element->caps.value.u.NotRange.StringIndex = feature->caps.u.NotRange.StringIndex;
786 wine_element->caps.value.u.NotRange.Reserved2 = feature->caps.u.NotRange.StringIndex;
787 wine_element->caps.value.u.NotRange.DesignatorIndex = feature->caps.u.NotRange.DesignatorIndex;
788 wine_element->caps.value.u.NotRange.Reserved3 = feature->caps.u.NotRange.DesignatorIndex;
789 wine_element->caps.value.u.NotRange.DataIndex = *data_index;
790 wine_element->caps.value.u.NotRange.Reserved4 = *data_index;
791 *data_index = *data_index + 1;
794 wine_report->elementCount++;
797 static void count_elements(struct feature* feature, USHORT *buttons, USHORT *values)
799 if (!feature->isData)
800 return;
802 if (feature->caps.BitSize == 1)
803 (*buttons)++;
804 else
805 (*values)++;
808 struct preparse_ctx
810 int report_count[3];
811 int elem_count;
812 int report_elem_count[3][256];
814 int elem_alloc;
815 BOOL report_created[3][256];
818 static void create_preparse_ctx(const struct collection *base, struct preparse_ctx *ctx)
820 struct feature *f;
821 struct collection *c;
823 LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry)
825 ctx->elem_count++;
826 ctx->report_elem_count[f->type][f->caps.ReportID]++;
827 if (ctx->report_elem_count[f->type][f->caps.ReportID] != 1)
828 continue;
829 ctx->report_count[f->type]++;
832 LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry)
833 create_preparse_ctx(c, ctx);
836 static void preparse_collection(const struct collection *root, const struct collection *base,
837 WINE_HIDP_PREPARSED_DATA *data, struct preparse_ctx *ctx)
839 WINE_HID_ELEMENT *elem = HID_ELEMS(data);
840 WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data);
841 struct feature *f;
842 struct collection *c;
843 struct list *entry;
845 LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry)
847 WINE_HID_REPORT *report;
849 if (!ctx->report_created[f->type][f->caps.ReportID])
851 ctx->report_created[f->type][f->caps.ReportID] = TRUE;
852 data->reportIdx[f->type][f->caps.ReportID] = data->reportCount[f->type]++;
853 if (f->type > 0) data->reportIdx[f->type][f->caps.ReportID] += ctx->report_count[0];
854 if (f->type > 1) data->reportIdx[f->type][f->caps.ReportID] += ctx->report_count[1];
856 report = &data->reports[data->reportIdx[f->type][f->caps.ReportID]];
857 report->reportID = f->caps.ReportID;
858 /* Room for the reportID */
859 report->bitSize = 8;
860 report->elementIdx = ctx->elem_alloc;
861 ctx->elem_alloc += ctx->report_elem_count[f->type][f->caps.ReportID];
864 report = &data->reports[data->reportIdx[f->type][f->caps.ReportID]];
865 switch (f->type)
867 case HidP_Input:
868 build_elements(report, elem, f, &data->caps.NumberInputDataIndices);
869 count_elements(f, &data->caps.NumberInputButtonCaps, &data->caps.NumberInputValueCaps);
870 data->caps.InputReportByteLength =
871 max(data->caps.InputReportByteLength, (report->bitSize + 7) / 8);
872 break;
873 case HidP_Output:
874 build_elements(report, elem, f, &data->caps.NumberOutputDataIndices);
875 count_elements(f, &data->caps.NumberOutputButtonCaps, &data->caps.NumberOutputValueCaps);
876 data->caps.OutputReportByteLength =
877 max(data->caps.OutputReportByteLength, (report->bitSize + 7) / 8);
878 break;
879 case HidP_Feature:
880 build_elements(report, elem, f, &data->caps.NumberFeatureDataIndices);
881 count_elements(f, &data->caps.NumberFeatureButtonCaps, &data->caps.NumberFeatureValueCaps);
882 data->caps.FeatureReportByteLength =
883 max(data->caps.FeatureReportByteLength, (report->bitSize + 7) / 8);
884 break;
888 if (root != base)
890 nodes[base->index].LinkUsagePage = base->caps.UsagePage;
891 nodes[base->index].LinkUsage = base->caps.u.NotRange.Usage;
892 nodes[base->index].Parent = base->parent == root ? 0 : base->parent->index;
893 nodes[base->index].CollectionType = base->type;
894 nodes[base->index].IsAlias = 0;
896 if ((entry = list_head(&base->collections)))
897 nodes[base->index].FirstChild = LIST_ENTRY(entry, struct collection, entry)->index;
900 LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry)
902 preparse_collection(root, c, data, ctx);
904 if ((entry = list_next(&base->collections, &c->entry)))
905 nodes[c->index].NextSibling = LIST_ENTRY(entry, struct collection, entry)->index;
906 if (root != base) nodes[base->index].NumberOfChildren++;
910 static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_collection, unsigned int node_count)
912 WINE_HIDP_PREPARSED_DATA *data;
913 unsigned int report_count;
914 unsigned int size;
916 struct preparse_ctx ctx;
917 unsigned int element_off;
918 unsigned int nodes_offset;
920 memset(&ctx, 0, sizeof(ctx));
921 create_preparse_ctx(base_collection, &ctx);
923 report_count = ctx.report_count[HidP_Input] + ctx.report_count[HidP_Output]
924 + ctx.report_count[HidP_Feature];
925 element_off = FIELD_OFFSET(WINE_HIDP_PREPARSED_DATA, reports[report_count]);
926 size = element_off + (ctx.elem_count * sizeof(WINE_HID_ELEMENT));
928 nodes_offset = size;
929 size += node_count * sizeof(WINE_HID_LINK_COLLECTION_NODE);
931 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
932 data->magic = HID_MAGIC;
933 data->dwSize = size;
934 data->caps.Usage = base_collection->caps.u.NotRange.Usage;
935 data->caps.UsagePage = base_collection->caps.UsagePage;
936 data->caps.NumberLinkCollectionNodes = node_count;
937 data->elementOffset = element_off;
938 data->nodesOffset = nodes_offset;
940 preparse_collection(base_collection, base_collection, data, &ctx);
941 return data;
944 static void free_collection(struct collection *collection)
946 struct feature *fentry, *fnext;
947 struct collection *centry, *cnext;
948 LIST_FOR_EACH_ENTRY_SAFE(centry, cnext, &collection->collections, struct collection, entry)
950 list_remove(&centry->entry);
951 free_collection(centry);
953 LIST_FOR_EACH_ENTRY_SAFE(fentry, fnext, &collection->features, struct feature, entry)
955 list_remove(&fentry->entry);
956 HeapFree(GetProcessHeap(), 0, fentry);
958 HeapFree(GetProcessHeap(), 0, collection);
961 WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
963 WINE_HIDP_PREPARSED_DATA *data = NULL;
964 struct collection *base;
965 struct caps caps;
967 struct list caps_stack;
969 unsigned int feature_count = 0;
970 unsigned int cidx;
972 if (TRACE_ON(hid))
974 TRACE("Descriptor[%i]: ", length);
975 for (cidx = 0; cidx < length; cidx++)
977 TRACE("%x ",descriptor[cidx]);
978 if ((cidx+1) % 80 == 0)
979 TRACE("\n");
981 TRACE("\n");
984 list_init(&caps_stack);
986 base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*base));
987 base->index = 1;
988 list_init(&base->features);
989 list_init(&base->collections);
990 memset(&caps, 0, sizeof(caps));
992 cidx = 0;
993 parse_descriptor(descriptor, 0, length, &feature_count, &cidx, base, &caps, &caps_stack);
995 debug_collection(base);
997 if (!list_empty(&caps_stack))
999 struct caps_stack *entry, *cursor;
1000 ERR("%i unpopped device caps on the stack\n", list_count(&caps_stack));
1001 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor, &caps_stack, struct caps_stack, entry)
1003 list_remove(&entry->entry);
1004 HeapFree(GetProcessHeap(), 0, entry);
1008 data = build_PreparseData(base, cidx);
1009 debug_print_preparsed(data);
1010 free_collection(base);
1012 return data;