Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e05eefb9 authored by Nikolai Kondrashov's avatar Nikolai Kondrashov Committed by Jiri Kosina
Browse files

HID: add support for DragonRise PID 0011 gamepad



Add support for DragonRise Inc. gamepad with USB PID 0x0011 by fixing its report
descriptor. This mainly removes spurious axis.

Signed-off-by: default avatarNikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 152fd634
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -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_MOUSE) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
	{ 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, 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_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_MULTITOUCH1) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+116 −1
Original line number Original line Diff line number Diff line
@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid)
}
}
#endif
#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)
static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
{
	int ret;
	int ret;
@@ -163,7 +267,16 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
		goto err;
		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;
	return 0;
err:
err:
@@ -172,6 +285,7 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)


static const struct hid_device_id dr_devices[] = {
static const struct hid_device_id dr_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006),  },
	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011),  },
	{ }
	{ }
};
};
MODULE_DEVICE_TABLE(hid, dr_devices);
MODULE_DEVICE_TABLE(hid, dr_devices);
@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices);
static struct hid_driver dr_driver = {
static struct hid_driver dr_driver = {
	.name = "dragonrise",
	.name = "dragonrise",
	.id_table = dr_devices,
	.id_table = dr_devices,
	.report_fixup = dr_report_fixup,
	.probe = dr_probe,
	.probe = dr_probe,
};
};