| 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 |