hidclass.sys: Add a stack to parser_state to store global items.
[wine.git] / dlls / hidclass.sys / descriptor.c
blobb57ab2a7da843b85908de42acdefb0c4f7519b27
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 #include "hid.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(hid);
31 /* Flags that are defined in the document
32 "Device Class Definition for Human Interface Devices" */
33 enum {
34 INPUT_DATA_CONST = 0x01, /* Data (0) | Constant (1) */
35 INPUT_ARRAY_VAR = 0x02, /* Array (0) | Variable (1) */
36 INPUT_ABS_REL = 0x04, /* Absolute (0) | Relative (1) */
37 INPUT_WRAP = 0x08, /* No Wrap (0) | Wrap (1) */
38 INPUT_LINEAR = 0x10, /* Linear (0) | Non Linear (1) */
39 INPUT_PREFSTATE = 0x20, /* Preferred State (0) | No Preferred (1) */
40 INPUT_NULL = 0x40, /* No Null position (0) | Null state(1) */
41 INPUT_VOLATILE = 0x80, /* Non Volatile (0) | Volatile (1) */
42 INPUT_BITFIELD = 0x100 /* Bit Field (0) | Buffered Bytes (1) */
45 enum {
46 TAG_TYPE_MAIN = 0x0,
47 TAG_TYPE_GLOBAL,
48 TAG_TYPE_LOCAL,
49 TAG_TYPE_RESERVED,
52 enum {
53 TAG_MAIN_INPUT = 0x08,
54 TAG_MAIN_OUTPUT = 0x09,
55 TAG_MAIN_FEATURE = 0x0B,
56 TAG_MAIN_COLLECTION = 0x0A,
57 TAG_MAIN_END_COLLECTION = 0x0C
60 enum {
61 TAG_GLOBAL_USAGE_PAGE = 0x0,
62 TAG_GLOBAL_LOGICAL_MINIMUM,
63 TAG_GLOBAL_LOGICAL_MAXIMUM,
64 TAG_GLOBAL_PHYSICAL_MINIMUM,
65 TAG_GLOBAL_PHYSICAL_MAXIMUM,
66 TAG_GLOBAL_UNIT_EXPONENT,
67 TAG_GLOBAL_UNIT,
68 TAG_GLOBAL_REPORT_SIZE,
69 TAG_GLOBAL_REPORT_ID,
70 TAG_GLOBAL_REPORT_COUNT,
71 TAG_GLOBAL_PUSH,
72 TAG_GLOBAL_POP
75 enum {
76 TAG_LOCAL_USAGE = 0x0,
77 TAG_LOCAL_USAGE_MINIMUM,
78 TAG_LOCAL_USAGE_MAXIMUM,
79 TAG_LOCAL_DESIGNATOR_INDEX,
80 TAG_LOCAL_DESIGNATOR_MINIMUM,
81 TAG_LOCAL_DESIGNATOR_MAXIMUM,
82 TAG_LOCAL_STRING_INDEX,
83 TAG_LOCAL_STRING_MINIMUM,
84 TAG_LOCAL_STRING_MAXIMUM,
85 TAG_LOCAL_DELIMITER
89 static const char* const feature_string[] =
90 { "Input", "Output", "Feature" };
92 struct feature {
93 struct list entry;
94 HIDP_VALUE_CAPS caps;
96 HIDP_REPORT_TYPE type;
97 BOOLEAN isData;
98 BOOLEAN isArray;
99 BOOLEAN IsAbsolute;
100 BOOLEAN Wrap;
101 BOOLEAN Linear;
102 BOOLEAN prefState;
103 BOOLEAN HasNull;
104 BOOLEAN Volatile;
105 BOOLEAN BitField;
107 unsigned int index;
108 struct collection *collection;
111 static const char* const collection_string[] = {
112 "Physical",
113 "Application",
114 "Logical",
115 "Report",
116 "Named Array",
117 "Usage Switch",
118 "Usage Modifier",
121 struct collection {
122 struct list entry;
123 HIDP_VALUE_CAPS caps;
124 unsigned int index;
125 unsigned int type;
126 struct collection *parent;
127 struct list features;
128 struct list collections;
131 static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps )
133 if (!caps) return "(null)";
134 return wine_dbg_sprintf( "RId %d, Usg %02x:%02x-%02x Dat %02x-%02x (%d), Str %d-%d (%d), Des %d-%d (%d), "
135 "Bits %02x, Als %d, Abs %d, Nul %d, LCol %d LUsg %02x:%02x, BitSz %d, RCnt %d, "
136 "Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d",
137 caps->ReportID, caps->UsagePage, caps->Range.UsageMin, caps->Range.UsageMax, caps->Range.DataIndexMin, caps->Range.DataIndexMax, caps->IsRange,
138 caps->Range.StringMin, caps->Range.StringMax, caps->IsStringRange, caps->Range.DesignatorMin, caps->Range.DesignatorMax, caps->IsDesignatorRange,
139 caps->BitField, caps->IsAlias, caps->IsAbsolute, caps->HasNull, caps->LinkCollection, caps->LinkUsagePage, caps->LinkUsage, caps->BitSize, caps->ReportCount,
140 caps->Units, caps->UnitsExp, caps->LogicalMin, caps->LogicalMax, caps->PhysicalMin, caps->PhysicalMax );
143 static void copy_hidp_value_caps( HIDP_VALUE_CAPS *out, const struct hid_value_caps *in )
145 out->UsagePage = in->usage_page;
146 out->ReportID = in->report_id;
147 out->IsAlias = FALSE;
148 out->BitSize = in->bit_size;
149 out->ReportCount = in->report_count;
150 out->UnitsExp = in->units_exp;
151 out->Units = in->units;
152 out->LogicalMin = in->logical_min;
153 out->LogicalMax = in->logical_max;
154 out->PhysicalMin = in->physical_min;
155 out->PhysicalMax = in->physical_max;
156 if (!(out->IsRange = in->is_range))
157 out->NotRange.Usage = in->usage_min;
158 else
160 out->Range.UsageMin = in->usage_min;
161 out->Range.UsageMax = in->usage_max;
163 if (!(out->IsStringRange = in->is_string_range))
164 out->NotRange.StringIndex = in->string_min;
165 else
167 out->Range.StringMin = in->string_min;
168 out->Range.StringMax = in->string_max;
170 if ((out->IsDesignatorRange = in->is_designator_range))
171 out->NotRange.DesignatorIndex = in->designator_min;
172 else
174 out->Range.DesignatorMin = in->designator_min;
175 out->Range.DesignatorMax = in->designator_max;
179 static void debug_feature(struct feature *feature)
181 if (!feature)
182 return;
183 TRACE("[Feature type %s [%i]; %s; %s; %s; %s; %s; %s; %s; %s; %s]\n",
184 feature_string[feature->type],
185 feature->index,
186 (feature->isData)?"Data":"Const",
187 (feature->isArray)?"Array":"Var",
188 (feature->IsAbsolute)?"Abs":"Rel",
189 (feature->Wrap)?"Wrap":"NoWrap",
190 (feature->Linear)?"Linear":"NonLinear",
191 (feature->prefState)?"PrefStat":"NoPrefState",
192 (feature->HasNull)?"HasNull":"NoNull",
193 (feature->Volatile)?"Volatile":"NonVolatile",
194 (feature->BitField)?"BitField":"Buffered");
196 TRACE("Feature %s\n", debugstr_hidp_value_caps(&feature->caps));
199 static void debug_collection(struct collection *collection)
201 struct feature *fentry;
202 struct collection *centry;
203 if (TRACE_ON(hid))
205 TRACE("START Collection %i <<< %s, parent: %p, %i features, %i collections\n",
206 collection->index, collection_string[collection->type], collection->parent,
207 list_count(&collection->features), list_count(&collection->collections));
208 TRACE("Collection %s\n", debugstr_hidp_value_caps(&collection->caps));
209 LIST_FOR_EACH_ENTRY(fentry, &collection->features, struct feature, entry)
210 debug_feature(fentry);
211 LIST_FOR_EACH_ENTRY(centry, &collection->collections, struct collection, entry)
212 debug_collection(centry);
213 TRACE(">>> END Collection %i\n", collection->index);
217 static void debug_print_report(const char* type, WINE_HIDP_PREPARSED_DATA *data,
218 WINE_HID_REPORT *report)
220 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
221 unsigned int i;
222 TRACE("START Report %i <<< %s report : bitSize: %i elementCount: %i\n",
223 report->reportID,
224 type,
225 report->bitSize,
226 report->elementCount);
227 for (i = 0; i < report->elementCount; i++)
229 WINE_HID_ELEMENT *elem = elems + report->elementIdx + i;
230 TRACE("%s: %s, StartBit %d, BitCount %d\n", type, debugstr_hidp_value_caps(&elem->caps), elem->valueStartBit, elem->bitCount);
232 TRACE(">>> END Report %i\n",report->reportID);
235 static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data)
237 unsigned int i, end;
238 if (TRACE_ON(hid))
240 TRACE("START PREPARSED Data <<< dwSize: %i Usage: %i, UsagePage: %i, "
241 "InputReportByteLength: %i, tOutputReportByteLength: %i, "
242 "FeatureReportByteLength: %i, NumberLinkCollectionNodes: %i, "
243 "NumberInputButtonCaps: %i, NumberInputValueCaps: %i, "
244 "NumberInputDataIndices: %i, NumberOutputButtonCaps: %i, "
245 "NumberOutputValueCaps: %i, NumberOutputDataIndices: %i, "
246 "NumberFeatureButtonCaps: %i, NumberFeatureValueCaps: %i, "
247 "NumberFeatureDataIndices: %i, reportCount[HidP_Input]: %i, "
248 "reportCount[HidP_Output]: %i, reportCount[HidP_Feature]: %i, "
249 "elementOffset: %i\n",
250 data->dwSize,
251 data->caps.Usage,
252 data->caps.UsagePage,
253 data->caps.InputReportByteLength,
254 data->caps.OutputReportByteLength,
255 data->caps.FeatureReportByteLength,
256 data->caps.NumberLinkCollectionNodes,
257 data->caps.NumberInputButtonCaps,
258 data->caps.NumberInputValueCaps,
259 data->caps.NumberInputDataIndices,
260 data->caps.NumberOutputButtonCaps,
261 data->caps.NumberOutputValueCaps,
262 data->caps.NumberOutputDataIndices,
263 data->caps.NumberFeatureButtonCaps,
264 data->caps.NumberFeatureValueCaps,
265 data->caps.NumberFeatureDataIndices,
266 data->reportCount[HidP_Input],
267 data->reportCount[HidP_Output],
268 data->reportCount[HidP_Feature],
269 data->elementOffset);
271 end = data->reportCount[HidP_Input];
272 for (i = 0; i < end; i++)
274 debug_print_report("INPUT", data, &data->reports[i]);
276 end += data->reportCount[HidP_Output];
277 for (; i < end; i++)
279 debug_print_report("OUTPUT", data, &data->reports[i]);
281 end += data->reportCount[HidP_Feature];
282 for (; i < end; i++)
284 debug_print_report("FEATURE", data, &data->reports[i]);
286 TRACE(">>> END Preparsed Data\n");
290 struct hid_parser_state
292 USAGE usages[256];
293 DWORD usages_size;
295 struct hid_value_caps items;
297 struct hid_value_caps *stack;
298 DWORD stack_size;
299 DWORD global_idx;
302 static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index )
304 if (index < *array_size) return TRUE;
305 if ((*array_size = *array_size ? (*array_size * 3 / 2) : 32) <= index) return FALSE;
306 if (!(*array = realloc( *array, *array_size * sizeof(**array) ))) return FALSE;
307 return TRUE;
310 static void copy_global_items( struct hid_value_caps *dst, const struct hid_value_caps *src )
312 dst->usage_page = src->usage_page;
313 dst->logical_min = src->logical_min;
314 dst->logical_max = src->logical_max;
315 dst->physical_min = src->physical_min;
316 dst->physical_max = src->physical_max;
317 dst->units_exp = src->units_exp;
318 dst->units = src->units;
319 dst->bit_size = src->bit_size;
320 dst->report_id = src->report_id;
321 dst->report_count = src->report_count;
324 static void reset_local_items( struct hid_parser_state *state )
326 struct hid_value_caps tmp;
327 copy_global_items( &tmp, &state->items );
328 memset( &state->items, 0, sizeof(state->items) );
329 copy_global_items( &state->items, &tmp );
330 state->usages_size = 0;
333 static BOOL parse_global_push( struct hid_parser_state *state )
335 if (!array_reserve( &state->stack, &state->stack_size, state->global_idx ))
337 ERR( "HID parser stack overflow!\n" );
338 return FALSE;
341 copy_global_items( state->stack + state->global_idx, &state->items );
342 state->global_idx++;
343 return TRUE;
346 static BOOL parse_global_pop( struct hid_parser_state *state )
348 if (!state->global_idx)
350 ERR( "HID parser global stack underflow!\n" );
351 return FALSE;
354 state->global_idx--;
355 copy_global_items( &state->items, state->stack + state->global_idx );
356 return TRUE;
359 static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage )
361 state->usages[state->usages_size] = usage;
362 state->items.is_range = FALSE;
363 if (state->usages_size++ == 255) ERR( "HID parser usages stack overflow!\n" );
364 return state->usages_size <= 255;
367 static void free_parser_state( struct hid_parser_state *state )
369 if (state->global_idx) ERR( "%u unpopped device caps on the stack\n", state->global_idx );
370 free( state->stack );
371 free( state );
374 static void parse_io_feature(unsigned int bSize, int itemVal, int bTag,
375 unsigned int *feature_index,
376 struct feature *feature)
378 if (bSize == 0)
380 return;
382 else
384 feature->isData = ((itemVal & INPUT_DATA_CONST) == 0);
385 feature->isArray = ((itemVal & INPUT_ARRAY_VAR) == 0);
386 feature->IsAbsolute = ((itemVal & INPUT_ABS_REL) == 0);
387 feature->Wrap = ((itemVal & INPUT_WRAP) != 0);
388 feature->Linear = ((itemVal & INPUT_LINEAR) == 0);
389 feature->prefState = ((itemVal & INPUT_PREFSTATE) == 0);
390 feature->HasNull = ((itemVal & INPUT_NULL) != 0);
392 if (bTag != TAG_MAIN_INPUT)
394 feature->Volatile = ((itemVal & INPUT_VOLATILE) != 0);
396 if (bSize > 1)
398 feature->BitField = ((itemVal & INPUT_BITFIELD) == 0);
400 feature->index = *feature_index;
401 *feature_index = *feature_index + 1;
405 static void parse_collection(unsigned int bSize, int itemVal,
406 struct collection *collection)
408 if (bSize)
410 collection->type = itemVal;
412 if (itemVal >= 0x07 && itemVal <= 0x7F) {
413 ERR(" (Reserved 0x%x )\n", itemVal);
415 else if (itemVal >= 0x80 && itemVal <= 0xFF) {
416 ERR(" (Vendor Defined 0x%x )\n", itemVal);
421 static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int length,
422 unsigned int *feature_index, unsigned int *collection_index,
423 struct collection *collection, struct hid_parser_state *state )
425 int i, j;
426 UINT32 value;
427 INT32 signed_value;
428 struct feature *feature;
430 for (i = index; i < length;)
432 BYTE item = descriptor[i++];
433 BYTE tag = item >> 4;
434 int size = item & 0x03;
436 if (size == 3) size = 4;
437 if (length - i < size)
439 ERR("Need %d bytes to read item value\n", size);
440 return -1;
443 if (size == 0) signed_value = value = 0;
444 else if (size == 1) signed_value = (INT8)(value = *(UINT8 *)(descriptor + i));
445 else if (size == 2) signed_value = (INT16)(value = *(UINT16 *)(descriptor + i));
446 else if (size == 4) signed_value = (INT32)(value = *(UINT32 *)(descriptor + i));
447 else
449 ERR("Unexpected item value size %d.\n", size);
450 return -1;
452 i += size;
454 #define SHORT_ITEM(tag,type) (((tag)<<4)|((type)<<2))
455 switch (item & SHORT_ITEM(0xf,0x3))
457 case SHORT_ITEM(TAG_MAIN_INPUT, TAG_TYPE_MAIN):
458 case SHORT_ITEM(TAG_MAIN_OUTPUT, TAG_TYPE_MAIN):
459 case SHORT_ITEM(TAG_MAIN_FEATURE, TAG_TYPE_MAIN):
460 for (j = 0; j < state->items.report_count; j++)
462 if (!(feature = calloc(1, sizeof(*feature)))) return -1;
463 list_add_tail(&collection->features, &feature->entry);
464 if (tag == TAG_MAIN_INPUT)
465 feature->type = HidP_Input;
466 else if (tag == TAG_MAIN_OUTPUT)
467 feature->type = HidP_Output;
468 else
469 feature->type = HidP_Feature;
470 parse_io_feature(size, value, tag, feature_index, feature);
471 if (j < state->usages_size) state->items.usage_min = state->usages[j];
472 copy_hidp_value_caps( &feature->caps, &state->items );
473 feature->caps.ReportCount = 1;
474 feature->collection = collection;
475 if (j + 1 >= state->usages_size)
477 feature->caps.ReportCount += state->items.report_count - (j + 1);
478 break;
481 reset_local_items( state );
482 break;
483 case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN):
485 struct collection *subcollection;
486 if (!(subcollection = calloc(1, sizeof(struct collection)))) return -1;
487 list_add_tail(&collection->collections, &subcollection->entry);
488 subcollection->parent = collection;
489 /* Only set our collection once...
490 We do not properly handle composite devices yet. */
491 if (state->usages_size) state->items.usage_min = state->usages[state->usages_size - 1];
492 if (*collection_index == 0) copy_hidp_value_caps( &collection->caps, &state->items );
493 copy_hidp_value_caps( &subcollection->caps, &state->items );
494 subcollection->index = *collection_index;
495 *collection_index = *collection_index + 1;
496 list_init(&subcollection->features);
497 list_init(&subcollection->collections);
498 parse_collection(size, value, subcollection);
499 reset_local_items( state );
501 if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index,
502 subcollection, state )) < 0)
503 return i;
504 continue;
506 case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN):
507 reset_local_items( state );
508 return i;
510 case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL):
511 state->items.usage_page = value;
512 break;
513 case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL):
514 state->items.logical_min = signed_value;
515 break;
516 case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL):
517 state->items.logical_max = signed_value;
518 break;
519 case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL):
520 state->items.physical_min = signed_value;
521 break;
522 case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL):
523 state->items.physical_max = signed_value;
524 break;
525 case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL):
526 state->items.units_exp = signed_value;
527 break;
528 case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL):
529 state->items.units = signed_value;
530 break;
531 case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL):
532 state->items.bit_size = value;
533 break;
534 case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL):
535 state->items.report_id = value;
536 break;
537 case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL):
538 state->items.report_count = value;
539 break;
540 case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL):
541 if (!parse_global_push( state )) return -1;
542 break;
543 case SHORT_ITEM(TAG_GLOBAL_POP, TAG_TYPE_GLOBAL):
544 if (!parse_global_pop( state )) return -1;
545 break;
547 case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL):
548 if (!parse_local_usage( state, value )) return -1;
549 break;
550 case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL):
551 state->items.usage_min = value;
552 state->items.is_range = TRUE;
553 break;
554 case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL):
555 state->items.usage_max = value;
556 state->items.is_range = TRUE;
557 break;
558 case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL):
559 state->items.designator_min = state->items.designator_max = value;
560 state->items.is_designator_range = FALSE;
561 break;
562 case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL):
563 state->items.designator_min = value;
564 state->items.is_designator_range = TRUE;
565 break;
566 case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL):
567 state->items.designator_max = value;
568 state->items.is_designator_range = TRUE;
569 break;
570 case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL):
571 state->items.string_min = state->items.string_max = value;
572 state->items.is_string_range = FALSE;
573 break;
574 case SHORT_ITEM(TAG_LOCAL_STRING_MINIMUM, TAG_TYPE_LOCAL):
575 state->items.string_min = value;
576 state->items.is_string_range = TRUE;
577 break;
578 case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL):
579 state->items.string_max = value;
580 state->items.is_string_range = TRUE;
581 break;
582 case SHORT_ITEM(TAG_LOCAL_DELIMITER, TAG_TYPE_LOCAL):
583 FIXME("delimiter %d not implemented!\n", value);
584 return -1;
586 default:
587 FIXME("item type %x not implemented!\n", item);
588 return -1;
590 #undef SHORT_ITEM
592 return i;
595 static void build_elements(WINE_HID_REPORT *wine_report, WINE_HID_ELEMENT *elems,
596 struct feature* feature, USHORT *data_index)
598 WINE_HID_ELEMENT *wine_element = elems + wine_report->elementIdx + wine_report->elementCount;
599 ULONG index_count;
601 if (!feature->isData)
603 wine_report->bitSize += feature->caps.BitSize * feature->caps.ReportCount;
604 return;
607 wine_element->valueStartBit = wine_report->bitSize;
609 wine_element->bitCount = (feature->caps.BitSize * feature->caps.ReportCount);
610 wine_report->bitSize += wine_element->bitCount;
612 wine_element->caps = feature->caps;
613 wine_element->caps.BitField = feature->BitField;
614 wine_element->caps.LinkCollection = feature->collection->index;
615 wine_element->caps.LinkUsage = feature->collection->caps.NotRange.Usage;
616 wine_element->caps.LinkUsagePage = feature->collection->caps.UsagePage;
617 wine_element->caps.IsAbsolute = feature->IsAbsolute;
618 wine_element->caps.HasNull = feature->HasNull;
620 if (wine_element->caps.IsRange)
622 if (wine_element->caps.BitSize == 1) index_count = wine_element->bitCount - 1;
623 else index_count = wine_element->caps.Range.UsageMax - wine_element->caps.Range.UsageMin;
624 wine_element->caps.Range.DataIndexMin = *data_index;
625 wine_element->caps.Range.DataIndexMax = *data_index + index_count;
626 *data_index = *data_index + index_count + 1;
628 else
630 wine_element->caps.NotRange.DataIndex = *data_index;
631 wine_element->caps.NotRange.Reserved4 = *data_index;
632 *data_index = *data_index + 1;
635 wine_report->elementCount++;
638 static void count_elements(struct feature* feature, USHORT *buttons, USHORT *values)
640 if (!feature->isData)
641 return;
643 if (feature->caps.BitSize == 1)
644 (*buttons)++;
645 else
646 (*values)++;
649 struct preparse_ctx
651 int report_count[3];
652 int elem_count;
653 int report_elem_count[3][256];
655 int elem_alloc;
656 BOOL report_created[3][256];
659 static void create_preparse_ctx(const struct collection *base, struct preparse_ctx *ctx)
661 struct feature *f;
662 struct collection *c;
664 LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry)
666 ctx->elem_count++;
667 ctx->report_elem_count[f->type][f->caps.ReportID]++;
668 if (ctx->report_elem_count[f->type][f->caps.ReportID] != 1)
669 continue;
670 ctx->report_count[f->type]++;
673 LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry)
674 create_preparse_ctx(c, ctx);
677 static void preparse_collection(const struct collection *root, const struct collection *base,
678 WINE_HIDP_PREPARSED_DATA *data, struct preparse_ctx *ctx)
680 WINE_HID_ELEMENT *elem = HID_ELEMS(data);
681 WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data);
682 struct feature *f;
683 struct collection *c;
684 struct list *entry;
686 LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry)
688 WINE_HID_REPORT *report;
690 if (!ctx->report_created[f->type][f->caps.ReportID])
692 ctx->report_created[f->type][f->caps.ReportID] = TRUE;
693 data->reportIdx[f->type][f->caps.ReportID] = data->reportCount[f->type]++;
694 if (f->type > 0) data->reportIdx[f->type][f->caps.ReportID] += ctx->report_count[0];
695 if (f->type > 1) data->reportIdx[f->type][f->caps.ReportID] += ctx->report_count[1];
697 report = &data->reports[data->reportIdx[f->type][f->caps.ReportID]];
698 report->reportID = f->caps.ReportID;
699 /* Room for the reportID */
700 report->bitSize = 8;
701 report->elementIdx = ctx->elem_alloc;
702 ctx->elem_alloc += ctx->report_elem_count[f->type][f->caps.ReportID];
705 report = &data->reports[data->reportIdx[f->type][f->caps.ReportID]];
706 switch (f->type)
708 case HidP_Input:
709 build_elements(report, elem, f, &data->caps.NumberInputDataIndices);
710 count_elements(f, &data->caps.NumberInputButtonCaps, &data->caps.NumberInputValueCaps);
711 data->caps.InputReportByteLength =
712 max(data->caps.InputReportByteLength, (report->bitSize + 7) / 8);
713 break;
714 case HidP_Output:
715 build_elements(report, elem, f, &data->caps.NumberOutputDataIndices);
716 count_elements(f, &data->caps.NumberOutputButtonCaps, &data->caps.NumberOutputValueCaps);
717 data->caps.OutputReportByteLength =
718 max(data->caps.OutputReportByteLength, (report->bitSize + 7) / 8);
719 break;
720 case HidP_Feature:
721 build_elements(report, elem, f, &data->caps.NumberFeatureDataIndices);
722 count_elements(f, &data->caps.NumberFeatureButtonCaps, &data->caps.NumberFeatureValueCaps);
723 data->caps.FeatureReportByteLength =
724 max(data->caps.FeatureReportByteLength, (report->bitSize + 7) / 8);
725 break;
729 if (root != base)
731 nodes[base->index].LinkUsagePage = base->caps.UsagePage;
732 nodes[base->index].LinkUsage = base->caps.NotRange.Usage;
733 nodes[base->index].Parent = base->parent == root ? 0 : base->parent->index;
734 nodes[base->index].CollectionType = base->type;
735 nodes[base->index].IsAlias = 0;
737 if ((entry = list_head(&base->collections)))
738 nodes[base->index].FirstChild = LIST_ENTRY(entry, struct collection, entry)->index;
741 LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry)
743 preparse_collection(root, c, data, ctx);
745 if ((entry = list_next(&base->collections, &c->entry)))
746 nodes[c->index].NextSibling = LIST_ENTRY(entry, struct collection, entry)->index;
747 if (root != base) nodes[base->index].NumberOfChildren++;
751 static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_collection, unsigned int node_count)
753 WINE_HIDP_PREPARSED_DATA *data;
754 unsigned int report_count;
755 unsigned int size;
757 struct preparse_ctx ctx;
758 unsigned int element_off;
759 unsigned int nodes_offset;
761 memset(&ctx, 0, sizeof(ctx));
762 create_preparse_ctx(base_collection, &ctx);
764 report_count = ctx.report_count[HidP_Input] + ctx.report_count[HidP_Output]
765 + ctx.report_count[HidP_Feature];
766 element_off = FIELD_OFFSET(WINE_HIDP_PREPARSED_DATA, reports[report_count]);
767 size = element_off + (ctx.elem_count * sizeof(WINE_HID_ELEMENT));
769 nodes_offset = size;
770 size += node_count * sizeof(WINE_HID_LINK_COLLECTION_NODE);
772 if (!(data = calloc(1, size))) return NULL;
773 data->magic = HID_MAGIC;
774 data->dwSize = size;
775 data->caps.Usage = base_collection->caps.NotRange.Usage;
776 data->caps.UsagePage = base_collection->caps.UsagePage;
777 data->caps.NumberLinkCollectionNodes = node_count;
778 data->elementOffset = element_off;
779 data->nodesOffset = nodes_offset;
781 preparse_collection(base_collection, base_collection, data, &ctx);
782 return data;
785 static void free_collection(struct collection *collection)
787 struct feature *fentry, *fnext;
788 struct collection *centry, *cnext;
789 LIST_FOR_EACH_ENTRY_SAFE(centry, cnext, &collection->collections, struct collection, entry)
791 list_remove(&centry->entry);
792 free_collection(centry);
794 LIST_FOR_EACH_ENTRY_SAFE(fentry, fnext, &collection->features, struct feature, entry)
796 list_remove(&fentry->entry);
797 free(fentry);
799 free(collection);
802 WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
804 WINE_HIDP_PREPARSED_DATA *data = NULL;
805 struct hid_parser_state *state;
806 struct collection *base;
807 int i;
809 unsigned int feature_count = 0;
810 unsigned int cidx;
812 if (TRACE_ON(hid))
814 TRACE("descriptor %p, length %u:\n", descriptor, length);
815 for (i = 0; i < length;)
817 TRACE("%08x ", i);
818 do { TRACE(" %02x", descriptor[i]); } while (++i % 16 && i < length);
819 TRACE("\n");
823 if (!(state = calloc( 1, sizeof(*state) ))) return NULL;
824 if (!(base = calloc( 1, sizeof(*base) )))
826 free( state );
827 return NULL;
829 base->index = 1;
830 list_init(&base->features);
831 list_init(&base->collections);
833 cidx = 0;
834 if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state ) < 0)
836 free_collection(base);
837 free_parser_state( state );
838 return NULL;
841 debug_collection(base);
843 if ((data = build_PreparseData(base, cidx)))
844 debug_print_preparsed(data);
845 free_collection(base);
847 free_parser_state( state );
848 return data;