mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2025-03-01 06:51:22 +00:00
234 lines
8.4 KiB
Diff
234 lines
8.4 KiB
Diff
From ba1a3e7c8132c9e3e0b9a973043f9fc15fc3e69b Mon Sep 17 00:00:00 2001
|
|
From: "Daniel J. Ogorchock" <djogorchock@gmail.com>
|
|
Date: Sat, 28 Dec 2019 03:06:42 -0600
|
|
Subject: [PATCH] HID: nintendo: add support for charging grip
|
|
|
|
This patch adds support for the joy-con charging grip. The peripheral
|
|
essentially behaves the same as a pro controller, but with two joy-cons
|
|
attached to the grip. However the grip exposes the two joy-cons as
|
|
separate hid devices, so extra handling is required. The joy-con is
|
|
queried to check if it is a right or left joy-con (since the product ID
|
|
is identical between left/right when using the grip).
|
|
|
|
Since controller model detection is now more complicated, the various
|
|
checks for hid product values have been replaced with helper macros to
|
|
reduce code duplication.
|
|
|
|
Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com>
|
|
---
|
|
drivers/hid/hid-ids.h | 1 +
|
|
drivers/hid/hid-nintendo.c | 67 ++++++++++++++++++++++++++++++--------
|
|
2 files changed, 55 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
index 1b87721c2b28..a808c2195b91 100644
|
|
--- a/drivers/hid/hid-ids.h
|
|
+++ b/drivers/hid/hid-ids.h
|
|
@@ -901,6 +901,7 @@
|
|
#define USB_DEVICE_ID_NINTENDO_JOYCONL 0x2006
|
|
#define USB_DEVICE_ID_NINTENDO_JOYCONR 0x2007
|
|
#define USB_DEVICE_ID_NINTENDO_PROCON 0x2009
|
|
+#define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200E
|
|
|
|
#define USB_VENDOR_ID_NOVATEK 0x0603
|
|
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
|
|
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
|
|
index 85870569cb49..afb461d765b1 100644
|
|
--- a/drivers/hid/hid-nintendo.c
|
|
+++ b/drivers/hid/hid-nintendo.c
|
|
@@ -233,6 +233,13 @@ enum joycon_ctlr_state {
|
|
JOYCON_CTLR_STATE_REMOVED,
|
|
};
|
|
|
|
+/* Controller type received as part of device info */
|
|
+enum joycon_ctlr_type {
|
|
+ JOYCON_CTLR_TYPE_JCL = 0x01,
|
|
+ JOYCON_CTLR_TYPE_JCR = 0x02,
|
|
+ JOYCON_CTLR_TYPE_PRO = 0x03,
|
|
+};
|
|
+
|
|
struct joycon_stick_cal {
|
|
s32 max;
|
|
s32 min;
|
|
@@ -321,6 +328,7 @@ struct joycon_ctlr {
|
|
spinlock_t lock;
|
|
u8 mac_addr[6];
|
|
char *mac_addr_str;
|
|
+ enum joycon_ctlr_type ctlr_type;
|
|
|
|
/* The following members are used for synchronous sends/receives */
|
|
enum joycon_msg_type msg_type;
|
|
@@ -359,6 +367,26 @@ struct joycon_ctlr {
|
|
u16 rumble_rh_freq;
|
|
};
|
|
|
|
+/* Helper macros for checking controller type */
|
|
+#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)
|
|
+#define jc_type_is_procon(ctlr) \
|
|
+ (ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON)
|
|
+#define jc_type_is_chrggrip(ctlr) \
|
|
+ (ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP)
|
|
+
|
|
+/* Does this controller have inputs associated with left joycon? */
|
|
+#define jc_type_has_left(ctlr) \
|
|
+ (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL || \
|
|
+ ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
|
|
+
|
|
+/* Does this controller have inputs associated with right joycon? */
|
|
+#define jc_type_has_right(ctlr) \
|
|
+ (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \
|
|
+ ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
|
|
+
|
|
static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
|
|
{
|
|
u8 *buf;
|
|
@@ -655,7 +683,6 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
|
unsigned long flags;
|
|
u8 tmp;
|
|
u32 btns;
|
|
- u32 id = ctlr->hdev->product;
|
|
unsigned long msecs = jiffies_to_msecs(jiffies);
|
|
|
|
spin_lock_irqsave(&ctlr->lock, flags);
|
|
@@ -694,7 +721,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 (id != USB_DEVICE_ID_NINTENDO_JOYCONR) {
|
|
+ if (jc_type_has_left(ctlr)) {
|
|
u16 raw_x;
|
|
u16 raw_y;
|
|
s32 x;
|
|
@@ -718,7 +745,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
|
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) {
|
|
+ if (jc_type_is_joycon(ctlr)) {
|
|
/* 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);
|
|
@@ -750,7 +777,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
|
input_report_abs(dev, ABS_HAT0Y, haty);
|
|
}
|
|
}
|
|
- if (id != USB_DEVICE_ID_NINTENDO_JOYCONL) {
|
|
+ if (jc_type_has_right(ctlr)) {
|
|
u16 raw_x;
|
|
u16 raw_y;
|
|
s32 x;
|
|
@@ -770,7 +797,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
|
/* report buttons */
|
|
input_report_key(dev, BTN_TR, btns & JC_BTN_R);
|
|
input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR);
|
|
- if (id != USB_DEVICE_ID_NINTENDO_PROCON) {
|
|
+ if (jc_type_is_joycon(ctlr)) {
|
|
/* Report the S buttons as the non-existent triggers */
|
|
input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R);
|
|
input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R);
|
|
@@ -989,6 +1016,12 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
|
case USB_DEVICE_ID_NINTENDO_PROCON:
|
|
name = "Nintendo Switch Pro Controller";
|
|
break;
|
|
+ case USB_DEVICE_ID_NINTENDO_CHRGGRIP:
|
|
+ if (jc_type_has_left(ctlr))
|
|
+ name = "Nintendo Switch Left Joy-Con (Grip)";
|
|
+ else
|
|
+ name = "Nintendo Switch Right Joy-Con (Grip)";
|
|
+ break;
|
|
case USB_DEVICE_ID_NINTENDO_JOYCONL:
|
|
name = "Nintendo Switch Left Joy-Con";
|
|
break;
|
|
@@ -1011,9 +1044,8 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
|
ctlr->input->name = name;
|
|
input_set_drvdata(ctlr->input, ctlr);
|
|
|
|
-
|
|
/* set up sticks and buttons */
|
|
- if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONR) {
|
|
+ if (jc_type_has_left(ctlr)) {
|
|
input_set_abs_params(ctlr->input, ABS_X,
|
|
-JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
|
|
JC_STICK_FUZZ, JC_STICK_FLAT);
|
|
@@ -1039,7 +1071,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
|
JC_DPAD_FUZZ, JC_DPAD_FLAT);
|
|
}
|
|
}
|
|
- if (hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONL) {
|
|
+ if (jc_type_has_right(ctlr)) {
|
|
input_set_abs_params(ctlr->input, ABS_RX,
|
|
-JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
|
|
JC_STICK_FUZZ, JC_STICK_FLAT);
|
|
@@ -1207,7 +1239,7 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
|
|
mutex_unlock(&joycon_input_num_mutex);
|
|
|
|
/* configure the home LED */
|
|
- if (ctlr->hdev->product != USB_DEVICE_ID_NINTENDO_JOYCONL) {
|
|
+ if (jc_type_has_right(ctlr)) {
|
|
name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", d_name, "home");
|
|
if (!name)
|
|
return ret;
|
|
@@ -1320,7 +1352,7 @@ static int joycon_power_supply_create(struct joycon_ctlr *ctlr)
|
|
return 0;
|
|
}
|
|
|
|
-static int joycon_read_mac(struct joycon_ctlr *ctlr)
|
|
+static int joycon_read_info(struct joycon_ctlr *ctlr)
|
|
{
|
|
int ret;
|
|
int i;
|
|
@@ -1352,6 +1384,9 @@ static int joycon_read_mac(struct joycon_ctlr *ctlr)
|
|
return -ENOMEM;
|
|
hid_info(ctlr->hdev, "controller MAC = %s\n", ctlr->mac_addr_str);
|
|
|
|
+ /* Retrieve the type so we can distinguish for charging grip */
|
|
+ ctlr->ctlr_type = report->reply.data[2];
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1487,7 +1522,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 (hdev->product == USB_DEVICE_ID_NINTENDO_PROCON &&
|
|
+ if ((jc_type_is_procon(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 */
|
|
@@ -1507,6 +1542,10 @@ static int nintendo_hid_probe(struct hid_device *hdev,
|
|
* This doesn't send a response, so ignore the timeout.
|
|
*/
|
|
joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
|
|
+ } else if (jc_type_is_chrggrip(ctlr)) {
|
|
+ hid_err(hdev, "Failed charging grip handshake\n");
|
|
+ ret = -ETIMEDOUT;
|
|
+ goto err_mutex;
|
|
}
|
|
|
|
/* get controller calibration data, and parse it */
|
|
@@ -1533,9 +1572,9 @@ static int nintendo_hid_probe(struct hid_device *hdev,
|
|
goto err_mutex;
|
|
}
|
|
|
|
- ret = joycon_read_mac(ctlr);
|
|
+ ret = joycon_read_info(ctlr);
|
|
if (ret) {
|
|
- hid_err(hdev, "Failed to retrieve controller MAC; ret=%d\n",
|
|
+ hid_err(hdev, "Failed to retrieve controller info; ret=%d\n",
|
|
ret);
|
|
goto err_close;
|
|
}
|
|
@@ -1603,6 +1642,8 @@ static const struct hid_device_id nintendo_hid_devices[] = {
|
|
USB_DEVICE_ID_NINTENDO_PROCON) },
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
|
USB_DEVICE_ID_NINTENDO_PROCON) },
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
|
|
+ USB_DEVICE_ID_NINTENDO_CHRGGRIP) },
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
|
USB_DEVICE_ID_NINTENDO_JOYCONL) },
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|