diff options
Diffstat (limited to 'hid-nintendo.c')
-rw-r--r-- | hid-nintendo.c | 132 |
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); |