mirror of
https://github.com/MiSTer-devel/Linux-Kernel_MiSTer.git
synced 2026-04-26 03:04:36 +00:00
add support for NSO N64 controller (#49)
* add support for NSO N64 controller
This commit is contained in:
@@ -928,6 +928,7 @@
|
||||
#define USB_DEVICE_ID_NINTENDO_PROCON 0x2009
|
||||
#define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200E
|
||||
#define USB_DEVICE_ID_NINTENDO_SNESCON 0x2017
|
||||
#define USB_DEVICE_ID_NINTENDO_N64CON 0x2019
|
||||
#define USB_DEVICE_ID_NINTENDO_GAMECUBE_ADAPTER 0x0337
|
||||
|
||||
#define USB_VENDOR_ID_NOVATEK 0x0603
|
||||
|
||||
@@ -304,7 +304,8 @@ enum joycon_ctlr_type {
|
||||
JOYCON_CTLR_TYPE_PRO = 0x03,
|
||||
JOYCON_CTLR_TYPE_NESL = 0x09,
|
||||
JOYCON_CTLR_TYPE_NESR = 0x0A,
|
||||
JOYCON_CTLR_TYPE_SNES = 0x0B
|
||||
JOYCON_CTLR_TYPE_SNES = 0x0B,
|
||||
JOYCON_CTLR_TYPE_N64 = 0x0D,
|
||||
};
|
||||
|
||||
struct joycon_stick_cal {
|
||||
@@ -498,6 +499,8 @@ struct joycon_ctlr {
|
||||
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON)
|
||||
#define jc_type_is_chrggrip(ctlr) \
|
||||
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP)
|
||||
#define jc_type_is_n64con(ctlr) \
|
||||
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON)
|
||||
|
||||
/* Does this controller have inputs associated with left joycon? */
|
||||
#define jc_type_has_left(ctlr) \
|
||||
@@ -509,8 +512,26 @@ struct joycon_ctlr {
|
||||
(ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \
|
||||
ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
|
||||
|
||||
/* Is this one of the Nintendo Switch Online controllers? */
|
||||
#define jc_type_is_nso(ctlr) \
|
||||
(jc_type_is_nescon(ctlr) || \
|
||||
jc_type_is_snescon(ctlr) || \
|
||||
jc_type_is_n64con(ctlr))
|
||||
|
||||
/* Can this controller be connected via USB */
|
||||
#define jc_has_usb(ctlr) \
|
||||
(jc_type_is_procon(ctlr) || \
|
||||
jc_type_is_chrggrip(ctlr) || \
|
||||
jc_type_is_snescon(ctlr) || \
|
||||
jc_type_is_n64con(ctlr))
|
||||
|
||||
/* Does this controller have motion sensors */
|
||||
#define jc_has_imu(ctlr) \
|
||||
(jc_type_is_joycon(ctlr) || jc_type_is_procon(ctlr))
|
||||
(!jc_type_is_nso(ctlr))
|
||||
|
||||
/* Does this controller have rumble */
|
||||
#define jc_has_rumble(ctlr) \
|
||||
(!jc_type_is_nescon(ctlr) && !jc_type_is_snescon(ctlr))
|
||||
|
||||
static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
|
||||
{
|
||||
@@ -1233,7 +1254,8 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
||||
unsigned long msecs = jiffies_to_msecs(jiffies);
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
|
||||
if (IS_ENABLED(CONFIG_NINTENDO_FF) && jc_has_rumble(ctlr) &&
|
||||
rep->vibrator_report &&
|
||||
(msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS &&
|
||||
(ctlr->rumble_queue_head != ctlr->rumble_queue_tail ||
|
||||
ctlr->rumble_zero_countdown > 0)) {
|
||||
@@ -1279,7 +1301,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
||||
/* Parse the buttons and sticks */
|
||||
btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24);
|
||||
|
||||
if (jc_type_has_left(ctlr)) {
|
||||
if (jc_type_has_left(ctlr) || jc_type_is_n64con(ctlr)) {
|
||||
u16 raw_x;
|
||||
u16 raw_y;
|
||||
s32 x;
|
||||
@@ -1295,7 +1317,8 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
||||
/* report sticks */
|
||||
input_report_abs(dev, ABS_X, x);
|
||||
input_report_abs(dev, ABS_Y, y);
|
||||
|
||||
}
|
||||
if (jc_type_has_left(ctlr)) {
|
||||
/* report buttons */
|
||||
input_report_key(dev, BTN_TL, btns & JC_BTN_L);
|
||||
input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
|
||||
@@ -1369,7 +1392,7 @@ 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)) {
|
||||
if (jc_type_is_nso(ctlr)) {
|
||||
s8 x = 0;
|
||||
s8 y = 0;
|
||||
|
||||
@@ -1391,15 +1414,34 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
||||
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_n64con(ctlr)) {
|
||||
input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (jc_type_is_n64con(ctlr)) {
|
||||
input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
|
||||
input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME);
|
||||
input_report_key(dev, BTN_Z, btns & JC_BTN_CAP);
|
||||
|
||||
/* Back ZR button */
|
||||
input_report_key(dev, BTN_TR2, btns & JC_BTN_LSTICK);
|
||||
|
||||
/* C-buttons: up, right, down, left */
|
||||
input_report_key(dev, BTN_NORTH, btns & JC_BTN_Y);
|
||||
input_report_key(dev, BTN_THUMBR,
|
||||
btns & JC_BTN_MINUS);
|
||||
input_report_key(dev, BTN_THUMBL, btns & JC_BTN_ZR);
|
||||
input_report_key(dev, BTN_WEST, btns & JC_BTN_X);
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
@@ -1461,6 +1503,10 @@ static void joycon_rumble_worker(struct work_struct *work)
|
||||
bool again = true;
|
||||
int ret;
|
||||
|
||||
if (!jc_has_rumble(ctlr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (again) {
|
||||
mutex_lock(&ctlr->output_mutex);
|
||||
ret = joycon_send_rumble_data(ctlr);
|
||||
@@ -1644,6 +1690,15 @@ static const unsigned int snescon_button_inputs[] = {
|
||||
0 /* 0 signals end of array */
|
||||
};
|
||||
|
||||
static const unsigned int n64con_button_inputs[] = {
|
||||
/* Original N64 controller buttons */
|
||||
BTN_START, BTN_B, BTN_A, BTN_TL, BTN_TL2, BTN_TR,
|
||||
BTN_WEST, BTN_NORTH, BTN_THUMBL, BTN_THUMBR,
|
||||
/* NSO controller additions */
|
||||
BTN_TR2, BTN_MODE, BTN_Z,
|
||||
0 /* 0 signals end of array */
|
||||
};
|
||||
|
||||
static int joycon_input_create(struct joycon_ctlr *ctlr)
|
||||
{
|
||||
struct hid_device *hdev;
|
||||
@@ -1688,6 +1743,10 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
||||
name = "Nintendo Switch SNES Controller";
|
||||
imu_name = NULL;
|
||||
break;
|
||||
case USB_DEVICE_ID_NINTENDO_N64CON:
|
||||
name = "Nintendo Switch N64 Controller";
|
||||
imu_name = NULL;
|
||||
break;
|
||||
default: /* Should be impossible */
|
||||
hid_err(hdev, "Invalid hid product\n");
|
||||
return -EINVAL;
|
||||
@@ -1743,9 +1802,28 @@ 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;
|
||||
|
||||
if (jc_type_is_nso(ctlr)) {
|
||||
const unsigned int* inputs;
|
||||
|
||||
if (jc_type_is_nescon(ctlr)) {
|
||||
inputs = nescon_button_inputs;
|
||||
} else if (jc_type_is_snescon(ctlr)) {
|
||||
inputs = snescon_button_inputs;
|
||||
} else if (jc_type_is_n64con(ctlr)) {
|
||||
inputs = n64con_button_inputs;
|
||||
|
||||
input_set_abs_params(ctlr->input, ABS_X,
|
||||
-JC_MAX_STICK_MAG,
|
||||
JC_MAX_STICK_MAG,
|
||||
JC_STICK_FUZZ,
|
||||
JC_STICK_FLAT);
|
||||
input_set_abs_params(ctlr->input, ABS_Y,
|
||||
-JC_MAX_STICK_MAG,
|
||||
JC_MAX_STICK_MAG,
|
||||
JC_STICK_FUZZ,
|
||||
JC_STICK_FLAT);
|
||||
}
|
||||
|
||||
/* set up d-pad hat */
|
||||
input_set_abs_params(ctlr->input, ABS_HAT0X, -1, 1, 0, 0);
|
||||
@@ -1754,13 +1832,6 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
||||
/* 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 */
|
||||
@@ -1774,21 +1845,27 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
||||
|
||||
#if IS_ENABLED(CONFIG_NINTENDO_FF)
|
||||
/* set up rumble */
|
||||
input_set_capability(ctlr->input, EV_FF, FF_RUMBLE);
|
||||
input_ff_create_memless(ctlr->input, NULL, joycon_play_effect);
|
||||
ctlr->rumble_ll_freq = JC_RUMBLE_DFLT_LOW_FREQ;
|
||||
ctlr->rumble_lh_freq = JC_RUMBLE_DFLT_HIGH_FREQ;
|
||||
ctlr->rumble_rl_freq = JC_RUMBLE_DFLT_LOW_FREQ;
|
||||
ctlr->rumble_rh_freq = JC_RUMBLE_DFLT_HIGH_FREQ;
|
||||
joycon_clamp_rumble_freqs(ctlr);
|
||||
joycon_set_rumble(ctlr, 0, 0, false);
|
||||
ctlr->rumble_msecs = jiffies_to_msecs(jiffies);
|
||||
if (jc_has_rumble(ctlr)) {
|
||||
input_set_capability(ctlr->input, EV_FF, FF_RUMBLE);
|
||||
input_ff_create_memless(ctlr->input, NULL, joycon_play_effect);
|
||||
ctlr->rumble_ll_freq = JC_RUMBLE_DFLT_LOW_FREQ;
|
||||
ctlr->rumble_lh_freq = JC_RUMBLE_DFLT_HIGH_FREQ;
|
||||
ctlr->rumble_rl_freq = JC_RUMBLE_DFLT_LOW_FREQ;
|
||||
ctlr->rumble_rh_freq = JC_RUMBLE_DFLT_HIGH_FREQ;
|
||||
joycon_clamp_rumble_freqs(ctlr);
|
||||
joycon_set_rumble(ctlr, 0, 0, false);
|
||||
ctlr->rumble_msecs = jiffies_to_msecs(jiffies);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = input_register_device(ctlr->input);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* setup is done if the controller has no IMU */
|
||||
if (!jc_has_imu(ctlr))
|
||||
return 0;
|
||||
|
||||
/* configure the imu input device */
|
||||
ctlr->imu_input = devm_input_allocate_device(&hdev->dev);
|
||||
if (!ctlr->imu_input)
|
||||
@@ -2262,7 +2339,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_snescon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
|
||||
if (jc_has_usb(ctlr) &&
|
||||
!joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
|
||||
hid_dbg(hdev, "detected USB controller\n");
|
||||
/* set baudrate for improved latency */
|
||||
@@ -2315,14 +2392,16 @@ static int nintendo_hid_probe(struct hid_device *hdev,
|
||||
goto err_mutex;
|
||||
}
|
||||
|
||||
if (!jc_type_is_snescon(ctlr) && !jc_type_is_nescon(ctlr)) {
|
||||
if (jc_has_rumble(ctlr)) {
|
||||
/* 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_has_imu(ctlr)) {
|
||||
/* Enable the IMU */
|
||||
ret = joycon_enable_imu(ctlr);
|
||||
if (ret) {
|
||||
@@ -2411,6 +2490,10 @@ static const struct hid_device_id nintendo_hid_devices[] = {
|
||||
USB_DEVICE_ID_NINTENDO_SNESCON) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_SNESCON) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_N64CON) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_N64CON) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, nintendo_hid_devices);
|
||||
|
||||
Reference in New Issue
Block a user