From 2dea7cd7287781cd4bfd0167dba423e0f486ef61 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Mar 2017 16:02:57 +0000 Subject: [PATCH 01/61] USB: serial: ftdi_sio: don't access latency timer on old chips The latency timer was introduced with the FT232BM and FT245BM chips. Do not bother attempting to read or write it for older chip versions. Signed-off-by: Ian Abbott Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c540de15aad2..72314734dfd0 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1406,6 +1406,9 @@ static int write_latency_timer(struct usb_serial_port *port) int rv; int l = priv->latency; + if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + return -EINVAL; + if (priv->flags & ASYNC_LOW_LATENCY) l = 1; @@ -1429,6 +1432,9 @@ static int read_latency_timer(struct usb_serial_port *port) unsigned char *buf; int rv; + if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + return -EINVAL; + buf = kmalloc(1, GFP_KERNEL); if (!buf) return -ENOMEM; From 7e1e6ceda3f07a40445ae1c4ac5549a899d5e252 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Mar 2017 16:02:58 +0000 Subject: [PATCH 02/61] USB: serial: ftdi_sio: detect BM chip with iSerialNumber bug If a BM type chip has iSerialNumber set to 0 in its EEPROM, an incorrect value is read from the bcdDevice field of the USB descriptor, making it look like an AM type chip. Attempt to correct this in ftdi_determine_type() by attempting to read the latency timer for an AM type chip if it has iSerialNumber set to 0. If that succeeds, assume it is a BM type chip. Currently, read_latency_timer() bails out without reading the latency timer for an AM type chip, so factor out the guts of read_latency_timer() into a new function _read_latency_timer() that attempts to read the latency timer regardless of chip type, and returns either the latency timer value or a negative error number. Signed-off-by: Ian Abbott Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 41 ++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 72314734dfd0..2b9b5119ff13 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1425,16 +1425,13 @@ static int write_latency_timer(struct usb_serial_port *port) return rv; } -static int read_latency_timer(struct usb_serial_port *port) +static int _read_latency_timer(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_device *udev = port->serial->dev; unsigned char *buf; int rv; - if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) - return -EINVAL; - buf = kmalloc(1, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1446,11 +1443,10 @@ static int read_latency_timer(struct usb_serial_port *port) 0, priv->interface, buf, 1, WDR_TIMEOUT); if (rv < 1) { - dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); if (rv >= 0) rv = -EIO; } else { - priv->latency = buf[0]; + rv = buf[0]; } kfree(buf); @@ -1458,6 +1454,25 @@ static int read_latency_timer(struct usb_serial_port *port) return rv; } +static int read_latency_timer(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + int rv; + + if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + return -EINVAL; + + rv = _read_latency_timer(port); + if (rv < 0) { + dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); + return rv; + } + + priv->latency = rv; + + return 0; +} + static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) { @@ -1609,9 +1624,19 @@ static void ftdi_determine_type(struct usb_serial_port *port) priv->baud_base = 12000000 / 16; } else if (version < 0x400) { /* Assume it's an FT8U232AM (or FT8U245AM) */ - /* (It might be a BM because of the iSerialNumber bug, - * but it will still work as an AM device.) */ priv->chip_type = FT8U232AM; + /* + * It might be a BM type because of the iSerialNumber bug. + * If iSerialNumber==0 and the latency timer is readable, + * assume it is BM type. + */ + if (udev->descriptor.iSerialNumber == 0 && + _read_latency_timer(port) >= 0) { + dev_dbg(&port->dev, + "%s: has latency timer so not an AM type\n", + __func__); + priv->chip_type = FT232BM; + } } else if (version < 0x600) { /* Assume it's an FT232BM (or FT245BM) */ priv->chip_type = FT232BM; From db9240662a44e1b7781c8dbf35631bcec7a369c6 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Mar 2017 16:02:59 +0000 Subject: [PATCH 03/61] USB: serial: ftdi_sio: only allow valid latency timer values Valid latency timer values are between 1 ms and 255 ms in 1 ms steps. The store function for the "latency_timer" device attribute currently allows any value, although only the lower 16 bits will be sent to the device, and the device only stores the lower 8 bits. The hardware appears to accept the (invalid) value 0 and treats it the same as 1 (resulting in a latency of 1 ms). Change the latency_timer_store() function to accept only the values 0 to 255, returning an error -EINVAL for out-of-range values. Call kstrtou8() to parse the integer instead of the obsolete simple_strtoul(). Signed-off-by: Ian Abbott Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2b9b5119ff13..b774f9d32d4f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1716,9 +1716,12 @@ static ssize_t latency_timer_store(struct device *dev, { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - int v = simple_strtoul(valbuf, NULL, 10); + u8 v; int rv; + if (kstrtou8(valbuf, 10, &v)) + return -EINVAL; + priv->latency = v; rv = write_latency_timer(port); if (rv < 0) From d0559a2f294c9b50d7795a8362931f0db8953de1 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Mar 2017 16:03:00 +0000 Subject: [PATCH 04/61] USB: serial: ftdi_sio: only allow valid event_char values The "event_char" device attribute value, when written, is interpreted as an enable bit in bit 8, and an "event character" in bits 7 to 0. Return an error -EINVAL for out-of-range values. Use kstrtouint() to parse the integer instead of the obsolete simple_strtoul(). Signed-off-by: Ian Abbott Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b774f9d32d4f..4032a675643c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1738,9 +1738,12 @@ static ssize_t store_event_char(struct device *dev, struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_device *udev = port->serial->dev; - int v = simple_strtoul(valbuf, NULL, 10); + unsigned int v; int rv; + if (kstrtouint(valbuf, 10, &v) || v >= 0x200) + return -EINVAL; + dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v); rv = usb_control_msg(udev, From f1ce25f292e7ef7a86e44ec4d30a7e179d3ddce0 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 8 Mar 2017 16:03:01 +0000 Subject: [PATCH 05/61] USB: serial: ftdi_sio: allow other bases for "event_char" The 'store' function for the "event_char" device attribute currently expects a base 10 value. The value is composed of an enable bit in bit 8 and an 8-bit "event character" code in bits 7 to 0. It seems reasonable to allow hexadecimal and octal numbers to be written to the device attribute in addition to decimal. Make it so. Change the debug message to show the value in hexadecimal, rather than decimal. Signed-off-by: Ian Abbott Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4032a675643c..546171289869 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1741,10 +1741,10 @@ static ssize_t store_event_char(struct device *dev, unsigned int v; int rv; - if (kstrtouint(valbuf, 10, &v) || v >= 0x200) + if (kstrtouint(valbuf, 0, &v) || v >= 0x200) return -EINVAL; - dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v); + dev_dbg(&port->dev, "%s: setting event char = 0x%03x\n", __func__, v); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), From c2fef4564cae387c2f724a95350084c2e9371250 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:14 +0100 Subject: [PATCH 06/61] USB: serial: clean up probe error paths Clean up the probe error paths by adding a couple of new error labels. Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4a037b4a79cf..c20d90ed1ef2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -752,8 +752,8 @@ static int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { - module_put(type->driver.owner); - return -ENOMEM; + retval = -ENOMEM; + goto err_put_module; } /* if this device type has a probe function, call it */ @@ -765,9 +765,7 @@ static int usb_serial_probe(struct usb_interface *interface, if (retval) { dev_dbg(ddev, "sub driver rejected device\n"); - usb_serial_put(serial); - module_put(type->driver.owner); - return retval; + goto err_put_serial; } } @@ -849,9 +847,8 @@ static int usb_serial_probe(struct usb_interface *interface, */ if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); - usb_serial_put(serial); - module_put(type->driver.owner); - return -ENODEV; + retval = -ENODEV; + goto err_put_serial; } } /* END HORRIBLE HACK FOR PL2303 */ @@ -862,9 +859,8 @@ static int usb_serial_probe(struct usb_interface *interface, num_ports = num_bulk_out; if (num_ports == 0) { dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); - usb_serial_put(serial); - module_put(type->driver.owner); - return -EIO; + retval = -EIO; + goto err_put_serial; } dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); @@ -1085,9 +1081,13 @@ exit: return 0; probe_error: + retval = -EIO; +err_put_serial: usb_serial_put(serial); +err_put_module: module_put(type->driver.owner); - return -EIO; + + return retval; } static void usb_serial_disconnect(struct usb_interface *interface) From ef88f33fc1ee0a12a1e5eee7e4f70b7743100a19 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:15 +0100 Subject: [PATCH 07/61] USB: serial: clean up endpoint and port-counter types Use unsigned-char type for the endpoint and port counters. Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 14 +++++++------- include/linux/usb/serial.h | 11 ++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c20d90ed1ef2..e5b859ad15c6 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -728,12 +728,12 @@ static int usb_serial_probe(struct usb_interface *interface, int buffer_size; int i; int j; - int num_interrupt_in = 0; - int num_interrupt_out = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; + unsigned char num_interrupt_in = 0; + unsigned char num_interrupt_out = 0; + unsigned char num_bulk_in = 0; + unsigned char num_bulk_out = 0; int num_ports = 0; - int max_endpoints; + unsigned char max_endpoints; mutex_lock(&table_lock); type = search_serial_device(interface); @@ -879,7 +879,7 @@ static int usb_serial_probe(struct usb_interface *interface, num_ports = MAX_NUM_PORTS; } - serial->num_ports = num_ports; + serial->num_ports = (unsigned char)num_ports; serial->num_bulk_in = num_bulk_in; serial->num_bulk_out = num_bulk_out; serial->num_interrupt_in = num_interrupt_in; @@ -894,7 +894,7 @@ static int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(num_bulk_in, num_bulk_out); max_endpoints = max(max_endpoints, num_interrupt_in); max_endpoints = max(max_endpoints, num_interrupt_out); - max_endpoints = max(max_endpoints, (int)serial->num_ports); + max_endpoints = max(max_endpoints, serial->num_ports); serial->num_port_pointers = max_endpoints; dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 704a1ab8240c..85b475933848 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -159,10 +159,10 @@ struct usb_serial { unsigned char minors_reserved:1; unsigned char num_ports; unsigned char num_port_pointers; - char num_interrupt_in; - char num_interrupt_out; - char num_bulk_in; - char num_bulk_out; + unsigned char num_interrupt_in; + unsigned char num_interrupt_out; + unsigned char num_bulk_in; + unsigned char num_bulk_out; struct usb_serial_port *port[MAX_NUM_PORTS]; struct kref kref; struct mutex disc_mutex; @@ -227,13 +227,14 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) struct usb_serial_driver { const char *description; const struct usb_device_id *id_table; - char num_ports; struct list_head driver_list; struct device_driver driver; struct usb_driver *usb_driver; struct usb_dynids dynids; + unsigned char num_ports; + size_t bulk_in_size; size_t bulk_out_size; From 1546e6aecb2490c4510bcd953cbb522d85957791 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 21 Aug 2014 19:33:25 +0200 Subject: [PATCH 08/61] USB: serial: refactor and clean up endpoint handling Refactor and clean up endpoint handling. This specifically moves the endpoint-descriptor arrays of the stack. Note that an err_free_epds label is not yet added to avoid a compilation warning when neither CONFIG_USB_SERIAL_PL2303 or CONFIG_USB_SERIAL_GENERIC is selected. Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 154 +++++++++++++++++--------------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e5b859ad15c6..09eb639298c8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -710,6 +710,53 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_port_shutdown, }; +struct usb_serial_endpoints { + unsigned char num_bulk_in; + unsigned char num_bulk_out; + unsigned char num_interrupt_in; + unsigned char num_interrupt_out; + struct usb_endpoint_descriptor *bulk_in[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *bulk_out[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *interrupt_in[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *interrupt_out[MAX_NUM_PORTS]; +}; + +static void find_endpoints(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + struct device *dev = &serial->interface->dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *epd; + unsigned int i; + + iface_desc = serial->interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + epd = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(epd)) { + dev_dbg(dev, "found bulk in on endpoint %u\n", i); + if (epds->num_bulk_in == MAX_NUM_PORTS) + continue; + epds->bulk_in[epds->num_bulk_in++] = epd; + } else if (usb_endpoint_is_bulk_out(epd)) { + dev_dbg(dev, "found bulk out on endpoint %u\n", i); + if (epds->num_bulk_out == MAX_NUM_PORTS) + continue; + epds->bulk_out[epds->num_bulk_out++] = epd; + } else if (usb_endpoint_is_int_in(epd)) { + dev_dbg(dev, "found interrupt in on endpoint %u\n", i); + if (epds->num_interrupt_in == MAX_NUM_PORTS) + continue; + epds->interrupt_in[epds->num_interrupt_in++] = epd; + } else if (usb_endpoint_is_int_out(epd)) { + dev_dbg(dev, "found interrupt out on endpoint %u\n", i); + if (epds->num_interrupt_out == MAX_NUM_PORTS) + continue; + epds->interrupt_out[epds->num_interrupt_out++] = epd; + } + } +} + static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -717,21 +764,13 @@ static int usb_serial_probe(struct usb_interface *interface, struct usb_device *dev = interface_to_usbdev(interface); struct usb_serial *serial = NULL; struct usb_serial_port *port; - struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; + struct usb_serial_endpoints *epds; struct usb_serial_driver *type = NULL; int retval; int buffer_size; int i; int j; - unsigned char num_interrupt_in = 0; - unsigned char num_interrupt_out = 0; - unsigned char num_bulk_in = 0; - unsigned char num_bulk_out = 0; int num_ports = 0; unsigned char max_endpoints; @@ -770,50 +809,14 @@ static int usb_serial_probe(struct usb_interface *interface, } /* descriptor matches, let's find the endpoints needed */ - /* check out the endpoints */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - dev_dbg(ddev, "found bulk in on endpoint %d\n", i); - if (num_bulk_in < MAX_NUM_PORTS) { - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - } - - if (usb_endpoint_is_bulk_out(endpoint)) { - /* we found a bulk out endpoint */ - dev_dbg(ddev, "found bulk out on endpoint %d\n", i); - if (num_bulk_out < MAX_NUM_PORTS) { - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } - } - - if (usb_endpoint_is_int_in(endpoint)) { - /* we found a interrupt in endpoint */ - dev_dbg(ddev, "found interrupt in on endpoint %d\n", i); - if (num_interrupt_in < MAX_NUM_PORTS) { - interrupt_in_endpoint[num_interrupt_in] = - endpoint; - ++num_interrupt_in; - } - } - - if (usb_endpoint_is_int_out(endpoint)) { - /* we found an interrupt out endpoint */ - dev_dbg(ddev, "found interrupt out on endpoint %d\n", i); - if (num_interrupt_out < MAX_NUM_PORTS) { - interrupt_out_endpoint[num_interrupt_out] = - endpoint; - ++num_interrupt_out; - } - } + epds = kzalloc(sizeof(*epds), GFP_KERNEL); + if (!epds) { + retval = -ENOMEM; + goto err_put_serial; } + 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 */ @@ -826,6 +829,8 @@ static int usb_serial_probe(struct usb_interface *interface, ((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) { @@ -833,10 +838,8 @@ static int usb_serial_probe(struct usb_interface *interface, 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 (num_interrupt_in < MAX_NUM_PORTS) { - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } + if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in)) + epds->interrupt_in[epds->num_interrupt_in++] = endpoint; } } } @@ -845,9 +848,10 @@ static int usb_serial_probe(struct usb_interface *interface, * If not, give up now and hope this hack will work * properly during a later invocation of usb_serial_probe */ - if (num_bulk_in == 0 || num_bulk_out == 0) { + 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; + kfree(epds); goto err_put_serial; } } @@ -856,10 +860,11 @@ static int usb_serial_probe(struct usb_interface *interface, #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { - num_ports = num_bulk_out; + num_ports = epds->num_bulk_out; if (num_ports == 0) { dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); retval = -EIO; + kfree(epds); goto err_put_serial; } dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); @@ -880,10 +885,10 @@ static int usb_serial_probe(struct usb_interface *interface, } serial->num_ports = (unsigned char)num_ports; - serial->num_bulk_in = num_bulk_in; - serial->num_bulk_out = num_bulk_out; - serial->num_interrupt_in = num_interrupt_in; - serial->num_interrupt_out = num_interrupt_out; + serial->num_bulk_in = epds->num_bulk_in; + serial->num_bulk_out = epds->num_bulk_out; + serial->num_interrupt_in = epds->num_interrupt_in; + serial->num_interrupt_out = epds->num_interrupt_out; /* found all that we need */ dev_info(ddev, "%s converter detected\n", type->description); @@ -891,9 +896,9 @@ static int usb_serial_probe(struct usb_interface *interface, /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here because some devices have more endpoint pairs than ports */ - max_endpoints = max(num_bulk_in, num_bulk_out); - max_endpoints = max(max_endpoints, num_interrupt_in); - max_endpoints = max(max_endpoints, num_interrupt_out); + max_endpoints = max(epds->num_bulk_in, epds->num_bulk_out); + max_endpoints = max(max_endpoints, epds->num_interrupt_in); + max_endpoints = max(max_endpoints, epds->num_interrupt_out); max_endpoints = max(max_endpoints, serial->num_ports); serial->num_port_pointers = max_endpoints; @@ -919,8 +924,8 @@ static int usb_serial_probe(struct usb_interface *interface, } /* set up the endpoint information */ - for (i = 0; i < num_bulk_in; ++i) { - endpoint = bulk_in_endpoint[i]; + for (i = 0; i < epds->num_bulk_in; ++i) { + endpoint = epds->bulk_in[i]; port = serial->port[i]; buffer_size = max_t(int, serial->type->bulk_in_size, usb_endpoint_maxp(endpoint)); @@ -948,8 +953,8 @@ static int usb_serial_probe(struct usb_interface *interface, port->bulk_in_buffer = port->bulk_in_buffers[0]; } - for (i = 0; i < num_bulk_out; ++i) { - endpoint = bulk_out_endpoint[i]; + for (i = 0; i < epds->num_bulk_out; ++i) { + endpoint = epds->bulk_out[i]; port = serial->port[i]; if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) goto probe_error; @@ -981,8 +986,8 @@ static int usb_serial_probe(struct usb_interface *interface, } if (serial->type->read_int_callback) { - for (i = 0; i < num_interrupt_in; ++i) { - endpoint = interrupt_in_endpoint[i]; + for (i = 0; i < epds->num_interrupt_in; ++i) { + endpoint = epds->interrupt_in[i]; port = serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->interrupt_in_urb) @@ -1001,13 +1006,13 @@ static int usb_serial_probe(struct usb_interface *interface, serial->type->read_int_callback, port, endpoint->bInterval); } - } else if (num_interrupt_in) { + } else if (epds->num_interrupt_in) { dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n"); } if (serial->type->write_int_callback) { - for (i = 0; i < num_interrupt_out; ++i) { - endpoint = interrupt_out_endpoint[i]; + for (i = 0; i < epds->num_interrupt_out; ++i) { + endpoint = epds->interrupt_out[i]; port = serial->port[i]; port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!port->interrupt_out_urb) @@ -1027,7 +1032,7 @@ static int usb_serial_probe(struct usb_interface *interface, serial->type->write_int_callback, port, endpoint->bInterval); } - } else if (num_interrupt_out) { + } else if (epds->num_interrupt_out) { dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n"); } @@ -1077,6 +1082,7 @@ static int usb_serial_probe(struct usb_interface *interface, if (num_ports > 0) usb_serial_console_init(serial->port[0]->minor); exit: + kfree(epds); module_put(type->driver.owner); return 0; From ff0c5703a4b11fca86886e5b7ce40c396bef8381 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:17 +0100 Subject: [PATCH 09/61] USB: serial: allow up to 16 ports per device Raise the arbitrary limit of how many ports a single device can claim from eight to 16. This specifically enables the upper eight ports of some mxuport devices. Signed-off-by: Johan Hovold --- include/linux/usb/serial.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 85b475933848..ee4394d8932f 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -20,7 +20,7 @@ #include /* The maximum number of ports one device can grab at once */ -#define MAX_NUM_PORTS 8 +#define MAX_NUM_PORTS 16 /* parity check flag */ #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) From 8520ac0d70d6c1709bf6768cb79f3b75115def09 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:18 +0100 Subject: [PATCH 10/61] USB: serial: replace runtime overflow check Since commit 0a8fd1346254 ("USB: fix problems with duplicate endpoint addresses") USB core guarantees that there are no more than 15 endpoint descriptors per type (and altsetting) so the corresponding overflow checks can now be replaced with a compile-time check on the array sizes (and indirectly the maximum number of ports). Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 09eb639298c8..ccc729d17a89 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -729,29 +729,26 @@ static void find_endpoints(struct usb_serial *serial, struct usb_endpoint_descriptor *epd; unsigned int i; + BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_in) < USB_MAXENDPOINTS / 2); + BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < USB_MAXENDPOINTS / 2); + BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_in) < USB_MAXENDPOINTS / 2); + BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_out) < USB_MAXENDPOINTS / 2); + iface_desc = serial->interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_in(epd)) { dev_dbg(dev, "found bulk in on endpoint %u\n", i); - if (epds->num_bulk_in == MAX_NUM_PORTS) - continue; epds->bulk_in[epds->num_bulk_in++] = epd; } else if (usb_endpoint_is_bulk_out(epd)) { dev_dbg(dev, "found bulk out on endpoint %u\n", i); - if (epds->num_bulk_out == MAX_NUM_PORTS) - continue; epds->bulk_out[epds->num_bulk_out++] = epd; } else if (usb_endpoint_is_int_in(epd)) { dev_dbg(dev, "found interrupt in on endpoint %u\n", i); - if (epds->num_interrupt_in == MAX_NUM_PORTS) - continue; epds->interrupt_in[epds->num_interrupt_in++] = epd; } else if (usb_endpoint_is_int_out(epd)) { dev_dbg(dev, "found interrupt out on endpoint %u\n", i); - if (epds->num_interrupt_out == MAX_NUM_PORTS) - continue; epds->interrupt_out[epds->num_interrupt_out++] = epd; } } From 92e6b2c675e1d247317ec41a078f49aaade7f716 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:19 +0100 Subject: [PATCH 11/61] USB: serial: add endpoint sanity check to core Allow drivers to specify a minimum number of endpoints per type, which USB serial core will verify after subdriver probe has returned (where the current alternate setting may have been changed). Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 17 ++++++++++++----- include/linux/usb/serial.h | 9 +++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index ccc729d17a89..747dd414bef9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -848,21 +848,26 @@ static int usb_serial_probe(struct usb_interface *interface, 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; - kfree(epds); - goto err_put_serial; + 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 || + epds->num_interrupt_out < type->num_interrupt_out) { + dev_err(ddev, "required endpoints missing\n"); + retval = -ENODEV; + goto err_free_epds; + } #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = epds->num_bulk_out; if (num_ports == 0) { dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); retval = -EIO; - kfree(epds); - goto err_put_serial; + goto err_free_epds; } dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); @@ -1085,6 +1090,8 @@ exit: probe_error: retval = -EIO; +err_free_epds: + kfree(epds); err_put_serial: usb_serial_put(serial); err_put_module: diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index ee4394d8932f..f1b8a8493762 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -188,6 +188,10 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. * @num_ports: the number of different ports this device will have. + * @num_bulk_in: minimum number of bulk-in endpoints + * @num_bulk_out: minimum number of bulk-out endpoints + * @num_interrupt_in: minimum number of interrupt-in endpoints + * @num_interrupt_out: minimum number of interrupt-out endpoints * @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer * (0 = end-point size) * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size) @@ -235,6 +239,11 @@ struct usb_serial_driver { unsigned char num_ports; + unsigned char num_bulk_in; + unsigned char num_bulk_out; + unsigned char num_interrupt_in; + unsigned char num_interrupt_out; + size_t bulk_in_size; size_t bulk_out_size; From 52ccf4607a5581234fb5c5cff1d38a8c1b69fdc2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:20 +0100 Subject: [PATCH 12/61] USB: serial: ark3116: simplify endpoint sanity check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/ark3116.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 2779e59c30f1..0adbd38b4eea 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -122,19 +122,6 @@ static inline int calc_divisor(int bps) return (12000000 + 2*bps) / (4*bps); } -static int ark3116_attach(struct usb_serial *serial) -{ - /* make sure we have our end-points */ - if (serial->num_bulk_in == 0 || - serial->num_bulk_out == 0 || - serial->num_interrupt_in == 0) { - dev_err(&serial->interface->dev, "missing endpoint\n"); - return -ENODEV; - } - - return 0; -} - static int ark3116_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; @@ -671,7 +658,9 @@ static struct usb_serial_driver ark3116_device = { }, .id_table = id_table, .num_ports = 1, - .attach = ark3116_attach, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .port_probe = ark3116_port_probe, .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, From d183b9b43390cf58ec01e05e81defe764b410a77 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:21 +0100 Subject: [PATCH 13/61] USB: serial: cyberjack: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/cyberjack.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 80260b08398b..47fbd9f0c0c7 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -50,7 +50,6 @@ #define CYBERJACK_PRODUCT_ID 0x0100 /* Function prototypes */ -static int cyberjack_attach(struct usb_serial *serial); static int cyberjack_port_probe(struct usb_serial_port *port); static int cyberjack_port_remove(struct usb_serial_port *port); static int cyberjack_open(struct tty_struct *tty, @@ -78,7 +77,7 @@ static struct usb_serial_driver cyberjack_device = { .description = "Reiner SCT Cyberjack USB card reader", .id_table = id_table, .num_ports = 1, - .attach = cyberjack_attach, + .num_bulk_out = 1, .port_probe = cyberjack_port_probe, .port_remove = cyberjack_port_remove, .open = cyberjack_open, @@ -102,14 +101,6 @@ struct cyberjack_private { short wrsent; /* Data already sent */ }; -static int cyberjack_attach(struct usb_serial *serial) -{ - if (serial->num_bulk_out < serial->num_ports) - return -ENODEV; - - return 0; -} - static int cyberjack_port_probe(struct usb_serial_port *port) { struct cyberjack_private *priv; From e7d6507e5ba7aa015b454f4871d4dec1e751d3ce Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:22 +0100 Subject: [PATCH 14/61] USB: serial: digi_acceleport: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Note that this driver uses an additional bulk-endpoint pair as an out-of-band port. Signed-off-by: Johan Hovold --- drivers/usb/serial/digi_acceleport.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6537d3ca2797..2ce39af32cfa 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -273,6 +273,8 @@ static struct usb_serial_driver digi_acceleport_2_device = { .description = "Digi 2 port USB adapter", .id_table = id_table_2, .num_ports = 3, + .num_bulk_in = 4, + .num_bulk_out = 4, .open = digi_open, .close = digi_close, .dtr_rts = digi_dtr_rts, @@ -302,6 +304,8 @@ static struct usb_serial_driver digi_acceleport_4_device = { .description = "Digi 4 port USB adapter", .id_table = id_table_4, .num_ports = 4, + .num_bulk_in = 5, + .num_bulk_out = 5, .open = digi_open, .close = digi_close, .write = digi_write, @@ -1251,27 +1255,8 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) static int digi_startup(struct usb_serial *serial) { - struct device *dev = &serial->interface->dev; struct digi_serial *serial_priv; int ret; - int i; - - /* check whether the device has the expected number of endpoints */ - if (serial->num_port_pointers < serial->type->num_ports + 1) { - dev_err(dev, "OOB endpoints missing\n"); - return -ENODEV; - } - - for (i = 0; i < serial->type->num_ports + 1 ; i++) { - if (!serial->port[i]->read_urb) { - dev_err(dev, "bulk-in endpoint missing\n"); - return -ENODEV; - } - if (!serial->port[i]->write_urb) { - dev_err(dev, "bulk-out endpoint missing\n"); - return -ENODEV; - } - } serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); if (!serial_priv) From fd0c883e597493d85d0800629798fc6fcce8e24e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:23 +0100 Subject: [PATCH 15/61] USB: serial: io_edgeport: simplify and tighten endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Also require the presence of a bulk-out endpoint, something which prevents the driver from trying to send bulk messages over the control pipe should a bulk-out endpoint be missing. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index bb7673e80a57..751e7454c37b 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2848,11 +2848,6 @@ static int edge_startup(struct usb_serial *serial) EDGE_COMPATIBILITY_MASK1, EDGE_COMPATIBILITY_MASK2 }; - if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - dev = serial->dev; /* create our private serial structure */ @@ -3120,6 +3115,9 @@ static struct usb_serial_driver edgeport_2port_device = { .description = "Edgeport 2 port adapter", .id_table = edgeport_2port_id_table, .num_ports = 2, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, @@ -3152,6 +3150,9 @@ static struct usb_serial_driver edgeport_4port_device = { .description = "Edgeport 4 port adapter", .id_table = edgeport_4port_id_table, .num_ports = 4, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, @@ -3184,6 +3185,9 @@ static struct usb_serial_driver edgeport_8port_device = { .description = "Edgeport 8 port adapter", .id_table = edgeport_8port_id_table, .num_ports = 8, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, @@ -3216,6 +3220,9 @@ static struct usb_serial_driver epic_device = { .description = "EPiC device", .id_table = Epic_port_id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, From fb527736ebcca0c8b67bc4754a3804e6048b6dff Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:24 +0100 Subject: [PATCH 16/61] USB: serial: iuu_phoenix: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/iuu_phoenix.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 030390f37b0a..7dd1601e4a02 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -68,16 +68,6 @@ struct iuu_private { u32 clk; }; -static int iuu_attach(struct usb_serial *serial) -{ - unsigned char num_ports = serial->num_ports; - - if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports) - return -ENODEV; - - return 0; -} - static int iuu_port_probe(struct usb_serial_port *port) { struct iuu_private *priv; @@ -1183,6 +1173,8 @@ static struct usb_serial_driver iuu_device = { }, .id_table = id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, .bulk_in_size = 512, .bulk_out_size = 512, .open = iuu_open, @@ -1193,7 +1185,6 @@ static struct usb_serial_driver iuu_device = { .tiocmset = iuu_tiocmset, .set_termios = iuu_set_termios, .init_termios = iuu_init_termios, - .attach = iuu_attach, .port_probe = iuu_port_probe, .port_remove = iuu_port_remove, }; From b714d5dc0631285d2cf237c1d4ed16ba9b68c6fb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:25 +0100 Subject: [PATCH 17/61] USB: serial: keyspan_pda: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/keyspan_pda.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index d2dab2a341b8..196908dd25a1 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -708,19 +708,6 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); #endif -static int keyspan_pda_attach(struct usb_serial *serial) -{ - unsigned char num_ports = serial->num_ports; - - if (serial->num_bulk_out < num_ports || - serial->num_interrupt_in < num_ports) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - - return 0; -} - static int keyspan_pda_port_probe(struct usb_serial_port *port) { @@ -784,6 +771,8 @@ static struct usb_serial_driver keyspan_pda_device = { .description = "Keyspan PDA", .id_table = id_table_std, .num_ports = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .dtr_rts = keyspan_pda_dtr_rts, .open = keyspan_pda_open, .close = keyspan_pda_close, @@ -798,7 +787,6 @@ static struct usb_serial_driver keyspan_pda_device = { .break_ctl = keyspan_pda_break_ctl, .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, - .attach = keyspan_pda_attach, .port_probe = keyspan_pda_port_probe, .port_remove = keyspan_pda_port_remove, }; From 35194572b4ede8b021d4c70c8785cd4d5c3fae0a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:26 +0100 Subject: [PATCH 18/61] USB: serial: kobil_sct: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/kobil_sct.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 813035f51fe7..3024b9b25360 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -51,7 +51,6 @@ /* Function prototypes */ -static int kobil_attach(struct usb_serial *serial); static int kobil_port_probe(struct usb_serial_port *probe); static int kobil_port_remove(struct usb_serial_port *probe); static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port); @@ -87,7 +86,7 @@ static struct usb_serial_driver kobil_device = { .description = "KOBIL USB smart card terminal", .id_table = id_table, .num_ports = 1, - .attach = kobil_attach, + .num_interrupt_out = 1, .port_probe = kobil_port_probe, .port_remove = kobil_port_remove, .ioctl = kobil_ioctl, @@ -115,16 +114,6 @@ struct kobil_private { }; -static int kobil_attach(struct usb_serial *serial) -{ - if (serial->num_interrupt_out < serial->num_ports) { - dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n"); - return -ENODEV; - } - - return 0; -} - static int kobil_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; From 206ff831bebb816087da29a34fcff5bd603602e1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:27 +0100 Subject: [PATCH 19/61] USB: serial: mos7720: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Note that the driver expects two bulk-endpoint pairs also for mcs7715 devices for which only one serial port is registered. Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7720.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index f075121c6e32..df45ebad5f6f 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1900,11 +1900,6 @@ static int mos7720_startup(struct usb_serial *serial) u16 product; int ret_val; - if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) { - dev_err(&serial->interface->dev, "missing bulk endpoints\n"); - return -ENODEV; - } - product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; @@ -2039,6 +2034,8 @@ static struct usb_serial_driver moschip7720_2port_driver = { }, .description = "Moschip 2 port adapter", .id_table = id_table, + .num_bulk_in = 2, + .num_bulk_out = 2, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, From 8ee1592d125a95dc8a554398e014b65ee04cd80c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:28 +0100 Subject: [PATCH 20/61] USB: serial: omninet: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Note that the driver uses the second bulk-out endpoint for writing. Signed-off-by: Johan Hovold --- drivers/usb/serial/omninet.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index dd706953b466..7be40dfa3620 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -37,7 +37,6 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); static void omninet_disconnect(struct usb_serial *serial); -static int omninet_attach(struct usb_serial *serial); static int omninet_port_probe(struct usb_serial_port *port); static int omninet_port_remove(struct usb_serial_port *port); @@ -56,7 +55,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .description = "ZyXEL - omni.net lcd plus usb", .id_table = id_table, .num_ports = 1, - .attach = omninet_attach, + .num_bulk_out = 2, .port_probe = omninet_port_probe, .port_remove = omninet_port_remove, .write = omninet_write, @@ -104,17 +103,6 @@ struct omninet_data { __u8 od_outseq; /* Sequence number for bulk_out URBs */ }; -static int omninet_attach(struct usb_serial *serial) -{ - /* The second bulk-out endpoint is used for writing. */ - if (serial->num_bulk_out < 2) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - - return 0; -} - static int omninet_port_probe(struct usb_serial_port *port) { struct omninet_data *od; From 5e5b6444d099ac7b883f5cc112f5415fe619a595 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:29 +0100 Subject: [PATCH 21/61] USB: serial: opticon: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/opticon.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 3937b9c3cc69..58657d64678b 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -367,16 +367,6 @@ static int opticon_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } -static int opticon_startup(struct usb_serial *serial) -{ - if (!serial->num_bulk_in) { - dev_err(&serial->dev->dev, "no bulk in endpoint\n"); - return -ENODEV; - } - - return 0; -} - static int opticon_port_probe(struct usb_serial_port *port) { struct opticon_private *priv; @@ -408,8 +398,8 @@ static struct usb_serial_driver opticon_device = { }, .id_table = id_table, .num_ports = 1, + .num_bulk_in = 1, .bulk_in_size = 256, - .attach = opticon_startup, .port_probe = opticon_port_probe, .port_remove = opticon_port_remove, .open = opticon_open, From 32814c87f446b90efe4350bb97924eca53152d26 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:30 +0100 Subject: [PATCH 22/61] USB: serial: oti6858: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/oti6858.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index b8bf52bf7a94..b11eead469ee 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -134,7 +134,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty); static int oti6858_tiocmget(struct tty_struct *tty); static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int oti6858_attach(struct usb_serial *serial); static int oti6858_port_probe(struct usb_serial_port *port); static int oti6858_port_remove(struct usb_serial_port *port); @@ -146,6 +145,9 @@ static struct usb_serial_driver oti6858_device = { }, .id_table = id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .open = oti6858_open, .close = oti6858_close, .write = oti6858_write, @@ -159,7 +161,6 @@ static struct usb_serial_driver oti6858_device = { .write_bulk_callback = oti6858_write_bulk_callback, .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, - .attach = oti6858_attach, .port_probe = oti6858_port_probe, .port_remove = oti6858_port_remove, }; @@ -326,20 +327,6 @@ static void send_data(struct work_struct *work) usb_serial_port_softint(port); } -static int oti6858_attach(struct usb_serial *serial) -{ - unsigned char num_ports = serial->num_ports; - - if (serial->num_bulk_in < num_ports || - serial->num_bulk_out < num_ports || - serial->num_interrupt_in < num_ports) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - - return 0; -} - static int oti6858_port_probe(struct usb_serial_port *port) { struct oti6858_private *priv; From 590298b2232503ee5088c3abfe6cf69d51ade427 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:31 +0100 Subject: [PATCH 23/61] USB: serial: pl2303: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ca69eb42071b..60840004568a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -221,17 +221,9 @@ static int pl2303_probe(struct usb_serial *serial, static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; - unsigned char num_ports = serial->num_ports; enum pl2303_type type = TYPE_01; unsigned char *buf; - if (serial->num_bulk_in < num_ports || - serial->num_bulk_out < num_ports || - serial->num_interrupt_in < num_ports) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; @@ -939,6 +931,9 @@ static struct usb_serial_driver pl2303_device = { }, .id_table = id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_interrupt_in = 1, .bulk_in_size = 256, .bulk_out_size = 256, .open = pl2303_open, From bdd154436077391e40fd20be8ff384d4002b3970 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:32 +0100 Subject: [PATCH 24/61] USB: serial: spcp8x5: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/spcp8x5.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index ddfd787c461c..5167b6564c8b 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -154,19 +154,6 @@ static int spcp8x5_probe(struct usb_serial *serial, return 0; } -static int spcp8x5_attach(struct usb_serial *serial) -{ - unsigned char num_ports = serial->num_ports; - - if (serial->num_bulk_in < num_ports || - serial->num_bulk_out < num_ports) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - - return 0; -} - static int spcp8x5_port_probe(struct usb_serial_port *port) { const struct usb_device_id *id = usb_get_serial_data(port->serial); @@ -488,6 +475,8 @@ static struct usb_serial_driver spcp8x5_device = { }, .id_table = id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, .open = spcp8x5_open, .dtr_rts = spcp8x5_dtr_rts, .carrier_raised = spcp8x5_carrier_raised, @@ -496,7 +485,6 @@ static struct usb_serial_driver spcp8x5_device = { .tiocmget = spcp8x5_tiocmget, .tiocmset = spcp8x5_tiocmset, .probe = spcp8x5_probe, - .attach = spcp8x5_attach, .port_probe = spcp8x5_port_probe, .port_remove = spcp8x5_port_remove, }; From e2cd017f1b7c2e79b3a89d3c8e31c88ad365243a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:33 +0100 Subject: [PATCH 25/61] USB: serial: symbolserial: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Signed-off-by: Johan Hovold --- drivers/usb/serial/symbolserial.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 37f3ad15ed06..0d1727232d0c 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -147,16 +147,6 @@ static void symbol_unthrottle(struct tty_struct *tty) } } -static int symbol_startup(struct usb_serial *serial) -{ - if (!serial->num_interrupt_in) { - dev_err(&serial->dev->dev, "no interrupt-in endpoint\n"); - return -ENODEV; - } - - return 0; -} - static int symbol_port_probe(struct usb_serial_port *port) { struct symbol_private *priv; @@ -188,7 +178,7 @@ static struct usb_serial_driver symbol_device = { }, .id_table = id_table, .num_ports = 1, - .attach = symbol_startup, + .num_interrupt_in = 1, .port_probe = symbol_port_probe, .port_remove = symbol_port_remove, .open = symbol_open, From 2ac8fc51ddf152fdd2344c6d286976803183d59c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Mar 2017 12:51:34 +0100 Subject: [PATCH 26/61] USB: serial: whiteheat: simplify endpoint check Simplify the endpoint sanity check by letting core verify that the required endpoints are present. Note that the driver registers four ports but uses five bulk-endpoint pairs. Signed-off-by: Johan Hovold --- drivers/usb/serial/whiteheat.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5ab65eb1dacc..55cebc1e6fec 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -80,8 +80,6 @@ static int whiteheat_firmware_download(struct usb_serial *serial, static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ -static int whiteheat_probe(struct usb_serial *serial, - const struct usb_device_id *id); static int whiteheat_attach(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial); static int whiteheat_port_probe(struct usb_serial_port *port); @@ -118,7 +116,8 @@ static struct usb_serial_driver whiteheat_device = { .description = "Connect Tech - WhiteHEAT", .id_table = id_table_std, .num_ports = 4, - .probe = whiteheat_probe, + .num_bulk_in = 5, + .num_bulk_out = 5, .attach = whiteheat_attach, .release = whiteheat_release, .port_probe = whiteheat_port_probe, @@ -221,33 +220,6 @@ static int whiteheat_firmware_attach(struct usb_serial *serial) * Connect Tech's White Heat serial driver functions *****************************************************************************/ -static int whiteheat_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - size_t num_bulk_in = 0; - size_t num_bulk_out = 0; - size_t min_num_bulk; - unsigned int i; - - iface_desc = serial->interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_bulk_in(endpoint)) - ++num_bulk_in; - if (usb_endpoint_is_bulk_out(endpoint)) - ++num_bulk_out; - } - - min_num_bulk = COMMAND_PORT + 1; - if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk) - return -ENODEV; - - return 0; -} - static int whiteheat_attach(struct usb_serial *serial) { struct usb_serial_port *command_port; From 07814246dd5530860ef758fd9b2b5f2e26472aa2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:30 +0100 Subject: [PATCH 27/61] USB: serial: allow subdrivers to modify port-endpoint mapping Allow subdrivers to modify the port-endpoint mapping by passing the endpoint descriptors to calc_num_ports. The callback can now also be used to verify that the required endpoints exists and abort probing otherwise. This will allow us to get rid of a few hacks in subdrivers that are already modifying the port-endpoint mapping (or aborting probe due to missing endpoints), but only after the port structures have been setup. Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 3 ++- drivers/usb/serial/ipaq.c | 6 ++++-- drivers/usb/serial/mos7720.c | 3 ++- drivers/usb/serial/mos7840.c | 3 ++- drivers/usb/serial/mxuport.c | 3 ++- drivers/usb/serial/quatech2.c | 3 ++- drivers/usb/serial/sierra.c | 3 ++- drivers/usb/serial/usb-serial.c | 19 ++++++------------- drivers/usb/serial/visor.c | 6 ++++-- include/linux/usb/serial.h | 19 ++++++++++++++++--- 10 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 22f23a429a95..385087c008ed 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -611,7 +611,8 @@ static int f81534_find_config_idx(struct usb_serial *serial, u8 *index) * The f81534_calc_num_ports() will run to "new style" with checking * F81534_PORT_UNAVAILABLE section. */ -static int f81534_calc_num_ports(struct usb_serial *serial) +static int f81534_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { u8 setting[F81534_CUSTOM_DATA_SIZE]; u8 setting_idx; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index ec1b8f2c1183..df5f1a7d7c6f 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -33,7 +33,8 @@ static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port); -static int ipaq_calc_num_ports(struct usb_serial *serial); +static int ipaq_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds); static int ipaq_startup(struct usb_serial *serial); static const struct usb_device_id ipaq_id_table[] = { @@ -550,7 +551,8 @@ static int ipaq_open(struct tty_struct *tty, return usb_serial_generic_open(tty, port); } -static int ipaq_calc_num_ports(struct usb_serial *serial) +static int ipaq_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { /* * some devices have 3 endpoints, the 3rd of which diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index df45ebad5f6f..9ec3e4fb9678 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -973,7 +973,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) tty_port_tty_wakeup(&mos7720_port->port->port); } -static int mos77xx_calc_num_ports(struct usb_serial *serial) +static int mos77xx_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); if (product == MOSCHIP_DEVICE_ID_7715) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 3821c53fcee9..326d6c5055ef 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2104,7 +2104,8 @@ out: return 0; } -static int mos7840_calc_num_ports(struct usb_serial *serial) +static int mos7840_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { int device_type = (unsigned long)usb_get_serial_data(serial); int mos7840_num_ports; diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index c88215a0fa3d..bf543e6c05ea 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -946,7 +946,8 @@ out: * Determine how many ports this device has dynamically. It will be * called after the probe() callback is called, but before attach(). */ -static int mxuport_calc_num_ports(struct usb_serial *serial) +static int mxuport_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { unsigned long features = (unsigned long)usb_get_serial_data(serial); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index fdbb904d153f..6ddcaa2de902 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -246,7 +246,8 @@ static inline int update_mctrl(struct qt2_port_private *port_priv, return status; } -static int qt2_calc_num_ports(struct usb_serial *serial) +static int qt2_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { struct qt2_device_detail d; int i; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 465e851b2815..4c4ac4705ac0 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -85,7 +85,8 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) USB_CTRL_SET_TIMEOUT); /* int timeout */ } -static int sierra_calc_num_ports(struct usb_serial *serial) +static int sierra_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { int num_ports = 0; u8 ifnum, numendpoints; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 747dd414bef9..f0761f491c5f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -710,17 +710,6 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_port_shutdown, }; -struct usb_serial_endpoints { - unsigned char num_bulk_in; - unsigned char num_bulk_out; - unsigned char num_interrupt_in; - unsigned char num_interrupt_out; - struct usb_endpoint_descriptor *bulk_in[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_out[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *interrupt_in[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *interrupt_out[MAX_NUM_PORTS]; -}; - static void find_endpoints(struct usb_serial *serial, struct usb_serial_endpoints *epds) { @@ -875,8 +864,12 @@ static int usb_serial_probe(struct usb_interface *interface, #endif if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) - num_ports = type->calc_num_ports(serial); + if (type->calc_num_ports) { + retval = type->calc_num_ports(serial, epds); + if (retval < 0) + goto err_free_epds; + num_ports = retval; + } if (!num_ports) num_ports = type->num_ports; } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 337a0be89fcf..3f943f877ac2 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -40,7 +40,8 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port); static void visor_close(struct usb_serial_port *port); static int visor_probe(struct usb_serial *serial, const struct usb_device_id *id); -static int visor_calc_num_ports(struct usb_serial *serial); +static int visor_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds); static void visor_read_int_callback(struct urb *urb); static int clie_3_5_startup(struct usb_serial *serial); static int treo_attach(struct usb_serial *serial); @@ -466,7 +467,8 @@ static int visor_probe(struct usb_serial *serial, return retval; } -static int visor_calc_num_ports(struct usb_serial *serial) +static int visor_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { int num_ports = (int)(long)(usb_get_serial_data(serial)); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index f1b8a8493762..da528818cfd8 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -181,6 +181,17 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) serial->private = data; } +struct usb_serial_endpoints { + unsigned char num_bulk_in; + unsigned char num_bulk_out; + unsigned char num_interrupt_in; + unsigned char num_interrupt_out; + struct usb_endpoint_descriptor *bulk_in[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *bulk_out[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *interrupt_in[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *interrupt_out[MAX_NUM_PORTS]; +}; + /** * usb_serial_driver - describes a usb serial driver * @description: pointer to a string that describes this driver. This string @@ -196,8 +207,9 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) * (0 = end-point size) * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size) * @calc_num_ports: pointer to a function to determine how many ports this - * device has dynamically. It will be called after the probe() - * callback is called, but before attach() + * device has dynamically. It can also be used to verify the number of + * endpoints or to modify the port-endpoint mapping. It will be called + * after the probe() callback is called, but before attach(). * @probe: pointer to the driver's probe function. * This will be called when the device is inserted into the system, * but before the device has been fully initialized by the usb_serial @@ -249,7 +261,8 @@ struct usb_serial_driver { int (*probe)(struct usb_serial *serial, const struct usb_device_id *id); int (*attach)(struct usb_serial *serial); - int (*calc_num_ports) (struct usb_serial *serial); + int (*calc_num_ports)(struct usb_serial *serial, + struct usb_serial_endpoints *epds); void (*disconnect)(struct usb_serial *serial); void (*release)(struct usb_serial *serial); From 415d7b3a5407d91fdf47a07fd31d63e4b548651f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:31 +0100 Subject: [PATCH 28/61] USB: serial: add probe callback to generic driver Add a probe callback to the generic driver and print the only-for-testing message there. This is a first step in getting rid of the CONFIG_USB_SERIAL_GENERIC ifdef from usb-serial core. Signed-off-by: Johan Hovold --- drivers/usb/serial/generic.c | 12 ++++++++++++ drivers/usb/serial/usb-serial.c | 2 -- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 49ce2be90fa0..8c7600472019 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -37,6 +37,17 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ +static int usb_serial_generic_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + struct device *dev = &serial->interface->dev; + + dev_info(dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); + dev_info(dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); + + return 0; +} + struct usb_serial_driver usb_serial_generic_device = { .driver = { .owner = THIS_MODULE, @@ -44,6 +55,7 @@ struct usb_serial_driver usb_serial_generic_device = { }, .id_table = generic_device_ids, .num_ports = 1, + .probe = usb_serial_generic_probe, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f0761f491c5f..f8ae09e2cff5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -858,8 +858,6 @@ static int usb_serial_probe(struct usb_interface *interface, retval = -EIO; goto err_free_epds; } - dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); - dev_info(ddev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); } #endif if (!num_ports) { From a794499b261b8487a984783ccc864975e1bcc7bf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:32 +0100 Subject: [PATCH 29/61] USB: serial: add calc_num_ports callback to generic driver Add a calc_num_ports callback to the generic driver and verify that the device has the required endpoints there instead of in core. Note that the generic driver num_ports field was never used. Signed-off-by: Johan Hovold --- drivers/usb/serial/generic.c | 18 ++++++++++++++++-- drivers/usb/serial/usb-serial.c | 27 ++++++++------------------- include/linux/usb/serial.h | 1 - 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 8c7600472019..2d3599f014e2 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -48,14 +48,28 @@ static int usb_serial_generic_probe(struct usb_serial *serial, return 0; } -struct usb_serial_driver usb_serial_generic_device = { +static int usb_serial_generic_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + struct device *dev = &serial->interface->dev; + int num_ports = epds->num_bulk_out; + + if (num_ports == 0) { + dev_err(dev, "Generic device with no bulk out, not allowed.\n"); + return -ENODEV; + } + + return num_ports; +} + +static struct usb_serial_driver usb_serial_generic_device = { .driver = { .owner = THIS_MODULE, .name = "generic", }, .id_table = generic_device_ids, - .num_ports = 1, .probe = usb_serial_generic_probe, + .calc_num_ports = usb_serial_generic_calc_num_ports, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f8ae09e2cff5..101eb105d78e 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -850,28 +850,17 @@ static int usb_serial_probe(struct usb_interface *interface, retval = -ENODEV; goto err_free_epds; } -#ifdef CONFIG_USB_SERIAL_GENERIC - if (type == &usb_serial_generic_device) { - num_ports = epds->num_bulk_out; - if (num_ports == 0) { - dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); - retval = -EIO; + + if (type->calc_num_ports) { + retval = type->calc_num_ports(serial, epds); + if (retval < 0) goto err_free_epds; - } - } -#endif - if (!num_ports) { - /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) { - retval = type->calc_num_ports(serial, epds); - if (retval < 0) - goto err_free_epds; - num_ports = retval; - } - if (!num_ports) - num_ports = type->num_ports; + num_ports = retval; } + if (!num_ports) + num_ports = type->num_ports; + if (num_ports > MAX_NUM_PORTS) { dev_warn(ddev, "too many ports requested: %d\n", num_ports); num_ports = MAX_NUM_PORTS; diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index da528818cfd8..e2f0ab07eea5 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -379,7 +379,6 @@ extern void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, extern int usb_serial_bus_register(struct usb_serial_driver *device); extern void usb_serial_bus_deregister(struct usb_serial_driver *device); -extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; From 6538808c5619850cfedc9bee6d64d3793b31923d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:33 +0100 Subject: [PATCH 30/61] USB: serial: relax generic driver bulk-endpoint requirement Relax the generic driver bulk-endpoint requirement. The driver handles devices without bulk-out endpoints just fine these days. Signed-off-by: Johan Hovold --- drivers/usb/serial/generic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 2d3599f014e2..35cb8c0e584f 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -52,10 +52,12 @@ static int usb_serial_generic_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { struct device *dev = &serial->interface->dev; - int num_ports = epds->num_bulk_out; + int num_ports; + + num_ports = max(epds->num_bulk_in, epds->num_bulk_out); if (num_ports == 0) { - dev_err(dev, "Generic device with no bulk out, not allowed.\n"); + dev_err(dev, "device has no bulk endpoints\n"); return -ENODEV; } From 9fda620a5f3d7711d0b27d36eeec3a24a097af97 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:34 +0100 Subject: [PATCH 31/61] 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 60840004568a..b8edd7bc71f2 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 101eb105d78e..0fa2030c275c 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 || From 9d717271d6b5cbbe6aaa975648d9dcfe9b6e7b82 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:35 +0100 Subject: [PATCH 32/61] USB: serial: pl2303: clean up legacy endpoint hack Implement the "horrible endpoint hack" for some legacy devices as a quirk and clean up the code somewhat. Note that the bulk-endpoint check can be removed as core will already have verified this. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 84 ++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index b8edd7bc71f2..c9ebefd8f35f 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -33,9 +33,11 @@ #define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) #define PL2303_QUIRK_LEGACY BIT(1) +#define PL2303_QUIRK_ENDPOINT_HACK BIT(2) static const struct usb_device_id id_table[] = { - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, @@ -48,7 +50,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, - { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, @@ -68,7 +71,8 @@ static const struct usb_device_id id_table[] = { .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, @@ -78,7 +82,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, - { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, @@ -218,7 +223,12 @@ static int pl2303_probe(struct usb_serial *serial, return 0; } -static int pl2303_calc_num_ports(struct usb_serial *serial, +/* + * Use interrupt endpoint from first interface if available. + * + * This is needed due to the looney way its endpoints are set up. + */ +static int pl2303_endpoint_hack(struct usb_serial *serial, struct usb_serial_endpoints *epds) { struct usb_interface *interface = serial->interface; @@ -228,43 +238,41 @@ static int pl2303_calc_num_ports(struct usb_serial *serial, 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; - } - } - } + if (interface == dev->actconfig->interface[0]) + return 0; - /* 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; - } + /* 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)) + continue; + + dev_dbg(ddev, "found interrupt in on separate interface\n"); + if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in)) + epds->interrupt_in[epds->num_interrupt_in++] = endpoint; + } + + return 0; +} + +static int pl2303_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + unsigned long quirks = (unsigned long)usb_get_serial_data(serial); + struct device *dev = &serial->interface->dev; + int ret; + + if (quirks & PL2303_QUIRK_ENDPOINT_HACK) { + ret = pl2303_endpoint_hack(serial, epds); + if (ret) + return ret; } - /* END HORRIBLE HACK FOR PL2303 */ if (epds->num_interrupt_in < 1) { - dev_err(ddev, "required interrupt-in endpoint missing\n"); + dev_err(dev, "required interrupt-in endpoint missing\n"); return -ENODEV; } From 5f391979c9aaa0ccecaf40f9b39359c584f7d615 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:36 +0100 Subject: [PATCH 33/61] USB: serial: aircable: use calc_num_endpoints to verify endpoints Use the calc_num_ports rather than probe callback to determine which interface to bind to. This allows us to remove some duplicate code. Signed-off-by: Johan Hovold --- drivers/usb/serial/aircable.c | 36 ++++++++--------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 80a9845cd93f..569c2200ba42 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -29,12 +29,6 @@ * is any other control code, I will simply check for the first * one. * - * The driver registers himself with the USB-serial core and the USB Core. I had - * to implement a probe function against USB-serial, because other way, the - * driver was attaching himself to both interfaces. I have tried with different - * configurations of usb_serial_driver with out exit, only the probe function - * could handle this correctly. - * * I have taken some info from a Greg Kroah-Hartman article: * http://www.linuxjournal.com/article/6573 * And from Linux Device Driver Kit CD, which is a great work, the authors taken @@ -93,30 +87,17 @@ static int aircable_prepare_write_buffer(struct usb_serial_port *port, return count + HCI_HEADER_LENGTH; } -static int aircable_probe(struct usb_serial *serial, - const struct usb_device_id *id) +static int aircable_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { - struct usb_host_interface *iface_desc = serial->interface-> - cur_altsetting; - struct usb_endpoint_descriptor *endpoint; - int num_bulk_out = 0; - int i; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_bulk_out(endpoint)) { - dev_dbg(&serial->dev->dev, - "found bulk out on endpoint %d\n", i); - ++num_bulk_out; - } - } - - if (num_bulk_out == 0) { - dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n"); + /* Ignore the first interface, which has no bulk endpoints. */ + if (epds->num_bulk_out == 0) { + dev_dbg(&serial->interface->dev, + "ignoring interface with no bulk-out endpoints\n"); return -ENODEV; } - return 0; + return 1; } static int aircable_process_packet(struct usb_serial_port *port, @@ -164,9 +145,8 @@ static struct usb_serial_driver aircable_device = { .name = "aircable", }, .id_table = id_table, - .num_ports = 1, .bulk_out_size = HCI_COMPLETE_FRAME, - .probe = aircable_probe, + .calc_num_ports = aircable_calc_num_ports, .process_read_urb = aircable_process_read_urb, .prepare_write_buffer = aircable_prepare_write_buffer, .throttle = usb_serial_generic_throttle, From cac4cea513c7193512a58da4b1bfa46c04246546 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:37 +0100 Subject: [PATCH 34/61] USB: serial: f81534: use calc_num_endpoints to verify endpoints Simplify the endpoint sanity check by letting core verify that the required endpoints are present and moving the max-packet check to calc_num_ports. Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 55 ++++++++----------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 385087c008ed..a4b1fea4453e 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -614,12 +614,21 @@ static int f81534_find_config_idx(struct usb_serial *serial, u8 *index) static int f81534_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { + struct device *dev = &serial->interface->dev; + int size_bulk_in = usb_endpoint_maxp(epds->bulk_in[0]); + int size_bulk_out = usb_endpoint_maxp(epds->bulk_out[0]); u8 setting[F81534_CUSTOM_DATA_SIZE]; u8 setting_idx; u8 num_port = 0; int status; size_t i; + if (size_bulk_out != F81534_WRITE_BUFFER_SIZE || + size_bulk_in != F81534_MAX_RECEIVE_BLOCK_SIZE) { + dev_err(dev, "unsupported endpoint max packet size\n"); + return -ENODEV; + } + /* Check had custom setting */ status = f81534_find_config_idx(serial, &setting_idx); if (status) { @@ -1115,49 +1124,6 @@ static int f81534_setup_ports(struct usb_serial *serial) return 0; } -static int f81534_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct usb_endpoint_descriptor *endpoint; - struct usb_host_interface *iface_desc; - struct device *dev; - int num_bulk_in = 0; - int num_bulk_out = 0; - int size_bulk_in = 0; - int size_bulk_out = 0; - int i; - - dev = &serial->interface->dev; - iface_desc = serial->interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - ++num_bulk_in; - size_bulk_in = usb_endpoint_maxp(endpoint); - } - - if (usb_endpoint_is_bulk_out(endpoint)) { - ++num_bulk_out; - size_bulk_out = usb_endpoint_maxp(endpoint); - } - } - - if (num_bulk_in != 1 || num_bulk_out != 1) { - dev_err(dev, "expected endpoints not found\n"); - return -ENODEV; - } - - if (size_bulk_out != F81534_WRITE_BUFFER_SIZE || - size_bulk_in != F81534_MAX_RECEIVE_BLOCK_SIZE) { - dev_err(dev, "unsupported endpoint max packet size\n"); - return -ENODEV; - } - - return 0; -} - static int f81534_attach(struct usb_serial *serial) { struct f81534_serial_private *serial_priv; @@ -1381,12 +1347,13 @@ static struct usb_serial_driver f81534_device = { }, .description = DRIVER_DESC, .id_table = f81534_id_table, + .num_bulk_in = 1, + .num_bulk_out = 1, .open = f81534_open, .close = f81534_close, .write = f81534_write, .tx_empty = f81534_tx_empty, .calc_num_ports = f81534_calc_num_ports, - .probe = f81534_probe, .attach = f81534_attach, .port_probe = f81534_port_probe, .dtr_rts = f81534_dtr_rts, From 2f16621b9a06c1956eba57a23ff990bd24ceee82 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:38 +0100 Subject: [PATCH 35/61] USB: serial: f81534: abort probe on early errors We can now abort probe early after an error in calc_num_ports by returning an errno instead of attempting to continue probing but not register any ports. Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index a4b1fea4453e..be106f4e3e57 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -634,7 +634,7 @@ static int f81534_calc_num_ports(struct usb_serial *serial, if (status) { dev_err(&serial->interface->dev, "%s: find idx failed: %d\n", __func__, status); - return 0; + return status; } /* @@ -650,7 +650,7 @@ static int f81534_calc_num_ports(struct usb_serial *serial, dev_err(&serial->interface->dev, "%s: get custom data failed: %d\n", __func__, status); - return 0; + return status; } dev_dbg(&serial->interface->dev, @@ -666,7 +666,7 @@ static int f81534_calc_num_ports(struct usb_serial *serial, dev_err(&serial->interface->dev, "%s: read failed: %d\n", __func__, status); - return 0; + return status; } dev_dbg(&serial->interface->dev, "%s: read default config\n", From 03b72aecadc2d7b0e8f200ec70b853e39a7e55da Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:39 +0100 Subject: [PATCH 36/61] USB: serial: ipaq: use calc_num_endpoints to verify endpoints Use the calc_num_ports rather than attach callback to determine which interface to bind to in order to avoid allocating port-resources for interfaces that won't be bound. Signed-off-by: Johan Hovold --- drivers/usb/serial/ipaq.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index df5f1a7d7c6f..c638571f0175 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -574,20 +574,22 @@ static int ipaq_calc_num_ports(struct usb_serial *serial, ipaq_num_ports = 2; } + /* + * Some of the devices in ipaq_id_table[] are composite, and we + * shouldn't bind to all the interfaces. This test will rule out + * some obviously invalid possibilities. + */ + if (epds->num_bulk_in < ipaq_num_ports || + epds->num_bulk_out < ipaq_num_ports) { + return -ENODEV; + } + return ipaq_num_ports; } static int ipaq_startup(struct usb_serial *serial) { - /* Some of the devices in ipaq_id_table[] are composite, and we - * shouldn't bind to all the interfaces. This test will rule out - * some obviously invalid possibilities. - */ - if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) - return -ENODEV; - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { /* * FIXME: HP iPaq rx3715, possibly others, have 1 config that From 204cc473bc896134870fda21cd279774b3ead024 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:40 +0100 Subject: [PATCH 37/61] USB: serial: ipaq: always register a single port Use the calc_num_ports callback to ignore unused endpoints. The driver binds to any interface with at least one bulk-in and one bulk-out endpoint, but some devices can have three or more endpoints of which only either the first or second pair of endpoints is needed. This avoids allocating resources for unused endpoints, and specifically a port is no longer registered for the unused first endpoint pair when there are more than three endpoints. Signed-off-by: Johan Hovold --- drivers/usb/serial/ipaq.c | 47 +++++++++++++++------------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c638571f0175..cde0dcdce9c4 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -554,39 +554,32 @@ static int ipaq_open(struct tty_struct *tty, static int ipaq_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { - /* - * some devices have 3 endpoints, the 3rd of which - * must be ignored as it would make the core - * create a second port which oopses when used - */ - int ipaq_num_ports = 1; - - dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__, - (int)serial->interface->cur_altsetting->desc.bNumEndpoints); - - /* - * a few devices have 4 endpoints, seemingly Yakuma devices, - * and we need the second pair, so let them have 2 ports - * - * TODO: can we drop port 1 ? - */ - if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) { - ipaq_num_ports = 2; - } - /* * Some of the devices in ipaq_id_table[] are composite, and we - * shouldn't bind to all the interfaces. This test will rule out + * shouldn't bind to all the interfaces. This test will rule out * some obviously invalid possibilities. */ - if (epds->num_bulk_in < ipaq_num_ports || - epds->num_bulk_out < ipaq_num_ports) { + if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) return -ENODEV; + + /* + * A few devices have four endpoints, seemingly Yakuma devices, and + * we need the second pair. + */ + if (epds->num_bulk_in > 1 && epds->num_bulk_out > 1) { + epds->bulk_in[0] = epds->bulk_in[1]; + epds->bulk_out[0] = epds->bulk_out[1]; } - return ipaq_num_ports; -} + /* + * Other devices have 3 endpoints, but we only use the first bulk in + * and out endpoints. + */ + epds->num_bulk_in = 1; + epds->num_bulk_out = 1; + return 1; +} static int ipaq_startup(struct usb_serial *serial) { @@ -601,10 +594,6 @@ static int ipaq_startup(struct usb_serial *serial) return -ENODEV; } - dev_dbg(&serial->dev->dev, - "%s - iPAQ module configured for %d ports\n", __func__, - serial->num_ports); - return usb_reset_configuration(serial->dev); } From 49f4ff2d74f5b6a865f6433c8995855092dcf97a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:41 +0100 Subject: [PATCH 38/61] USB: serial: io_ti: use calc_num_endpoints to verify endpoints Use the calc_num_ports rather than attach callback to verify that the required endpoints are present when in download mode. This avoids allocating port resources for interfaces that won't be bound. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index a76b95d32157..989795ab064a 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2544,19 +2544,30 @@ static void edge_heartbeat_work(struct work_struct *work) edge_heartbeat_schedule(serial); } +static int edge_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + struct device *dev = &serial->interface->dev; + unsigned char num_ports = serial->type->num_ports; + + /* Make sure we have the required endpoints when in download mode. */ + if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) { + if (epds->num_bulk_in < num_ports || + epds->num_bulk_out < num_ports) { + dev_err(dev, "required endpoints missing\n"); + return -ENODEV; + } + } + + return num_ports; +} + static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; int status; u16 product_id; - /* Make sure we have the required endpoints when in download mode. */ - if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) { - if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) - return -ENODEV; - } - /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); if (!edge_serial) @@ -2741,6 +2752,7 @@ static struct usb_serial_driver edgeport_1port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, @@ -2778,6 +2790,7 @@ static struct usb_serial_driver edgeport_2port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, From 8d9c4d9ebffe5ed7be34dad7bc4ef4ab6807c501 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:42 +0100 Subject: [PATCH 39/61] USB: serial: io_ti: always require a bulk-out endpoint These devices always require at least one bulk-out endpoint so let core verify that. This avoids attempting to send bulk data to the default pipe when downloading firmware in boot mode. Note that further endpoints are still needed when not in boot mode. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 989795ab064a..c315836793b3 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2747,6 +2747,7 @@ static struct usb_serial_driver edgeport_1port_device = { .description = "Edgeport TI 1 port adapter", .id_table = edgeport_1port_id_table, .num_ports = 1, + .num_bulk_out = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, @@ -2785,6 +2786,7 @@ static struct usb_serial_driver edgeport_2port_device = { .description = "Edgeport TI 2 port adapter", .id_table = edgeport_2port_id_table, .num_ports = 2, + .num_bulk_out = 1, .open = edge_open, .close = edge_close, .throttle = edge_throttle, From 9c8299b43e577828057988eb8bd4920ab656022b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:43 +0100 Subject: [PATCH 40/61] USB: serial: io_ti: verify interrupt endpoint at probe Verify that the required interrupt endpoint is present at probe rather than at open to avoid allocating resources for an unusable device. Note that the endpoint is only required when in download mode. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c315836793b3..a962082cf3b0 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1933,13 +1933,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (edge_serial->num_ports_open == 0) { /* we are the first port to open, post the interrupt urb */ urb = edge_serial->serial->port[0]->interrupt_in_urb; - if (!urb) { - dev_err(&port->dev, - "%s - no interrupt urb present, exiting\n", - __func__); - status = -EINVAL; - goto release_es_lock; - } urb->context = edge_serial; status = usb_submit_urb(urb, GFP_KERNEL); if (status) { @@ -2553,7 +2546,8 @@ static int edge_calc_num_ports(struct usb_serial *serial, /* Make sure we have the required endpoints when in download mode. */ if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) { if (epds->num_bulk_in < num_ports || - epds->num_bulk_out < num_ports) { + epds->num_bulk_out < num_ports || + epds->num_interrupt_in < 1) { dev_err(dev, "required endpoints missing\n"); return -ENODEV; } From 772b2c5d6c929d9d35e9c915dea8df8c6a799aed Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:44 +0100 Subject: [PATCH 41/61] USB: serial: io_ti: drop redundant read-urb check Drop the redundant read-urb check from open. The presence of a bulk-in endpoint is now verified during probe and core has allocated the corresponding resources. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index a962082cf3b0..f3ed131d14bf 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1952,12 +1952,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) /* start up our bulk read urb */ urb = port->read_urb; - if (!urb) { - dev_err(&port->dev, "%s - no read urb present, exiting\n", - __func__); - status = -EINVAL; - goto unlink_int_urb; - } edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; urb->context = edge_port; status = usb_submit_urb(urb, GFP_KERNEL); From d760557d38ba62a8fe91dec5e32acb4fdf52d9d4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:45 +0100 Subject: [PATCH 42/61] USB: serial: mos7720: clean up mcs7715 port setup Clean up the mcs7715 port setup by using the new endpoint-remap functionality provided by core. Instead of poking around in internal port-structure fields, simply swap the endpoint descriptors of the two ports in calc_num_ports before the port structures are even allocated. Note that we still need to override the default interrupt completion handler. Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7720.c | 52 ++++++++++++++---------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 9ec3e4fb9678..eabea0bc1a04 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -977,8 +977,20 @@ static int mos77xx_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - if (product == MOSCHIP_DEVICE_ID_7715) + + if (product == MOSCHIP_DEVICE_ID_7715) { + /* + * The 7715 uses the first bulk in/out endpoint pair for the + * parallel port, and the second for the serial port. We swap + * the endpoint descriptors here so that the the first and + * only registered port structure uses the serial-port + * endpoints. + */ + swap(epds->bulk_in[0], epds->bulk_in[1]); + swap(epds->bulk_out[0], epds->bulk_out[1]); + return 1; + } return 2; } @@ -1904,46 +1916,22 @@ static int mos7720_startup(struct usb_serial *serial) product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; - /* - * The 7715 uses the first bulk in/out endpoint pair for the parallel - * port, and the second for the serial port. Because the usbserial core - * assumes both pairs are serial ports, we must engage in a bit of - * subterfuge and swap the pointers for ports 0 and 1 in order to make - * port 0 point to the serial port. However, both moschip devices use a - * single interrupt-in endpoint for both ports (as mentioned a little - * further down), and this endpoint was assigned to port 0. So after - * the swap, we must copy the interrupt endpoint elements from port 1 - * (as newly assigned) to port 0, and null out port 1 pointers. - */ - if (product == MOSCHIP_DEVICE_ID_7715) { - struct usb_serial_port *tmp = serial->port[0]; - serial->port[0] = serial->port[1]; - serial->port[1] = tmp; - serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb; - serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer; - serial->port[0]->interrupt_in_endpointAddress = - tmp->interrupt_in_endpointAddress; - serial->port[1]->interrupt_in_urb = NULL; - serial->port[1]->interrupt_in_buffer = NULL; - - if (serial->port[0]->interrupt_in_urb) { - struct urb *urb = serial->port[0]->interrupt_in_urb; - - urb->complete = mos7715_interrupt_callback; - } - } - /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT if (product == MOSCHIP_DEVICE_ID_7715) { + struct urb *urb = serial->port[0]->interrupt_in_urb; + + if (urb) + urb->complete = mos7715_interrupt_callback; + +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT ret_val = mos7715_parport_init(serial); if (ret_val < 0) return ret_val; - } #endif + } /* start the interrupt urb */ ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); if (ret_val) { From 6a1eaf19f525ed9e4fa09ed1f05c6502a90b4ccb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:46 +0100 Subject: [PATCH 43/61] USB: serial: mos7720: always require an interrupt endpoint This driver have treated the interrupt endpoint as optional despite it always being present (according to the datasheet). Let's consider it mandatory instead. Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7720.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index eabea0bc1a04..b1f6b275e7c1 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1923,8 +1923,7 @@ static int mos7720_startup(struct usb_serial *serial) if (product == MOSCHIP_DEVICE_ID_7715) { struct urb *urb = serial->port[0]->interrupt_in_urb; - if (urb) - urb->complete = mos7715_interrupt_callback; + urb->complete = mos7715_interrupt_callback; #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT ret_val = mos7715_parport_init(serial); @@ -2025,6 +2024,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .id_table = id_table, .num_bulk_in = 2, .num_bulk_out = 2, + .num_interrupt_in = 1, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, From 95254020235aa0c0f12bfb7d9b4cd18730dfc499 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:47 +0100 Subject: [PATCH 44/61] USB: serial: mos7840: clean up endpoint sanity check Clean up the endpoint sanity check by letting core verify the single interrupt endpoint, and verifying the bulk endpoints in calc_num_ports after having determined the number of ports. Note that the static type num_ports field was neither correct or used (since calc_num_ports never returns zero). Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7840.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 326d6c5055ef..770b3a470232 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2108,23 +2108,23 @@ static int mos7840_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { int device_type = (unsigned long)usb_get_serial_data(serial); - int mos7840_num_ports; + int num_ports; - mos7840_num_ports = (device_type >> 4) & 0x000F; + num_ports = (device_type >> 4) & 0x000F; - return mos7840_num_ports; -} + /* + * num_ports is currently never zero as device_type is one of + * MOSCHIP_DEVICE_ID_78{1,2,4}0. + */ + if (num_ports == 0) + return -ENODEV; -static int mos7840_attach(struct usb_serial *serial) -{ - if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports || - serial->num_interrupt_in < 1) { + if (epds->num_bulk_in < num_ports || epds->num_bulk_out < num_ports) { dev_err(&serial->interface->dev, "missing endpoints\n"); return -ENODEV; } - return 0; + return num_ports; } static int mos7840_port_probe(struct usb_serial_port *port) @@ -2385,7 +2385,7 @@ static struct usb_serial_driver moschip7840_4port_device = { }, .description = DRIVER_DESC, .id_table = id_table, - .num_ports = 4, + .num_interrupt_in = 1, .open = mos7840_open, .close = mos7840_close, .write = mos7840_write, @@ -2402,7 +2402,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .tiocmset = mos7840_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .attach = mos7840_attach, .port_probe = mos7840_port_probe, .port_remove = mos7840_port_remove, .read_bulk_callback = mos7840_bulk_in_callback, From 2dc1071b345816eca531360a22fa7a70563a7fc2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:48 +0100 Subject: [PATCH 45/61] USB: serial: omninet: clean up port setup These devices use the second bulk-out endpoint for writing. Instead of using the resources of the second port structure setup by core, use the new endpoint-remap functionality to simply ignore the first bulk-out endpoint. This specifically avoids allocating resources for the unused endpoint. Note that the disconnect callback was always redundant as all URBs would have been killed by USB core on disconnect. Signed-off-by: Johan Hovold --- drivers/usb/serial/omninet.c | 47 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 7be40dfa3620..558a620d8868 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -36,7 +36,8 @@ static void omninet_write_bulk_callback(struct urb *urb); static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); -static void omninet_disconnect(struct usb_serial *serial); +static int omninet_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds); static int omninet_port_probe(struct usb_serial_port *port); static int omninet_port_remove(struct usb_serial_port *port); @@ -54,15 +55,14 @@ static struct usb_serial_driver zyxel_omninet_device = { }, .description = "ZyXEL - omni.net lcd plus usb", .id_table = id_table, - .num_ports = 1, .num_bulk_out = 2, + .calc_num_ports = omninet_calc_num_ports, .port_probe = omninet_port_probe, .port_remove = omninet_port_remove, .write = omninet_write, .write_room = omninet_write_room, .write_bulk_callback = omninet_write_bulk_callback, .process_read_urb = omninet_process_read_urb, - .disconnect = omninet_disconnect, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -103,6 +103,16 @@ struct omninet_data { __u8 od_outseq; /* Sequence number for bulk_out URBs */ }; +static int omninet_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + /* We need only the second bulk-out for our single-port device. */ + epds->bulk_out[0] = epds->bulk_out[1]; + epds->num_bulk_out = 1; + + return 1; +} + static int omninet_port_probe(struct usb_serial_port *port) { struct omninet_data *od; @@ -150,13 +160,9 @@ static void omninet_process_read_urb(struct urb *urb) static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = serial->port[1]; - struct omninet_data *od = usb_get_serial_port_data(port); struct omninet_header *header = (struct omninet_header *) - wport->write_urb->transfer_buffer; - + port->write_urb->transfer_buffer; int result; if (count == 0) { @@ -171,11 +177,11 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; - memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, + memcpy(port->write_urb->transfer_buffer + OMNINET_HEADERLEN, buf, count); usb_serial_debug_data(&port->dev, __func__, count, - wport->write_urb->transfer_buffer); + port->write_urb->transfer_buffer); header->oh_seq = od->od_outseq++; header->oh_len = count; @@ -183,11 +189,11 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, header->oh_pad = 0x00; /* send the data out the bulk port, always 64 bytes */ - wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; + port->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; - result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { - set_bit(0, &wport->write_urbs_free); + set_bit(0, &port->write_urbs_free); dev_err_console(port, "%s - failed submitting write urb, error %d\n", __func__, result); @@ -201,13 +207,10 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, static int omninet_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = serial->port[1]; - int room = 0; /* Default: no room */ - if (test_bit(0, &wport->write_urbs_free)) - room = wport->bulk_out_size - OMNINET_HEADERLEN; + if (test_bit(0, &port->write_urbs_free)) + room = port->bulk_out_size - OMNINET_HEADERLEN; dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); @@ -231,14 +234,6 @@ static void omninet_write_bulk_callback(struct urb *urb) usb_serial_port_softint(port); } - -static void omninet_disconnect(struct usb_serial *serial) -{ - struct usb_serial_port *wport = serial->port[1]; - - usb_kill_urb(wport->write_urb); -} - module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); From d27444152c0d1fb969ee0acb8334287cf8b30d1b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:49 +0100 Subject: [PATCH 46/61] USB: serial: omninet: use generic write implementation Now that the endpoint-port mapping has been properly set up during probe, we can switch to using the more efficient generic write implementation. Note that this currently means that chars_in_buffer now overcounts slightly as we always write a full endpoint-sized packet. Also add a copyright entry. Signed-off-by: Johan Hovold --- drivers/usb/serial/omninet.c | 93 +++++++----------------------------- 1 file changed, 17 insertions(+), 76 deletions(-) diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 558a620d8868..efcd7feed6f4 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -1,6 +1,8 @@ /* * USB ZyXEL omni.net LCD PLUS driver * + * Copyright (C) 2013,2017 Johan Hovold + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. @@ -32,10 +34,8 @@ /* function prototypes */ static void omninet_process_read_urb(struct urb *urb); -static void omninet_write_bulk_callback(struct urb *urb); -static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int omninet_write_room(struct tty_struct *tty); +static int omninet_prepare_write_buffer(struct usb_serial_port *port, + void *buf, size_t count); static int omninet_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds); static int omninet_port_probe(struct usb_serial_port *port); @@ -59,10 +59,8 @@ static struct usb_serial_driver zyxel_omninet_device = { .calc_num_ports = omninet_calc_num_ports, .port_probe = omninet_port_probe, .port_remove = omninet_port_remove, - .write = omninet_write, - .write_room = omninet_write_room, - .write_bulk_callback = omninet_write_bulk_callback, .process_read_urb = omninet_process_read_urb, + .prepare_write_buffer = omninet_prepare_write_buffer, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -157,81 +155,24 @@ static void omninet_process_read_urb(struct urb *urb) tty_flip_buffer_push(&port->port); } -static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) +static int omninet_prepare_write_buffer(struct usb_serial_port *port, + void *buf, size_t count) { struct omninet_data *od = usb_get_serial_port_data(port); - struct omninet_header *header = (struct omninet_header *) - port->write_urb->transfer_buffer; - int result; + struct omninet_header *header = buf; - if (count == 0) { - dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); - return 0; - } + count = min_t(size_t, count, OMNINET_PAYLOADSIZE); - if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dev_dbg(&port->dev, "%s - already writing\n", __func__); - return 0; - } + count = kfifo_out_locked(&port->write_fifo, buf + OMNINET_HEADERLEN, + count, &port->lock); - count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; + header->oh_seq = od->od_outseq++; + header->oh_len = count; + header->oh_xxx = 0x03; + header->oh_pad = 0x00; - memcpy(port->write_urb->transfer_buffer + OMNINET_HEADERLEN, - buf, count); - - usb_serial_debug_data(&port->dev, __func__, count, - port->write_urb->transfer_buffer); - - header->oh_seq = od->od_outseq++; - header->oh_len = count; - header->oh_xxx = 0x03; - header->oh_pad = 0x00; - - /* send the data out the bulk port, always 64 bytes */ - port->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; - - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - set_bit(0, &port->write_urbs_free); - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else - result = count; - - return result; -} - - -static int omninet_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int room = 0; /* Default: no room */ - - if (test_bit(0, &port->write_urbs_free)) - room = port->bulk_out_size - OMNINET_HEADERLEN; - - dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); - - return room; -} - -static void omninet_write_bulk_callback(struct urb *urb) -{ -/* struct omninet_header *header = (struct omninet_header *) - urb->transfer_buffer; */ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - set_bit(0, &port->write_urbs_free); - if (status) { - dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", - __func__, status); - return; - } - - usb_serial_port_softint(port); + /* always 64 bytes */ + return OMNINET_BULKOUTSIZE; } module_usb_serial_driver(serial_drivers, id_table); From c0dcf242d27a785930d73885471b368798720718 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:50 +0100 Subject: [PATCH 47/61] USB: serial: ti_usb_3410_5052: always require a bulk-out endpoint These devices always require at least one bulk-out endpoint so let core verify that. This avoids attempting to send bulk data to the default pipe when downloading firmware in boot mode. Note that further endpoints are still needed when not in boot mode. Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 3107bf5d1c96..e16558b63fcc 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -427,6 +427,7 @@ static struct usb_serial_driver ti_1port_device = { .description = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, .num_ports = 1, + .num_bulk_out = 1, .attach = ti_startup, .release = ti_release, .port_probe = ti_port_probe, @@ -459,6 +460,7 @@ static struct usb_serial_driver ti_2port_device = { .description = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, .num_ports = 2, + .num_bulk_out = 1, .attach = ti_startup, .release = ti_release, .port_probe = ti_port_probe, From a5b669f4c60e0bbb55b36e71ac4e273ab95160f3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:51 +0100 Subject: [PATCH 48/61] USB: serial: visor: drop redundant calc_num_ports callback Drop the redundant calc_num_ports callback from the clie_5 type, for which the callback always returns zero and hence falls back to the type num_ports value (2). Signed-off-by: Johan Hovold --- drivers/usb/serial/visor.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 3f943f877ac2..8b4429e4a73c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -197,7 +197,6 @@ static struct usb_serial_driver clie_5_device = { .unthrottle = usb_serial_generic_unthrottle, .attach = clie_5_attach, .probe = visor_probe, - .calc_num_ports = visor_calc_num_ports, .read_int_callback = visor_read_int_callback, }; From da2befa6d57e9dc04060207d98b130a59e2448cd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:52 +0100 Subject: [PATCH 49/61] USB: serial: visor: clean up clie_5 endpoint hack Use the new endpoint-remap functionality to configure the ports for clie_5 devices. Note that the same bulk-out endpoint is being used for both ports. Signed-off-by: Johan Hovold --- drivers/usb/serial/visor.c | 57 +++++++++++++++----------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 8b4429e4a73c..41d135f46fa0 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -42,10 +42,11 @@ static int visor_probe(struct usb_serial *serial, const struct usb_device_id *id); static int visor_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds); +static int clie_5_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds); static void visor_read_int_callback(struct urb *urb); static int clie_3_5_startup(struct usb_serial *serial); static int treo_attach(struct usb_serial *serial); -static int clie_5_attach(struct usb_serial *serial); static int palm_os_3_probe(struct usb_serial *serial, const struct usb_device_id *id); static int palm_os_4_probe(struct usb_serial *serial, @@ -190,13 +191,14 @@ static struct usb_serial_driver clie_5_device = { .description = "Sony Clie 5.0", .id_table = clie_id_5_table, .num_ports = 2, + .num_bulk_out = 2, .bulk_out_size = 256, .open = visor_open, .close = visor_close, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .attach = clie_5_attach, .probe = visor_probe, + .calc_num_ports = clie_5_calc_num_ports, .read_int_callback = visor_read_int_callback, }; @@ -477,6 +479,25 @@ static int visor_calc_num_ports(struct usb_serial *serial, return num_ports; } +static int clie_5_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + /* + * TH55 registers 2 ports. + * Communication in from the UX50/TH55 uses the first bulk-in + * endpoint, while communication out to the UX50/TH55 uses the second + * bulk-out endpoint. + */ + + /* + * FIXME: Should we swap the descriptors instead of using the same + * bulk-out endpoint for both ports? + */ + epds->bulk_out[0] = epds->bulk_out[1]; + + return serial->type->num_ports; +} + static int clie_3_5_startup(struct usb_serial *serial) { struct device *dev = &serial->dev->dev; @@ -588,38 +609,6 @@ static int treo_attach(struct usb_serial *serial) return 0; } -static int clie_5_attach(struct usb_serial *serial) -{ - struct usb_serial_port *port; - unsigned int pipe; - int j; - - /* TH55 registers 2 ports. - Communication in from the UX50/TH55 uses bulk_in_endpointAddress - from port 0. Communication out to the UX50/TH55 uses - bulk_out_endpointAddress from port 1 - - Lets do a quick and dirty mapping - */ - - /* some sanity check */ - if (serial->num_bulk_out < 2) { - dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); - return -ENODEV; - } - - /* port 0 now uses the modified endpoint Address */ - port = serial->port[0]; - port->bulk_out_endpointAddress = - serial->port[1]->bulk_out_endpointAddress; - - pipe = usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress); - for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) - port->write_urbs[j]->pipe = pipe; - - return 0; -} - module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); From ea3c6ebdcb4e6f9e1b16d9ced983a8f9131abd01 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:53 +0100 Subject: [PATCH 50/61] USB: serial: visor: clean up treo endpoint hack Use the new endpoint-remap functionality to configure the ports for treo devices instead of poking around in the port structures after the ports have been setup. Signed-off-by: Johan Hovold --- drivers/usb/serial/visor.c | 82 +++++++++++--------------------------- 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 41d135f46fa0..9f3317a940ef 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int clie_5_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds); static void visor_read_int_callback(struct urb *urb); static int clie_3_5_startup(struct usb_serial *serial); -static int treo_attach(struct usb_serial *serial); static int palm_os_3_probe(struct usb_serial *serial, const struct usb_device_id *id); static int palm_os_4_probe(struct usb_serial *serial, @@ -176,7 +175,6 @@ static struct usb_serial_driver handspring_device = { .close = visor_close, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .attach = treo_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, .read_int_callback = visor_read_int_callback, @@ -471,11 +469,35 @@ static int visor_probe(struct usb_serial *serial, static int visor_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { + unsigned int vid = le16_to_cpu(serial->dev->descriptor.idVendor); int num_ports = (int)(long)(usb_get_serial_data(serial)); if (num_ports) usb_set_serial_data(serial, NULL); + /* + * Only swap the bulk endpoints for the Handspring devices with + * interrupt in endpoints, which for now are the Treo devices. + */ + if (!(vid == HANDSPRING_VENDOR_ID || vid == KYOCERA_VENDOR_ID) || + epds->num_interrupt_in == 0) + goto out; + + if (epds->num_bulk_in < 2 || epds->num_interrupt_in < 2) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + /* + * It appears that Treos and Kyoceras want to use the + * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, + * so let's swap the 1st and 2nd bulk in and interrupt endpoints. + * Note that swapping the bulk out endpoints would break lots of + * apps that want to communicate on the second port. + */ + swap(epds->bulk_in[0], epds->bulk_in[1]); + swap(epds->interrupt_in[0], epds->interrupt_in[1]); +out: return num_ports; } @@ -553,62 +575,6 @@ out: return result; } -static int treo_attach(struct usb_serial *serial) -{ - struct usb_serial_port *swap_port; - - /* Only do this endpoint hack for the Handspring devices with - * interrupt in endpoints, which for now are the Treo devices. */ - if (!((le16_to_cpu(serial->dev->descriptor.idVendor) - == HANDSPRING_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) - == KYOCERA_VENDOR_ID)) || - (serial->num_interrupt_in == 0)) - return 0; - - if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } - - /* - * It appears that Treos and Kyoceras want to use the - * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, - * so let's swap the 1st and 2nd bulk in and interrupt endpoints. - * Note that swapping the bulk out endpoints would break lots of - * apps that want to communicate on the second port. - */ -#define COPY_PORT(dest, src) \ - do { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(src->read_urbs); ++i) { \ - dest->read_urbs[i] = src->read_urbs[i]; \ - dest->read_urbs[i]->context = dest; \ - dest->bulk_in_buffers[i] = src->bulk_in_buffers[i]; \ - } \ - dest->read_urb = src->read_urb; \ - dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\ - dest->bulk_in_buffer = src->bulk_in_buffer; \ - dest->bulk_in_size = src->bulk_in_size; \ - dest->interrupt_in_urb = src->interrupt_in_urb; \ - dest->interrupt_in_urb->context = dest; \ - dest->interrupt_in_endpointAddress = \ - src->interrupt_in_endpointAddress;\ - dest->interrupt_in_buffer = src->interrupt_in_buffer; \ - } while (0); - - swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL); - if (!swap_port) - return -ENOMEM; - COPY_PORT(swap_port, serial->port[0]); - COPY_PORT(serial->port[0], serial->port[1]); - COPY_PORT(serial->port[1], swap_port); - kfree(swap_port); - - return 0; -} - module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); From bc4c2c15cbfc3747d0c14f547beb5d46cbe43641 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:54 +0100 Subject: [PATCH 51/61] USB: serial: mxuport: register two ports for unknown devices Print a message and register two ports for interfaces for which we do not know how many ports there are instead of binding, allocating resources, but not register any ports. This provides a hint that anyone adding a dynamic device id must also provide a reference id (driver info) from which the port count can be retrieved, for example: echo 0 0x110A 0x1410 > new_id Signed-off-by: Johan Hovold --- drivers/usb/serial/mxuport.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index bf543e6c05ea..3355737cbfd1 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -950,17 +950,23 @@ static int mxuport_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { unsigned long features = (unsigned long)usb_get_serial_data(serial); + int num_ports; - if (features & MX_UPORT_2_PORT) - return 2; - if (features & MX_UPORT_4_PORT) - return 4; - if (features & MX_UPORT_8_PORT) - return 8; - if (features & MX_UPORT_16_PORT) - return 16; + if (features & MX_UPORT_2_PORT) { + num_ports = 2; + } else if (features & MX_UPORT_4_PORT) { + num_ports = 4; + } else if (features & MX_UPORT_8_PORT) { + num_ports = 8; + } else if (features & MX_UPORT_16_PORT) { + num_ports = 16; + } else { + dev_warn(&serial->interface->dev, + "unknown device, assuming two ports\n"); + num_ports = 2; + } - return 0; + return num_ports; } /* Get the version of the firmware currently running. */ @@ -1367,7 +1373,6 @@ static struct usb_serial_driver mxuport_device = { }, .description = "MOXA UPort", .id_table = mxuport_idtable, - .num_ports = 0, .probe = mxuport_probe, .port_probe = mxuport_port_probe, .attach = mxuport_attach, From 6b0464c9d76bb6a3b192f6d518f7e5f510af72e8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:55 +0100 Subject: [PATCH 52/61] USB: serial: mxuport: add endpoint sanity check Add an explicit sanity check to make sure we have the expected endpoints. This will provide a descriptive error message in case an expected endpoint is missing when probing. Note that the driver already gracefully fails to probe (albeit with a less descriptive error message) if a bulk-in endpoint is missing, and an attempt to write to a port whose device lack a bulk-out endpoint would fail with -ENODEV. Signed-off-by: Johan Hovold --- drivers/usb/serial/mxuport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 3355737cbfd1..34142feffd4d 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -1373,6 +1373,8 @@ static struct usb_serial_driver mxuport_device = { }, .description = "MOXA UPort", .id_table = mxuport_idtable, + .num_bulk_in = 2, + .num_bulk_out = 1, .probe = mxuport_probe, .port_probe = mxuport_port_probe, .attach = mxuport_attach, From d69f138747b92856cad63437f859f27da9d8ea70 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:56 +0100 Subject: [PATCH 53/61] USB: serial: mxuport: clean up port bulk-out setup Setup each port to use the first bulk-out endpoint in calc_num_ports so that core allocates the corresponding port resources for us. Signed-off-by: Johan Hovold --- drivers/usb/serial/mxuport.c | 103 ++++------------------------------- 1 file changed, 12 insertions(+), 91 deletions(-) diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 34142feffd4d..3aef091fe88b 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -951,6 +951,7 @@ static int mxuport_calc_num_ports(struct usb_serial *serial, { unsigned long features = (unsigned long)usb_get_serial_data(serial); int num_ports; + int i; if (features & MX_UPORT_2_PORT) { num_ports = 2; @@ -966,6 +967,17 @@ static int mxuport_calc_num_ports(struct usb_serial *serial, num_ports = 2; } + /* + * Setup bulk-out endpoint multiplexing. All ports share the same + * bulk-out endpoint. + */ + BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < 16); + + for (i = 1; i < num_ports; ++i) + epds->bulk_out[i] = epds->bulk_out[0]; + + epds->num_bulk_out = num_ports; + return num_ports; } @@ -1149,102 +1161,11 @@ static int mxuport_port_probe(struct usb_serial_port *port) port->port_number); } -static int mxuport_alloc_write_urb(struct usb_serial *serial, - struct usb_serial_port *port, - struct usb_serial_port *port0, - int j) -{ - struct usb_device *dev = interface_to_usbdev(serial->interface); - - set_bit(j, &port->write_urbs_free); - port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urbs[j]) - return -ENOMEM; - - port->bulk_out_buffers[j] = kmalloc(port0->bulk_out_size, GFP_KERNEL); - if (!port->bulk_out_buffers[j]) - return -ENOMEM; - - usb_fill_bulk_urb(port->write_urbs[j], dev, - usb_sndbulkpipe(dev, port->bulk_out_endpointAddress), - port->bulk_out_buffers[j], - port->bulk_out_size, - serial->type->write_bulk_callback, - port); - return 0; -} - - -static int mxuport_alloc_write_urbs(struct usb_serial *serial, - struct usb_serial_port *port, - struct usb_serial_port *port0) -{ - int j; - int ret; - - for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { - ret = mxuport_alloc_write_urb(serial, port, port0, j); - if (ret) - return ret; - } - return 0; -} - - static int mxuport_attach(struct usb_serial *serial) { struct usb_serial_port *port0 = serial->port[0]; struct usb_serial_port *port1 = serial->port[1]; - struct usb_serial_port *port; int err; - int i; - int j; - - /* - * Throw away all but the first allocated write URBs so we can - * set them up again to fit the multiplexing scheme. - */ - for (i = 1; i < serial->num_bulk_out; ++i) { - port = serial->port[i]; - for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { - usb_free_urb(port->write_urbs[j]); - kfree(port->bulk_out_buffers[j]); - port->write_urbs[j] = NULL; - port->bulk_out_buffers[j] = NULL; - } - port->write_urbs_free = 0; - } - - /* - * All write data is sent over the first bulk out endpoint, - * with an added header to indicate the port. Allocate URBs - * for each port to the first bulk out endpoint. - */ - for (i = 1; i < serial->num_ports; ++i) { - port = serial->port[i]; - port->bulk_out_size = port0->bulk_out_size; - port->bulk_out_endpointAddress = - port0->bulk_out_endpointAddress; - - err = mxuport_alloc_write_urbs(serial, port, port0); - if (err) - return err; - - port->write_urb = port->write_urbs[0]; - port->bulk_out_buffer = port->bulk_out_buffers[0]; - - /* - * Ensure each port has a fifo. The framework only - * allocates a fifo to ports with a bulk out endpoint, - * where as we need one for every port. - */ - if (!kfifo_initialized(&port->write_fifo)) { - err = kfifo_alloc(&port->write_fifo, PAGE_SIZE, - GFP_KERNEL); - if (err) - return err; - } - } /* * All data from the ports is received on the first bulk in From 5e07240a12101af8481a90283da766905caf35f8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:57 +0100 Subject: [PATCH 54/61] USB: serial: f81534: clean up calc_num_ports Clean up calc_num_ports with respect to handling older chips that lack config data. Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index be106f4e3e57..365e3acd6c6c 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -681,12 +681,13 @@ static int f81534_calc_num_ports(struct usb_serial *serial, ++num_port; } - if (num_port) - return num_port; + if (!num_port) { + dev_warn(&serial->interface->dev, + "no config found, assuming 4 ports\n"); + num_port = 4; /* Nothing found, oldest version IC */ + } - dev_warn(&serial->interface->dev, "%s: Read Failed. default 4 ports\n", - __func__); - return 4; /* Nothing found, oldest version IC */ + return num_port; } static void f81534_set_termios(struct tty_struct *tty, From d5ccfce09249e1c2f0fe62718e29b0993e4a4022 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Mar 2017 17:13:58 +0100 Subject: [PATCH 55/61] USB: serial: f81534: clean up port bulk-out setup Setup each port to use the first bulk-out endpoint in calc_num_ports so that core allocates the corresponding port resources for us. Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 62 +++++++------------------------------ 1 file changed, 11 insertions(+), 51 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 365e3acd6c6c..3d616a2a9f96 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -687,6 +687,17 @@ static int f81534_calc_num_ports(struct usb_serial *serial, num_port = 4; /* Nothing found, oldest version IC */ } + /* + * Setup bulk-out endpoint multiplexing. All ports share the same + * bulk-out endpoint. + */ + BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < F81534_NUM_PORT); + + for (i = 1; i < num_port; ++i) + epds->bulk_out[i] = epds->bulk_out[0]; + + epds->num_bulk_out = num_port; + return num_port; } @@ -1078,53 +1089,6 @@ static void f81534_write_usb_callback(struct urb *urb) } } -static int f81534_setup_ports(struct usb_serial *serial) -{ - struct usb_serial_port *port; - u8 port0_out_address; - int buffer_size; - size_t i; - - /* - * In our system architecture, we had 2 or 4 serial ports, - * but only get 1 set of bulk in/out endpoints. - * - * The usb-serial subsystem will generate port 0 data, - * but port 1/2/3 will not. It's will generate write URB and buffer - * by following code and use the port0 read URB for read operation. - */ - for (i = 1; i < serial->num_ports; ++i) { - port0_out_address = serial->port[0]->bulk_out_endpointAddress; - buffer_size = serial->port[0]->bulk_out_size; - port = serial->port[i]; - - if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) - return -ENOMEM; - - port->bulk_out_size = buffer_size; - port->bulk_out_endpointAddress = port0_out_address; - - port->write_urbs[0] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urbs[0]) - return -ENOMEM; - - port->bulk_out_buffers[0] = kzalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_out_buffers[0]) - return -ENOMEM; - - usb_fill_bulk_urb(port->write_urbs[0], serial->dev, - usb_sndbulkpipe(serial->dev, - port0_out_address), - port->bulk_out_buffers[0], buffer_size, - serial->type->write_bulk_callback, port); - - port->write_urb = port->write_urbs[0]; - port->bulk_out_buffer = port->bulk_out_buffers[0]; - } - - return 0; -} - static int f81534_attach(struct usb_serial *serial) { struct f81534_serial_private *serial_priv; @@ -1141,10 +1105,6 @@ static int f81534_attach(struct usb_serial *serial) mutex_init(&serial_priv->urb_mutex); - status = f81534_setup_ports(serial); - if (status) - return status; - /* Check had custom setting */ status = f81534_find_config_idx(serial, &serial_priv->setting_idx); if (status) { From bc242fc107c71354181ba82bd9e539de8d088ae9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 28 Mar 2017 12:13:50 +0200 Subject: [PATCH 56/61] USB: serial: drop termios-flag debugging Drop some unnecessary termios-flag debugging that have been faithfully reproduced in a few old drivers, including the "clfag" typo and all. This also addresses a compiler warning on sparc where tcflag_t is unsigned long and would have required an explicit cast. Reported-by: Geert Uytterhoeven Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 5 ----- drivers/usb/serial/io_ti.c | 8 -------- drivers/usb/serial/mos7720.c | 11 ----------- drivers/usb/serial/mos7840.c | 10 ---------- drivers/usb/serial/ti_usb_3410_5052.c | 8 -------- 5 files changed, 42 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 751e7454c37b..e5d6265eac6e 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1544,11 +1544,6 @@ static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int cflag; - - cflag = tty->termios.c_cflag; - dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios.c_cflag, tty->termios.c_iflag); - dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index f3ed131d14bf..87798e625d6c 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2372,14 +2372,6 @@ static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int cflag; - - cflag = tty->termios.c_cflag; - - dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, - tty->termios.c_cflag, tty->termios.c_iflag); - dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, - old_termios->c_cflag, old_termios->c_iflag); if (edge_port == NULL) return; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index b1f6b275e7c1..c3a314d5bdc6 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1688,7 +1688,6 @@ static void mos7720_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { int status; - unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7720_port; @@ -1704,16 +1703,6 @@ static void mos7720_set_termios(struct tty_struct *tty, return; } - dev_dbg(&port->dev, "setting termios - ASPIRE\n"); - - cflag = tty->termios.c_cflag; - - dev_dbg(&port->dev, "%s - cflag %08x iflag %08x\n", __func__, - tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); - - dev_dbg(&port->dev, "%s - old cflag %08x old iflag %08x\n", __func__, - old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); - /* change the port settings to the new ones specified */ change_port_settings(tty, mos7720_port, old_termios); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 770b3a470232..e8669aae14b3 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1868,7 +1868,6 @@ static void mos7840_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { int status; - unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; @@ -1890,15 +1889,6 @@ static void mos7840_set_termios(struct tty_struct *tty, return; } - dev_dbg(&port->dev, "%s", "setting termios - \n"); - - cflag = tty->termios.c_cflag; - - dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, - tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); - dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, - old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); - /* change the port settings to the new ones specified */ mos7840_change_port_settings(tty, mos7840_port, old_termios); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index e16558b63fcc..8fc3854e5e69 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -929,7 +929,6 @@ static void ti_set_termios(struct tty_struct *tty, { struct ti_port *tport = usb_get_serial_port_data(port); struct ti_uart_config *config; - tcflag_t cflag, iflag; int baud; int status; int port_number = port->port_number; @@ -937,13 +936,6 @@ static void ti_set_termios(struct tty_struct *tty, u16 wbaudrate; u16 wflags = 0; - cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; - - dev_dbg(&port->dev, "%s - cflag %08x, iflag %08x\n", __func__, cflag, iflag); - dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__, - old_termios->c_cflag, old_termios->c_iflag); - config = kmalloc(sizeof(*config), GFP_KERNEL); if (!config) return; From e1fdd5b2620198979b23abb679848a78461481e6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 15:46:30 +0200 Subject: [PATCH 57/61] USB: serial: drop obsolete open-race workaround Commit a65a6f14dc24 ("USB: serial: fix race between probe and open") fixed a race between probe and open, which could lead to crashes when a not yet fully initialised port was being opened. This race was later incidentally closed by commit 7e73eca6a7b2 ("TTY: move cdev_add to tty_register_device") which moved character-device registration from tty_register_driver to tty_register_device, which isn't called until the port has been fully set up. Remove the now redundant workaround which had the negative side effect of not allowing a port to be opened immediately after user space had been notified of a new tty device. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 0fa2030c275c..c7ca95f64edc 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -996,12 +996,6 @@ static int usb_serial_probe(struct usb_interface *interface, serial->attached = 1; } - /* Avoid race with tty_open and serial_install by setting the - * disconnected flag and not clearing it until all ports have been - * registered. - */ - serial->disconnected = 1; - if (allocate_minors(serial, num_ports)) { dev_err(ddev, "No more free serial minor numbers\n"); goto probe_error; @@ -1019,8 +1013,6 @@ static int usb_serial_probe(struct usb_interface *interface, dev_err(ddev, "Error registering port device, continuing\n"); } - serial->disconnected = 0; - if (num_ports > 0) usb_serial_console_init(serial->port[0]->minor); exit: From 7aac5e7d204f344f5f273deeeb8fd237e4f5b87c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 3 Apr 2017 11:57:14 +0200 Subject: [PATCH 58/61] USB: serial: iuu_phoenix: drop excessive sanity checks The transfer buffers and URBs are allocated and initialised by USB serial core during probe, and there's no need to check for NULL transfer buffers in the bulk-in completion handlers. Signed-off-by: Johan Hovold --- drivers/usb/serial/iuu_phoenix.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 7dd1601e4a02..18fc992a245f 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -588,9 +588,8 @@ static void read_buf_callback(struct urb *urb) } dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length); - if (data == NULL) - dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); - if (urb->actual_length && data) { + + if (urb->actual_length) { tty_insert_flip_string(&port->port, data, urb->actual_length); tty_flip_buffer_push(&port->port); } @@ -655,10 +654,8 @@ static void iuu_uart_read_callback(struct urb *urb) /* error stop all */ return; } - if (data == NULL) - dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__); - if (urb->actual_length == 1 && data != NULL) + if (urb->actual_length == 1) len = (int) data[0]; if (urb->actual_length > 1) { From 185fcb3fbe6d32d894b8b72429622d91c59b10f6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 3 Apr 2017 11:58:55 +0200 Subject: [PATCH 59/61] USB: serial: quatech2: drop redundant tty_buffer_request_room Drop redundant calls to tty_buffer_request_room and use the more efficient tty_insert_flip_char when inserting single characters. Signed-off-by: Johan Hovold --- drivers/usb/serial/quatech2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 6ddcaa2de902..60e17d1444c3 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -601,7 +601,6 @@ static void qt2_process_read_urb(struct urb *urb) escapeflag = true; break; case QT2_CONTROL_ESCAPE: - tty_buffer_request_room(&port->port, 2); tty_insert_flip_string(&port->port, ch, 2); i += 2; escapeflag = true; @@ -616,8 +615,7 @@ static void qt2_process_read_urb(struct urb *urb) continue; } - tty_buffer_request_room(&port->port, 1); - tty_insert_flip_string(&port->port, ch, 1); + tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); } tty_flip_buffer_push(&port->port); From 4f37fa549d0de7aee547783752e70f877a49b0c9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 18 Apr 2017 14:42:28 +0200 Subject: [PATCH 60/61] USB: serial: constify static arrays Declare three immutable static driver arrays as const. Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 6 +++--- drivers/usb/serial/mos7720.c | 2 +- drivers/usb/serial/usb_debug.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index e5d6265eac6e..bdf8bd814a9a 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2839,9 +2839,9 @@ static int edge_startup(struct usb_serial *serial) bool interrupt_in_found; bool bulk_in_found; bool bulk_out_found; - static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, - EDGE_COMPATIBILITY_MASK1, - EDGE_COMPATIBILITY_MASK2 }; + static const __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index c3a314d5bdc6..a453965f9e9a 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1408,7 +1408,7 @@ struct divisor_table_entry { /* Define table of divisors for moschip 7720 hardware * * These assume a 3.6864MHz crystal, the standard /16, and * * MCR.7 = 0. */ -static struct divisor_table_entry divisor_table[] = { +static const struct divisor_table_entry divisor_table[] = { { 50, 2304}, { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index ca2fa5bbe17e..d210eff4cd33 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -17,7 +17,7 @@ #define USB_DEBUG_MAX_PACKET_SIZE 8 #define USB_DEBUG_BRK_SIZE 8 -static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { +static const char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { 0x00, 0xff, 0x01, From 31c5d1922b90ddc1da6a6ddecef7cd31f17aa32b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 18 Apr 2017 20:07:56 +0200 Subject: [PATCH 61/61] USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit This development kit has an FT4232 on it with a custom USB VID/PID. The FT4232 provides four UARTs, but only two are used. The UART 0 is used by the FlashPro5 programmer and UART 2 is connected to the SmartFusion2 CortexM3 SoC UART port. Note that the USB VID is registered to Actel according to Linux USB VID database, but that was acquired by Microsemi. Signed-off-by: Marek Vasut Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 546171289869..d38780fa8788 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -873,6 +873,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0x00) }, + { USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 48ee04c94a75..71fb9e59db71 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -873,6 +873,12 @@ #define FIC_VID 0x1457 #define FIC_NEO1973_DEBUG_PID 0x5118 +/* + * Actel / Microsemi + */ +#define ACTEL_VID 0x1514 +#define MICROSEMI_ARROW_SF2PLUS_BOARD_PID 0x2008 + /* Olimex */ #define OLIMEX_VID 0x15BA #define OLIMEX_ARM_USB_OCD_PID 0x0003