Skip to content

Commit

Permalink
[BT] Add support for 8bitdo GC Modkit
Browse files Browse the repository at this point in the history
  • Loading branch information
darthcloud committed Oct 6, 2024
1 parent 2b30fdf commit 5f9608f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 73 deletions.
1 change: 1 addition & 0 deletions main/adapter/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ enum {
BT_QUIRK_8BITDO_SATURN,
BT_QUIRK_STADIA,
BT_QUIRK_OUYA,
BT_QUIRK_8BITDO_GC,
};

/* Wired flags */
Expand Down
19 changes: 19 additions & 0 deletions main/adapter/mapping_quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]);
}
}
161 changes: 88 additions & 73 deletions main/adapter/wireless/hid_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

1 change: 1 addition & 0 deletions main/bluetooth/hidp/hidp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand Down

0 comments on commit 5f9608f

Please sign in to comment.