GCC Code Coverage Report


Directory: main/
File: adapter/wireless/hid_generic.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 258 533 48.4%
Functions: 4 8 50.0%
Branches: 117 270 43.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2019-2025, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <math.h>
9 #include "zephyr/types.h"
10 #include "zephyr/usb_hid.h"
11 #include "tools/util.h"
12 #include "tests/cmds.h"
13 #include "hid_generic.h"
14 #include "adapter/mapping_quirks.h"
15 #include "adapter/hid_parser.h"
16 #include "bluetooth/mon.h"
17
18 /* dinput buttons */
19 enum {
20 HID_A = 0,
21 HID_B,
22 HID_C,
23 HID_X,
24 HID_Y,
25 HID_Z,
26 HID_LB,
27 HID_RB,
28 HID_L,
29 HID_R,
30 HID_SELECT,
31 HID_START,
32 HID_MENU,
33 HID_LJ,
34 HID_RJ,
35 };
36
37 struct hid_report_meta {
38 int8_t hid_btn_idx;
39 int8_t hid_hat_idx;
40 uint8_t kb_bitfield;
41 };
42
43 struct hid_reports_meta {
44 struct hid_report_meta reports_meta[REPORT_MAX];
45 };
46
47 static struct hid_reports_meta devices_meta[BT_MAX_DEV] = {0};
48
49 struct generic_rumble {
50 uint8_t state[88];
51 uint8_t report_id;
52 uint32_t report_size;
53 } __packed;
54
55 static const uint32_t hid_kb_bitfield_to_generic[8] = {
56 KB_LCTRL,
57 KB_LSHIFT,
58 KB_LALT,
59 KB_LWIN,
60 KB_RCTRL,
61 KB_RSHIFT,
62 KB_RALT,
63 KB_RWIN,
64 };
65
66 static const uint32_t hid_kb_key_to_generic[] = {
67 0, 0, 0, 0, KB_A, KB_B, KB_C, KB_D,
68 KB_E, KB_F, KB_G, KB_H, KB_I, KB_J, KB_K, KB_L,
69 KB_M, KB_N, KB_O, KB_P, KB_Q, KB_R, KB_S, KB_T,
70 KB_U, KB_V, KB_W, KB_X, KB_Y, KB_Z, KB_1, KB_2,
71 KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9, KB_0,
72 KB_ENTER, KB_ESC, KB_BACKSPACE, KB_TAB, KB_SPACE, KB_MINUS, KB_EQUAL, KB_LEFTBRACE,
73 KB_RIGHTBRACE, KB_BACKSLASH, KB_HASH, KB_SEMICOLON, KB_APOSTROPHE, KB_GRAVE, KB_COMMA, KB_DOT,
74 KB_SLASH, KB_CAPSLOCK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6,
75 KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_PSCREEN, KB_SCROLL,
76 KB_PAUSE, KB_INSERT, KB_HOME, KB_PAGEUP, KB_DEL, KB_END, KB_PAGEDOWN, KB_RIGHT,
77 KB_LEFT, KB_DOWN, KB_UP, KB_NUMLOCK, KB_KP_DIV, KB_KP_MULTI, KB_KP_MINUS, KB_KP_PLUS,
78 KB_KP_ENTER, KB_KP_1, KB_KP_2, KB_KP_3, KB_KP_4, KB_KP_5, KB_KP_6, KB_KP_7,
79 KB_KP_8, KB_KP_9, KB_KP_0, KB_KP_DOT,
80 };
81
82 static const uint32_t hid_pad_default_btns_idx[32] = {
83 PAD_RB_DOWN, PAD_RB_RIGHT, PAD_RT,
84 PAD_RB_LEFT, PAD_RB_UP, PAD_LT,
85 PAD_LS, PAD_RS,
86 PAD_LM, PAD_RM,
87 PAD_MS, PAD_MM, PAD_MT,
88 PAD_LJ, PAD_RJ,
89 PAD_MQ,
90 PAD_RD_LEFT, PAD_RD_RIGHT, PAD_RD_DOWN, PAD_RD_UP,
91 };
92
93 static const uint32_t hid_pad_xinput_btns_idx[32] = {
94 PAD_RB_DOWN, PAD_RB_RIGHT,
95 PAD_RB_LEFT, PAD_RB_UP,
96 PAD_LS, PAD_RS,
97 PAD_MS, PAD_MM,
98 PAD_LJ, PAD_RJ,
99 };
100
101 static void hid_kb_init(struct hid_report_meta *meta, struct hid_report *report, struct raw_src_mapping *map) {
102 memset(map->axes_idx, -1, sizeof(map->axes_idx));
103 meta->hid_btn_idx = -1;
104
105 for (uint32_t i = 0; i < report->usage_cnt; i++) {
106 if (report->usages[i].usage > 0 && report->usages[i].usage < 0xE0) {
107 meta->kb_bitfield = 1;
108 break;
109 }
110 }
111 for (uint32_t i = 0, key_idx = 0; i < report->usage_cnt; i++) {
112 switch (report->usages[i].usage_page) {
113 case USAGE_GEN_KEYBOARD:
114 if (report->usages[i].usage >= 0xE0 && report->usages[i].usage <= 0xE7) {
115 map->mask[0] |= BIT(KB_LWIN & 0x1F) | BIT(KB_LCTRL & 0x1F) | BIT(KB_LSHIFT & 0x1F);
116 map->mask[3] |= BIT(KB_LALT & 0x1F) | BIT(KB_RCTRL & 0x1F) | BIT(KB_RSHIFT & 0x1F) | BIT(KB_RALT & 0x1F) | BIT(KB_RWIN & 0x1F);
117 meta->hid_btn_idx = i;
118 }
119 else if (key_idx < 6) {
120 map->axes_idx[key_idx] = i;
121 key_idx++;
122 }
123 break;
124 }
125 }
126 map->mask[0] |= 0xE6FF0F0F;
127 map->mask[1] |= 0xFFFFFFFF;
128 map->mask[2] |= 0xFFFFFFFF;
129 map->mask[3] |= 0x7FFFF;
130 }
131
132 static void hid_kb_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
133 struct hid_report_meta *meta = &devices_meta[bt_data->base.pids->id].reports_meta[KB];
134 struct raw_src_mapping *map = &bt_data->raw_src_mappings[KB];
135
136 TESTS_CMDS_LOG("\"wireless_input\": {\"report_id\": %ld", bt_data->base.report_id);
137
138 if (!atomic_test_bit(&bt_data->base.flags[KB], BT_INIT)) {
139 hid_parser_load_report(bt_data, bt_data->base.report_id);
140 hid_kb_init(meta, bt_data->reports[KB], &bt_data->raw_src_mappings[KB]);
141 atomic_set_bit(&bt_data->base.flags[KB], BT_INIT);
142 }
143
144 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
145
146 ctrl_data->mask = (uint32_t *)bt_data->raw_src_mappings[KB].mask;
147 ctrl_data->desc = (uint32_t *)bt_data->raw_src_mappings[KB].desc;
148
149 if (meta->hid_btn_idx > -1) {
150 uint32_t len = bt_data->reports[KB]->usages[meta->hid_btn_idx].bit_size;
151 uint32_t offset = bt_data->reports[KB]->usages[meta->hid_btn_idx].bit_offset;
152 uint32_t mask = (1ULL << len) - 1;
153 uint32_t byte_offset = offset / 8;
154 uint32_t bit_shift = offset % 8;
155 uint32_t buttons = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
156
157 TESTS_CMDS_LOG(", \"modifiers\": %lu", buttons);
158
159 for (uint8_t i = 0, mask = 1; mask; i++, mask <<= 1) {
160 if (buttons & mask) {
161 ctrl_data->btns[(hid_kb_bitfield_to_generic[i] >> 5)].value |= BIT(hid_kb_bitfield_to_generic[i] & 0x1F);
162 }
163 }
164 }
165
166 if (meta->kb_bitfield) {
167 TESTS_CMDS_LOG(", \"keys\": [");
168 for (uint32_t i = 0; i < ADAPTER_PS2_MAX_AXES; i++) {
169 if (map->axes_idx[i] > -1) {
170 int32_t len = bt_data->reports[KB]->usages[map->axes_idx[i]].bit_size;
171 uint32_t offset = bt_data->reports[KB]->usages[map->axes_idx[i]].bit_offset;
172 uint32_t mask = (1ULL << len) - 1;
173 uint32_t byte_offset = offset / 8;
174 uint32_t bit_shift = offset % 8;
175 uint32_t key_field = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
176
177 if (i) {
178 TESTS_CMDS_LOG(", ");
179 }
180 TESTS_CMDS_LOG("%lu", key_field);
181
182 for (uint32_t mask = 1; mask; mask <<= 1) {
183 uint32_t key = __builtin_ffs(key_field & mask);
184 if (key) {
185 key = key - 1 + bt_data->reports[KB]->usages[map->axes_idx[i]].usage;
186 ctrl_data->btns[(hid_kb_key_to_generic[key] >> 5)].value |= BIT(hid_kb_key_to_generic[key] & 0x1F);
187 }
188 }
189 }
190 }
191 }
192 else {
193 TESTS_CMDS_LOG(", \"keys\": [");
194 for (uint32_t i = 0; i < ADAPTER_PS2_MAX_AXES; i++) {
195 if (map->axes_idx[i] > -1) {
196 int32_t len = bt_data->reports[KB]->usages[map->axes_idx[i]].bit_size;
197 uint32_t offset = bt_data->reports[KB]->usages[map->axes_idx[i]].bit_offset;
198 uint32_t mask = (1ULL << len) - 1;
199 uint32_t byte_offset = offset / 8;
200 uint32_t bit_shift = offset % 8;
201 uint32_t key = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
202
203 if (i) {
204 TESTS_CMDS_LOG(", ");
205 }
206 TESTS_CMDS_LOG("%lu", key);
207
208 if (key > 3 && key < ARRAY_SIZE(hid_kb_key_to_generic)) {
209 ctrl_data->btns[(hid_kb_key_to_generic[key] >> 5)].value |= BIT(hid_kb_key_to_generic[key] & 0x1F);
210 }
211 }
212 }
213 }
214 TESTS_CMDS_LOG("]},\n");
215 }
216
217 static void hid_mouse_init(struct hid_report_meta *meta, struct hid_report *report, struct raw_src_mapping *map) {
218 memset(map->axes_idx, -1, sizeof(map->axes_idx));
219 meta->hid_btn_idx = -1;
220
221 for (uint32_t i = 0; i < report->usage_cnt; i++) {
222 switch (report->usages[i].usage_page) {
223 case USAGE_GEN_DESKTOP:
224 switch (report->usages[i].usage) {
225 case USAGE_GEN_DESKTOP_X:
226 map->mask[0] |= BIT(MOUSE_X_LEFT) | BIT(MOUSE_X_RIGHT);
227 map->desc[0] |= BIT(MOUSE_X_LEFT) | BIT(MOUSE_X_RIGHT);
228 map->axes_idx[AXIS_RX] = i;
229 map->meta[AXIS_RX].neutral = 0;
230 map->meta[AXIS_RX].abs_max = report->usages[i].logical_max;
231 map->meta[AXIS_RX].abs_min = report->usages[i].logical_min;
232 map->meta[AXIS_RX].relative = 1;
233 break;
234 case USAGE_GEN_DESKTOP_Y:
235 map->mask[0] |= BIT(MOUSE_Y_DOWN) | BIT(MOUSE_Y_UP);
236 map->desc[0] |= BIT(MOUSE_Y_DOWN) | BIT(MOUSE_Y_UP);
237 map->axes_idx[AXIS_RY] = i;
238 map->meta[AXIS_RY].neutral = 0;
239 map->meta[AXIS_RY].abs_max = report->usages[i].logical_max;
240 map->meta[AXIS_RY].abs_min = report->usages[i].logical_min;
241 map->meta[AXIS_RY].polarity = 1;
242 map->meta[AXIS_RY].relative = 1;
243 break;
244 case USAGE_GEN_DESKTOP_WHEEL:
245 map->mask[0] |= BIT(MOUSE_WY_DOWN) | BIT(MOUSE_WY_UP);
246 map->desc[0] |= BIT(MOUSE_WY_DOWN) | BIT(MOUSE_WY_UP);
247 map->axes_idx[AXIS_LY] = i;
248 map->meta[AXIS_LY].neutral = 0;
249 map->meta[AXIS_LY].abs_max = report->usages[i].logical_max;
250 map->meta[AXIS_LY].abs_min = report->usages[i].logical_min;
251 map->meta[AXIS_LY].polarity = 1;
252 map->meta[AXIS_LY].relative = 1;
253 break;
254 case 0x85: /* Sys Main Menu */
255 /* Hack for xinput Xbox btn */
256 meta->hid_btn_idx = i;
257 map->mask[0] |= BIT(PAD_MT);
258 map->btns_mask[PAD_MT] = BIT(0);
259 break;
260 }
261 break;
262 case USAGE_GEN_BUTTON:
263 meta->hid_btn_idx = i;
264 for (uint32_t i = 0; i < report->usages[i].bit_size; i++) {
265 switch (i) {
266 case 0:
267 map->mask[0] |= BIT(MOUSE_LEFT);
268 map->btns_mask[MOUSE_LEFT] = BIT(i);
269 break;
270 case 1:
271 map->mask[0] |= BIT(MOUSE_RIGHT);
272 map->btns_mask[MOUSE_RIGHT] = BIT(i);
273 break;
274 case 2:
275 map->mask[0] |= BIT(MOUSE_MIDDLE);
276 map->btns_mask[MOUSE_MIDDLE] = BIT(i);
277 break;
278 case 7:
279 map->mask[0] |= BIT(MOUSE_8);
280 map->btns_mask[MOUSE_8] = BIT(i);
281 break;
282 default:
283 map->mask[0] |= BIT(MOUSE_4 + i - 3);
284 map->btns_mask[MOUSE_4 + i - 3] = BIT(i);
285 break;
286 }
287 }
288 break;
289 }
290 }
291 }
292
293 static void hid_mouse_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
294 struct hid_report_meta *meta = &devices_meta[bt_data->base.pids->id].reports_meta[MOUSE];
295 struct ctrl_meta *ctrl_meta = bt_data->raw_src_mappings[MOUSE].meta;
296 struct raw_src_mapping *map = &bt_data->raw_src_mappings[MOUSE];
297
298 if (!atomic_test_bit(&bt_data->base.flags[MOUSE], BT_INIT)) {
299 hid_parser_load_report(bt_data, bt_data->base.report_id);
300 hid_mouse_init(meta, bt_data->reports[MOUSE], &bt_data->raw_src_mappings[MOUSE]);
301 atomic_set_bit(&bt_data->base.flags[MOUSE], BT_INIT);
302 }
303
304 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
305
306 ctrl_data->mask = (uint32_t *)bt_data->raw_src_mappings[MOUSE].mask;
307 ctrl_data->desc = (uint32_t *)bt_data->raw_src_mappings[MOUSE].desc;
308
309 if (meta->hid_btn_idx > -1) {
310 uint32_t len = bt_data->reports[MOUSE]->usages[meta->hid_btn_idx].bit_size;
311 uint32_t offset = bt_data->reports[MOUSE]->usages[meta->hid_btn_idx].bit_offset;
312 uint32_t mask = (1ULL << len) - 1;
313 uint32_t byte_offset = offset / 8;
314 uint32_t bit_shift = offset % 8;
315 uint32_t buttons = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
316
317 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
318 if (buttons & bt_data->raw_src_mappings[MOUSE].btns_mask[i]) {
319 ctrl_data->btns[0].value |= generic_btns_mask[i];
320 }
321 }
322 }
323
324 for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) {
325 if (map->axes_idx[i] > -1) {
326 int32_t len = bt_data->reports[MOUSE]->usages[map->axes_idx[i]].bit_size;
327 uint32_t offset = bt_data->reports[MOUSE]->usages[map->axes_idx[i]].bit_offset;
328 uint32_t mask = (1ULL << len) - 1;
329 uint32_t byte_offset = offset / 8;
330 uint32_t bit_shift = offset % 8;
331
332 ctrl_data->axes[i].meta = &ctrl_meta[i];
333 ctrl_data->axes[i].value = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
334 if (ctrl_data->axes[i].value & BIT(len - 1)) {
335 ctrl_data->axes[i].value |= ~mask;
336 }
337 }
338 }
339 }
340
341 13 static void hid_pad_init(struct hid_report_meta *meta, struct hid_report *report, struct raw_src_mapping *map) {
342 13 bool btns_is_xinput = 0;
343 13 uint32_t z_is_joy = 0;
344 13 int8_t hid_cbtn_idx = -1;
345 13 memset(map->axes_idx, -1, sizeof(map->axes_idx));
346 13 meta->hid_btn_idx = -1;
347 13 meta->hid_hat_idx = -1;
348
349 /* Detect if Z axis is Right joystick or a trigger */
350
2/2
✓ Branch 0 (13→4) taken 75 times.
✓ Branch 1 (13→14) taken 3 times.
78 for (uint32_t i = 0; i < report->usage_cnt; i++) {
351
4/4
✓ Branch 0 (4→5) taken 18 times.
✓ Branch 1 (4→12) taken 57 times.
✓ Branch 2 (5→6) taken 12 times.
✓ Branch 3 (5→12) taken 6 times.
75 if (report->usages[i].usage_page == USAGE_GEN_DESKTOP && report->usages[i].usage == USAGE_GEN_DESKTOP_X) {
352 12 i++;
353
2/4
✓ Branch 0 (6→7) taken 12 times.
✗ Branch 1 (6→12) not taken.
✓ Branch 2 (7→8) taken 12 times.
✗ Branch 3 (7→12) not taken.
12 if (report->usages[i].usage_page == USAGE_GEN_DESKTOP && report->usages[i].usage == USAGE_GEN_DESKTOP_Y) {
354 12 i++;
355
3/4
✓ Branch 0 (8→9) taken 10 times.
✓ Branch 1 (8→10) taken 2 times.
✓ Branch 2 (9→10) taken 10 times.
✗ Branch 3 (9→14) not taken.
12 if (report->usages[i].usage_page == USAGE_GEN_DESKTOP && report->usages[i].usage == 0x33 /* USAGE_GEN_DESKTOP_RX */) {
356 z_is_joy = 0;
357 break;
358 }
359
3/4
✓ Branch 0 (10→11) taken 10 times.
✓ Branch 1 (10→12) taken 2 times.
✗ Branch 2 (11→12) not taken.
✓ Branch 3 (11→14) taken 10 times.
12 else if (report->usages[i].usage_page == USAGE_GEN_DESKTOP && report->usages[i].usage == 0x32 /* USAGE_GEN_DESKTOP_Z */) {
360 z_is_joy = 1;
361 break;
362 }
363 }
364 }
365 }
366
367 26 btns_is_xinput = (
368 4 report->usage_cnt == 8 &&
369
2/4
✓ Branch 0 (15→16) taken 4 times.
✗ Branch 1 (15→32) not taken.
✓ Branch 2 (16→17) taken 4 times.
✗ Branch 3 (16→32) not taken.
4 report->usages[0].usage_page == USAGE_GEN_DESKTOP && report->usages[0].usage == USAGE_GEN_DESKTOP_X &&
370
2/4
✓ Branch 0 (17→18) taken 4 times.
✗ Branch 1 (17→32) not taken.
✓ Branch 2 (18→19) taken 4 times.
✗ Branch 3 (18→32) not taken.
4 report->usages[1].usage_page == USAGE_GEN_DESKTOP && report->usages[1].usage == USAGE_GEN_DESKTOP_Y &&
371
2/4
✓ Branch 0 (19→20) taken 4 times.
✗ Branch 1 (19→32) not taken.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→32) taken 4 times.
4 report->usages[2].usage_page == USAGE_GEN_DESKTOP && report->usages[2].usage == 0x33 &&
372 report->usages[3].usage_page == USAGE_GEN_DESKTOP && report->usages[3].usage == 0x34 &&
373 report->usages[4].usage_page == USAGE_GEN_DESKTOP && report->usages[4].usage == 0x32 &&
374 report->usages[5].usage_page == USAGE_GEN_DESKTOP && report->usages[5].usage == 0x35 &&
375 report->usages[6].usage_page == USAGE_GEN_DESKTOP && report->usages[6].usage == 0x39 &&
376 report->usages[7].usage_page == USAGE_GEN_BUTTON &&
377
2/6
✓ Branch 0 (14→15) taken 4 times.
✓ Branch 1 (14→32) taken 9 times.
✗ Branch 2 (30→31) not taken.
✗ Branch 3 (30→32) not taken.
✗ Branch 4 (31→32) not taken.
✗ Branch 5 (31→33) not taken.
13 report->usages[7].usage == 0x01 && report->usages[7].usage_max == 0x0A
378 );
379
380 /* Build mask, desc, idx and meta base on usage */
381
2/2
✓ Branch 0 (78→34) taken 143 times.
✓ Branch 1 (78→79) taken 13 times.
156 for (uint32_t i = 0; i < report->usage_cnt; i++) {
382
4/5
✗ Branch 0 (34→35) not taken.
✓ Branch 1 (34→36) taken 56 times.
✓ Branch 2 (34→70) taken 56 times.
✓ Branch 3 (34→72) taken 20 times.
✓ Branch 4 (34→75) taken 11 times.
143 switch (report->usages[i].usage_page) {
383 56 case USAGE_GEN_DESKTOP:
384
6/8
✓ Branch 0 (36→35) taken 1 times.
✓ Branch 1 (36→37) taken 12 times.
✓ Branch 2 (36→41) taken 12 times.
✓ Branch 3 (36→45) taken 10 times.
✗ Branch 4 (36→51) not taken.
✗ Branch 5 (36→57) not taken.
✓ Branch 6 (36→63) taken 10 times.
✓ Branch 7 (36→69) taken 11 times.
56 switch (report->usages[i].usage) {
385 12 case USAGE_GEN_DESKTOP_X:
386 12 map->mask[0] |= BIT(PAD_LX_LEFT) | BIT(PAD_LX_RIGHT);
387 12 map->desc[0] |= BIT(PAD_LX_LEFT) | BIT(PAD_LX_RIGHT);
388 12 map->axes_idx[AXIS_LX] = i;
389
2/2
✓ Branch 0 (37→38) taken 10 times.
✓ Branch 1 (37→39) taken 2 times.
12 if (report->usages[i].logical_min >= 0) {
390 10 map->meta[AXIS_LX].neutral = (report->usages[i].logical_max / 2) + 1;
391 }
392 else {
393 2 map->meta[AXIS_LX].neutral = 0;
394 }
395 12 map->meta[AXIS_LX].abs_max = report->usages[i].logical_max - map->meta[AXIS_LX].neutral;
396 12 map->meta[AXIS_LX].abs_min = map->meta[AXIS_LX].neutral - report->usages[i].logical_min;
397 12 break;
398 12 case USAGE_GEN_DESKTOP_Y:
399 12 map->mask[0] |= BIT(PAD_LY_DOWN) | BIT(PAD_LY_UP);
400 12 map->desc[0] |= BIT(PAD_LY_DOWN) | BIT(PAD_LY_UP);
401 12 map->axes_idx[AXIS_LY] = i;
402
2/2
✓ Branch 0 (41→42) taken 10 times.
✓ Branch 1 (41→43) taken 2 times.
12 if (report->usages[i].logical_min >= 0) {
403 10 map->meta[AXIS_LY].neutral = (report->usages[i].logical_max / 2) + 1;
404 }
405 else {
406 2 map->meta[AXIS_LY].neutral = 0;
407 }
408 12 map->meta[AXIS_LY].abs_max = report->usages[i].logical_max - map->meta[AXIS_LY].neutral;
409 12 map->meta[AXIS_LY].abs_min = map->meta[AXIS_LY].neutral - report->usages[i].logical_min;
410 12 map->meta[AXIS_LY].polarity = 1;
411 12 break;
412 10 case 0x32 /* USAGE_GEN_DESKTOP_Z */:
413
1/2
✓ Branch 0 (45→46) taken 10 times.
✗ Branch 1 (45→50) not taken.
10 if (z_is_joy) {
414 10 map->mask[0] |= BIT(PAD_RX_LEFT) | BIT(PAD_RX_RIGHT);
415 10 map->desc[0] |= BIT(PAD_RX_LEFT) | BIT(PAD_RX_RIGHT);
416 10 map->axes_idx[AXIS_RX] = i;
417
2/2
✓ Branch 0 (46→47) taken 8 times.
✓ Branch 1 (46→48) taken 2 times.
10 if (report->usages[i].logical_min >= 0) {
418 8 map->meta[AXIS_RX].neutral = (report->usages[i].logical_max / 2) + 1;
419 }
420 else {
421 2 map->meta[AXIS_RX].neutral = 0;
422 }
423 10 map->meta[AXIS_RX].abs_max = report->usages[i].logical_max - map->meta[AXIS_RX].neutral;
424 10 map->meta[AXIS_RX].abs_min = map->meta[AXIS_RX].neutral - report->usages[i].logical_min;
425 }
426 else {
427 map->mask[0] |= BIT(PAD_LM);
428 map->desc[0] |= BIT(PAD_LM);
429 map->axes_idx[TRIG_L] = i;
430 map->meta[TRIG_L].abs_max = report->usages[i].logical_max;
431 map->meta[TRIG_L].abs_min = report->usages[i].logical_min;
432 map->meta[TRIG_L].neutral = report->usages[i].logical_min;
433 }
434 break;
435 case 0x33 /* USAGE_GEN_DESKTOP_RX */:
436 if (z_is_joy) {
437 map->mask[0] |= BIT(PAD_LM);
438 map->desc[0] |= BIT(PAD_LM);
439 map->axes_idx[TRIG_L] = i;
440 map->meta[TRIG_L].abs_max = report->usages[i].logical_max;
441 map->meta[TRIG_L].abs_min = report->usages[i].logical_min;
442 map->meta[TRIG_L].neutral = report->usages[i].logical_min;
443 }
444 else {
445 map->mask[0] |= BIT(PAD_RX_LEFT) | BIT(PAD_RX_RIGHT);
446 map->desc[0] |= BIT(PAD_RX_LEFT) | BIT(PAD_RX_RIGHT);
447 map->axes_idx[AXIS_RX] = i;
448 if (report->usages[i].logical_min >= 0) {
449 map->meta[AXIS_RX].neutral = (report->usages[i].logical_max / 2) + 1;
450 }
451 else {
452 map->meta[AXIS_RX].neutral = 0;
453 }
454 map->meta[AXIS_RX].abs_max = report->usages[i].logical_max - map->meta[AXIS_RX].neutral;
455 map->meta[AXIS_RX].abs_min = map->meta[AXIS_RX].neutral - report->usages[i].logical_min;
456 }
457 break;
458 case 0x34 /* USAGE_GEN_DESKTOP_RY */:
459 if (z_is_joy) {
460 map->mask[0] |= BIT(PAD_RM);
461 map->desc[0] |= BIT(PAD_RM);
462 map->axes_idx[TRIG_R] = i;
463 map->meta[TRIG_R].abs_max = report->usages[i].logical_max;
464 map->meta[TRIG_R].abs_min = report->usages[i].logical_min;
465 map->meta[TRIG_R].neutral = report->usages[i].logical_min;
466 }
467 else {
468 map->mask[0] |= BIT(PAD_RY_DOWN) | BIT(PAD_RY_UP);
469 map->desc[0] |= BIT(PAD_RY_DOWN) | BIT(PAD_RY_UP);
470 map->axes_idx[AXIS_RY] = i;
471 if (report->usages[i].logical_min >= 0) {
472 map->meta[AXIS_RY].neutral = (report->usages[i].logical_max / 2) + 1;
473 }
474 else {
475 map->meta[AXIS_RY].neutral = 0;
476 }
477 map->meta[AXIS_RY].abs_max = report->usages[i].logical_max - map->meta[AXIS_RY].neutral;
478 map->meta[AXIS_RY].abs_min = map->meta[AXIS_RY].neutral - report->usages[i].logical_min;
479 map->meta[AXIS_RY].polarity = 1;
480 }
481 break;
482 10 case 0x35 /* USAGE_GEN_DESKTOP_RZ */:
483
1/2
✓ Branch 0 (63→64) taken 10 times.
✗ Branch 1 (63→68) not taken.
10 if (z_is_joy) {
484 10 map->mask[0] |= BIT(PAD_RY_DOWN) | BIT(PAD_RY_UP);
485 10 map->desc[0] |= BIT(PAD_RY_DOWN) | BIT(PAD_RY_UP);
486 10 map->axes_idx[AXIS_RY] = i;
487
2/2
✓ Branch 0 (64→65) taken 8 times.
✓ Branch 1 (64→66) taken 2 times.
10 if (report->usages[i].logical_min >= 0) {
488 8 map->meta[AXIS_RY].neutral = (report->usages[i].logical_max / 2) + 1;
489 }
490 else {
491 2 map->meta[AXIS_RY].neutral = 0;
492 }
493 10 map->meta[AXIS_RY].abs_max = report->usages[i].logical_max - map->meta[AXIS_RY].neutral;
494 10 map->meta[AXIS_RY].abs_min = map->meta[AXIS_RY].neutral - report->usages[i].logical_min;
495 10 map->meta[AXIS_RY].polarity = 1;
496 }
497 else {
498 map->mask[0] |= BIT(PAD_RM);
499 map->desc[0] |= BIT(PAD_RM);
500 map->axes_idx[TRIG_R] = i;
501 map->meta[TRIG_R].abs_max = report->usages[i].logical_max;
502 map->meta[TRIG_R].abs_min = report->usages[i].logical_min;
503 map->meta[TRIG_R].neutral = report->usages[i].logical_min;
504 }
505 break;
506 11 case 0x39 /* USAGE_GEN_DESKTOP_HAT */:
507 11 map->mask[0] |= BIT(PAD_LD_LEFT) | BIT(PAD_LD_RIGHT) | BIT(PAD_LD_DOWN) | BIT(PAD_LD_UP);
508 11 meta->hid_hat_idx = i;
509 11 break;
510 }
511 break;
512 56 case USAGE_GEN_BUTTON:
513
2/2
✓ Branch 0 (70→35) taken 43 times.
✓ Branch 1 (70→71) taken 13 times.
56 if (meta->hid_btn_idx < 0) {
514 13 meta->hid_btn_idx = i;
515 }
516 break;
517 20 case 0x02 /* USAGE_SIMS */:
518
2/3
✗ Branch 0 (72→35) not taken.
✓ Branch 1 (72→73) taken 10 times.
✓ Branch 2 (72→74) taken 10 times.
20 switch (report->usages[i].usage) {
519 10 case 0xC4 /* USAGE_SIMS_ACCEL */:
520 10 map->mask[0] |= BIT(PAD_RM);
521 10 map->desc[0] |= BIT(PAD_RM);
522 10 map->axes_idx[TRIG_R] = i;
523 10 map->meta[TRIG_R].abs_max = report->usages[i].logical_max;
524 10 map->meta[TRIG_R].abs_min = report->usages[i].logical_min;
525 10 map->meta[TRIG_R].neutral = report->usages[i].logical_min;
526 10 break;
527 10 case 0xC5 /* USAGE_SIMS_BRAKE */:
528 10 map->mask[0] |= BIT(PAD_LM);
529 10 map->desc[0] |= BIT(PAD_LM);
530 10 map->axes_idx[TRIG_L] = i;
531 10 map->meta[TRIG_L].abs_max = report->usages[i].logical_max;
532 10 map->meta[TRIG_L].abs_min = report->usages[i].logical_min;
533 10 map->meta[TRIG_L].neutral = report->usages[i].logical_min;
534 10 break;
535 }
536 break;
537 11 case 0x0C: /* Consumer */
538
2/2
✓ Branch 0 (75→35) taken 6 times.
✓ Branch 1 (75→76) taken 5 times.
11 if (hid_cbtn_idx < 0) {
539 5 hid_cbtn_idx = i;
540 }
541 break;
542 }
543 }
544
545 /* Add a little pull-back on axis max */
546
2/2
✓ Branch 0 (81→80) taken 78 times.
✓ Branch 1 (81→82) taken 13 times.
91 for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) {
547 78 map->meta[i].abs_max *= MAX_PULL_BACK;
548 78 map->meta[i].abs_min *= MAX_PULL_BACK;
549 }
550
551 /* We assume here that button-like usages are all */
552 /* placed consecutively in the report. We try here to aggregate */
553 /* then all under a single button usage. */
554 13 int8_t btn_idx = 0;
555 13 uint32_t btn_offset = 0;
556
3/4
✓ Branch 0 (82→83) taken 13 times.
✗ Branch 1 (82→85) not taken.
✓ Branch 2 (83→84) taken 8 times.
✓ Branch 3 (83→85) taken 5 times.
13 if (meta->hid_btn_idx > -1 && hid_cbtn_idx == -1) {
557 8 btn_idx = meta->hid_btn_idx;
558 8 btn_offset = report->usages[btn_idx].bit_offset;
559 }
560
1/4
✗ Branch 0 (85→86) not taken.
✓ Branch 1 (85→88) taken 5 times.
✗ Branch 2 (86→87) not taken.
✗ Branch 3 (86→88) not taken.
5 else if (meta->hid_btn_idx == -1 && hid_cbtn_idx > -1) {
561 btn_idx = hid_cbtn_idx;
562 btn_offset = report->usages[btn_idx].bit_offset;
563 }
564
2/4
✓ Branch 0 (88→89) taken 5 times.
✗ Branch 1 (88→93) not taken.
✓ Branch 2 (89→90) taken 5 times.
✗ Branch 3 (89→93) not taken.
5 else if (meta->hid_btn_idx > -1 && hid_cbtn_idx > -1) {
565 5 btn_idx = meta->hid_btn_idx;
566
1/2
✓ Branch 0 (90→91) taken 5 times.
✗ Branch 1 (90→92) not taken.
5 if (meta->hid_btn_idx < hid_cbtn_idx) {
567 5 btn_offset = report->usages[meta->hid_btn_idx].bit_offset;
568 }
569 else {
570 btn_offset = report->usages[hid_cbtn_idx].bit_offset;
571 }
572 }
573
574
1/2
✓ Branch 0 (93→94) taken 13 times.
✗ Branch 1 (93→106) not taken.
13 if (meta->hid_btn_idx > -1) {
575
1/2
✓ Branch 0 (94→95) taken 13 times.
✗ Branch 1 (94→96) not taken.
13 const uint32_t *btns_idx = (btns_is_xinput) ? hid_pad_xinput_btns_idx : hid_pad_default_btns_idx;
576 13 uint32_t uidx = meta->hid_btn_idx;
577 13 uint32_t undef_usage = 15;
578
2/2
✓ Branch 0 (104→97) taken 56 times.
✓ Branch 1 (104→105) taken 13 times.
69 for (; report->usages[uidx].usage_page == USAGE_GEN_BUTTON; uidx++) {
579
1/2
✓ Branch 0 (97→98) taken 56 times.
✗ Branch 1 (97→103) not taken.
56 if (report->usages[uidx].usage) {
580 56 uint32_t usage = report->usages[uidx].usage - 1;
581
2/2
✓ Branch 0 (98→99) taken 8 times.
✓ Branch 1 (98→100) taken 48 times.
56 if (usage > HID_RJ) {
582 8 usage = undef_usage++;
583 }
584
2/2
✓ Branch 0 (102→101) taken 206 times.
✓ Branch 1 (102→103) taken 56 times.
262 for (uint32_t j = 0; j < report->usages[uidx].bit_size; j++, usage++) {
585 206 map->mask[0] |= BIT(btns_idx[usage]);
586 206 map->btns_mask[btns_idx[usage]] =
587 206 BIT(report->usages[uidx].bit_offset - btn_offset + j);
588 }
589 }
590 }
591 13 report->usages[btn_idx].bit_size =
592 13 report->usages[uidx - 1].bit_offset + report->usages[uidx - 1].bit_size - btn_offset;
593 }
594
2/2
✓ Branch 0 (106→107) taken 5 times.
✓ Branch 1 (106→120) taken 8 times.
13 if (hid_cbtn_idx > -1) {
595 5 uint32_t uidx = hid_cbtn_idx;
596
2/2
✓ Branch 0 (115→108) taken 11 times.
✓ Branch 1 (115→116) taken 5 times.
16 for (; report->usages[uidx].usage_page == 0x0C; uidx++) {
597
1/2
✓ Branch 0 (108→109) taken 11 times.
✗ Branch 1 (108→114) not taken.
11 if (report->usages[uidx].usage) {
598
4/5
✓ Branch 0 (109→110) taken 3 times.
✓ Branch 1 (109→111) taken 2 times.
✓ Branch 2 (109→112) taken 3 times.
✓ Branch 3 (109→113) taken 3 times.
✗ Branch 4 (109→114) not taken.
11 switch (report->usages[uidx].usage) {
599 3 case 0x40 /* Menu */:
600 3 map->mask[0] |= BIT(PAD_MM);
601 3 map->btns_mask[PAD_MM] =
602 3 BIT(report->usages[uidx].bit_offset - btn_offset);
603 3 break;
604 2 case 0xB2 /* Record */:
605 2 map->mask[0] |= BIT(PAD_MQ);
606 2 map->btns_mask[PAD_MQ] =
607 2 BIT(report->usages[uidx].bit_offset - btn_offset);
608 2 break;
609 3 case 0x223 /* AC Home */:
610 3 map->mask[0] |= BIT(PAD_MT);
611 3 map->btns_mask[PAD_MT] =
612 3 BIT(report->usages[uidx].bit_offset - btn_offset);
613 3 break;
614 3 case 0x224 /* AC Back */:
615 3 map->mask[0] |= BIT(PAD_MS);
616 3 map->btns_mask[PAD_MS] =
617 3 BIT(report->usages[uidx].bit_offset - btn_offset);
618 3 break;
619 }
620 }
621 }
622 5 uint32_t bit_size =
623 5 report->usages[uidx - 1].bit_offset + report->usages[uidx - 1].bit_size - btn_offset;
624
1/2
✓ Branch 0 (116→117) taken 5 times.
✗ Branch 1 (116→118) not taken.
5 if (bit_size > report->usages[btn_idx].bit_size) {
625 5 report->usages[btn_idx].bit_size = bit_size;
626 }
627
1/2
✗ Branch 0 (118→119) not taken.
✓ Branch 1 (118→120) taken 5 times.
5 if (btn_idx == hid_cbtn_idx) {
628 meta->hid_btn_idx = btn_idx;
629 }
630 }
631 13 }
632
633 235 static void hid_pad_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
634 235 struct hid_report_meta *meta = &devices_meta[bt_data->base.pids->id].reports_meta[PAD];
635 235 struct ctrl_meta *ctrl_meta = bt_data->raw_src_mappings[PAD].meta;
636 235 struct raw_src_mapping *map = &bt_data->raw_src_mappings[PAD];
637
638 235 TESTS_CMDS_LOG("\"wireless_input\": {\"report_id\": %ld", bt_data->base.report_id);
639 #ifdef CONFIG_BLUERETRO_ADAPTER_INPUT_DBG
640 235 printf("R%ld: ", bt_data->base.report_id);
641 #endif
642
643
2/2
✓ Branch 0 (5→6) taken 13 times.
✓ Branch 1 (5→10) taken 222 times.
235 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
644 13 hid_parser_load_report(bt_data, bt_data->base.report_id);
645 13 hid_pad_init(meta, bt_data->reports[PAD], &bt_data->raw_src_mappings[PAD]);
646 13 mapping_quirks_apply(bt_data);
647 13 bt_mon_log(false, "%s: axes_cal: [", __FUNCTION__);
648 }
649
650 235 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
651
652 235 ctrl_data->mask = (uint32_t *)bt_data->raw_src_mappings[PAD].mask;
653 235 ctrl_data->desc = (uint32_t *)bt_data->raw_src_mappings[PAD].desc;
654
655
1/2
✓ Branch 0 (11→12) taken 235 times.
✗ Branch 1 (11→18) not taken.
235 if (meta->hid_btn_idx > -1) {
656 235 uint32_t len = bt_data->reports[PAD]->usages[meta->hid_btn_idx].bit_size;
657 235 uint32_t offset = bt_data->reports[PAD]->usages[meta->hid_btn_idx].bit_offset;
658 235 uint32_t mask = (1ULL << len) - 1;
659 235 uint32_t byte_offset = offset / 8;
660 235 uint32_t bit_shift = offset % 8;
661 235 uint32_t buttons = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
662
663 235 TESTS_CMDS_LOG(", \"btns\": %lu", buttons);
664
665
2/2
✓ Branch 0 (17→14) taken 7520 times.
✓ Branch 1 (17→18) taken 235 times.
7755 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
666
2/2
✓ Branch 0 (14→15) taken 208 times.
✓ Branch 1 (14→16) taken 7312 times.
7520 if (buttons & bt_data->raw_src_mappings[PAD].btns_mask[i]) {
667 208 ctrl_data->btns[0].value |= generic_btns_mask[i];
668 }
669 }
670 }
671
672 /* Convert hat to regular btns */
673
2/2
✓ Branch 0 (18→19) taken 191 times.
✓ Branch 1 (18→21) taken 44 times.
235 if (meta->hid_hat_idx > -1) {
674 191 uint32_t len = bt_data->reports[PAD]->usages[meta->hid_hat_idx].bit_size;
675 191 uint32_t offset = bt_data->reports[PAD]->usages[meta->hid_hat_idx].bit_offset;
676 191 uint32_t mask = (1ULL << len) - 1;
677 191 uint32_t byte_offset = offset / 8;
678 191 uint32_t bit_shift = offset % 8;
679 191 uint32_t hat = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
680 191 uint32_t min = bt_data->reports[PAD]->usages[meta->hid_hat_idx].logical_min;
681
682 191 TESTS_CMDS_LOG(", \"hat\": %lu", hat);
683
684 191 ctrl_data->btns[0].value |= hat_to_ld_btns[(hat - min) & 0xF];
685 }
686
687 235 TESTS_CMDS_LOG(", \"axes\": [");
688
689
2/2
✓ Branch 0 (38→23) taken 3760 times.
✓ Branch 1 (38→39) taken 235 times.
3995 for (uint32_t i = 0; i < ADAPTER_PS2_MAX_AXES; i++) {
690
2/2
✓ Branch 0 (23→24) taken 1084 times.
✓ Branch 1 (23→37) taken 2676 times.
3760 if (map->axes_idx[i] > -1) {
691 1084 int32_t len = bt_data->reports[PAD]->usages[map->axes_idx[i]].bit_size;
692 1084 uint32_t offset = bt_data->reports[PAD]->usages[map->axes_idx[i]].bit_offset;
693 1084 uint32_t mask = (1ULL << len) - 1;
694 1084 uint32_t byte_offset = offset / 8;
695 1084 uint32_t bit_shift = offset % 8;
696 1084 uint32_t value = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
697
698
2/2
✓ Branch 0 (24→25) taken 874 times.
✓ Branch 1 (24→26) taken 210 times.
1084 if (i) {
699 874 TESTS_CMDS_LOG(", ");
700 }
701
702
2/2
✓ Branch 0 (27→28) taken 64 times.
✓ Branch 1 (27→31) taken 1020 times.
1084 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
703 64 bt_data->base.axes_cal[i] = -(value - ctrl_meta[i].neutral);
704
2/2
✓ Branch 0 (28→29) taken 52 times.
✓ Branch 1 (28→30) taken 12 times.
64 if (i) {
705 52 bt_mon_log(false, ", ");
706 }
707 64 bt_mon_log(false, "%d", bt_data->base.axes_cal[i]);
708 }
709
710 1084 ctrl_data->axes[i].meta = &ctrl_meta[i];
711
712 /* Is axis unsign? */
713
2/2
✓ Branch 0 (31→32) taken 932 times.
✓ Branch 1 (31→33) taken 152 times.
1084 if (bt_data->reports[PAD]->usages[map->axes_idx[i]].logical_min >= 0) {
714 932 ctrl_data->axes[i].value = value - ctrl_meta[i].neutral + bt_data->base.axes_cal[i];
715 932 TESTS_CMDS_LOG("%lu", value);
716 }
717 else {
718 152 ctrl_data->axes[i].value = value;
719
2/2
✓ Branch 0 (33→34) taken 10 times.
✓ Branch 1 (33→35) taken 142 times.
152 if (ctrl_data->axes[i].value & BIT(len - 1)) {
720 10 ctrl_data->axes[i].value |= ~mask;
721 }
722 152 TESTS_CMDS_LOG("%ld", ctrl_data->axes[i].value);
723 152 ctrl_data->axes[i].value += bt_data->base.axes_cal[i];
724 }
725 }
726 }
727
2/2
✓ Branch 0 (40→41) taken 13 times.
✓ Branch 1 (40→43) taken 222 times.
235 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
728 13 atomic_set_bit(&bt_data->base.flags[PAD], BT_INIT);
729 13 bt_mon_log(true, "]");
730 }
731 235 TESTS_CMDS_LOG("]},\n");
732 235 }
733
734 235 int32_t hid_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
735 #ifdef CONFIG_BLUERETRO_GENERIC_HID_DEBUG
736 struct hid_report *report = hid_parser_get_report(bt_data->base.pids->id, bt_data->base.report_id);
737 for (uint32_t i = 0; i < report->usage_cnt; i++) {
738 int32_t len = report->usages[i].bit_size;
739 uint32_t offset = report->usages[i].bit_offset;
740 uint32_t mask = (1ULL << len) - 1;
741 uint32_t byte_offset = offset / 8;
742 uint32_t bit_shift = offset % 8;
743 uint32_t value = ((*(uint32_t *)(bt_data->base.input + byte_offset)) >> bit_shift) & mask;
744 if (report->usages[i].bit_size <= 4) {
745 printf("R%ld %02lX%02lX: %s%01lX%s, ", bt_data->base.report_type, report->usages[i].usage_page, report->usages[i].usage, BOLD, value, RESET);
746 }
747 else if (report->usages[i].bit_size <= 8) {
748 printf("R%ld %02lX%02lX: %s%02lX%s, ", bt_data->base.report_type, report->usages[i].usage_page, report->usages[i].usage, BOLD, value, RESET);
749 }
750 else if (report->usages[i].bit_size <= 12) {
751 printf("R%ld %02lX%02lX: %s%03lX%s, ", bt_data->base.report_type, report->usages[i].usage_page, report->usages[i].usage, BOLD, value, RESET);
752 }
753 else if (report->usages[i].bit_size <= 16) {
754 printf("R%ld %02lX%02lX: %s%04lX%s, ", bt_data->base.report_type, report->usages[i].usage_page, report->usages[i].usage, BOLD, value, RESET);
755 }
756 else if (report->usages[i].bit_size <= 32) {
757 printf("R%ld %02lX%02lX: %s%08lX%s, ", bt_data->base.report_type, report->usages[i].usage_page, report->usages[i].usage, BOLD, value, RESET);
758 }
759 }
760 printf("\n");
761 return -1;
762 #else
763
1/4
✗ Branch 0 (2→3) not taken.
✗ Branch 1 (2→5) not taken.
✓ Branch 2 (2→8) taken 235 times.
✗ Branch 3 (2→10) not taken.
235 switch (bt_data->base.report_type) {
764 case KB:
765 hid_kb_to_generic(bt_data, ctrl_data);
766 break;
767 case MOUSE:
768 hid_mouse_to_generic(bt_data, ctrl_data);
769 break;
770 235 case PAD:
771 235 hid_pad_to_generic(bt_data, ctrl_data);
772 235 break;
773 default:
774 printf("# Unsupported report type: %02lX\n", bt_data->base.report_type);
775 return -1;
776 }
777 #endif
778
779 return 0;
780 }
781
782 6 bool hid_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) {
783 6 bool ret = true;
784
785
1/2
✓ Branch 0 (2→3) taken 6 times.
✗ Branch 1 (2→33) not taken.
6 switch (fb_data->type) {
786 6 case FB_TYPE_RUMBLE:
787
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→8) taken 6 times.
6 if (atomic_test_bit(&bt_data->base.flags[PAD], BT_QUIRK_8BITDO_GC)) {
788 struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output;
789
790 rumble->report_id = 0xA5;
791 rumble->report_size = 3;
792 rumble->state[0] = 0xdb;
793 if (fb_data->state) {
794 rumble->state[1] = fb_data->lf_pwr;
795 rumble->state[2] = fb_data->hf_pwr;
796 }
797 else {
798 rumble->state[1] = 0x00;
799 rumble->state[2] = 0x00;
800 }
801 }
802
2/2
✓ Branch 0 (8→9) taken 1 times.
✓ Branch 1 (8→33) taken 5 times.
6 else if (bt_data->reports[RUMBLE]) {
803 1 struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output;
804
805 1 rumble->report_size = 0;
806 1 uint32_t bytes_count = 0;
807 1 uint32_t tmp_value = 0;
808 1 uint32_t offset = 0;
809 1 uint32_t counter = 0;
810 1 uint32_t pwr[2];
811 1 uint32_t pwr_idx = 0;
812 1 bool is_rumble_usage = false;
813
814 1 pwr[0] = fb_data->lf_pwr;
815 1 pwr[1] = fb_data->hf_pwr;
816
817
2/2
✓ Branch 0 (31→10) taken 2 times.
✓ Branch 1 (31→32) taken 1 times.
3 for (uint32_t i = 0; i < bt_data->reports[RUMBLE]->usage_cnt; i++)
818 {
819 2 is_rumble_usage = false;
820
821
1/6
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→14) taken 2 times.
✗ Branch 2 (10→17) not taken.
✗ Branch 3 (10→20) not taken.
✗ Branch 4 (10→23) not taken.
✗ Branch 5 (10→30) not taken.
2 switch (bt_data->reports[RUMBLE]->usages[i].usage)
822 {
823 case 0x50: /* Duration */
824 bytes_count = (bt_data->reports[RUMBLE]->usages[i].bit_size + 7) / 8;
825 rumble->report_size += bytes_count;
826
827 if (fb_data->state) {
828 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_max;
829 }
830 else {
831 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_min;
832 }
833
834 is_rumble_usage = true;
835 break;
836 2 case 0x97: /* Enable Actuators */
837
1/2
✗ Branch 0 (14→15) not taken.
✓ Branch 1 (14→17) taken 2 times.
2 if (bt_data->reports[RUMBLE]->usages[i].logical_max == 1 &&
838 bt_data->reports[RUMBLE]->usages[i].bit_size == 4) {
839 bytes_count = (bt_data->reports[RUMBLE]->usages[i].bit_size + 7) / 8;
840 rumble->report_size += bytes_count;
841
842 tmp_value = 0x03;
843
844 is_rumble_usage = true;
845 break;
846 }
847 /* Fallthrough */
848 case 0x70: /* Magnitude */
849 2 bytes_count = (bt_data->reports[RUMBLE]->usages[i].bit_size + 7) / 8;
850 2 rumble->report_size += bytes_count;
851
852
1/2
✓ Branch 0 (17→18) taken 2 times.
✗ Branch 1 (17→19) not taken.
2 if (fb_data->state && pwr_idx < sizeof(pwr)/sizeof(pwr[0])) {
853 2 tmp_value = ((float)bt_data->reports[RUMBLE]->usages[i].logical_max / 255.0) * pwr[pwr_idx++];
854 }
855 else {
856 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_min;
857 }
858
859 is_rumble_usage = true;
860 break;
861 case 0x7C: /* Loop Count */
862 bytes_count = (bt_data->reports[RUMBLE]->usages[i].bit_size + 7) / 8;
863 rumble->report_size += bytes_count;
864
865 if (fb_data->state) {
866 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_max;
867 }
868 else {
869 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_min;
870 }
871
872 is_rumble_usage = true;
873 break;
874 case 0xA7: /* Start Delay */
875 bytes_count = (bt_data->reports[RUMBLE]->usages[i].bit_size + 7) / 8;
876 rumble->report_size += bytes_count;
877
878 tmp_value = bt_data->reports[RUMBLE]->usages[i].logical_min;
879
880 is_rumble_usage = true;
881 break;
882 }
883
884 2 if (is_rumble_usage) {
885 counter = 0;
886
2/2
✓ Branch 0 (26→25) taken 4 times.
✓ Branch 1 (26→27) taken 2 times.
6 while(tmp_value)
887 {
888 4 rumble->state[offset++] = tmp_value;
889 4 tmp_value >>= 8;
890 4 counter++;
891 }
892
1/2
✗ Branch 0 (29→28) not taken.
✓ Branch 1 (29→30) taken 2 times.
2 for (uint32_t refill = counter; refill < bytes_count; refill++) {
893 rumble->state[offset++] = 0;
894 }
895 }
896 2 pwr_idx &= 0x01;
897 }
898
899 1 rumble->report_id = bt_data->reports[RUMBLE]->id;
900 }
901 break;
902 }
903 6 return ret;
904 }
905
906