Declare functions in a the right order to avoid prototyping.
There is no functional change here.

Signed-off-by: Mathieu OTHACEHE <[email protected]>
---
 drivers/usb/serial/ti_usb_3410_5052.c | 1112 ++++++++++++++++-----------------
 1 file changed, 544 insertions(+), 568 deletions(-)

diff --git a/drivers/usb/serial/ti_usb_3410_5052.c 
b/drivers/usb/serial/ti_usb_3410_5052.c
index 1e36c46..95bdcca 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -286,28 +286,6 @@ struct ti_device {
        int model;
 };
 
-static int ti_startup(struct usb_serial *serial);
-static void ti_release(struct usb_serial *serial);
-static int ti_port_probe(struct usb_serial_port *port);
-static int ti_port_remove(struct usb_serial_port *port);
-static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ti_close(struct usb_serial_port *port);
-static bool ti_tx_empty(struct usb_serial_port *port);
-static int ti_ioctl(struct tty_struct *tty,
-               unsigned int cmd, unsigned long arg);
-static void ti_set_termios(struct tty_struct *tty,
-               struct usb_serial_port *port, struct ktermios *old_termios);
-static int ti_tiocmget(struct tty_struct *tty);
-static int ti_tiocmset(struct tty_struct *tty,
-               unsigned int set, unsigned int clear);
-static void ti_break(struct tty_struct *tty, int break_state);
-static void ti_interrupt_callback(struct urb *urb);
-
-static int ti_set_mcr(struct usb_serial_port *port, unsigned int mcr);
-static int ti_get_lsr(struct usb_serial_port *port, u8 *lsr);
-static void ti_handle_new_msr(struct usb_serial_port *port, u8 msr);
-static int ti_download_firmware(struct usb_serial *serial);
-
 static const struct usb_device_id ti_id_table_3410[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
@@ -372,80 +350,7 @@ static const struct usb_device_id ti_id_table_combined[] = 
{
        { }     /* terminator */
 };
 
-static struct usb_serial_driver ti_1port_device = {
-       .driver = {
-               .owner          = THIS_MODULE,
-               .name           = "ti_usb_3410_5052_1",
-       },
-       .description            = "TI USB 3410 1 port adapter",
-       .id_table               = ti_id_table_3410,
-       .num_ports              = 1,
-       .attach                 = ti_startup,
-       .release                = ti_release,
-       .port_probe             = ti_port_probe,
-       .port_remove            = ti_port_remove,
-       .open                   = ti_open,
-       .close                  = ti_close,
-       .tx_empty               = ti_tx_empty,
-       .ioctl                  = ti_ioctl,
-       .set_termios            = ti_set_termios,
-       .tiocmget               = ti_tiocmget,
-       .tiocmset               = ti_tiocmset,
-       .tiocmiwait             = usb_serial_generic_tiocmiwait,
-       .get_icount             = usb_serial_generic_get_icount,
-       .break_ctl              = ti_break,
-       .read_int_callback      = ti_interrupt_callback,
-};
-
-static struct usb_serial_driver ti_2port_device = {
-       .driver = {
-               .owner          = THIS_MODULE,
-               .name           = "ti_usb_3410_5052_2",
-       },
-       .description            = "TI USB 5052 2 port adapter",
-       .id_table               = ti_id_table_5052,
-       .num_ports              = 2,
-       .attach                 = ti_startup,
-       .release                = ti_release,
-       .port_probe             = ti_port_probe,
-       .port_remove            = ti_port_remove,
-       .open                   = ti_open,
-       .close                  = ti_close,
-       .tx_empty               = ti_tx_empty,
-       .ioctl                  = ti_ioctl,
-       .set_termios            = ti_set_termios,
-       .tiocmget               = ti_tiocmget,
-       .tiocmset               = ti_tiocmset,
-       .tiocmiwait             = usb_serial_generic_tiocmiwait,
-       .get_icount             = usb_serial_generic_get_icount,
-       .break_ctl              = ti_break,
-       .read_int_callback      = ti_interrupt_callback,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &ti_1port_device, &ti_2port_device, NULL
-};
-
-MODULE_AUTHOR(TI_DRIVER_AUTHOR);
-MODULE_DESCRIPTION(TI_DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-MODULE_FIRMWARE("ti_3410.fw");
-MODULE_FIRMWARE("ti_5052.fw");
-MODULE_FIRMWARE("mts_cdma.fw");
-MODULE_FIRMWARE("mts_gsm.fw");
-MODULE_FIRMWARE("mts_edge.fw");
-MODULE_FIRMWARE("mts_mt9234mu.fw");
-MODULE_FIRMWARE("mts_mt9234zba.fw");
-MODULE_FIRMWARE("moxa/moxa-1110.fw");
-MODULE_FIRMWARE("moxa/moxa-1130.fw");
-MODULE_FIRMWARE("moxa/moxa-1131.fw");
-MODULE_FIRMWARE("moxa/moxa-1150.fw");
-MODULE_FIRMWARE("moxa/moxa-1151.fw");
-
-MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
-
-module_usb_serial_driver(serial_drivers, ti_id_table_combined);
+static struct usb_serial_driver ti_1port_device;
 
 static int ti_send_ctrl_data_urb(struct usb_serial *serial, u8 request,
                                 u16 value, u16 index, void *data, size_t size)
@@ -512,120 +417,134 @@ static int ti_recv_ctrl_data_urb(struct usb_serial 
*serial, u8 request,
        return 0;
 }
 
-static int ti_write_byte(struct usb_serial_port *port, u32 addr,
-                       u8 mask, u8 byte)
+static int ti_do_download(struct usb_serial *serial,
+                         const struct firmware *fw_p)
 {
-       int status;
-       size_t size;
-       struct ti_write_data_bytes *data;
+       int pos;
+       u8 cs = 0;
+       int done;
+       struct usb_device *dev = serial->dev;
+       struct ti_firmware_header *header;
+       int status = 0;
+       u8 *buffer;
+       int buffer_size;
+       int len;
+       unsigned int pipe;
 
-       dev_dbg(&port->dev, "%s - addr 0x%08X, mask 0x%02X, byte 0x%02X\n",
-               __func__, addr, mask, byte);
+       pipe = usb_sndbulkpipe(dev, serial->port[0]->bulk_out_endpointAddress);
 
-       size = sizeof(struct ti_write_data_bytes) + 2;
-       data = kmalloc(size, GFP_KERNEL);
-       if (!data)
+       buffer_size = fw_p->size;
+       buffer = kmalloc(buffer_size, GFP_KERNEL);
+       if (!buffer)
                return -ENOMEM;
 
-       data->bAddrType = TI_RW_DATA_ADDR_XDATA;
-       data->bDataType = TI_RW_DATA_BYTE;
-       data->bDataCounter = 1;
-       data->wBaseAddrHi = cpu_to_be16(addr >> 16);
-       data->wBaseAddrLo = cpu_to_be16(addr);
-       data->bData[0] = mask;
-       data->bData[1] = byte;
+       memcpy(buffer, fw_p->data, fw_p->size);
 
-       status = ti_send_ctrl_data_urb(port->serial, TI_WRITE_DATA, 0,
-                                      TI_RAM_PORT, data, size);
-       if (status < 0)
-               dev_err(&port->dev, "%s - failed: %d\n", __func__, status);
+       for (pos = sizeof(*header); pos < buffer_size; pos++)
+               cs = (u8)(cs + buffer[pos]);
 
-       kfree(data);
+       header = (struct ti_firmware_header *)buffer;
+       header->wLength = cpu_to_le16(buffer_size - sizeof(*header));
+       header->bCheckSum = cs;
 
-       return status;
+       dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
+       for (pos = 0; pos < buffer_size; pos += done) {
+               len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
+               status = usb_bulk_msg(dev, pipe, buffer + pos, len, &done,
+                                     TI_DOWNLOAD_TIMEOUT);
+               if (status)
+                       break;
+       }
+
+       kfree(buffer);
+
+       if (status) {
+               dev_err(&dev->dev, "failed to download firmware: %d\n", status);
+               return status;
+       }
+
+       dev_dbg(&dev->dev, "%s - download successful\n", __func__);
+
+       return 0;
 }
 
-static int ti_startup(struct usb_serial *serial)
+static int ti_download_firmware(struct usb_serial *serial)
 {
-       struct ti_device *tdev;
-       struct usb_device *dev = serial->dev;
-       struct usb_host_interface *cur_altsetting;
-       int num_endpoints;
-       u16 vid, pid;
        int status;
+       struct usb_device *dev = serial->dev;
+       struct ti_device *tdev = usb_get_serial_data(serial);
+       const struct firmware *fw_p;
+       char buf[32];
+       __le16 vendor, product;
 
-       dev_dbg(&dev->dev,
-               "%s - product 0x%4X, num configurations %d, configuration value 
%d\n",
-               __func__, le16_to_cpu(dev->descriptor.idProduct),
-               dev->descriptor.bNumConfigurations,
-               dev->actconfig->desc.bConfigurationValue);
-
-       tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
-       if (!tdev)
-               return -ENOMEM;
-
-       mutex_init(&tdev->open_close_lock);
-       usb_set_serial_data(serial, tdev);
+       vendor = le16_to_cpu(dev->descriptor.idVendor);
+       product = le16_to_cpu(dev->descriptor.idProduct);
 
-       /* determine device type */
-       if (serial->type == &ti_1port_device)
-               tdev->is_3410 = true;
-       dev_dbg(&dev->dev, "%s - device type is: %s\n", __func__,
-               tdev->is_3410 ? "3410" : "5052");
+       if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
+               snprintf(buf,
+                       sizeof(buf),
+                       "moxa/moxa-%04x.fw",
+                       le16_to_cpu(dev->descriptor.idProduct));
 
-       vid = le16_to_cpu(dev->descriptor.idVendor);
-       pid = le16_to_cpu(dev->descriptor.idProduct);
-       if (vid == MXU1_VENDOR_ID) {
-               switch (pid) {
-               case MXU1_1130_PRODUCT_ID:
-               case MXU1_1131_PRODUCT_ID:
-                       tdev->rs485_only = true;
-                       break;
-               }
+               status = request_firmware(&fw_p, buf, &dev->dev);
+               goto check_firmware;
        }
 
-       cur_altsetting = serial->interface->cur_altsetting;
-       num_endpoints = cur_altsetting->desc.bNumEndpoints;
-
-       /* if we have only 1 configuration and 1 endpoint, download firmware */
-       if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) {
-               status = ti_download_firmware(serial);
+       /* try ID specific firmware first, then try generic firmware */
+       sprintf(buf, "ti_usb-v%04x-p%04x.fw", vendor, product);
+       status = request_firmware(&fw_p, buf, &dev->dev);
 
-               if (status != 0)
-                       goto free_tdev;
+       if (status != 0) {
+               buf[0] = '\0';
+               if (vendor == MTS_VENDOR_ID) {
+                       switch (product) {
+                       case MTS_CDMA_PRODUCT_ID:
+                               strcpy(buf, "mts_cdma.fw");
+                               break;
+                       case MTS_GSM_PRODUCT_ID:
+                               strcpy(buf, "mts_gsm.fw");
+                               break;
+                       case MTS_EDGE_PRODUCT_ID:
+                               strcpy(buf, "mts_edge.fw");
+                               break;
+                       case MTS_MT9234MU_PRODUCT_ID:
+                               strcpy(buf, "mts_mt9234mu.fw");
+                               break;
+                       case MTS_MT9234ZBA_PRODUCT_ID:
+                               strcpy(buf, "mts_mt9234zba.fw");
+                               break;
+                       case MTS_MT9234ZBAOLD_PRODUCT_ID:
+                               strcpy(buf, "mts_mt9234zba.fw");
+                               break;                  }
+               }
 
-               /* 3410 must be reset, 5052 resets itself */
-               if (tdev->is_3410) {
-                       msleep_interruptible(100);
-                       usb_reset_device(dev);
+               if (buf[0] == '\0') {
+                       if (tdev->is_3410)
+                               strcpy(buf, "ti_3410.fw");
+                       else
+                               strcpy(buf, "ti_5052.fw");
                }
+               status = request_firmware(&fw_p, buf, &dev->dev);
+       }
 
-               status = -ENODEV;
-               goto free_tdev;
+check_firmware:
+       if (status) {
+               dev_err(&dev->dev, "failed to request firmware: %d\n", status);
+               return -ENOENT;
        }
 
-       /* the second configuration must be set */
-       if (dev->actconfig->desc.bConfigurationValue == TI_BOOT_CONFIG) {
-               status = usb_driver_set_configuration(dev, TI_ACTIVE_CONFIG);
-               status = status ? status : -ENODEV;
-               goto free_tdev;
+       if (fw_p->size > TI_FIRMWARE_BUF_SIZE) {
+               dev_err(&dev->dev, "firmware too large: %zu\n", fw_p->size);
+               release_firmware(fw_p);
+               return -ENOENT;
        }
 
+       ti_do_download(serial, fw_p);
+
+       release_firmware(fw_p);
+
        return 0;
-
-free_tdev:
-       kfree(tdev);
-       usb_set_serial_data(serial, NULL);
-       return status;
-}
-
-
-static void ti_release(struct usb_serial *serial)
-{
-       struct ti_device *tdev = usb_get_serial_data(serial);
-
-       kfree(tdev);
-}
+}
 
 static int ti_port_probe(struct usb_serial_port *port)
 {
@@ -670,258 +589,157 @@ static int ti_port_remove(struct usb_serial_port *port)
        return 0;
 }
 
-static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
+static int ti_startup(struct usb_serial *serial)
 {
-       struct ti_port *tport = usb_get_serial_port_data(port);
-       struct ti_device *tdev = usb_get_serial_data(port->serial);
-       struct usb_serial *serial = port->serial;
-       struct urb *urb;
-       int port_number;
+       struct ti_device *tdev;
+       struct usb_device *dev = serial->dev;
+       struct usb_host_interface *cur_altsetting;
+       int num_endpoints;
+       u16 vid, pid;
        int status;
-       u16 open_settings;
 
-       open_settings = (TI_PIPE_MODE_CONTINUOUS |
-                        TI_PIPE_TIMEOUT_ENABLE |
-                        (TI_TRANSFER_TIMEOUT << 2));
+       dev_dbg(&dev->dev,
+               "%s - product 0x%4X, num configurations %d, configuration value 
%d\n",
+               __func__, le16_to_cpu(dev->descriptor.idProduct),
+               dev->descriptor.bNumConfigurations,
+               dev->actconfig->desc.bConfigurationValue);
 
-       /* only one open on any port on a device at a time */
-       if (mutex_lock_interruptible(&tdev->open_close_lock))
-               return -ERESTARTSYS;
+       tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
+       if (!tdev)
+               return -ENOMEM;
 
-       port_number = port->port_number;
+       mutex_init(&tdev->open_close_lock);
+       usb_set_serial_data(serial, tdev);
 
-       tport->msr = 0;
+       /* determine device type */
+       if (serial->type == &ti_1port_device)
+               tdev->is_3410 = true;
+       dev_dbg(&dev->dev, "%s - device type is: %s\n", __func__,
+               tdev->is_3410 ? "3410" : "5052");
 
-       /* start interrupt urb the first time a port is opened on this device */
-       if (tdev->open_port_count == 0) {
-               dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__);
-               urb = serial->port[0]->interrupt_in_urb;
-               if (!urb) {
-                       dev_err(&port->dev, "no interrupt endpoint\n");
-                       status = -EINVAL;
-                       goto release_lock;
-               }
-               status = usb_submit_urb(urb, GFP_KERNEL);
-               if (status) {
-                       dev_err(&port->dev, "failed to submit interrupt urb: 
%d\n",
-                               status);
-                       goto release_lock;
+       vid = le16_to_cpu(dev->descriptor.idVendor);
+       pid = le16_to_cpu(dev->descriptor.idProduct);
+       if (vid == MXU1_VENDOR_ID) {
+               switch (pid) {
+               case MXU1_1130_PRODUCT_ID:
+               case MXU1_1131_PRODUCT_ID:
+                       tdev->rs485_only = true;
+                       break;
                }
        }
 
-       if (tty)
-               ti_set_termios(tty, port, NULL);
+       cur_altsetting = serial->interface->cur_altsetting;
+       num_endpoints = cur_altsetting->desc.bNumEndpoints;
 
-       status = ti_send_ctrl_urb(serial, TI_OPEN_PORT, open_settings,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot send open command: %d\n", status);
-               goto unlink_int_urb;
-       }
+       /* if we have only 1 configuration and 1 endpoint, download firmware */
+       if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) {
+               status = ti_download_firmware(serial);
 
-       status = ti_send_ctrl_urb(serial, TI_START_PORT, 0,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot send start command: %d\n", status);
-               goto unlink_int_urb;
-       }
+               if (status != 0)
+                       goto free_tdev;
 
-       status = ti_send_ctrl_urb(serial, TI_PURGE_PORT, TI_PURGE_INPUT,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot clear input buffers: %d\n", status);
-               goto unlink_int_urb;
-       }
+               /* 3410 must be reset, 5052 resets itself */
+               if (tdev->is_3410) {
+                       msleep_interruptible(100);
+                       usb_reset_device(dev);
+               }
 
-       status = ti_send_ctrl_urb(serial, TI_PURGE_PORT, TI_PURGE_OUTPUT,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot clear output buffers: %d\n",
-                       status);
-               goto unlink_int_urb;
+               status = -ENODEV;
+               goto free_tdev;
        }
 
-       /*
-        * reset the data toggle on the bulk endpoints to work around bug in
-        * host controllers where things get out of sync some times
-        */
-       usb_clear_halt(serial->dev, port->write_urb->pipe);
-       usb_clear_halt(serial->dev, port->read_urb->pipe);
-
-       if (tty)
-               ti_set_termios(tty, port, NULL);
-
-       status = ti_send_ctrl_urb(serial, TI_OPEN_PORT, open_settings,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot send open command (2): %d\n",
-                       status);
-               goto unlink_int_urb;
+       /* the second configuration must be set */
+       if (dev->actconfig->desc.bConfigurationValue == TI_BOOT_CONFIG) {
+               status = usb_driver_set_configuration(dev, TI_ACTIVE_CONFIG);
+               status = status ? status : -ENODEV;
+               goto free_tdev;
        }
 
-       status = ti_send_ctrl_urb(serial, TI_START_PORT, 0,
-                                 TI_UART1_PORT + port_number);
-       if (status) {
-               dev_err(&port->dev, "cannot send start command (2): %d\n",
-                       status);
-               goto unlink_int_urb;
-       }
+       return 0;
 
-       status = usb_serial_generic_open(tty, port);
-       if (status)
-               goto unlink_int_urb;
+free_tdev:
+       kfree(tdev);
+       usb_set_serial_data(serial, NULL);
+       return status;
+}
 
-       ++tdev->open_port_count;
 
-       goto release_lock;
+static void ti_release(struct usb_serial *serial)
+{
+       struct ti_device *tdev = usb_get_serial_data(serial);
 
-unlink_int_urb:
-       if (tdev->open_port_count == 0)
-               usb_kill_urb(serial->port[0]->interrupt_in_urb);
-release_lock:
-       mutex_unlock(&tdev->open_close_lock);
-       return status;
+       kfree(tdev);
 }
 
-
-static void ti_close(struct usb_serial_port *port)
+static int ti_write_byte(struct usb_serial_port *port, u32 addr,
+                       u8 mask, u8 byte)
 {
-       struct ti_device *tdev;
-       struct ti_port *tport;
        int status;
-       int do_unlock;
+       size_t size;
+       struct ti_write_data_bytes *data;
 
-       tdev = usb_get_serial_data(port->serial);
-       tport = usb_get_serial_port_data(port);
+       dev_dbg(&port->dev, "%s - addr 0x%08X, mask 0x%02X, byte 0x%02X\n",
+               __func__, addr, mask, byte);
 
-       usb_serial_generic_close(port);
+       size = sizeof(struct ti_write_data_bytes) + 2;
+       data = kmalloc(size, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-       status = ti_send_ctrl_urb(port->serial, TI_CLOSE_PORT, 0,
-                                 TI_UART1_PORT + port->port_number);
-       if (status) {
-               dev_err(&port->dev, "failed to send close port command: %d\n",
-                       status);
-       }
+       data->bAddrType = TI_RW_DATA_ADDR_XDATA;
+       data->bDataType = TI_RW_DATA_BYTE;
+       data->bDataCounter = 1;
+       data->wBaseAddrHi = cpu_to_be16(addr >> 16);
+       data->wBaseAddrLo = cpu_to_be16(addr);
+       data->bData[0] = mask;
+       data->bData[1] = byte;
 
-       /* if mutex_lock is interrupted, continue anyway */
-       do_unlock = !mutex_lock_interruptible(&tdev->open_close_lock);
-       tdev->open_port_count--;
-       if (tdev->open_port_count <= 0) {
-               /* last port is closed, shut down interrupt urb */
-               usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-               tdev->open_port_count = 0;
-       }
-       if (do_unlock)
-               mutex_unlock(&tdev->open_close_lock);
+       status = ti_send_ctrl_data_urb(port->serial, TI_WRITE_DATA, 0,
+                                      TI_RAM_PORT, data, size);
+       if (status < 0)
+               dev_err(&port->dev, "%s - failed: %d\n", __func__, status);
+
+       kfree(data);
+
+       return status;
 }
 
-static bool ti_tx_empty(struct usb_serial_port *port)
+static int ti_set_mcr(struct usb_serial_port *port, unsigned int mcr)
 {
-       int ret;
-       u8 lsr;
-
-       ret = ti_get_lsr(port, &lsr);
-       if (!ret && !(lsr & TI_LSR_TX_EMPTY))
-               return false;
+       struct ti_port *tport = usb_get_serial_port_data(port);
+       int status;
 
-       return true;
+       status = ti_write_byte(port,
+                              tport->uart_base_addr + TI_UART_OFFSET_MCR,
+                              TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr);
+       return status;
 }
 
-static int ti_get_serial_info(struct usb_serial_port *port,
-                             struct serial_struct __user *ret_arg)
+static void ti_set_termios(struct tty_struct *tty,
+                          struct usb_serial_port *port,
+                          struct ktermios *old_termios)
 {
+       struct ti_port *tport = usb_get_serial_port_data(port);
        struct ti_device *tdev = usb_get_serial_data(port->serial);
-       struct serial_struct ret_serial;
-       unsigned int cwait;
-       int baud_base;
+       struct ti_uart_config *config;
+       tcflag_t cflag, iflag;
+       int baud;
+       int status;
+       int port_number = port->port_number;
+       unsigned int mcr;
 
-       if (!ret_arg)
-               return -EFAULT;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
-       cwait = port->port.closing_wait;
-       if (cwait != ASYNC_CLOSING_WAIT_NONE)
-               cwait = jiffies_to_msecs(cwait) / 10;
+       if (old_termios &&
+               !tty_termios_hw_change(&tty->termios, old_termios) &&
+               tty->termios.c_iflag == old_termios->c_iflag) {
+               dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
+               return;
+       }
 
-       memset(&ret_serial, 0, sizeof(ret_serial));
-
-       if (tdev->is_3410)
-               baud_base = TI_3410_BAUD_BASE;
-       else
-               baud_base = TI_5052_BAUD_BASE;
-
-       ret_serial.type = PORT_16550A;
-       ret_serial.line = port->minor;
-       ret_serial.port = port->port_number;
-       ret_serial.xmit_fifo_size = port->bulk_out_size;
-       ret_serial.baud_base = baud_base;
-       ret_serial.closing_wait = cwait;
-
-       if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int ti_set_serial_info(struct usb_serial_port *port,
-                             struct serial_struct __user *new_arg)
-{
-       struct serial_struct new_serial;
-       unsigned int cwait;
-
-       if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
-               return -EFAULT;
-
-       cwait = new_serial.closing_wait;
-       if (cwait != ASYNC_CLOSING_WAIT_NONE)
-               cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
-
-       port->port.closing_wait = cwait;
-
-       return 0;
-}
-
-static int ti_ioctl(struct tty_struct *tty,
-                   unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return ti_get_serial_info(port,
-                                         (struct serial_struct __user *)arg);
-       case TIOCSSERIAL:
-               return ti_set_serial_info(port,
-                                         (struct serial_struct __user *)arg);
-       }
-       return -ENOIOCTLCMD;
-}
-
-
-static void ti_set_termios(struct tty_struct *tty,
-                          struct usb_serial_port *port,
-                          struct ktermios *old_termios)
-{
-       struct ti_port *tport = usb_get_serial_port_data(port);
-       struct ti_device *tdev = usb_get_serial_data(port->serial);
-       struct ti_uart_config *config;
-       tcflag_t cflag, iflag;
-       int baud;
-       int status;
-       int port_number = port->port_number;
-       unsigned int mcr;
-
-       cflag = tty->termios.c_cflag;
-       iflag = tty->termios.c_iflag;
-
-       if (old_termios &&
-               !tty_termios_hw_change(&tty->termios, old_termios) &&
-               tty->termios.c_iflag == old_termios->c_iflag) {
-               dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
-               return;
-       }
-
-       dev_dbg(&port->dev,
-               "%s - cflag 0x%08x, iflag 0x%08x\n", __func__, cflag, iflag);
+       dev_dbg(&port->dev,
+               "%s - cflag 0x%08x, iflag 0x%08x\n", __func__, cflag, iflag);
 
        if (old_termios) {
                dev_dbg(&port->dev, "%s - old clfag 0x%08x, old iflag 0x%08x\n",
@@ -1045,6 +863,74 @@ static void ti_set_termios(struct tty_struct *tty,
        kfree(config);
 }
 
+static int ti_get_serial_info(struct usb_serial_port *port,
+                             struct serial_struct __user *ret_arg)
+{
+       struct ti_device *tdev = usb_get_serial_data(port->serial);
+       struct serial_struct ret_serial;
+       unsigned int cwait;
+       int baud_base;
+
+       if (!ret_arg)
+               return -EFAULT;
+
+       cwait = port->port.closing_wait;
+       if (cwait != ASYNC_CLOSING_WAIT_NONE)
+               cwait = jiffies_to_msecs(cwait) / 10;
+
+       memset(&ret_serial, 0, sizeof(ret_serial));
+
+       if (tdev->is_3410)
+               baud_base = TI_3410_BAUD_BASE;
+       else
+               baud_base = TI_5052_BAUD_BASE;
+
+       ret_serial.type = PORT_16550A;
+       ret_serial.line = port->minor;
+       ret_serial.port = port->port_number;
+       ret_serial.xmit_fifo_size = port->bulk_out_size;
+       ret_serial.baud_base = baud_base;
+       ret_serial.closing_wait = cwait;
+
+       if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int ti_set_serial_info(struct usb_serial_port *port,
+                             struct serial_struct __user *new_arg)
+{
+       struct serial_struct new_serial;
+       unsigned int cwait;
+
+       if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
+               return -EFAULT;
+
+       cwait = new_serial.closing_wait;
+       if (cwait != ASYNC_CLOSING_WAIT_NONE)
+               cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+
+       port->port.closing_wait = cwait;
+
+       return 0;
+}
+
+static int ti_ioctl(struct tty_struct *tty,
+                   unsigned int cmd, unsigned long arg)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       switch (cmd) {
+       case TIOCGSERIAL:
+               return ti_get_serial_info(port,
+                                         (struct serial_struct __user *)arg);
+       case TIOCSSERIAL:
+               return ti_set_serial_info(port,
+                                         (struct serial_struct __user *)arg);
+       }
+       return -ENOIOCTLCMD;
+}
 
 static int ti_tiocmget(struct tty_struct *tty)
 {
@@ -1126,91 +1012,151 @@ static void ti_break(struct tty_struct *tty, int 
break_state)
                dev_dbg(&port->dev, "failed to set break: %d\n", status);
 }
 
-
-static void ti_interrupt_callback(struct urb *urb)
+static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-       struct usb_serial_port *port = urb->context;
-       unsigned char *data = urb->transfer_buffer;
-       int length = urb->actual_length;
+       struct ti_port *tport = usb_get_serial_port_data(port);
+       struct ti_device *tdev = usb_get_serial_data(port->serial);
+       struct usb_serial *serial = port->serial;
+       struct urb *urb;
        int port_number;
-       int function;
-       int status = urb->status;
-       u8 msr;
-
-       switch (status) {
-       case 0:
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               dev_dbg(&port->dev, "%s - urb shutting down: %d\n",
-                       __func__, status);
-               return;
-       default:
-               dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
-                       __func__, status);
-               goto exit;
-       }
+       int status;
+       u16 open_settings;
 
-       if (length != 2) {
-               dev_dbg(&port->dev, "%s - bad packet size: %d\n",
-                       __func__, length);
-               goto exit;
-       }
+       open_settings = (TI_PIPE_MODE_CONTINUOUS |
+                        TI_PIPE_TIMEOUT_ENABLE |
+                        (TI_TRANSFER_TIMEOUT << 2));
 
-       if (data[0] == TI_CODE_HARDWARE_ERROR) {
-               dev_err(&port->dev, "%s - hardware error: %d\n",
-                       __func__, data[1]);
-               goto exit;
-       }
+       /* only one open on any port on a device at a time */
+       if (mutex_lock_interruptible(&tdev->open_close_lock))
+               return -ERESTARTSYS;
 
-       port_number = ti_get_port_from_code(data[0]);
-       function = ti_get_func_from_code(data[0]);
+       port_number = port->port_number;
 
-       dev_dbg(&port->dev, "%s - port_number %d, function %d, data 0x%02X\n",
-               __func__, port_number, function, data[1]);
+       tport->msr = 0;
 
-       if (port_number >= port->serial->num_ports) {
-               dev_err(&port->dev, "bad port number: %d\n", port_number);
-               goto exit;
+       /* start interrupt urb the first time a port is opened on this device */
+       if (tdev->open_port_count == 0) {
+               dev_dbg(&port->dev, "%s - start interrupt in urb\n", __func__);
+               urb = serial->port[0]->interrupt_in_urb;
+               if (!urb) {
+                       dev_err(&port->dev, "no interrupt endpoint\n");
+                       status = -EINVAL;
+                       goto release_lock;
+               }
+               status = usb_submit_urb(urb, GFP_KERNEL);
+               if (status) {
+                       dev_err(&port->dev, "failed to submit interrupt urb: 
%d\n",
+                               status);
+                       goto release_lock;
+               }
        }
 
-       switch (function) {
-       case TI_CODE_DATA_ERROR:
-               dev_dbg(&port->dev, "%s - DATA ERROR, port %d, data 0x%02X\n",
-                       __func__, port_number, data[1]);
-               break;
+       if (tty)
+               ti_set_termios(tty, port, NULL);
 
-       case TI_CODE_MODEM_STATUS:
-               msr = data[1];
-               ti_handle_new_msr(port, msr);
-               break;
+       status = ti_send_ctrl_urb(serial, TI_OPEN_PORT, open_settings,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot send open command: %d\n", status);
+               goto unlink_int_urb;
+       }
 
-       default:
-               dev_err(&port->dev, "unknown interrupt code: 0x%02X\n",
-                       data[1]);
-               break;
+       status = ti_send_ctrl_urb(serial, TI_START_PORT, 0,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot send start command: %d\n", status);
+               goto unlink_int_urb;
        }
 
-exit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               dev_err(&port->dev, "resubmit interrupt urb failed: %d\n",
-                       status);
-}
+       status = ti_send_ctrl_urb(serial, TI_PURGE_PORT, TI_PURGE_INPUT,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot clear input buffers: %d\n", status);
+               goto unlink_int_urb;
+       }
 
-static int ti_set_mcr(struct usb_serial_port *port, unsigned int mcr)
-{
-       struct ti_port *tport = usb_get_serial_port_data(port);
-       int status;
+       status = ti_send_ctrl_urb(serial, TI_PURGE_PORT, TI_PURGE_OUTPUT,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot clear output buffers: %d\n",
+                       status);
+               goto unlink_int_urb;
+       }
 
-       status = ti_write_byte(port,
-                              tport->uart_base_addr + TI_UART_OFFSET_MCR,
-                              TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr);
+       /*
+        * reset the data toggle on the bulk endpoints to work around bug in
+        * host controllers where things get out of sync some times
+        */
+       usb_clear_halt(serial->dev, port->write_urb->pipe);
+       usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+       if (tty)
+               ti_set_termios(tty, port, NULL);
+
+       status = ti_send_ctrl_urb(serial, TI_OPEN_PORT, open_settings,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot send open command (2): %d\n",
+                       status);
+               goto unlink_int_urb;
+       }
+
+       status = ti_send_ctrl_urb(serial, TI_START_PORT, 0,
+                                 TI_UART1_PORT + port_number);
+       if (status) {
+               dev_err(&port->dev, "cannot send start command (2): %d\n",
+                       status);
+               goto unlink_int_urb;
+       }
+
+       status = usb_serial_generic_open(tty, port);
+       if (status)
+               goto unlink_int_urb;
+
+       ++tdev->open_port_count;
+
+       goto release_lock;
+
+unlink_int_urb:
+       if (tdev->open_port_count == 0)
+               usb_kill_urb(serial->port[0]->interrupt_in_urb);
+release_lock:
+       mutex_unlock(&tdev->open_close_lock);
        return status;
 }
 
 
+static void ti_close(struct usb_serial_port *port)
+{
+       struct ti_device *tdev;
+       struct ti_port *tport;
+       int status;
+       int do_unlock;
+
+       tdev = usb_get_serial_data(port->serial);
+       tport = usb_get_serial_port_data(port);
+
+       usb_serial_generic_close(port);
+
+       status = ti_send_ctrl_urb(port->serial, TI_CLOSE_PORT, 0,
+                                 TI_UART1_PORT + port->port_number);
+       if (status) {
+               dev_err(&port->dev, "failed to send close port command: %d\n",
+                       status);
+       }
+
+       /* if mutex_lock is interrupted, continue anyway */
+       do_unlock = !mutex_lock_interruptible(&tdev->open_close_lock);
+       tdev->open_port_count--;
+       if (tdev->open_port_count <= 0) {
+               /* last port is closed, shut down interrupt urb */
+               usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+               tdev->open_port_count = 0;
+       }
+       if (do_unlock)
+               mutex_unlock(&tdev->open_close_lock);
+}
+
 static int ti_get_lsr(struct usb_serial_port *port, u8 *lsr)
 {
        int size, status;
@@ -1240,6 +1186,18 @@ free_data:
        return status;
 }
 
+static bool ti_tx_empty(struct usb_serial_port *port)
+{
+       int ret;
+       u8 lsr;
+
+       ret = ti_get_lsr(port, &lsr);
+       if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+               return false;
+
+       return true;
+}
+
 static void ti_handle_new_msr(struct usb_serial_port *port, u8 msr)
 {
        struct ti_port *tport = usb_get_serial_port_data(port);
@@ -1267,131 +1225,149 @@ static void ti_handle_new_msr(struct usb_serial_port 
*port, u8 msr)
        }
 }
 
-static int ti_do_download(struct usb_serial *serial,
-                         const struct firmware *fw_p)
+static void ti_interrupt_callback(struct urb *urb)
 {
-       int pos;
-       u8 cs = 0;
-       int done;
-       struct usb_device *dev = serial->dev;
-       struct ti_firmware_header *header;
-       int status = 0;
-       u8 *buffer;
-       int buffer_size;
-       int len;
-       unsigned int pipe;
-
-       pipe = usb_sndbulkpipe(dev, serial->port[0]->bulk_out_endpointAddress);
-
-       buffer_size = fw_p->size;
-       buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       memcpy(buffer, fw_p->data, fw_p->size);
-
-       for (pos = sizeof(*header); pos < buffer_size; pos++)
-               cs = (u8)(cs + buffer[pos]);
-
-       header = (struct ti_firmware_header *)buffer;
-       header->wLength = cpu_to_le16(buffer_size - sizeof(*header));
-       header->bCheckSum = cs;
+       struct usb_serial_port *port = urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       int length = urb->actual_length;
+       int port_number;
+       int function;
+       int status = urb->status;
+       u8 msr;
 
-       dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
-       for (pos = 0; pos < buffer_size; pos += done) {
-               len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
-               status = usb_bulk_msg(dev, pipe, buffer + pos, len, &done,
-                                     TI_DOWNLOAD_TIMEOUT);
-               if (status)
-                       break;
+       switch (status) {
+       case 0:
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               dev_dbg(&port->dev, "%s - urb shutting down: %d\n",
+                       __func__, status);
+               return;
+       default:
+               dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
+                       __func__, status);
+               goto exit;
        }
 
-       kfree(buffer);
+       if (length != 2) {
+               dev_dbg(&port->dev, "%s - bad packet size: %d\n",
+                       __func__, length);
+               goto exit;
+       }
 
-       if (status) {
-               dev_err(&dev->dev, "failed to download firmware: %d\n", status);
-               return status;
+       if (data[0] == TI_CODE_HARDWARE_ERROR) {
+               dev_err(&port->dev, "%s - hardware error: %d\n",
+                       __func__, data[1]);
+               goto exit;
        }
 
-       dev_dbg(&dev->dev, "%s - download successful\n", __func__);
+       port_number = ti_get_port_from_code(data[0]);
+       function = ti_get_func_from_code(data[0]);
 
-       return 0;
-}
+       dev_dbg(&port->dev, "%s - port_number %d, function %d, data 0x%02X\n",
+               __func__, port_number, function, data[1]);
 
-static int ti_download_firmware(struct usb_serial *serial)
-{
-       int status;
-       struct usb_device *dev = serial->dev;
-       struct ti_device *tdev = usb_get_serial_data(serial);
-       const struct firmware *fw_p;
-       char buf[32];
-       __le16 vendor, product;
+       if (port_number >= port->serial->num_ports) {
+               dev_err(&port->dev, "bad port number: %d\n", port_number);
+               goto exit;
+       }
 
-       vendor = le16_to_cpu(dev->descriptor.idVendor);
-       product = le16_to_cpu(dev->descriptor.idProduct);
+       switch (function) {
+       case TI_CODE_DATA_ERROR:
+               dev_dbg(&port->dev, "%s - DATA ERROR, port %d, data 0x%02X\n",
+                       __func__, port_number, data[1]);
+               break;
 
-       if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
-               snprintf(buf,
-                       sizeof(buf),
-                       "moxa/moxa-%04x.fw",
-                       le16_to_cpu(dev->descriptor.idProduct));
+       case TI_CODE_MODEM_STATUS:
+               msr = data[1];
+               ti_handle_new_msr(port, msr);
+               break;
 
-               status = request_firmware(&fw_p, buf, &dev->dev);
-               goto check_firmware;
+       default:
+               dev_err(&port->dev, "unknown interrupt code: 0x%02X\n",
+                       data[1]);
+               break;
        }
 
-       /* try ID specific firmware first, then try generic firmware */
-       sprintf(buf, "ti_usb-v%04x-p%04x.fw", vendor, product);
-       status = request_firmware(&fw_p, buf, &dev->dev);
+exit:
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status)
+               dev_err(&port->dev, "resubmit interrupt urb failed: %d\n",
+                       status);
+}
 
-       if (status != 0) {
-               buf[0] = '\0';
-               if (vendor == MTS_VENDOR_ID) {
-                       switch (product) {
-                       case MTS_CDMA_PRODUCT_ID:
-                               strcpy(buf, "mts_cdma.fw");
-                               break;
-                       case MTS_GSM_PRODUCT_ID:
-                               strcpy(buf, "mts_gsm.fw");
-                               break;
-                       case MTS_EDGE_PRODUCT_ID:
-                               strcpy(buf, "mts_edge.fw");
-                               break;
-                       case MTS_MT9234MU_PRODUCT_ID:
-                               strcpy(buf, "mts_mt9234mu.fw");
-                               break;
-                       case MTS_MT9234ZBA_PRODUCT_ID:
-                               strcpy(buf, "mts_mt9234zba.fw");
-                               break;
-                       case MTS_MT9234ZBAOLD_PRODUCT_ID:
-                               strcpy(buf, "mts_mt9234zba.fw");
-                               break;                  }
-               }
+static struct usb_serial_driver ti_1port_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "ti_usb_3410_5052_1",
+       },
+       .description            = "TI USB 3410 1 port adapter",
+       .id_table               = ti_id_table_3410,
+       .num_ports              = 1,
+       .attach                 = ti_startup,
+       .release                = ti_release,
+       .port_probe             = ti_port_probe,
+       .port_remove            = ti_port_remove,
+       .open                   = ti_open,
+       .close                  = ti_close,
+       .tx_empty               = ti_tx_empty,
+       .ioctl                  = ti_ioctl,
+       .set_termios            = ti_set_termios,
+       .tiocmget               = ti_tiocmget,
+       .tiocmset               = ti_tiocmset,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
+       .break_ctl              = ti_break,
+       .read_int_callback      = ti_interrupt_callback,
+};
 
-               if (buf[0] == '\0') {
-                       if (tdev->is_3410)
-                               strcpy(buf, "ti_3410.fw");
-                       else
-                               strcpy(buf, "ti_5052.fw");
-               }
-               status = request_firmware(&fw_p, buf, &dev->dev);
-       }
+static struct usb_serial_driver ti_2port_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "ti_usb_3410_5052_2",
+       },
+       .description            = "TI USB 5052 2 port adapter",
+       .id_table               = ti_id_table_5052,
+       .num_ports              = 2,
+       .attach                 = ti_startup,
+       .release                = ti_release,
+       .port_probe             = ti_port_probe,
+       .port_remove            = ti_port_remove,
+       .open                   = ti_open,
+       .close                  = ti_close,
+       .tx_empty               = ti_tx_empty,
+       .ioctl                  = ti_ioctl,
+       .set_termios            = ti_set_termios,
+       .tiocmget               = ti_tiocmget,
+       .tiocmset               = ti_tiocmset,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
+       .break_ctl              = ti_break,
+       .read_int_callback      = ti_interrupt_callback,
+};
 
