[PATCH 2/2] Use usb_skelswitch module to switch Logitech G920 Racing Wheel to HID mode.

From: Michal MalÃ
Date: Sat Jan 23 2016 - 05:35:48 EST


Tested-by: Elias Vanderstuyft <elias.vds@xxxxxxxxx>
Signed-off-by: Michal Malà <madcatxster@xxxxxxxxxxxxxxxxxx>
---
drivers/usb/common/Kconfig | 2 ++
drivers/usb/common/usb-skelswitch.c | 60 +++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)

diff --git a/drivers/usb/common/Kconfig b/drivers/usb/common/Kconfig
index 6d9ec79..8ae9a1e 100644
--- a/drivers/usb/common/Kconfig
+++ b/drivers/usb/common/Kconfig
@@ -11,5 +11,7 @@ config USB_SKELSWITCH
appear as a generic USB device.

Say Y if you intend to use a device that requires this initial switch.
+ Devices that currently require this module:
+ - Logitech G920 Racing Wheel

endif # USB_COMMON
diff --git a/drivers/usb/common/usb-skelswitch.c b/drivers/usb/common/usb-skelswitch.c
index ae72068..fc85c70 100644
--- a/drivers/usb/common/usb-skelswitch.c
+++ b/drivers/usb/common/usb-skelswitch.c
@@ -14,10 +14,70 @@ struct usb_skelswitch_vendor {
};

static const struct usb_device_id usb_skelswitch_table[] = {
+ { USB_DEVICE(0x046d, 0xc261) },
{ }
};

+MODULE_DEVICE_TABLE(usb, usb_skelswitch_table);
+
+static int usb_skelswitch_lg_g920(struct usb_interface *intf)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev;
+ int idx;
+ int ret;
+ int xferred;
+ size_t buffer_size;
+ unsigned char cmd[] = { 0x0f, 0x00, 0x01, 0x01, 0x42 };
+ const size_t cmd_len = ARRAY_SIZE(cmd);
+ u8 intr_out_addr = 0;
+
+ udev = usb_get_dev(interface_to_usbdev(intf));
+ iface_desc = intf->cur_altsetting;
+ for (idx = 0; idx < iface_desc->desc.bNumEndpoints; idx++) {
+ endpoint = &iface_desc->endpoint[idx].desc;
+
+ if (usb_endpoint_is_int_out(endpoint)) {
+ intr_out_addr = endpoint->bEndpointAddress;
+ buffer_size = usb_endpoint_maxp(endpoint);
+ break;
+ }
+ }
+
+ if (!intr_out_addr) {
+ dev_err(&udev->dev, "Logitech G920 - No interrupt out endpoint found");
+ return -ENODEV;
+ }
+
+ if (buffer_size < cmd_len) {
+ dev_err(&udev->dev, "usb_skelswitch: Logitech G920 - Output buffer is too small");
+ return -ENODEV;
+ }
+
+
+ ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, intr_out_addr),
+ cmd, cmd_len, &xferred, USB_CTRL_SET_TIMEOUT);
+
+ if (ret) {
+ dev_err(&udev->dev, "LG G920: Failed to submit URB, errno: %d", ret);
+ return ret;
+ }
+ if (xferred != cmd_len) {
+ dev_err(&udev->dev, "LG G920: Incorrect number of bytes transferred: %d", xferred);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct usb_skelswitch_product usb_skelswitch_logitech_devs[] = {
+ { 0xc261, usb_skelswitch_lg_g920 },
+ { 0, NULL }
+};
+
static const struct usb_skelswitch_vendor usb_skelswitch_vendors[] = {
+ { 0x046d, usb_skelswitch_logitech_devs },
{ 0, NULL }
};

--
2.7.0