From 5f9608f807ac55af455f5f8056950ce7ac714327 Mon Sep 17 00:00:00 2001 From: Jacques Gagnon Date: Sat, 5 Oct 2024 23:45:43 -0400 Subject: [PATCH] [BT] Add support for 8bitdo GC Modkit --- main/adapter/adapter.h | 1 + main/adapter/mapping_quirks.c | 19 ++++ main/adapter/wireless/hid_generic.c | 161 +++++++++++++++------------- main/bluetooth/hidp/hidp.c | 1 + 4 files changed, 109 insertions(+), 73 deletions(-) diff --git a/main/adapter/adapter.h b/main/adapter/adapter.h index 3ead5a8d..f13f3c92 100644 --- a/main/adapter/adapter.h +++ b/main/adapter/adapter.h @@ -318,6 +318,7 @@ enum { BT_QUIRK_8BITDO_SATURN, BT_QUIRK_STADIA, BT_QUIRK_OUYA, + BT_QUIRK_8BITDO_GC, }; /* Wired flags */ diff --git a/main/adapter/mapping_quirks.c b/main/adapter/mapping_quirks.c index bab3fd16..4c21a799 100644 --- a/main/adapter/mapping_quirks.c +++ b/main/adapter/mapping_quirks.c @@ -105,6 +105,22 @@ static void saturn_diy_8bitdo(struct raw_src_mapping *map) { map->btns_mask[PAD_RS] = tmp; } +static void gc_diy_8bitdo(struct raw_src_mapping *map) { + map->mask[0] = 0xFF1F0FFF; + map->desc[0] = 0x110000FF; + + uint32_t tmp = map->btns_mask[PAD_RB_LEFT]; + map->btns_mask[PAD_RB_LEFT] = map->btns_mask[PAD_RB_RIGHT]; + map->btns_mask[PAD_RB_RIGHT] = tmp; + map->btns_mask[PAD_RS] = map->btns_mask[PAD_MS]; + map->btns_mask[PAD_LT] = BIT(8); + map->btns_mask[PAD_RT] = BIT(9); + map->btns_mask[PAD_MS] = 0; + map->btns_mask[PAD_LM] = 0; + map->btns_mask[PAD_RM] = 0; + map->btns_mask[PAD_LS] = 0; +} + static void n64_bluen64(struct raw_src_mapping *map) { map->mask[0] = 0x23150FFF; map->desc[0] = 0x000000FF; @@ -246,4 +262,7 @@ void mapping_quirks_apply(struct bt_data *bt_data) { if (atomic_test_bit(&bt_data->base.flags[PAD], BT_QUIRK_OUYA)) { ouya(&bt_data->raw_src_mappings[PAD]); } + if (atomic_test_bit(&bt_data->base.flags[PAD], BT_QUIRK_8BITDO_GC)) { + gc_diy_8bitdo(&bt_data->raw_src_mappings[PAD]); + } } diff --git a/main/adapter/wireless/hid_generic.c b/main/adapter/wireless/hid_generic.c index 890625d5..bc24bb7f 100644 --- a/main/adapter/wireless/hid_generic.c +++ b/main/adapter/wireless/hid_generic.c @@ -699,94 +699,109 @@ void hid_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) { switch (fb_data->type) { case FB_TYPE_RUMBLE: - { - struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output; - - rumble->report_size = 0; - uint32_t bytes_count = 0; - uint32_t tmp_value = 0; - uint32_t offset = 0; - uint32_t counter = 0; - uint32_t pwr[2]; - uint32_t pwr_idx = 0; - bool is_rumble_usage = false; - - pwr[0] = fb_data->lf_pwr; - pwr[1] = fb_data->hf_pwr; - - for (uint32_t i = 0; i < bt_data->reports[RUMBLE].usage_cnt; i++) - { - is_rumble_usage = false; - - switch (bt_data->reports[RUMBLE].usages[i].usage) + if (atomic_test_bit(&bt_data->base.flags[PAD], BT_QUIRK_8BITDO_GC)) { + struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output; + + rumble->report_id = 0xA5; + rumble->report_size = 3; + rumble->state[0] = 0xdb; + if (fb_data->state) { + rumble->state[1] = fb_data->lf_pwr; + rumble->state[2] = fb_data->hf_pwr; + } + else { + rumble->state[1] = 0x00; + rumble->state[2] = 0x00; + } + } + else { + struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output; + + rumble->report_size = 0; + uint32_t bytes_count = 0; + uint32_t tmp_value = 0; + uint32_t offset = 0; + uint32_t counter = 0; + uint32_t pwr[2]; + uint32_t pwr_idx = 0; + bool is_rumble_usage = false; + + pwr[0] = fb_data->lf_pwr; + pwr[1] = fb_data->hf_pwr; + + for (uint32_t i = 0; i < bt_data->reports[RUMBLE].usage_cnt; i++) { - case 0x50: /* Duration */ - bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; - rumble->report_size += bytes_count; + is_rumble_usage = false; - if (fb_data->state) { - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max; - } - else { - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; - } + switch (bt_data->reports[RUMBLE].usages[i].usage) + { + case 0x50: /* Duration */ + bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; + rumble->report_size += bytes_count; - is_rumble_usage = true; - break; - case 0x70: /* Magnitude */ - case 0x97: /* Enable Actuators */ - bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; - rumble->report_size += bytes_count; + if (fb_data->state) { + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max; + } + else { + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; + } - if (fb_data->state && pwr_idx < sizeof(pwr)/sizeof(pwr[0])) { - tmp_value = ((float)bt_data->reports[RUMBLE].usages[i].logical_max / 255.0) * pwr[pwr_idx++]; - } - else { - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; - } + is_rumble_usage = true; + break; + case 0x70: /* Magnitude */ + case 0x97: /* Enable Actuators */ + bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; + rumble->report_size += bytes_count; - is_rumble_usage = true; - break; - case 0x7C: /* Loop Count */ - bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; - rumble->report_size += bytes_count; + if (fb_data->state && pwr_idx < sizeof(pwr)/sizeof(pwr[0])) { + tmp_value = ((float)bt_data->reports[RUMBLE].usages[i].logical_max / 255.0) * pwr[pwr_idx++]; + } + else { + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; + } - if (fb_data->state) { - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max; - } - else { - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; - } + is_rumble_usage = true; + break; + case 0x7C: /* Loop Count */ + bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; + rumble->report_size += bytes_count; - is_rumble_usage = true; - break; - case 0xA7: /* Start Delay */ - bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; - rumble->report_size += bytes_count; + if (fb_data->state) { + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max; + } + else { + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; + } - tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; + is_rumble_usage = true; + break; + case 0xA7: /* Start Delay */ + bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8; + rumble->report_size += bytes_count; - is_rumble_usage = true; - break; - } + tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min; - if (is_rumble_usage) { - counter = 0; - while(tmp_value) - { - rumble->state[offset++] = tmp_value; - tmp_value >>= 8; - counter++; + is_rumble_usage = true; + break; } - for (uint32_t refill = counter; refill < bytes_count; refill++) { - rumble->state[offset++] = 0; + + if (is_rumble_usage) { + counter = 0; + while(tmp_value) + { + rumble->state[offset++] = tmp_value; + tmp_value >>= 8; + counter++; + } + for (uint32_t refill = counter; refill < bytes_count; refill++) { + rumble->state[offset++] = 0; + } } } - } - rumble->report_id = bt_data->reports[RUMBLE].id; + rumble->report_id = bt_data->reports[RUMBLE].id; + } break; - } } } diff --git a/main/bluetooth/hidp/hidp.c b/main/bluetooth/hidp/hidp.c index 14e35305..03f0a6e2 100644 --- a/main/bluetooth/hidp/hidp.c +++ b/main/bluetooth/hidp/hidp.c @@ -39,6 +39,7 @@ static const struct bt_name_type bt_name_type[] = { {"NES Controller", BT_SW, BT_SW_NES, BIT(BT_QUIRK_FACE_BTNS_ROTATE_RIGHT) | BIT(BT_QUIRK_TRIGGER_PRI_SEC_INVERT)}, {"N64 Controller", BT_SW, BT_SW_N64, 0}, {"MD/Gen Control Pad", BT_SW, BT_SW_MD_GEN, 0}, + {"8BitDo NGC Modkit", BT_HID_GENERIC, BT_SUBTYPE_DEFAULT, BIT(BT_QUIRK_8BITDO_GC)}, {"8BitDo N30 Modkit", BT_XBOX, BT_XBOX_XINPUT, BIT(BT_QUIRK_FACE_BTNS_ROTATE_RIGHT)}, {"8BitDo GBros Adapter", BT_XBOX, BT_8BITDO_GBROS, 0}, {"8Bitdo N64 GamePad", BT_HID_GENERIC, BT_SUBTYPE_DEFAULT, BIT(BT_QUIRK_8BITDO_N64)},