ntoskrnl.exe: Implement ObReferenceObjectByName but only for loaded drivers.
[wine.git] / dlls / hidclass.sys / descriptor.c
blob9a26f0f4d5babca98eafc142e18fb582b14f32ae
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 "config.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #define NONAMELESSUNION
27 #include "hid.h"
29 #include "wine/debug.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(hid);
34 #define USAGE_MAX 10
36 /* Flags that are defined in the document
37 "Device Class Definition for Human Interface Devices" */
38 enum {
39 INPUT_DATA_CONST = 0x01, /* Data (0) | Constant (1) */
40 INPUT_ARRAY_VAR = 0x02, /* Array (0) | Variable (1) */
41 INPUT_ABS_REL = 0x04, /* Absolute (0) | Relative (1) */
42 INPUT_WRAP = 0x08, /* No Wrap (0) | Wrap (1) */
43 INPUT_LINEAR = 0x10, /* Linear (0) | Non Linear (1) */
44 INPUT_PREFSTATE = 0x20, /* Preferred State (0) | No Preferred (1) */
45 INPUT_NULL = 0x40, /* No Null position (0) | Null state(1) */
46 INPUT_VOLATILE = 0x80, /* Non Volatile (0) | Volatile (1) */
47 INPUT_BITFIELD = 0x100 /* Bit Field (0) | Buffered Bytes (1) */
50 enum {
51 TAG_TYPE_MAIN = 0x0,
52 TAG_TYPE_GLOBAL,
53 TAG_TYPE_LOCAL,
54 TAG_TYPE_RESERVED,
57 enum {
58 TAG_MAIN_INPUT = 0x08,
59 TAG_MAIN_OUTPUT = 0x09,
60 TAG_MAIN_FEATURE = 0x0B,
61 TAG_MAIN_COLLECTION = 0x0A,
62 TAG_MAIN_END_COLLECTION = 0x0C
65 enum {
66 TAG_GLOBAL_USAGE_PAGE = 0x0,
67 TAG_GLOBAL_LOGICAL_MINIMUM,
68 TAG_GLOBAL_LOGICAL_MAXIMUM,
69 TAG_GLOBAL_PHYSICAL_MINIMUM,
70 TAG_GLOBAL_PHYSICAL_MAXIMUM,
71 TAG_GLOBAL_UNIT_EXPONENT,
72 TAG_GLOBAL_UNIT,
73 TAG_GLOBAL_REPORT_SIZE,
74 TAG_GLOBAL_REPORT_ID,
75 TAG_GLOBAL_REPORT_COUNT,
76 TAG_GLOBAL_PUSH,
77 TAG_GLOBAL_POP
80 enum {
81 TAG_LOCAL_USAGE = 0x0,
82 TAG_LOCAL_USAGE_MINIMUM,
83 TAG_LOCAL_USAGE_MAXIMUM,
84 TAG_LOCAL_DESIGNATOR_INDEX,
85 TAG_LOCAL_DESIGNATOR_MINIMUM,
86 TAG_LOCAL_DESIGNATOR_MAXIMUM,
87 TAG_LOCAL_STRING_INDEX,
88 TAG_LOCAL_STRING_MINIMUM,
89 TAG_LOCAL_STRING_MAXIMUM,
90 TAG_LOCAL_DELIMITER
94 static const char* const feature_string[] =
95 { "Input", "Output", "Feature" };
97 struct caps {
98 USAGE UsagePage;
99 LONG LogicalMin;
100 LONG LogicalMax;
101 LONG PhysicalMin;
102 LONG PhysicalMax;
103 ULONG UnitsExp;
104 ULONG Units;
105 USHORT BitSize;
106 UCHAR ReportID;
107 USHORT ReportCount;
109 BOOLEAN IsRange;
110 BOOLEAN IsStringRange;
111 BOOLEAN IsDesignatorRange;
112 unsigned int usage_count;
113 union {
114 struct {
115 USAGE UsageMin;
116 USAGE UsageMax;
117 USHORT StringMin;
118 USHORT StringMax;
119 USHORT DesignatorMin;
120 USHORT DesignatorMax;
121 } Range;
122 struct {
123 USAGE Usage[USAGE_MAX];
124 USAGE Reserved1;
125 USHORT StringIndex;
126 USHORT Reserved2;
127 USHORT DesignatorIndex;
128 USHORT Reserved3;
129 } NotRange;
130 } DUMMYUNIONNAME;
132 int Delim;
135 struct feature {
136 struct list entry;
137 struct list col_entry;
138 struct caps caps;
140 HIDP_REPORT_TYPE type;
141 BOOLEAN isData;
142 BOOLEAN isArray;
143 BOOLEAN IsAbsolute;
144 BOOLEAN Wrap;
145 BOOLEAN Linear;
146 BOOLEAN prefState;
147 BOOLEAN HasNull;
148 BOOLEAN Volatile;
149 BOOLEAN BitField;
151 unsigned int index;
152 struct collection *collection;
155 static const char* const collection_string[] = {
156 "Physical",
157 "Application",
158 "Logical",
159 "Report",
160 "Named Array",
161 "Usage Switch",
162 "Usage Modifier",
165 struct collection {
166 struct list entry;
167 struct caps caps;
168 unsigned int index;
169 unsigned int type;
170 struct collection *parent;
171 struct list features;
172 struct list collections;
175 static const char* debugstr_usages(struct caps *caps)
177 if (!caps->IsRange)
179 char out[12 * USAGE_MAX];
180 unsigned int i;
181 if (caps->usage_count == 0)
182 return "[ none ]";
183 out[0] = 0;
184 for (i = 0; i < caps->usage_count; i++)
185 sprintf(out + strlen(out), "0x%x ", caps->u.NotRange.Usage[i]);
186 return wine_dbg_sprintf("[ %s] ", out);
188 else
189 return wine_dbg_sprintf("[0x%x - 0x%x]", caps->u.Range.UsageMin, caps->u.Range.UsageMax);
192 static const char* debugstr_stringindex(struct caps *caps)
194 if (!caps->IsStringRange)
195 return wine_dbg_sprintf("%i", caps->u.NotRange.StringIndex);
196 else
197 return wine_dbg_sprintf("[%i - %i]", caps->u.Range.StringMin, caps->u.Range.StringMax);
200 static const char* debugstr_designatorindex(struct caps *caps)
202 if (!caps->IsDesignatorRange)
203 return wine_dbg_sprintf("%i", caps->u.NotRange.DesignatorIndex);
204 else
205 return wine_dbg_sprintf("[%i - %i]", caps->u.Range.DesignatorMin, caps->u.Range.DesignatorMax);
208 static void debugstr_caps(const char* type, struct caps *caps)
210 if (!caps)
211 return;
212 TRACE("(%s Caps: UsagePage 0x%x; LogicalMin %i; LogicalMax %i; PhysicalMin %i; PhysicalMax %i; UnitsExp %i; Units %i; BitSize %i; ReportID %i; ReportCount %i; Usage %s; StringIndex %s; DesignatorIndex %s; Delim %i;)\n",
213 type,
214 caps->UsagePage,
215 caps->LogicalMin,
216 caps->LogicalMax,
217 caps->PhysicalMin,
218 caps->PhysicalMax,
219 caps->UnitsExp,
220 caps->Units,
221 caps->BitSize,
222 caps->ReportID,
223 caps->ReportCount,
224 debugstr_usages(caps),
225 debugstr_stringindex(caps),
226 debugstr_designatorindex(caps),
227 caps->Delim);
230 static void debug_feature(struct feature *feature)
232 if (!feature)
233 return;
234 TRACE("[Feature type %s [%i]; %s; %s; %s; %s; %s; %s; %s; %s; %s]\n",
235 feature_string[feature->type],
236 feature->index,
237 (feature->isData)?"Data":"Const",
238 (feature->isArray)?"Array":"Var",
239 (feature->IsAbsolute)?"Abs":"Rel",
240 (feature->Wrap)?"Wrap":"NoWrap",
241 (feature->Linear)?"Linear":"NonLinear",
242 (feature->prefState)?"PrefStat":"NoPrefState",
243 (feature->HasNull)?"HasNull":"NoNull",
244 (feature->Volatile)?"Volatile":"NonVolatile",
245 (feature->BitField)?"BitField":"Buffered");
247 debugstr_caps("Feature", &feature->caps);
250 static void debug_collection(struct collection *collection)
252 struct feature *fentry;
253 struct collection *centry;
254 if (TRACE_ON(hid))
256 TRACE("START Collection %i <<< %s, parent: %p, %i features, %i collections\n", collection->index, collection_string[collection->type], collection->parent, list_count(&collection->features), list_count(&collection->collections));
257 debugstr_caps("Collection", &collection->caps);
258 LIST_FOR_EACH_ENTRY(fentry, &collection->features, struct feature, col_entry)
259 debug_feature(fentry);
260 LIST_FOR_EACH_ENTRY(centry, &collection->collections, struct collection, entry)
261 debug_collection(centry);
262 TRACE(">>> END Collection %i\n", collection->index);
266 static void debug_print_button_cap(const CHAR * type, WINE_HID_ELEMENT *wine_element)
268 if (!wine_element->caps.button.IsRange)
269 TRACE("%s Button: 0x%x/0x%04x: ReportId %i, startBit %i/1\n" , type,
270 wine_element->caps.button.UsagePage,
271 wine_element->caps.button.u.NotRange.Usage,
272 wine_element->caps.value.ReportID,
273 wine_element->valueStartBit);
274 else
275 TRACE("%s Button: 0x%x/[0x%04x-0x%04x]: ReportId %i, startBit %i/%i\n" ,type,
276 wine_element->caps.button.UsagePage,
277 wine_element->caps.button.u.Range.UsageMin,
278 wine_element->caps.button.u.Range.UsageMax,
279 wine_element->caps.value.ReportID,
280 wine_element->valueStartBit,
281 wine_element->bitCount);
284 static void debug_print_value_cap(const CHAR * type, WINE_HID_ELEMENT *wine_element)
286 TRACE("%s Value: 0x%x/0x%x: ReportId %i, IsAbsolute %i, HasNull %i, "
287 "Bit Size %i, ReportCount %i, UnitsExp %i, Units %i, "
288 "LogicalMin %i, Logical Max %i, PhysicalMin %i, "
289 "PhysicalMax %i -- StartBit %i/%i\n", type,
290 wine_element->caps.value.UsagePage,
291 wine_element->caps.value.u.NotRange.Usage,
292 wine_element->caps.value.ReportID,
293 wine_element->caps.value.IsAbsolute,
294 wine_element->caps.value.HasNull,
295 wine_element->caps.value.BitSize,
296 wine_element->caps.value.ReportCount,
297 wine_element->caps.value.UnitsExp,
298 wine_element->caps.value.Units,
299 wine_element->caps.value.LogicalMin,
300 wine_element->caps.value.LogicalMax,
301 wine_element->caps.value.PhysicalMin,
302 wine_element->caps.value.PhysicalMax,
303 wine_element->valueStartBit,
304 wine_element->bitCount);
307 static void debug_print_element(const CHAR* type, WINE_HID_ELEMENT *wine_element)
309 if (wine_element->ElementType == ButtonElement)
310 debug_print_button_cap(type, wine_element);
311 else if (wine_element->ElementType == ValueElement)
312 debug_print_value_cap(type, wine_element);
313 else
314 TRACE("%s: UNKNOWN\n", type);
317 static void debug_print_report(const char* type, WINE_HID_REPORT *report)
319 unsigned int i;
320 TRACE("START Report %i <<< %s report : dwSize: %i elementCount: %i\n",
321 report->reportID,
322 type,
323 report->dwSize,
324 report->elementCount);
325 for (i = 0; i < report->elementCount; i++)
326 debug_print_element(type, &report->Elements[i]);
327 TRACE(">>> END Report %i\n",report->reportID);
330 static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data)
332 unsigned int i;
333 WINE_HID_REPORT *r;
334 if (TRACE_ON(hid))
336 TRACE("START PREPARSED Data <<< dwSize: %i Usage: %i, UsagePage: %i, InputReportByteLength: %i, tOutputReportByteLength: %i, FeatureReportByteLength: %i, NumberLinkCollectionNodes: %i, NumberInputButtonCaps: %i, NumberInputValueCaps: %i,NumberInputDataIndices: %i, NumberOutputButtonCaps: %i, NumberOutputValueCaps: %i, NumberOutputDataIndices: %i, NumberFeatureButtonCaps: %i, NumberFeatureValueCaps: %i, NumberFeatureDataIndices: %i, dwInputReportCount: %i, dwOutputReportCount: %i, dwFeatureReportCount: %i, dwOutputReportOffset: %i, dwFeatureReportOffset: %i\n",
337 data->dwSize,
338 data->caps.Usage,
339 data->caps.UsagePage,
340 data->caps.InputReportByteLength,
341 data->caps.OutputReportByteLength,
342 data->caps.FeatureReportByteLength,
343 data->caps.NumberLinkCollectionNodes,
344 data->caps.NumberInputButtonCaps,
345 data->caps.NumberInputValueCaps,
346 data->caps.NumberInputDataIndices,
347 data->caps.NumberOutputButtonCaps,
348 data->caps.NumberOutputValueCaps,
349 data->caps.NumberOutputDataIndices,
350 data->caps.NumberFeatureButtonCaps,
351 data->caps.NumberFeatureValueCaps,
352 data->caps.NumberFeatureDataIndices,
353 data->dwInputReportCount,
354 data->dwOutputReportCount,
355 data->dwFeatureReportCount,
356 data->dwOutputReportOffset,
357 data->dwFeatureReportOffset);
359 r = HID_INPUT_REPORTS(data);
360 for (i = 0; i < data->dwInputReportCount; i++)
362 debug_print_report("INPUT", r);
363 r = HID_NEXT_REPORT(data, r);
365 r = HID_OUTPUT_REPORTS(data);
366 for (i = 0; i < data->dwOutputReportCount; i++)
368 debug_print_report("OUTPUT", r);
369 r = HID_NEXT_REPORT(data, r);
371 r = HID_FEATURE_REPORTS(data);
372 for (i = 0; i < data->dwFeatureReportCount; i++)
374 debug_print_report("FEATURE", r);
375 r = HID_NEXT_REPORT(data, r);
377 TRACE(">>> END Preparsed Data\n");
381 static int getValue(int bsize, int source)
383 int mask = 0xff;
384 int negative = 0x80;
385 int outofrange = 0x100;
386 int value;
387 unsigned int i;
389 if (bsize == 4)
390 return source;
392 for (i = 1; i < bsize; i++)
394 mask = (mask<<8) + 0xff;
395 negative = (negative<<8);
396 outofrange = (outofrange<<8);
398 value = (source&mask);
399 if (value&negative)
400 value = -1 * (outofrange - value);
401 return value;
404 static void parse_io_feature(unsigned int bSize, int itemVal, int bTag,
405 unsigned int *feature_index,
406 struct feature *feature)
408 if (bSize <= 0)
410 return;
412 else
414 feature->isData = ((itemVal & INPUT_DATA_CONST) == 0);
415 feature->isArray = ((itemVal & INPUT_ARRAY_VAR) == 0);
416 feature->IsAbsolute = ((itemVal & INPUT_ABS_REL) == 0);
417 feature->Wrap = ((itemVal & INPUT_WRAP) != 0);
418 feature->Linear = ((itemVal & INPUT_LINEAR) == 0);
419 feature->prefState = ((itemVal & INPUT_PREFSTATE) == 0);
420 feature->HasNull = ((itemVal & INPUT_NULL) != 0);
422 if (bTag != TAG_MAIN_INPUT)
424 feature->Volatile = ((itemVal & INPUT_VOLATILE) != 0);
426 if (bSize > 1)
428 feature->BitField = ((itemVal & INPUT_BITFIELD) == 0);
430 feature->index = *feature_index;
431 *feature_index = *feature_index + 1;
435 static void parse_collection(unsigned int bSize, int itemVal,
436 struct collection *collection)
438 if (bSize <= 0)
439 return;
440 else
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->usage_count = 0;
461 static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int length, unsigned int *feature_index, unsigned int *collection_index, struct collection *collection, struct caps *caps, struct list *features)
463 unsigned int i;
464 for (i = index; i < length;)
466 BYTE b0 = descriptor[i++];
467 int bSize = b0 & 0x03;
468 int bType = (b0 >> 2) & 0x03;
469 int bTag = (b0 >> 4) & 0x0F;
471 bSize = (bSize == 3) ? 4 : bSize;
472 if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && bSize == 2 &&
473 i + 2 < length)
475 /* Long data items: Should be unused */
476 ERR("Long Data Item, should be unused\n");
478 else
480 int bSizeActual = 0;
481 int itemVal = 0;
482 unsigned int j;
484 for (j = 0; j < bSize; j++)
486 if (i + j < length)
488 itemVal += descriptor[i + j] << (8 * j);
489 bSizeActual++;
492 TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-1,bType, bTag, bSize, itemVal );
494 if (bType == TAG_TYPE_MAIN)
496 struct feature *feature;
497 switch(bTag)
499 case TAG_MAIN_INPUT:
500 feature = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*feature));
501 list_add_tail(&collection->features, &feature->col_entry);
502 list_add_tail(features, &feature->entry);
503 feature->type = HidP_Input;
504 parse_io_feature(bSize, itemVal, bTag, feature_index, feature);
505 feature->caps = *caps;
506 feature->collection = collection;
507 new_caps(caps);
508 break;
509 case TAG_MAIN_OUTPUT:
510 feature = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*feature));
511 list_add_tail(&collection->features, &feature->col_entry);
512 list_add_tail(features, &feature->entry);
513 feature->type = HidP_Output;
514 parse_io_feature(bSize, itemVal, bTag, feature_index, feature);
515 feature->caps = *caps;
516 feature->collection = collection;
517 new_caps(caps);
518 break;
519 case TAG_MAIN_FEATURE:
520 feature = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*feature));
521 list_add_tail(&collection->features, &feature->col_entry);
522 list_add_tail(features, &feature->entry);
523 feature->type = HidP_Feature;
524 parse_io_feature(bSize, itemVal, bTag, feature_index, feature);
525 feature->caps = *caps;
526 feature->collection = collection;
527 new_caps(caps);
528 break;
529 case TAG_MAIN_COLLECTION:
531 struct collection *subcollection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct collection));
532 list_add_tail(&collection->collections, &subcollection->entry);
533 subcollection->parent = collection;
534 /* Only set our collection once...
535 We do not properly handle composite devices yet. */
536 if (*collection_index == 0)
537 collection->caps = *caps;
538 subcollection->caps = *caps;
539 subcollection->index = *collection_index;
540 *collection_index = *collection_index + 1;
541 list_init(&subcollection->features);
542 list_init(&subcollection->collections);
543 new_caps(caps);
545 parse_collection(bSize, itemVal, subcollection);
547 i = parse_descriptor(descriptor, i+1, length, feature_index, collection_index, subcollection, caps, features);
548 continue;
550 case TAG_MAIN_END_COLLECTION:
551 return i;
552 default:
553 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
556 else if (bType == TAG_TYPE_GLOBAL)
558 switch(bTag)
560 case TAG_GLOBAL_USAGE_PAGE:
561 caps->UsagePage = getValue(bSize, itemVal);
562 break;
563 case TAG_GLOBAL_LOGICAL_MINIMUM:
564 caps->LogicalMin = getValue(bSize, itemVal);
565 break;
566 case TAG_GLOBAL_LOGICAL_MAXIMUM:
567 caps->LogicalMax = getValue(bSize, itemVal);
568 break;
569 case TAG_GLOBAL_PHYSICAL_MINIMUM:
570 caps->PhysicalMin = getValue(bSize, itemVal);
571 break;
572 case TAG_GLOBAL_PHYSICAL_MAXIMUM:
573 caps->PhysicalMax = getValue(bSize, itemVal);
574 break;
575 case TAG_GLOBAL_UNIT_EXPONENT:
576 caps->UnitsExp = getValue(bSize, itemVal);
577 break;
578 case TAG_GLOBAL_UNIT:
579 caps->Units = getValue(bSize, itemVal);
580 break;
581 case TAG_GLOBAL_REPORT_SIZE:
582 caps->BitSize = getValue(bSize, itemVal);
583 break;
584 case TAG_GLOBAL_REPORT_ID:
585 caps->ReportID = getValue(bSize, itemVal);
586 break;
587 case TAG_GLOBAL_REPORT_COUNT:
588 caps->ReportCount = getValue(bSize, itemVal);
589 break;
590 case TAG_GLOBAL_PUSH:
591 FIXME("Unhandled Push\n");
592 break;
593 case TAG_GLOBAL_POP:
594 FIXME("Unhandled Pop\n");
595 break;
596 default:
597 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
600 else if (bType == TAG_TYPE_LOCAL)
602 switch(bTag)
604 case TAG_LOCAL_USAGE:
605 if (caps->usage_count >= USAGE_MAX)
606 FIXME("More than %i individual usages defined\n",USAGE_MAX);
607 else
609 caps->u.NotRange.Usage[caps->usage_count++] = getValue(bSize, itemVal);
610 caps->IsRange = FALSE;
612 break;
613 case TAG_LOCAL_USAGE_MINIMUM:
614 caps->usage_count = 1;
615 caps->u.Range.UsageMin = getValue(bSize, itemVal);
616 caps->IsRange = TRUE;
617 break;
618 case TAG_LOCAL_USAGE_MAXIMUM:
619 caps->usage_count = 1;
620 caps->u.Range.UsageMax = getValue(bSize, itemVal);
621 caps->IsRange = TRUE;
622 break;
623 case TAG_LOCAL_DESIGNATOR_INDEX:
624 caps->u.NotRange.DesignatorIndex = getValue(bSize, itemVal);
625 caps->IsDesignatorRange = FALSE;
626 break;
627 case TAG_LOCAL_DESIGNATOR_MINIMUM:
628 caps->u.Range.DesignatorMin = getValue(bSize, itemVal);
629 caps->IsDesignatorRange = TRUE;
630 break;
631 case TAG_LOCAL_DESIGNATOR_MAXIMUM:
632 caps->u.Range.DesignatorMax = getValue(bSize, itemVal);
633 caps->IsDesignatorRange = TRUE;
634 break;
635 case TAG_LOCAL_STRING_INDEX:
636 caps->u.NotRange.StringIndex = getValue(bSize, itemVal);
637 caps->IsStringRange = FALSE;
638 break;
639 case TAG_LOCAL_STRING_MINIMUM:
640 caps->u.Range.StringMin = getValue(bSize, itemVal);
641 caps->IsStringRange = TRUE;
642 break;
643 case TAG_LOCAL_STRING_MAXIMUM:
644 caps->u.Range.StringMax = getValue(bSize, itemVal);
645 caps->IsStringRange = TRUE;
646 break;
647 case TAG_LOCAL_DELIMITER:
648 caps->Delim = getValue(bSize, itemVal);
649 break;
650 default:
651 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
654 else
655 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType);
657 i += bSize;
660 return i;
663 static inline void new_report(WINE_HID_REPORT *wine_report, struct feature* feature)
665 wine_report->reportID = feature->caps.ReportID;
666 wine_report->dwSize = sizeof(*wine_report) - sizeof(WINE_HID_ELEMENT);
667 wine_report->elementCount = 0;
670 static void build_elements(WINE_HID_REPORT *wine_report, struct feature* feature, DWORD *bitOffset)
672 unsigned int i;
674 if (!feature->isData)
676 *bitOffset = *bitOffset + (feature->caps.BitSize * feature->caps.ReportCount);
677 return;
680 for (i = 0; i < feature->caps.usage_count; i++)
682 WINE_HID_ELEMENT *wine_element = &wine_report->Elements[wine_report->elementCount];
684 wine_element->valueStartBit = *bitOffset;
685 if (feature->caps.UsagePage == HID_USAGE_PAGE_BUTTON)
687 wine_element->ElementType = ButtonElement;
688 wine_element->caps.button.UsagePage = feature->caps.UsagePage;
689 wine_element->caps.button.ReportID = feature->caps.ReportID;
690 wine_element->caps.button.BitField = feature->BitField;
691 wine_element->caps.button.IsRange = feature->caps.IsRange;
692 wine_element->caps.button.IsStringRange = feature->caps.IsStringRange;
693 wine_element->caps.button.IsDesignatorRange = feature->caps.IsDesignatorRange;
694 wine_element->caps.button.IsAbsolute = feature->IsAbsolute;
695 if (wine_element->caps.button.IsRange)
697 wine_element->bitCount = (feature->caps.u.Range.UsageMax - feature->caps.u.Range.UsageMin) + 1;
698 *bitOffset = *bitOffset + wine_element->bitCount;
699 wine_element->caps.button.u.Range.UsageMin = feature->caps.u.Range.UsageMin;
700 wine_element->caps.button.u.Range.UsageMax = feature->caps.u.Range.UsageMax;
701 wine_element->caps.button.u.Range.StringMin = feature->caps.u.Range.StringMin;
702 wine_element->caps.button.u.Range.StringMax = feature->caps.u.Range.StringMax;
703 wine_element->caps.button.u.Range.DesignatorMin = feature->caps.u.Range.DesignatorMin;
704 wine_element->caps.button.u.Range.DesignatorMax = feature->caps.u.Range.DesignatorMax;
706 else
708 *bitOffset = *bitOffset + 1;
709 wine_element->bitCount = 1;
710 wine_element->caps.button.u.NotRange.Usage = feature->caps.u.NotRange.Usage[i];
711 wine_element->caps.button.u.NotRange.StringIndex = feature->caps.u.NotRange.StringIndex;
712 wine_element->caps.button.u.NotRange.DesignatorIndex = feature->caps.u.NotRange.DesignatorIndex;
715 else
717 wine_element->ElementType = ValueElement;
718 wine_element->caps.value.UsagePage = feature->caps.UsagePage;
719 wine_element->caps.value.ReportID = feature->caps.ReportID;
720 wine_element->caps.value.BitField = feature->BitField;
721 wine_element->caps.value.IsRange = feature->caps.IsRange;
722 wine_element->caps.value.IsStringRange = feature->caps.IsStringRange;
723 wine_element->caps.value.IsDesignatorRange = feature->caps.IsDesignatorRange;
724 wine_element->caps.value.IsAbsolute = feature->IsAbsolute;
725 wine_element->caps.value.HasNull = feature->HasNull;
726 wine_element->caps.value.BitSize = feature->caps.BitSize;
727 if (feature->caps.usage_count > 1)
728 wine_element->caps.value.ReportCount = 1;
729 else
730 wine_element->caps.value.ReportCount = feature->caps.ReportCount;
731 wine_element->bitCount = (feature->caps.BitSize * wine_element->caps.value.ReportCount);
732 *bitOffset = *bitOffset + wine_element->bitCount;
733 wine_element->caps.value.UnitsExp = feature->caps.UnitsExp;
734 wine_element->caps.value.Units = feature->caps.Units;
735 wine_element->caps.value.LogicalMin = feature->caps.LogicalMin;
736 wine_element->caps.value.LogicalMax = feature->caps.LogicalMax;
737 wine_element->caps.value.PhysicalMin = feature->caps.PhysicalMin;
738 wine_element->caps.value.PhysicalMax = feature->caps.PhysicalMax;
739 if (wine_element->caps.value.IsRange)
741 wine_element->caps.value.u.Range.UsageMin = feature->caps.u.Range.UsageMin;
742 wine_element->caps.value.u.Range.UsageMax = feature->caps.u.Range.UsageMax;
743 wine_element->caps.value.u.Range.StringMin = feature->caps.u.Range.StringMin;
744 wine_element->caps.value.u.Range.StringMax = feature->caps.u.Range.StringMax;
745 wine_element->caps.value.u.Range.DesignatorMin = feature->caps.u.Range.DesignatorMin;
746 wine_element->caps.value.u.Range.DesignatorMax = feature->caps.u.Range.DesignatorMax;
748 else
750 wine_element->caps.value.u.NotRange.Usage = feature->caps.u.NotRange.Usage[i];
751 wine_element->caps.value.u.NotRange.StringIndex = feature->caps.u.NotRange.StringIndex;
752 wine_element->caps.value.u.NotRange.DesignatorIndex = feature->caps.u.NotRange.DesignatorIndex;
756 wine_report->elementCount++;
760 static void count_elements(struct feature* feature, USHORT *buttons, USHORT *values)
762 if (feature->caps.UsagePage == HID_USAGE_PAGE_BUTTON)
764 if (feature->caps.IsRange)
765 *buttons = *buttons + 1;
766 else
767 *buttons = *buttons + feature->caps.usage_count;
769 else
771 if (feature->caps.IsRange)
772 *values = *values + 1;
773 else
774 *values = *values + feature->caps.usage_count;
778 static WINE_HIDP_PREPARSED_DATA* build_PreparseData(
779 struct feature **features, int feature_count,
780 struct feature **input_features, int i_count,
781 struct feature **output_features, int o_count,
782 struct feature **feature_features, int f_count,
783 struct collection *base_collection)
785 WINE_HIDP_PREPARSED_DATA *data;
786 WINE_HID_REPORT *wine_report = NULL;
787 DWORD bitOffset, bitLength;
788 unsigned int report_count = 1;
789 unsigned int i;
790 unsigned int element_count;
791 unsigned int size = 0;
793 if (features[0]->caps.ReportID != 0)
795 unsigned int *report_ids;
796 unsigned int cnt = max(i_count, o_count);
797 cnt = max(cnt, f_count);
798 report_ids = HeapAlloc(GetProcessHeap(), 0 , sizeof(*report_ids) * cnt);
800 if (i_count)
802 report_ids[0] = input_features[0]->caps.ReportID;
803 for (i = 1; i < i_count; i++)
805 unsigned int j;
806 unsigned int found = FALSE;
807 for (j = 0; !found && j < i_count; j++)
809 if (report_ids[j] == input_features[i]->caps.ReportID)
810 found = TRUE;
812 if (!found)
814 report_ids[report_count] = input_features[i]->caps.ReportID;
815 report_count++;
819 if (o_count)
821 report_count++;
822 report_ids[0] = output_features[0]->caps.ReportID;
823 for (i = 1; i < o_count; i++)
825 unsigned int j;
826 unsigned int found = FALSE;
827 for (j = 0; !found && j < o_count; j++)
829 if (report_ids[j] == output_features[i]->caps.ReportID)
830 found = TRUE;
832 if (!found)
834 report_ids[report_count] = output_features[i]->caps.ReportID;
835 report_count++;
839 if (f_count)
841 report_count++;
842 report_ids[0] = feature_features[0]->caps.ReportID;
843 for (i = 1; i < f_count; i++)
845 unsigned int j;
846 unsigned int found = FALSE;
847 for (j = 0; !found && j < f_count; j++)
849 if (report_ids[j] == feature_features[i]->caps.ReportID)
850 found = TRUE;
852 if (!found)
854 report_ids[report_count] = feature_features[i]->caps.ReportID;
855 report_count++;
859 HeapFree(GetProcessHeap(), 0, report_ids);
861 else
863 if (o_count) report_count++;
864 if (f_count) report_count++;
867 element_count = 0;
868 for (i = 0; i < feature_count; i++)
869 element_count += features[i]->caps.usage_count;
871 size = sizeof(WINE_HIDP_PREPARSED_DATA) +
872 (element_count * sizeof(WINE_HID_ELEMENT)) +
873 (report_count * sizeof(WINE_HID_REPORT));
875 TRACE("%i reports %i elements -> size %i\n",report_count, element_count, size);
877 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
878 data->magic = HID_MAGIC;
879 data->dwSize = size;
880 data->caps.Usage = base_collection->caps.u.NotRange.Usage[0];
881 data->caps.UsagePage = base_collection->caps.UsagePage;
883 wine_report = data->InputReports;
884 if (i_count)
886 bitLength = 0;
887 new_report(wine_report, input_features[0]);
888 data->dwInputReportCount++;
890 if (input_features[0]->caps.ReportID != 0)
891 bitOffset = 8;
892 else
893 bitOffset = 0;
895 for (i = 0; i < i_count; i++)
897 if (input_features[i]->caps.ReportID != wine_report->reportID)
899 wine_report->dwSize += (sizeof(WINE_HID_ELEMENT) * wine_report->elementCount);
900 wine_report = (WINE_HID_REPORT*)(((BYTE*)wine_report)+wine_report->dwSize);
901 new_report(wine_report, input_features[i]);
902 data->dwInputReportCount++;
903 bitLength = max(bitOffset, bitLength);
904 if (input_features[i]->caps.ReportID != 0)
905 bitOffset = 8;
906 else
907 bitOffset = 0;
909 build_elements(wine_report, input_features[i], &bitOffset);
910 count_elements(input_features[i], &data->caps.NumberInputButtonCaps,
911 &data->caps.NumberInputValueCaps);
913 wine_report->dwSize += (sizeof(WINE_HID_ELEMENT) * wine_report->elementCount);
914 bitLength = max(bitOffset, bitLength);
915 data->caps.InputReportByteLength = ((bitLength + 7) & ~7)/8;
918 if (o_count)
920 bitLength = 0;
921 wine_report = (WINE_HID_REPORT*)(((BYTE*)wine_report)+wine_report->dwSize);
922 data->dwOutputReportOffset = (BYTE*)wine_report - (BYTE*)data->InputReports;
923 new_report(wine_report, output_features[0]);
924 data->dwOutputReportCount++;
925 if (output_features[0]->caps.ReportID != 0)
926 bitOffset = 8;
927 else
928 bitOffset = 0;
930 for (i = 0; i < o_count; i++)
932 if (output_features[i]->caps.ReportID != wine_report->reportID)
934 wine_report->dwSize += (sizeof(WINE_HID_ELEMENT) * wine_report->elementCount);
935 wine_report = (WINE_HID_REPORT*)(((BYTE*)wine_report)+wine_report->dwSize);
936 new_report(wine_report, output_features[i]);
937 data->dwOutputReportCount++;
938 bitLength = max(bitOffset, bitLength);
939 if (output_features[0]->caps.ReportID != 0)
940 bitOffset = 8;
941 else
942 bitOffset = 0;
944 build_elements(wine_report, output_features[i], &bitOffset);
945 count_elements(output_features[i], &data->caps.NumberOutputButtonCaps,
946 &data->caps.NumberOutputValueCaps);
948 wine_report->dwSize += (sizeof(WINE_HID_ELEMENT) * wine_report->elementCount);
949 bitLength = max(bitOffset, bitLength);
950 data->caps.OutputReportByteLength = ((bitLength + 7) & ~7)/8;
953 if (f_count)
955 bitLength = 0;
956 wine_report = (WINE_HID_REPORT*)(((BYTE*)wine_report)+wine_report->dwSize);
957 data->dwFeatureReportOffset = (BYTE*)wine_report - (BYTE*)data->InputReports;
958 new_report(wine_report, feature_features[0]);
959 data->dwFeatureReportCount++;
960 if (feature_features[0]->caps.ReportID != 0)
961 bitOffset = 8;
962 else
963 bitOffset = 0;
965 for (i = 0; i < f_count; i++)
967 if (feature_features[i]->caps.ReportID != wine_report->reportID)
969 wine_report->dwSize += (sizeof(WINE_HID_ELEMENT) * wine_report->elementCount);
970 wine_report = (WINE_HID_REPORT*)((BYTE*)wine_report+wine_report->dwSize);
971 new_report(wine_report, feature_features[i]);
972 data->dwFeatureReportCount++;
973 bitLength = max(bitOffset, bitLength);
974 if (feature_features[0]->caps.ReportID != 0)
975 bitOffset = 8;
976 else
977 bitOffset = 0;
979 build_elements(wine_report, feature_features[i], &bitOffset);
980 count_elements(feature_features[i], &data->caps.NumberFeatureButtonCaps,
981 &data->caps.NumberFeatureValueCaps);
983 bitLength = max(bitOffset, bitLength);
984 data->caps.FeatureReportByteLength = ((bitLength + 7) & ~7)/8;
987 return data;
990 static void free_collection(struct collection *collection)
992 struct feature *fentry, *fnext;
993 struct collection *centry, *cnext;
994 LIST_FOR_EACH_ENTRY_SAFE(centry, cnext, &collection->collections, struct collection, entry)
996 list_remove(&centry->entry);
997 free_collection(centry);
999 LIST_FOR_EACH_ENTRY_SAFE(fentry, fnext, &collection->features, struct feature, col_entry)
1001 list_remove(&fentry->col_entry);
1002 HeapFree(GetProcessHeap(), 0, fentry);
1004 HeapFree(GetProcessHeap(), 0, collection);
1007 static int compare_reports(const void *a, const void* b)
1009 struct feature *f1 = *(struct feature **)a;
1010 struct feature *f2 = *(struct feature **)b;
1011 int c = (f1->caps.ReportID - f2->caps.ReportID);
1012 if (c) return c;
1013 return (f1->index - f2->index);
1016 WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
1018 WINE_HIDP_PREPARSED_DATA *data = NULL;
1019 struct collection *base;
1020 struct caps caps;
1022 struct list features;
1024 unsigned int feature_count = 0;
1025 unsigned int cidx;
1027 if (TRACE_ON(hid))
1029 TRACE("Descriptor[%i]: ", length);
1030 for (cidx = 0; cidx < length; cidx++)
1032 TRACE("%x ",descriptor[cidx]);
1033 if ((cidx+1) % 80 == 0)
1034 TRACE("\n");
1036 TRACE("\n");
1039 list_init(&features);
1041 base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*base));
1042 base->index = 1;
1043 list_init(&base->features);
1044 list_init(&base->collections);
1045 memset(&caps, 0, sizeof(caps));
1047 cidx = 0;
1048 parse_descriptor(descriptor, 0, length, &feature_count, &cidx, base, &caps, &features);
1050 debug_collection(base);
1052 cidx = 2;
1053 if (feature_count)
1055 struct feature *entry;
1056 struct feature** sorted_features;
1057 struct feature** input_features;
1058 struct feature** output_features;
1059 struct feature** feature_features;
1060 unsigned int i_count, o_count, f_count;
1061 unsigned int i;
1063 i_count = o_count = f_count = 0;
1065 sorted_features = HeapAlloc(GetProcessHeap(), 0, sizeof(*sorted_features) * feature_count);
1066 input_features = HeapAlloc(GetProcessHeap(), 0, sizeof(*input_features) * feature_count);
1067 output_features = HeapAlloc(GetProcessHeap(), 0, sizeof(*output_features) * feature_count);
1068 feature_features = HeapAlloc(GetProcessHeap(), 0, sizeof(*feature_features) * feature_count);
1070 i = 0;
1071 LIST_FOR_EACH_ENTRY(entry, &features, struct feature, entry)
1072 sorted_features[i++] = entry;
1074 /* Sort features base on report if there are multiple reports */
1075 if (sorted_features[0]->caps.ReportID != 0)
1076 qsort(sorted_features, feature_count, sizeof(struct feature*), compare_reports);
1078 for (i = 0; i < feature_count; i++)
1080 switch (sorted_features[i]->type)
1082 case HidP_Input:
1083 input_features[i_count] = sorted_features[i];
1084 i_count++;
1085 break;
1086 case HidP_Output:
1087 output_features[o_count] = sorted_features[i];
1088 o_count++;
1089 break;
1090 case HidP_Feature:
1091 feature_features[f_count] = sorted_features[i];
1092 f_count++;
1093 break;
1094 default:
1095 ERR("Unknown type %i\n",sorted_features[i]->type);
1099 if (TRACE_ON(hid))
1101 TRACE("DUMP FEATURES:\n");
1102 TRACE("----INPUT----\n");
1103 for (cidx = 0; cidx < i_count; cidx++)
1104 debug_feature(input_features[cidx]);
1105 TRACE("----OUTPUT----\n");
1106 for (cidx = 0; cidx < o_count; cidx++)
1107 debug_feature(output_features[cidx]);
1108 TRACE("----FEATURE----\n");
1109 for (cidx = 0; cidx < f_count; cidx++)
1110 debug_feature(feature_features[cidx]);
1113 data = build_PreparseData(sorted_features, feature_count, input_features, i_count, output_features, o_count, feature_features, f_count, base);
1115 debug_print_preparsed(data);
1117 HeapFree(GetProcessHeap(), 0, sorted_features);
1118 HeapFree(GetProcessHeap(), 0, input_features);
1119 HeapFree(GetProcessHeap(), 0, output_features);
1120 HeapFree(GetProcessHeap(), 0, feature_features);
1123 free_collection(base);
1124 /* We do not have to free the list as free_collection does all the work */
1126 return data;