OSDN Git Service

USB: serial: metro-usb: add missing interrupt-out endpoint check
authorJohan Hovold <johan@kernel.org>
Thu, 12 Oct 2017 08:54:23 +0000 (10:54 +0200)
committerJohan Hovold <johan@kernel.org>
Fri, 13 Oct 2017 07:45:09 +0000 (09:45 +0200)
One class of "unidirectional" devices managed by this driver uses an
interrupt-out endpoint to send control messages at open and close. Due
to a missing endpoint sanity check, this could result in an interrupt
URB being submitted to endpoint 0 instead. This would be caught by
USB core (without a WARN dump), but let's verify that the expected
endpoints are present at probe rather than when a port is later opened.

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
drivers/usb/serial/metro-usb.c

index a649409..f16915b 100644 (file)
@@ -53,21 +53,33 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define UNI_CMD_OPEN   0x80
 #define UNI_CMD_CLOSE  0xFF
 
-static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+static int metrousb_is_unidirectional_mode(struct usb_serial *serial)
 {
-       __u16 product_id = le16_to_cpu(
-               port->serial->dev->descriptor.idProduct);
+       u16 product_id = le16_to_cpu(serial->dev->descriptor.idProduct);
 
        return product_id == FOCUS_PRODUCT_ID_UNI;
 }
 
+static int metrousb_calc_num_ports(struct usb_serial *serial,
+                                  struct usb_serial_endpoints *epds)
+{
+       if (metrousb_is_unidirectional_mode(serial)) {
+               if (epds->num_interrupt_out == 0) {
+                       dev_err(&serial->interface->dev, "interrupt-out endpoint missing\n");
+                       return -ENODEV;
+               }
+       }
+
+       return 1;
+}
+
 static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
 {
        int ret;
        int actual_len;
        u8 *buffer_cmd = NULL;
 
-       if (!metrousb_is_unidirectional_mode(port))
+       if (!metrousb_is_unidirectional_mode(port->serial))
                return 0;
 
        buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
@@ -334,8 +346,8 @@ static struct usb_serial_driver metrousb_device = {
        },
        .description            = "Metrologic USB to Serial",
        .id_table               = id_table,
-       .num_ports              = 1,
        .num_interrupt_in       = 1,
+       .calc_num_ports         = metrousb_calc_num_ports,
        .open                   = metrousb_open,
        .close                  = metrousb_cleanup,
        .read_int_callback      = metrousb_read_int_callback,