GCC Code Coverage Report


Directory: main/
File: adapter/wireless/sw.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 149 154 96.8%
Functions: 5 5 100.0%
Branches: 57 61 93.4%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2019-2025, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <string.h>
7 #include "zephyr/types.h"
8 #include "tools/util.h"
9 #include "adapter/mapping_quirks.h"
10 #include "bluetooth/hidp/sw.h"
11 #include "tests/cmds.h"
12 #include "bluetooth/mon.h"
13 #include "sw.h"
14
15 #define BT_HIDP_SW_SUBCMD_SET_LED 0x30
16 #define SW_AXES_MAX 4
17
18 enum {
19 SW_PRO_B = 0,
20 SW_PRO_A,
21 SW_PRO_Y,
22 SW_PRO_X,
23 SW_PRO_L,
24 SW_PRO_R,
25 SW_PRO_ZL,
26 SW_PRO_ZR,
27 SW_PRO_MINUS,
28 SW_PRO_PLUS,
29 SW_PRO_LJ,
30 SW_PRO_RJ,
31 SW_PRO_HOME,
32 SW_PRO_CAPTURE,
33 SW_SNES_ZR = 15,
34 };
35
36 enum {
37 SW_LJC_DOWN = 0,
38 SW_LJC_RIGHT,
39 SW_LJC_LEFT,
40 SW_LJC_UP,
41 SW_LJC_SL,
42 SW_LJC_SR,
43 SW_LJC_MINUS = 8,
44 SW_LJC_LJ = 10,
45 SW_LJC_CAPTURE = 13,
46 SW_LJC_L,
47 SW_LJC_ZL,
48 };
49
50 enum {
51 SW_RJC_A = 0,
52 SW_RJC_X,
53 SW_RJC_B,
54 SW_RJC_Y,
55 SW_RJC_SL,
56 SW_RJC_SR,
57 SW_RJC_PLUS = 9,
58 SW_RJC_RJ = 11,
59 SW_RJC_HOME,
60 SW_RJC_R = 14,
61 SW_RJC_ZR,
62 };
63
64 enum {
65 SW_GEN_B = 0,
66 SW_GEN_A,
67 SW_GEN_Y,
68 SW_GEN_Z = 4,
69 SW_GEN_C,
70 SW_GEN_X,
71 SW_GEN_MODE,
72 SW_GEN_START = 9,
73 SW_GEN_HOME = 12,
74 SW_GEN_CAPTURE,
75 };
76
77 enum {
78 SW_N64_B = 0,
79 SW_N64_A,
80 SW_N64_C_UP,
81 SW_N64_C_LEFT,
82 SW_N64_L,
83 SW_N64_R,
84 SW_N64_Z,
85 SW_N64_C_DOWN,
86 SW_N64_C_RIGHT,
87 SW_N64_START,
88 SW_N64_ZR,
89 SW_N64_HOME = 12,
90 SW_N64_CAPTURE,
91 };
92
93 enum {
94 SW_N_Y = 8,
95 SW_N_X,
96 SW_N_B,
97 SW_N_A,
98 SW_N_R_SR,
99 SW_N_R_SL,
100 SW_N_R,
101 SW_N_ZR,
102 SW_N_MINUS,
103 SW_N_PLUS,
104 SW_N_RJ,
105 SW_N_LJ,
106 SW_N_HOME,
107 SW_N_CAPTURE,
108 SW_N_DOWN = 24,
109 SW_N_UP,
110 SW_N_RIGHT,
111 SW_N_LEFT,
112 SW_N_L_SR,
113 SW_N_L_SL,
114 SW_N_L,
115 SW_N_ZL,
116 };
117
118 static const uint8_t led_dev_id_map[] = {
119 0x1, 0x2, 0x4, 0x8, 0x3, 0x6, 0xC
120 };
121
122 static const uint8_t sw_axes_idx[SW_AXES_MAX] =
123 {
124 /* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY */
125 0, 1, 2, 3
126 };
127
128 static const uint8_t sw_jc_axes_idx[SW_AXES_MAX] =
129 {
130 /* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY */
131 1, 0, 3, 2
132 };
133
134 static const struct ctrl_meta sw_axes_meta[SW_AXES_MAX] =
135 {
136 {.neutral = 0x800, .abs_max = 0x578, .abs_min = 0x578},
137 {.neutral = 0x800, .abs_max = 0x578, .abs_min = 0x578},
138 {.neutral = 0x800, .abs_max = 0x578, .abs_min = 0x578},
139 {.neutral = 0x800, .abs_max = 0x578, .abs_min = 0x578},
140 };
141
142 struct sw_map {
143 uint16_t buttons;
144 uint8_t hat;
145 uint16_t axes[4];
146 } __packed;
147
148 struct sw_native_map {
149 uint8_t timer;
150 uint32_t buttons;
151 uint8_t axes[6];
152 } __packed;
153
154 static const uint32_t sw_pro_mask[4] = {0xFFFF0FFF, 0x00000000, 0x00000000, 0x00000000};
155 static const uint32_t sw_pro_desc[4] = {0x000000FF, 0x00000000, 0x00000000, 0x00000000};
156 static const uint32_t sw_legacy_mask[4] = {0xFFFF0F00, 0x00000000, 0x00000000, 0x00000000};
157 static const uint32_t sw_legacy_desc[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000000};
158 static const uint32_t sw_pro_btns_mask[2][32] = {
159 {
160 0, 0, 0, 0,
161 0, 0, 0, 0,
162 0, 0, 0, 0,
163 0, 0, 0, 0,
164 BIT(SW_PRO_Y), BIT(SW_PRO_A), BIT(SW_PRO_B), BIT(SW_PRO_X),
165 BIT(SW_PRO_PLUS), BIT(SW_PRO_MINUS), BIT(SW_PRO_HOME), BIT(SW_PRO_CAPTURE),
166 BIT(SW_PRO_ZL), BIT(SW_PRO_L), 0, BIT(SW_PRO_LJ),
167 BIT(SW_PRO_ZR) | BIT(SW_SNES_ZR), BIT(SW_PRO_R), 0, BIT(SW_PRO_RJ),
168 },
169 {
170 0, 0, 0, 0,
171 0, 0, 0, 0,
172 BIT(SW_N_LEFT), BIT(SW_N_RIGHT), BIT(SW_N_DOWN), BIT(SW_N_UP),
173 0, 0, 0, 0,
174 BIT(SW_N_Y), BIT(SW_N_A), BIT(SW_N_B), BIT(SW_N_X),
175 BIT(SW_N_PLUS), BIT(SW_N_MINUS), BIT(SW_N_HOME), BIT(SW_N_CAPTURE),
176 BIT(SW_N_ZL), BIT(SW_N_L), BIT(SW_N_L_SL) | BIT(SW_N_R_SL), BIT(SW_N_LJ),
177 BIT(SW_N_ZR), BIT(SW_N_R), BIT(SW_N_L_SR) | BIT(SW_N_R_SR), BIT(SW_N_RJ),
178 },
179 };
180
181 static const uint32_t sw_jc_mask[4] = {0x3B3F000F, 0x00000000, 0x00000000, 0x00000000};
182 static const uint32_t sw_jc_desc[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000000};
183 static const uint32_t sw_jc_native_desc[4] = {0x0000000F, 0x00000000, 0x00000000, 0x00000000};
184 static const uint32_t sw_jc_btns_mask[2][32] = {
185 {
186 0, 0, 0, 0,
187 0, 0, 0, 0,
188 0, 0, 0, 0,
189 0, 0, 0, 0,
190 BIT(SW_LJC_LEFT), BIT(SW_LJC_RIGHT), BIT(SW_LJC_DOWN), BIT(SW_LJC_UP),
191 BIT(SW_LJC_CAPTURE) | BIT(SW_RJC_PLUS), BIT(SW_LJC_MINUS) | BIT(SW_RJC_HOME), 0, 0,
192 BIT(SW_LJC_SL), BIT(SW_LJC_L) | BIT(SW_RJC_R), 0, BIT(SW_LJC_LJ) | BIT(SW_RJC_RJ),
193 BIT(SW_LJC_SR), BIT(SW_LJC_ZL) | BIT(SW_RJC_ZR), 0, 0,
194 },
195 {
196 0, 0, 0, 0,
197 0, 0, 0, 0,
198 0, 0, 0, 0,
199 0, 0, 0, 0,
200 BIT(SW_N_B) | BIT(SW_N_UP), BIT(SW_N_X) | BIT(SW_N_DOWN), BIT(SW_N_A) | BIT(SW_N_LEFT), BIT(SW_N_Y) | BIT(SW_N_RIGHT),
201 BIT(SW_N_CAPTURE) | BIT(SW_N_PLUS), BIT(SW_N_MINUS) | BIT(SW_N_HOME), 0, 0,
202 BIT(SW_N_L_SL) | BIT(SW_N_R_SL), BIT(SW_N_ZL) | BIT(SW_N_ZR), 0, BIT(SW_N_LJ) | BIT(SW_N_RJ),
203 BIT(SW_N_L_SR) | BIT(SW_N_R_SR), BIT(SW_N_L) | BIT(SW_N_R), 0, 0,
204 },
205 };
206
207 static const uint32_t sw_gen_mask[4] = {0x22FF0F00, 0x00000000, 0x00000000, 0x00000000};
208 static const uint32_t sw_gen_desc[4] = {0x0000000F, 0x00000000, 0x00000000, 0x00000000};
209 static const uint32_t sw_gen_btns_mask[2][32] = {
210 {
211 0, 0, 0, 0,
212 0, 0, 0, 0,
213 0, 0, 0, 0,
214 0, 0, 0, 0,
215 BIT(SW_GEN_A), BIT(SW_GEN_C), BIT(SW_GEN_B), BIT(SW_GEN_Y),
216 BIT(SW_GEN_START), BIT(SW_GEN_MODE), BIT(SW_GEN_HOME), BIT(SW_GEN_CAPTURE),
217 0, BIT(SW_GEN_X), 0, 0,
218 0, BIT(SW_GEN_Z), 0, 0,
219 },
220 {
221 0, 0, 0, 0,
222 0, 0, 0, 0,
223 BIT(SW_N_LEFT), BIT(SW_N_RIGHT), BIT(SW_N_DOWN), BIT(SW_N_UP),
224 0, 0, 0, 0,
225 BIT(SW_N_A), BIT(SW_N_R), BIT(SW_N_B), BIT(SW_N_Y),
226 BIT(SW_N_PLUS), BIT(SW_N_ZR), BIT(SW_N_HOME), BIT(SW_N_CAPTURE),
227 0, BIT(SW_N_X), 0, 0,
228 0, BIT(SW_N_L), 0, 0,
229 },
230 };
231
232 static const uint32_t sw_n64_mask[4] = {0x33D50FFF, 0x00000000, 0x00000000, 0x00000000};
233 static const uint32_t sw_n64_desc[4] = {0x0000000F, 0x00000000, 0x00000000, 0x00000000};
234 static const uint32_t sw_n64_btns_mask[2][32] = {
235 {
236 0, 0, 0, 0,
237 BIT(SW_N64_C_LEFT), BIT(SW_N64_C_RIGHT), BIT(SW_N64_C_DOWN), BIT(SW_N64_C_UP),
238 0, 0, 0, 0,
239 0, 0, 0, 0,
240 BIT(SW_N64_B), 0, BIT(SW_N64_A), 0,
241 BIT(SW_N64_START), 0, BIT(SW_N64_HOME), BIT(SW_N64_CAPTURE),
242 BIT(SW_N64_Z), BIT(SW_N64_L), 0, 0,
243 BIT(SW_N64_ZR), BIT(SW_N64_R), 0, 0,
244 },
245 {
246 0, 0, 0, 0,
247 BIT(SW_N_X), BIT(SW_N_MINUS), BIT(SW_N_ZR), BIT(SW_N_Y),
248 BIT(SW_N_LEFT), BIT(SW_N_RIGHT), BIT(SW_N_DOWN), BIT(SW_N_UP),
249 0, 0, 0, 0,
250 BIT(SW_N_B), 0, BIT(SW_N_A), 0,
251 BIT(SW_N_PLUS), 0, BIT(SW_N_HOME), BIT(SW_N_CAPTURE),
252 BIT(SW_N_ZL), BIT(SW_N_L), 0, 0,
253 BIT(SW_N_LJ), BIT(SW_N_R), 0, 0,
254 },
255 };
256
257 static const uint32_t sw_admiral_btns_mask[32] = {
258 0, 0, 0, 0,
259 BIT(SW_PRO_MINUS), BIT(SW_PRO_RJ), BIT(SW_PRO_CAPTURE), BIT(SW_PRO_HOME),
260 0, 0, 0, 0,
261 0, 0, 0, 0,
262 BIT(SW_PRO_B), 0, BIT(SW_PRO_A), 0,
263 BIT(SW_PRO_PLUS), 0, 0, 0,
264 BIT(SW_LJC_L), BIT(SW_PRO_L), 0, 0,
265 0, BIT(SW_PRO_R), 0, 0,
266 };
267
268 static const uint32_t sw_brawler64_btns_mask[32] = {
269 0, 0, 0, 0,
270 BIT(SW_PRO_X), BIT(SW_PRO_LJ), BIT(SW_PRO_Y), BIT(SW_PRO_RJ),
271 0, 0, 0, 0,
272 0, 0, 0, 0,
273 BIT(SW_PRO_A), 0, BIT(SW_PRO_B), 0,
274 BIT(SW_PRO_PLUS), BIT(SW_PRO_MINUS), BIT(SW_PRO_HOME), BIT(SW_PRO_CAPTURE),
275 BIT(SW_PRO_ZL), BIT(SW_PRO_L), 0, 0,
276 BIT(SW_PRO_ZR), BIT(SW_PRO_R), 0, 0,
277 };
278
279 42 static int32_t sw_pad_init(struct bt_data *bt_data) {
280 42 struct bt_hid_sw_ctrl_calib *calib = NULL;
281 42 const uint8_t *axes_idx = sw_axes_idx;
282 42 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
283 42 uint8_t report_type = (bt_data->base.report_id == 0x30) ? 1 : 0;
284
285 42 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_pro_btns_mask[report_type],
286 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
287
288 42 mapping_quirks_apply(bt_data);
289
290 42 bt_hid_sw_get_calib(bt_data->base.pids->id, &calib);
291
292
2/2
✓ Branch 0 (5→6) taken 4 times.
✓ Branch 1 (5→12) taken 38 times.
42 if (bt_data->base.pids->subtype == BT_SW_LEFT_JOYCON) {
293
2/2
✓ Branch 0 (6→7) taken 1 times.
✓ Branch 1 (6→8) taken 3 times.
4 const uint32_t *desc = (report_type) ? sw_jc_native_desc : sw_jc_desc;
294 4 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type],
295 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
296
297 4 meta[0].polarity = 1;
298 4 meta[1].polarity = 0;
299 4 axes_idx = sw_jc_axes_idx;
300 4 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask,
301 sizeof(bt_data->raw_src_mappings[PAD].mask));
302 4 memcpy(bt_data->raw_src_mappings[PAD].desc, desc,
303 sizeof(bt_data->raw_src_mappings[PAD].desc));
304 }
305
2/2
✓ Branch 0 (12→13) taken 4 times.
✓ Branch 1 (12→18) taken 34 times.
38 else if (bt_data->base.pids->subtype == BT_SW_RIGHT_JOYCON) {
306
2/2
✓ Branch 0 (13→14) taken 1 times.
✓ Branch 1 (13→15) taken 3 times.
4 const uint32_t *desc = (report_type) ? sw_jc_native_desc : sw_jc_desc;
307 4 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type],
308 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
309
310 4 meta[0].polarity = 0;
311 4 meta[1].polarity = 1;
312 4 axes_idx = sw_jc_axes_idx;
313 4 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask,
314 sizeof(bt_data->raw_src_mappings[PAD].mask));
315 4 memcpy(bt_data->raw_src_mappings[PAD].desc, desc,
316 sizeof(bt_data->raw_src_mappings[PAD].desc));
317 }
318
2/2
✓ Branch 0 (18→19) taken 12 times.
✓ Branch 1 (18→22) taken 22 times.
34 else if (bt_data->base.pids->subtype == BT_SUBTYPE_DEFAULT) {
319 12 meta[0].polarity = 0;
320 12 meta[1].polarity = 0;
321 12 meta[2].polarity = 0;
322 12 meta[3].polarity = 0;
323 12 axes_idx = sw_axes_idx;
324 12 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_pro_mask,
325 sizeof(bt_data->raw_src_mappings[PAD].mask));
326 12 memcpy(bt_data->raw_src_mappings[PAD].desc, sw_pro_desc,
327 sizeof(bt_data->raw_src_mappings[PAD].desc));
328 }
329
2/2
✓ Branch 0 (22→23) taken 2 times.
✓ Branch 1 (22→26) taken 20 times.
22 else if (bt_data->base.pids->subtype == BT_SW_MD_GEN) {
330 2 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_gen_btns_mask[report_type],
331 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
332
333 2 meta[0].polarity = 0;
334 2 meta[1].polarity = 0;
335 2 axes_idx = sw_axes_idx;
336 2 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_gen_mask,
337 sizeof(bt_data->raw_src_mappings[PAD].mask));
338 2 memcpy(bt_data->raw_src_mappings[PAD].desc, sw_gen_desc,
339 sizeof(bt_data->raw_src_mappings[PAD].desc));
340 }
341
2/2
✓ Branch 0 (26→27) taken 8 times.
✓ Branch 1 (26→33) taken 12 times.
20 else if (bt_data->base.pids->subtype == BT_SW_N64) {
342
4/4
✓ Branch 0 (27→28) taken 5 times.
✓ Branch 1 (27→30) taken 3 times.
✓ Branch 2 (28→29) taken 2 times.
✓ Branch 3 (28→30) taken 3 times.
8 if (bt_data->base.report_id == 0x3F && calib == NULL) {
343 /* RF Brawler64 HID mapping is wrong, if no calib data provided */
344 /* while using the N64 name we assume it's the RF Brawler64 */
345 2 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_brawler64_btns_mask,
346 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
347 }
348 else {
349 6 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_n64_btns_mask[report_type],
350 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
351 }
352
353 8 meta[0].polarity = 0;
354 8 meta[1].polarity = 0;
355 8 axes_idx = sw_axes_idx;
356 8 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_n64_mask,
357 sizeof(bt_data->raw_src_mappings[PAD].mask));
358 8 memcpy(bt_data->raw_src_mappings[PAD].desc, sw_n64_desc,
359 sizeof(bt_data->raw_src_mappings[PAD].desc));
360 }
361
2/2
✓ Branch 0 (33→34) taken 2 times.
✓ Branch 1 (33→37) taken 10 times.
12 else if (bt_data->base.pids->subtype == BT_SW_HYPERKIN_ADMIRAL) {
362 2 memcpy(bt_data->raw_src_mappings[PAD].btns_mask, sw_admiral_btns_mask,
363 sizeof(bt_data->raw_src_mappings[PAD].btns_mask));
364
365 2 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_n64_mask,
366 sizeof(bt_data->raw_src_mappings[PAD].mask));
367 2 memcpy(bt_data->raw_src_mappings[PAD].desc, sw_n64_desc,
368 sizeof(bt_data->raw_src_mappings[PAD].desc));
369 }
370 else {
371 10 meta[0].polarity = 0;
372 10 meta[1].polarity = 0;
373 10 axes_idx = sw_axes_idx;
374 10 memcpy(bt_data->raw_src_mappings[PAD].mask, sw_legacy_mask,
375 sizeof(bt_data->raw_src_mappings[PAD].mask));
376 10 memcpy(bt_data->raw_src_mappings[PAD].desc, sw_legacy_desc,
377 sizeof(bt_data->raw_src_mappings[PAD].desc));
378 }
379
380
2/2
✓ Branch 0 (45→40) taken 168 times.
✓ Branch 1 (45→46) taken 42 times.
210 for (uint32_t i = 0; i < SW_AXES_MAX; i++) {
381
4/4
✓ Branch 0 (40→41) taken 40 times.
✓ Branch 1 (40→43) taken 128 times.
✓ Branch 2 (41→42) taken 16 times.
✓ Branch 3 (41→43) taken 24 times.
168 if (calib && calib->sticks[i / 2].axes[i % 2].neutral) {
382 16 meta[axes_idx[i]].neutral = calib->sticks[i / 2].axes[i % 2].neutral;
383 16 meta[axes_idx[i]].abs_max = calib->sticks[i / 2].axes[i % 2].rel_max * MAX_PULL_BACK;
384 16 meta[axes_idx[i]].abs_min = calib->sticks[i / 2].axes[i % 2].rel_min * MAX_PULL_BACK;
385 16 meta[axes_idx[i]].deadzone = calib->sticks[i / 2].deadzone;
386 16 printf("# %s: controller calib loaded\n", __FUNCTION__);
387 }
388 else {
389 152 meta[axes_idx[i]].neutral = sw_axes_meta[i].neutral;
390 152 meta[axes_idx[i]].abs_max = sw_axes_meta[i].abs_max * MAX_PULL_BACK;
391 152 meta[axes_idx[i]].abs_min = sw_axes_meta[i].abs_min * MAX_PULL_BACK;
392 152 meta[axes_idx[i]].deadzone = sw_axes_meta[i].deadzone;
393 152 printf("# %s: no calib, using default\n", __FUNCTION__);
394 }
395 168 bt_data->base.axes_cal[i] = 0;
396 }
397
398 42 atomic_set_bit(&bt_data->base.flags[PAD], BT_INIT);
399 42 return 0;
400 }
401
402 239 static int32_t sw_native_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
403 239 struct sw_native_map *map = (struct sw_native_map *)bt_data->base.input;
404 239 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
405 239 uint16_t axes[4];
406
407
2/2
✓ Branch 0 (3→4) taken 21 times.
✓ Branch 1 (3→5) taken 218 times.
239 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
408 21 if (sw_pad_init(bt_data)) {
409 return -1;
410 }
411 }
412
413 239 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
414
415 239 ctrl_data->mask = (uint32_t *)bt_data->raw_src_mappings[PAD].mask;
416 239 ctrl_data->desc = (uint32_t *)bt_data->raw_src_mappings[PAD].desc;
417
418
2/2
✓ Branch 0 (10→7) taken 7648 times.
✓ Branch 1 (10→11) taken 239 times.
7887 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
419
2/2
✓ Branch 0 (7→8) taken 294 times.
✓ Branch 1 (7→9) taken 7354 times.
7648 if (map->buttons & bt_data->raw_src_mappings[PAD].btns_mask[i]) {
420 294 ctrl_data->btns[0].value |= generic_btns_mask[i];
421 }
422 }
423
424
2/2
✓ Branch 0 (11→12) taken 27 times.
✓ Branch 1 (11→13) taken 212 times.
239 if (bt_data->base.pids->subtype == BT_SW_LEFT_JOYCON) {
425 27 axes[1] = map->axes[0] | ((map->axes[1] & 0xF) << 8);
426 27 axes[0] = (map->axes[1] >> 4) | (map->axes[2] << 4);
427 27 axes[3] = map->axes[3] | ((map->axes[4] & 0xF) << 8);
428 27 axes[2] = (map->axes[4] >> 4) | (map->axes[5] << 4);
429 }
430
2/2
✓ Branch 0 (13→14) taken 27 times.
✓ Branch 1 (13→15) taken 185 times.
212 else if (bt_data->base.pids->subtype == BT_SW_RIGHT_JOYCON) {
431 27 axes[3] = map->axes[0] | ((map->axes[1] & 0xF) << 8);
432 27 axes[2] = (map->axes[1] >> 4) | (map->axes[2] << 4);
433 27 axes[1] = map->axes[3] | ((map->axes[4] & 0xF) << 8);
434 27 axes[0] = (map->axes[4] >> 4) | (map->axes[5] << 4);
435 }
436 else {
437 185 axes[0] = map->axes[0] | ((map->axes[1] & 0xF) << 8);
438 185 axes[1] = (map->axes[1] >> 4) | (map->axes[2] << 4);
439 185 axes[2] = map->axes[3] | ((map->axes[4] & 0xF) << 8);
440 185 axes[3] = (map->axes[4] >> 4) | (map->axes[5] << 4);
441 }
442
443 239 TESTS_CMDS_LOG("\"wireless_input\": {\"axes\": [%u, %u, %u, %u], \"btns\": %lu},\n",
444 axes[0], axes[1], axes[2], axes[3], map->buttons);
445
446
2/2
✓ Branch 0 (19→18) taken 956 times.
✓ Branch 1 (19→20) taken 239 times.
1195 for (uint32_t i = 0; i < SW_AXES_MAX; i++) {
447 956 ctrl_data->axes[i].meta = &meta[i];
448 956 ctrl_data->axes[i].value = axes[i] - meta[i].neutral;
449 }
450 return 0;
451 }
452
453 421 static int32_t sw_hid_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
454 421 struct sw_map *map = (struct sw_map *)bt_data->base.input;
455 421 struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta;
456
457 421 TESTS_CMDS_LOG("\"wireless_input\": {\"report_id\": %ld, \"axes\": [%u, %u, %u, %u], \"btns\": %u, \"hat\": %u},\n",
458 bt_data->base.report_id, map->axes[sw_axes_idx[0]], map->axes[sw_axes_idx[1]],
459 map->axes[sw_axes_idx[2]], map->axes[sw_axes_idx[3]], map->buttons, map->hat);
460
461
2/2
✓ Branch 0 (4→5) taken 21 times.
✓ Branch 1 (4→6) taken 400 times.
421 if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) {
462 21 if (sw_pad_init(bt_data)) {
463 return -1;
464 }
465 }
466
467 421 memset((void *)ctrl_data, 0, sizeof(*ctrl_data));
468
469 421 ctrl_data->mask = (uint32_t *)bt_data->raw_src_mappings[PAD].mask;
470 421 ctrl_data->desc = (uint32_t *)bt_data->raw_src_mappings[PAD].desc;
471
472
2/2
✓ Branch 0 (11→8) taken 13472 times.
✓ Branch 1 (11→12) taken 421 times.
13893 for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) {
473
2/2
✓ Branch 0 (8→9) taken 262 times.
✓ Branch 1 (8→10) taken 13210 times.
13472 if (map->buttons & bt_data->raw_src_mappings[PAD].btns_mask[i]) {
474 262 ctrl_data->btns[0].value |= generic_btns_mask[i];
475 }
476 }
477
478
2/2
✓ Branch 0 (12→13) taken 58 times.
✓ Branch 1 (12→14) taken 363 times.
421 if (bt_data->base.pids->subtype == BT_SW_LEFT_JOYCON || bt_data->base.pids->subtype == BT_SW_RIGHT_JOYCON) {
479 58 uint32_t hat = hat_to_ld_btns[map->hat & 0xF];
480 58 ctrl_data->btns[0].value |= hat >> 8;
481 }
482 else {
483 /* Convert hat to regular btns */
484
2/2
✓ Branch 0 (14→15) taken 35 times.
✓ Branch 1 (14→17) taken 328 times.
363 if (bt_data->base.pids->subtype == BT_SW_HYPERKIN_ADMIRAL) {
485 35 ctrl_data->btns[0].value |= hat_to_ld_btns[(map->hat - 1) & 0xF];
486 }
487 else {
488 328 ctrl_data->btns[0].value |= hat_to_ld_btns[map->hat & 0xF];
489 }
490
491
2/2
✓ Branch 0 (22→18) taken 1452 times.
✓ Branch 1 (22→23) taken 363 times.
1815 for (uint32_t i = 0; i < SW_AXES_MAX; i++) {
492 1452 ctrl_data->axes[i].meta = &meta[i];
493
2/2
✓ Branch 0 (18→19) taken 726 times.
✓ Branch 1 (18→20) taken 726 times.
1452 if (i & 0x1) {
494 726 ctrl_data->axes[i].value = (~(map->axes[sw_axes_idx[i]] >> 4) & 0xFFF) + 1 - meta[i].neutral;
495 }
496 else {
497 726 ctrl_data->axes[i].value = (map->axes[sw_axes_idx[i]] >> 4) - meta[i].neutral;
498 }
499 }
500 }
501 421 return 0;
502 }
503
504 660 int32_t sw_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) {
505
2/2
✓ Branch 0 (2→3) taken 239 times.
✓ Branch 1 (2→4) taken 421 times.
660 if (bt_data->base.report_id == 0x30) {
506 239 return sw_native_to_generic(bt_data, ctrl_data);
507 }
508
1/2
✓ Branch 0 (4→5) taken 421 times.
✗ Branch 1 (4→6) not taken.
421 else if (bt_data->base.report_id == 0x3F) {
509 421 return sw_hid_to_generic(bt_data, ctrl_data);
510 }
511 return -1;
512 }
513
514 11 bool sw_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) {
515 11 struct bt_hidp_sw_conf *set_conf = (struct bt_hidp_sw_conf *)bt_data->base.output;
516 11 bool ret = true;
517 /* 8bitdo wont rumble w/ set_conf so we need keep track of fb_type somehow */
518 11 bt_data->base.output[127] = fb_data->type;
519
520
1/3
✓ Branch 0 (2→3) taken 11 times.
✗ Branch 1 (2→6) not taken.
✗ Branch 2 (2→7) not taken.
11 switch (fb_data->type) {
521 11 case FB_TYPE_RUMBLE:
522
1/2
✓ Branch 0 (3→4) taken 11 times.
✗ Branch 1 (3→5) not taken.
11 if (fb_data->state) {
523 11 set_conf->r_lra.hf.freq = BT_HIDP_SW_LRA_R_HF_FREQ;
524 11 set_conf->r_lra.hf.amp = (uint8_t)((float)fb_data->hf_pwr / 2.55);
525 11 set_conf->r_lra.lf.freq = BT_HIDP_SW_LRA_R_LF_FREQ;
526 11 set_conf->r_lra.lf.amp = (uint8_t)((float)fb_data->hf_pwr / 2.55);
527 11 set_conf->r_lra.lf.tbd1 = 1;
528
529 11 set_conf->l_lra.hf.freq = BT_HIDP_SW_LRA_L_HF_FREQ;
530 11 set_conf->l_lra.hf.amp = (uint8_t)((float)fb_data->lf_pwr / 2.55);
531 11 set_conf->l_lra.lf.freq = BT_HIDP_SW_LRA_L_LF_FREQ;
532 11 set_conf->l_lra.lf.amp = (uint8_t)((float)fb_data->lf_pwr / 2.55);
533 11 set_conf->l_lra.lf.tbd1 = 1;
534 }
535 else {
536 set_conf->l_lra.val = BT_HIDP_SW_LRA_IDLE;
537 set_conf->r_lra.val = BT_HIDP_SW_LRA_IDLE;
538 }
539 break;
540 case FB_TYPE_PLAYER_LED:
541 set_conf->subcmd_data[0] = led_dev_id_map[bt_data->base.pids->out_idx];
542 break;
543 }
544 11 return ret;
545 }
546
547