]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'usb-serial-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Apr 2017 15:22:51 +0000 (17:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Apr 2017 15:22:51 +0000 (17:22 +0200)
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>
31 files changed:
drivers/usb/serial/aircable.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/f81534.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/mxuport.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/quatech2.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
include/linux/usb/serial.h

index 80a9845cd93fba16e50ae7797606b7b9b925c887..569c2200ba42a915902385ed61f71bd8e0f124cc 100644 (file)
  * 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,
index 2779e59c30f1e3532d036b37c97f799d963c52fb..0adbd38b4eeaef03ab7f4230158bd37cdb918a01 100644 (file)
@@ -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,
index 80260b08398b2e55833c65d21e0be70cc43ccf01..47fbd9f0c0c7a8508f23b562f4a220dbd19bc33f 100644 (file)
@@ -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;
index 6537d3ca2797d8573236578e3088f6dbce1ce1b5..2ce39af32cfa614c2b7ccd26d2df1581cfc89c16 100644 (file)
@@ -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)
index 22f23a429a95cb6a1cdeaca445a92035fd3e98e8..3d616a2a9f963a96e73ae865651d40e868aeb4c9 100644 (file)
@@ -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,
index c540de15aad2c7d301543aef202b3560fb2f7399..d38780fa87881a0ef3696e73e61527304271393c 100644 (file)
@@ -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),
index 48ee04c94a7541ad6c5f9023be107246207c56fd..71fb9e59db7125c845a9a1c23c4e33430a142a3e 100644 (file)
 #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
index 49ce2be90fa00e5b4305784f2532e34069752072..35cb8c0e584fc19f4550e24eb7b35fed3819bcc4 100644 (file)
@@ -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,
index bb7673e80a57aeeba501cd7dc4628394c491f1d0..bdf8bd814a9aaf89d646545cac01da659ab475b6 100644 (file)
@@ -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,
index a76b95d32157871f5e2964b629784a7642da8480..87798e625d6c827ed09b79a011eb46cdd770c864 100644 (file)
@@ -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,
index ec1b8f2c11837fecd39468c1e053880d72da9f94..cde0dcdce9c4d1402b69076c2a6a228b36963833 100644 (file)
@@ -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);
 }
 
index 030390f37b0a8e4822a58b9e1e3fa412736ad451..18fc992a245fcd8c700aea392ed2a1fcf9d584ea 100644 (file)
@@ -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,
 };
index d2dab2a341b827d558eea480858b791344fd38b6..196908dd25a1e8f6591643a0149f4d83c46f3c62 100644 (file)
@@ -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,
 };
index 813035f51fe73a4e0de69ce76e6c3329ba4d376c..3024b9b253605160a5f5e7038159bcc47ec4d1ea 100644 (file)
@@ -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;
index f075121c6e32329d136935d2d1d56ae8b49c784f..a453965f9e9a3153ffcbb28d4a6257a4db094cd3 100644 (file)
@@ -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,
index 3821c53fcee9ec2c269ce562ef25d7a67ed34965..e8669aae14b3504d5e8cf2a6db25900edd66e269 100644 (file)
@@ -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,
index c88215a0fa3d8d0eaa22be4e873cf59d2525e481..3aef091fe88b6b69540e012cc0842dcdb8e77e59 100644 (file)
@@ -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,
index dd706953b4660905cc5abf5e85477bfb6bdb4149..efcd7feed6f4d1c882627736de30253ca2858da6 100644 (file)
@@ -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.
 
 /* 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);
index 3937b9c3cc691b778cfb7a310a6e5400ee53d095..58657d64678ba06eff913acec8c7584a19502db9 100644 (file)
@@ -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,
index b8bf52bf7a944d5fddd6976f90a63db3cd6807e5..b11eead469eee85860119eda06db9aecec5e1838 100644 (file)
@@ -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;
index ca69eb42071bcb1ed5d01706698e2289d5757b03..c9ebefd8f35fdbe5491627f4df89b80c87aeabad 100644 (file)
 
 #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,
index fdbb904d153f735b83c007137eaa42d5bf76a6b4..60e17d1444c39fc50f4fbd85a579e967ba823775 100644 (file)
@@ -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);
index 465e851b281585b3b7445177868a061cecfd3c15..4c4ac4705ac03f8d850a653fe91e35b78bfe25b6 100644 (file)
@@ -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;
index ddfd787c461cb5367c1f932b3edffb42c0812832..5167b6564c8b4574016aa48d068bb290e3ade06e 100644 (file)
@@ -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,
 };
index 37f3ad15ed06a5f6c1cf9db54ca0beef801d523f..0d1727232d0c1b2168804a557a71a24c2dcce247 100644 (file)
@@ -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,
index 3107bf5d1c966bbe35f4b0c84af803fcf0c0308e..8fc3854e5e6967dc32f1a04e5ba95a304f10b683 100644 (file)
@@ -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;
index 4a037b4a79cf3168cb45d60d1b6488ac21681570..c7ca95f64edc2b178dec37f852dbb90333efe637 100644 (file)
@@ -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)
index ca2fa5bbe17e1a9406079a89571e8dd31a083c9a..d210eff4cd33af1d33b735043f47fe971246ecf6 100644 (file)
@@ -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,
index 337a0be89fcf0767f67731a9b0a50700e1df9318..9f3317a940ef6a8d88767eaa919bb4b61f6f13b6 100644 (file)
@@ -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);
index 5ab65eb1dacc8b5aa2fdf5152df2a381180683c2..55cebc1e6fec1d6a2664e2d796c49e2af728af75 100644 (file)
@@ -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;
index 704a1ab8240ca124f29c5ce361c871090d28ea5b..e2f0ab07eea5bd4d6b49abb7c563d7816934394d 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/kfifo.h>
 
 /* 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))
@@ -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;
@@ -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
@@ -188,12 +199,17 @@ 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)
  * @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
@@ -227,19 +243,26 @@ 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;
+
+       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;
 
        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);
@@ -356,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;