-check_firmware:
-       if (status) {
-               dev_err(&dev->dev, "failed to request firmware: %d\n", status);
-               return -ENOENT;
-       }
+static struct usb_serial_driver * const serial_drivers[] = {
+       &ti_1port_device, &ti_2port_device, NULL
+};
 
-       if (fw_p->size > TI_FIRMWARE_BUF_SIZE) {
-               dev_err(&dev->dev, "firmware too large: %zu\n", fw_p->size);
-               release_firmware(fw_p);
-               return -ENOENT;
-       }
+MODULE_AUTHOR(TI_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(TI_DRIVER_DESC);
+MODULE_LICENSE("GPL");
 
-       ti_do_download(serial, fw_p);
+MODULE_FIRMWARE("ti_3410.fw");
+MODULE_FIRMWARE("ti_5052.fw");
+MODULE_FIRMWARE("mts_cdma.fw");
+MODULE_FIRMWARE("mts_gsm.fw");
+MODULE_FIRMWARE("mts_edge.fw");
+MODULE_FIRMWARE("mts_mt9234mu.fw");
+MODULE_FIRMWARE("mts_mt9234zba.fw");
+MODULE_FIRMWARE("moxa/moxa-1110.fw");
+MODULE_FIRMWARE("moxa/moxa-1130.fw");
+MODULE_FIRMWARE("moxa/moxa-1131.fw");
+MODULE_FIRMWARE("moxa/moxa-1150.fw");
+MODULE_FIRMWARE("moxa/moxa-1151.fw");
 
-       release_firmware(fw_p);
+MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
 
-       return 0;
-}
+module_usb_serial_driver(serial_drivers, ti_id_table_combined);
-- 
2.8.2

Reply via email to