GCC Code Coverage Report


Directory: main/
File: adapter/hid_parser.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 269 343 78.4%
Functions: 8 9 88.9%
Branches: 171 238 71.8%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2019-2023, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <esp_heap_caps.h>
9 #include "adapter.h"
10 #include "hid_parser.h"
11 #include "zephyr/usb_hid.h"
12 #include "tools/util.h"
13 #include "bluetooth/mon.h"
14 #include "tests/cmds.h"
15
16 #define HID_STACK_MAX 4
17
18 struct hid_stack_element {
19 uint32_t report_size;
20 uint32_t report_cnt;
21 int32_t logical_min;
22 int32_t logical_max;
23 uint32_t usage_page;
24 uint32_t usage_max;
25 };
26
27 static struct hid_report *reports[BT_MAX_DEV][HID_MAX_REPORT] = {0};
28
29 /* List of usage we don't care about */
30 395 static uint32_t hid_usage_is_collection(uint32_t page, uint32_t usage) {
31
5/8
✓ Branch 0 (2→3) taken 148 times.
✓ Branch 1 (2→4) taken 36 times.
✗ Branch 2 (2→5) not taken.
✗ Branch 3 (2→6) not taken.
✗ Branch 4 (2→7) not taken.
✓ Branch 5 (2→8) taken 38 times.
✓ Branch 6 (2→9) taken 15 times.
✓ Branch 7 (2→11) taken 158 times.
395 switch (page) {
32 148 case 0x01: /* Generic Desktop Ctrls */
33
2/2
✓ Branch 0 (3→10) taken 47 times.
✓ Branch 1 (3→11) taken 101 times.
148 switch (usage) {
34 case 0x01:
35 case 0x02:
36 case 0x04:
37 case 0x05:
38 case 0x06:
39 case 0x07:
40 case 0x08:
41 case 0x09:
42 case 0x3A:
43 case 0x80:
44 return 1;
45 default:
46 return 0;
47 }
48 36 case 0x02: /* Sim Ctrls */
49
1/2
✗ Branch 0 (4→10) not taken.
✓ Branch 1 (4→11) taken 36 times.
36 switch (usage) {
50 case 0x01:
51 case 0x02:
52 case 0x03:
53 case 0x04:
54 case 0x05:
55 case 0x06:
56 case 0x07:
57 case 0x08:
58 case 0x09:
59 case 0x0A:
60 case 0x0B:
61 case 0x0C:
62 case 0x20:
63 case 0x21:
64 case 0x22:
65 case 0x23:
66 case 0x24:
67 case 0x25:
68 return 1;
69 default:
70 return 0;
71 }
72 case 0x03: /* VR Ctrls */
73 switch (usage) {
74 case 0x01:
75 case 0x02:
76 case 0x03:
77 case 0x04:
78 case 0x05:
79 case 0x06:
80 case 0x07:
81 case 0x08:
82 case 0x09:
83 case 0x0A:
84 return 1;
85 default:
86 return 0;
87 }
88 case 0x04: /* Sport Ctrls */
89 switch (usage) {
90 case 0x01:
91 case 0x02:
92 case 0x03:
93 case 0x04:
94 case 0x38:
95 return 1;
96 default:
97 return 0;
98 }
99 case 0x05: /* Game Ctrls */
100 switch (usage) {
101 case 0x01:
102 case 0x02:
103 case 0x03:
104 case 0x20:
105 case 0x32:
106 case 0x37:
107 case 0x39:
108 return 1;
109 default:
110 return 0;
111 }
112 38 case 0x0C: /* Consumer */
113
2/2
✓ Branch 0 (8→10) taken 2 times.
✓ Branch 1 (8→11) taken 36 times.
38 switch (usage) {
114 case 0x01:
115 case 0x02:
116 case 0x03:
117 case 0x04:
118 case 0x05:
119 case 0x06:
120 case 0x36:
121 case 0x80:
122 case 0x87:
123 case 0xBA:
124 case 0xF1:
125 return 1;
126 default:
127 return 0;
128 }
129 15 case 0x0F: /* PID */
130
2/2
✓ Branch 0 (9→10) taken 2 times.
✓ Branch 1 (9→11) taken 13 times.
15 switch (usage) {
131 case 0x01:
132 case 0x21:
133 case 0x25:
134 case 0x57:
135 case 0x58:
136 case 0x59:
137 case 0x5A:
138 case 0x5F:
139 case 0x66:
140 case 0x68:
141 case 0x6B:
142 case 0x6E:
143 case 0x73:
144 case 0x74:
145 case 0x77:
146 case 0x78:
147 case 0x7D:
148 case 0x7F:
149 case 0x85:
150 case 0x89:
151 case 0x8B:
152 case 0x90:
153 case 0x91:
154 case 0x92:
155 case 0x95:
156 case 0x96:
157 case 0xA8:
158 case 0xAB:
159 return 1;
160 default:
161 return 0;
162 }
163 default:
164 return 0;
165 }
166 }
167
168 /* List of usage we care about */
169 563 static uint32_t hid_usage_is_used(uint32_t page, uint32_t usage) {
170
7/7
✓ Branch 0 (2→3) taken 110 times.
✓ Branch 1 (2→4) taken 64 times.
✓ Branch 2 (2→5) taken 106 times.
✓ Branch 3 (2→6) taken 71 times.
✓ Branch 4 (2→7) taken 22 times.
✓ Branch 5 (2→8) taken 12 times.
✓ Branch 6 (2→9) taken 178 times.
563 switch (page) {
171 110 case 0x01: /* Generic Desktop Ctrls */
172
2/2
✓ Branch 0 (3→8) taken 94 times.
✓ Branch 1 (3→9) taken 16 times.
110 switch (usage) {
173 case 0x30: /* X */
174 case 0x31: /* Y */
175 case 0x32: /* Z */
176 case 0x33: /* RX */
177 case 0x34: /* RY */
178 case 0x35: /* RZ */
179 case 0x36: /* Slider */
180 case 0x37: /* Dial */
181 case 0x38: /* Wheel */
182 case 0x39: /* Hat */
183 case 0x85: /* Sys Main Menu */
184 return 1;
185 default:
186 return 0;
187 }
188 64 case 0x02: /* Sim Ctrls */
189
2/2
✓ Branch 0 (4→8) taken 31 times.
✓ Branch 1 (4→9) taken 33 times.
64 switch (usage) {
190 case 0xC4: /* Accel */
191 case 0xC5: /* Brake */
192 return 1;
193 default:
194 return 0;
195 }
196 case 0x07: /* Keyboard */
197 return 1;
198 106 case 0x09: /* Button */
199
1/2
✓ Branch 0 (5→8) taken 106 times.
✗ Branch 1 (5→9) not taken.
106 if (usage <= 20) {
200 return 1;
201 }
202 return 0;
203 71 case 0x0C: /* Consumer */
204
2/2
✓ Branch 0 (6→8) taken 27 times.
✓ Branch 1 (6→9) taken 44 times.
71 switch (usage) {
205 case 0x40 /* Menu */:
206 case 0xB2 /* Record */:
207 case 0x223 /* AC Home */:
208 case 0x224 /* AC Back */:
209 return 1;
210 default:
211 return 0;
212 }
213 22 case 0x0F: /* PID */
214
1/2
✓ Branch 0 (7→8) taken 22 times.
✗ Branch 1 (7→9) not taken.
22 switch (usage) {
215 case 0x50: /* Duration */
216 case 0x97: /* Enable Actuators */
217 case 0x70: /* Magnitude */
218 case 0x7C: /* Loop Count */
219 case 0xA7: /* Start Delay */
220 return 1;
221 default:
222 return 0;
223 }
224 default:
225 return 0;
226 }
227 }
228
229 62 static int32_t hid_report_fingerprint(struct hid_report *report) {
230 62 int32_t type = REPORT_NONE;
231
2/2
✓ Branch 0 (16→3) taken 104 times.
✓ Branch 1 (16→17) taken 33 times.
137 for (uint32_t i = 0; i < report->usage_cnt; i++) {
232
1/2
✓ Branch 0 (3→4) taken 104 times.
✗ Branch 1 (3→17) not taken.
104 if (report->usages[i].usage_page) {
233
5/5
✓ Branch 0 (4→5) taken 22 times.
✓ Branch 1 (4→9) taken 39 times.
✓ Branch 2 (4→10) taken 7 times.
✓ Branch 3 (4→14) taken 24 times.
✓ Branch 4 (4→15) taken 12 times.
104 switch (report->usages[i].usage_page) {
234 22 case USAGE_GEN_DESKTOP:
235
2/4
✓ Branch 0 (5→6) taken 11 times.
✗ Branch 1 (5→8) not taken.
✗ Branch 2 (5→14) not taken.
✓ Branch 3 (5→17) taken 11 times.
22 switch (report->usages[i].usage) {
236 11 case USAGE_GEN_DESKTOP_X:
237 case USAGE_GEN_DESKTOP_Y:
238
1/2
✓ Branch 0 (6→7) taken 11 times.
✗ Branch 1 (6→17) not taken.
11 if (report->usages[i].flags & 0x04) {
239 /* relative */
240 return MOUSE;
241 }
242 else {
243 11 return PAD;
244 }
245 case 0x39: /* HAT_SWITCH */
246 return PAD;
247 case 0x85: /* Sys Main Menu */
248 return MOUSE; /* Hack for xinput Xbox btn */
249 }
250 break;
251 case USAGE_GEN_KEYBOARD:
252 75 type = KB;
253 break;
254 39 case USAGE_GEN_BUTTON:
255 39 type = PAD;
256 39 break;
257 7 case USAGE_GEN_PHYS_INPUT:
258
2/2
✓ Branch 0 (10→11) taken 2 times.
✓ Branch 1 (10→17) taken 5 times.
7 if ((report->usages[i].usage >= 0x95 && report->usages[i].usage <= 0x9C) ||
259
1/4
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→17) taken 2 times.
✗ Branch 2 (12→13) not taken.
✗ Branch 3 (12→17) not taken.
2 report->usages[i].usage == 0x50 || report->usages[i].usage == 0x70 ||
260 report->usages[i].usage == 0x7C || report->usages[i].usage == 0xA7) {
261 /*
262 0x50: Duration
263 0x70: Magnitude
264 0x7C: Loop count
265 0xA7: Start Delay
266 0x95: PID Device Control Report
267 0x96: PID Device Control
268 0x97: Enable Actuators
269 0x98: Disable Actuators
270 0x99: Stop all effects
271 0x9A: Device Reset
272 0x9B: Device Pause
273 0x9C: Device Continue
274 More info: https://www.usb.org/sites/default/files/hut1_4.pdf#page=213
275 */
276 return RUMBLE;
277 }
278 break;
279 }
280 }
281 else {
282 break;
283 }
284 }
285 return type;
286 }
287
288 62 static void hid_patch_report(struct bt_data *bt_data, struct hid_report *report) {
289
2/2
✓ Branch 0 (2→3) taken 11 times.
✓ Branch 1 (2→12) taken 51 times.
62 switch (bt_data->base.vid) {
290 11 case 0x3250: /* Atari VCS */
291 {
292 11 uint32_t usage_cnt = 8;
293
2/3
✓ Branch 0 (3→4) taken 5 times.
✓ Branch 1 (3→5) taken 6 times.
✗ Branch 2 (3→12) not taken.
11 switch (bt_data->base.pid) {
294 5 case 0x1001: /* Classic Controller */
295 5 usage_cnt = 4;
296 /* Fallthrough */
297 11 case 0x1002: /* Modern Controller */
298 /* Rumble report */
299
4/4
✓ Branch 0 (5→6) taken 4 times.
✓ Branch 1 (5→12) taken 7 times.
✓ Branch 2 (6→7) taken 2 times.
✓ Branch 3 (6→12) taken 2 times.
11 if (report->id == 1 && report->tag == 1) {
300 2 uint8_t usages[] = {
301 0x70, 0x50, 0xA7, 0x7C, /* LF (left) */
302 0x70, 0x50, 0xA7, 0x7C, /* HF (right) */
303 };
304 2 report->usage_cnt = usage_cnt;
305
2/2
✓ Branch 0 (10→8) taken 12 times.
✓ Branch 1 (10→11) taken 2 times.
14 for (uint32_t i = 0; i < usage_cnt; i++) {
306 12 memset(&report->usages[i], 0, sizeof(report->usages[0]));
307 12 report->usages[i].usage_page = USAGE_GEN_PHYS_INPUT;
308 12 report->usages[i].usage = usages[i];
309 12 report->usages[i].logical_min = 0;
310 12 report->usages[i].logical_max = 0xFF;
311 12 report->usages[i].bit_size = 8;
312 12 report->usages[i].bit_offset = i * 8;
313 }
314 }
315 break;
316 }
317 break;
318 }
319 }
320 62 }
321
322 62 static void hid_process_report(struct bt_data *bt_data, struct hid_report *report) {
323 62 hid_patch_report(bt_data, report);
324 62 report->type = hid_report_fingerprint(report);
325 62 TESTS_CMDS_LOG("{\"report_id\": %ld, \"report_tag\": %ld, \"usages\": [", report->id, report->tag);
326
2/2
✓ Branch 0 (10→6) taken 304 times.
✓ Branch 1 (10→11) taken 62 times.
366 for (uint32_t i = 0; i < report->usage_cnt; i++) {
327
2/2
✓ Branch 0 (6→7) taken 273 times.
✓ Branch 1 (6→8) taken 31 times.
304 if (i) {
328 273 TESTS_CMDS_LOG(", ");
329 }
330 304 TESTS_CMDS_LOG("{\"usage_page\": %ld, \"usage\": %ld, \"bit_offset\": %lu, \"bit_size\": %lu}",
331 report->usages[i].usage_page, report->usages[i].usage, report->usages[i].bit_offset,
332 report->usages[i].bit_size);
333 }
334 62 TESTS_CMDS_LOG("]");
335
2/2
✓ Branch 0 (12→13) taken 38 times.
✓ Branch 1 (12→14) taken 24 times.
100 printf("%ld %c ", report->id, (report->tag) ? 'O' : 'I');
336
2/2
✓ Branch 0 (15→16) taken 38 times.
✓ Branch 1 (15→17) taken 24 times.
62 bt_mon_log(false, "%ld %c ", report->id, (report->tag) ? 'O' : 'I');
337
2/2
✓ Branch 0 (22→19) taken 304 times.
✓ Branch 1 (22→23) taken 62 times.
366 for (uint32_t i = 0; i < report->usage_cnt; i++) {
338 304 printf("%02lX%02lX %lu %lu ", report->usages[i].usage_page, report->usages[i].usage,
339 report->usages[i].bit_offset, report->usages[i].bit_size);
340 304 bt_mon_log(false, "%02lX%02lX %lu %lu ", report->usages[i].usage_page, report->usages[i].usage,
341 report->usages[i].bit_offset, report->usages[i].bit_size);
342 }
343
2/2
✓ Branch 0 (23→24) taken 30 times.
✓ Branch 1 (23→30) taken 32 times.
62 if (report->type != REPORT_NONE) {
344 30 TESTS_CMDS_LOG(", \"report_type\": %ld", report->type);
345 30 printf("rtype: %ld", report->type);
346 30 bt_mon_log(false, "rtype: %ld", report->type);
347 /* For output report we got to make a choice. */
348 /* So we use the first one we find. */
349
3/4
✓ Branch 0 (27→28) taken 7 times.
✓ Branch 1 (27→30) taken 23 times.
✓ Branch 2 (28→29) taken 7 times.
✗ Branch 3 (28→30) not taken.
30 if (report->tag == HID_OUT && bt_data->reports[report->type] == NULL) {
350 7 bt_data->reports[report->type] = report;
351 }
352 }
353 62 TESTS_CMDS_LOG("}");
354 62 printf("\n");
355 62 bt_mon_log(true, "");
356 62 }
357
358 23 void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) {
359 23 struct hid_stack_element hid_stack[HID_STACK_MAX] = {0};
360 23 uint8_t hid_stack_idx = 0;
361 23 uint8_t usage_idx = 0;
362 23 uint16_t usage_list[REPORT_MAX_USAGE] = {0};
363 23 uint8_t *end = data + len;
364 23 uint8_t *desc = data;
365 23 uint8_t report_id = 0;
366 23 uint8_t tag_idx = 0;
367 23 uint32_t report_bit_offset[HID_TAG_CNT] = {0};
368 23 uint32_t report_usage_idx[HID_TAG_CNT] = {0};
369 23 uint8_t report_idx = 0;
370 23 struct hid_report *wip_report[2] = {0};
371
372 /* Free pre-existing reports for this device id */
373
2/2
✓ Branch 0 (6→3) taken 230 times.
✓ Branch 1 (6→7) taken 23 times.
253 for (uint32_t i = 0; i < HID_MAX_REPORT; i++) {
374
2/2
✓ Branch 0 (3→4) taken 61 times.
✓ Branch 1 (3→5) taken 169 times.
230 if (reports[bt_data->base.pids->id][i]) {
375 61 free(reports[bt_data->base.pids->id][i]);
376 61 reports[bt_data->base.pids->id][i] = NULL;
377 }
378 }
379
380 23 wip_report[0] = heap_caps_aligned_alloc(32, sizeof(struct hid_report), MALLOC_CAP_32BIT);
381
1/2
✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→10) taken 23 times.
23 if (wip_report[0] == NULL) {
382 printf("# %s: failed to alloc wip_report[0]\n", __FUNCTION__);
383 return;
384 }
385 23 wip_report[1] = heap_caps_aligned_alloc(32, sizeof(struct hid_report), MALLOC_CAP_32BIT);
386
1/2
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→14) taken 23 times.
23 if (wip_report[1] == NULL) {
387 printf("# %s: failed to alloc wip_report[1]\n", __FUNCTION__);
388 free(wip_report[0]);
389 return;
390 }
391
392 23 memset(wip_report[0], 0, sizeof(struct hid_report));
393 23 memset(wip_report[1], 0, sizeof(struct hid_report));
394
395
396 #ifdef CONFIG_BLUERETRO_DUMP_HID_DESC
397 23 data_dump(data, len);
398 #endif
399 23 TESTS_CMDS_LOG("\"hid_reports\": [");
400
401
2/2
✓ Branch 0 (114→19) taken 2095 times.
✓ Branch 1 (114→115) taken 23 times.
2118 while (desc < end) {
402
24/37
✗ Branch 0 (19→20) not taken.
✗ Branch 1 (19→21) not taken.
✓ Branch 2 (19→22) taken 157 times.
✓ Branch 3 (19→23) taken 4 times.
✗ Branch 4 (19→24) not taken.
✓ Branch 5 (19→25) taken 395 times.
✓ Branch 6 (19→29) taken 33 times.
✗ Branch 7 (19→32) not taken.
✓ Branch 8 (19→33) taken 186 times.
✓ Branch 9 (19→34) taken 7 times.
✗ Branch 10 (19→35) not taken.
✓ Branch 11 (19→36) taken 100 times.
✓ Branch 12 (19→37) taken 81 times.
✓ Branch 13 (19→38) taken 17 times.
✓ Branch 14 (19→39) taken 14 times.
✗ Branch 15 (19→40) not taken.
✗ Branch 16 (19→41) not taken.
✓ Branch 17 (19→42) taken 18 times.
✓ Branch 18 (19→43) taken 14 times.
✓ Branch 19 (19→44) taken 13 times.
✓ Branch 20 (19→45) taken 7 times.
✓ Branch 21 (19→46) taken 19 times.
✓ Branch 22 (19→47) taken 15 times.
✓ Branch 23 (19→48) taken 262 times.
✓ Branch 24 (19→49) taken 35 times.
✓ Branch 25 (19→50) taken 264 times.
✓ Branch 26 (19→83) taken 41 times.
✓ Branch 27 (19→98) taken 272 times.
✗ Branch 28 (19→99) not taken.
✓ Branch 29 (19→100) taken 73 times.
✗ Branch 30 (19→101) not taken.
✓ Branch 31 (19→105) taken 1 times.
✗ Branch 32 (19→106) not taken.
✗ Branch 33 (19→107) not taken.
✗ Branch 34 (19→110) not taken.
✗ Branch 35 (19→111) not taken.
✓ Branch 36 (19→113) taken 67 times.
2095 switch (*desc++) {
403 case 0x00:
404 break;
405 case 0x01:
406 desc++;
407 break;
408 case 0x03:
409 desc += 4;
410 break;
411 157 case HID_GI_USAGE_PAGE: /* 0x05 */
412 157 hid_stack[hid_stack_idx].usage_page = *desc++;
413 157 break;
414 4 case 0x06: /* USAGE_PAGE16 */
415 4 hid_stack[hid_stack_idx].usage_page = *(uint16_t *)desc;
416 4 desc += 2;
417 4 break;
418 case 0x07: /* USAGE_PAGE32 */
419 hid_stack[hid_stack_idx].usage_page = *(uint32_t *)desc;
420 desc += 4;
421 break;
422 395 case HID_LI_USAGE: /* 0x09 */
423 case HID_LI_USAGE_MIN(1): /* 0x19 */
424
2/2
✓ Branch 0 (25→26) taken 344 times.
✓ Branch 1 (25→28) taken 51 times.
395 if (!hid_usage_is_collection(hid_stack[hid_stack_idx].usage_page, *desc)) {
425
1/2
✓ Branch 0 (26→27) taken 344 times.
✗ Branch 1 (26→28) not taken.
344 if (usage_idx < REPORT_MAX_USAGE) {
426 344 usage_list[usage_idx++] = *desc;
427 }
428 }
429 395 desc++;
430 395 break;
431 33 case 0x0A: /* USAGE16 */
432 case HID_LI_USAGE_MIN(2): /* 0x1A */
433
1/2
✓ Branch 0 (29→30) taken 33 times.
✗ Branch 1 (29→31) not taken.
33 if (usage_idx < REPORT_MAX_USAGE) {
434 33 usage_list[usage_idx++] = *(uint16_t *)desc;
435 }
436 33 desc += 2;
437 33 break;
438 case 0x0D:
439 desc++;
440 break;
441 186 case HID_GI_LOGICAL_MIN(1): /* 0x15 */
442 186 hid_stack[hid_stack_idx].logical_min = *(int8_t *)desc++;
443 186 break;
444 7 case HID_GI_LOGICAL_MIN(2): /* 0x16 */
445 7 hid_stack[hid_stack_idx].logical_min = *(int16_t *)desc;
446 7 desc += 2;
447 7 break;
448 case HID_GI_LOGICAL_MIN(3): /* 0x17 */
449 hid_stack[hid_stack_idx].logical_min = *(int32_t *)desc;
450 desc += 4;
451 break;
452 100 case HID_GI_LOGICAL_MAX(1): /* 0x25 */
453 100 hid_stack[hid_stack_idx].logical_max = *(int8_t *)desc++;
454 100 break;
455 81 case HID_GI_LOGICAL_MAX(2): /* 0x26 */
456 81 hid_stack[hid_stack_idx].logical_max = *(int16_t *)desc;
457 81 desc += 2;
458 81 break;
459 17 case HID_GI_LOGICAL_MAX(3): /* 0x27 */
460 17 hid_stack[hid_stack_idx].logical_max = *(int32_t *)desc;
461 17 desc += 4;
462 17 break;
463 14 case HID_LI_USAGE_MAX(1): /* 0x29 */
464 14 hid_stack[hid_stack_idx].usage_max = *(int8_t *)desc++;
465 14 break;
466 case HID_LI_USAGE_MAX(2): /* 0x2A */
467 hid_stack[hid_stack_idx].usage_max = *(int16_t *)desc;
468 desc += 2;
469 break;
470 case HID_LI_USAGE_MAX(3): /* 0x2B */
471 hid_stack[hid_stack_idx].usage_max = *(int32_t *)desc;
472 desc += 4;
473 break;
474 18 case 0x35: /* PHYSICAL_MIN */
475 18 desc++;
476 18 break;
477 14 case 0x45: /* PHYSICAL_MAX */
478 14 desc++;
479 14 break;
480 13 case 0x46: /* PHYSICAL_MAX16 */
481 13 desc += 2;
482 13 break;
483 7 case 0x55: /* UNIT_EXP */
484 7 desc++;
485 7 break;
486 19 case 0x65: /* UNIT */
487 19 desc++;
488 19 break;
489 15 case 0x66: /* UNIT16 */
490 15 desc += 2;
491 15 break;
492 262 case HID_GI_REPORT_SIZE: /* 0x75 */
493 262 hid_stack[hid_stack_idx].report_size = *desc++;
494 262 break;
495 case 0x7C:
496 break;
497 35 case HID_MI_OUTPUT: /* 0x91 */
498 35 tag_idx = 1;
499 /* Fallthrough */
500 299 case HID_MI_INPUT: /* 0x81 */
501
5/8
✓ Branch 0 (50→51) taken 215 times.
✓ Branch 1 (50→80) taken 84 times.
✓ Branch 2 (51→52) taken 215 times.
✗ Branch 3 (51→80) not taken.
✓ Branch 4 (52→53) taken 215 times.
✗ Branch 5 (52→80) not taken.
✓ Branch 6 (53→54) taken 215 times.
✗ Branch 7 (53→80) not taken.
299 if (!(*desc & 0x01) && hid_stack[hid_stack_idx].usage_page != 0xFF && usage_list[0] != 0xFF && report_usage_idx[tag_idx] < REPORT_MAX_USAGE) {
502
6/6
✓ Branch 0 (54→55) taken 163 times.
✓ Branch 1 (54→57) taken 52 times.
✓ Branch 2 (55→56) taken 69 times.
✓ Branch 3 (55→57) taken 94 times.
✓ Branch 4 (56→57) taken 52 times.
✓ Branch 5 (56→58) taken 17 times.
215 bool bitfield_merge = (usage_idx == 1 && hid_stack[hid_stack_idx].report_size == 1 && hid_stack[hid_stack_idx].report_cnt > 1);
503 198 uint32_t usage_cnt = (bitfield_merge) ? 1 : hid_stack[hid_stack_idx].report_cnt;
504
2/2
✓ Branch 0 (79→59) taken 563 times.
✓ Branch 1 (79→81) taken 215 times.
778 for (uint32_t i = 0; i < usage_cnt; i++) {
505
2/2
✓ Branch 0 (59→60) taken 212 times.
✓ Branch 1 (59→61) taken 351 times.
563 uint16_t usage = (usage_idx == 1) ? usage_list[0] : usage_list[i];
506
2/2
✓ Branch 0 (61→62) taken 292 times.
✓ Branch 1 (61→75) taken 271 times.
563 if (hid_usage_is_used(hid_stack[hid_stack_idx].usage_page, usage)) {
507 292 uint32_t frag_cnt = 1;
508
2/2
✓ Branch 0 (62→63) taken 12 times.
✓ Branch 1 (62→65) taken 280 times.
292 if (bitfield_merge) {
509 12 frag_cnt = hid_stack[hid_stack_idx].report_cnt / 32;
510
2/2
✓ Branch 0 (63→64) taken 9 times.
✓ Branch 1 (63→65) taken 3 times.
12 if (hid_stack[hid_stack_idx].report_cnt % 32) {
511 9 frag_cnt++;
512 }
513 }
514
2/2
✓ Branch 0 (74→66) taken 292 times.
✓ Branch 1 (74→75) taken 292 times.
584 for (uint32_t j = 0; j < frag_cnt; j++) {
515 292 uint32_t usage_offset = j * 32;
516 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage_page = hid_stack[hid_stack_idx].usage_page;
517 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage = usage;
518 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage += usage_offset;
519 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].flags = *desc;
520 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_offset = report_bit_offset[tag_idx];
521 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_offset += usage_offset;
522 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_size;
523 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_min = hid_stack[hid_stack_idx].logical_min;
524 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_max = hid_stack[hid_stack_idx].logical_max;
525 292 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage_max = hid_stack[hid_stack_idx].usage_max;
526
2/2
✓ Branch 0 (66→67) taken 12 times.
✓ Branch 1 (66→70) taken 280 times.
292 if (bitfield_merge) {
527
1/2
✓ Branch 0 (67→68) taken 12 times.
✗ Branch 1 (67→69) not taken.
12 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size *= (frag_cnt > 1) ? 32 : hid_stack[hid_stack_idx].report_cnt;
528 }
529
1/4
✗ Branch 0 (70→71) not taken.
✓ Branch 1 (70→73) taken 292 times.
✗ Branch 2 (71→72) not taken.
✗ Branch 3 (71→73) not taken.
292 if (frag_cnt > 1 && j == (frag_cnt - 1)) {
530 wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_cnt % 32;
531 }
532 292 report_usage_idx[tag_idx]++;
533 }
534 }
535
2/2
✓ Branch 0 (75→76) taken 17 times.
✓ Branch 1 (75→77) taken 546 times.
563 if (bitfield_merge) {
536 17 report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
537 }
538 else {
539 546 report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_size;
540 }
541 }
542 }
543 else {
544 84 report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_size * hid_stack[hid_stack_idx].report_cnt;
545 }
546 299 usage_idx = 0;
547 299 tag_idx = 0;
548 299 memset(usage_list, 0xFF, sizeof(usage_list));
549 299 desc++;
550 299 break;
551 41 case HID_GI_REPORT_ID: /* 0x85 */
552 /* process previous report fingerprint */
553
2/2
✓ Branch 0 (83→94) taken 21 times.
✓ Branch 1 (83→95) taken 20 times.
41 if (report_id) {
554
2/2
✓ Branch 0 (94→84) taken 42 times.
✓ Branch 1 (94→95) taken 21 times.
63 for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
555 42 wip_report[i]->tag = i;
556 42 wip_report[i]->usage_cnt = report_usage_idx[i];
557 42 wip_report[i]->len = report_bit_offset[i] / 8;
558
1/2
✗ Branch 0 (84→85) not taken.
✓ Branch 1 (84→86) taken 42 times.
42 if (report_bit_offset[i] % 8) {
559 wip_report[i]->len++;
560 }
561
2/2
✓ Branch 0 (86→87) taken 36 times.
✓ Branch 1 (86→93) taken 6 times.
42 if (wip_report[i]->len) {
562
2/2
✓ Branch 0 (87→88) taken 22 times.
✓ Branch 1 (87→89) taken 14 times.
36 if (report_idx) {
563 22 TESTS_CMDS_LOG(",\n");
564 }
565 36 hid_process_report(bt_data, wip_report[i]);
566 36 reports[bt_data->base.pids->id][report_idx++] = wip_report[i];
567 36 wip_report[i] = heap_caps_aligned_alloc(32, sizeof(struct hid_report), MALLOC_CAP_32BIT);
568
1/2
✓ Branch 0 (91→92) taken 36 times.
✗ Branch 1 (91→133) not taken.
36 if (wip_report[i] == NULL) {
569 return;
570 }
571 36 memset(wip_report[i], 0, sizeof(struct hid_report));
572 }
573 }
574 }
575 41 report_id = *desc++;
576
2/2
✓ Branch 0 (97→96) taken 82 times.
✓ Branch 1 (97→113) taken 41 times.
123 for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
577 82 wip_report[i]->id = report_id;
578 82 report_usage_idx[i] = 0;
579 82 report_bit_offset[i] = 0;
580 }
581 break;
582 272 case HID_GI_REPORT_COUNT: /* 0x95 */
583 272 hid_stack[hid_stack_idx].report_cnt = *desc++;
584 272 break;
585 case 0x96: /* REPORT_COUNT16 */
586 hid_stack[hid_stack_idx].report_cnt = *(uint16_t *)desc;
587 desc += 2;
588 break;
589 73 case HID_MI_COLLECTION: /* 0xA1 */
590 73 desc++;
591 73 break;
592 case 0xA4: /* PUSH */
593 if (hid_stack_idx < (HID_STACK_MAX - 1)) {
594 memcpy(&hid_stack[hid_stack_idx + 1], &hid_stack[hid_stack_idx], sizeof(hid_stack[0]));
595 hid_stack_idx++;
596 }
597 else {
598 printf("# %s HID stack overflow\n", __FUNCTION__);
599 }
600 break;
601 1 case 0xB1: /* FEATURE */
602 1 usage_idx = 0;
603 1 desc++;
604 1 break;
605 case 0xB2: /* FEATURE16 */
606 usage_idx = 0;
607 desc += 2;
608 break;
609 case 0xB4: /* POP */
610 if (hid_stack_idx > 0) {
611 hid_stack_idx--;
612 }
613 else {
614 printf("# %s HID stack underrun\n", __FUNCTION__);
615 }
616 break;
617 case HID_MI_COLLECTION_END: /* 0xC0 */
618 break;
619 case 0xFF:
620 desc += 4;
621 break;
622 default:
623 printf("# Unknown HID marker: %02X\n", *--desc);
624 return;
625 }
626 }
627
4/4
✓ Branch 0 (115→116) taken 9 times.
✓ Branch 1 (115→118) taken 14 times.
✓ Branch 2 (116→117) taken 3 times.
✓ Branch 3 (116→118) taken 6 times.
23 if (report_idx == 0 && wip_report[HID_IN]->id == 0) {
628 3 report_id = 1;
629 3 wip_report[HID_IN]->id = 1;
630 3 wip_report[HID_OUT]->id = 1;
631 }
632
1/2
✓ Branch 0 (118→127) taken 23 times.
✗ Branch 1 (118→128) not taken.
23 if (report_id) {
633
2/2
✓ Branch 0 (127→119) taken 46 times.
✓ Branch 1 (127→128) taken 23 times.
69 for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
634 46 wip_report[i]->tag = i;
635 46 wip_report[i]->usage_cnt = report_usage_idx[i];
636 46 wip_report[i]->len = report_bit_offset[i] / 8;
637
1/2
✗ Branch 0 (119→120) not taken.
✓ Branch 1 (119→121) taken 46 times.
46 if (report_bit_offset[i] % 8) {
638 wip_report[i]->len++;
639 }
640
2/2
✓ Branch 0 (121→122) taken 26 times.
✓ Branch 1 (121→126) taken 20 times.
46 if (wip_report[i]->len) {
641
2/2
✓ Branch 0 (122→123) taken 17 times.
✓ Branch 1 (122→124) taken 9 times.
26 if (report_idx) {
642 17 TESTS_CMDS_LOG(",\n");
643 }
644 26 hid_process_report(bt_data, wip_report[i]);
645 26 reports[bt_data->base.pids->id][report_idx++] = wip_report[i];
646 }
647 }
648 }
649 23 TESTS_CMDS_LOG("],\n");
650
651 /* Free reports for non-generic devices */
652
1/2
✗ Branch 0 (129→130) not taken.
✓ Branch 1 (129→131) taken 23 times.
23 if (bt_data->base.pids->type > BT_HID_GENERIC) {
653 hid_parser_free_reports(bt_data->base.pids->id);
654 }
655 }
656
657 261 struct hid_report *hid_parser_get_report(int32_t dev_id, uint8_t report_id) {
658 261 struct hid_report **our_reports = reports[dev_id];
659
660
1/2
✓ Branch 0 (8→3) taken 261 times.
✗ Branch 1 (8→9) not taken.
261 for (uint32_t i = 0; i < HID_MAX_REPORT; i++) {
661 261 struct hid_report *report = our_reports[i];
662
4/8
✓ Branch 0 (3→4) taken 261 times.
✗ Branch 1 (3→7) not taken.
✓ Branch 2 (4→5) taken 261 times.
✗ Branch 3 (4→7) not taken.
✓ Branch 4 (5→6) taken 261 times.
✗ Branch 5 (5→7) not taken.
✗ Branch 6 (6→7) not taken.
✓ Branch 7 (6→9) taken 261 times.
261 if (report && report->len && report->id == report_id && report->tag == HID_IN) {
663 return report;
664 }
665 }
666 return NULL;
667 }
668
669 13 void hid_parser_load_report(struct bt_data *bt_data, uint8_t report_id) {
670 13 struct hid_report **our_reports = reports[bt_data->base.pids->id];
671
672
2/2
✓ Branch 0 (10→3) taken 130 times.
✓ Branch 1 (10→11) taken 13 times.
143 for (uint32_t i = 0; i < HID_MAX_REPORT; i++) {
673 130 struct hid_report *report = our_reports[i];
674
7/8
✓ Branch 0 (3→4) taken 31 times.
✓ Branch 1 (3→9) taken 99 times.
✓ Branch 2 (4→5) taken 31 times.
✗ Branch 3 (4→9) not taken.
✓ Branch 4 (5→6) taken 16 times.
✓ Branch 5 (5→9) taken 15 times.
✓ Branch 6 (6→7) taken 13 times.
✓ Branch 7 (6→9) taken 3 times.
130 if (report && report->len && report->id == report_id && report->tag == HID_IN) {
675
1/2
✓ Branch 0 (7→8) taken 13 times.
✗ Branch 1 (7→9) not taken.
13 if (report->type != REPORT_NONE) {
676 13 bt_data->reports[report->type] = report;
677 }
678 }
679 }
680 13 }
681
682 void hid_parser_free_reports(int32_t dev_id) {
683 struct hid_report **our_reports = reports[dev_id];
684
685 for (uint32_t i = 0; i < HID_MAX_REPORT; i++) {
686 struct hid_report *report = our_reports[i];
687 if (report) {
688 free(report);
689 our_reports[i] = NULL;
690 }
691 }
692 }
693