Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/hidapi/windows/hidapi_descriptor_reconstruct.c
9917 views
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
*/
25
struct 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
*/
37
static 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
*/
53
static 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
134
static 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
157
static 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
166
static 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
181
int 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
}
991
992