diff options
author | Johan Hovold <johan@kernel.org> | 2017-10-12 11:54:23 +0300 |
---|---|---|
committer | Johan Hovold <johan@kernel.org> | 2017-10-13 10:45:09 +0300 |
commit | ee13a25fc355650b3acf43857b7a496eb6b07f0b (patch) | |
tree | 748ff505fb70d5a48a75ae9923151260a034b845 /drivers/usb/serial | |
parent | 6f792f471fad3ed16aca9ccedacdcd48fbedf7a9 (diff) | |
download | linux-ee13a25fc355650b3acf43857b7a496eb6b07f0b.tar.xz |
USB: serial: metro-usb: add missing interrupt-out endpoint check
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>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/metro-usb.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index a64940975ac6..f16915b457c9 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -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, |