diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-20 17:22:51 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-20 17:22:51 +0200 |
commit | 8ebe0e20bf483de2860073898f08cbdf855e93e0 (patch) | |
tree | 882f8e11ca110620b6bbbe84cbb57054de5abd77 /drivers/usb | |
parent | usb: host: xhci: print correct command ring address (diff) | |
parent | USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit (diff) | |
download | linux-8ebe0e20bf483de2860073898f08cbdf855e93e0.tar.xz linux-8ebe0e20bf483de2860073898f08cbdf855e93e0.zip |
Merge tag 'usb-serial-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
USB-serial updates for v4.12-rc1
Here are the USB-serial updates for 4.12, including:
- support for devices with up to 16 ports (e.g. some Moxa devices)
- support for endpoint sanity checks in core, which allows for code sharing
and avoids allocating resources for rejected interfaces
- support for endpoint-port remapping, which allows some driver hacks to
be removed as well as omninet to use the generic write implementation
- removal of an obsolete tty open-race workaround which prevented a
port from being opened immediately after having been registered
- generic-driver support for interfaces with just a bulk-in endpoint
- improved ftdi_sio event-char and latency-timer handling
- improved ftdi_sio support for some broken BM chips
Included are also various clean ups and a new ftdi_sio device id.
All have been in linux-next with no reported issues.
Signed-off-by: Johan Hovold <johan@kernel.org>
Diffstat (limited to 'drivers/usb')
30 files changed, 517 insertions, 923 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, 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, 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; 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) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 22f23a429a95..3d616a2a9f96 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -611,20 +611,30 @@ 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) { + 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) { dev_err(&serial->interface->dev, "%s: find idx failed: %d\n", __func__, status); - return 0; + return status; } /* @@ -640,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, @@ -656,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", @@ -671,12 +681,24 @@ 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 */ + } + + /* + * 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]; - dev_warn(&serial->interface->dev, "%s: Read Failed. default 4 ports\n", - __func__); - return 4; /* Nothing found, oldest version IC */ + epds->num_bulk_out = num_port; + + return num_port; } static void f81534_set_termios(struct tty_struct *tty, @@ -1067,96 +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_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; @@ -1173,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) { @@ -1380,12 +1308,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, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c540de15aad2..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 }, @@ -1406,6 +1407,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; @@ -1422,7 +1426,7 @@ 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; @@ -1440,11 +1444,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); @@ -1452,6 +1455,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) { @@ -1603,9 +1625,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; @@ -1685,9 +1717,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) @@ -1704,10 +1739,13 @@ 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; - dev_dbg(&port->dev, "%s: setting event char = %i\n", __func__, v); + if (kstrtouint(valbuf, 0, &v) || v >= 0x200) + return -EINVAL; + + dev_dbg(&port->dev, "%s: setting event char = 0x%03x\n", __func__, v); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 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 diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 49ce2be90fa0..35cb8c0e584f 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -37,13 +37,41 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ -struct usb_serial_driver usb_serial_generic_device = { +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; +} + +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; + + num_ports = max(epds->num_bulk_in, epds->num_bulk_out); + + if (num_ports == 0) { + dev_err(dev, "device has no bulk endpoints\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/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index bb7673e80a57..bdf8bd814a9a 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; @@ -2844,14 +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 }; - - if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) { - dev_err(&serial->interface->dev, "missing endpoints\n"); - return -ENODEV; - } + static const __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; @@ -3120,6 +3110,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 +3145,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 +3180,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 +3215,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, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index a76b95d32157..87798e625d6c 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) { @@ -1959,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); @@ -2385,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; @@ -2544,19 +2523,31 @@ static void edge_heartbeat_work(struct work_struct *work) edge_heartbeat_schedule(serial); } -static int edge_startup(struct usb_serial *serial) +static int edge_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { - struct edgeport_serial *edge_serial; - int status; - u16 product_id; + 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 (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) + if (epds->num_bulk_in < num_ports || + epds->num_bulk_out < num_ports || + epds->num_interrupt_in < 1) { + 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; + /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); if (!edge_serial) @@ -2736,11 +2727,13 @@ 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, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, @@ -2773,11 +2766,13 @@ 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, .unthrottle = edge_unthrottle, .attach = edge_startup, + .calc_num_ports = edge_calc_num_ports, .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_port_probe, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index ec1b8f2c1183..cde0dcdce9c4 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,42 +551,38 @@ 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 - * must be ignored as it would make the core - * create a second port which oopses when used + * 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. */ - int ipaq_num_ports = 1; - - dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__, - (int)serial->interface->cur_altsetting->desc.bNumEndpoints); + if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) + return -ENODEV; /* - * 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 ? + * A few devices have four endpoints, seemingly Yakuma devices, and + * we need the second pair. */ - if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) { - ipaq_num_ports = 2; + 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) { - /* 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 @@ -597,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); } diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 030390f37b0a..18fc992a245f 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; @@ -598,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); } @@ -665,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) { @@ -1183,6 +1170,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 +1182,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, }; 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, }; 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; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index f075121c6e32..a453965f9e9a 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -973,11 +973,24 @@ 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) + + 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; } @@ -1395,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 */ @@ -1675,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; @@ -1691,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); @@ -1900,54 +1902,24 @@ 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; - /* - * 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; + + 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) { @@ -2039,6 +2011,9 @@ 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, + .num_interrupt_in = 1, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 3821c53fcee9..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); @@ -2104,26 +2094,27 @@ 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; + 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) @@ -2384,7 +2375,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, @@ -2401,7 +2392,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, diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index c88215a0fa3d..3aef091fe88b 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -946,20 +946,39 @@ 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); + int num_ports; + int i; - 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; + /* + * 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; } /* Get the version of the firmware currently running. */ @@ -1142,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 @@ -1366,7 +1294,8 @@ static struct usb_serial_driver mxuport_device = { }, .description = "MOXA UPort", .id_table = mxuport_idtable, - .num_ports = 0, + .num_bulk_in = 2, + .num_bulk_out = 1, .probe = mxuport_probe, .port_probe = mxuport_port_probe, .attach = mxuport_attach, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index dd706953b466..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 <johan@kernel.org> + * * 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,12 +34,10 @@ /* 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 void omninet_disconnect(struct usb_serial *serial); -static int omninet_attach(struct usb_serial *serial); +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); static int omninet_port_remove(struct usb_serial_port *port); @@ -55,15 +55,12 @@ 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, + .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, + .prepare_write_buffer = omninet_prepare_write_buffer, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -104,15 +101,14 @@ struct omninet_data { __u8 od_outseq; /* Sequence number for bulk_out URBs */ }; -static int omninet_attach(struct usb_serial *serial) +static int omninet_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { - /* 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; - } + /* 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 0; + return 1; } static int omninet_port_probe(struct usb_serial_port *port) @@ -159,96 +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 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; - - int result; - - if (count == 0) { - dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); - return 0; - } - - if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dev_dbg(&port->dev, "%s - already writing\n", __func__); - return 0; - } - - count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; - - memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, - buf, count); - - usb_serial_debug_data(&port->dev, __func__, count, - wport->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 */ - wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; - - result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); - if (result) { - set_bit(0, &wport->write_urbs_free); - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else - result = count; - - return result; -} + struct omninet_header *header = buf; + count = min_t(size_t, count, OMNINET_PAYLOADSIZE); -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; - - 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; - } + count = kfifo_out_locked(&port->write_fifo, buf + OMNINET_HEADERLEN, + count, &port->lock); - usb_serial_port_softint(port); -} - - -static void omninet_disconnect(struct usb_serial *serial) -{ - struct usb_serial_port *wport = serial->port[1]; + header->oh_seq = od->od_outseq++; + header->oh_len = count; + header->oh_xxx = 0x03; + header->oh_pad = 0x00; - usb_kill_urb(wport->write_urb); + /* always 64 bytes */ + return OMNINET_BULKOUTSIZE; } module_usb_serial_driver(serial_drivers, id_table); 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, 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; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ca69eb42071b..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,20 +223,68 @@ static int pl2303_probe(struct usb_serial *serial, return 0; } +/* + * 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; + 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; + + if (interface == dev->actconfig->interface[0]) + return 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)) + 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; + } + + if (epds->num_interrupt_in < 1) { + dev_err(dev, "required interrupt-in endpoint missing\n"); + return -ENODEV; + } + + return 1; +} + 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; @@ -938,7 +991,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 = 0, /* see pl2303_calc_num_ports */ .bulk_in_size = 256, .bulk_out_size = 256, .open = pl2303_open, @@ -954,6 +1009,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/quatech2.c b/drivers/usb/serial/quatech2.c index fdbb904d153f..60e17d1444c3 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; @@ -600,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; @@ -615,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); 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/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, }; 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, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 3107bf5d1c96..8fc3854e5e69 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, @@ -927,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; @@ -935,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; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4a037b4a79cf..c7ca95f64edc 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -38,7 +38,6 @@ #include <linux/usb/serial.h> #include <linux/kfifo.h> #include <linux/idr.h> -#include "pl2303.h" #define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" #define DRIVER_DESC "USB Serial Driver core" @@ -710,6 +709,39 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_port_shutdown, }; +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; + + 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); + 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); + 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); + 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); + epds->interrupt_out[epds->num_interrupt_out++] = epd; + } + } +} + static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -717,23 +749,15 @@ 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; - int num_interrupt_in = 0; - int num_interrupt_out = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; int num_ports = 0; - int max_endpoints; + unsigned char max_endpoints; mutex_lock(&table_lock); type = search_serial_device(interface); @@ -752,8 +776,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,129 +789,48 @@ 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; } } /* 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; } -#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]) { - /* 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 (num_interrupt_in < MAX_NUM_PORTS) { - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - } - } - } + find_endpoints(serial, epds); - /* 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 (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; - } - } - /* END HORRIBLE HACK FOR PL2303 */ -#endif - -#ifdef CONFIG_USB_SERIAL_GENERIC - if (type == &usb_serial_generic_device) { - 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; - } - 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"); + 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; } -#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 (!num_ports) - num_ports = type->num_ports; + + 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; + if (num_ports > MAX_NUM_PORTS) { dev_warn(ddev, "too many ports requested: %d\n", num_ports); num_ports = MAX_NUM_PORTS; } - serial->num_ports = 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_ports = (unsigned char)num_ports; + 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); @@ -895,10 +838,10 @@ 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(max_endpoints, (int)serial->num_ports); + 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; dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints); @@ -923,8 +866,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)); @@ -952,8 +895,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; @@ -985,8 +928,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) @@ -1005,13 +948,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) @@ -1031,7 +974,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"); } @@ -1053,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; @@ -1076,18 +1013,23 @@ 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: + kfree(epds); module_put(type->driver.owner); return 0; probe_error: + retval = -EIO; +err_free_epds: + kfree(epds); +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) 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, diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 337a0be89fcf..9f3317a940ef 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -40,11 +40,12 @@ 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 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, @@ -174,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, @@ -189,14 +189,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 = visor_calc_num_ports, + .calc_num_ports = clie_5_calc_num_ports, .read_int_callback = visor_read_int_callback, }; @@ -466,16 +466,60 @@ 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) { + 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; } +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; @@ -531,94 +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; -} - -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); 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; |