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