mirror of
https://github.com/MiSTer-devel/Linux-Kernel_MiSTer.git
synced 2026-05-17 03:03:57 +00:00
hid-nintendo: support for Switch NES and SNES controllers.
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user