hid-nintendo: support for Switch NES and SNES controllers.

This commit is contained in:
Sorgelig
2021-09-04 21:13:47 +08:00
parent 01450528b2
commit 80f1520f28

View File

@@ -302,6 +302,9 @@ enum joycon_ctlr_type {
JOYCON_CTLR_TYPE_JCL = 0x01,
JOYCON_CTLR_TYPE_JCR = 0x02,
JOYCON_CTLR_TYPE_PRO = 0x03,
JOYCON_CTLR_TYPE_NESL = 0x09,
JOYCON_CTLR_TYPE_NESR = 0x0A,
JOYCON_CTLR_TYPE_SNES = 0x0B
};
struct joycon_stick_cal {
@@ -480,12 +483,19 @@ struct joycon_ctlr {
};
/* Helper macros for checking controller type */
#define jc_type_is_nescon(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR && \
(ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL || \
ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR))
#define jc_type_is_joycon(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL || \
ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR || \
ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP)
((ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL || \
ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR || \
ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP) && \
!jc_type_is_nescon(ctlr))
#define jc_type_is_procon(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON)
#define jc_type_is_snescon(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON)
#define jc_type_is_chrggrip(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP)
@@ -499,6 +509,9 @@ struct joycon_ctlr {
(ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \
ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
#define jc_has_imu(ctlr) \
(jc_type_is_joycon(ctlr) || jc_type_is_procon(ctlr))
static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
{
u8 *buf;
@@ -1356,6 +1369,39 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B);
}
if (jc_type_is_nescon(ctlr) || jc_type_is_snescon(ctlr)) {
s8 x = 0;
s8 y = 0;
if (btns & JC_BTN_LEFT)
x = -1;
else if (btns & JC_BTN_RIGHT)
x = 1;
if (btns & JC_BTN_UP)
y = -1;
else if (btns & JC_BTN_DOWN)
y = 1;
input_report_abs(dev, ABS_HAT0X, x);
input_report_abs(dev, ABS_HAT0Y, y);
/* report buttons */
input_report_key(dev, BTN_EAST, btns & JC_BTN_A);
input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B);
input_report_key(dev, BTN_TL, btns & JC_BTN_L);
input_report_key(dev, BTN_TR, btns & JC_BTN_R);
input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
input_report_key(dev, BTN_START, btns & JC_BTN_PLUS);
if (jc_type_is_snescon(ctlr)) {
input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR);
input_report_key(dev, BTN_NORTH, btns & JC_BTN_X);
input_report_key(dev, BTN_WEST, btns & JC_BTN_Y);
}
}
input_sync(dev);
/*
@@ -1371,7 +1417,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
}
/* parse IMU data if present */
if (rep->id == JC_INPUT_IMU_DATA)
if (rep->id == JC_INPUT_IMU_DATA && jc_has_imu(ctlr))
joycon_parse_imu_report(ctlr, rep);
}
@@ -1587,6 +1633,17 @@ static const unsigned int joycon_dpad_inputs_jc[] = {
BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT,
};
static const unsigned int nescon_button_inputs[] = {
BTN_SELECT, BTN_START, BTN_SOUTH, BTN_EAST, BTN_TL, BTN_TR,
0 /* 0 signals end of array */
};
static const unsigned int snescon_button_inputs[] = {
BTN_SELECT, BTN_START, BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST,
BTN_TL, BTN_TL2, BTN_TR, BTN_TR2,
0 /* 0 signals end of array */
};
static int joycon_input_create(struct joycon_ctlr *ctlr)
{
struct hid_device *hdev;
@@ -1616,8 +1673,20 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
imu_name = "Nintendo Switch Left Joy-Con IMU";
break;
case USB_DEVICE_ID_NINTENDO_JOYCONR:
name = "Nintendo Switch Right Joy-Con";
imu_name = "Nintendo Switch Right Joy-Con IMU";
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL) {
name = "Nintendo Switch NES Controller (L)";
imu_name = NULL;
} else if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR) {
name = "Nintendo Switch NES Controller (R)";
imu_name = NULL;
} else {
name = "Nintendo Switch Right Joy-Con";
imu_name = "Nintendo Switch Right Joy-Con IMU";
}
break;
case USB_DEVICE_ID_NINTENDO_SNESCON:
name = "Nintendo Switch SNES Controller";
imu_name = NULL;
break;
default: /* Should be impossible */
hid_err(hdev, "Invalid hid product\n");
@@ -1674,6 +1743,25 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
input_set_capability(ctlr->input, EV_KEY,
joycon_button_inputs_r[i]);
}
if (jc_type_is_nescon(ctlr) || jc_type_is_snescon(ctlr)) {
const unsigned int* inputs = jc_type_is_nescon(ctlr) ?
nescon_button_inputs : snescon_button_inputs;
/* set up d-pad hat */
input_set_abs_params(ctlr->input, ABS_HAT0X, -1, 1, 0, 0);
input_set_abs_params(ctlr->input, ABS_HAT0Y, -1, 1, 0, 0);
/* set up buttons */
for (i = 0; inputs[i] > 0; i++)
input_set_capability(ctlr->input, EV_KEY, inputs[i]);
/* register the device here, we don't need any more setup */
ret = input_register_device(ctlr->input);
if (ret)
return ret;
return 0;
}
/* Let's report joy-con S triggers separately */
if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) {
@@ -2174,7 +2262,7 @@ static int nintendo_hid_probe(struct hid_device *hdev,
/* Initialize the controller */
mutex_lock(&ctlr->output_mutex);
/* if handshake command fails, assume ble pro controller */
if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
if ((jc_type_is_procon(ctlr) || jc_type_is_snescon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
!joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
hid_dbg(hdev, "detected USB controller\n");
/* set baudrate for improved latency */
@@ -2227,18 +2315,20 @@ static int nintendo_hid_probe(struct hid_device *hdev,
goto err_mutex;
}
/* Enable rumble */
ret = joycon_enable_rumble(ctlr);
if (ret) {
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
goto err_mutex;
}
if (!jc_type_is_snescon(ctlr) && !jc_type_is_nescon(ctlr)) {
/* Enable rumble */
ret = joycon_enable_rumble(ctlr);
if (ret) {
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
goto err_mutex;
}
/* Enable the IMU */
ret = joycon_enable_imu(ctlr);
if (ret) {
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
goto err_mutex;
/* Enable the IMU */
ret = joycon_enable_imu(ctlr);
if (ret) {
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
goto err_mutex;
}
}
ret = joycon_read_info(ctlr);
@@ -2317,6 +2407,10 @@ static const struct hid_device_id nintendo_hid_devices[] = {
USB_DEVICE_ID_NINTENDO_JOYCONL) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_JOYCONR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_SNESCON) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_SNESCON) },
{ }
};
MODULE_DEVICE_TABLE(hid, nintendo_hid_devices);