summaryrefslogtreecommitdiff
path: root/drivers/usb/serial/metro-usb.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2017-10-12 10:54:23 +0200
committerJohan Hovold <johan@kernel.org>2017-10-13 09:45:09 +0200
commitee13a25fc355650b3acf43857b7a496eb6b07f0b (patch)
tree748ff505fb70d5a48a75ae9923151260a034b845 /drivers/usb/serial/metro-usb.c
parent6f792f471fad3ed16aca9ccedacdcd48fbedf7a9 (diff)
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/metro-usb.c')
-rw-r--r--drivers/usb/serial/metro-usb.c22
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,