From 9fda620a5f3d7711d0b27d36eeec3a24a097af97 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:34 +0100 Subject: [PATCH] USB: serial: move pl2303 hack out of usb-serial core Some pl2303 devices require the use of the interrupt endpoint of an unrelated interface. This has so far been dealt with in usb-serial core, but can now be moved to a driver calc_num_ports callback. Note that we relax the endpoint requirements checked by core and instead verify that we have an interrupt-in endpoint in calc_num_ports for all devices so that the hack can first be applied. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 57 +++++++++++++++++++++++++++++++++++++++-- drivers/usb/serial/usb-serial.c | 40 ----------------------------- 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6084000..b8edd7b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -218,6 +218,59 @@ static int pl2303_probe(struct usb_serial *serial, return 0; } +static int pl2303_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + struct usb_interface *interface = serial->interface; + struct usb_device *dev = serial->dev; + struct device *ddev = &interface->dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + unsigned int i; + + /* BEGIN HORRIBLE HACK FOR PL2303 */ + /* this is needed due to the looney way its endpoints are set up */ + if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) && + (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) || + ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) && + (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) || + ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) && + (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) || + ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) && + (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) { + if (interface != dev->actconfig->interface[0]) { + /* check out the endpoints of the other interface*/ + iface_desc = dev->actconfig->interface[0]->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_int_in(endpoint)) { + /* we found a interrupt in endpoint */ + dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); + if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in)) + epds->interrupt_in[epds->num_interrupt_in++] = endpoint; + } + } + } + + /* Now make sure the PL-2303 is configured correctly. + * If not, give up now and hope this hack will work + * properly during a later invocation of usb_serial_probe + */ + if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) { + dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); + return -ENODEV; + } + } + /* END HORRIBLE HACK FOR PL2303 */ + + if (epds->num_interrupt_in < 1) { + dev_err(ddev, "required interrupt-in endpoint missing\n"); + return -ENODEV; + } + + return 1; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; @@ -930,10 +983,9 @@ static struct usb_serial_driver pl2303_device = { .name = "pl2303", }, .id_table = id_table, - .num_ports = 1, .num_bulk_in = 1, .num_bulk_out = 1, - .num_interrupt_in = 1, + .num_interrupt_in = 0, /* see pl2303_calc_num_ports */ .bulk_in_size = 256, .bulk_out_size = 256, .open = pl2303_open, @@ -949,6 +1001,7 @@ static struct usb_serial_driver pl2303_device = { .process_read_urb = pl2303_process_read_urb, .read_int_callback = pl2303_read_int_callback, .probe = pl2303_probe, + .calc_num_ports = pl2303_calc_num_ports, .attach = pl2303_startup, .release = pl2303_release, .port_probe = pl2303_port_probe, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 101eb10..0fa2030 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -38,7 +38,6 @@ #include #include #include -#include "pl2303.h" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB Serial Driver core" @@ -803,45 +802,6 @@ static int usb_serial_probe(struct usb_interface *interface, find_endpoints(serial, epds); -#if IS_ENABLED(CONFIG_USB_SERIAL_PL2303) - /* BEGIN HORRIBLE HACK FOR PL2303 */ - /* this is needed due to the looney way its endpoints are set up */ - if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) { - if (interface != dev->actconfig->interface[0]) { - struct usb_host_interface *iface_desc; - - /* check out the endpoints of the other interface*/ - iface_desc = dev->actconfig->interface[0]->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_int_in(endpoint)) { - /* we found a interrupt in endpoint */ - dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); - if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in)) - epds->interrupt_in[epds->num_interrupt_in++] = endpoint; - } - } - } - - /* Now make sure the PL-2303 is configured correctly. - * If not, give up now and hope this hack will work - * properly during a later invocation of usb_serial_probe - */ - if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) { - dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); - retval = -ENODEV; - goto err_free_epds; - } - } - /* END HORRIBLE HACK FOR PL2303 */ -#endif if (epds->num_bulk_in < type->num_bulk_in || epds->num_bulk_out < type->num_bulk_out || epds->num_interrupt_in < type->num_interrupt_in || -- 2.7.4