summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c')
-rw-r--r--contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c990
1 files changed, 990 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c b/contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c
new file mode 100644
index 0000000..6697d3c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c
@@ -0,0 +1,990 @@
1/*******************************************************
2 HIDAPI - Multi-Platform library for
3 communication with HID devices.
4
5 libusb/hidapi Team
6
7 Copyright 2022, All Rights Reserved.
8
9 At the discretion of the user of this library,
10 this software may be licensed under the terms of the
11 GNU General Public License v3, a BSD-Style license, or the
12 original HIDAPI license as outlined in the LICENSE.txt,
13 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
14 files located at the root of the source distribution.
15 These files may also be found in the public source
16 code repository located at:
17 https://github.com/libusb/hidapi .
18********************************************************/
19#include "hidapi_descriptor_reconstruct.h"
20
21/**
22 * @brief References to report descriptor buffer.
23 *
24 */
25struct rd_buffer {
26 unsigned char* buf; /* Pointer to the array which stores the reconstructed descriptor */
27 size_t buf_size; /* Size of the buffer in bytes */
28 size_t byte_idx; /* Index of the next report byte to write to buf array */
29};
30
31/**
32 * @brief Function that appends a byte to encoded report descriptor buffer.
33 *
34 * @param[in] byte Single byte to append.
35 * @param rpt_desc Pointer to report descriptor buffer struct.
36 */
37static void rd_append_byte(unsigned char byte, struct rd_buffer* rpt_desc) {
38 if (rpt_desc->byte_idx < rpt_desc->buf_size) {
39 rpt_desc->buf[rpt_desc->byte_idx] = byte;
40 rpt_desc->byte_idx++;
41 }
42}
43
44/**
45 * @brief Writes a short report descriptor item according USB HID spec 1.11 chapter 6.2.2.2.
46 *
47 * @param[in] rd_item Enumeration identifying type (Main, Global, Local) and function (e.g Usage or Report Count) of the item.
48 * @param[in] data Data (Size depends on rd_item 0,1,2 or 4bytes).
49 * @param rpt_desc Pointer to report descriptor buffer struct.
50 *
51 * @return Returns 0 if successful, -1 for error.
52 */
53static int rd_write_short_item(rd_items rd_item, LONG64 data, struct rd_buffer* rpt_desc) {
54 if (rd_item & 0x03) {
55 // Invalid input data, last to bits are reserved for data size
56 return -1;
57 }
58
59 if (rd_item == rd_main_collection_end) {
60 // Item without data (1Byte prefix only)
61 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x00;
62 rd_append_byte(oneBytePrefix, rpt_desc);
63 }
64 else if ((rd_item == rd_global_logical_minimum) ||
65 (rd_item == rd_global_logical_maximum) ||
66 (rd_item == rd_global_physical_minimum) ||
67 (rd_item == rd_global_physical_maximum)) {
68 // Item with signed integer data
69 if ((data >= -128) && (data <= 127)) {
70 // 1Byte prefix + 1Byte data
71 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
72 char localData = (char)data;
73 rd_append_byte(oneBytePrefix, rpt_desc);
74 rd_append_byte(localData & 0xFF, rpt_desc);
75 }
76 else if ((data >= -32768) && (data <= 32767)) {
77 // 1Byte prefix + 2Byte data
78 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
79 INT16 localData = (INT16)data;
80 rd_append_byte(oneBytePrefix, rpt_desc);
81 rd_append_byte(localData & 0xFF, rpt_desc);
82 rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
83 }
84 else if ((data >= -2147483648LL) && (data <= 2147483647)) {
85 // 1Byte prefix + 4Byte data
86 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
87 INT32 localData = (INT32)data;
88 rd_append_byte(oneBytePrefix, rpt_desc);
89 rd_append_byte(localData & 0xFF, rpt_desc);
90 rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
91 rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
92 rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
93 }
94 else {
95 // Data out of 32 bit signed integer range
96 return -1;
97 }
98 }
99 else {
100 // Item with unsigned integer data
101 if ((data >= 0) && (data <= 0xFF)) {
102 // 1Byte prefix + 1Byte data
103 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
104 unsigned char localData = (unsigned char)data;
105 rd_append_byte(oneBytePrefix, rpt_desc);
106 rd_append_byte(localData & 0xFF, rpt_desc);
107 }
108 else if ((data >= 0) && (data <= 0xFFFF)) {
109 // 1Byte prefix + 2Byte data
110 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
111 UINT16 localData = (UINT16)data;
112 rd_append_byte(oneBytePrefix, rpt_desc);
113 rd_append_byte(localData & 0xFF, rpt_desc);
114 rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
115 }
116 else if ((data >= 0) && (data <= 0xFFFFFFFF)) {
117 // 1Byte prefix + 4Byte data
118 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
119 UINT32 localData = (UINT32)data;
120 rd_append_byte(oneBytePrefix, rpt_desc);
121 rd_append_byte(localData & 0xFF, rpt_desc);
122 rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
123 rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
124 rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
125 }
126 else {
127 // Data out of 32 bit unsigned integer range
128 return -1;
129 }
130 }
131 return 0;
132}
133
134static struct rd_main_item_node * rd_append_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
135 struct rd_main_item_node *new_list_node;
136
137 // Determine last node in the list
138 while (*list != NULL)
139 {
140 list = &(*list)->next;
141 }
142
143 new_list_node = malloc(sizeof(*new_list_node)); // Create new list entry
144 new_list_node->FirstBit = first_bit;
145 new_list_node->LastBit = last_bit;
146 new_list_node->TypeOfNode = type_of_node;
147 new_list_node->CapsIndex = caps_index;
148 new_list_node->CollectionIndex = collection_index;
149 new_list_node->MainItemType = main_item_type;
150 new_list_node->ReportID = report_id;
151 new_list_node->next = NULL; // NULL marks last node in the list
152
153 *list = new_list_node;
154 return new_list_node;
155}
156
157static struct rd_main_item_node * rd_insert_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
158 // Insert item after the main item node referenced by list
159 struct rd_main_item_node *next_item = (*list)->next;
160 (*list)->next = NULL;
161 rd_append_main_item_node(first_bit, last_bit, type_of_node, caps_index, collection_index, main_item_type, report_id, list);
162 (*list)->next->next = next_item;
163 return (*list)->next;
164}
165
166static struct rd_main_item_node * rd_search_main_item_list_for_bit_position(int search_bit, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
167 // Determine first INPUT/OUTPUT/FEATURE main item, where the last bit position is equal or greater than the search bit position
168
169 while (((*list)->next->MainItemType != rd_collection) &&
170 ((*list)->next->MainItemType != rd_collection_end) &&
171 !(((*list)->next->LastBit >= search_bit) &&
172 ((*list)->next->ReportID == report_id) &&
173 ((*list)->next->MainItemType == main_item_type))
174 )
175 {
176 list = &(*list)->next;
177 }
178 return *list;
179}
180
181int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned char *buf, size_t buf_size)
182{
183 hidp_preparsed_data *pp_data = (hidp_preparsed_data *) preparsed_data;
184
185 // Check if MagicKey is correct, to ensure that pp_data points to an valid preparse data structure
186 if (memcmp(pp_data->MagicKey, "HidP KDR", 8) != 0) {
187 return -1;
188 }
189
190 struct rd_buffer rpt_desc;
191 rpt_desc.buf = buf;
192 rpt_desc.buf_size = buf_size;
193 rpt_desc.byte_idx = 0;
194
195 // Set pointer to the first node of link_collection_nodes
196 phid_pp_link_collection_node link_collection_nodes = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
197
198 // ****************************************************************************************************************************
199 // Create lookup tables for the bit range of each report per collection (position of first bit and last bit in each collection)
200 // coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
201 // ****************************************************************************************************************************
202
203 // Allocate memory and initialize lookup table
204 rd_bit_range ****coll_bit_range;
205 coll_bit_range = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_bit_range));
206 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
207 coll_bit_range[collection_node_idx] = malloc(256 * sizeof(*coll_bit_range[0])); // 256 possible report IDs (incl. 0x00)
208 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
209 coll_bit_range[collection_node_idx][reportid_idx] = malloc(NUM_OF_HIDP_REPORT_TYPES * sizeof(*coll_bit_range[0][0]));
210 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
211 coll_bit_range[collection_node_idx][reportid_idx][rt_idx] = malloc(sizeof(rd_bit_range));
212 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = -1;
213 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = -1;
214 }
215 }
216 }
217
218 // Fill the lookup table where caps exist
219 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
220 for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
221 int first_bit, last_bit;
222 first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8
223 + pp_data->caps[caps_idx].BitPosition;
224 last_bit = first_bit + pp_data->caps[caps_idx].ReportSize
225 * pp_data->caps[caps_idx].ReportCount - 1;
226 if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit == -1 ||
227 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit > first_bit) {
228 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit = first_bit;
229 }
230 if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit < last_bit) {
231 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit = last_bit;
232 }
233 }
234 }
235
236 // *************************************************************************
237 // -Determine hierarchy levels of each collections and store it in:
238 // coll_levels[COLLECTION_INDEX]
239 // -Determine number of direct childs of each collections and store it in:
240 // coll_number_of_direct_childs[COLLECTION_INDEX]
241 // *************************************************************************
242 int max_coll_level = 0;
243 int *coll_levels = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_levels[0]));
244 int *coll_number_of_direct_childs = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_number_of_direct_childs[0]));
245 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
246 coll_levels[collection_node_idx] = -1;
247 coll_number_of_direct_childs[collection_node_idx] = 0;
248 }
249
250 {
251 int actual_coll_level = 0;
252 USHORT collection_node_idx = 0;
253 while (actual_coll_level >= 0) {
254 coll_levels[collection_node_idx] = actual_coll_level;
255 if ((link_collection_nodes[collection_node_idx].NumberOfChildren > 0) &&
256 (coll_levels[link_collection_nodes[collection_node_idx].FirstChild] == -1)) {
257 actual_coll_level++;
258 coll_levels[collection_node_idx] = actual_coll_level;
259 if (max_coll_level < actual_coll_level) {
260 max_coll_level = actual_coll_level;
261 }
262 coll_number_of_direct_childs[collection_node_idx]++;
263 collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
264 }
265 else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
266 coll_number_of_direct_childs[link_collection_nodes[collection_node_idx].Parent]++;
267 collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
268 }
269 else {
270 actual_coll_level--;
271 if (actual_coll_level >= 0) {
272 collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
273 }
274 }
275 }
276 }
277
278 // *********************************************************************************
279 // Propagate the bit range of each report from the child collections to their parent
280 // and store the merged result for the parent
281 // *********************************************************************************
282 for (int actual_coll_level = max_coll_level - 1; actual_coll_level >= 0; actual_coll_level--) {
283 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
284 if (coll_levels[collection_node_idx] == actual_coll_level) {
285 USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
286 while (child_idx) {
287 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
288 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
289 // Merge bit range from childs
290 if ((coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
291 (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit)) {
292 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit;
293 }
294 if (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit < coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit) {
295 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit;
296 }
297 child_idx = link_collection_nodes[child_idx].NextSibling;
298 }
299 }
300 }
301 }
302 }
303 }
304
305 // **************************************************************************************************
306 // Determine child collection order of the whole hierarchy, based on previously determined bit ranges
307 // and store it this index coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
308 // **************************************************************************************************
309 USHORT **coll_child_order;
310 coll_child_order = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_child_order));
311 {
312 BOOLEAN *coll_parsed_flag;
313 coll_parsed_flag = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_parsed_flag[0]));
314 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
315 coll_parsed_flag[collection_node_idx] = FALSE;
316 }
317 int actual_coll_level = 0;
318 USHORT collection_node_idx = 0;
319 while (actual_coll_level >= 0) {
320 if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
321 (coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] == FALSE)) {
322 coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] = TRUE;
323 coll_child_order[collection_node_idx] = malloc((coll_number_of_direct_childs[collection_node_idx]) * sizeof(*coll_child_order[0]));
324
325 {
326 // Create list of child collection indices
327 // sorted reverse to the order returned to HidP_GetLinkCollectionNodeschild
328 // which seems to match the original order, as long as no bit position needs to be considered
329 USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
330 int child_count = coll_number_of_direct_childs[collection_node_idx] - 1;
331 coll_child_order[collection_node_idx][child_count] = child_idx;
332 while (link_collection_nodes[child_idx].NextSibling) {
333 child_count--;
334 child_idx = link_collection_nodes[child_idx].NextSibling;
335 coll_child_order[collection_node_idx][child_count] = child_idx;
336 }
337 }
338
339 if (coll_number_of_direct_childs[collection_node_idx] > 1) {
340 // Sort child collections indices by bit positions
341 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
342 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
343 for (int child_idx = 1; child_idx < coll_number_of_direct_childs[collection_node_idx]; child_idx++) {
344 // since the coll_bit_range array is not sorted, we need to reference the collection index in
345 // our sorted coll_child_order array, and look up the corresponding bit ranges for comparing values to sort
346 int prev_coll_idx = coll_child_order[collection_node_idx][child_idx - 1];
347 int cur_coll_idx = coll_child_order[collection_node_idx][child_idx];
348 if ((coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
349 (coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
350 (coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit)) {
351 // Swap position indices of the two compared child collections
352 USHORT idx_latch = coll_child_order[collection_node_idx][child_idx - 1];
353 coll_child_order[collection_node_idx][child_idx - 1] = coll_child_order[collection_node_idx][child_idx];
354 coll_child_order[collection_node_idx][child_idx] = idx_latch;
355 }
356 }
357 }
358 }
359 }
360 actual_coll_level++;
361 collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
362 }
363 else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
364 collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
365 }
366 else {
367 actual_coll_level--;
368 if (actual_coll_level >= 0) {
369 collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
370 }
371 }
372 }
373 free(coll_parsed_flag);
374 }
375
376
377 // ***************************************************************************************
378 // Create sorted main_item_list containing all the Collection and CollectionEnd main items
379 // ***************************************************************************************
380 struct rd_main_item_node *main_item_list = NULL; // List root
381 // Lookup table to find the Collection items in the list by index
382 struct rd_main_item_node **coll_begin_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_begin_lookup));
383 struct rd_main_item_node **coll_end_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_end_lookup));
384 {
385 int *coll_last_written_child = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_last_written_child[0]));
386 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
387 coll_last_written_child[collection_node_idx] = -1;
388 }
389
390 int actual_coll_level = 0;
391 USHORT collection_node_idx = 0;
392 struct rd_main_item_node *firstDelimiterNode = NULL;
393 struct rd_main_item_node *delimiterCloseNode = NULL;
394 coll_begin_lookup[0] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
395 while (actual_coll_level >= 0) {
396 if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
397 (coll_last_written_child[collection_node_idx] == -1)) {
398 // Collection has child collections, but none is written to the list yet
399
400 coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][0];
401 collection_node_idx = coll_child_order[collection_node_idx][0];
402
403 // In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
404 // While the order in the WIN32 capabiliy strutures is the opposite:
405 // Here the preferred usage is the last aliased usage in the sequence.
406
407 if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
408 // Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
409 firstDelimiterNode = main_item_list;
410 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
411 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
412 delimiterCloseNode = main_item_list;
413 }
414 else {
415 // Normal not aliased collection
416 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
417 actual_coll_level++;
418 }
419
420
421 }
422 else if ((coll_number_of_direct_childs[collection_node_idx] > 1) &&
423 (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][coll_number_of_direct_childs[collection_node_idx] - 1])) {
424 // Collection has child collections, and this is not the first child
425
426 int nextChild = 1;
427 while (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][nextChild - 1]) {
428 nextChild++;
429 }
430 coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][nextChild];
431 collection_node_idx = coll_child_order[collection_node_idx][nextChild];
432
433 if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
434 // Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
435 firstDelimiterNode = main_item_list;
436 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
437 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
438 delimiterCloseNode = main_item_list;
439 }
440 else if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
441 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
442 }
443 else if (!link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
444 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
445 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_open, 0, &firstDelimiterNode);
446 firstDelimiterNode = NULL;
447 main_item_list = delimiterCloseNode;
448 delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
449 }
450 if (!link_collection_nodes[collection_node_idx].IsAlias) {
451 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
452 actual_coll_level++;
453 }
454 }
455 else {
456 actual_coll_level--;
457 coll_end_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection_end, 0, &main_item_list);
458 collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
459 }
460 }
461 free(coll_last_written_child);
462 }
463
464
465 // ****************************************************************
466 // Inserted Input/Output/Feature main items into the main_item_list
467 // in order of reconstructed bit positions
468 // ****************************************************************
469 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
470 // Add all value caps to node list
471 struct rd_main_item_node *firstDelimiterNode = NULL;
472 struct rd_main_item_node *delimiterCloseNode = NULL;
473 for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
474 struct rd_main_item_node *coll_begin = coll_begin_lookup[pp_data->caps[caps_idx].LinkCollection];
475 int first_bit, last_bit;
476 first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 +
477 pp_data->caps[caps_idx].BitPosition;
478 last_bit = first_bit + pp_data->caps[caps_idx].ReportSize *
479 pp_data->caps[caps_idx].ReportCount - 1;
480
481 for (int child_idx = 0; child_idx < coll_number_of_direct_childs[pp_data->caps[caps_idx].LinkCollection]; child_idx++) {
482 // Determine in which section before/between/after child collection the item should be inserted
483 if (first_bit < coll_bit_range[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit)
484 {
485 // Note, that the default value for undefined coll_bit_range is -1, which can't be greater than the bit position
486 break;
487 }
488 coll_begin = coll_end_lookup[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]];
489 }
490 struct rd_main_item_node *list_node;
491 list_node = rd_search_main_item_list_for_bit_position(first_bit, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &coll_begin);
492
493 // In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
494 // While the order in the WIN32 capabiliy strutures is the opposite:
495 // Here the preferred usage is the last aliased usage in the sequence.
496
497 if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode == NULL)) {
498 // Alliased Usage (First node in pp_data->caps -> Last entry in report descriptor output)
499 firstDelimiterNode = list_node;
500 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
501 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_close, pp_data->caps[caps_idx].ReportID, &list_node);
502 delimiterCloseNode = list_node;
503 } else if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
504 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
505 }
506 else if (!pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
507 // Alliased Collection (Last node in pp_data->caps -> First entry in report descriptor output)
508 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
509 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_open, pp_data->caps[caps_idx].ReportID, &list_node);
510 firstDelimiterNode = NULL;
511 list_node = delimiterCloseNode;
512 delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
513 }
514 if (!pp_data->caps[caps_idx].IsAlias) {
515 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &list_node);
516 }
517 }
518 }
519
520
521 // ***********************************************************
522 // Add const main items for padding to main_item_list
523 // -To fill all bit gaps
524 // -At each report end for 8bit padding
525 // Note that information about the padding at the report end,
526 // is not stored in the preparsed data, but in practice all
527 // report descriptors seem to have it, as assumed here.
528 // ***********************************************************
529 {
530 int *last_bit_position[NUM_OF_HIDP_REPORT_TYPES];
531 struct rd_main_item_node **last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES];
532 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
533 last_bit_position[rt_idx] = malloc(256 * sizeof(*last_bit_position[rt_idx]));
534 last_report_item_lookup[rt_idx] = malloc(256 * sizeof(*last_report_item_lookup[rt_idx]));
535 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
536 last_bit_position[rt_idx][reportid_idx] = -1;
537 last_report_item_lookup[rt_idx][reportid_idx] = NULL;
538 }
539 }
540
541 struct rd_main_item_node *list = main_item_list; // List root;
542
543 while (list->next != NULL)
544 {
545 if ((list->MainItemType >= rd_input) &&
546 (list->MainItemType <= rd_feature)) {
547 // INPUT, OUTPUT or FEATURE
548 if (list->FirstBit != -1) {
549 if ((last_bit_position[list->MainItemType][list->ReportID] + 1 != list->FirstBit) &&
550 (last_report_item_lookup[list->MainItemType][list->ReportID] != NULL) &&
551 (last_report_item_lookup[list->MainItemType][list->ReportID]->FirstBit != list->FirstBit) // Happens in case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array
552 ) {
553 struct rd_main_item_node *list_node = rd_search_main_item_list_for_bit_position(last_bit_position[list->MainItemType][list->ReportID], list->MainItemType, list->ReportID, &last_report_item_lookup[list->MainItemType][list->ReportID]);
554 rd_insert_main_item_node(last_bit_position[list->MainItemType][list->ReportID] + 1, list->FirstBit - 1, rd_item_node_padding, -1, 0, list->MainItemType, list->ReportID, &list_node);
555 }
556 last_bit_position[list->MainItemType][list->ReportID] = list->LastBit;
557 last_report_item_lookup[list->MainItemType][list->ReportID] = list;
558 }
559 }
560 list = list->next;
561 }
562 // Add 8 bit padding at each report end
563 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
564 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
565 if (last_bit_position[rt_idx][reportid_idx] != -1) {
566 int padding = 8 - ((last_bit_position[rt_idx][reportid_idx] + 1) % 8);
567 if (padding < 8) {
568 // Insert padding item after item referenced in last_report_item_lookup
569 rd_insert_main_item_node(last_bit_position[rt_idx][reportid_idx] + 1, last_bit_position[rt_idx][reportid_idx] + padding, rd_item_node_padding, -1, 0, (rd_main_items) rt_idx, (unsigned char) reportid_idx, &last_report_item_lookup[rt_idx][reportid_idx]);
570 }
571 }
572 }
573 free(last_bit_position[rt_idx]);
574 free(last_report_item_lookup[rt_idx]);
575 }
576 }
577
578
579 // ***********************************
580 // Encode the report descriptor output
581 // ***********************************
582 UCHAR last_report_id = 0;
583 USAGE last_usage_page = 0;
584 LONG last_physical_min = 0;// If both, Physical Minimum and Physical Maximum are 0, the logical limits should be taken as physical limits according USB HID spec 1.11 chapter 6.2.2.7
585 LONG last_physical_max = 0;
586 ULONG last_unit_exponent = 0; // If Unit Exponent is Undefined it should be considered as 0 according USB HID spec 1.11 chapter 6.2.2.7
587 ULONG last_unit = 0; // If the first nibble is 7, or second nibble of Unit is 0, the unit is None according USB HID spec 1.11 chapter 6.2.2.7
588 BOOLEAN inhibit_write_of_usage = FALSE; // Needed in case of delimited usage print, before the normal collection or cap
589 int report_count = 0;
590 while (main_item_list != NULL)
591 {
592 int rt_idx = main_item_list->MainItemType;
593 int caps_idx = main_item_list->CapsIndex;
594 if (main_item_list->MainItemType == rd_collection) {
595 if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
596 // Write "Usage Page" at the begin of a collection - except it refers the same table as wrote last
597 rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
598 last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
599 }
600 if (inhibit_write_of_usage) {
601 // Inhibit only once after DELIMITER statement
602 inhibit_write_of_usage = FALSE;
603 }
604 else {
605 // Write "Usage" of collection
606 rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
607 }
608 // Write begin of "Collection"
609 rd_write_short_item(rd_main_collection, link_collection_nodes[main_item_list->CollectionIndex].CollectionType, &rpt_desc);
610 }
611 else if (main_item_list->MainItemType == rd_collection_end) {
612 // Write "End Collection"
613 rd_write_short_item(rd_main_collection_end, 0, &rpt_desc);
614 }
615 else if (main_item_list->MainItemType == rd_delimiter_open) {
616 if (main_item_list->CollectionIndex != -1) {
617 // Write "Usage Page" inside of a collection delmiter section
618 if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
619 rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
620 last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
621 }
622 }
623 else if (main_item_list->CapsIndex != 0) {
624 // Write "Usage Page" inside of a main item delmiter section
625 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
626 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
627 last_usage_page = pp_data->caps[caps_idx].UsagePage;
628 }
629 }
630 // Write "Delimiter Open"
631 rd_write_short_item(rd_local_delimiter, 1, &rpt_desc); // 1 = open set of aliased usages
632 }
633 else if (main_item_list->MainItemType == rd_delimiter_usage) {
634 if (main_item_list->CollectionIndex != -1) {
635 // Write aliased collection "Usage"
636 rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
637 } if (main_item_list->CapsIndex != 0) {
638 // Write aliased main item range from "Usage Minimum" to "Usage Maximum"
639 if (pp_data->caps[caps_idx].IsRange) {
640 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
641 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
642 }
643 else {
644 // Write single aliased main item "Usage"
645 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
646 }
647 }
648 }
649 else if (main_item_list->MainItemType == rd_delimiter_close) {
650 // Write "Delimiter Close"
651 rd_write_short_item(rd_local_delimiter, 0, &rpt_desc); // 0 = close set of aliased usages
652 // Inhibit next usage write
653 inhibit_write_of_usage = TRUE;
654 }
655 else if (main_item_list->TypeOfNode == rd_item_node_padding) {
656 // Padding
657 // The preparsed data doesn't contain any information about padding. Therefore all undefined gaps
658 // in the reports are filled with the same style of constant padding.
659
660 // Write "Report Size" with number of padding bits
661 rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
662
663 // Write "Report Count" for padding always as 1
664 rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
665
666 if (rt_idx == HidP_Input) {
667 // Write "Input" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
668 rd_write_short_item(rd_main_input, 0x03, &rpt_desc); // Const / Abs
669 }
670 else if (rt_idx == HidP_Output) {
671 // Write "Output" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
672 rd_write_short_item(rd_main_output, 0x03, &rpt_desc); // Const / Abs
673 }
674 else if (rt_idx == HidP_Feature) {
675 // Write "Feature" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
676 rd_write_short_item(rd_main_feature, 0x03, &rpt_desc); // Const / Abs
677 }
678 report_count = 0;
679 }
680 else if (pp_data->caps[caps_idx].IsButtonCap) {
681 // Button
682 // (The preparsed data contain different data for 1 bit Button caps, than for parametric Value caps)
683
684 if (last_report_id != pp_data->caps[caps_idx].ReportID) {
685 // Write "Report ID" if changed
686 rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
687 last_report_id = pp_data->caps[caps_idx].ReportID;
688 }
689
690 // Write "Usage Page" when changed
691 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
692 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
693 last_usage_page = pp_data->caps[caps_idx].UsagePage;
694 }
695
696 // Write only local report items for each cap, if ReportCount > 1
697 if (pp_data->caps[caps_idx].IsRange) {
698 report_count += (pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin);
699 }
700
701 if (inhibit_write_of_usage) {
702 // Inhibit only once after Delimiter - Reset flag
703 inhibit_write_of_usage = FALSE;
704 }
705 else {
706 if (pp_data->caps[caps_idx].IsRange) {
707 // Write range from "Usage Minimum" to "Usage Maximum"
708 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
709 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
710 }
711 else {
712 // Write single "Usage"
713 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
714 }
715 }
716
717 if (pp_data->caps[caps_idx].IsDesignatorRange) {
718 // Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
719 rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
720 rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
721 }
722 else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
723 // Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
724 // that specifies the number of additional descriptor sets.
725 // Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
726 // Write single "Designator Index"
727 rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
728 }
729
730 if (pp_data->caps[caps_idx].IsStringRange) {
731 // Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
732 rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
733 rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
734 }
735 else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
736 // String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
737 // therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
738 // Write single "String Index"
739 rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
740 }
741
742 if ((main_item_list->next != NULL) &&
743 ((int)main_item_list->next->MainItemType == rt_idx) &&
744 (main_item_list->next->TypeOfNode == rd_item_node_cap) &&
745 (pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
746 (!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
747 (!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
748 (pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
749 (pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
750 (pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField)
751 ) {
752 if (main_item_list->next->FirstBit != main_item_list->FirstBit) {
753 // In case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array, the report count should be incremented
754
755 // Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
756 report_count++;
757 }
758 }
759 else {
760
761 if ((pp_data->caps[caps_idx].Button.LogicalMin == 0) &&
762 (pp_data->caps[caps_idx].Button.LogicalMax == 0)) {
763 // While a HID report descriptor must always contain LogicalMinimum and LogicalMaximum,
764 // the preparsed data contain both fields set to zero, for the case of simple buttons
765 // Write "Logical Minimum" set to 0 and "Logical Maximum" set to 1
766 rd_write_short_item(rd_global_logical_minimum, 0, &rpt_desc);
767 rd_write_short_item(rd_global_logical_maximum, 1, &rpt_desc);
768 }
769 else {
770 // Write logical range from "Logical Minimum" to "Logical Maximum"
771 rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].Button.LogicalMin, &rpt_desc);
772 rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].Button.LogicalMax, &rpt_desc);
773 }
774
775 // Write "Report Size"
776 rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
777
778 // Write "Report Count"
779 if (!pp_data->caps[caps_idx].IsRange) {
780 // Variable bit field with one bit per button
781 // In case of multiple usages with the same items, only "Usage" is written per cap, and "Report Count" is incremented
782 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
783 }
784 else {
785 // Button array of "Report Size" x "Report Count
786 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount, &rpt_desc);
787 }
788
789
790 // Buttons have only 1 bit and therefore no physical limits/units -> Set to undefined state
791 if (last_physical_min != 0) {
792 // Write "Physical Minimum", but only if changed
793 last_physical_min = 0;
794 rd_write_short_item(rd_global_physical_minimum, last_physical_min, &rpt_desc);
795 }
796 if (last_physical_max != 0) {
797 // Write "Physical Maximum", but only if changed
798 last_physical_max = 0;
799 rd_write_short_item(rd_global_physical_maximum, last_physical_max, &rpt_desc);
800 }
801 if (last_unit_exponent != 0) {
802 // Write "Unit Exponent", but only if changed
803 last_unit_exponent = 0;
804 rd_write_short_item(rd_global_unit_exponent, last_unit_exponent, &rpt_desc);
805 }
806 if (last_unit != 0) {
807 // Write "Unit",but only if changed
808 last_unit = 0;
809 rd_write_short_item(rd_global_unit, last_unit, &rpt_desc);
810 }
811
812 // Write "Input" main item
813 if (rt_idx == HidP_Input) {
814 rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
815 }
816 // Write "Output" main item
817 else if (rt_idx == HidP_Output) {
818 rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
819 }
820 // Write "Feature" main item
821 else if (rt_idx == HidP_Feature) {
822 rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
823 }
824 report_count = 0;
825 }
826 }
827 else {
828
829 if (last_report_id != pp_data->caps[caps_idx].ReportID) {
830 // Write "Report ID" if changed
831 rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
832 last_report_id = pp_data->caps[caps_idx].ReportID;
833 }
834
835 // Write "Usage Page" if changed
836 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
837 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
838 last_usage_page = pp_data->caps[caps_idx].UsagePage;
839 }
840
841 if (inhibit_write_of_usage) {
842 // Inhibit only once after Delimiter - Reset flag
843 inhibit_write_of_usage = FALSE;
844 }
845 else {
846 if (pp_data->caps[caps_idx].IsRange) {
847 // Write usage range from "Usage Minimum" to "Usage Maximum"
848 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
849 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
850 }
851 else {
852 // Write single "Usage"
853 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
854 }
855 }
856
857 if (pp_data->caps[caps_idx].IsDesignatorRange) {
858 // Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
859 rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
860 rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
861 }
862 else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
863 // Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
864 // that specifies the number of additional descriptor sets.
865 // Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
866 // Write single "Designator Index"
867 rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
868 }
869
870 if (pp_data->caps[caps_idx].IsStringRange) {
871 // Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
872 rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
873 rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
874 }
875 else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
876 // String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
877 // therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
878 // Write single "String Index"
879 rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
880 }
881
882 if ((pp_data->caps[caps_idx].BitField & 0x02) != 0x02) {
883 // In case of an value array overwrite "Report Count"
884 pp_data->caps[caps_idx].ReportCount = pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin + 1;
885 }
886
887
888 // Print only local report items for each cap, if ReportCount > 1
889 if ((main_item_list->next != NULL) &&
890 ((int) main_item_list->next->MainItemType == rt_idx) &&
891 (main_item_list->next->TypeOfNode == rd_item_node_cap) &&
892 (!pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
893 (!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
894 (!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
895 (pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
896 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMin == pp_data->caps[caps_idx].NotButton.LogicalMin) &&
897 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMax == pp_data->caps[caps_idx].NotButton.LogicalMax) &&
898 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMin == pp_data->caps[caps_idx].NotButton.PhysicalMin) &&
899 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMax == pp_data->caps[caps_idx].NotButton.PhysicalMax) &&
900 (pp_data->caps[main_item_list->next->CapsIndex].UnitsExp == pp_data->caps[caps_idx].UnitsExp) &&
901 (pp_data->caps[main_item_list->next->CapsIndex].Units == pp_data->caps[caps_idx].Units) &&
902 (pp_data->caps[main_item_list->next->CapsIndex].ReportSize == pp_data->caps[caps_idx].ReportSize) &&
903 (pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
904 (pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) &&
905 (pp_data->caps[main_item_list->next->CapsIndex].ReportCount == 1) &&
906 (pp_data->caps[caps_idx].ReportCount == 1)
907 ) {
908 // Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
909 report_count++;
910 }
911 else {
912 // Value
913
914 // Write logical range from "Logical Minimum" to "Logical Maximum"
915 rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].NotButton.LogicalMin, &rpt_desc);
916 rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].NotButton.LogicalMax, &rpt_desc);
917
918 if ((last_physical_min != pp_data->caps[caps_idx].NotButton.PhysicalMin) ||
919 (last_physical_max != pp_data->caps[caps_idx].NotButton.PhysicalMax)) {
920 // Write range from "Physical Minimum" to " Physical Maximum", but only if one of them changed
921 rd_write_short_item(rd_global_physical_minimum, pp_data->caps[caps_idx].NotButton.PhysicalMin, &rpt_desc);
922 last_physical_min = pp_data->caps[caps_idx].NotButton.PhysicalMin;
923 rd_write_short_item(rd_global_physical_maximum, pp_data->caps[caps_idx].NotButton.PhysicalMax, &rpt_desc);
924 last_physical_max = pp_data->caps[caps_idx].NotButton.PhysicalMax;
925 }
926
927
928 if (last_unit_exponent != pp_data->caps[caps_idx].UnitsExp) {
929 // Write "Unit Exponent", but only if changed
930 rd_write_short_item(rd_global_unit_exponent, pp_data->caps[caps_idx].UnitsExp, &rpt_desc);
931 last_unit_exponent = pp_data->caps[caps_idx].UnitsExp;
932 }
933
934 if (last_unit != pp_data->caps[caps_idx].Units) {
935 // Write physical "Unit", but only if changed
936 rd_write_short_item(rd_global_unit, pp_data->caps[caps_idx].Units, &rpt_desc);
937 last_unit = pp_data->caps[caps_idx].Units;
938 }
939
940 // Write "Report Size"
941 rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
942
943 // Write "Report Count"
944 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
945
946 if (rt_idx == HidP_Input) {
947 // Write "Input" main item
948 rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
949 }
950 else if (rt_idx == HidP_Output) {
951 // Write "Output" main item
952 rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
953 }
954 else if (rt_idx == HidP_Feature) {
955 // Write "Feature" main item
956 rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
957 }
958 report_count = 0;
959 }
960 }
961
962 // Go to next item in main_item_list and free the memory of the actual item
963 struct rd_main_item_node *main_item_list_prev = main_item_list;
964 main_item_list = main_item_list->next;
965 free(main_item_list_prev);
966 }
967
968 // Free multidimensionable array: coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
969 // Free multidimensionable array: coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
970 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
971 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
972 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
973 free(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]);
974 }
975 free(coll_bit_range[collection_node_idx][reportid_idx]);
976 }
977 free(coll_bit_range[collection_node_idx]);
978 if (coll_number_of_direct_childs[collection_node_idx] != 0) free(coll_child_order[collection_node_idx]);
979 }
980 free(coll_bit_range);
981 free(coll_child_order);
982
983 // Free one dimensional arrays
984 free(coll_begin_lookup);
985 free(coll_end_lookup);
986 free(coll_levels);
987 free(coll_number_of_direct_childs);
988
989 return (int) rpt_desc.byte_idx;
990}