| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2025, Jacques Gagnon | ||
| 3 | * SPDX-License-Identifier: Apache-2.0 | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | #include <string.h> | ||
| 8 | #include "zephyr/types.h" | ||
| 9 | #include "tools/util.h" | ||
| 10 | #include "adapter/config.h" | ||
| 11 | #include "adapter/mapping_quirks.h" | ||
| 12 | #include "tests/cmds.h" | ||
| 13 | #include "bluetooth/mon.h" | ||
| 14 | #include "bluetooth/hidp/sw2.h" | ||
| 15 | #include "sw2.h" | ||
| 16 | |||
| 17 | #define SW2_AXES_MAX 4 | ||
| 18 | |||
| 19 | enum { | ||
| 20 | SW2_Y = 0, | ||
| 21 | SW2_X, | ||
| 22 | SW2_B, | ||
| 23 | SW2_A, | ||
| 24 | SW2_R_SR, | ||
| 25 | SW2_R_SL, | ||
| 26 | SW2_R, | ||
| 27 | SW2_ZR, | ||
| 28 | SW2_MINUS, | ||
| 29 | SW2_PLUS, | ||
| 30 | SW2_RJ, | ||
| 31 | SW2_LJ, | ||
| 32 | SW2_HOME, | ||
| 33 | SW2_CAPTURE, | ||
| 34 | SW2_C, | ||
| 35 | SW2_UNKNOWN, | ||
| 36 | SW2_DOWN, | ||
| 37 | SW2_UP, | ||
| 38 | SW2_RIGHT, | ||
| 39 | SW2_LEFT, | ||
| 40 | SW2_L_SR, | ||
| 41 | SW2_L_SL, | ||
| 42 | SW2_L, | ||
| 43 | SW2_ZL, | ||
| 44 | SW2_GR, | ||
| 45 | SW2_GL, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const uint8_t sw2_axes_idx[ADAPTER_MAX_AXES] = | ||
| 49 | { | ||
| 50 | /* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY, TRIG_L, TRIG_R */ | ||
| 51 | 0, 1, 2, 3, 4, 5 | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const struct ctrl_meta sw2_pro_axes_meta[ADAPTER_MAX_AXES] = | ||
| 55 | { | ||
| 56 | {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610}, | ||
| 57 | {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610}, | ||
| 58 | {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610}, | ||
| 59 | {.neutral = 0x800, .abs_max = 1610, .abs_min = 1610}, | ||
| 60 | {.neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00}, | ||
| 61 | {.neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00}, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static const struct ctrl_meta sw2_gc_axes_meta[ADAPTER_MAX_AXES] = | ||
| 65 | { | ||
| 66 | {.neutral = 0x800, .abs_max = 1225, .abs_min = 1225}, | ||
| 67 | {.neutral = 0x800, .abs_max = 1225, .abs_min = 1225}, | ||
| 68 | {.neutral = 0x800, .abs_max = 1120, .abs_min = 1120}, | ||
| 69 | {.neutral = 0x800, .abs_max = 1120, .abs_min = 1120}, | ||
| 70 | {.neutral = 30, .abs_max = 195, .abs_min = 0x00}, | ||
| 71 | {.neutral = 30, .abs_max = 195, .abs_min = 0x00}, | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct sw2_map { | ||
| 75 | uint8_t tbd[4]; | ||
| 76 | uint32_t buttons; | ||
| 77 | uint8_t tbd1[2]; | ||
| 78 | uint8_t axes[6]; | ||
| 79 | uint8_t tbd2[44]; | ||
| 80 | uint8_t triggers[2]; | ||
| 81 | uint8_t tbd3; | ||
| 82 | } __packed; | ||
| 83 | |||
| 84 | static const uint32_t sw2_pro_mask[4] = {0xFFFF1FFF, 0x00000000, 0x00000000, 0x00000000}; | ||
| 85 | static const uint32_t sw2_pro_desc[4] = {0x000000FF, 0x00000000, 0x00000000, 0x00000000}; | ||
| 86 | static const uint32_t sw2_pro_btns_mask[32] = { | ||
| 87 | 0, 0, 0, 0, | ||
| 88 | 0, 0, 0, 0, | ||
| 89 | BIT(SW2_LEFT), BIT(SW2_RIGHT), BIT(SW2_DOWN), BIT(SW2_UP), | ||
| 90 | BIT(SW2_C), 0, 0, 0, | ||
| 91 | BIT(SW2_Y), BIT(SW2_A), BIT(SW2_B), BIT(SW2_X), | ||
| 92 | BIT(SW2_PLUS), BIT(SW2_MINUS), BIT(SW2_HOME), BIT(SW2_CAPTURE), | ||
| 93 | BIT(SW2_ZL), BIT(SW2_L), BIT(SW2_GL), BIT(SW2_LJ), | ||
| 94 | BIT(SW2_ZR), BIT(SW2_R), BIT(SW2_GR), BIT(SW2_RJ), | ||
| 95 | }; | ||
| 96 | |||
| 97 | static const uint32_t sw2_gc_mask[4] = {0x77FF0FFF, 0x00000000, 0x00000000, 0x00000000}; | ||
| 98 | static const uint32_t sw2_gc_desc[4] = {0x110000FF, 0x00000000, 0x00000000, 0x00000000}; | ||
| 99 | static const uint32_t sw2_gc_btns_mask[32] = { | ||
| 100 | 0, 0, 0, 0, | ||
| 101 | 0, 0, 0, 0, | ||
| 102 | BIT(SW2_LEFT), BIT(SW2_RIGHT), BIT(SW2_DOWN), BIT(SW2_UP), | ||
| 103 | 0, 0, 0, 0, | ||
| 104 | BIT(SW2_B), BIT(SW2_X), BIT(SW2_A), BIT(SW2_Y), | ||
| 105 | BIT(SW2_PLUS), BIT(SW2_C), BIT(SW2_HOME), BIT(SW2_CAPTURE), | ||
| 106 | 0, BIT(SW2_ZL), BIT(SW2_L), 0, | ||
| 107 | 0, BIT(SW2_ZR), BIT(SW2_R), 0, | ||
| 108 | }; | ||
| 109 | |||
| 110 | ✗ | static int32_t sw2_pad_init(struct bt_data *bt_data) { | |
| 111 | ✗ | struct bt_hid_sw2_ctrl_calib *calib = NULL; | |
| 112 | ✗ | const uint8_t *axes_idx = sw2_axes_idx; | |
| 113 | ✗ | struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta; | |
| 114 | ✗ | const struct ctrl_meta *sw2_axes_meta = sw2_pro_axes_meta; | |
| 115 | |||
| 116 | ✗ | mapping_quirks_apply(bt_data); | |
| 117 | |||
| 118 | ✗ | bt_hid_sw2_get_calib(bt_data->base.pids->id, &calib); | |
| 119 | |||
| 120 | ✗ | switch (bt_data->base.pid) { | |
| 121 | case SW2_LJC_PID: | ||
| 122 | { | ||
| 123 | // memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type], | ||
| 124 | // sizeof(bt_data->raw_src_mappings[PAD].btns_mask)); | ||
| 125 | |||
| 126 | // meta[0].polarity = 1; | ||
| 127 | // meta[1].polarity = 0; | ||
| 128 | // axes_idx = sw_jc_axes_idx; | ||
| 129 | // memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask, | ||
| 130 | // sizeof(bt_data->raw_src_mappings[PAD].mask)); | ||
| 131 | // memcpy(bt_data->raw_src_mappings[PAD].desc, desc, | ||
| 132 | // sizeof(bt_data->raw_src_mappings[PAD].desc)); | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | case SW2_RJC_PID: | ||
| 136 | { | ||
| 137 | // memcpy(bt_data->raw_src_mappings[PAD].btns_mask, &sw_jc_btns_mask[report_type], | ||
| 138 | // sizeof(bt_data->raw_src_mappings[PAD].btns_mask)); | ||
| 139 | |||
| 140 | // meta[0].polarity = 0; | ||
| 141 | // meta[1].polarity = 1; | ||
| 142 | // axes_idx = sw_jc_axes_idx; | ||
| 143 | // memcpy(bt_data->raw_src_mappings[PAD].mask, sw_jc_mask, | ||
| 144 | // sizeof(bt_data->raw_src_mappings[PAD].mask)); | ||
| 145 | // memcpy(bt_data->raw_src_mappings[PAD].desc, desc, | ||
| 146 | // sizeof(bt_data->raw_src_mappings[PAD].desc)); | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | ✗ | case SW2_GC_PID: | |
| 150 | { | ||
| 151 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].btns_mask, sw2_gc_btns_mask, | |
| 152 | sizeof(bt_data->raw_src_mappings[PAD].btns_mask)); | ||
| 153 | ✗ | meta[0].polarity = 0; | |
| 154 | ✗ | meta[1].polarity = 0; | |
| 155 | ✗ | meta[2].polarity = 0; | |
| 156 | ✗ | meta[3].polarity = 0; | |
| 157 | ✗ | axes_idx = sw2_axes_idx; | |
| 158 | ✗ | sw2_axes_meta = sw2_gc_axes_meta; | |
| 159 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].mask, sw2_gc_mask, | |
| 160 | sizeof(bt_data->raw_src_mappings[PAD].mask)); | ||
| 161 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].desc, sw2_gc_desc, | |
| 162 | sizeof(bt_data->raw_src_mappings[PAD].desc)); | ||
| 163 | |||
| 164 | ✗ | meta[TRIG_L].neutral = sw2_gc_axes_meta[TRIG_L].neutral; | |
| 165 | ✗ | meta[TRIG_L].abs_max = sw2_gc_axes_meta[TRIG_L].abs_max; | |
| 166 | ✗ | meta[TRIG_L].abs_min = sw2_gc_axes_meta[TRIG_L].abs_min; | |
| 167 | ✗ | meta[TRIG_R].neutral = sw2_gc_axes_meta[TRIG_R].neutral; | |
| 168 | ✗ | meta[TRIG_R].abs_max = sw2_gc_axes_meta[TRIG_R].abs_max; | |
| 169 | ✗ | meta[TRIG_R].abs_min = sw2_gc_axes_meta[TRIG_R].abs_min; | |
| 170 | ✗ | break; | |
| 171 | } | ||
| 172 | ✗ | case SW2_PRO2_PID: | |
| 173 | default: | ||
| 174 | { | ||
| 175 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].btns_mask, sw2_pro_btns_mask, | |
| 176 | sizeof(bt_data->raw_src_mappings[PAD].btns_mask)); | ||
| 177 | ✗ | meta[0].polarity = 0; | |
| 178 | ✗ | meta[1].polarity = 0; | |
| 179 | ✗ | meta[2].polarity = 0; | |
| 180 | ✗ | meta[3].polarity = 0; | |
| 181 | ✗ | axes_idx = sw2_axes_idx; | |
| 182 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].mask, sw2_pro_mask, | |
| 183 | sizeof(bt_data->raw_src_mappings[PAD].mask)); | ||
| 184 | ✗ | memcpy(bt_data->raw_src_mappings[PAD].desc, sw2_pro_desc, | |
| 185 | sizeof(bt_data->raw_src_mappings[PAD].desc)); | ||
| 186 | ✗ | break; | |
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | ✗ | for (uint32_t i = 0; i < SW2_AXES_MAX; i++) { | |
| 191 | ✗ | if (calib && calib->sticks[i / 2].axes[i % 2].neutral) { | |
| 192 | ✗ | meta[axes_idx[i]].neutral = calib->sticks[i / 2].axes[i % 2].neutral; | |
| 193 | ✗ | meta[axes_idx[i]].abs_max = calib->sticks[i / 2].axes[i % 2].rel_max * MAX_PULL_BACK; | |
| 194 | ✗ | meta[axes_idx[i]].abs_min = calib->sticks[i / 2].axes[i % 2].rel_min * MAX_PULL_BACK; | |
| 195 | ✗ | meta[axes_idx[i]].deadzone = calib->sticks[i / 2].deadzone; | |
| 196 | ✗ | printf("# %s: controller calib loaded\n", __FUNCTION__); | |
| 197 | } | ||
| 198 | else { | ||
| 199 | ✗ | meta[axes_idx[i]].neutral = sw2_axes_meta[i].neutral; | |
| 200 | ✗ | meta[axes_idx[i]].abs_max = sw2_axes_meta[i].abs_max * MAX_PULL_BACK; | |
| 201 | ✗ | meta[axes_idx[i]].abs_min = sw2_axes_meta[i].abs_min * MAX_PULL_BACK; | |
| 202 | ✗ | meta[axes_idx[i]].deadzone = sw2_axes_meta[i].deadzone; | |
| 203 | ✗ | printf("# %s: no calib, using default\n", __FUNCTION__); | |
| 204 | } | ||
| 205 | ✗ | bt_data->base.axes_cal[i] = 0; | |
| 206 | } | ||
| 207 | |||
| 208 | ✗ | atomic_set_bit(&bt_data->base.flags[PAD], BT_INIT); | |
| 209 | ✗ | return 0; | |
| 210 | } | ||
| 211 | |||
| 212 | ✗ | static int32_t sw2_pro_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) { | |
| 213 | ✗ | struct sw2_map *map = (struct sw2_map *)bt_data->base.input; | |
| 214 | ✗ | struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta; | |
| 215 | ✗ | uint16_t axes[4]; | |
| 216 | |||
| 217 | ✗ | if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) { | |
| 218 | ✗ | if (sw2_pad_init(bt_data)) { | |
| 219 | return -1; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | ✗ | memset((void *)ctrl_data, 0, sizeof(*ctrl_data)); | |
| 224 | |||
| 225 | ✗ | ctrl_data->mask = (uint32_t *)sw2_pro_mask; | |
| 226 | ✗ | ctrl_data->desc = (uint32_t *)sw2_pro_desc; | |
| 227 | |||
| 228 | ✗ | for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) { | |
| 229 | ✗ | if (map->buttons & sw2_pro_btns_mask[i]) { | |
| 230 | ✗ | ctrl_data->btns[0].value |= generic_btns_mask[i]; | |
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | ✗ | axes[0] = map->axes[0] | ((map->axes[1] & 0xF) << 8); | |
| 235 | ✗ | axes[1] = (map->axes[1] >> 4) | (map->axes[2] << 4); | |
| 236 | ✗ | axes[2] = map->axes[3] | ((map->axes[4] & 0xF) << 8); | |
| 237 | ✗ | axes[3] = (map->axes[4] >> 4) | (map->axes[5] << 4); | |
| 238 | |||
| 239 | ✗ | TESTS_CMDS_LOG("\"wireless_input\": {\"axes\": [%u, %u, %u, %u], \"btns\": %lu},\n", | |
| 240 | axes[0], axes[1], axes[2], axes[3], map->buttons); | ||
| 241 | |||
| 242 | ✗ | for (uint32_t i = 0; i < SW2_AXES_MAX; i++) { | |
| 243 | ✗ | ctrl_data->axes[i].meta = &meta[i]; | |
| 244 | ✗ | ctrl_data->axes[i].value = axes[i] - meta[i].neutral; | |
| 245 | } | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | ✗ | static int32_t sw2_gc_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) { | |
| 250 | |||
| 251 | ✗ | struct sw2_map *map = (struct sw2_map *)bt_data->base.input; | |
| 252 | ✗ | struct ctrl_meta *meta = bt_data->raw_src_mappings[PAD].meta; | |
| 253 | ✗ | uint16_t axes[4]; | |
| 254 | |||
| 255 | ✗ | if (!atomic_test_bit(&bt_data->base.flags[PAD], BT_INIT)) { | |
| 256 | ✗ | if (sw2_pad_init(bt_data)) { | |
| 257 | return -1; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | ✗ | memset((void *)ctrl_data, 0, sizeof(*ctrl_data)); | |
| 262 | |||
| 263 | ✗ | ctrl_data->mask = (uint32_t *)sw2_gc_mask; | |
| 264 | ✗ | ctrl_data->desc = (uint32_t *)sw2_gc_desc; | |
| 265 | |||
| 266 | ✗ | for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) { | |
| 267 | ✗ | if (map->buttons & sw2_gc_btns_mask[i]) { | |
| 268 | ✗ | ctrl_data->btns[0].value |= generic_btns_mask[i]; | |
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | ✗ | axes[0] = map->axes[0] | ((map->axes[1] & 0xF) << 8); | |
| 273 | ✗ | axes[1] = (map->axes[1] >> 4) | (map->axes[2] << 4); | |
| 274 | ✗ | axes[2] = map->axes[3] | ((map->axes[4] & 0xF) << 8); | |
| 275 | ✗ | axes[3] = (map->axes[4] >> 4) | (map->axes[5] << 4); | |
| 276 | |||
| 277 | ✗ | TESTS_CMDS_LOG("\"wireless_input\": {\"axes\": [%u, %u, %u, %u], \"btns\": %lu},\n", | |
| 278 | axes[0], axes[1], axes[2], axes[3], map->buttons); | ||
| 279 | |||
| 280 | ✗ | for (uint32_t i = 0; i < SW2_AXES_MAX; i++) { | |
| 281 | ✗ | ctrl_data->axes[i].meta = &meta[i]; | |
| 282 | ✗ | ctrl_data->axes[i].value = axes[i] - meta[i].neutral; | |
| 283 | } | ||
| 284 | ✗ | for (uint32_t i = 4; i < ADAPTER_MAX_AXES; i++) { | |
| 285 | ✗ | ctrl_data->axes[i].meta = &meta[i]; | |
| 286 | ✗ | ctrl_data->axes[i].value = map->triggers[i - 4] - meta[i].neutral; | |
| 287 | } | ||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | ✗ | int32_t sw2_to_generic(struct bt_data *bt_data, struct wireless_ctrl *ctrl_data) { | |
| 292 | ✗ | switch (bt_data->base.pid) { | |
| 293 | ✗ | case SW2_LJC_PID: | |
| 294 | case SW2_RJC_PID: | ||
| 295 | case SW2_PRO2_PID: | ||
| 296 | ✗ | return sw2_pro_to_generic(bt_data, ctrl_data); | |
| 297 | ✗ | case SW2_GC_PID: | |
| 298 | ✗ | return sw2_gc_to_generic(bt_data, ctrl_data); | |
| 299 | ✗ | default: | |
| 300 | ✗ | printf("# Unknown pid : %04X\n", bt_data->base.pid); | |
| 301 | ✗ | return -1; | |
| 302 | } | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | ✗ | bool sw2_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) { | |
| 307 | ✗ | struct bt_hidp_sw2_out *out = (struct bt_hidp_sw2_out *)bt_data->base.output; | |
| 308 | ✗ | bool ret = true; | |
| 309 | |||
| 310 | ✗ | switch (bt_data->base.pid) { | |
| 311 | ✗ | case SW2_LJC_PID: | |
| 312 | case SW2_RJC_PID: | ||
| 313 | case SW2_PRO2_PID: | ||
| 314 | ✗ | switch (fb_data->type) { | |
| 315 | ✗ | case FB_TYPE_RUMBLE: | |
| 316 | ✗ | if (fb_data->hf_pwr || fb_data->lf_pwr) { | |
| 317 | ✗ | out->r_lra.ops[0].hf_freq = BT_HIDP_SW2_LRA_R_HF_FREQ; | |
| 318 | ✗ | out->r_lra.ops[0].hf_amp = (uint8_t)((float)fb_data->hf_pwr / 2.68); | |
| 319 | ✗ | out->r_lra.ops[0].lf_freq = BT_HIDP_SW2_LRA_R_LF_FREQ; | |
| 320 | ✗ | out->r_lra.ops[0].lf_amp = (uint16_t)((float)fb_data->hf_pwr / 0.3156); | |
| 321 | ✗ | out->r_lra.ops[0].enable = 1; | |
| 322 | |||
| 323 | ✗ | out->l_lra.ops[0].hf_freq = BT_HIDP_SW2_LRA_L_HF_FREQ; | |
| 324 | ✗ | out->l_lra.ops[0].hf_amp = (uint8_t)((float)fb_data->lf_pwr / 2.68); | |
| 325 | ✗ | out->l_lra.ops[0].lf_freq = BT_HIDP_SW2_LRA_L_LF_FREQ; | |
| 326 | ✗ | out->l_lra.ops[0].lf_amp = (uint16_t)((float)fb_data->lf_pwr / 0.3156); | |
| 327 | ✗ | out->l_lra.ops[0].enable = 1; | |
| 328 | } | ||
| 329 | else { | ||
| 330 | ✗ | out->l_lra.ops[0].val = BT_HIDP_SW2_LRA_IDLE_32; | |
| 331 | ✗ | out->l_lra.ops[0].hf_amp = BT_HIDP_SW2_LRA_IDLE_8; | |
| 332 | ✗ | out->r_lra.ops[0].val = BT_HIDP_SW2_LRA_IDLE_32; | |
| 333 | ✗ | out->r_lra.ops[0].hf_amp = BT_HIDP_SW2_LRA_IDLE_8; | |
| 334 | } | ||
| 335 | //printf("%08lX %02X %08lX %02X\n", out->l_lra.ops[0].val, out->l_lra.ops[0].hf_amp, out->r_lra.ops[0].val, out->r_lra.ops[0].hf_amp); | ||
| 336 | break; | ||
| 337 | ✗ | case FB_TYPE_PLAYER_LED: | |
| 338 | ✗ | bt_data->base.output[41] = bt_hid_led_dev_id_map[bt_data->base.pids->out_idx]; | |
| 339 | ✗ | break; | |
| 340 | } | ||
| 341 | break; | ||
| 342 | ✗ | case SW2_GC_PID: | |
| 343 | { | ||
| 344 | ✗ | uint8_t cur_val = bt_data->base.output[2]; | |
| 345 | ✗ | switch (fb_data->type) { | |
| 346 | ✗ | case FB_TYPE_RUMBLE: | |
| 347 | ✗ | if (fb_data->state) { | |
| 348 | ✗ | bt_data->base.output[2] = 0x01; | |
| 349 | } | ||
| 350 | else { | ||
| 351 | ✗ | bt_data->base.output[2] = 0x00; | |
| 352 | } | ||
| 353 | break; | ||
| 354 | ✗ | case FB_TYPE_PLAYER_LED: | |
| 355 | ✗ | bt_data->base.output[13] = bt_hid_led_dev_id_map[bt_data->base.pids->out_idx]; | |
| 356 | ✗ | break; | |
| 357 | } | ||
| 358 | ✗ | ret = (cur_val != bt_data->base.output[2]); | |
| 359 | ✗ | break; | |
| 360 | } | ||
| 361 | ✗ | default: | |
| 362 | ✗ | printf("# Unknown pid : %04X\n", bt_data->base.pid); | |
| 363 | } | ||
| 364 | ✗ | return ret; | |
| 365 | } | ||
| 366 |