Skip to content

Commit

Permalink
[ADAPTER] Add support for individualy described buttons in HID descri…
Browse files Browse the repository at this point in the history
…ptors
  • Loading branch information
darthcloud committed Dec 12, 2024
1 parent 974eabc commit ddbe5a3
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 43 deletions.
2 changes: 1 addition & 1 deletion main/adapter/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#define WIRED_MAX_DEV 12 /* Saturn limit */
#define ADAPTER_MAX_AXES 6
#define ADAPTER_PS2_MAX_AXES 16
#define REPORT_MAX_USAGE 16
#define REPORT_MAX_USAGE 18
#define HID_MAX_REPORT 10
#define MAX_PULL_BACK 0.95

Expand Down
32 changes: 23 additions & 9 deletions main/adapter/hid_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,15 +380,29 @@ void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) {
}
}
else {
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage_page = hid_stack[hid_stack_idx].usage_page;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage = usage_list[0];
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].flags = *desc;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_offset = report_bit_offset[tag_idx];
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_min = hid_stack[hid_stack_idx].logical_min;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_max = hid_stack[hid_stack_idx].logical_max;
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
++report_usage_idx[tag_idx];
uint32_t idx_end = report_usage_idx[tag_idx] + hid_stack[hid_stack_idx].report_cnt;
if (idx_end > REPORT_MAX_USAGE) {
idx_end = REPORT_MAX_USAGE;
}
if (hid_stack[hid_stack_idx].usage_page == USAGE_GEN_BUTTON) {
idx_end = report_usage_idx[tag_idx] + 1;
}
for (uint32_t i = 0; report_usage_idx[tag_idx] < idx_end; ++i, ++report_usage_idx[tag_idx]) {
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage_page = hid_stack[hid_stack_idx].usage_page;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].usage = usage_list[i];
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].flags = *desc;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_offset = report_bit_offset[tag_idx];
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_min = hid_stack[hid_stack_idx].logical_min;
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].logical_max = hid_stack[hid_stack_idx].logical_max;
if (hid_stack[hid_stack_idx].usage_page == USAGE_GEN_BUTTON) {
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
}
else {
wip_report[tag_idx]->usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_size;
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_size;
}
}
}
}
else {
Expand Down
125 changes: 92 additions & 33 deletions main/adapter/wireless/hid_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,26 @@ static const uint32_t hid_kb_key_to_generic[] = {
KB_KP_8, KB_KP_9, KB_KP_0, KB_KP_DOT,
};

static const uint32_t hid_pad_default_btns_mask[32] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, BIT(HID_Z), 0, BIT(HID_C),
BIT(HID_X), BIT(HID_B), BIT(HID_A), BIT(HID_Y),
BIT(HID_START), BIT(HID_SELECT), BIT(HID_MENU), 0,
BIT(HID_L), BIT(HID_LB), 0, BIT(HID_LJ),
BIT(HID_R), BIT(HID_RB), 0, BIT(HID_RJ),
// static const uint32_t hid_pad_default_btns_mask[32] = {
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, 0, 0, 0,
// 0, BIT(HID_Z), 0, BIT(HID_C),
// BIT(HID_X), BIT(HID_B), BIT(HID_A), BIT(HID_Y),
// BIT(HID_START), BIT(HID_SELECT), BIT(HID_MENU), 0,
// BIT(HID_L), BIT(HID_LB), 0, BIT(HID_LJ),
// BIT(HID_R), BIT(HID_RB), 0, BIT(HID_RJ),
// };

static const uint32_t hid_pad_default_btns_idx[32] = {
PAD_RB_DOWN, PAD_RB_RIGHT, PAD_LT,
PAD_RB_LEFT, PAD_RB_UP, PAD_RT,
PAD_LS, PAD_RS,
PAD_LM, PAD_RM,
PAD_MS, PAD_MM, PAD_MT,
PAD_LJ, PAD_RJ,
PAD_MQ,
PAD_RD_LEFT, PAD_RD_RIGHT, PAD_RD_DOWN, PAD_RD_UP,
};

static void hid_kb_init(struct hid_report_meta *meta, struct hid_report *report, struct raw_src_mapping *map) {
Expand Down Expand Up @@ -306,6 +317,7 @@ static void hid_mouse_to_generic(struct bt_data *bt_data, struct wireless_ctrl *

static void hid_pad_init(struct hid_report_meta *meta, struct hid_report *report, struct raw_src_mapping *map) {
uint32_t z_is_joy = 0;
int8_t hid_cbtn_idx = -1;
memset(meta->hid_axes_idx, -1, sizeof(meta->hid_axes_idx));
meta->hid_btn_idx = -1;
meta->hid_hat_idx = -1;
Expand Down Expand Up @@ -473,7 +485,9 @@ static void hid_pad_init(struct hid_report_meta *meta, struct hid_report *report
}
break;
case USAGE_GEN_BUTTON:
meta->hid_btn_idx = i;
if (meta->hid_btn_idx < 0) {
meta->hid_btn_idx = i;
}
break;
case 0x02 /* USAGE_SIMS */:
switch (report->usages[i].usage) {
Expand All @@ -495,6 +509,11 @@ static void hid_pad_init(struct hid_report_meta *meta, struct hid_report *report
break;
}
break;
case 0x0C: /* Consumer */
if (hid_cbtn_idx < 0) {
hid_cbtn_idx = i;
}
break;
}
}

Expand All @@ -504,35 +523,75 @@ static void hid_pad_init(struct hid_report_meta *meta, struct hid_report *report
meta->hid_axes_meta[i].abs_min *= MAX_PULL_BACK;
}

/* HID buttons order is from most important to the less in HID spec. */
if (meta->hid_btn_idx > -1) {
uint32_t hid_mask = (1 << report->usages[meta->hid_btn_idx].bit_size) - 1;

/* Use a good default for most modern controller */
for (uint32_t i = 12; i < ARRAY_SIZE(generic_btns_mask); i++) {
if (hid_pad_default_btns_mask[i] && !(map->mask[0] & BIT(i))) {
map->mask[0] |= BIT(i);
map->btns_mask[i] = hid_pad_default_btns_mask[i];
hid_mask &= ~hid_pad_default_btns_mask[i];
}
/* We assume here that button-like usages are all */
/* placed consecutively in the report. We try here to aggregate */
/* then all under a single button usage. */
int8_t btn_idx = 0;
uint32_t btn_offset = 0;
if (meta->hid_btn_idx > -1 && hid_cbtn_idx == -1) {
btn_idx = meta->hid_btn_idx;
btn_offset = report->usages[btn_idx].bit_offset;
}
else if (meta->hid_btn_idx == -1 && hid_cbtn_idx > -1) {
btn_idx = hid_cbtn_idx;
btn_offset = report->usages[btn_idx].bit_offset;
}
else if (meta->hid_btn_idx > -1 && hid_cbtn_idx > -1) {
btn_idx = meta->hid_btn_idx;
if (meta->hid_btn_idx < hid_cbtn_idx) {
btn_offset = report->usages[meta->hid_btn_idx].bit_offset;
}
else {
btn_offset = report->usages[hid_cbtn_idx].bit_offset;
}
}

/* fillup what is left */
for (uint32_t hid_btn = 15, i = 12; hid_btn < report->usages[meta->hid_btn_idx].bit_size; hid_btn++) {
while (map->btns_mask[i]) {
i++;
if (i > 32) {
goto fillup_end;
if (meta->hid_btn_idx > -1) {
uint32_t uidx = meta->hid_btn_idx;
for (; report->usages[uidx].usage_page == USAGE_GEN_BUTTON; uidx++) {
if (report->usages[uidx].usage) {
uint32_t usage = report->usages[uidx].usage - 1;
for (uint32_t j = 0; j < report->usages[uidx].bit_size; j++, usage++) {
map->mask[0] |= BIT(hid_pad_default_btns_idx[usage]);
map->btns_mask[hid_pad_default_btns_idx[usage]] =
BIT(report->usages[uidx].bit_offset - btn_offset + j);
}
}
if (!(map->mask[0] & BIT(i))) {
map->mask[0] |= BIT(i);
map->btns_mask[i] = BIT(hid_btn);
hid_mask &= ~BIT(hid_btn);
}
report->usages[btn_idx].bit_size =
report->usages[uidx - 1].bit_offset + report->usages[uidx - 1].bit_size - btn_offset;
}
if (hid_cbtn_idx > -1) {
uint32_t uidx = hid_cbtn_idx;
for (; report->usages[uidx].usage_page == 0x0C; uidx++) {
if (report->usages[uidx].usage) {
switch (report->usages[uidx].usage) {
case 0x40 /* Menu */:
map->mask[0] |= BIT(PAD_MM);
map->btns_mask[PAD_MM] =
BIT(report->usages[uidx].bit_offset - btn_offset);
break;
case 0x223 /* AC Home */:
map->mask[0] |= BIT(PAD_MT);
map->btns_mask[PAD_MT] =
BIT(report->usages[uidx].bit_offset - btn_offset);
break;
case 0x224 /* AC Back */:
map->mask[0] |= BIT(PAD_MS);
map->btns_mask[PAD_MS] =
BIT(report->usages[uidx].bit_offset - btn_offset);
break;
}
}
}
fillup_end:
;
uint32_t bit_size =
report->usages[uidx - 1].bit_offset + report->usages[uidx - 1].bit_size - btn_offset;
if (bit_size > report->usages[btn_idx].bit_size) {
report->usages[btn_idx].bit_size = bit_size;
}
if (btn_idx == hid_cbtn_idx) {
meta->hid_btn_idx = btn_idx;
}
}
}

Expand Down

0 comments on commit ddbe5a3

Please sign in to comment.