diff options
-rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
-rw-r--r-- | 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 6b698c64bf52..896b252daa10 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -920,6 +920,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 ac171ee5066a..ad054ca9080c 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; @@ -328,6 +335,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; @@ -366,6 +374,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; @@ -662,7 +690,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); @@ -701,7 +728,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; @@ -725,7 +752,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); @@ -757,7 +784,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; @@ -777,7 +804,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); @@ -996,6 +1023,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; @@ -1018,9 +1051,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); @@ -1046,7 +1078,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); @@ -1209,7 +1241,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:%s", d_name, "blue", @@ -1325,7 +1357,7 @@ static int joycon_power_supply_create(struct joycon_ctlr *ctlr) return power_supply_powers(ctlr->battery, &hdev->dev); } -static int joycon_read_mac(struct joycon_ctlr *ctlr) +static int joycon_read_info(struct joycon_ctlr *ctlr) { int ret; int i; @@ -1357,6 +1389,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; } @@ -1490,7 +1525,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 */ @@ -1510,6 +1545,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 */ @@ -1536,9 +1575,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_mutex; } @@ -1606,6 +1645,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, |