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 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html