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
26 #define NONAMELESSUNION
29 #include "wine/debug.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
42 INPUT_PREFSTATE
= 0x20,
44 INPUT_VOLATILE
= 0x80,
45 INPUT_BITFIELD
= 0x100
56 TAG_MAIN_INPUT
= 0x08,
57 TAG_MAIN_OUTPUT
= 0x09,
58 TAG_MAIN_FEATURE
= 0x0B,
59 TAG_MAIN_COLLECTION
= 0x0A,
60 TAG_MAIN_END_COLLECTION
= 0x0C
64 TAG_GLOBAL_USAGE_PAGE
= 0x0,
65 TAG_GLOBAL_LOGICAL_MINIMUM
,
66 TAG_GLOBAL_LOGICAL_MAXIMUM
,
67 TAG_GLOBAL_PHYSICAL_MINIMUM
,
68 TAG_GLOBAL_PHYSICAL_MAXIMUM
,
69 TAG_GLOBAL_UNIT_EXPONENT
,
71 TAG_GLOBAL_REPORT_SIZE
,
73 TAG_GLOBAL_REPORT_COUNT
,
79 TAG_LOCAL_USAGE
= 0x0,
80 TAG_LOCAL_USAGE_MINIMUM
,
81 TAG_LOCAL_USAGE_MAXIMUM
,
82 TAG_LOCAL_DESIGNATOR_INDEX
,
83 TAG_LOCAL_DESIGNATOR_MINIMUM
,
84 TAG_LOCAL_DESIGNATOR_MAXIMUM
,
85 TAG_LOCAL_STRING_INDEX
,
86 TAG_LOCAL_STRING_MINIMUM
,
87 TAG_LOCAL_STRING_MAXIMUM
,
92 static const char* const feature_string
[] =
93 { "Input", "Output", "Feature" };
108 BOOLEAN IsStringRange
;
109 BOOLEAN IsDesignatorRange
;
110 unsigned int usage_count
;
117 USHORT DesignatorMin
;
118 USHORT DesignatorMax
;
121 USAGE Usage
[USAGE_MAX
];
125 USHORT DesignatorIndex
;
135 struct list col_entry
;
138 HIDP_REPORT_TYPE type
;
150 struct collection
*collection
;
153 static const char* const collection_string
[] = {
168 struct collection
*parent
;
169 struct list features
;
170 struct list collections
;
173 static const char* debugstr_usages(struct caps
*caps
)
177 char out
[12 * USAGE_MAX
];
179 if (caps
->usage_count
== 0)
182 for (i
= 0; i
< caps
->usage_count
; i
++)
183 sprintf(out
+ strlen(out
), "0x%x ", caps
->u
.NotRange
.Usage
[i
]);
184 return wine_dbg_sprintf("[ %s] ", out
);
187 return wine_dbg_sprintf("[0x%x - 0x%x]", caps
->u
.Range
.UsageMin
, caps
->u
.Range
.UsageMax
);
190 static const char* debugstr_stringindex(struct caps
*caps
)
192 if (!caps
->IsStringRange
)
193 return wine_dbg_sprintf("%i", caps
->u
.NotRange
.StringIndex
);
195 return wine_dbg_sprintf("[%i - %i]", caps
->u
.Range
.StringMin
, caps
->u
.Range
.StringMax
);
198 static const char* debugstr_designatorindex(struct caps
*caps
)
200 if (!caps
->IsDesignatorRange
)
201 return wine_dbg_sprintf("%i", caps
->u
.NotRange
.DesignatorIndex
);
203 return wine_dbg_sprintf("[%i - %i]", caps
->u
.Range
.DesignatorMin
, caps
->u
.Range
.DesignatorMax
);
206 static void debugstr_caps(const char* type
, struct caps
*caps
)
210 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",
222 debugstr_usages(caps
),
223 debugstr_stringindex(caps
),
224 debugstr_designatorindex(caps
),
228 static void debug_feature(struct feature
*feature
)
232 TRACE("[Feature type %s [%i]; %s; %s; %s; %s; %s; %s; %s; %s; %s]\n",
233 feature_string
[feature
->type
],
235 (feature
->isData
)?"Data":"Const",
236 (feature
->isArray
)?"Array":"Var",
237 (feature
->IsAbsolute
)?"Abs":"Rel",
238 (feature
->Wrap
)?"Wrap":"NoWrap",
239 (feature
->Linear
)?"Linear":"NonLinear",
240 (feature
->prefState
)?"PrefStat":"NoPrefState",
241 (feature
->HasNull
)?"HasNull":"NoNull",
242 (feature
->Volatile
)?"Volatile":"NonVolatile",
243 (feature
->BitField
)?"BitField":"Buffered");
245 debugstr_caps("Feature", &feature
->caps
);
248 static void debug_collection(struct collection
*collection
)
250 struct feature
*fentry
;
251 struct collection
*centry
;
254 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
));
255 debugstr_caps("Collection", &collection
->caps
);
256 LIST_FOR_EACH_ENTRY(fentry
, &collection
->features
, struct feature
, col_entry
)
257 debug_feature(fentry
);
258 LIST_FOR_EACH_ENTRY(centry
, &collection
->collections
, struct collection
, entry
)
259 debug_collection(centry
);
260 TRACE(">>> END Collection %i\n", collection
->index
);
264 static void debug_print_button_cap(const CHAR
* type
, WINE_HID_ELEMENT
*wine_element
)
266 if (!wine_element
->caps
.button
.IsRange
)
267 TRACE("%s Button: 0x%x/0x%04x: ReportId %i, startBit %i/1\n" , type
,
268 wine_element
->caps
.button
.UsagePage
,
269 wine_element
->caps
.button
.u
.NotRange
.Usage
,
270 wine_element
->caps
.value
.ReportID
,
271 wine_element
->valueStartBit
);
273 TRACE("%s Button: 0x%x/[0x%04x-0x%04x]: ReportId %i, startBit %i/%i\n" ,type
,
274 wine_element
->caps
.button
.UsagePage
,
275 wine_element
->caps
.button
.u
.Range
.UsageMin
,
276 wine_element
->caps
.button
.u
.Range
.UsageMax
,
277 wine_element
->caps
.value
.ReportID
,
278 wine_element
->valueStartBit
,
279 wine_element
->bitCount
);
282 static void debug_print_value_cap(const CHAR
* type
, WINE_HID_ELEMENT
*wine_element
)
284 TRACE("%s Value: 0x%x/0x%x: ReportId %i, IsAbsolute %i, HasNull %i, "
285 "Bit Size %i, ReportCount %i, UnitsExp %i, Units %i, "
286 "LogicalMin %i, Logical Max %i, PhysicalMin %i, "
287 "PhysicalMax %i -- StartBit %i/%i\n", type
,
288 wine_element
->caps
.value
.UsagePage
,
289 wine_element
->caps
.value
.u
.NotRange
.Usage
,
290 wine_element
->caps
.value
.ReportID
,
291 wine_element
->caps
.value
.IsAbsolute
,
292 wine_element
->caps
.value
.HasNull
,
293 wine_element
->caps
.value
.BitSize
,
294 wine_element
->caps
.value
.ReportCount
,
295 wine_element
->caps
.value
.UnitsExp
,
296 wine_element
->caps
.value
.Units
,
297 wine_element
->caps
.value
.LogicalMin
,
298 wine_element
->caps
.value
.LogicalMax
,
299 wine_element
->caps
.value
.PhysicalMin
,
300 wine_element
->caps
.value
.PhysicalMax
,
301 wine_element
->valueStartBit
,
302 wine_element
->bitCount
);
305 static void debug_print_element(const CHAR
* type
, WINE_HID_ELEMENT
*wine_element
)
307 if (wine_element
->ElementType
== ButtonElement
)
308 debug_print_button_cap(type
, wine_element
);
309 else if (wine_element
->ElementType
== ValueElement
)
310 debug_print_value_cap(type
, wine_element
);
312 TRACE("%s: UNKNOWN\n", type
);
315 static void debug_print_report(const char* type
, WINE_HID_REPORT
*report
)
318 TRACE("START Report %i <<< %s report : dwSize: %i elementCount: %i\n",
322 report
->elementCount
);
323 for (i
= 0; i
< report
->elementCount
; i
++)
324 debug_print_element(type
, &report
->Elements
[i
]);
325 TRACE(">>> END Report %i\n",report
->reportID
);
328 static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA
*data
)
334 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
->caps
.UsagePage
,
338 data
->caps
.InputReportByteLength
,
339 data
->caps
.OutputReportByteLength
,
340 data
->caps
.FeatureReportByteLength
,
341 data
->caps
.NumberLinkCollectionNodes
,
342 data
->caps
.NumberInputButtonCaps
,
343 data
->caps
.NumberInputValueCaps
,
344 data
->caps
.NumberInputDataIndices
,
345 data
->caps
.NumberOutputButtonCaps
,
346 data
->caps
.NumberOutputValueCaps
,
347 data
->caps
.NumberOutputDataIndices
,
348 data
->caps
.NumberFeatureButtonCaps
,
349 data
->caps
.NumberFeatureValueCaps
,
350 data
->caps
.NumberFeatureDataIndices
,
351 data
->dwInputReportCount
,
352 data
->dwOutputReportCount
,
353 data
->dwFeatureReportCount
,
354 data
->dwOutputReportOffset
,
355 data
->dwFeatureReportOffset
);
357 r
= HID_INPUT_REPORTS(data
);
358 for (i
= 0; i
< data
->dwInputReportCount
; i
++)
360 debug_print_report("INPUT", r
);
361 r
= HID_NEXT_REPORT(data
, r
);
363 r
= HID_OUTPUT_REPORTS(data
);
364 for (i
= 0; i
< data
->dwOutputReportCount
; i
++)
366 debug_print_report("OUTPUT", r
);
367 r
= HID_NEXT_REPORT(data
, r
);
369 r
= HID_FEATURE_REPORTS(data
);
370 for (i
= 0; i
< data
->dwFeatureReportCount
; i
++)
372 debug_print_report("FEATURE", r
);
373 r
= HID_NEXT_REPORT(data
, r
);
375 TRACE(">>> END Preparsed Data\n");
379 static int getValue(int bsize
, int source
)
383 int outofrange
= 0x100;
390 for (i
= 1; i
< bsize
; i
++)
392 mask
= (mask
<<8) + 0xff;
393 negative
= (negative
<<8);
394 outofrange
= (outofrange
<<8);
396 value
= (source
&mask
);
398 value
= -1 * (outofrange
- value
);
402 void parse_io_feature(unsigned int bSize
, int itemVal
, int bTag
, unsigned int *feature_index
, struct feature
*feature
)
410 if ((itemVal
& INPUT_DATA
) == 0)
411 feature
->isData
= TRUE
;
413 feature
->isData
= FALSE
; /* Const */
414 if ((itemVal
& INPUT_ARRAY
) == 0)
415 feature
->isArray
= TRUE
;
417 feature
->isArray
= TRUE
; /* Var */
418 if ((itemVal
& INPUT_ABS
) == 0)
419 feature
->IsAbsolute
= TRUE
;
421 feature
->IsAbsolute
= FALSE
; /* Rel */
422 if ((itemVal
& INPUT_WRAP
) == 0)
423 feature
->Wrap
= FALSE
;
425 feature
->Wrap
= TRUE
;
426 if ((itemVal
& INPUT_LINEAR
) == 0)
427 feature
->Linear
= TRUE
;
429 feature
->Linear
= FALSE
;
430 if ((itemVal
& INPUT_PREFSTATE
) == 0)
431 feature
->prefState
= TRUE
;
433 feature
->prefState
= FALSE
;
434 if ((itemVal
& INPUT_NULL
) == 0)
435 feature
->HasNull
= FALSE
;
437 feature
->HasNull
= TRUE
;
439 if (bTag
!= TAG_MAIN_INPUT
)
441 if ((itemVal
& INPUT_VOLATILE
) == 0)
442 feature
->Volatile
= FALSE
;
444 feature
->Volatile
= TRUE
;
448 if ((itemVal
& INPUT_BITFIELD
) == 0)
449 feature
->BitField
= TRUE
;
451 feature
->BitField
= FALSE
; /* Buffered Bytes */
453 feature
->index
= *feature_index
;
454 *feature_index
= *feature_index
+ 1;
458 void parse_collection(unsigned int bSize
, int itemVal
, struct collection
*collection
)
464 collection
->type
= itemVal
;
466 if (itemVal
>= 0x07 && itemVal
<= 0x7F) {
467 ERR(" (Reserved 0x%x )\n", itemVal
);
469 else if (itemVal
>= 0x80 && itemVal
<= 0xFF) {
470 ERR(" (Vendor Defined 0x%x )\n", itemVal
);
475 static void new_caps(struct caps
*caps
)
478 caps
->IsStringRange
= 0;
479 caps
->IsDesignatorRange
= 0;
480 caps
->usage_count
= 0;
483 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
)
486 for (i
= index
; i
< length
;)
488 BYTE b0
= descriptor
[i
++];
489 int bSize
= b0
& 0x03;
490 int bType
= (b0
>> 2) & 0x03;
491 int bTag
= (b0
>> 4) & 0x0F;
493 bSize
= (bSize
== 3) ? 4 : bSize
;
494 if (bType
== TAG_TYPE_RESERVED
&& bTag
== 0x0F && bSize
== 2 &&
497 /* Long data items: Should be unused */
498 ERR("Long Data Item, should be unused\n");
506 for (j
= 0; j
< bSize
; j
++)
510 itemVal
+= descriptor
[i
+ j
] << (8 * j
);
514 TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0
,i
-1,bType
, bTag
, bSize
, itemVal
);
516 if (bType
== TAG_TYPE_MAIN
)
518 struct feature
*feature
;
522 feature
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*feature
));
523 list_add_tail(&collection
->features
, &feature
->col_entry
);
524 list_add_tail(features
, &feature
->entry
);
525 feature
->type
= HidP_Input
;
526 parse_io_feature(bSize
, itemVal
, bTag
, feature_index
, feature
);
527 feature
->caps
= *caps
;
528 feature
->collection
= collection
;
531 case TAG_MAIN_OUTPUT
:
532 feature
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*feature
));
533 list_add_tail(&collection
->features
, &feature
->col_entry
);
534 list_add_tail(features
, &feature
->entry
);
535 feature
->type
= HidP_Output
;
536 parse_io_feature(bSize
, itemVal
, bTag
, feature_index
, feature
);
537 feature
->caps
= *caps
;
538 feature
->collection
= collection
;
541 case TAG_MAIN_FEATURE
:
542 feature
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*feature
));
543 list_add_tail(&collection
->features
, &feature
->col_entry
);
544 list_add_tail(features
, &feature
->entry
);
545 feature
->type
= HidP_Feature
;
546 parse_io_feature(bSize
, itemVal
, bTag
, feature_index
, feature
);
547 feature
->caps
= *caps
;
548 feature
->collection
= collection
;
551 case TAG_MAIN_COLLECTION
:
553 struct collection
*subcollection
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct collection
));
554 list_add_tail(&collection
->collections
, &subcollection
->entry
);
555 subcollection
->parent
= collection
;
556 /* Only set our collection once...
557 We do not properly handle composite devices yet. */
558 if (*collection_index
== 0)
559 collection
->caps
= *caps
;
560 subcollection
->caps
= *caps
;
561 subcollection
->index
= *collection_index
;
562 *collection_index
= *collection_index
+ 1;
563 list_init(&subcollection
->features
);
564 list_init(&subcollection
->collections
);
567 parse_collection(bSize
, itemVal
, subcollection
);
569 i
= parse_descriptor(descriptor
, i
+1, length
, feature_index
, collection_index
, subcollection
, caps
, features
);
572 case TAG_MAIN_END_COLLECTION
:
575 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag
, bType
);
578 else if (bType
== TAG_TYPE_GLOBAL
)
582 case TAG_GLOBAL_USAGE_PAGE
:
583 caps
->UsagePage
= getValue(bSize
, itemVal
);
585 case TAG_GLOBAL_LOGICAL_MINIMUM
:
586 caps
->LogicalMin
= getValue(bSize
, itemVal
);
588 case TAG_GLOBAL_LOGICAL_MAXIMUM
:
589 caps
->LogicalMax
= getValue(bSize
, itemVal
);
591 case TAG_GLOBAL_PHYSICAL_MINIMUM
:
592 caps
->PhysicalMin
= getValue(bSize
, itemVal
);
594 case TAG_GLOBAL_PHYSICAL_MAXIMUM
:
595 caps
->PhysicalMax
= getValue(bSize
, itemVal
);
597 case TAG_GLOBAL_UNIT_EXPONENT
:
598 caps
->UnitsExp
= getValue(bSize
, itemVal
);
600 case TAG_GLOBAL_UNIT
:
601 caps
->Units
= getValue(bSize
, itemVal
);
603 case TAG_GLOBAL_REPORT_SIZE
:
604 caps
->BitSize
= getValue(bSize
, itemVal
);
606 case TAG_GLOBAL_REPORT_ID
:
607 caps
->ReportID
= getValue(bSize
, itemVal
);
609 case TAG_GLOBAL_REPORT_COUNT
:
610 caps
->ReportCount
= getValue(bSize
, itemVal
);
612 case TAG_GLOBAL_PUSH
:
613 FIXME("Unhandled Push\n");
616 FIXME("Unhandled Pop\n");
619 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag
, bType
);
622 else if (bType
== TAG_TYPE_LOCAL
)
626 case TAG_LOCAL_USAGE
:
627 if (caps
->usage_count
>= USAGE_MAX
)
628 FIXME("More than %i individual usages defined\n",USAGE_MAX
);
631 caps
->u
.NotRange
.Usage
[caps
->usage_count
++] = getValue(bSize
, itemVal
);
632 caps
->IsRange
= FALSE
;
635 case TAG_LOCAL_USAGE_MINIMUM
:
636 caps
->usage_count
= 1;
637 caps
->u
.Range
.UsageMin
= getValue(bSize
, itemVal
);
638 caps
->IsRange
= TRUE
;
640 case TAG_LOCAL_USAGE_MAXIMUM
:
641 caps
->usage_count
= 1;
642 caps
->u
.Range
.UsageMax
= getValue(bSize
, itemVal
);
643 caps
->IsRange
= TRUE
;
645 case TAG_LOCAL_DESIGNATOR_INDEX
:
646 caps
->u
.NotRange
.DesignatorIndex
= getValue(bSize
, itemVal
);
647 caps
->IsDesignatorRange
= FALSE
;
649 case TAG_LOCAL_DESIGNATOR_MINIMUM
:
650 caps
->u
.Range
.DesignatorMin
= getValue(bSize
, itemVal
);
651 caps
->IsDesignatorRange
= TRUE
;
653 case TAG_LOCAL_DESIGNATOR_MAXIMUM
:
654 caps
->u
.Range
.DesignatorMax
= getValue(bSize
, itemVal
);
655 caps
->IsDesignatorRange
= TRUE
;
657 case TAG_LOCAL_STRING_INDEX
:
658 caps
->u
.NotRange
.StringIndex
= getValue(bSize
, itemVal
);
659 caps
->IsStringRange
= FALSE
;
661 case TAG_LOCAL_STRING_MINIMUM
:
662 caps
->u
.Range
.StringMin
= getValue(bSize
, itemVal
);
663 caps
->IsStringRange
= TRUE
;
665 case TAG_LOCAL_STRING_MAXIMUM
:
666 caps
->u
.Range
.StringMax
= getValue(bSize
, itemVal
);
667 caps
->IsStringRange
= TRUE
;
669 case TAG_LOCAL_DELIMITER
:
670 caps
->Delim
= getValue(bSize
, itemVal
);
673 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag
, bType
);
677 ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag
, bType
);
685 static inline void new_report(WINE_HID_REPORT
*wine_report
, struct feature
* feature
)
687 wine_report
->reportID
= feature
->caps
.ReportID
;
688 wine_report
->dwSize
= sizeof(*wine_report
) - sizeof(WINE_HID_ELEMENT
);
689 wine_report
->elementCount
= 0;
692 static void build_elements(WINE_HID_REPORT
*wine_report
, struct feature
* feature
, DWORD
*bitOffset
)
696 if (!feature
->isData
)
698 *bitOffset
= *bitOffset
+ (feature
->caps
.BitSize
* feature
->caps
.ReportCount
);
702 for (i
= 0; i
< feature
->caps
.usage_count
; i
++)
704 WINE_HID_ELEMENT
*wine_element
= &wine_report
->Elements
[wine_report
->elementCount
];
706 wine_element
->valueStartBit
= *bitOffset
;
707 if (feature
->caps
.UsagePage
== HID_USAGE_PAGE_BUTTON
)
709 wine_element
->ElementType
= ButtonElement
;
710 wine_element
->caps
.button
.UsagePage
= feature
->caps
.UsagePage
;
711 wine_element
->caps
.button
.ReportID
= feature
->caps
.ReportID
;
712 wine_element
->caps
.button
.BitField
= feature
->BitField
;
713 wine_element
->caps
.button
.IsRange
= feature
->caps
.IsRange
;
714 wine_element
->caps
.button
.IsStringRange
= feature
->caps
.IsStringRange
;
715 wine_element
->caps
.button
.IsDesignatorRange
= feature
->caps
.IsDesignatorRange
;
716 wine_element
->caps
.button
.IsAbsolute
= feature
->IsAbsolute
;
717 if (wine_element
->caps
.button
.IsRange
)
719 wine_element
->bitCount
= (feature
->caps
.u
.Range
.UsageMax
- feature
->caps
.u
.Range
.UsageMin
) + 1;
720 *bitOffset
= *bitOffset
+ wine_element
->bitCount
;
721 wine_element
->caps
.button
.u
.Range
.UsageMin
= feature
->caps
.u
.Range
.UsageMin
;
722 wine_element
->caps
.button
.u
.Range
.UsageMax
= feature
->caps
.u
.Range
.UsageMax
;
723 wine_element
->caps
.button
.u
.Range
.StringMin
= feature
->caps
.u
.Range
.StringMin
;
724 wine_element
->caps
.button
.u
.Range
.StringMax
= feature
->caps
.u
.Range
.StringMax
;
725 wine_element
->caps
.button
.u
.Range
.DesignatorMin
= feature
->caps
.u
.Range
.DesignatorMin
;
726 wine_element
->caps
.button
.u
.Range
.DesignatorMax
= feature
->caps
.u
.Range
.DesignatorMax
;
730 *bitOffset
= *bitOffset
+ 1;
731 wine_element
->bitCount
= 1;
732 wine_element
->caps
.button
.u
.NotRange
.Usage
= feature
->caps
.u
.NotRange
.Usage
[i
];
733 wine_element
->caps
.button
.u
.NotRange
.StringIndex
= feature
->caps
.u
.NotRange
.StringIndex
;
734 wine_element
->caps
.button
.u
.NotRange
.DesignatorIndex
= feature
->caps
.u
.NotRange
.DesignatorIndex
;
739 wine_element
->ElementType
= ValueElement
;
740 wine_element
->caps
.value
.UsagePage
= feature
->caps
.UsagePage
;
741 wine_element
->caps
.value
.ReportID
= feature
->caps
.ReportID
;
742 wine_element
->caps
.value
.BitField
= feature
->BitField
;
743 wine_element
->caps
.value
.IsRange
= feature
->caps
.IsRange
;
744 wine_element
->caps
.value
.IsStringRange
= feature
->caps
.IsStringRange
;
745 wine_element
->caps
.value
.IsDesignatorRange
= feature
->caps
.IsDesignatorRange
;
746 wine_element
->caps
.value
.IsAbsolute
= feature
->IsAbsolute
;
747 wine_element
->caps
.value
.HasNull
= feature
->HasNull
;
748 wine_element
->caps
.value
.BitSize
= feature
->caps
.BitSize
;
749 if (feature
->caps
.usage_count
> 1)
750 wine_element
->caps
.value
.ReportCount
= 1;
752 wine_element
->caps
.value
.ReportCount
= feature
->caps
.ReportCount
;
753 wine_element
->bitCount
= (feature
->caps
.BitSize
* wine_element
->caps
.value
.ReportCount
);
754 *bitOffset
= *bitOffset
+ wine_element
->bitCount
;
755 wine_element
->caps
.value
.UnitsExp
= feature
->caps
.UnitsExp
;
756 wine_element
->caps
.value
.Units
= feature
->caps
.Units
;
757 wine_element
->caps
.value
.LogicalMin
= feature
->caps
.LogicalMin
;
758 wine_element
->caps
.value
.LogicalMax
= feature
->caps
.LogicalMax
;
759 wine_element
->caps
.value
.PhysicalMin
= feature
->caps
.PhysicalMin
;
760 wine_element
->caps
.value
.PhysicalMax
= feature
->caps
.PhysicalMax
;
761 if (wine_element
->caps
.value
.IsRange
)
763 wine_element
->caps
.value
.u
.Range
.UsageMin
= feature
->caps
.u
.Range
.UsageMin
;
764 wine_element
->caps
.value
.u
.Range
.UsageMax
= feature
->caps
.u
.Range
.UsageMax
;
765 wine_element
->caps
.value
.u
.Range
.StringMin
= feature
->caps
.u
.Range
.StringMin
;
766 wine_element
->caps
.value
.u
.Range
.StringMax
= feature
->caps
.u
.Range
.StringMax
;
767 wine_element
->caps
.value
.u
.Range
.DesignatorMin
= feature
->caps
.u
.Range
.DesignatorMin
;
768 wine_element
->caps
.value
.u
.Range
.DesignatorMax
= feature
->caps
.u
.Range
.DesignatorMax
;
772 wine_element
->caps
.value
.u
.NotRange
.Usage
= feature
->caps
.u
.NotRange
.Usage
[i
];
773 wine_element
->caps
.value
.u
.NotRange
.StringIndex
= feature
->caps
.u
.NotRange
.StringIndex
;
774 wine_element
->caps
.value
.u
.NotRange
.DesignatorIndex
= feature
->caps
.u
.NotRange
.DesignatorIndex
;
778 wine_report
->elementCount
++;
782 static void count_elements(struct feature
* feature
, USHORT
*buttons
, USHORT
*values
)
784 if (feature
->caps
.UsagePage
== HID_USAGE_PAGE_BUTTON
)
786 if (feature
->caps
.IsRange
)
787 *buttons
= *buttons
+ 1;
789 *buttons
= *buttons
+ feature
->caps
.usage_count
;
793 if (feature
->caps
.IsRange
)
794 *values
= *values
+ 1;
796 *values
= *values
+ feature
->caps
.usage_count
;
800 WINE_HIDP_PREPARSED_DATA
* build_PreparseData(
801 struct feature
**features
, int feature_count
,
802 struct feature
**input_features
, int i_count
,
803 struct feature
**output_features
, int o_count
,
804 struct feature
**feature_features
, int f_count
,
805 struct collection
*base_collection
)
807 WINE_HIDP_PREPARSED_DATA
*data
;
808 WINE_HID_REPORT
*wine_report
= NULL
;
809 DWORD bitOffset
, bitLength
;
810 unsigned int report_count
= 1;
812 unsigned int element_count
;
813 unsigned int size
= 0;
815 if (features
[0]->caps
.ReportID
!= 0)
817 unsigned int *report_ids
;
818 unsigned int cnt
= max(i_count
, o_count
);
819 cnt
= max(cnt
, f_count
);
820 report_ids
= HeapAlloc(GetProcessHeap(), 0 , sizeof(*report_ids
) * cnt
);
824 report_ids
[0] = input_features
[0]->caps
.ReportID
;
825 for (i
= 1; i
< i_count
; i
++)
828 unsigned int found
= FALSE
;
829 for (j
= 0; !found
&& j
< i_count
; j
++)
831 if (report_ids
[j
] == input_features
[i
]->caps
.ReportID
)
836 report_ids
[report_count
] = input_features
[i
]->caps
.ReportID
;
844 report_ids
[0] = output_features
[0]->caps
.ReportID
;
845 for (i
= 1; i
< o_count
; i
++)
848 unsigned int found
= FALSE
;
849 for (j
= 0; !found
&& j
< o_count
; j
++)
851 if (report_ids
[j
] == output_features
[i
]->caps
.ReportID
)
856 report_ids
[report_count
] = output_features
[i
]->caps
.ReportID
;
864 report_ids
[0] = feature_features
[0]->caps
.ReportID
;
865 for (i
= 1; i
< f_count
; i
++)
868 unsigned int found
= FALSE
;
869 for (j
= 0; !found
&& j
< f_count
; j
++)
871 if (report_ids
[j
] == feature_features
[i
]->caps
.ReportID
)
876 report_ids
[report_count
] = feature_features
[i
]->caps
.ReportID
;
881 HeapFree(GetProcessHeap(), 0, report_ids
);
885 if (o_count
) report_count
++;
886 if (f_count
) report_count
++;
890 for (i
= 0; i
< feature_count
; i
++)
891 element_count
+= features
[i
]->caps
.usage_count
;
893 size
= sizeof(WINE_HIDP_PREPARSED_DATA
) +
894 (element_count
* sizeof(WINE_HID_ELEMENT
)) +
895 (report_count
* sizeof(WINE_HID_REPORT
));
897 TRACE("%i reports %i elements -> size %i\n",report_count
, element_count
, size
);
899 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
900 data
->magic
= HID_MAGIC
;
902 data
->caps
.Usage
= base_collection
->caps
.u
.NotRange
.Usage
[0];
903 data
->caps
.UsagePage
= base_collection
->caps
.UsagePage
;
905 wine_report
= data
->InputReports
;
909 new_report(wine_report
, input_features
[0]);
910 data
->dwInputReportCount
++;
912 if (input_features
[0]->caps
.ReportID
!= 0)
917 for (i
= 0; i
< i_count
; i
++)
919 if (input_features
[i
]->caps
.ReportID
!= wine_report
->reportID
)
921 wine_report
->dwSize
+= (sizeof(WINE_HID_ELEMENT
) * wine_report
->elementCount
);
922 wine_report
= (WINE_HID_REPORT
*)(((BYTE
*)wine_report
)+wine_report
->dwSize
);
923 new_report(wine_report
, input_features
[i
]);
924 data
->dwInputReportCount
++;
925 bitLength
= max(bitOffset
, bitLength
);
926 if (input_features
[i
]->caps
.ReportID
!= 0)
931 build_elements(wine_report
, input_features
[i
], &bitOffset
);
932 count_elements(input_features
[i
], &data
->caps
.NumberInputButtonCaps
,
933 &data
->caps
.NumberInputValueCaps
);
935 wine_report
->dwSize
+= (sizeof(WINE_HID_ELEMENT
) * wine_report
->elementCount
);
936 bitLength
= max(bitOffset
, bitLength
);
937 data
->caps
.InputReportByteLength
= ((bitLength
+ 7) & ~7)/8;
943 wine_report
= (WINE_HID_REPORT
*)(((BYTE
*)wine_report
)+wine_report
->dwSize
);
944 data
->dwOutputReportOffset
= (BYTE
*)wine_report
- (BYTE
*)data
->InputReports
;
945 new_report(wine_report
, output_features
[0]);
946 data
->dwOutputReportCount
++;
947 if (output_features
[0]->caps
.ReportID
!= 0)
952 for (i
= 0; i
< o_count
; i
++)
954 if (output_features
[i
]->caps
.ReportID
!= wine_report
->reportID
)
956 wine_report
->dwSize
+= (sizeof(WINE_HID_ELEMENT
) * wine_report
->elementCount
);
957 wine_report
= (WINE_HID_REPORT
*)(((BYTE
*)wine_report
)+wine_report
->dwSize
);
958 new_report(wine_report
, output_features
[i
]);
959 data
->dwOutputReportCount
++;
960 bitLength
= max(bitOffset
, bitLength
);
961 if (output_features
[0]->caps
.ReportID
!= 0)
966 build_elements(wine_report
, output_features
[i
], &bitOffset
);
967 count_elements(output_features
[i
], &data
->caps
.NumberOutputButtonCaps
,
968 &data
->caps
.NumberOutputValueCaps
);
970 wine_report
->dwSize
+= (sizeof(WINE_HID_ELEMENT
) * wine_report
->elementCount
);
971 bitLength
= max(bitOffset
, bitLength
);
972 data
->caps
.OutputReportByteLength
= ((bitLength
+ 7) & ~7)/8;
978 wine_report
= (WINE_HID_REPORT
*)(((BYTE
*)wine_report
)+wine_report
->dwSize
);
979 data
->dwFeatureReportOffset
= (BYTE
*)wine_report
- (BYTE
*)data
->InputReports
;
980 new_report(wine_report
, feature_features
[0]);
981 data
->dwFeatureReportCount
++;
982 if (feature_features
[0]->caps
.ReportID
!= 0)
987 for (i
= 0; i
< f_count
; i
++)
989 if (feature_features
[i
]->caps
.ReportID
!= wine_report
->reportID
)
991 wine_report
->dwSize
+= (sizeof(WINE_HID_ELEMENT
) * wine_report
->elementCount
);
992 wine_report
= (WINE_HID_REPORT
*)((BYTE
*)wine_report
)+wine_report
->dwSize
;
993 new_report(wine_report
, feature_features
[i
]);
994 data
->dwFeatureReportCount
++;
995 bitLength
= max(bitOffset
, bitLength
);
996 if (feature_features
[0]->caps
.ReportID
!= 0)
1001 build_elements(wine_report
, feature_features
[i
], &bitOffset
);
1002 count_elements(feature_features
[i
], &data
->caps
.NumberFeatureButtonCaps
,
1003 &data
->caps
.NumberFeatureValueCaps
);
1005 bitLength
= max(bitOffset
, bitLength
);
1006 data
->caps
.FeatureReportByteLength
= ((bitLength
+ 7) & ~7)/8;
1012 static void free_collection(struct collection
*collection
)
1014 struct feature
*fentry
, *fnext
;
1015 struct collection
*centry
, *cnext
;
1016 LIST_FOR_EACH_ENTRY_SAFE(centry
, cnext
, &collection
->collections
, struct collection
, entry
)
1018 list_remove(¢ry
->entry
);
1019 free_collection(centry
);
1021 LIST_FOR_EACH_ENTRY_SAFE(fentry
, fnext
, &collection
->features
, struct feature
, col_entry
)
1023 list_remove(&fentry
->col_entry
);
1024 HeapFree(GetProcessHeap(), 0, fentry
);
1026 HeapFree(GetProcessHeap(), 0, collection
);
1029 static int compare_reports(const void *a
, const void* b
)
1031 struct feature
*f1
= *(struct feature
**)a
;
1032 struct feature
*f2
= *(struct feature
**)b
;
1033 int c
= (f1
->caps
.ReportID
- f2
->caps
.ReportID
);
1035 return (f1
->index
- f2
->index
);
1038 WINE_HIDP_PREPARSED_DATA
* ParseDescriptor(BYTE
*descriptor
, unsigned int length
)
1040 WINE_HIDP_PREPARSED_DATA
*data
= NULL
;
1041 struct collection
*base
;
1044 struct list features
;
1046 unsigned int feature_count
= 0;
1051 TRACE("Descriptor[%i]: ", length
);
1052 for (cidx
= 0; cidx
< length
; cidx
++)
1053 TRACE("%x ",descriptor
[cidx
]);
1057 list_init(&features
);
1059 base
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*base
));
1061 list_init(&base
->features
);
1062 list_init(&base
->collections
);
1063 memset(&caps
, 0, sizeof(caps
));
1066 parse_descriptor(descriptor
, 0, length
, &feature_count
, &cidx
, base
, &caps
, &features
);
1068 debug_collection(base
);
1073 struct feature
*entry
;
1074 struct feature
** sorted_features
;
1075 struct feature
** input_features
;
1076 struct feature
** output_features
;
1077 struct feature
** feature_features
;
1078 unsigned int i_count
, o_count
, f_count
;
1081 i_count
= o_count
= f_count
= 0;
1083 sorted_features
= HeapAlloc(GetProcessHeap(), 0, sizeof(*sorted_features
) * feature_count
);
1084 input_features
= HeapAlloc(GetProcessHeap(), 0, sizeof(*input_features
) * feature_count
);
1085 output_features
= HeapAlloc(GetProcessHeap(), 0, sizeof(*output_features
) * feature_count
);
1086 feature_features
= HeapAlloc(GetProcessHeap(), 0, sizeof(*feature_features
) * feature_count
);
1089 LIST_FOR_EACH_ENTRY(entry
, &features
, struct feature
, entry
)
1090 sorted_features
[i
++] = entry
;
1092 /* Sort features base on report if there are multiple reports */
1093 if (sorted_features
[0]->caps
.ReportID
!= 0)
1094 qsort(sorted_features
, feature_count
, sizeof(struct feature
*), compare_reports
);
1096 for (i
= 0; i
< feature_count
; i
++)
1098 switch (sorted_features
[i
]->type
)
1101 input_features
[i_count
] = sorted_features
[i
];
1105 output_features
[o_count
] = sorted_features
[i
];
1109 feature_features
[f_count
] = sorted_features
[i
];
1113 ERR("Unknown type %i\n",sorted_features
[i
]->type
);
1119 TRACE("DUMP FEATURES:\n");
1120 TRACE("----INPUT----\n");
1121 for (cidx
= 0; cidx
< i_count
; cidx
++)
1122 debug_feature(input_features
[cidx
]);
1123 TRACE("----OUTPUT----\n");
1124 for (cidx
= 0; cidx
< o_count
; cidx
++)
1125 debug_feature(output_features
[cidx
]);
1126 TRACE("----FEATURE----\n");
1127 for (cidx
= 0; cidx
< f_count
; cidx
++)
1128 debug_feature(feature_features
[cidx
]);
1131 data
= build_PreparseData(sorted_features
, feature_count
, input_features
, i_count
, output_features
, o_count
, feature_features
, f_count
, base
);
1133 debug_print_preparsed(data
);
1135 HeapFree(GetProcessHeap(), 0, sorted_features
);
1136 HeapFree(GetProcessHeap(), 0, input_features
);
1137 HeapFree(GetProcessHeap(), 0, output_features
);
1138 HeapFree(GetProcessHeap(), 0, feature_features
);
1141 free_collection(base
);
1142 /* We do not have to free the list as free_collection does all the work */