HID: add support for DragonRise PID 0011 gamepad
authorNikolai Kondrashov <spbnick@gmail.com>
Fri, 28 Jan 2011 11:50:52 +0000 (14:50 +0300)
committerJiri Kosina <jkosina@suse.cz>
Tue, 1 Feb 2011 10:01:06 +0000 (11:01 +0100)
Add support for DragonRise Inc. gamepad with USB PID 0x0011 by fixing its report
descriptor. This mainly removes spurious axis.

Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-core.c
drivers/hid/hid-dr.c

index d678cf3d33d5eaf80ab46a7ea58bcd369637c308..75af1f83532011b5b9a2c28796c8d6584b27fcc0 100644 (file)
@@ -1328,6 +1328,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
index afcf3d67eb024683cc43e11f5325184ce8235871..61eece47204d370f4d66de3d672be96468da42e8 100644 (file)
@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid)
 }
 #endif
 
+/*
+ * The original descriptor of joystick with PID 0x0011, represented by DVTech PC
+ * JS19. It seems both copied from another device and a result of confusion
+ * either about the specification or about the program used to create the
+ * descriptor. In any case, it's a wonder it works on Windows.
+ *
+ *  Usage Page (Desktop),             ; Generic desktop controls (01h)
+ *  Usage (Joystik),                  ; Joystik (04h, application collection)
+ *  Collection (Application),
+ *    Collection (Logical),
+ *      Report Size (8),
+ *      Report Count (5),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Physical Minimum (0),
+ *      Physical Maximum (255),
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Usage (Y),                    ; Y (31h, dynamic value)
+ *      Input (Variable),
+ *      Report Size (4),
+ *      Report Count (1),
+ *      Logical Maximum (7),
+ *      Physical Maximum (315),
+ *      Unit (Degrees),
+ *      Usage (00h),
+ *      Input (Variable, Null State),
+ *      Unit,
+ *      Report Size (1),
+ *      Report Count (10),
+ *      Logical Maximum (1),
+ *      Physical Maximum (1),
+ *      Usage Page (Button),          ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (0Ah),
+ *      Input (Variable),
+ *      Usage Page (FF00h),           ; FF00h, vendor-defined
+ *      Report Size (1),
+ *      Report Count (10),
+ *      Logical Maximum (1),
+ *      Physical Maximum (1),
+ *      Usage (01h),
+ *      Input (Variable),
+ *    End Collection,
+ *    Collection (Logical),
+ *      Report Size (8),
+ *      Report Count (4),
+ *      Physical Maximum (255),
+ *      Logical Maximum (255),
+ *      Usage (02h),
+ *      Output (Variable),
+ *    End Collection,
+ *  End Collection
+ */
+
+/* Size of the original descriptor of the PID 0x0011 joystick */
+#define PID0011_RDESC_ORIG_SIZE        101
+
+/* Fixed report descriptor for PID 0x011 joystick */
+static __u8 pid0011_rdesc_fixed[] = {
+       0x05, 0x01,         /*  Usage Page (Desktop),           */
+       0x09, 0x04,         /*  Usage (Joystik),                */
+       0xA1, 0x01,         /*  Collection (Application),       */
+       0xA1, 0x02,         /*      Collection (Logical),       */
+       0x14,               /*          Logical Minimum (0),    */
+       0x75, 0x08,         /*          Report Size (8),        */
+       0x95, 0x03,         /*          Report Count (3),       */
+       0x81, 0x01,         /*          Input (Constant),       */
+       0x26, 0xFF, 0x00,   /*          Logical Maximum (255),  */
+       0x95, 0x02,         /*          Report Count (2),       */
+       0x09, 0x30,         /*          Usage (X),              */
+       0x09, 0x31,         /*          Usage (Y),              */
+       0x81, 0x02,         /*          Input (Variable),       */
+       0x75, 0x01,         /*          Report Size (1),        */
+       0x95, 0x04,         /*          Report Count (4),       */
+       0x81, 0x01,         /*          Input (Constant),       */
+       0x25, 0x01,         /*          Logical Maximum (1),    */
+       0x95, 0x0A,         /*          Report Count (10),      */
+       0x05, 0x09,         /*          Usage Page (Button),    */
+       0x19, 0x01,         /*          Usage Minimum (01h),    */
+       0x29, 0x0A,         /*          Usage Maximum (0Ah),    */
+       0x81, 0x02,         /*          Input (Variable),       */
+       0x95, 0x0A,         /*          Report Count (10),      */
+       0x81, 0x01,         /*          Input (Constant),       */
+       0xC0,               /*      End Collection,             */
+       0xC0                /*  End Collection                  */
+};
+
+static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+                               unsigned int *rsize)
+{
+       switch (hdev->product) {
+       case 0x0011:
+               if (*rsize == PID0011_RDESC_ORIG_SIZE) {
+                       rdesc = pid0011_rdesc_fixed;
+                       *rsize = sizeof(pid0011_rdesc_fixed);
+               }
+               break;
+       }
+       return rdesc;
+}
+
 static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
@@ -163,7 +267,16 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err;
        }
 
-       drff_init(hdev);
+       switch (hdev->product) {
+       case 0x0006:
+               ret = drff_init(hdev);
+               if (ret) {
+                       dev_err(&hdev->dev, "force feedback init failed\n");
+                       hid_hw_stop(hdev);
+                       goto err;
+               }
+               break;
+       }
 
        return 0;
 err:
@@ -172,6 +285,7 @@ err:
 
 static const struct hid_device_id dr_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011),  },
        { }
 };
 MODULE_DEVICE_TABLE(hid, dr_devices);
@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices);
 static struct hid_driver dr_driver = {
        .name = "dragonrise",
        .id_table = dr_devices,
+       .report_fixup = dr_report_fixup,
        .probe = dr_probe,
 };