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 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html