| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2019-2024, Jacques Gagnon | ||
| 3 | * SPDX-License-Identifier: Apache-2.0 | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <stdio.h> | ||
| 7 | #include "bluetooth/host.h" | ||
| 8 | #include "wii.h" | ||
| 9 | |||
| 10 | enum { | ||
| 11 | WII_EXT_STATE_SET_INIT0 = 0, | ||
| 12 | WII_EXT_STATE_SET_INIT1, | ||
| 13 | WII_EXT_STATE_GET_TYPE, | ||
| 14 | WII_EXT_STATE_SET_8BIT, | ||
| 15 | WII_EXT_STATE_GET_8BIT, | ||
| 16 | }; | ||
| 17 | |||
| 18 | struct bt_wii_ext_type { | ||
| 19 | uint8_t ext_type[6]; | ||
| 20 | uint32_t subtype; | ||
| 21 | }; | ||
| 22 | |||
| 23 | static const struct bt_hidp_wii_rep_mode wii_rep_conf = { | ||
| 24 | BT_HIDP_WII_CONTINUOUS, | ||
| 25 | BT_HIDP_WII_CORE_ACC_EXT, | ||
| 26 | }; | ||
| 27 | |||
| 28 | static const struct bt_hidp_wii_wr_mem wii_ext_init0 = { | ||
| 29 | BT_HIDP_WII_REG, | ||
| 30 | {0xA4, 0x00, 0xF0}, | ||
| 31 | 0x01, | ||
| 32 | {0x55}, | ||
| 33 | }; | ||
| 34 | |||
| 35 | static const struct bt_hidp_wii_wr_mem wii_ext_init1 = { | ||
| 36 | BT_HIDP_WII_REG, | ||
| 37 | {0xA4, 0x00, 0xFB}, | ||
| 38 | 0x01, | ||
| 39 | {0x00}, | ||
| 40 | }; | ||
| 41 | |||
| 42 | static const struct bt_hidp_wii_wr_mem wii_ext_8bit = { | ||
| 43 | BT_HIDP_WII_REG, | ||
| 44 | {0xA4, 0x00, 0xFE}, | ||
| 45 | 0x01, | ||
| 46 | {0x03}, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static const struct bt_hidp_wii_rd_mem wii_ext_type = { | ||
| 50 | BT_HIDP_WII_REG, | ||
| 51 | {0xA4, 0x00, 0xFA}, | ||
| 52 | 0x0600, | ||
| 53 | }; | ||
| 54 | |||
| 55 | static const struct bt_wii_ext_type bt_wii_ext_type[] = { | ||
| 56 | {{0x00, 0x00, 0xA4, 0x20, 0x00, 0x00}, BT_WII_NUNCHUCK}, | ||
| 57 | {{0x00, 0x00, 0xA4, 0x20, 0x01, 0x01}, BT_WII_CLASSIC}, | ||
| 58 | {{0x01, 0x00, 0xA4, 0x20, 0x01, 0x01}, BT_WII_CLASSIC_PRO}, | ||
| 59 | {{0x00, 0x00, 0xA4, 0x20, 0x03, 0x01}, BT_WII_CLASSIC_8BIT}, | ||
| 60 | {{0x01, 0x00, 0xA4, 0x20, 0x03, 0x01}, BT_WII_CLASSIC_PRO_8BIT}, | ||
| 61 | {{0x00, 0x00, 0xA4, 0x20, 0x01, 0x20}, BT_WIIU_PRO}, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static uint32_t bt_get_subtype_from_wii_ext(const uint8_t* ext_type); | ||
| 65 | static void bt_hid_cmd_wii_set_rep_mode(struct bt_dev *device, void *report); | ||
| 66 | static void bt_hid_cmd_wii_read(struct bt_dev *device, void *report); | ||
| 67 | static void bt_hid_cmd_wii_write(struct bt_dev *device, void *report); | ||
| 68 | |||
| 69 | 10 | static uint32_t bt_get_subtype_from_wii_ext(const uint8_t* ext_type) { | |
| 70 |
1/2✓ Branch 0 (6→3) taken 30 times.
✗ Branch 1 (6→7) not taken.
|
30 | for (uint32_t i = 0; i < sizeof(bt_wii_ext_type)/sizeof(*bt_wii_ext_type); i++) { |
| 71 |
2/2✓ Branch 0 (3→4) taken 10 times.
✓ Branch 1 (3→5) taken 20 times.
|
30 | if (memcmp(ext_type, bt_wii_ext_type[i].ext_type, sizeof(bt_wii_ext_type[0].ext_type)) == 0) { |
| 72 | 10 | return bt_wii_ext_type[i].subtype; | |
| 73 | } | ||
| 74 | } | ||
| 75 | return BT_SUBTYPE_DEFAULT; | ||
| 76 | } | ||
| 77 | |||
| 78 | 4 | static void bt_wii_exec_next_state(struct bt_dev *device) { | |
| 79 |
1/6✗ Branch 0 (2→3) not taken.
✗ Branch 1 (2→5) not taken.
✗ Branch 2 (2→7) not taken.
✓ Branch 3 (2→9) taken 4 times.
✗ Branch 4 (2→11) not taken.
✗ Branch 5 (2→13) not taken.
|
4 | switch(device->hid_state) { |
| 80 | ✗ | case WII_EXT_STATE_SET_INIT0: | |
| 81 | ✗ | bt_hid_cmd_wii_write(device, (void *)&wii_ext_init0); | |
| 82 | ✗ | break; | |
| 83 | ✗ | case WII_EXT_STATE_SET_INIT1: | |
| 84 | ✗ | bt_hid_cmd_wii_write(device, (void *)&wii_ext_init1); | |
| 85 | ✗ | break; | |
| 86 | ✗ | case WII_EXT_STATE_GET_TYPE: | |
| 87 | ✗ | bt_hid_cmd_wii_read(device, (void *)&wii_ext_type); | |
| 88 | ✗ | break; | |
| 89 | 4 | case WII_EXT_STATE_SET_8BIT: | |
| 90 | 4 | bt_hid_cmd_wii_write(device, (void *)&wii_ext_8bit); | |
| 91 | 4 | break; | |
| 92 | ✗ | case WII_EXT_STATE_GET_8BIT: | |
| 93 | ✗ | bt_hid_cmd_wii_read(device, (void *)&wii_ext_type); | |
| 94 | ✗ | break; | |
| 95 | default: | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | 4 | } | |
| 99 | |||
| 100 | 19 | static void bt_hid_cmd_wii_set_rep_mode(struct bt_dev *device, void *report) { | |
| 101 | 19 | struct bt_hidp_wii_rep_mode *wii_rep_mode = (struct bt_hidp_wii_rep_mode *)bt_hci_pkt_tmp.hidp_data; | |
| 102 | 19 | printf("# %s\n", __FUNCTION__); | |
| 103 | |||
| 104 | 19 | memcpy((void *)wii_rep_mode, report, sizeof(*wii_rep_mode)); | |
| 105 | |||
| 106 | 19 | bt_hid_cmd(device->acl_handle, device->intr_chan.dcid, BT_HIDP_DATA_OUT, BT_HIDP_WII_REP_MODE, sizeof(*wii_rep_mode)); | |
| 107 | 19 | } | |
| 108 | |||
| 109 | ✗ | static void bt_hid_cmd_wii_read(struct bt_dev *device, void *report) { | |
| 110 | ✗ | struct bt_hidp_wii_rd_mem *wii_rd_mem = (struct bt_hidp_wii_rd_mem *)bt_hci_pkt_tmp.hidp_data; | |
| 111 | ✗ | printf("# %s\n", __FUNCTION__); | |
| 112 | |||
| 113 | ✗ | memcpy((void *)wii_rd_mem, report, sizeof(*wii_rd_mem)); | |
| 114 | |||
| 115 | ✗ | bt_hid_cmd(device->acl_handle, device->intr_chan.dcid, BT_HIDP_DATA_OUT, BT_HIDP_WII_RD_MEM, sizeof(*wii_rd_mem)); | |
| 116 | ✗ | } | |
| 117 | |||
| 118 | 4 | static void bt_hid_cmd_wii_write(struct bt_dev *device, void *report) { | |
| 119 | 4 | struct bt_hidp_wii_wr_mem *wii_wr_mem = (struct bt_hidp_wii_wr_mem *)bt_hci_pkt_tmp.hidp_data; | |
| 120 | 4 | printf("# %s\n", __FUNCTION__); | |
| 121 | |||
| 122 | 4 | memcpy((void *)wii_wr_mem, report, sizeof(*wii_wr_mem)); | |
| 123 | |||
| 124 | 4 | bt_hid_cmd(device->acl_handle, device->intr_chan.dcid, BT_HIDP_DATA_OUT, BT_HIDP_WII_WR_MEM, sizeof(*wii_wr_mem)); | |
| 125 | 4 | } | |
| 126 | |||
| 127 | 20 | void bt_hid_cmd_wii_set_feedback(struct bt_dev *device, void *report) { | |
| 128 | 20 | struct bt_hidp_wii_conf *wii_conf = (struct bt_hidp_wii_conf *)bt_hci_pkt_tmp.hidp_data; | |
| 129 | //printf("# %s\n", __FUNCTION__); | ||
| 130 | |||
| 131 | 20 | memcpy((void *)wii_conf, report, sizeof(*wii_conf)); | |
| 132 | |||
| 133 | 20 | bt_hid_cmd(device->acl_handle, device->intr_chan.dcid, BT_HIDP_DATA_OUT, BT_HIDP_WII_LED_REPORT, sizeof(*wii_conf)); | |
| 134 | 20 | } | |
| 135 | |||
| 136 | 13 | void bt_hid_wii_init(struct bt_dev *device) { | |
| 137 | 13 | struct bt_data *bt_data = &bt_adapter.data[device->ids.id]; | |
| 138 | 13 | struct bt_hidp_wii_conf *set_conf = (struct bt_hidp_wii_conf *)bt_data->base.output; | |
| 139 | 13 | set_conf->conf = bt_hid_led_dev_id_map[device->ids.out_idx] << 4; | |
| 140 | |||
| 141 | 13 | struct bt_hidp_wii_conf wii_conf = {.conf = (bt_hid_led_dev_id_map[device->ids.out_idx] << 4)}; | |
| 142 | 13 | printf("# %s\n", __FUNCTION__); | |
| 143 | |||
| 144 | 13 | bt_hid_cmd_wii_set_feedback(device, (void *)&wii_conf); | |
| 145 | 13 | bt_hid_cmd_wii_set_rep_mode(device, (void *)&wii_rep_conf); | |
| 146 | |||
| 147 | 13 | atomic_set_bit(&device->flags, BT_DEV_HID_INIT_DONE); | |
| 148 | 13 | } | |
| 149 | |||
| 150 | 225 | void bt_hid_wii_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt, uint32_t len) { | |
| 151 | 225 | uint32_t hidp_data_len = len - (BT_HCI_H4_HDR_SIZE + BT_HCI_ACL_HDR_SIZE | |
| 152 | + sizeof(struct bt_l2cap_hdr) + sizeof(struct bt_hidp_hdr)); | ||
| 153 | |||
| 154 |
1/2✓ Branch 0 (2→3) taken 225 times.
✗ Branch 1 (2→27) not taken.
|
225 | switch (bt_hci_acl_pkt->sig_hdr.code) { |
| 155 | 225 | case BT_HIDP_DATA_IN: | |
| 156 |
2/5✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→10) taken 10 times.
✗ Branch 2 (3→18) not taken.
✓ Branch 3 (3→25) taken 215 times.
✗ Branch 4 (3→27) not taken.
|
225 | switch (bt_hci_acl_pkt->hidp_hdr.protocol) { |
| 157 | ✗ | case BT_HIDP_WII_STATUS: | |
| 158 | { | ||
| 159 | ✗ | struct bt_hidp_wii_status *status = (struct bt_hidp_wii_status *)bt_hci_acl_pkt->hidp_data; | |
| 160 | ✗ | printf("# BT_HIDP_WII_STATUS\n"); | |
| 161 | ✗ | if (device->ids.subtype != BT_WIIU_PRO) { | |
| 162 | ✗ | bt_type_update(device->ids.id, BT_WII, BT_SUBTYPE_DEFAULT); | |
| 163 | ✗ | if (status->flags & BT_HIDP_WII_FLAGS_EXT_CONN) { | |
| 164 | ✗ | device->hid_state = WII_EXT_STATE_SET_INIT0; | |
| 165 | ✗ | bt_hid_cmd_wii_write(device, (void *)&wii_ext_init0); | |
| 166 | } | ||
| 167 | else { | ||
| 168 | ✗ | bt_hid_cmd_wii_set_rep_mode(device, (void *)&wii_rep_conf); | |
| 169 | } | ||
| 170 | } | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | 10 | case BT_HIDP_WII_RD_DATA: | |
| 174 | { | ||
| 175 | 10 | struct bt_hidp_wii_rd_data *rd_data = (struct bt_hidp_wii_rd_data *)bt_hci_acl_pkt->hidp_data; | |
| 176 | 10 | uint32_t subtype = bt_get_subtype_from_wii_ext(rd_data->data); | |
| 177 | 10 | printf("# BT_HIDP_WII_RD_DATA\n"); | |
| 178 |
1/2✓ Branch 0 (11→12) taken 10 times.
✗ Branch 1 (11→13) not taken.
|
10 | if (subtype > BT_SUBTYPE_DEFAULT) { |
| 179 | 10 | bt_type_update(device->ids.id, BT_WII, subtype); | |
| 180 | } | ||
| 181 | 10 | printf("# dev: %ld wii ext: %ld\n", device->ids.id, device->ids.subtype); | |
| 182 | |||
| 183 | #ifndef CONFIG_BLUERETRO_TEST_FALLBACK_REPORT | ||
| 184 |
3/4✓ Branch 0 (14→15) taken 4 times.
✓ Branch 1 (14→17) taken 6 times.
✓ Branch 2 (15→16) taken 4 times.
✗ Branch 3 (15→17) not taken.
|
10 | if ((subtype == BT_WII_CLASSIC || subtype == BT_WII_CLASSIC_PRO) && device->hid_state < WII_EXT_STATE_SET_8BIT) { |
| 185 | 4 | device->hid_state = WII_EXT_STATE_SET_8BIT; | |
| 186 | 4 | bt_wii_exec_next_state(device); | |
| 187 | } | ||
| 188 | else | ||
| 189 | #endif | ||
| 190 | { | ||
| 191 | 6 | bt_hid_cmd_wii_set_rep_mode(device, (void *)&wii_rep_conf); | |
| 192 | } | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | ✗ | case BT_HIDP_WII_ACK: | |
| 196 | { | ||
| 197 | ✗ | struct bt_hidp_wii_ack *ack = (struct bt_hidp_wii_ack *)bt_hci_acl_pkt->hidp_data; | |
| 198 | ✗ | printf("# BT_HIDP_WII_ACK\n"); | |
| 199 | ✗ | if (ack->err) { | |
| 200 | ✗ | printf("# dev: %ld ack err: 0x%02X\n", device->ids.id, ack->err); | |
| 201 | ✗ | bt_wii_exec_next_state(device); | |
| 202 | } | ||
| 203 | else { | ||
| 204 | ✗ | device->hid_state++; | |
| 205 | ✗ | switch(ack->report) { | |
| 206 | ✗ | case BT_HIDP_WII_WR_MEM: | |
| 207 | ✗ | bt_wii_exec_next_state(device); | |
| 208 | ✗ | break; | |
| 209 | } | ||
| 210 | } | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | 215 | case BT_HIDP_WII_CORE_ACC_EXT: | |
| 214 | { | ||
| 215 | 215 | bt_host_bridge(device, bt_hci_acl_pkt->hidp_hdr.protocol, bt_hci_acl_pkt->hidp_data, hidp_data_len); | |
| 216 | 215 | break; | |
| 217 | } | ||
| 218 | } | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | 225 | } | |
| 222 |