Merge branch 'for-5.15/sony' into for-linus
[linux-2.6-microblaze.git] / drivers / hid / hid-sony.c
index a2fef59..d1b107d 100644 (file)
@@ -11,8 +11,9 @@
  *  Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
  *  Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
  *  Copyright (c) 2018 Todd Kelner
- *  Copyright (c) 2020 Pascal Giard <pascal.giard@etsmtl.ca>
+ *  Copyright (c) 2020-2021 Pascal Giard <pascal.giard@etsmtl.ca>
  *  Copyright (c) 2020 Sanjay Govind <sanjay.govind9@gmail.com>
+ *  Copyright (c) 2021 Daniel Nguyen <daniel.nguyen.1@ens.etsmtl.ca>
  */
 
 /*
@@ -62,6 +63,7 @@
 #define SHANWAN_GAMEPAD           BIT(16)
 #define GH_GUITAR_CONTROLLER      BIT(17)
 #define GHL_GUITAR_PS3WIIU        BIT(18)
+#define GHL_GUITAR_PS4            BIT(19)
 
 #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
 #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
 #define NSG_MRXU_MAX_X 1667
 #define NSG_MRXU_MAX_Y 1868
 
-#define GHL_GUITAR_POKE_INTERVAL 10 /* In seconds */
+/* The PS3/Wii U dongles require a poke every 10 seconds, but the PS4
+ * requires one every 8 seconds. Using 8 seconds for all for simplicity.
+ */
+#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */
 #define GUITAR_TILT_USAGE 44
 
-/* Magic value and data taken from GHLtarUtility:
+/* Magic data taken from GHLtarUtility:
  * https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs
  * Note: The Wii U and PS3 dongles happen to share the same!
  */
-static const u16 ghl_ps3wiiu_magic_value = 0x201;
 static const char ghl_ps3wiiu_magic_data[] = {
        0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+/* Magic data for the PS4 dongles sniffed with a USB protocol
+ * analyzer.
+ */
+static const char ghl_ps4_magic_data[] = {
+       0x30, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
 /* PS/3 Motion controller */
 static u8 motion_rdesc[] = {
        0x05, 0x01,         /*  Usage Page (Desktop),               */
@@ -642,14 +653,14 @@ static void ghl_magic_poke(struct timer_list *t)
                hid_err(sc->hdev, "usb_submit_urb failed: %d", ret);
 }
 
-static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
+static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev,
+                                          const char ghl_magic_data[], u16 poke_size)
 {
        struct usb_ctrlrequest *cr;
-       u16 poke_size;
        u8 *databuf;
        unsigned int pipe;
+       u16 ghl_magic_value = (((HID_OUTPUT_REPORT + 1) << 8) | ghl_magic_data[0]);
 
-       poke_size = ARRAY_SIZE(ghl_ps3wiiu_magic_data);
        pipe = usb_sndctrlpipe(usbdev, 0);
 
        cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC);
@@ -663,10 +674,10 @@ static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
        cr->bRequestType =
                USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
        cr->bRequest = USB_REQ_SET_CONFIGURATION;
-       cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
+       cr->wValue = cpu_to_le16(ghl_magic_value);
        cr->wIndex = 0;
        cr->wLength = cpu_to_le16(poke_size);
-       memcpy(databuf, ghl_ps3wiiu_magic_data, poke_size);
+       memcpy(databuf, ghl_magic_data, poke_size);
        usb_fill_control_urb(
                sc->ghl_urb, usbdev, pipe,
                (unsigned char *) cr, databuf, poke_size,
@@ -3031,11 +3042,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return -ENODEV;
        }
 
-       if (sc->quirks & GHL_GUITAR_PS3WIIU) {
+       if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
                sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
                if (!sc->ghl_urb)
                        return -ENOMEM;
-               ret = ghl_init_urb(sc, usbdev);
+
+               if (sc->quirks & GHL_GUITAR_PS3WIIU)
+                       ret = ghl_init_urb(sc, usbdev, ghl_ps3wiiu_magic_data,
+                                                          ARRAY_SIZE(ghl_ps3wiiu_magic_data));
+               else if (sc->quirks & GHL_GUITAR_PS4)
+                       ret = ghl_init_urb(sc, usbdev, ghl_ps4_magic_data,
+                                                          ARRAY_SIZE(ghl_ps4_magic_data));
                if (ret) {
                        hid_err(hdev, "error preparing URB\n");
                        return ret;
@@ -3053,7 +3070,7 @@ static void sony_remove(struct hid_device *hdev)
 {
        struct sony_sc *sc = hid_get_drvdata(hdev);
 
-       if (sc->quirks & GHL_GUITAR_PS3WIIU) {
+       if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
                del_timer_sync(&sc->ghl_poke_timer);
                usb_free_urb(sc->ghl_urb);
        }
@@ -3173,11 +3190,14 @@ static const struct hid_device_id sony_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE),
                .driver_data = GHL_GUITAR_PS3WIIU | GH_GUITAR_CONTROLLER },
        /* Guitar Hero PC Guitar Dongle */
-       { HID_USB_DEVICE(USB_VENDOR_ID_ACTIVISION, USB_DEVICE_ID_ACTIVISION_GUITAR_DONGLE),
+       { HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_GUITAR_DONGLE),
                .driver_data = GH_GUITAR_CONTROLLER },
        /* Guitar Hero PS3 World Tour Guitar Dongle */
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3_GUITAR_DONGLE),
                .driver_data = GH_GUITAR_CONTROLLER },
+       /* Guitar Hero Live PS4 guitar dongles */
+       { HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_PS4_GHLIVE_DONGLE),
+               .driver_data = GHL_GUITAR_PS4 | GH_GUITAR_CONTROLLER },
        { }
 };
 MODULE_DEVICE_TABLE(hid, sony_devices);