summarylogtreecommitdiffstats
path: root/hid-nintendo.c
diff options
context:
space:
mode:
Diffstat (limited to 'hid-nintendo.c')
-rw-r--r--hid-nintendo.c132
1 files changed, 99 insertions, 33 deletions
diff --git a/hid-nintendo.c b/hid-nintendo.c
index 56e9b8fbd9d4..b0487b9d3cb0 100644
--- a/hid-nintendo.c
+++ b/hid-nintendo.c
@@ -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 {
@@ -482,6 +483,8 @@ struct joycon_ctlr {
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP)
#define jc_type_is_snescon(ctlr) \
(ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON)
+#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) \
@@ -493,15 +496,22 @@ 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_snescon(ctlr) || \
+ jc_type_is_n64con(ctlr))
/* Does this controller have motion sensors */
#define jc_has_imu(ctlr) \
- (!jc_type_is_nescon(ctlr) && !jc_type_is_snescon(ctlr))
+ (!jc_type_is_nso(ctlr))
/* Does this controller have rumble */
#define jc_has_rumble(ctlr) \
@@ -1202,7 +1212,7 @@ 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) && */ jc_has_rumble(ctlr) && \
+ 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 ||
@@ -1240,7 +1250,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;
@@ -1256,7 +1266,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);
@@ -1330,7 +1341,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;
@@ -1352,15 +1363,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);
@@ -1416,7 +1446,7 @@ static void joycon_rumble_worker(struct work_struct *work)
}
}
-//#if IS_ENABLED(CONFIG_NINTENDO_FF)
+#if IS_ENABLED(CONFIG_NINTENDO_FF)
static struct joycon_rumble_freq_data joycon_find_rumble_freq(u16 freq)
{
const size_t length = ARRAY_SIZE(joycon_rumble_frequencies);
@@ -1545,7 +1575,7 @@ static int joycon_play_effect(struct input_dev *dev, void *data,
effect->u.rumble.strong_magnitude,
true);
}
-//#endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */
+#endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */
static const unsigned int joycon_button_inputs_l[] = {
BTN_SELECT, BTN_Z, BTN_THUMBL,
@@ -1576,6 +1606,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;
@@ -1620,6 +1659,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;
@@ -1675,9 +1718,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,
@@ -1690,41 +1752,41 @@ 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 */
- if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) {
+ if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL) {
input_set_capability(ctlr->input, EV_KEY, BTN_TR);
input_set_capability(ctlr->input, EV_KEY, BTN_TR2);
- } else if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR) {
+ } else if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR) {
input_set_capability(ctlr->input, EV_KEY, BTN_TL);
input_set_capability(ctlr->input, EV_KEY, BTN_TL2);
}
-//#if IS_ENABLED(CONFIG_NINTENDO_FF)
+#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);
-//#endif
+ 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)
@@ -2335,6 +2397,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);