USB: serial: move pl2303 hack out of usb-serial core
authorJohan Hovold <johan@kernel.org>
Thu, 16 Mar 2017 16:13:34 +0000 (17:13 +0100)
committerJohan Hovold <johan@kernel.org>
Tue, 28 Mar 2017 08:59:01 +0000 (10:59 +0200)
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 <johan@kernel.org>
drivers/usb/serial/pl2303.c
drivers/usb/serial/usb-serial.c

index 60840004568a4d434023c81eaf61de151f9df10c..b8edd7bc71f2a29958328f8b420d911265450254 100644 (file)
@@ -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,
index 101eb105d78e583913cbe24eb41dfa55763d5a69..0fa2030c275c6af952fa74e2dbf986342c3329c1 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/usb/serial.h>
 #include <linux/kfifo.h>
 #include <linux/idr.h>
-#include "pl2303.h"
 
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
 #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 ||