--- v9
+++ v14
@@ -10,16 +10,16 @@
drivers/hid/Kconfig | 11 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 3 +
- drivers/hid/hid-nintendo.c | 806 +++++++++++++++++++++++++++++++++++++
- 5 files changed, 827 insertions(+)
+ drivers/hid/hid-nintendo.c | 869 +++++++++++++++++++++++++++++++++++++
+ 5 files changed, 890 insertions(+)
create mode 100644 drivers/hid/hid-nintendo.c
diff --git a/MAINTAINERS b/MAINTAINERS
-index 1d235c674be8..9e9846cdd524 100644
+index 0cce91cd56243..24f6b18356b7d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -11393,6 +11393,12 @@ S: Maintained
- F: Documentation/scsi/NinjaSCSI.txt
+@@ -12968,6 +12968,12 @@ W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+ F: Documentation/scsi/NinjaSCSI.rst
F: drivers/scsi/nsp32*
+NINTENDO HID DRIVER
@@ -29,13 +29,13 @@
+F: drivers/hid/hid-nintendo*
+
NIOS2 ARCHITECTURE
- M: Ley Foon Tan <lftan@altera.com>
- L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
+ M: Ley Foon Tan <ley.foon.tan@intel.com>
+ S: Maintained
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 3872e03d9a59..47ec750c2baf 100644
+index 160554903ef96..a95334b42f68a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
-@@ -692,6 +692,17 @@ config HID_MULTITOUCH
+@@ -730,6 +730,17 @@ config HID_MULTITOUCH
To compile this driver as a module, choose M here: the
module will be called hid-multitouch.
@@ -52,12 +52,12 @@
+
config HID_NTI
tristate "NTI keyboard adapters"
- ---help---
+ help
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index cc5d827c9164..398d5e91fa4b 100644
+index 1ea1a7c0b20fe..2eddcb84d2adc 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
-@@ -72,6 +72,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
+@@ -78,6 +78,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
@@ -66,10 +66,10 @@
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
-index e4d51ce20a6a..4a916c00b749 100644
+index 63ca5959dc679..d67da66ac958c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
-@@ -864,6 +864,9 @@
+@@ -917,6 +917,9 @@
#define USB_VENDOR_ID_NINTENDO 0x057e
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330
@@ -81,10 +81,10 @@
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
new file mode 100644
-index 000000000000..882b3758c3be
+index 0000000000000..b6c0e5e36d8b0
--- /dev/null
+++ b/drivers/hid/hid-nintendo.c
-@@ -0,0 +1,806 @@
+@@ -0,0 +1,869 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * HID driver for Nintendo Switch Joy-Cons and Pro Controllers
@@ -128,7 +128,7 @@
+static const u8 JC_OUTPUT_USB_CMD = 0x80;
+
+/* Subcommand IDs */
-+static const u8 JC_SUBCMD_STATE = 0x00;
++static const u8 JC_SUBCMD_STATE /*= 0x00*/;
+static const u8 JC_SUBCMD_MANUAL_BT_PAIRING = 0x01;
+static const u8 JC_SUBCMD_REQ_DEV_INFO = 0x02;
+static const u8 JC_SUBCMD_SET_REPORT_MODE = 0x03;
@@ -188,6 +188,11 @@
+static const u16 JC_MAX_STICK_MAG = 32767;
+static const u16 JC_STICK_FUZZ = 250;
+static const u16 JC_STICK_FLAT = 500;
++
++/* Hat values for pro controller's d-pad */
++static const u16 JC_MAX_DPAD_MAG = 1;
++static const u16 JC_DPAD_FUZZ /*= 0*/;
++static const u16 JC_DPAD_FLAT /*= 0*/;
+
+/* States for controller state machine */
+enum joycon_ctlr_state {
@@ -239,13 +244,13 @@
+ u8 packet_num; /* incremented every send */
+ u8 rumble_data[8];
+ u8 subcmd_id;
-+ u8 data[0]; /* length depends on the subcommand */
++ u8 data[]; /* length depends on the subcommand */
+} __packed;
+
+struct joycon_subcmd_reply {
+ u8 ack; /* MSB 1 for ACK, 0 for NACK */
+ u8 id; /* id of requested subcmd */
-+ u8 data[0]; /* will be at most 35 bytes */
++ u8 data[]; /* will be at most 35 bytes */
+} __packed;
+
+struct joycon_input_report {
@@ -543,18 +548,41 @@
+ /* report buttons */
+ input_report_key(dev, BTN_TL, btns & JC_BTN_L);
+ input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
++ input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
++ input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK);
++ input_report_key(dev, BTN_Z, btns & JC_BTN_CAP);
++
+ if (id != USB_DEVICE_ID_NINTENDO_PROCON) {
+ /* Report the S buttons as the non-existent triggers */
+ input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L);
+ input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L);
++
++ /* Report d-pad as digital buttons for the joy-cons */
++ input_report_key(dev, BTN_DPAD_DOWN,
++ btns & JC_BTN_DOWN);
++ input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP);
++ input_report_key(dev, BTN_DPAD_RIGHT,
++ btns & JC_BTN_RIGHT);
++ input_report_key(dev, BTN_DPAD_LEFT,
++ btns & JC_BTN_LEFT);
++ } else {
++ int hatx = 0;
++ int haty = 0;
++
++ /* d-pad x */
++ if (btns & JC_BTN_LEFT)
++ hatx = -1;
++ else if (btns & JC_BTN_RIGHT)
++ hatx = 1;
++ input_report_abs(dev, ABS_HAT0X, hatx);
++
++ /* d-pad y */
++ if (btns & JC_BTN_UP)
++ haty = -1;
++ else if (btns & JC_BTN_DOWN)
++ haty = 1;
++ input_report_abs(dev, ABS_HAT0Y, haty);
+ }
-+ input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
-+ input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK);
-+ input_report_key(dev, BTN_Z, btns & JC_BTN_CAP);
-+ input_report_key(dev, BTN_DPAD_DOWN, btns & JC_BTN_DOWN);
-+ input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP);
-+ input_report_key(dev, BTN_DPAD_RIGHT, btns & JC_BTN_RIGHT);
-+ input_report_key(dev, BTN_DPAD_LEFT, btns & JC_BTN_LEFT);
+ }
+ if (id != USB_DEVICE_ID_NINTENDO_JOYCONL) {
+ u16 raw_x;
@@ -581,7 +609,6 @@
+ input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R);
+ input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R);
+ }
-+ input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR);
+ input_report_key(dev, BTN_START, btns & JC_BTN_PLUS);
+ input_report_key(dev, BTN_THUMBR, btns & JC_BTN_RSTICK);
+ input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME);
@@ -595,13 +622,22 @@
+}
+
+
-+static const unsigned int joycon_button_inputs[] = {
++static const unsigned int joycon_button_inputs_l[] = {
+ BTN_SELECT, BTN_Z, BTN_THUMBL,
++ BTN_TL, BTN_TL2,
++ 0 /* 0 signals end of array */
++};
++
++static const unsigned int joycon_button_inputs_r[] = {
+ BTN_START, BTN_MODE, BTN_THUMBR,
+ BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST,
++ BTN_TR, BTN_TR2,
++ 0 /* 0 signals end of array */
++};
++
++/* We report joy-con d-pad inputs as buttons and pro controller as a hat. */
++static const unsigned int joycon_dpad_inputs_jc[] = {
+ BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT,
-+ BTN_TL, BTN_TR, BTN_TL2, BTN_TR2,
-+ 0 /* 0 signals end of array */
+};
+
+static DEFINE_MUTEX(joycon_input_num_mutex);
@@ -641,23 +677,54 @@
+ input_set_drvdata(ctlr->input, ctlr);
+
+
-+ /* set up sticks */
-+ 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);
-+ input_set_abs_params(ctlr->input, ABS_RX,
-+ -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
-+ JC_STICK_FUZZ, JC_STICK_FLAT);
-+ input_set_abs_params(ctlr->input, ABS_RY,
-+ -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
-+ JC_STICK_FUZZ, JC_STICK_FLAT);
-+ /* set up buttons */
-+ for (i = 0; joycon_button_inputs[i] > 0; i++)
-+ input_set_capability(ctlr->input, EV_KEY,
-+ joycon_button_inputs[i]);
++ /* set up sticks and buttons */
++ if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONR) {
++ 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);
++
++ for (i = 0; joycon_button_inputs_l[i] > 0; i++)
++ input_set_capability(ctlr->input, EV_KEY,
++ joycon_button_inputs_l[i]);
++
++ /* configure d-pad differently for joy-con vs pro controller */
++ if (hdev->product != USB_DEVICE_ID_NINTENDO_PROCON) {
++ for (i = 0; joycon_dpad_inputs_jc[i] > 0; i++)
++ input_set_capability(ctlr->input, EV_KEY,
++ joycon_dpad_inputs_jc[i]);
++ } else {
++ input_set_abs_params(ctlr->input, ABS_HAT0X,
++ -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG,
++ JC_DPAD_FUZZ, JC_DPAD_FLAT);
++ input_set_abs_params(ctlr->input, ABS_HAT0Y,
++ -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG,
++ JC_DPAD_FUZZ, JC_DPAD_FLAT);
++ }
++ }
++ if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONL) {
++ input_set_abs_params(ctlr->input, ABS_RX,
++ -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
++ JC_STICK_FUZZ, JC_STICK_FLAT);
++ input_set_abs_params(ctlr->input, ABS_RY,
++ -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
++ JC_STICK_FUZZ, JC_STICK_FLAT);
++
++ for (i = 0; joycon_button_inputs_r[i] > 0; i++)
++ input_set_capability(ctlr->input, EV_KEY,
++ joycon_button_inputs_r[i]);
++ }
++
++ /* Let's report joy-con S triggers separately */
++ if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) {
++ 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) {
++ input_set_capability(ctlr->input, EV_KEY, BTN_TL);
++ input_set_capability(ctlr->input, EV_KEY, BTN_TL2);
++ }
+
+ ret = input_register_device(ctlr->input);
+ if (ret)
@@ -681,8 +748,6 @@
+static int joycon_ctlr_read_handler(struct joycon_ctlr *ctlr, u8 *data,
+ int size)
+{
-+ int ret = 0;
-+
+ if (data[0] == JC_INPUT_SUBCMD_REPLY || data[0] == JC_INPUT_IMU_DATA ||
+ data[0] == JC_INPUT_MCU_DATA) {
+ if (size >= 12) /* make sure it contains the input report */
@@ -690,7 +755,7 @@
+ (struct joycon_input_report *)data);
+ }
+
-+ return ret;
++ return 0;
+}
+
+static int joycon_ctlr_handle_event(struct joycon_ctlr *ctlr, u8 *data,
@@ -859,8 +924,6 @@
+
+static void nintendo_hid_remove(struct hid_device *hdev)
+{
-+ struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
-+
+ hid_dbg(hdev, "remove\n");
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
@@ -892,5 +955,5 @@
+MODULE_AUTHOR("Daniel J. Ogorchock <djogorchock@gmail.com>");
+MODULE_DESCRIPTION("Driver for Nintendo Switch Controllers");
--
-2.23.0
+2.32.0