[PATCH 35/36] usb: serial: ti_usb_3410_5052: Remove function prototypes

From: Mathieu OTHACEHE
Date: Thu May 12 2016 - 04:53:00 EST


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

Signed-off-by: Mathieu OTHACEHE <m.othacehe@xxxxxxxxx>
---
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