diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2010-05-21 21:27:26 +0200 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2010-05-21 21:27:26 +0200 |
commit | ee9a3607fb03e804ddf624544105f4e34260c380 (patch) | |
tree | ce41b6e0fa10982a306f6c142a92dbf3c9961284 /drivers/usb/serial | |
parent | b492e95be0ae672922f4734acf3f5d35c30be948 (diff) | |
parent | d515e86e639890b33a09390d062b0831664f04a2 (diff) |
Merge branch 'master' into for-2.6.35
Conflicts:
fs/ext3/fsync.c
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/usb/serial')
52 files changed, 3181 insertions, 6354 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index a0ecb42cb33..bd8aab0ef1c 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -425,6 +425,16 @@ config USB_SERIAL_MOS7720 To compile this driver as a module, choose M here: the module will be called mos7720. +config USB_SERIAL_MOS7715_PARPORT + bool "Support for parallel port on the Moschip 7715" + depends on USB_SERIAL_MOS7720 + depends on PARPORT=y || PARPORT=USB_SERIAL_MOS7720 + select PARPORT_NOT_PC + ---help--- + Say Y if you have a Moschip 7715 device and would like to use + the parallel port it provides. The port will register with + the parport subsystem as a low-level driver. + config USB_SERIAL_MOS7840 tristate "USB Moschip 7840/7820 USB Serial Driver" ---help--- @@ -485,6 +495,7 @@ config USB_SERIAL_QCAUX config USB_SERIAL_QUALCOMM tristate "USB Qualcomm Serial modem" + select USB_SERIAL_WWAN help Say Y here if you have a Qualcomm USB modem device. These are usually wireless cellular modems. @@ -576,8 +587,12 @@ config USB_SERIAL_XIRCOM To compile this driver as a module, choose M here: the module will be called keyspan_pda. +config USB_SERIAL_WWAN + tristate + config USB_SERIAL_OPTION tristate "USB driver for GSM and CDMA modems" + select USB_SERIAL_WWAN help Say Y here if you have a GSM or CDMA modem that's connected to USB. @@ -619,6 +634,14 @@ config USB_SERIAL_VIVOPAY_SERIAL To compile this driver as a module, choose M here: the module will be called vivopay-serial. +config USB_SERIAL_ZIO + tristate "ZIO Motherboard USB serial interface driver" + help + Say Y here if you want to use ZIO Motherboard. + + To compile this driver as a module, choose M here: the + module will be called zio. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 83c9e431a56..e54c728c016 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -52,9 +52,11 @@ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o +obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o +obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 4fd7af98b1a..0db6ace16f7 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -1,7 +1,9 @@ /* * AIRcable USB Bluetooth Dongle Driver. * + * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@gmail.com) + * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. @@ -42,10 +44,10 @@ * */ +#include <asm/unaligned.h> #include <linux/tty.h> #include <linux/slab.h> #include <linux/tty_flip.h> -#include <linux/circ_buf.h> #include <linux/usb.h> #include <linux/usb/serial.h> @@ -55,16 +57,12 @@ static int debug; #define AIRCABLE_VID 0x16CA #define AIRCABLE_USB_PID 0x1502 -/* write buffer size defines */ -#define AIRCABLE_BUF_SIZE 2048 - /* Protocol Stuff */ #define HCI_HEADER_LENGTH 0x4 #define TX_HEADER_0 0x20 #define TX_HEADER_1 0x29 #define RX_HEADER_0 0x00 #define RX_HEADER_1 0x20 -#define MAX_HCI_FRAMESIZE 60 #define HCI_COMPLETE_FRAME 64 /* rx_flags */ @@ -74,8 +72,8 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v1.0b2" -#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>" +#define DRIVER_VERSION "v2.0" +#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "AIRcable USB Driver" /* ID table that will be registered with USB core */ @@ -85,226 +83,21 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); - -/* Internal Structure */ -struct aircable_private { - spinlock_t rx_lock; /* spinlock for the receive lines */ - struct circ_buf *tx_buf; /* write buffer */ - struct circ_buf *rx_buf; /* read buffer */ - int rx_flags; /* for throttilng */ - struct work_struct rx_work; /* work cue for the receiving line */ - struct usb_serial_port *port; /* USB port with which associated */ -}; - -/* Private methods */ - -/* Circular Buffer Methods, code from ti_usb_3410_5052 used */ -/* - * serial_buf_clear - * - * Clear out all data in the circular buffer. - */ -static void serial_buf_clear(struct circ_buf *cb) -{ - cb->head = cb->tail = 0; -} - -/* - * serial_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ -static struct circ_buf *serial_buf_alloc(void) -{ - struct circ_buf *cb; - cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL); - if (cb == NULL) - return NULL; - cb->buf = kmalloc(AIRCABLE_BUF_SIZE, GFP_KERNEL); - if (cb->buf == NULL) { - kfree(cb); - return NULL; - } - serial_buf_clear(cb); - return cb; -} - -/* - * serial_buf_free - * - * Free the buffer and all associated memory. - */ -static void serial_buf_free(struct circ_buf *cb) -{ - kfree(cb->buf); - kfree(cb); -} - -/* - * serial_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ -static int serial_buf_data_avail(struct circ_buf *cb) -{ - return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE); -} - -/* - * serial_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ -static int serial_buf_put(struct circ_buf *cb, const char *buf, int count) -{ - int c, ret = 0; - while (1) { - c = CIRC_SPACE_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(cb->buf + cb->head, buf, c); - cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1); - buf += c; - count -= c; - ret = c; - } - return ret; -} - -/* - * serial_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ -static int serial_buf_get(struct circ_buf *cb, char *buf, int count) -{ - int c, ret = 0; - while (1) { - c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(buf, cb->buf + cb->tail, c); - cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1); - buf += c; - count -= c; - ret = c; - } - return ret; -} - -/* End of circula buffer methods */ - -static void aircable_send(struct usb_serial_port *port) +static int aircable_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) { - int count, result; - struct aircable_private *priv = usb_get_serial_port_data(port); - unsigned char *buf; - __le16 *dbuf; - dbg("%s - port %d", __func__, port->number); - if (port->write_urb_busy) - return; - - count = min(serial_buf_data_avail(priv->tx_buf), MAX_HCI_FRAMESIZE); - if (count == 0) - return; - - buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC); - if (!buf) { - dev_err(&port->dev, "%s- kzalloc(%d) failed.\n", - __func__, count + HCI_HEADER_LENGTH); - return; - } + int count; + unsigned char *buf = dest; + count = kfifo_out_locked(&port->write_fifo, buf + HCI_HEADER_LENGTH, + size - HCI_HEADER_LENGTH, &port->lock); buf[0] = TX_HEADER_0; buf[1] = TX_HEADER_1; - dbuf = (__le16 *)&buf[2]; - *dbuf = cpu_to_le16((u16)count); - serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH, - MAX_HCI_FRAMESIZE); - - memcpy(port->write_urb->transfer_buffer, buf, - count + HCI_HEADER_LENGTH); - - kfree(buf); - port->write_urb_busy = 1; - usb_serial_debug_data(debug, &port->dev, __func__, - count + HCI_HEADER_LENGTH, - port->write_urb->transfer_buffer); - port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - - if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - port->write_urb_busy = 0; - } + put_unaligned_le16(count, &buf[2]); - schedule_work(&port->work); + return count + HCI_HEADER_LENGTH; } -static void aircable_read(struct work_struct *work) -{ - struct aircable_private *priv = - container_of(work, struct aircable_private, rx_work); - struct usb_serial_port *port = priv->port; - struct tty_struct *tty; - unsigned char *data; - int count; - if (priv->rx_flags & THROTTLED) { - if (priv->rx_flags & ACTUALLY_THROTTLED) - schedule_work(&priv->rx_work); - return; - } - - /* By now I will flush data to the tty in packages of no more than - * 64 bytes, to ensure I do not get throttled. - * Ask USB mailing list for better aproach. - */ - tty = tty_port_tty_get(&port->port); - - if (!tty) { - schedule_work(&priv->rx_work); - dev_err(&port->dev, "%s - No tty available\n", __func__); - return ; - } - - count = min(64, serial_buf_data_avail(priv->rx_buf)); - - if (count <= 0) - goto out; /* We have finished sending everything. */ - - tty_prepare_flip_string(tty, &data, count); - if (!data) { - dev_err(&port->dev, "%s- kzalloc(%d) failed.", - __func__, count); - goto out; - } - - serial_buf_get(priv->rx_buf, data, count); - - tty_flip_buffer_push(tty); - - if (serial_buf_data_avail(priv->rx_buf)) - schedule_work(&priv->rx_work); -out: - tty_kref_put(tty); - return; -} -/* End of private methods */ - static int aircable_probe(struct usb_serial *serial, const struct usb_device_id *id) { @@ -330,247 +123,50 @@ static int aircable_probe(struct usb_serial *serial, return 0; } -static int aircable_attach(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct aircable_private *priv; - - priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL); - if (!priv) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, - sizeof(struct aircable_private)); - return -ENOMEM; - } - - /* Allocation of Circular Buffers */ - priv->tx_buf = serial_buf_alloc(); - if (priv->tx_buf == NULL) { - kfree(priv); - return -ENOMEM; - } - - priv->rx_buf = serial_buf_alloc(); - if (priv->rx_buf == NULL) { - kfree(priv->tx_buf); - kfree(priv); - return -ENOMEM; - } - - priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - priv->port = port; - INIT_WORK(&priv->rx_work, aircable_read); - - usb_set_serial_port_data(serial->port[0], priv); - - return 0; -} - -static void aircable_release(struct usb_serial *serial) +static int aircable_process_packet(struct tty_struct *tty, + struct usb_serial_port *port, int has_headers, + char *packet, int len) { - - struct usb_serial_port *port = serial->port[0]; - struct aircable_private *priv = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - if (priv) { - serial_buf_free(priv->tx_buf); - serial_buf_free(priv->rx_buf); - kfree(priv); + if (has_headers) { + len -= HCI_HEADER_LENGTH; + packet += HCI_HEADER_LENGTH; } -} - -static int aircable_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct aircable_private *priv = usb_get_serial_port_data(port); - return serial_buf_data_avail(priv->tx_buf); -} - -static int aircable_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *source, int count) -{ - struct aircable_private *priv = usb_get_serial_port_data(port); - int temp; - - dbg("%s - port %d, %d bytes", __func__, port->number, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, source); - - if (!count) { - dbg("%s - write request of 0 bytes", __func__); - return count; + if (len <= 0) { + dbg("%s - malformed packet", __func__); + return 0; } - temp = serial_buf_put(priv->tx_buf, source, count); - - aircable_send(port); - - if (count > AIRCABLE_BUF_SIZE) - count = AIRCABLE_BUF_SIZE; - - return count; + tty_insert_flip_string(tty, packet, len); + return len; } -static void aircable_write_bulk_callback(struct urb *urb) +static void aircable_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - int status = urb->status; - int result; - - dbg("%s - urb status: %d", __func__ , status); - - /* This has been taken from cypress_m8.c cypress_write_int_callback */ - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - port->write_urb_busy = 0; - return; - default: - /* error in the urb, so we have to resubmit it */ - dbg("%s - Overflow in write", __func__); - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - failed resubmitting write urb, error %d\n", - __func__, result); - else - return; - } - - port->write_urb_busy = 0; - - aircable_send(port); -} - -static void aircable_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct aircable_private *priv = usb_get_serial_port_data(port); + char *data = (char *)urb->transfer_buffer; struct tty_struct *tty; - unsigned long no_packages, remaining, package_length, i; - int result, shift = 0; - unsigned char *temp; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - urb status = %d", __func__, status); - if (status == -EPROTO) { - dbg("%s - caught -EPROTO, resubmitting the urb", - __func__); - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - aircable_read_bulk_callback, port); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return; - } - dbg("%s - unable to handle the error, exiting.", __func__); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); + int has_headers; + int count; + int len; + int i; tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - if (urb->actual_length <= 2) { - /* This is an incomplete package */ - serial_buf_put(priv->rx_buf, urb->transfer_buffer, - urb->actual_length); - } else { - temp = urb->transfer_buffer; - if (temp[0] == RX_HEADER_0) - shift = HCI_HEADER_LENGTH; - - remaining = urb->actual_length; - no_packages = urb->actual_length / (HCI_COMPLETE_FRAME); - - if (urb->actual_length % HCI_COMPLETE_FRAME != 0) - no_packages++; + if (!tty) + return; - for (i = 0; i < no_packages; i++) { - if (remaining > (HCI_COMPLETE_FRAME)) - package_length = HCI_COMPLETE_FRAME; - else - package_length = remaining; - remaining -= package_length; + has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0); - serial_buf_put(priv->rx_buf, - urb->transfer_buffer + shift + - (HCI_COMPLETE_FRAME) * (i), - package_length - shift); - } - } - aircable_read(&priv->rx_work); + count = 0; + for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) { + len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME); + count += aircable_process_packet(tty, port, has_headers, + &data[i], len); } - tty_kref_put(tty); - - /* Schedule the next read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - aircable_read_bulk_callback, port); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result && result != -EPERM) - dev_err(&urb->dev->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); -} - -/* Based on ftdi_sio.c throttle */ -static void aircable_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct aircable_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->rx_lock); - priv->rx_flags |= THROTTLED; - spin_unlock_irq(&priv->rx_lock); -} - -/* Based on ftdi_sio.c unthrottle */ -static void aircable_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct aircable_private *priv = usb_get_serial_port_data(port); - int actually_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->rx_lock); - actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; - priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irq(&priv->rx_lock); - - if (actually_throttled) - schedule_work(&priv->rx_work); + if (count) + tty_flip_buffer_push(tty); + tty_kref_put(tty); } static struct usb_driver aircable_driver = { @@ -589,15 +185,12 @@ static struct usb_serial_driver aircable_device = { .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, - .attach = aircable_attach, + .bulk_out_size = HCI_COMPLETE_FRAME, .probe = aircable_probe, - .release = aircable_release, - .write = aircable_write, - .write_room = aircable_write_room, - .write_bulk_callback = aircable_write_bulk_callback, - .read_bulk_callback = aircable_read_bulk_callback, - .throttle = aircable_throttle, - .unthrottle = aircable_unthrottle, + .process_read_urb = aircable_process_read_urb, + .prepare_write_buffer = aircable_prepare_write_buffer, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; static int __init aircable_init(void) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 9b66bf19f75..4e41a2a3942 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -42,7 +42,7 @@ static int debug; * Version information */ -#define DRIVER_VERSION "v0.5" +#define DRIVER_VERSION "v0.6" #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>" #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" @@ -355,14 +355,11 @@ static void ark3116_close(struct usb_serial_port *port) /* deactivate interrupts */ ark3116_write_reg(serial, UART_IER, 0); - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) - usb_kill_urb(port->write_urb); - if (serial->num_bulk_in) - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); if (serial->num_interrupt_in) usb_kill_urb(port->interrupt_in_urb); } + } static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -675,87 +672,45 @@ static void ark3116_read_int_callback(struct urb *urb) * error for the next block of data as well... * For now, let's pretend this can't happen. */ - -static void send_to_tty(struct tty_struct *tty, - const unsigned char *chars, - size_t size, char flag) +static void ark3116_process_read_urb(struct urb *urb) { - if (size == 0) - return; - if (flag == TTY_NORMAL) { - tty_insert_flip_string(tty, chars, size); - } else { - int i; - for (i = 0; i < size; ++i) - tty_insert_flip_char(tty, chars[i], flag); - } -} - -static void ark3116_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; + struct usb_serial_port *port = urb->context; struct ark3116_private *priv = usb_get_serial_port_data(port); - const __u8 *data = urb->transfer_buffer; - int status = urb->status; struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + char tty_flag = TTY_NORMAL; unsigned long flags; - int result; - char flag; __u32 lsr; - switch (status) { - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + /* update line status */ + spin_lock_irqsave(&priv->status_lock, flags); + lsr = priv->lsr; + priv->lsr &= ~UART_LSR_BRK_ERROR_BITS; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if (!urb->actual_length) return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - break; - case 0: /* success */ - spin_lock_irqsave(&priv->status_lock, flags); - lsr = priv->lsr; - /* clear error bits */ - priv->lsr &= ~UART_LSR_BRK_ERROR_BITS; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (unlikely(lsr & UART_LSR_BI)) - flag = TTY_BREAK; - else if (unlikely(lsr & UART_LSR_PE)) - flag = TTY_PARITY; - else if (unlikely(lsr & UART_LSR_FE)) - flag = TTY_FRAME; - else - flag = TTY_NORMAL; - - tty = tty_port_tty_get(&port->port); - if (tty) { - /* overrun is special, not associated with a char */ - if (unlikely(lsr & UART_LSR_OE)) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - send_to_tty(tty, data, urb->actual_length, flag); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + + if (lsr & UART_LSR_BRK_ERROR_BITS) { + if (lsr & UART_LSR_BI) + tty_flag = TTY_BREAK; + else if (lsr & UART_LSR_PE) + tty_flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + tty_flag = TTY_FRAME; - /* Throttle the device if requested by tty */ - spin_lock_irqsave(&port->lock, flags); - port->throttled = port->throttle_req; - if (port->throttled) { - spin_unlock_irqrestore(&port->lock, flags); - return; - } else - spin_unlock_irqrestore(&port->lock, flags); + /* overrun is special, not associated with a char */ + if (lsr & UART_LSR_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); } - /* Continue reading from device */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting" - " read urb, error %d\n", __func__, result); + tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + urb->actual_length); + tty_flip_buffer_push(tty); + tty_kref_put(tty); } static struct usb_driver ark3116_driver = { @@ -785,7 +740,7 @@ static struct usb_serial_driver ark3116_device = { .close = ark3116_close, .break_ctl = ark3116_break_ctl, .read_int_callback = ark3116_read_int_callback, - .read_bulk_callback = ark3116_read_bulk_callback, + .process_read_urb = ark3116_process_read_urb, }; static int __init ark3116_init(void) diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 1295e44e3f1..36df35295db 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -3,6 +3,7 @@ * * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for @@ -84,7 +85,7 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v1.2" +#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>" #define DRIVER_DESC "USB Belkin Serial converter driver" @@ -95,6 +96,7 @@ static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port); static void belkin_sa_close(struct usb_serial_port *port); static void belkin_sa_read_int_callback(struct urb *urb); +static void belkin_sa_process_read_urb(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios * old); static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); @@ -112,7 +114,6 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table_combined); static struct usb_driver belkin_driver = { @@ -120,7 +121,7 @@ static struct usb_driver belkin_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; /* All of the device info needed for the serial converters */ @@ -136,7 +137,7 @@ static struct usb_serial_driver belkin_device = { .open = belkin_sa_open, .close = belkin_sa_close, .read_int_callback = belkin_sa_read_int_callback, - /* How we get the status info */ + .process_read_urb = belkin_sa_process_read_urb, .set_termios = belkin_sa_set_termios, .break_ctl = belkin_sa_break_ctl, .tiocmget = belkin_sa_tiocmget, @@ -145,7 +146,6 @@ static struct usb_serial_driver belkin_device = { .release = belkin_sa_release, }; - struct belkin_sa_private { spinlock_t lock; unsigned long control_state; @@ -196,62 +196,43 @@ static int belkin_sa_startup(struct usb_serial *serial) return 0; } - static void belkin_sa_release(struct usb_serial *serial) { - struct belkin_sa_private *priv; int i; dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { - /* My special items, the standard routines free my urbs */ - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } + for (i = 0; i < serial->num_ports; ++i) + kfree(usb_get_serial_port_data(serial->port[i])); } - -static int belkin_sa_open(struct tty_struct *tty, +static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port) { - int retval = 0; + int retval; dbg("%s port %d", __func__, port->number); - /*Start reading from the device*/ - /* TODO: Look at possibility of submitting multiple URBs to device to - * enhance buffering. Win trace shows 16 initial read URBs. - */ - port->read_urb->dev = port->serial->dev; - retval = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (retval) { - dev_err(&port->dev, "usb_submit_urb(read bulk) failed\n"); - goto exit; - } - - port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { - usb_kill_urb(port->read_urb); dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); + return retval; } -exit: - return retval; -} /* belkin_sa_open */ + retval = usb_serial_generic_open(tty, port); + if (retval) + usb_kill_urb(port->interrupt_in_urb); + return retval; +} static void belkin_sa_close(struct usb_serial_port *port) { dbg("%s port %d", __func__, port->number); - /* shutdown our bulk reads and writes */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); -} /* belkin_sa_close */ - +} static void belkin_sa_read_int_callback(struct urb *urb) { @@ -310,31 +291,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) else priv->control_state &= ~TIOCM_CD; - /* Now to report any errors */ priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; -#if 0 - /* - * fill in the flip buffer here, but I do not know the relation - * to the current/next receive buffer or characters. I need - * to look in to this before committing any code. - */ - if (priv->last_lsr & BELKIN_SA_LSR_ERR) { - tty = tty_port_tty_get(&port->port); - /* Overrun Error */ - if (priv->last_lsr & BELKIN_SA_LSR_OE) { - } - /* Parity Error */ - if (priv->last_lsr & BELKIN_SA_LSR_PE) { - } - /* Framing Error */ - if (priv->last_lsr & BELKIN_SA_LSR_FE) { - } - /* Break Indicator */ - if (priv->last_lsr & BELKIN_SA_LSR_BI) { - } - tty_kref_put(tty); - } -#endif spin_unlock_irqrestore(&priv->lock, flags); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -343,6 +300,53 @@ exit: "result %d\n", __func__, retval); } +static void belkin_sa_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct belkin_sa_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + unsigned long flags; + unsigned char status; + char tty_flag; + + /* Update line status */ + tty_flag = TTY_NORMAL; + + spin_lock_irqsave(&priv->lock, flags); + status = priv->last_lsr; + priv->last_lsr &= ~BELKIN_SA_LSR_ERR; + spin_unlock_irqrestore(&priv->lock, flags); + + if (!urb->actual_length) + return; + + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + + if (status & BELKIN_SA_LSR_ERR) { + /* Break takes precedence over parity, which takes precedence + * over framing errors. */ + if (status & BELKIN_SA_LSR_BI) + tty_flag = TTY_BREAK; + else if (status & BELKIN_SA_LSR_PE) + tty_flag = TTY_PARITY; + else if (status & BELKIN_SA_LSR_FE) + tty_flag = TTY_FRAME; + dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); + + /* Overrun is special, not associated with a char. */ + if (status & BELKIN_SA_LSR_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + urb->actual_length); + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -482,8 +486,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); priv->control_state = control_state; spin_unlock_irqrestore(&priv->lock, flags); -} /* belkin_sa_set_termios */ - +} static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state) { @@ -494,7 +497,6 @@ static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state) dev_err(&port->dev, "Set break_ctl %d\n", break_state); } - static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file) { struct usb_serial_port *port = tty->driver_data; @@ -511,7 +513,6 @@ static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file) return control_state; } - static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { @@ -583,7 +584,6 @@ failed_usb_serial_register: return retval; } - static void __exit belkin_sa_exit (void) { usb_deregister(&belkin_driver); diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h index c66a6730d38..c74b58ab56f 100644 --- a/drivers/usb/serial/belkin_sa.h +++ b/drivers/usb/serial/belkin_sa.h @@ -8,10 +8,10 @@ * and associated source files. Please see the usb/serial files for * individual credits and copyrights. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this * driver @@ -66,7 +66,7 @@ #ifdef WHEN_I_LEARN_THIS #define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */ /* (always in Wininit sequence before flow control) */ -#define BELKIN_SA_RESET xx /* Reset the port */ +#define BELKIN_SA_RESET xx /* Reset the port */ #define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */ #endif diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 7e8e3981841..63f7cc45bca 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -305,10 +305,7 @@ static void ch341_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index f347da2ef00..1ee6b2ab0f8 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -66,7 +66,7 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial_port *port; int retval; struct tty_struct *tty = NULL; - struct ktermios *termios = NULL, dummy; + struct ktermios dummy; dbg("%s", __func__); @@ -141,15 +141,14 @@ static int usb_console_setup(struct console *co, char *options) goto reset_open_count; } kref_init(&tty->kref); - termios = kzalloc(sizeof(*termios), GFP_KERNEL); - if (!termios) { + tty_port_tty_set(&port->port, tty); + tty->driver = usb_serial_tty_driver; + tty->index = co->index; + if (tty_init_termios(tty)) { retval = -ENOMEM; err("no more memory"); goto free_tty; } - memset(&dummy, 0, sizeof(struct ktermios)); - tty->termios = termios; - tty_port_tty_set(&port->port, tty); } /* only call the device specific open if this @@ -161,16 +160,16 @@ static int usb_console_setup(struct console *co, char *options) if (retval) { err("could not open USB console port"); - goto free_termios; + goto fail; } if (serial->type->set_termios) { - termios->c_cflag = cflag; - tty_termios_encode_baud_rate(termios, baud, baud); + tty->termios->c_cflag = cflag; + tty_termios_encode_baud_rate(tty->termios, baud, baud); + memset(&dummy, 0, sizeof(struct ktermios)); serial->type->set_termios(tty, port, &dummy); tty_port_tty_set(&port->port, NULL); - kfree(termios); kfree(tty); } set_bit(ASYNCB_INITIALIZED, &port->port.flags); @@ -180,14 +179,12 @@ static int usb_console_setup(struct console *co, char *options) --port->port.count; /* The console is special in terms of closing the device so * indicate this port is now acting as a system console. */ - port->console = 1; port->port.console = 1; mutex_unlock(&serial->disc_mutex); return retval; - free_termios: - kfree(termios); + fail: tty_port_tty_set(&port->port, NULL); free_tty: kfree(tty); @@ -217,7 +214,7 @@ static void usb_console_write(struct console *co, dbg("%s - port %d, %d byte(s)", __func__, port->number, count); - if (!port->console) { + if (!port->port.console) { dbg("%s - port not opened", __func__); return; } @@ -313,7 +310,7 @@ void usb_serial_console_exit(void) { if (usbcons_info.port) { unregister_console(&usbcons); - usbcons_info.port->console = 0; + usbcons_info.port->port.console = 0; usbcons_info.port = NULL; } } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index ec9b0449ccf..8b8c7976b4c 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -34,7 +34,6 @@ * Function Prototypes */ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); -static void cp210x_cleanup(struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *port); @@ -49,7 +48,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, unsigned int, unsigned int); static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); -static void cp210x_disconnect(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); static int cp210x_carrier_raised(struct usb_serial_port *p); @@ -61,6 +59,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ + { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ @@ -72,9 +72,12 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ + { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ + { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ + { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ @@ -82,12 +85,15 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ + { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ @@ -105,6 +111,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ @@ -115,6 +122,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ @@ -138,6 +147,8 @@ static struct usb_serial_driver cp210x_device = { .usb_driver = &cp210x_driver, .id_table = id_table, .num_ports = 1, + .bulk_in_size = 256, + .bulk_out_size = 256, .open = cp210x_open, .close = cp210x_close, .break_ctl = cp210x_break_ctl, @@ -145,7 +156,6 @@ static struct usb_serial_driver cp210x_device = { .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, - .disconnect = cp210x_disconnect, .dtr_rts = cp210x_dtr_rts, .carrier_raised = cp210x_carrier_raised }; @@ -370,7 +380,6 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; int result; dbg("%s - port %d", __func__, port->number); @@ -381,49 +390,20 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) return -EPROTO; } - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - serial->type->read_bulk_callback, - port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed resubmitting read urb, " - "error %d\n", __func__, result); + result = usb_serial_generic_open(tty, port); + if (result) return result; - } /* Configure the termios structure */ cp210x_get_termios(tty, port); return 0; } -static void cp210x_cleanup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - - dbg("%s - port %d", __func__, port->number); - - if (serial->dev) { - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) - usb_kill_urb(port->write_urb); - if (serial->num_bulk_in) - usb_kill_urb(port->read_urb); - } -} - static void cp210x_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) @@ -807,17 +787,6 @@ static int cp210x_startup(struct usb_serial *serial) return 0; } -static void cp210x_disconnect(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - /* Stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) - cp210x_cleanup(serial->port[i]); -} - static int __init cp210x_init(void) { int retval; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e23c77925e7..f5d06746cc3 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -64,6 +64,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/serial.h> +#include <linux/kfifo.h> #include <linux/delay.h> #include <linux/uaccess.h> #include <asm/unaligned.h> @@ -79,13 +80,12 @@ static int unstable_bauds; /* * Version Information */ -#define DRIVER_VERSION "v1.09" +#define DRIVER_VERSION "v1.10" #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>" #define DRIVER_DESC "Cypress USB to Serial Driver" /* write buffer size defines */ #define CYPRESS_BUF_SIZE 1024 -#define CYPRESS_CLOSING_WAIT (30*HZ) static const struct usb_device_id id_table_earthmate[] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, @@ -135,7 +135,7 @@ struct cypress_private { int bytes_out; /* used for statistics */ int cmd_count; /* used for statistics */ int cmd_ctrl; /* always set this to 1 before issuing a command */ - struct cypress_buf *buf; /* write buffer */ + struct kfifo write_fifo; /* write fifo */ int write_urb_in_use; /* write urb in use indicator */ int write_urb_interval; /* interval to use for write urb */ int read_urb_interval; /* interval to use for read urb */ @@ -157,14 +157,6 @@ struct cypress_private { struct ktermios tmp_termios; /* stores the old termios settings */ }; -/* write buffer structure */ -struct cypress_buf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - /* function prototypes for the Cypress USB to serial device */ static int cypress_earthmate_startup(struct usb_serial *serial); static int cypress_hidcom_startup(struct usb_serial *serial); @@ -190,17 +182,6 @@ static void cypress_unthrottle(struct tty_struct *tty); static void cypress_set_dead(struct usb_serial_port *port); static void cypress_read_int_callback(struct urb *urb); static void cypress_write_int_callback(struct urb *urb); -/* write buffer functions */ -static struct cypress_buf *cypress_buf_alloc(unsigned int size); -static void cypress_buf_free(struct cypress_buf *cb); -static void cypress_buf_clear(struct cypress_buf *cb); -static unsigned int cypress_buf_data_avail(struct cypress_buf *cb); -static unsigned int cypress_buf_space_avail(struct cypress_buf *cb); -static unsigned int cypress_buf_put(struct cypress_buf *cb, - const char *buf, unsigned int count); -static unsigned int cypress_buf_get(struct cypress_buf *cb, - char *buf, unsigned int count); - static struct usb_serial_driver cypress_earthmate_device = { .driver = { @@ -503,8 +484,7 @@ static int generic_startup(struct usb_serial *serial) priv->comm_is_ok = !0; spin_lock_init(&priv->lock); - priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE); - if (priv->buf == NULL) { + if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) { kfree(priv); return -ENOMEM; } @@ -627,7 +607,7 @@ static void cypress_release(struct usb_serial *serial) priv = usb_get_serial_port_data(serial->port[0]); if (priv) { - cypress_buf_free(priv->buf); + kfifo_free(&priv->write_fifo); kfree(priv); } } @@ -704,6 +684,7 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on) static void cypress_close(struct usb_serial_port *port) { struct cypress_private *priv = usb_get_serial_port_data(port); + unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -713,12 +694,14 @@ static void cypress_close(struct usb_serial_port *port) mutex_unlock(&port->serial->disc_mutex); return; } - cypress_buf_clear(priv->buf); + spin_lock_irqsave(&priv->lock, flags); + kfifo_reset_out(&priv->write_fifo); + spin_unlock_irqrestore(&priv->lock, flags); + dbg("%s - stopping urbs", __func__); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); - if (stats) dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); @@ -730,7 +713,6 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d, %d bytes", __func__, port->number, count); @@ -745,9 +727,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, if (!count) return count; - spin_lock_irqsave(&priv->lock, flags); - count = cypress_buf_put(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); + count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock); finish: cypress_send(port); @@ -807,9 +787,10 @@ static void cypress_send(struct usb_serial_port *port) } else spin_unlock_irqrestore(&priv->lock, flags); - count = cypress_buf_get(priv->buf, &port->interrupt_out_buffer[offset], - port->interrupt_out_size-offset); - + count = kfifo_out_locked(&priv->write_fifo, + &port->interrupt_out_buffer[offset], + port->interrupt_out_size - offset, + &priv->lock); if (count == 0) return; @@ -875,7 +856,7 @@ static int cypress_write_room(struct tty_struct *tty) dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); - room = cypress_buf_space_avail(priv->buf); + room = kfifo_avail(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __func__, room); @@ -1143,7 +1124,7 @@ static int cypress_chars_in_buffer(struct tty_struct *tty) dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); - chars = cypress_buf_data_avail(priv->buf); + chars = kfifo_len(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __func__, chars); @@ -1309,7 +1290,7 @@ static void cypress_read_int_callback(struct urb *urb) /* process read if there is data other than line status */ if (tty && bytes > i) { tty_insert_flip_string_fixed_flag(tty, data + i, - bytes - i, tty_flag); + tty_flag, bytes - i); tty_flip_buffer_push(tty); } @@ -1397,193 +1378,6 @@ static void cypress_write_int_callback(struct urb *urb) /***************************************************************************** - * Write buffer functions - buffering code from pl2303 used - *****************************************************************************/ - -/* - * cypress_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ - -static struct cypress_buf *cypress_buf_alloc(unsigned int size) -{ - - struct cypress_buf *cb; - - - if (size == 0) - return NULL; - - cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL); - if (cb == NULL) - return NULL; - - cb->buf_buf = kmalloc(size, GFP_KERNEL); - if (cb->buf_buf == NULL) { - kfree(cb); - return NULL; - } - - cb->buf_size = size; - cb->buf_get = cb->buf_put = cb->buf_buf; - - return cb; - -} - - -/* - * cypress_buf_free - * - * Free the buffer and all associated memory. - */ - -static void cypress_buf_free(struct cypress_buf *cb) -{ - if (cb) { - kfree(cb->buf_buf); - kfree(cb); - } -} - - -/* - * cypress_buf_clear - * - * Clear out all data in the circular buffer. - */ - -static void cypress_buf_clear(struct cypress_buf *cb) -{ - if (cb != NULL) - cb->buf_get = cb->buf_put; - /* equivalent to a get of all data available */ -} - - -/* - * cypress_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ - -static unsigned int cypress_buf_data_avail(struct cypress_buf *cb) -{ - if (cb != NULL) - return (cb->buf_size + cb->buf_put - cb->buf_get) - % cb->buf_size; - else - return 0; -} - - -/* - * cypress_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ - -static unsigned int cypress_buf_space_avail(struct cypress_buf *cb) -{ - if (cb != NULL) - return (cb->buf_size + cb->buf_get - cb->buf_put - 1) - % cb->buf_size; - else - return 0; -} - - -/* - * cypress_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ - -static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, - unsigned int count) -{ - - unsigned int len; - - - if (cb == NULL) - return 0; - - len = cypress_buf_space_avail(cb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = cb->buf_buf + cb->buf_size - cb->buf_put; - if (count > len) { - memcpy(cb->buf_put, buf, len); - memcpy(cb->buf_buf, buf+len, count - len); - cb->buf_put = cb->buf_buf + count - len; - } else { - memcpy(cb->buf_put, buf, count); - if (count < len) - cb->buf_put += count; - else /* count == len */ - cb->buf_put = cb->buf_buf; - } - - return count; - -} - - -/* - * cypress_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ - -static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, - unsigned int count) -{ - - unsigned int len; - - - if (cb == NULL) - return 0; - - len = cypress_buf_data_avail(cb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = cb->buf_buf + cb->buf_size - cb->buf_get; - if (count > len) { - memcpy(buf, cb->buf_get, len); - memcpy(buf+len, cb->buf_buf, count - len); - cb->buf_get = cb->buf_buf + count - len; - } else { - memcpy(buf, cb->buf_get, count); - if (count < len) - cb->buf_get += count; - else /* count == len */ - cb->buf_get = cb->buf_buf; - } - - return count; - -} - -/***************************************************************************** * Module functions *****************************************************************************/ diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index 1fd360e0406..67cf6082688 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -1,27 +1,32 @@ #ifndef CYPRESS_M8_H #define CYPRESS_M8_H -/* definitions and function prototypes used for the cypress USB to Serial controller */ +/* + * definitions and function prototypes used for the cypress USB to Serial + * controller + */ -/* For sending our feature buffer - controlling serial communication states */ -/* Linux HID has no support for serial devices so we do this through the driver */ -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_SET_REPORT 0x09 +/* + * For sending our feature buffer - controlling serial communication states. + * Linux HID has no support for serial devices so we do this through the driver + */ +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_SET_REPORT 0x09 /* List other cypress USB to Serial devices here, and add them to the id_table */ /* DeLorme Earthmate USB - a GPS device */ -#define VENDOR_ID_DELORME 0x1163 -#define PRODUCT_ID_EARTHMATEUSB 0x0100 -#define PRODUCT_ID_EARTHMATEUSB_LT20 0x0200 +#define VENDOR_ID_DELORME 0x1163 +#define PRODUCT_ID_EARTHMATEUSB 0x0100 +#define PRODUCT_ID_EARTHMATEUSB_LT20 0x0200 /* Cypress HID->COM RS232 Adapter */ -#define VENDOR_ID_CYPRESS 0x04b4 -#define PRODUCT_ID_CYPHIDCOM 0x5500 +#define VENDOR_ID_CYPRESS 0x04b4 +#define PRODUCT_ID_CYPHIDCOM 0x5500 /* Powercom UPS, chip CY7C63723 */ -#define VENDOR_ID_POWERCOM 0x0d9f -#define PRODUCT_ID_UPS 0x0002 +#define VENDOR_ID_POWERCOM 0x0d9f +#define PRODUCT_ID_UPS 0x0002 /* Nokia CA-42 USB to serial cable */ #define VENDOR_ID_DAZZLE 0x07d0 @@ -29,17 +34,17 @@ /* End of device listing */ /* Used for setting / requesting serial line settings */ -#define CYPRESS_SET_CONFIG 0x01 -#define CYPRESS_GET_CONFIG 0x02 +#define CYPRESS_SET_CONFIG 0x01 +#define CYPRESS_GET_CONFIG 0x02 /* Used for throttle control */ -#define THROTTLED 0x1 -#define ACTUALLY_THROTTLED 0x2 +#define THROTTLED 0x1 +#define ACTUALLY_THROTTLED 0x2 -/* chiptypes - used in case firmware differs from the generic form ... offering - * different baud speeds/etc. +/* + * chiptypes - used in case firmware differs from the generic form ... offering + * different baud speeds/etc. */ - #define CT_EARTHMATE 0x01 #define CT_CYPHIDCOM 0x02 #define CT_CA42V2 0x03 @@ -50,15 +55,15 @@ /* these are sent / read at byte 0 of the input/output hid reports */ /* You can find these values defined in the CY4601 USB to Serial design notes */ -#define CONTROL_DTR 0x20 /* data terminal ready - flow control - host to device */ +#define CONTROL_DTR 0x20 /* data terminal ready - flow control - host to device */ #define UART_DSR 0x20 /* data set ready - flow control - device to host */ -#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */ +#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */ #define UART_CTS 0x10 /* clear to send - flow control - device to host */ -#define UART_RI 0x10 /* ring indicator - modem - device to host */ +#define UART_RI 0x10 /* ring indicator - modem - device to host */ #define UART_CD 0x40 /* carrier detect - modem - device to host */ -#define CYP_ERROR 0x08 /* received from input report - device to host */ +#define CYP_ERROR 0x08 /* received from input report - device to host */ /* Note - the below has nothing to do with the "feature report" reset */ -#define CONTROL_RESET 0x08 /* sent with output report - host to device */ +#define CONTROL_RESET 0x08 /* sent with output report - host to device */ /* End of RS-232 protocol definitions */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 68b0aa5e516..3edda3ed822 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1703,8 +1703,8 @@ static int digi_read_inb_callback(struct urb *urb) /* data length is len-1 (one byte of len is port_status) */ --len; if (len > 0) { - tty_insert_flip_string_fixed_flag(tty, data, len, - flag); + tty_insert_flip_string_fixed_flag(tty, data, flag, + len); tty_flip_buffer_push(tty); } } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 5f740a1eaca..504b5585ea4 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -13,44 +13,6 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * - * (07/16/2001) gb - * remove unused code in empeg_close() (thanks to Oliver Neukum for - * pointing this out) and rewrote empeg_set_termios(). - * - * (05/30/2001) gkh - * switched from using spinlock to a semaphore, which fixes lots of - * problems. - * - * (04/08/2001) gb - * Identify version on module load. - * - * (01/22/2001) gb - * Added write_room() and chars_in_buffer() support. - * - * (12/21/2000) gb - * Moved termio stuff inside the port->active check. - * Moved MOD_DEC_USE_COUNT to end of empeg_close(). - * - * (12/03/2000) gb - * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open(). - * This notifies the tty driver that the termios have changed. - * - * (11/13/2000) gb - * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to - * empeg_open() (It only needs to be set once - Doh!) - * - * (11/11/2000) gb - * Updated to work with id_table structure. - * - * (11/04/2000) gb - * Forked this from visor.c, and hacked it up to work with an - * Empeg ltd. empeg-car player. Constructive criticism welcomed. - * I would like to say, 'Thank You' to Greg Kroah-Hartman for the - * use of his code, and for his guidance, advice and patience. :) - * A 'Thank You' is in order for John Ripley of Empeg ltd for his - * advice, and patience too. - * */ #include <linux/kernel.h> @@ -71,7 +33,7 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v1.2" +#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>" #define DRIVER_DESC "USB Empeg Mark I/II Driver" @@ -79,19 +41,8 @@ static int debug; #define EMPEG_PRODUCT_ID 0x0001 /* function prototypes for an empeg-car player */ -static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port); -static void empeg_close(struct usb_serial_port *port); -static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, - int count); -static int empeg_write_room(struct tty_struct *tty); -static int empeg_chars_in_buffer(struct tty_struct *tty); -static void empeg_throttle(struct tty_struct *tty); -static void empeg_unthrottle(struct tty_struct *tty); static int empeg_startup(struct usb_serial *serial); static void empeg_init_termios(struct tty_struct *tty); -static void empeg_write_bulk_callback(struct urb *urb); -static void empeg_read_bulk_callback(struct urb *urb); static const struct usb_device_id id_table[] = { { USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) }, @@ -105,7 +56,7 @@ static struct usb_driver empeg_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; static struct usb_serial_driver empeg_device = { @@ -114,291 +65,16 @@ static struct usb_serial_driver empeg_device = { .name = "empeg", }, .id_table = id_table, - .usb_driver = &empeg_driver, + .usb_driver = &empeg_driver, .num_ports = 1, - .open = empeg_open, - .close = empeg_close, - .throttle = empeg_throttle, - .unthrottle = empeg_unthrottle, + .bulk_out_size = 256, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .attach = empeg_startup, .init_termios = empeg_init_termios, - .write = empeg_write, - .write_room = empeg_write_room, - .chars_in_buffer = empeg_chars_in_buffer, - .write_bulk_callback = empeg_write_bulk_callback, - .read_bulk_callback = empeg_read_bulk_callback, }; -#define NUM_URBS 16 -#define URB_TRANSFER_BUFFER_SIZE 4096 - -static struct urb *write_urb_pool[NUM_URBS]; -static spinlock_t write_urb_pool_lock; -static int bytes_in; -static int bytes_out; - -/****************************************************************************** - * Empeg specific driver functions - ******************************************************************************/ -static int empeg_open(struct tty_struct *tty,struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - bytes_in = 0; - bytes_out = 0; - - /* Start reading from the device */ - usb_fill_bulk_urb( - port->read_urb, - serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - empeg_read_bulk_callback, - port); - - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - - return result; -} - - -static void empeg_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - /* shutdown our bulk read */ - usb_kill_urb(port->read_urb); - /* Uncomment the following line if you want to see some statistics in your syslog */ - /* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ -} - - -static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - struct urb *urb; - const unsigned char *current_position = buf; - unsigned long flags; - int status; - int i; - int bytes_sent = 0; - int transfer_size; - - dbg("%s - port %d", __func__, port->number); - - while (count > 0) { - /* try to find a free urb in our list of them */ - urb = NULL; - - spin_lock_irqsave(&write_urb_pool_lock, flags); - - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) { - urb = write_urb_pool[i]; - break; - } - } - - spin_unlock_irqrestore(&write_urb_pool_lock, flags); - - if (urb == NULL) { - dbg("%s - no more free urbs", __func__); - goto exit; - } - - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); - if (urb->transfer_buffer == NULL) { - dev_err(&port->dev, - "%s no more kernel memory...\n", - __func__); - goto exit; - } - } - - transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); - - memcpy(urb->transfer_buffer, current_position, transfer_size); - - usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, urb->transfer_buffer); - - /* build up our urb */ - usb_fill_bulk_urb( - urb, - serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, - transfer_size, - empeg_write_bulk_callback, - port); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status); - bytes_sent = status; - break; - } - - current_position += transfer_size; - bytes_sent += transfer_size; - count -= transfer_size; - bytes_out += transfer_size; - - } -exit: - return bytes_sent; -} - - -static int empeg_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int i; - int room = 0; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&write_urb_pool_lock, flags); - /* tally up the number of bytes available */ - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) - room += URB_TRANSFER_BUFFER_SIZE; - } - spin_unlock_irqrestore(&write_urb_pool_lock, flags); - dbg("%s - returns %d", __func__, room); - return room; - -} - - -static int empeg_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int i; - int chars = 0; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&write_urb_pool_lock, flags); - - /* tally up the number of bytes waiting */ - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status == -EINPROGRESS) - chars += URB_TRANSFER_BUFFER_SIZE; - } - - spin_unlock_irqrestore(&write_urb_pool_lock, flags); - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void empeg_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - -static void empeg_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - tty = tty_port_tty_get(&port->port); - - if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - bytes_in += urb->actual_length; - } - tty_kref_put(tty); - - /* Continue trying to always read */ - usb_fill_bulk_urb( - port->read_urb, - port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - empeg_read_bulk_callback, - port); - - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - - if (result) - dev_err(&urb->dev->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - - return; - -} - - -static void empeg_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->read_urb); -} - - -static void empeg_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int result; - dbg("%s - port %d", __func__, port->number); - - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); -} - - -static int empeg_startup(struct usb_serial *serial) +static int empeg_startup(struct usb_serial *serial) { int r; @@ -414,10 +90,8 @@ static int empeg_startup(struct usb_serial *serial) /* continue on with initialization */ return r; - } - static void empeg_init_termios(struct tty_struct *tty) { struct ktermios *termios = tty->termios; @@ -462,77 +136,28 @@ static void empeg_init_termios(struct tty_struct *tty) tty_encode_baud_rate(tty, 115200, 115200); } - static int __init empeg_init(void) { - struct urb *urb; - int i, retval; - - /* create our write urb pool and transfer buffers */ - spin_lock_init(&write_urb_pool_lock); - for (i = 0; i < NUM_URBS; ++i) { - urb = usb_alloc_urb(0, GFP_KERNEL); - write_urb_pool[i] = urb; - if (urb == NULL) { - printk(KERN_ERR "empeg: No more urbs???\n"); - continue; - } - - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, - GFP_KERNEL); - if (!urb->transfer_buffer) { - printk(KERN_ERR "empeg: %s - out of memory for urb " - "buffers.", __func__); - continue; - } - } + int retval; retval = usb_serial_register(&empeg_device); if (retval) - goto failed_usb_serial_register; + return retval; retval = usb_register(&empeg_driver); - if (retval) - goto failed_usb_register; - + if (retval) { + usb_serial_deregister(&empeg_device); + return retval; + } printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); return 0; -failed_usb_register: - usb_serial_deregister(&empeg_device); -failed_usb_serial_register: - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]) { - kfree(write_urb_pool[i]->transfer_buffer); - usb_free_urb(write_urb_pool[i]); - } - } - return retval; } - static void __exit empeg_exit(void) { - int i; - unsigned long flags; - usb_deregister(&empeg_driver); usb_serial_deregister(&empeg_device); - - spin_lock_irqsave(&write_urb_pool_lock, flags); - - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]) { - /* FIXME - uncomment the following usb_kill_urb call - * when the host controllers get fixed to set urb->dev - * = NULL after the urb is finished. Otherwise this - * call oopses. */ - /* usb_kill_urb(write_urb_pool[i]); */ - kfree(write_urb_pool[i]->transfer_buffer); - usb_free_urb(write_urb_pool[i]); - } - } - spin_unlock_irqrestore(&write_urb_pool_lock, flags); } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1d7c4fac02e..050211afc07 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,6 +1,8 @@ /* * USB FTDI SIO driver * + * Copyright (C) 2009 - 2010 + * Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) * Bill Ryder (bryder@sgi.com) @@ -49,8 +51,8 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.5.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr" +#define DRIVER_VERSION "v1.6.0" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" static int debug; @@ -59,7 +61,7 @@ static __u16 product; struct ftdi_private { struct kref kref; - ftdi_chip_type_t chip_type; + enum ftdi_chip_type chip_type; /* type of device, either SIO or FT8U232AM */ int baud_base; /* baud base clock for divisor setting */ int custom_divisor; /* custom_divisor kludge, this is for @@ -69,10 +71,6 @@ struct ftdi_private { /* the last data state set - needed for doing * a break */ - int write_offset; /* This is the offset in the usb data block to - * write the serial data - it varies between - * devices - */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ @@ -87,9 +85,6 @@ struct ftdi_private { be enabled */ unsigned int latency; /* latency setting in use */ - spinlock_t tx_lock; /* spinlock for transmit state */ - unsigned long tx_outstanding_bytes; - unsigned long tx_outstanding_urbs; unsigned short max_packet_size; struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ }; @@ -768,9 +763,6 @@ static const char *ftdi_chip_name[] = { }; -/* Constants for read urb and write urb */ -#define BUFSZ 512 - /* Used for TIOCMIWAIT */ #define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) @@ -787,13 +779,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); static void ftdi_close(struct usb_serial_port *port); static void ftdi_dtr_rts(struct usb_serial_port *port, int on); -static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int ftdi_write_room(struct tty_struct *tty); -static int ftdi_chars_in_buffer(struct tty_struct *tty); -static void ftdi_write_bulk_callback(struct urb *urb); -static void ftdi_read_bulk_callback(struct urb *urb); -static void ftdi_process_read(struct usb_serial_port *port); +static void ftdi_process_read_urb(struct urb *urb); +static int ftdi_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size); static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int ftdi_tiocmget(struct tty_struct *tty, struct file *file); @@ -802,8 +790,6 @@ static int ftdi_tiocmset(struct tty_struct *tty, struct file *file, static int ftdi_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); -static void ftdi_throttle(struct tty_struct *tty); -static void ftdi_unthrottle(struct tty_struct *tty); static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); @@ -821,19 +807,18 @@ static struct usb_serial_driver ftdi_sio_device = { .usb_driver = &ftdi_driver, .id_table = id_table_combined, .num_ports = 1, + .bulk_in_size = 512, + .bulk_out_size = 256, .probe = ftdi_sio_probe, .port_probe = ftdi_sio_port_probe, .port_remove = ftdi_sio_port_remove, .open = ftdi_open, .close = ftdi_close, .dtr_rts = ftdi_dtr_rts, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, + .process_read_urb = ftdi_process_read_urb, + .prepare_write_buffer = ftdi_prepare_write_buffer, .tiocmget = ftdi_tiocmget, .tiocmset = ftdi_tiocmset, .ioctl = ftdi_ioctl, @@ -849,9 +834,6 @@ static struct usb_serial_driver ftdi_sio_device = { #define HIGH 1 #define LOW 0 -/* number of outstanding urbs to prevent userspace DoS from happening */ -#define URB_UPPER_LIMIT 42 - /* * *************************************************************************** * Utility functions @@ -987,7 +969,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, static __u32 get_ftdi_divisor(struct tty_struct *tty, struct usb_serial_port *port) -{ /* get_ftdi_divisor */ +{ struct ftdi_private *priv = usb_get_serial_port_data(port); __u32 div_value = 0; int div_okay = 1; @@ -1211,12 +1193,11 @@ static int get_serial_info(struct usb_serial_port *port, if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; -} /* get_serial_info */ - +} static int set_serial_info(struct tty_struct *tty, struct usb_serial_port *port, struct serial_struct __user *newinfo) -{ /* set_serial_info */ +{ struct ftdi_private *priv = usb_get_serial_port_data(port); struct serial_struct new_serial; struct ftdi_private old_priv; @@ -1279,8 +1260,7 @@ check_and_exit: else mutex_unlock(&priv->cfg_lock); return 0; - -} /* set_serial_info */ +} /* Determine type of FTDI chip based on USB config and descriptor. */ @@ -1294,7 +1274,6 @@ static void ftdi_determine_type(struct usb_serial_port *port) /* Assume it is not the original SIO device for now. */ priv->baud_base = 48000000 / 2; - priv->write_offset = 0; version = le16_to_cpu(udev->descriptor.bcdDevice); interfaces = udev->actconfig->desc.bNumInterfaces; @@ -1336,7 +1315,6 @@ static void ftdi_determine_type(struct usb_serial_port *port) /* Old device. Assume it's the original SIO. */ priv->chip_type = SIO; priv->baud_base = 12000000 / 16; - priv->write_offset = 1; } else if (version < 0x400) { /* Assume it's an FT8U232AM (or FT8U245AM) */ /* (It might be a BM because of the iSerialNumber bug, @@ -1543,7 +1521,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) } kref_init(&priv->kref); - spin_lock_init(&priv->tx_lock); mutex_init(&priv->cfg_lock); init_waitqueue_head(&priv->delta_msr_wait); @@ -1552,28 +1529,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) if (quirk && quirk->port_probe) quirk->port_probe(priv); - /* Increase the size of read buffers */ - kfree(port->bulk_in_buffer); - port->bulk_in_buffer = kmalloc(BUFSZ, GFP_KERNEL); - if (!port->bulk_in_buffer) { - kfree(priv); - return -ENOMEM; - } - if (port->read_urb) { - port->read_urb->transfer_buffer = port->bulk_in_buffer; - port->read_urb->transfer_buffer_length = BUFSZ; - } - priv->port = port; - - /* Free port's existing write urb and transfer buffer. */ - if (port->write_urb) { - usb_free_urb(port->write_urb); - port->write_urb = NULL; - } - kfree(port->bulk_out_buffer); - port->bulk_out_buffer = NULL; - usb_set_serial_port_data(port, priv); ftdi_determine_type(port); @@ -1594,7 +1550,7 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = 38400; -} /* ftdi_USB_UIRT_setup */ +} /* Setup for the HE-TIRA1 device, which requires hardwired * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ @@ -1607,7 +1563,7 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) priv->custom_divisor = 240; priv->force_baud = 38400; priv->force_rtscts = 1; -} /* ftdi_HE_TIRA1_setup */ +} /* * Module parameter to control latency timer for NDI FTDI-based USB devices. @@ -1700,31 +1656,10 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) return 0; } -static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) -{ - struct urb *urb = port->read_urb; - struct usb_serial *serial = port->serial; - int result; - - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, - urb->transfer_buffer_length, - ftdi_read_bulk_callback, port); - result = usb_submit_urb(urb, mem_flags); - if (result && result != -EPERM) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - return result; -} - static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) -{ /* ftdi_open */ +{ struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - unsigned long flags; int result; dbg("%s", __func__); @@ -1746,20 +1681,13 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ftdi_set_termios(tty, port, tty->termios); - /* Not throttled */ - spin_lock_irqsave(&port->lock, flags); - port->throttled = 0; - port->throttle_req = 0; - spin_unlock_irqrestore(&port->lock, flags); - /* Start reading from the device */ - result = ftdi_submit_read_urb(port, GFP_KERNEL); + result = usb_serial_generic_open(tty, port); if (!result) kref_get(&priv->kref); return result; -} /* ftdi_open */ - +} static void ftdi_dtr_rts(struct usb_serial_port *port, int on) { @@ -1789,22 +1717,16 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) * usbserial:__serial_close only calls ftdi_close if the point is open * * This only gets called when it is the last close - * - * */ - static void ftdi_close(struct usb_serial_port *port) -{ /* ftdi_close */ +{ struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s", __func__); - /* shutdown our bulk read */ - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); kref_put(&priv->kref, ftdi_sio_priv_release); -} /* ftdi_close */ - - +} /* The SIO requires the first byte to have: * B0 1 @@ -1813,211 +1735,39 @@ static void ftdi_close(struct usb_serial_port *port) * * The new devices do not require this byte */ -static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ /* ftdi_write */ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct urb *urb; - unsigned char *buffer; - int data_offset ; /* will be 1 for the SIO and 0 otherwise */ - int status; - int transfer_size; +static int ftdi_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) +{ + struct ftdi_private *priv; + int count; unsigned long flags; - dbg("%s port %d, %d bytes", __func__, port->number, count); - - if (count == 0) { - dbg("write request of 0 bytes"); - return 0; - } - spin_lock_irqsave(&priv->tx_lock, flags); - if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) { - spin_unlock_irqrestore(&priv->tx_lock, flags); - dbg("%s - write limit hit", __func__); - return 0; - } - priv->tx_outstanding_urbs++; - spin_unlock_irqrestore(&priv->tx_lock, flags); - - data_offset = priv->write_offset; - dbg("data_offset set to %d", data_offset); - - /* Determine total transfer size */ - transfer_size = count; - if (data_offset > 0) { - /* Original sio needs control bytes too... */ - transfer_size += (data_offset * - ((count + (priv->max_packet_size - 1 - data_offset)) / - (priv->max_packet_size - data_offset))); - } - - buffer = kmalloc(transfer_size, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, - "%s ran out of kernel memory for urb ...\n", __func__); - count = -ENOMEM; - goto error_no_buffer; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "%s - no more free urbs\n", __func__); - count = -ENOMEM; - goto error_no_urb; - } + priv = usb_get_serial_port_data(port); - /* Copy data */ - if (data_offset > 0) { - /* Original sio requires control byte at start of - each packet. */ - int user_pktsz = priv->max_packet_size - data_offset; - int todo = count; - unsigned char *first_byte = buffer; - const unsigned char *current_position = buf; - - while (todo > 0) { - if (user_pktsz > todo) - user_pktsz = todo; - /* Write the control byte at the front of the packet*/ - *first_byte = 1 | ((user_pktsz) << 2); - /* Copy data for packet */ - memcpy(first_byte + data_offset, - current_position, user_pktsz); - first_byte += user_pktsz + data_offset; - current_position += user_pktsz; - todo -= user_pktsz; + if (priv->chip_type == SIO) { + unsigned char *buffer = dest; + int i, len, c; + + count = 0; + spin_lock_irqsave(&port->lock, flags); + for (i = 0; i < size - 1; i += priv->max_packet_size) { + len = min_t(int, size - i, priv->max_packet_size) - 1; + c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); + if (!c) + break; + buffer[i] = (c << 2) + 1; + count += c + 1; } + spin_unlock_irqrestore(&port->lock, flags); } else { - /* No control byte required. */ - /* Copy in the data to send */ - memcpy(buffer, buf, count); - } - - usb_serial_debug_data(debug, &port->dev, __func__, - transfer_size, buffer); - - /* fill the buffer and send it */ - usb_fill_bulk_urb(urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - buffer, transfer_size, - ftdi_write_bulk_callback, port); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, status); - count = status; - goto error; - } else { - spin_lock_irqsave(&priv->tx_lock, flags); - priv->tx_outstanding_bytes += count; - spin_unlock_irqrestore(&priv->tx_lock, flags); + count = kfifo_out_locked(&port->write_fifo, dest, size, + &port->lock); } - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb(urb); - - dbg("%s write returning: %d", __func__, count); - return count; -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&priv->tx_lock, flags); - priv->tx_outstanding_urbs--; - spin_unlock_irqrestore(&priv->tx_lock, flags); return count; -} /* ftdi_write */ - - -/* This function may get called when the device is closed */ - -static void ftdi_write_bulk_callback(struct urb *urb) -{ - unsigned long flags; - struct usb_serial_port *port = urb->context; - struct ftdi_private *priv; - int data_offset; /* will be 1 for the SIO and 0 otherwise */ - unsigned long countback; - int status = urb->status; - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - - dbg("%s - port %d", __func__, port->number); - - priv = usb_get_serial_port_data(port); - if (!priv) { - dbg("%s - bad port private data pointer - exiting", __func__); - return; - } - /* account for transferred data */ - countback = urb->transfer_buffer_length; - data_offset = priv->write_offset; - if (data_offset > 0) { - /* Subtract the control bytes */ - countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size)); - } - spin_lock_irqsave(&priv->tx_lock, flags); - --priv->tx_outstanding_urbs; - priv->tx_outstanding_bytes -= countback; - spin_unlock_irqrestore(&priv->tx_lock, flags); - - if (status) { - dbg("nonzero write bulk status received: %d", status); - } - - usb_serial_port_softint(port); -} /* ftdi_write_bulk_callback */ - - -static int ftdi_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - int room; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->tx_lock, flags); - if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) { - /* - * We really can take anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space - */ - room = 2048; - } else { - room = 0; - } - spin_unlock_irqrestore(&priv->tx_lock, flags); - return room; } -static int ftdi_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - int buffered; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->tx_lock, flags); - buffered = (int)priv->tx_outstanding_bytes; - spin_unlock_irqrestore(&priv->tx_lock, flags); - if (buffered < 0) { - dev_err(&port->dev, "%s outstanding tx bytes is negative!\n", - __func__); - buffered = 0; - } - return buffered; -} +#define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE) static int ftdi_process_packet(struct tty_struct *tty, struct usb_serial_port *port, struct ftdi_private *priv, @@ -2045,28 +1795,21 @@ static int ftdi_process_packet(struct tty_struct *tty, priv->prev_status = status; } - /* - * Although the device uses a bitmask and hence can have multiple - * errors on a packet - the order here sets the priority the error is - * returned to the tty layer. - */ flag = TTY_NORMAL; - if (packet[1] & FTDI_RS_OE) { - flag = TTY_OVERRUN; - dbg("OVERRRUN error"); - } - if (packet[1] & FTDI_RS_BI) { - flag = TTY_BREAK; - dbg("BREAK received"); - usb_serial_handle_break(port); - } - if (packet[1] & FTDI_RS_PE) { - flag = TTY_PARITY; - dbg("PARITY error"); - } - if (packet[1] & FTDI_RS_FE) { - flag = TTY_FRAME; - dbg("FRAMING error"); + if (packet[1] & FTDI_RS_ERR_MASK) { + /* Break takes precedence over parity, which takes precedence + * over framing errors */ + if (packet[1] & FTDI_RS_BI) { + flag = TTY_BREAK; + usb_serial_handle_break(port); + } else if (packet[1] & FTDI_RS_PE) { + flag = TTY_PARITY; + } else if (packet[1] & FTDI_RS_FE) { + flag = TTY_FRAME; + } + /* Overrun is special, not associated with a char */ + if (packet[1] & FTDI_RS_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); } len -= 2; @@ -2074,20 +1817,21 @@ static int ftdi_process_packet(struct tty_struct *tty, return 0; /* status only */ ch = packet + 2; - if (!(port->console && port->sysrq) && flag == TTY_NORMAL) - tty_insert_flip_string(tty, ch, len); - else { + if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { if (!usb_serial_handle_sysrq_char(tty, port, *ch)) tty_insert_flip_char(tty, *ch, flag); } + } else { + tty_insert_flip_string_fixed_flag(tty, ch, flag, len); } + return len; } -static void ftdi_process_read(struct usb_serial_port *port) +static void ftdi_process_read_urb(struct urb *urb) { - struct urb *urb = port->read_urb; + struct usb_serial_port *port = urb->context; struct tty_struct *tty; struct ftdi_private *priv = usb_get_serial_port_data(port); char *data = (char *)urb->transfer_buffer; @@ -2109,32 +1853,6 @@ static void ftdi_process_read(struct usb_serial_port *port) tty_kref_put(tty); } -static void ftdi_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, urb->status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - ftdi_process_read(port); - - spin_lock_irqsave(&port->lock, flags); - port->throttled = port->throttle_req; - if (!port->throttled) { - spin_unlock_irqrestore(&port->lock, flags); - ftdi_submit_read_urb(port, GFP_ATOMIC); - } else - spin_unlock_irqrestore(&port->lock, flags); -} - static void ftdi_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2165,15 +1883,13 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) } - /* old_termios contains the original termios settings and tty->termios contains * the new setting to be used * WARNING: set_termios calls this with old_termios in kernel space */ - static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) -{ /* ftdi_termios */ +{ struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); struct ktermios *termios = tty->termios; @@ -2401,7 +2117,6 @@ static int ftdi_tiocmset(struct tty_struct *tty, struct file *file, return update_mctrl(port, set, clear); } - static int ftdi_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2470,35 +2185,6 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } -static void ftdi_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&port->lock, flags); - port->throttle_req = 1; - spin_unlock_irqrestore(&port->lock, flags); -} - -void ftdi_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int was_throttled; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&port->lock, flags); - was_throttled = port->throttled; - port->throttled = port->throttle_req = 0; - spin_unlock_irqrestore(&port->lock, flags); - - if (was_throttled) - ftdi_submit_read_urb(port, GFP_KERNEL); -} - static int __init ftdi_init(void) { int retval; @@ -2529,15 +2215,12 @@ failed_sio_register: return retval; } - static void __exit ftdi_exit(void) { - dbg("%s", __func__); usb_deregister(&ftdi_driver); usb_serial_deregister(&ftdi_sio_device); - } diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index ff9bf80327a..213fe3d6128 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -23,14 +23,16 @@ */ /* Commands */ -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of + the port */ +#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem + status register */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ #define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ @@ -52,7 +54,7 @@ */ /* Port Identifier Table */ -#define PIT_DEFAULT 0 /* SIOA */ +#define PIT_DEFAULT 0 /* SIOA */ #define PIT_SIOA 1 /* SIOA */ /* The device this driver is tested with one has only one port */ #define PIT_SIOB 2 /* SIOB */ @@ -103,20 +105,21 @@ * wLength: 0 * Data: None * The BaudDivisor values are calculated as follows: - * - BaseClock is either 12000000 or 48000000 depending on the device. FIXME: I wish - * I knew how to detect old chips to select proper base clock! + * - BaseClock is either 12000000 or 48000000 depending on the device. + * FIXME: I wish I knew how to detect old chips to select proper base clock! * - BaudDivisor is a fixed point number encoded in a funny way. * (--WRONG WAY OF THINKING--) * BaudDivisor is a fixed point number encoded with following bit weighs: * (-2)(-1)(13..0). It is a radical with a denominator of 4, so values * end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...). * (--THE REALITY--) - * The both-bits-set has quite different meaning from 0.75 - the chip designers - * have decided it to mean 0.125 instead of 0.75. + * The both-bits-set has quite different meaning from 0.75 - the chip + * designers have decided it to mean 0.125 instead of 0.75. * This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates * and Flow Control Consideration for USB to RS232". * - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should - * automagically re-encode the resulting value to take fractions into consideration. + * automagically re-encode the resulting value to take fractions into + * consideration. * As all values are integers, some bit twiddling is in order: * BaudDivisor = (BaseClock / 16 / BaudRate) | * (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5 @@ -146,7 +149,7 @@ * not supported by the FT8U232AM). */ -typedef enum { +enum ftdi_chip_type { SIO = 1, FT8U232AM = 2, FT232BM = 3, @@ -154,37 +157,36 @@ typedef enum { FT232RL = 5, FT2232H = 6, FT4232H = 7 -} ftdi_chip_type_t; - -typedef enum { - ftdi_sio_b300 = 0, - ftdi_sio_b600 = 1, - ftdi_sio_b1200 = 2, - ftdi_sio_b2400 = 3, - ftdi_sio_b4800 = 4, - ftdi_sio_b9600 = 5, - ftdi_sio_b19200 = 6, - ftdi_sio_b38400 = 7, - ftdi_sio_b57600 = 8, - ftdi_sio_b115200 = 9 -} FTDI_SIO_baudrate_t; +}; + +enum ftdi_sio_baudrate { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +}; /* - * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values - * are calculated internally. + * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor + * values are calculated internally. */ - -#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) /* FTDI_SIO_SET_DATA */ /* @@ -287,8 +289,8 @@ typedef enum { * * A value of zero in the hIndex field disables handshaking * - * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character - * and the lValue field contains the XON character. + * If Xon/Xoff handshaking is specified, the hValue field should contain the + * XOFF character and the lValue field contains the XON character. */ /* @@ -373,7 +375,10 @@ typedef enum { /* FTDI_SIO_SET_ERROR_CHAR */ -/* Set the parity error replacement character for the specified communications port */ +/* + * Set the parity error replacement character for the specified communications + * port + */ /* * BmRequestType: 0100 0000b @@ -496,9 +501,10 @@ typedef enum { * * IN Endpoint * - * The device reserves the first two bytes of data on this endpoint to contain the current - * values of the modem and line status registers. In the absence of data, the device - * generates a message consisting of these two status bytes every 40 ms + * The device reserves the first two bytes of data on this endpoint to contain + * the current values of the modem and line status registers. In the absence of + * data, the device generates a message consisting of these two status bytes + * every 40 ms * * Byte 0: Modem Status * @@ -530,21 +536,21 @@ typedef enum { #define FTDI_RS0_RI (1 << 6) #define FTDI_RS0_RLSD (1 << 7) -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1<<1) +#define FTDI_RS_PE (1<<2) +#define FTDI_RS_FE (1<<3) +#define FTDI_RS_BI (1<<4) +#define FTDI_RS_THRE (1<<5) +#define FTDI_RS_TEMT (1<<6) +#define FTDI_RS_FIFO (1<<7) /* * OUT Endpoint * - * This device reserves the first bytes of data on this endpoint contain the length - * and port identifier of the message. For the FTDI USB Serial converter the port - * identifier is always 1. + * This device reserves the first bytes of data on this endpoint contain the + * length and port identifier of the message. For the FTDI USB Serial converter + * the port identifier is always 1. * * Byte 0: Line Status * diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 75482cbc399..94d86c3febc 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -275,8 +275,8 @@ /* * Hameg HO820 and HO870 interface (using VID 0x0403) */ -#define HAMEG_HO820_PID 0xed74 -#define HAMEG_HO870_PID 0xed71 +#define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO870_PID 0xed71 /* * MaxStream devices www.maxstream.net @@ -289,14 +289,14 @@ * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>. * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file. */ -#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ -#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ -#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ -#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ -#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ -#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ -#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ -#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ +#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ +#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ +#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ +#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ +#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ +#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ +#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ +#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ /* Domintell products http://www.domintell.com */ #define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */ @@ -483,9 +483,9 @@ * Blackfin gnICE JTAG * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice */ -#define ADI_VID 0x0456 -#define ADI_GNICE_PID 0xF000 -#define ADI_GNICEPLUS_PID 0xF001 +#define ADI_VID 0x0456 +#define ADI_GNICE_PID 0xF000 +#define ADI_GNICEPLUS_PID 0xF001 /* * RATOC REX-USB60F @@ -611,13 +611,13 @@ #define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ #define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ #define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ -#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ -#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ -#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ -#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ -#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ -#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ -#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ +#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ +#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ +#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ +#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ +#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ +#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ /* * JETI SPECTROMETER SPECBOS 1201 @@ -1013,7 +1013,7 @@ */ #define EVOLUTION_VID 0xDEEE /* Vendor ID */ #define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ -#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ +#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ #define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/ #define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index f804acb138e..a817ced8283 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,6 +1,7 @@ /* * USB Serial Converter Generic functions * + * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or @@ -12,6 +13,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/slab.h> +#include <linux/sysrq.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/module.h> @@ -117,7 +119,6 @@ void usb_serial_generic_deregister(void) int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; int result = 0; unsigned long flags; @@ -130,23 +131,8 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port spin_unlock_irqrestore(&port->lock, flags); /* if we have a bulk endpoint, start reading from it */ - if (port->bulk_in_size) { - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ((serial->type->read_bulk_callback) ? - serial->type->read_bulk_callback : - usb_serial_generic_read_bulk_callback), - port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - } + if (port->bulk_in_size) + result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); return result; } @@ -155,13 +141,22 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_open); static void generic_cleanup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + unsigned long flags; + int i; dbg("%s - port %d", __func__, port->number); if (serial->dev) { /* shutdown any bulk transfers that might be going on */ - if (port->bulk_out_size) + if (port->bulk_out_size) { usb_kill_urb(port->write_urb); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_kill_urb(port->write_urbs[i]); + + spin_lock_irqsave(&port->lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); + } if (port->bulk_in_size) usb_kill_urb(port->read_urb); } @@ -172,146 +167,68 @@ void usb_serial_generic_close(struct usb_serial_port *port) dbg("%s - port %d", __func__, port->number); generic_cleanup(port); } +EXPORT_SYMBOL_GPL(usb_serial_generic_close); -static int usb_serial_multi_urb_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) +int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) { - unsigned long flags; - struct urb *urb; - unsigned char *buffer; - int status; - int towrite; - int bwrite = 0; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) - dbg("%s - write request of 0 bytes", __func__); - - while (count > 0) { - towrite = (count > port->bulk_out_size) ? - port->bulk_out_size : count; - spin_lock_irqsave(&port->lock, flags); - if (port->urbs_in_flight > - port->serial->type->max_in_flight_urbs) { - spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - write limit hit", __func__); - return bwrite; - } - port->tx_bytes_flight += towrite; - port->urbs_in_flight++; - spin_unlock_irqrestore(&port->lock, flags); - - buffer = kmalloc(towrite, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, - "%s ran out of kernel memory for urb ...\n", __func__); - goto error_no_buffer; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "%s - no more free urbs\n", - __func__); - goto error_no_urb; - } - - /* Copy data */ - memcpy(buffer, buf + bwrite, towrite); - usb_serial_debug_data(debug, &port->dev, __func__, - towrite, buffer); - /* fill the buffer and send it */ - usb_fill_bulk_urb(urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - buffer, towrite, - usb_serial_generic_write_bulk_callback, port); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, status); - goto error; - } - - /* This urb is the responsibility of the host driver now */ - usb_free_urb(urb); - dbg("%s write: %d", __func__, towrite); - count -= towrite; - bwrite += towrite; - } - return bwrite; - -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&port->lock, flags); - port->urbs_in_flight--; - port->tx_bytes_flight -= towrite; - spin_unlock_irqrestore(&port->lock, flags); - return bwrite; + return kfifo_out_locked(&port->write_fifo, dest, size, &port->lock); } /** * usb_serial_generic_write_start - kick off an URB write * @port: Pointer to the &struct usb_serial_port data * - * Returns the number of bytes queued on success. This will be zero if there - * was nothing to send. Otherwise, it returns a negative errno value + * Returns zero on success, or a negative errno value */ static int usb_serial_generic_write_start(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - unsigned char *data; - int result; - int count; + struct urb *urb; + int count, result; unsigned long flags; - bool start_io; + int i; - /* Atomically determine whether we can and need to start a USB - * operation. */ + if (test_and_set_bit_lock(USB_SERIAL_WRITE_BUSY, &port->flags)) + return 0; +retry: spin_lock_irqsave(&port->lock, flags); - if (port->write_urb_busy) - start_io = false; - else { - start_io = (kfifo_len(&port->write_fifo) != 0); - port->write_urb_busy = start_io; + if (!port->write_urbs_free || !kfifo_len(&port->write_fifo)) { + clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); + spin_unlock_irqrestore(&port->lock, flags); + return 0; } + i = (int)find_first_bit(&port->write_urbs_free, + ARRAY_SIZE(port->write_urbs)); spin_unlock_irqrestore(&port->lock, flags); - if (!start_io) - return 0; - - data = port->write_urb->transfer_buffer; - count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock); - usb_serial_debug_data(debug, &port->dev, __func__, count, data); - - /* set up our urb */ - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ((serial->type->write_bulk_callback) ? - serial->type->write_bulk_callback : - usb_serial_generic_write_bulk_callback), - port); - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + urb = port->write_urbs[i]; + count = port->serial->type->prepare_write_buffer(port, + urb->transfer_buffer, + port->bulk_out_size); + urb->transfer_buffer_length = count; + usb_serial_debug_data(debug, &port->dev, __func__, count, + urb->transfer_buffer); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", + dev_err(&port->dev, "%s - error submitting urb: %d\n", __func__, result); - /* don't have to grab the lock here, as we will - retry if != 0 */ - port->write_urb_busy = 0; - } else - result = count; + clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); + return result; + } + clear_bit(i, &port->write_urbs_free); - return result; + spin_lock_irqsave(&port->lock, flags); + port->tx_bytes += count; + spin_unlock_irqrestore(&port->lock, flags); + + /* Try sending off another urb, unless in irq context (in which case + * there will be no free urb). */ + if (!in_irq()) + goto retry; + + clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); + + return 0; } /** @@ -328,7 +245,6 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port) int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - struct usb_serial *serial = port->serial; int result; dbg("%s - port %d", __func__, port->number); @@ -337,31 +253,23 @@ int usb_serial_generic_write(struct tty_struct *tty, if (!port->bulk_out_size) return -ENODEV; - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); + if (!count) return 0; - } - - if (serial->type->max_in_flight_urbs) - return usb_serial_multi_urb_write(tty, port, - buf, count); count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); result = usb_serial_generic_write_start(port); + if (result) + return result; - if (result >= 0) - result = count; - - return result; + return count; } EXPORT_SYMBOL_GPL(usb_serial_generic_write); int usb_serial_generic_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; unsigned long flags; - int room = 0; + int room; dbg("%s - port %d", __func__, port->number); @@ -369,14 +277,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&port->lock, flags); - if (serial->type->max_in_flight_urbs) { - if (port->urbs_in_flight < serial->type->max_in_flight_urbs) - room = port->bulk_out_size * - (serial->type->max_in_flight_urbs - - port->urbs_in_flight); - } else { - room = kfifo_avail(&port->write_fifo); - } + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); dbg("%s - returns %d", __func__, room); @@ -386,7 +287,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty) int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; unsigned long flags; int chars; @@ -396,61 +296,47 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) return 0; spin_lock_irqsave(&port->lock, flags); - if (serial->type->max_in_flight_urbs) - chars = port->tx_bytes_flight; - else - chars = kfifo_len(&port->write_fifo); + chars = kfifo_len(&port->write_fifo) + port->tx_bytes; spin_unlock_irqrestore(&port->lock, flags); dbg("%s - returns %d", __func__, chars); return chars; } - -void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, - gfp_t mem_flags) +int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, + gfp_t mem_flags) { - struct urb *urb = port->read_urb; - struct usb_serial *serial = port->serial; int result; - /* Continue reading from device */ - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, - urb->transfer_buffer_length, - ((serial->type->read_bulk_callback) ? - serial->type->read_bulk_callback : - usb_serial_generic_read_bulk_callback), port); - - result = usb_submit_urb(urb, mem_flags); + result = usb_submit_urb(port->read_urb, mem_flags); if (result && result != -EPERM) { - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", + dev_err(&port->dev, "%s - error submitting urb: %d\n", __func__, result); } + return result; } -EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); +EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); -/* Push data to tty layer and resubmit the bulk read URB */ -static void flush_and_resubmit_read_urb(struct usb_serial_port *port) +void usb_serial_generic_process_read_urb(struct urb *urb) { - struct urb *urb = port->read_urb; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct usb_serial_port *port = urb->context; + struct tty_struct *tty; char *ch = (char *)urb->transfer_buffer; int i; + if (!urb->actual_length) + return; + + tty = tty_port_tty_get(&port->port); if (!tty) - goto done; + return; /* The per character mucking around with sysrq path it too slow for stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases where the USB serial is not a console anyway */ - if (!port->console || !port->sysrq) + if (!port->port.console || !port->sysrq) tty_insert_flip_string(tty, ch, urb->actual_length); else { - /* Push data to tty */ for (i = 0; i < urb->actual_length; i++, ch++) { if (!usb_serial_handle_sysrq_char(tty, port, *ch)) tty_insert_flip_char(tty, *ch, TTY_NORMAL); @@ -458,9 +344,8 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) } tty_flip_buffer_push(tty); tty_kref_put(tty); -done: - usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); } +EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb); void usb_serial_generic_read_bulk_callback(struct urb *urb) { @@ -479,13 +364,14 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); + port->serial->type->process_read_urb(urb); /* Throttle the device if requested by tty */ spin_lock_irqsave(&port->lock, flags); port->throttled = port->throttle_req; if (!port->throttled) { spin_unlock_irqrestore(&port->lock, flags); - flush_and_resubmit_read_urb(port); + usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); } else spin_unlock_irqrestore(&port->lock, flags); } @@ -496,30 +382,29 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) unsigned long flags; struct usb_serial_port *port = urb->context; int status = urb->status; + int i; dbg("%s - port %d", __func__, port->number); - if (port->serial->type->max_in_flight_urbs) { - kfree(urb->transfer_buffer); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + if (port->write_urbs[i] == urb) + break; + + spin_lock_irqsave(&port->lock, flags); + port->tx_bytes -= urb->transfer_buffer_length; + set_bit(i, &port->write_urbs_free); + spin_unlock_irqrestore(&port->lock, flags); + + if (status) { + dbg("%s - non-zero urb status: %d", __func__, status); spin_lock_irqsave(&port->lock, flags); - --port->urbs_in_flight; - port->tx_bytes_flight -= urb->transfer_buffer_length; - if (port->urbs_in_flight < 0) - port->urbs_in_flight = 0; + kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); } else { - port->write_urb_busy = 0; - - if (status) - kfifo_reset_out(&port->write_fifo); - else - usb_serial_generic_write_start(port); + usb_serial_generic_write_start(port); } - if (status) - dbg("%s - non-zero urb status: %d", __func__, status); - usb_serial_port_softint(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); @@ -537,31 +422,31 @@ void usb_serial_generic_throttle(struct tty_struct *tty) port->throttle_req = 1; spin_unlock_irqrestore(&port->lock, flags); } +EXPORT_SYMBOL_GPL(usb_serial_generic_throttle); void usb_serial_generic_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; int was_throttled; - unsigned long flags; dbg("%s - port %d", __func__, port->number); /* Clear the throttle flags */ - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); was_throttled = port->throttled; port->throttled = port->throttle_req = 0; - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); - if (was_throttled) { - /* Resume reading from device */ - flush_and_resubmit_read_urb(port); - } + if (was_throttled) + usb_serial_generic_submit_read_urb(port, GFP_KERNEL); } +EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); +#ifdef CONFIG_MAGIC_SYSRQ int usb_serial_handle_sysrq_char(struct tty_struct *tty, struct usb_serial_port *port, unsigned int ch) { - if (port->sysrq && port->console) { + if (port->sysrq && port->port.console) { if (ch && time_before(jiffies, port->sysrq)) { handle_sysrq(ch, tty); port->sysrq = 0; @@ -571,6 +456,13 @@ int usb_serial_handle_sysrq_char(struct tty_struct *tty, } return 0; } +#else +int usb_serial_handle_sysrq_char(struct tty_struct *tty, + struct usb_serial_port *port, unsigned int ch) +{ + return 0; +} +#endif EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); int usb_serial_handle_break(struct usb_serial_port *port) @@ -600,7 +492,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) c++; } - if (port->write_urb) { + if (port->bulk_out_size) { r = usb_serial_generic_write_start(port); if (r < 0) c++; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 3ef8df0ef88..76e6fb3aab7 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -3020,7 +3020,7 @@ static int edge_startup(struct usb_serial *serial) /* set up our port private structures */ for (i = 0; i < serial->num_ports; ++i) { - edge_port = kmalloc(sizeof(struct edgeport_port), GFP_KERNEL); + edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); @@ -3033,7 +3033,6 @@ static int edge_startup(struct usb_serial *serial) kfree(edge_serial); return -ENOMEM; } - memset(edge_port, 0, sizeof(struct edgeport_port)); spin_lock_init(&edge_port->ep_lock); edge_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], edge_port); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index cb201c1f67f..dced7ec6547 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -34,15 +34,15 @@ -/* The following table is used to map the USBx port number to +/* The following table is used to map the USBx port number to * the device serial number (or physical USB path), */ #define MAX_EDGEPORTS 64 struct comMapper { char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */ - int numPorts; /* Number of ports */ - int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ - int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ + int numPorts; /* Number of ports */ + int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ + int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ }; @@ -51,7 +51,7 @@ struct comMapper { /* /proc/edgeport Interface * This interface uses read/write/lseek interface to talk to the edgeport driver * the following read functions are supported: */ -#define PROC_GET_MAPPING_TO_PATH 1 +#define PROC_GET_MAPPING_TO_PATH 1 #define PROC_GET_COM_ENTRY 2 #define PROC_GET_EDGE_MANUF_DESCRIPTOR 3 #define PROC_GET_BOOT_DESCRIPTOR 4 @@ -64,7 +64,7 @@ struct comMapper { /* the following write functions are supported: */ -#define PROC_SET_COM_MAPPING 1 +#define PROC_SET_COM_MAPPING 1 #define PROC_SET_COM_ENTRY 2 @@ -97,8 +97,8 @@ struct edgeport_product_info { __u8 BoardRev; /* PCB revision level (chg only if s/w visible) */ __u8 BootMajorVersion; /* Boot Firmware version: xx. */ - __u8 BootMinorVersion; /* yy. */ - __le16 BootBuildNumber; /* zzzz (LE format) */ + __u8 BootMinorVersion; /* yy. */ + __le16 BootBuildNumber; /* zzzz (LE format) */ __u8 FirmwareMajorVersion; /* Operational Firmware version:xx. */ __u8 FirmwareMinorVersion; /* yy. */ diff --git a/drivers/usb/serial/io_ionsp.h b/drivers/usb/serial/io_ionsp.h index 092e03d2dfc..5cc591bae54 100644 --- a/drivers/usb/serial/io_ionsp.h +++ b/drivers/usb/serial/io_ionsp.h @@ -89,10 +89,10 @@ All 16-bit fields are sent in little-endian (Intel) format. // struct int_status_pkt { - __u16 RxBytesAvail; // Additional bytes available to - // be read from Bulk IN pipe - __u16 TxCredits[ MAX_RS232_PORTS ]; // Additional space available in - // given port's TxBuffer + __u16 RxBytesAvail; // Additional bytes available to + // be read from Bulk IN pipe + __u16 TxCredits[MAX_RS232_PORTS]; // Additional space available in + // given port's TxBuffer }; @@ -115,24 +115,24 @@ struct int_status_pkt { #define IOSP_CMD_STAT_BIT 0x80 // If set, this is command/status header #define IS_CMD_STAT_HDR(Byte1) ((Byte1) & IOSP_CMD_STAT_BIT) -#define IS_DATA_HDR(Byte1) (! IS_CMD_STAT_HDR(Byte1)) +#define IS_DATA_HDR(Byte1) (!IS_CMD_STAT_HDR(Byte1)) #define IOSP_GET_HDR_PORT(Byte1) ((__u8) ((Byte1) & IOSP_PORT_MASK)) -#define IOSP_GET_HDR_DATA_LEN(Byte1, Byte2) ((__u16) ( ((__u16)((Byte1) & 0x78)) << 5) | (Byte2)) +#define IOSP_GET_HDR_DATA_LEN(Byte1, Byte2) ((__u16) (((__u16)((Byte1) & 0x78)) << 5) | (Byte2)) #define IOSP_GET_STATUS_CODE(Byte1) ((__u8) (((Byte1) & 0x78) >> 3)) // // These macros build the 1st and 2nd bytes for a data header // -#define IOSP_BUILD_DATA_HDR1(Port, Len) ((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78 )))) +#define IOSP_BUILD_DATA_HDR1(Port, Len) ((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78)))) #define IOSP_BUILD_DATA_HDR2(Port, Len) ((__u8) (Len)) // // These macros build the 1st and 2nd bytes for a command header // -#define IOSP_BUILD_CMD_HDR1(Port, Cmd) ((__u8) ( IOSP_CMD_STAT_BIT | (Port) | ((__u8) ((Cmd) << 3)) )) +#define IOSP_BUILD_CMD_HDR1(Port, Cmd) ((__u8) (IOSP_CMD_STAT_BIT | (Port) | ((__u8) ((Cmd) << 3)))) //-------------------------------------------------------------- @@ -194,24 +194,25 @@ struct int_status_pkt { // Define macros to simplify building of IOSP cmds // -#define MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val) \ - do { \ - (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_WRITE_UART_REG(Reg) ); \ - (*(ppBuf))[1] = (Val); \ - \ - *ppBuf += 2; \ - *pLen += 2; \ - } while (0) +#define MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val) \ +do { \ + (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port), \ + IOSP_WRITE_UART_REG(Reg)); \ + (*(ppBuf))[1] = (Val); \ + \ + *ppBuf += 2; \ + *pLen += 2; \ +} while (0) -#define MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param) \ - do { \ - (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_EXT_CMD ); \ - (*(ppBuf))[1] = (ExtCmd); \ - (*(ppBuf))[2] = (Param); \ - \ - *ppBuf += 3; \ - *pLen += 3; \ - } while (0) +#define MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param) \ +do { \ + (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port), IOSP_EXT_CMD); \ + (*(ppBuf))[1] = (ExtCmd); \ + (*(ppBuf))[2] = (Param); \ + \ + *ppBuf += 3; \ + *pLen += 3; \ +} while (0) @@ -310,16 +311,16 @@ struct int_status_pkt { // // IOSP_CMD_RX_CHECK_REQ // -// This command is used to assist in the implementation of the -// IOCTL_SERIAL_PURGE Windows IOCTL. -// This IOSP command tries to place a marker at the end of the RX -// queue in the Edgeport. If the Edgeport RX queue is full then -// the Check will be discarded. -// It is up to the device driver to timeout waiting for the -// RX_CHECK_RSP. If a RX_CHECK_RSP is received, the driver is -// sure that all data has been received from the edgeport and +// This command is used to assist in the implementation of the +// IOCTL_SERIAL_PURGE Windows IOCTL. +// This IOSP command tries to place a marker at the end of the RX +// queue in the Edgeport. If the Edgeport RX queue is full then +// the Check will be discarded. +// It is up to the device driver to timeout waiting for the +// RX_CHECK_RSP. If a RX_CHECK_RSP is received, the driver is +// sure that all data has been received from the edgeport and // may now purge any internal RX buffers. -// Note tat the sequence numbers may be used to detect lost +// Note tat the sequence numbers may be used to detect lost // CHECK_REQs. // Example for Port 0 @@ -341,7 +342,7 @@ struct int_status_pkt { // // 1ssssPPP P1P1P1P1 [ P2P2P2P2P2 ]... // -// ssss: 00-07 2-byte status. ssss identifies which UART register +// ssss: 00-07 2-byte status. ssss identifies which UART register // has changed value, and the new value is in P1. // Note that the ssss values do not correspond to the // 16554 register numbers given in 16554.H. Instead, @@ -383,14 +384,14 @@ struct int_status_pkt { // returns this in order to report // changes in modem status lines // (CTS, DSR, RI, CD) -// +// // 0x02 // Available for future expansion -// 0x03 // -// 0x04 // -// 0x05 // -// 0x06 // -// 0x07 // +// 0x03 // +// 0x04 // +// 0x05 // +// 0x06 // +// 0x07 // /**************************************************** @@ -400,7 +401,7 @@ struct int_status_pkt { #define IOSP_STATUS_LSR_DATA 0x08 // P1 is new value of LSR register (same as STATUS_LSR) // P2 is errored character read from -// RxFIFO after LSR reported an error. +// RxFIFO after LSR reported an error. #define IOSP_EXT_STATUS 0x09 // P1 is status/response code, param in P2. @@ -408,7 +409,7 @@ struct int_status_pkt { // Response Codes (P1 values) for 3-byte status messages #define IOSP_EXT_STATUS_CHASE_RSP 0 // Reply to CHASE_PORT cmd. P2 is outcome: -#define IOSP_EXT_STATUS_CHASE_PASS 0 // P2 = 0: All Tx data drained successfully +#define IOSP_EXT_STATUS_CHASE_PASS 0 // P2 = 0: All Tx data drained successfully #define IOSP_EXT_STATUS_CHASE_FAIL 1 // P2 = 1: Timed out (stuck due to flow // control from remote device). @@ -446,9 +447,9 @@ struct int_status_pkt { // Macros to parse status messages // -#define IOSP_GET_STATUS_LEN(code) ( (code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4) ) +#define IOSP_GET_STATUS_LEN(code) ((code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4)) -#define IOSP_STATUS_IS_2BYTE(code) ( (code) < 0x08 ) -#define IOSP_STATUS_IS_3BYTE(code) ( ((code) >= 0x08) && ((code) <= 0x0B) ) -#define IOSP_STATUS_IS_4BYTE(code) ( ((code) >= 0x0C) && ((code) <= 0x0D) ) +#define IOSP_STATUS_IS_2BYTE(code) ((code) < 0x08) +#define IOSP_STATUS_IS_3BYTE(code) (((code) >= 0x08) && ((code) <= 0x0B)) +#define IOSP_STATUS_IS_4BYTE(code) (((code) >= 0x0C) && ((code) <= 0x0D)) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index aa876f71f22..0fca2659206 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -36,6 +36,7 @@ #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/serial.h> +#include <linux/kfifo.h> #include <linux/ioctl.h> #include <linux/firmware.h> #include <linux/uaccess.h> @@ -56,10 +57,6 @@ #define EPROM_PAGE_SIZE 64 -struct edgeport_uart_buf_desc { - __u32 count; /* Number of bytes currently in buffer */ -}; - /* different hardware types */ #define HARDWARE_TYPE_930 0 #define HARDWARE_TYPE_TIUMP 1 @@ -87,14 +84,6 @@ struct product_info { __u8 hardware_type; /* Type of hardware */ } __attribute__((packed)); -/* circular buffer */ -struct edge_buf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - struct edgeport_port { __u16 uart_base; __u16 dma_address; @@ -108,7 +97,6 @@ struct edgeport_port { int baud_rate; int close_pending; int lsr_event; - struct edgeport_uart_buf_desc tx; struct async_icount icount; wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to @@ -119,7 +107,7 @@ struct edgeport_port { spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; - struct edge_buf *ep_out_buf; + struct kfifo write_fifo; }; struct edgeport_serial { @@ -249,17 +237,6 @@ static void edge_send(struct tty_struct *tty); static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); -/* circular buffer */ -static struct edge_buf *edge_buf_alloc(unsigned int size); -static void edge_buf_free(struct edge_buf *eb); -static void edge_buf_clear(struct edge_buf *eb); -static unsigned int edge_buf_data_avail(struct edge_buf *eb); -static unsigned int edge_buf_space_avail(struct edge_buf *eb); -static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, - unsigned int count); -static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, - unsigned int count); - static int ti_vread_sync(struct usb_device *dev, __u8 request, __u16 value, __u16 index, u8 *data, int size) @@ -590,7 +567,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, add_wait_queue(&tty->write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (edge_buf_data_avail(port->ep_out_buf) == 0 + if (kfifo_len(&port->write_fifo) == 0 || timeout == 0 || signal_pending(current) || !usb_get_intfdata(port->port->serial->interface)) /* disconnect */ @@ -602,7 +579,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); if (flush) - edge_buf_clear(port->ep_out_buf); + kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&port->ep_lock, flags); tty_kref_put(tty); @@ -2089,7 +2066,6 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -2103,10 +2079,8 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, if (edge_port->close_pending == 1) return -ENODEV; - spin_lock_irqsave(&edge_port->ep_lock, flags); - count = edge_buf_put(edge_port->ep_out_buf, data, count); - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - + count = kfifo_in_locked(&edge_port->write_fifo, data, count, + &edge_port->ep_lock); edge_send(tty); return count; @@ -2129,7 +2103,7 @@ static void edge_send(struct tty_struct *tty) return; } - count = edge_buf_get(edge_port->ep_out_buf, + count = kfifo_out(&edge_port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -2185,7 +2159,7 @@ static int edge_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - room = edge_buf_space_avail(edge_port->ep_out_buf); + room = kfifo_avail(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dbg("%s - returns %d", __func__, room); @@ -2207,7 +2181,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - chars = edge_buf_data_avail(edge_port->ep_out_buf); + chars = kfifo_len(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dbg("%s - returns %d", __func__, chars); @@ -2664,8 +2638,8 @@ static int edge_startup(struct usb_serial *serial) goto cleanup; } spin_lock_init(&edge_port->ep_lock); - edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE); - if (edge_port->ep_out_buf == NULL) { + if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, + GFP_KERNEL)) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); kfree(edge_port); @@ -2682,7 +2656,7 @@ static int edge_startup(struct usb_serial *serial) cleanup: for (--i; i >= 0; --i) { edge_port = usb_get_serial_port_data(serial->port[i]); - edge_buf_free(edge_port->ep_out_buf); + kfifo_free(&edge_port->write_fifo); kfree(edge_port); usb_set_serial_port_data(serial->port[i], NULL); } @@ -2713,7 +2687,7 @@ static void edge_release(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = usb_get_serial_port_data(serial->port[i]); - edge_buf_free(edge_port->ep_out_buf); + kfifo_free(&edge_port->write_fifo); kfree(edge_port); } kfree(usb_get_serial_data(serial)); @@ -2763,182 +2737,6 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port) } -/* Circular Buffer */ - -/* - * edge_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ - -static struct edge_buf *edge_buf_alloc(unsigned int size) -{ - struct edge_buf *eb; - - - if (size == 0) - return NULL; - - eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL); - if (eb == NULL) - return NULL; - - eb->buf_buf = kmalloc(size, GFP_KERNEL); - if (eb->buf_buf == NULL) { - kfree(eb); - return NULL; - } - - eb->buf_size = size; - eb->buf_get = eb->buf_put = eb->buf_buf; - - return eb; -} - - -/* - * edge_buf_free - * - * Free the buffer and all associated memory. - */ - -static void edge_buf_free(struct edge_buf *eb) -{ - if (eb) { - kfree(eb->buf_buf); - kfree(eb); - } -} - - -/* - * edge_buf_clear - * - * Clear out all data in the circular buffer. - */ - -static void edge_buf_clear(struct edge_buf *eb) -{ - if (eb != NULL) - eb->buf_get = eb->buf_put; - /* equivalent to a get of all data available */ -} - - -/* - * edge_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ - -static unsigned int edge_buf_data_avail(struct edge_buf *eb) -{ - if (eb == NULL) - return 0; - return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size); -} - - -/* - * edge_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ - -static unsigned int edge_buf_space_avail(struct edge_buf *eb) -{ - if (eb == NULL) - return 0; - return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size); -} - - -/* - * edge_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ - -static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, - unsigned int count) -{ - unsigned int len; - - - if (eb == NULL) - return 0; - - len = edge_buf_space_avail(eb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = eb->buf_buf + eb->buf_size - eb->buf_put; - if (count > len) { - memcpy(eb->buf_put, buf, len); - memcpy(eb->buf_buf, buf+len, count - len); - eb->buf_put = eb->buf_buf + count - len; - } else { - memcpy(eb->buf_put, buf, count); - if (count < len) - eb->buf_put += count; - else /* count == len */ - eb->buf_put = eb->buf_buf; - } - - return count; -} - - -/* - * edge_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ - -static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, - unsigned int count) -{ - unsigned int len; - - - if (eb == NULL) - return 0; - - len = edge_buf_data_avail(eb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = eb->buf_buf + eb->buf_size - eb->buf_get; - if (count > len) { - memcpy(buf, eb->buf_get, len); - memcpy(buf+len, eb->buf_buf, count - len); - eb->buf_get = eb->buf_buf + count - len; - } else { - memcpy(buf, eb->buf_get, count); - if (count < len) - eb->buf_get += count; - else /* count == len */ - eb->buf_get = eb->buf_buf; - } - - return count; -} - - static struct usb_serial_driver edgeport_1port_device = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index cab84f2256b..1bd67b24f91 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -1,4 +1,4 @@ -/***************************************************************************** +/***************************************************************************** * * Copyright (C) 1997-2002 Inside Out Networks, Inc. * @@ -22,10 +22,10 @@ #define DTK_ADDR_SPACE_I2C_TYPE_II 0x82 /* Addr is placed in I2C area */ #define DTK_ADDR_SPACE_I2C_TYPE_III 0x83 /* Addr is placed in I2C area */ -// UART Defines -#define UMPMEM_BASE_UART1 0xFFA0 /* UMP UART1 base address */ -#define UMPMEM_BASE_UART2 0xFFB0 /* UMP UART2 base address */ -#define UMPMEM_OFFS_UART_LSR 0x05 /* UMP UART LSR register offset */ +/* UART Defines */ +#define UMPMEM_BASE_UART1 0xFFA0 /* UMP UART1 base address */ +#define UMPMEM_BASE_UART2 0xFFB0 /* UMP UART2 base address */ +#define UMPMEM_OFFS_UART_LSR 0x05 /* UMP UART LSR register offset */ /* Bits per character */ #define UMP_UART_CHAR5BITS 0x00 @@ -54,7 +54,7 @@ #define UMP_UART_LSR_RX_MASK 0x10 #define UMP_UART_LSR_TX_MASK 0x20 -#define UMP_UART_LSR_DATA_MASK ( LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK ) +#define UMP_UART_LSR_DATA_MASK (LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK) /* Port Settings Constants) */ #define UMP_MASK_UART_FLAGS_RTS_FLOW 0x0001 @@ -79,50 +79,57 @@ #define UMP_PORT_DIR_OUT 0x01 #define UMP_PORT_DIR_IN 0x02 -// Address of Port 0 -#define UMPM_UART1_PORT 0x03 - -// Commands -#define UMPC_SET_CONFIG 0x05 -#define UMPC_OPEN_PORT 0x06 -#define UMPC_CLOSE_PORT 0x07 -#define UMPC_START_PORT 0x08 -#define UMPC_STOP_PORT 0x09 -#define UMPC_TEST_PORT 0x0A -#define UMPC_PURGE_PORT 0x0B - -#define UMPC_COMPLETE_READ 0x80 // Force the Firmware to complete the current Read -#define UMPC_HARDWARE_RESET 0x81 // Force UMP back into BOOT Mode -#define UMPC_COPY_DNLD_TO_I2C 0x82 // Copy current download image to type 0xf2 record in 16k I2C - // firmware will change 0xff record to type 2 record when complete +/* Address of Port 0 */ +#define UMPM_UART1_PORT 0x03 + +/* Commands */ +#define UMPC_SET_CONFIG 0x05 +#define UMPC_OPEN_PORT 0x06 +#define UMPC_CLOSE_PORT 0x07 +#define UMPC_START_PORT 0x08 +#define UMPC_STOP_PORT 0x09 +#define UMPC_TEST_PORT 0x0A +#define UMPC_PURGE_PORT 0x0B + +/* Force the Firmware to complete the current Read */ +#define UMPC_COMPLETE_READ 0x80 +/* Force UMP back into BOOT Mode */ +#define UMPC_HARDWARE_RESET 0x81 +/* + * Copy current download image to type 0xf2 record in 16k I2C + * firmware will change 0xff record to type 2 record when complete + */ +#define UMPC_COPY_DNLD_TO_I2C 0x82 - // Special function register commands - // wIndex is register address - // wValue is MSB/LSB mask/data -#define UMPC_WRITE_SFR 0x83 // Write SFR Register +/* + * Special function register commands + * wIndex is register address + * wValue is MSB/LSB mask/data + */ +#define UMPC_WRITE_SFR 0x83 /* Write SFR Register */ - // wIndex is register address -#define UMPC_READ_SFR 0x84 // Read SRF Register +/* wIndex is register address */ +#define UMPC_READ_SFR 0x84 /* Read SRF Register */ - // Set or Clear DTR (wValue bit 0 Set/Clear) wIndex ModuleID (port) +/* Set or Clear DTR (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ #define UMPC_SET_CLR_DTR 0x85 - // Set or Clear RTS (wValue bit 0 Set/Clear) wIndex ModuleID (port) +/* Set or Clear RTS (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ #define UMPC_SET_CLR_RTS 0x86 - // Set or Clear LOOPBACK (wValue bit 0 Set/Clear) wIndex ModuleID (port) +/* Set or Clear LOOPBACK (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ #define UMPC_SET_CLR_LOOPBACK 0x87 - // Set or Clear BREAK (wValue bit 0 Set/Clear) wIndex ModuleID (port) +/* Set or Clear BREAK (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ #define UMPC_SET_CLR_BREAK 0x88 - // Read MSR wIndex ModuleID (port) +/* Read MSR wIndex ModuleID (port) */ #define UMPC_READ_MSR 0x89 - /* Toolkit commands */ - /* Read-write group */ -#define UMPC_MEMORY_READ 0x92 -#define UMPC_MEMORY_WRITE 0x93 +/* Toolkit commands */ +/* Read-write group */ +#define UMPC_MEMORY_READ 0x92 +#define UMPC_MEMORY_WRITE 0x93 /* * UMP DMA Definitions @@ -130,8 +137,7 @@ #define UMPD_OEDB1_ADDRESS 0xFF08 #define UMPD_OEDB2_ADDRESS 0xFF10 -struct out_endpoint_desc_block -{ +struct out_endpoint_desc_block { __u8 Configuration; __u8 XBufAddr; __u8 XByteCount; @@ -147,8 +153,8 @@ struct out_endpoint_desc_block * TYPE DEFINITIONS * Structures for Firmware commands */ -struct ump_uart_config /* UART settings */ -{ +/* UART settings */ +struct ump_uart_config { __u16 wBaudRate; /* Baud rate */ __u16 wFlags; /* Bitmap mask of flags */ __u8 bDataBits; /* 5..8 - data bits per character */ @@ -165,8 +171,8 @@ struct ump_uart_config /* UART settings */ * TYPE DEFINITIONS * Structures for USB interrupts */ -struct ump_interrupt /* Interrupt packet structure */ -{ +/* Interrupt packet structure */ +struct ump_interrupt { __u8 bICode; /* Interrupt code (interrupt num) */ __u8 bIInfo; /* Interrupt information */ } __attribute__((packed)); diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 8e1a491e52a..51f83fbb73b 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -26,7 +26,7 @@ // // Definitions of USB product IDs -// +// #define USB_VENDOR_ID_ION 0x1608 // Our VID #define USB_VENDOR_ID_TI 0x0451 // TI VID @@ -54,7 +54,7 @@ // Product IDs - assigned to match middle digit of serial number (No longer true) #define ION_DEVICE_ID_80251_NETCHIP 0x020 // This bit is set in the PID if this edgeport hardware$ - // is based on the 80251+Netchip. + // is based on the 80251+Netchip. #define ION_DEVICE_ID_GENERATION_1 0x00 // Value for 930 based edgeports #define ION_DEVICE_ID_GENERATION_2 0x01 // Value for 80251+Netchip. @@ -134,7 +134,7 @@ #define ION_DEVICE_ID_TI_EDGEPORT_416 0x0212 // Edgeport/416 #define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 // Edgeport/1 RS232 #define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 // Edgeport/42 4 hub 2 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 +#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 #define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B // Edgeport/2c RS232 #define ION_DEVICE_ID_TI_EDGEPORT_221C 0x021C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and // 2 external hub ports - Large I2C @@ -142,7 +142,7 @@ // 2 external hub ports - Large I2C #define ION_DEVICE_ID_TI_EDGEPORT_21C 0x021E // Edgeport/21c is a TI based Edgeport/2 with lucent chip -// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) +// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) #define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x0240 // Edgeport/1 RS232 #define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x0241 // Edgeport/1i- RS422 model @@ -176,7 +176,7 @@ // Default to /P function #define ION_DEVICE_ID_PLUS_PWR_HP4CD 0x30C // 5052 Plus Power HubPort/4CD+ (for Dell) -#define ION_DEVICE_ID_PLUS_PWR_HP4C 0x30D // 5052 Plus Power HubPort/4C+ +#define ION_DEVICE_ID_PLUS_PWR_HP4C 0x30D // 5052 Plus Power HubPort/4C+ #define ION_DEVICE_ID_PLUS_PWR_PCI 0x30E // 3410 Plus Power PCI Host Controller 4 port @@ -217,17 +217,17 @@ #define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device -#define GENERATION_ID_FROM_USB_PRODUCT_ID( ProductId ) \ - ( (__u16) ((ProductId >> 8) & (ION_GENERATION_MASK)) ) +#define GENERATION_ID_FROM_USB_PRODUCT_ID(ProductId) \ + ((__u16) ((ProductId >> 8) & (ION_GENERATION_MASK))) -#define MAKE_USB_PRODUCT_ID( OemId, DeviceId ) \ - ( (__u16) (((OemId) << 10) || (DeviceId)) ) +#define MAKE_USB_PRODUCT_ID(OemId, DeviceId) \ + ((__u16) (((OemId) << 10) || (DeviceId))) -#define DEVICE_ID_FROM_USB_PRODUCT_ID( ProductId ) \ - ( (__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK)) ) +#define DEVICE_ID_FROM_USB_PRODUCT_ID(ProductId) \ + ((__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK))) -#define OEM_ID_FROM_USB_PRODUCT_ID( ProductId ) \ - ( (__u16) (((ProductId) >> 10) & 0x3F) ) +#define OEM_ID_FROM_USB_PRODUCT_ID(ProductId) \ + ((__u16) (((ProductId) >> 10) & 0x3F)) // // Definitions of parameters for download code. Note that these are @@ -237,7 +237,7 @@ // TxCredits value below which driver won't bother sending (to prevent too many small writes). // Send only if above 25% -#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max( ((InitialCredit) / 4), (MaxPacketSize) )) +#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max(((InitialCredit) / 4), (MaxPacketSize))) #define EDGE_FW_BULK_MAX_PACKET_SIZE 64 // Max Packet Size for Bulk In Endpoint (EP1) #define EDGE_FW_BULK_READ_BUFFER_SIZE 1024 // Size to use for Bulk reads @@ -263,7 +263,7 @@ // wValue = 16-bit address // wIndex = unused (though we could put segment 00: or FF: here) // wLength = # bytes to read/write (max 64) -// +// #define USB_REQUEST_ION_RESET_DEVICE 0 // Warm reboot Edgeport, retaining USB address #define USB_REQUEST_ION_GET_EPIC_DESC 1 // Get Edgeport Compatibility Descriptor @@ -278,7 +278,7 @@ #define USB_REQUEST_ION_ENABLE_SUSPEND 9 // Enable/Disable suspend feature // (wValue != 0: Enable; wValue = 0: Disable) -#define USB_REQUEST_ION_SEND_IOSP 10 // Send an IOSP command to the edgeport over the control pipe +#define USB_REQUEST_ION_SEND_IOSP 10 // Send an IOSP command to the edgeport over the control pipe #define USB_REQUEST_ION_RECV_IOSP 11 // Receive an IOSP command from the edgeport over the control pipe @@ -301,8 +301,7 @@ // this is a "real" Edgeport. // -struct edge_compatibility_bits -{ +struct edge_compatibility_bits { // This __u32 defines which Vendor-specific commands/functionality // the device supports on the default EP0 pipe. @@ -334,24 +333,22 @@ struct edge_compatibility_bits __u32 TrueEdgeport : 1; // 0001 Set if device is a 'real' Edgeport // (Used only by driver, NEVER set by an EPiC device) __u32 GenUnused : 31; // Available for future expansion, must be 0 - }; #define EDGE_COMPATIBILITY_MASK0 0x0001 #define EDGE_COMPATIBILITY_MASK1 0x3FFF #define EDGE_COMPATIBILITY_MASK2 0x0001 -struct edge_compatibility_descriptor -{ +struct edge_compatibility_descriptor { __u8 Length; // Descriptor Length (per USB spec) __u8 DescType; // Descriptor Type (per USB spec, =DEVICE type) __u8 EpicVer; // Version of EPiC spec supported - // (Currently must be 1) + // (Currently must be 1) __u8 NumPorts; // Number of serial ports supported __u8 iDownloadFile; // Index of string containing download code filename - // 0=no download, FF=download compiled into driver. - __u8 Unused[ 3 ]; // Available for future expansion, must be 0 - // (Currently must be 0). + // 0=no download, FF=download compiled into driver. + __u8 Unused[3]; // Available for future expansion, must be 0 + // (Currently must be 0). __u8 MajorVersion; // Firmware version: xx. __u8 MinorVersion; // yy. __le16 BuildNumber; // zzzz (LE format) @@ -359,9 +356,7 @@ struct edge_compatibility_descriptor // The following structure contains __u32s, with each bit // specifying whether the EPiC device supports the given // command or functionality. - struct edge_compatibility_bits Supports; - }; // Values for iDownloadFile @@ -391,8 +386,8 @@ struct edge_compatibility_descriptor // Define the max block size that may be read or written // in a read/write RAM/ROM command. -#define MAX_SIZE_REQ_ION_READ_MEM ( (__u16) 64 ) -#define MAX_SIZE_REQ_ION_WRITE_MEM ( (__u16) 64 ) +#define MAX_SIZE_REQ_ION_READ_MEM ((__u16)64) +#define MAX_SIZE_REQ_ION_WRITE_MEM ((__u16)64) // @@ -545,7 +540,7 @@ struct edge_boot_descriptor { __u8 MajorVersion; // C6 Firmware version: xx. __u8 MinorVersion; // C7 yy. __le16 BuildNumber; // C8 zzzz (LE format) - + __u16 EnumRootDescTable; // CA Root of ROM-based descriptor table __u8 NumDescTypes; // CC Number of supported descriptor types @@ -597,41 +592,36 @@ struct edge_boot_descriptor { #define I2C_DESC_TYPE_ION 0 // Not defined by TI -struct ti_i2c_desc -{ +struct ti_i2c_desc { __u8 Type; // Type of descriptor __u16 Size; // Size of data only not including header __u8 CheckSum; // Checksum (8 bit sum of data only) __u8 Data[0]; // Data starts here -}__attribute__((packed)); +} __attribute__((packed)); // for 5152 devices only (type 2 record) // for 3410 the version is stored in the WATCHPORT_FIRMWARE_VERSION descriptor -struct ti_i2c_firmware_rec -{ +struct ti_i2c_firmware_rec { __u8 Ver_Major; // Firmware Major version number __u8 Ver_Minor; // Firmware Minor version number __u8 Data[0]; // Download starts here -}__attribute__((packed)); +} __attribute__((packed)); -struct watchport_firmware_version -{ +struct watchport_firmware_version { // Added 2 bytes for version number __u8 Version_Major; // Download Version (for Watchport) __u8 Version_Minor; -}__attribute__((packed)); +} __attribute__((packed)); // Structure of header of download image in fw_down.h -struct ti_i2c_image_header -{ +struct ti_i2c_image_header { __le16 Length; __u8 CheckSum; -}__attribute__((packed)); +} __attribute__((packed)); -struct ti_basic_descriptor -{ +struct ti_basic_descriptor { __u8 Power; // Self powered // bit 7: 1 - power switching supported // 0 - power switching not supported @@ -663,9 +653,9 @@ struct ti_basic_descriptor #define TI_I2C_SIZE_MASK 0x1f // 5 bits #define TI_GET_I2C_SIZE(x) ((((x) & TI_I2C_SIZE_MASK)+1)*256) -#define TI_MAX_I2C_SIZE ( 16 * 1024 ) +#define TI_MAX_I2C_SIZE (16 * 1024) -#define TI_MANUF_VERSION_0 0 +#define TI_MANUF_VERSION_0 0 // IonConig2 flags #define TI_CONFIG2_RS232 0x01 @@ -676,8 +666,7 @@ struct ti_basic_descriptor #define TI_CONFIG2_WATCHPORT 0x10 -struct edge_ti_manuf_descriptor -{ +struct edge_ti_manuf_descriptor { __u8 IonConfig; // Config byte for ION manufacturing use __u8 IonConfig2; // Expansion __u8 Version; // Version @@ -688,7 +677,7 @@ struct edge_ti_manuf_descriptor __u8 HubConfig2; // Used to configure the Hub __u8 TotalPorts; // Total Number of Com Ports for the entire device (All UMPs) __u8 Reserved; // Reserved -}__attribute__((packed)); +} __attribute__((packed)); #endif // if !defined(_USBVEND_H) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 3fea9298eb1..28913fa95fb 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -56,7 +56,6 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> -#include "ipaq.h" #define KP_RETRIES 100 @@ -64,7 +63,7 @@ * Version Information */ -#define DRIVER_VERSION "v0.5" +#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" @@ -76,20 +75,8 @@ static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ipaq_close(struct usb_serial_port *port); static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); -static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int ipaq_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count); -static void ipaq_write_gather(struct usb_serial_port *port); -static void ipaq_read_bulk_callback(struct urb *urb); -static void ipaq_write_bulk_callback(struct urb *urb); -static int ipaq_write_room(struct tty_struct *tty); -static int ipaq_chars_in_buffer(struct tty_struct *tty); -static void ipaq_destroy_lists(struct usb_serial_port *port); - static struct usb_device_id ipaq_id_table [] = { /* The first entry is a placeholder for the insmod-specified device */ @@ -558,7 +545,7 @@ static struct usb_driver ipaq_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = ipaq_id_table, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; @@ -569,91 +556,24 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", - .usb_driver = &ipaq_driver, + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, + .bulk_in_size = 256, + .bulk_out_size = 256, .open = ipaq_open, - .close = ipaq_close, .attach = ipaq_startup, .calc_num_ports = ipaq_calc_num_ports, - .write = ipaq_write, - .write_room = ipaq_write_room, - .chars_in_buffer = ipaq_chars_in_buffer, - .read_bulk_callback = ipaq_read_bulk_callback, - .write_bulk_callback = ipaq_write_bulk_callback, }; -static spinlock_t write_list_lock; -static int bytes_in; -static int bytes_out; - static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct ipaq_private *priv; - struct ipaq_packet *pkt; - int i, result = 0; + int result = 0; int retries = connect_retries; dbg("%s - port %d", __func__, port->number); - bytes_in = 0; - bytes_out = 0; - priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); - if (priv == NULL) { - dev_err(&port->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - usb_set_serial_port_data(port, priv); - priv->active = 0; - priv->queue_len = 0; - priv->free_len = 0; - INIT_LIST_HEAD(&priv->queue); - INIT_LIST_HEAD(&priv->freelist); - - for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) { - pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL); - if (pkt == NULL) - goto enomem; - - pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL); - if (pkt->data == NULL) { - kfree(pkt); - goto enomem; - } - pkt->len = 0; - pkt->written = 0; - INIT_LIST_HEAD(&pkt->list); - list_add(&pkt->list, &priv->freelist); - priv->free_len += PACKET_SIZE; - } - - /* - * Lose the small buffers usbserial provides. Make larger ones. - */ - - kfree(port->bulk_in_buffer); - kfree(port->bulk_out_buffer); - /* make sure the generic serial code knows */ - port->bulk_out_buffer = NULL; - - port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); - if (port->bulk_in_buffer == NULL) - goto enomem; - - port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); - if (port->bulk_out_buffer == NULL) { - /* the buffer is useless, free it */ - kfree(port->bulk_in_buffer); - port->bulk_in_buffer = NULL; - goto enomem; - } - port->read_urb->transfer_buffer = port->bulk_in_buffer; - port->write_urb->transfer_buffer = port->bulk_out_buffer; - port->read_urb->transfer_buffer_length = URBDATA_SIZE; - port->bulk_out_size = port->write_urb->transfer_buffer_length - = URBDATA_SIZE; - msleep(1000*initial_wait); /* @@ -663,7 +583,6 @@ static int ipaq_open(struct tty_struct *tty, * through. Since this has a reasonably high failure rate, we retry * several times. */ - while (retries--) { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, @@ -673,269 +592,15 @@ static int ipaq_open(struct tty_struct *tty, msleep(1000); } - if (!retries && result) { - dev_err(&port->dev, "%s - failed doing control urb, error %d\n", __func__, result); - goto error; - } - - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ipaq_read_bulk_callback, port); - - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - goto error; - } - - return 0; - -enomem: - result = -ENOMEM; - dev_err(&port->dev, "%s - Out of memory\n", __func__); -error: - ipaq_destroy_lists(port); - kfree(priv); - return result; -} - - -static void ipaq_close(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - /* - * shut down bulk read and write - */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - ipaq_destroy_lists(port); - kfree(priv); - usb_set_serial_port_data(port, NULL); - - /* Uncomment the following line if you want to see some statistics - * in your syslog */ - /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ -} - -static void ipaq_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - bytes_in += urb->actual_length; - } - tty_kref_put(tty); - - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ipaq_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return; -} - -static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - const unsigned char *current_position = buf; - int bytes_sent = 0; - int transfer_size; - - dbg("%s - port %d", __func__, port->number); - - while (count > 0) { - transfer_size = min(count, PACKET_SIZE); - if (ipaq_write_bulk(port, current_position, transfer_size)) - break; - current_position += transfer_size; - bytes_sent += transfer_size; - count -= transfer_size; - bytes_out += transfer_size; + dev_err(&port->dev, "%s - failed doing control urb, error %d\n", + __func__, result); + return result; } - return bytes_sent; + return usb_serial_generic_open(tty, port); } -static int ipaq_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct ipaq_packet *pkt = NULL; - int result = 0; - unsigned long flags; - - if (priv->free_len <= 0) { - dbg("%s - we're stuffed", __func__); - return -EAGAIN; - } - - spin_lock_irqsave(&write_list_lock, flags); - if (!list_empty(&priv->freelist)) { - pkt = list_entry(priv->freelist.next, struct ipaq_packet, list); - list_del(&pkt->list); - priv->free_len -= PACKET_SIZE; - } - spin_unlock_irqrestore(&write_list_lock, flags); - if (pkt == NULL) { - dbg("%s - we're stuffed", __func__); - return -EAGAIN; - } - - memcpy(pkt->data, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data); - - pkt->len = count; - pkt->written = 0; - spin_lock_irqsave(&write_list_lock, flags); - list_add_tail(&pkt->list, &priv->queue); - priv->queue_len += count; - if (priv->active == 0) { - priv->active = 1; - ipaq_write_gather(port); - spin_unlock_irqrestore(&write_list_lock, flags); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else { - spin_unlock_irqrestore(&write_list_lock, flags); - } - return result; -} - -static void ipaq_write_gather(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - int count, room; - struct ipaq_packet *pkt, *tmp; - struct urb *urb = port->write_urb; - - room = URBDATA_SIZE; - list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { - count = min(room, (int)(pkt->len - pkt->written)); - memcpy(urb->transfer_buffer + (URBDATA_SIZE - room), - pkt->data + pkt->written, count); - room -= count; - pkt->written += count; - priv->queue_len -= count; - if (pkt->written == pkt->len) { - list_move(&pkt->list, &priv->freelist); - priv->free_len += PACKET_SIZE; - } - if (room == 0) - break; - } - - count = URBDATA_SIZE - room; - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ipaq_write_bulk_callback, port); - return; -} - -static void ipaq_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct ipaq_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - spin_lock_irqsave(&write_list_lock, flags); - if (!list_empty(&priv->queue)) { - ipaq_write_gather(port); - spin_unlock_irqrestore(&write_list_lock, flags); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else { - priv->active = 0; - spin_unlock_irqrestore(&write_list_lock, flags); - } - - usb_serial_port_softint(port); -} - -static int ipaq_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - freelen %d", __func__, priv->free_len); - return priv->free_len; -} - -static int ipaq_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ipaq_private *priv = usb_get_serial_port_data(port); - - dbg("%s - queuelen %d", __func__, priv->queue_len); - return priv->queue_len; -} - -static void ipaq_destroy_lists(struct usb_serial_port *port) -{ - struct ipaq_private *priv = usb_get_serial_port_data(port); - struct ipaq_packet *pkt, *tmp; - - list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { - kfree(pkt->data); - kfree(pkt); - } - list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) { - kfree(pkt->data); - kfree(pkt); - } -} - - static int ipaq_calc_num_ports(struct usb_serial *serial) { /* @@ -994,7 +659,6 @@ static int ipaq_startup(struct usb_serial *serial) static int __init ipaq_init(void) { int retval; - spin_lock_init(&write_list_lock); retval = usb_serial_register(&ipaq_device); if (retval) goto failed_usb_serial_register; @@ -1015,7 +679,6 @@ failed_usb_serial_register: return retval; } - static void __exit ipaq_exit(void) { usb_deregister(&ipaq_driver); diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h deleted file mode 100644 index 2b9035918b8..00000000000 --- a/drivers/usb/serial/ipaq.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * USB Compaq iPAQ driver - * - * Copyright (C) 2001 - 2002 - * Ganesh Varadarajan <ganesh@veritas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef __LINUX_USB_SERIAL_IPAQ_H -#define __LINUX_USB_SERIAL_IPAQ_H - -/* - * Since we can't queue our bulk write urbs (don't know why - it just - * doesn't work), we can send down only one write urb at a time. The simplistic - * approach taken by the generic usbserial driver will work, but it's not good - * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write - * requests coming from the line discipline. This is done by chaining them - * in lists of struct ipaq_packet, each packet holding a maximum of - * PACKET_SIZE bytes. - * - * ipaq_write() can be called from bottom half context; hence we can't - * allocate memory for packets there. So we initialize a pool of packets at - * the first open and maintain a freelist. - * - * The value of PACKET_SIZE was empirically determined by - * checking the maximum write sizes sent down by the ppp ldisc. - * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size. - */ - -struct ipaq_packet { - char *data; - size_t len; - size_t written; - struct list_head list; -}; - -struct ipaq_private { - int active; - int queue_len; - int free_len; - struct list_head queue; - struct list_head freelist; -}; - -#define URBDATA_SIZE 4096 -#define URBDATA_QUEUE_MAX (64 * 1024) -#define PACKET_SIZE 256 - -#endif diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index e1d07840cee..ca77e88836b 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -34,7 +34,6 @@ * DCD, DTR, RTS, CTS which are currently faked. * It's good enough for PPP at this point. It's based off all kinds of * code found in usb/serial and usb/class - * */ #include <linux/kernel.h> @@ -52,7 +51,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.3" +#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Roelf Diedericks" #define DRIVER_DESC "IPWireless tty driver" @@ -65,8 +64,6 @@ /* Message sizes */ #define EVENT_BUFFER_SIZE 0xFF #define CHAR2INT16(c1, c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff)) -#define NUM_BULK_URBS 24 -#define NUM_CONTROL_URBS 16 /* vendor/product pairs that are known work with this driver*/ #define IPW_VID 0x0bc3 @@ -151,47 +148,6 @@ static struct usb_driver usb_ipw_driver = { static int debug; -static void ipw_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ipw_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return; -} - static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_device *dev = port->serial->dev; @@ -229,15 +185,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) /*--2: Start reading from the device */ dbg("%s: setting up bulk read callback", __func__); - usb_fill_bulk_urb(port->read_urb, dev, - usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), - port->bulk_in_buffer, - port->bulk_in_size, - ipw_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result < 0) - dbg("%s - usb_submit_urb(read bulk) failed with status %d", - __func__, result); + usb_serial_generic_open(tty, port); /*--3: Tell the modem to open the floodgates on the rx bulk channel */ dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__); @@ -267,35 +215,6 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "initial flowcontrol failed (error = %d)\n", result); - - /*--5: raise the dtr */ - dbg("%s:raising dtr", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_SET_PIN, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_PIN_SETDTR, - 0, - NULL, - 0, - 200000); - if (result < 0) - dev_err(&port->dev, - "setting dtr failed (error = %d)\n", result); - - /*--6: raise the rts */ - dbg("%s:raising rts", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_SET_PIN, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_PIN_SETRTS, - 0, - NULL, - 0, - 200000); - if (result < 0) - dev_err(&port->dev, - "setting dtr failed (error = %d)\n", result); - kfree(buf_flow_init); return 0; } @@ -305,8 +224,8 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) struct usb_device *dev = port->serial->dev; int result; - /*--1: drop the dtr */ - dbg("%s:dropping dtr", __func__); + dbg("%s: on = %d", __func__, on); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, @@ -316,22 +235,20 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on) 0, 200000); if (result < 0) - dev_err(&port->dev, "dropping dtr failed (error = %d)\n", + dev_err(&port->dev, "setting dtr failed (error = %d)\n", result); - /*--2: drop the rts */ - dbg("%s:dropping rts", __func__); result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | - USB_RECIP_INTERFACE | USB_DIR_OUT, + USB_RECIP_INTERFACE | USB_DIR_OUT, on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS, 0, NULL, 0, 200000); if (result < 0) - dev_err(&port->dev, - "dropping rts failed (error = %d)\n", result); + dev_err(&port->dev, "setting rts failed (error = %d)\n", + result); } static void ipw_close(struct usb_serial_port *port) @@ -368,83 +285,7 @@ static void ipw_close(struct usb_serial_port *port) dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)\n", result); - /* shutdown any in-flight urbs that we know about */ - usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); -} - -static void ipw_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s", __func__); - - port->write_urb_busy = 0; - - if (status) - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - - usb_serial_port_softint(port); -} - -static int ipw_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_device *dev = port->serial->dev; - int ret; - - dbg("%s: TOP: count=%d, in_interrupt=%ld", __func__, - count, in_interrupt()); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - - spin_lock_bh(&port->lock); - if (port->write_urb_busy) { - spin_unlock_bh(&port->lock); - dbg("%s - already writing", __func__); - return 0; - } - port->write_urb_busy = 1; - spin_unlock_bh(&port->lock); - - count = min(count, port->bulk_out_size); - memcpy(port->bulk_out_buffer, buf, count); - - dbg("%s count now:%d", __func__, count); - - usb_fill_bulk_urb(port->write_urb, dev, - usb_sndbulkpipe(dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, - count, - ipw_write_bulk_callback, - port); - - ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (ret != 0) { - port->write_urb_busy = 0; - dbg("%s - usb_submit_urb(write bulk) failed with error = %d", - __func__, ret); - return ret; - } - - dbg("%s returning %d", __func__, count); - return count; -} - -static int ipw_probe(struct usb_serial_port *port) -{ - return 0; -} - -static int ipw_disconnect(struct usb_serial_port *port) -{ - usb_set_serial_port_data(port, NULL); - return 0; + usb_serial_generic_close(port); } static struct usb_serial_driver ipw_device = { @@ -453,17 +294,12 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", - .usb_driver = &usb_ipw_driver, + .usb_driver = &usb_ipw_driver, .id_table = usb_ipw_ids, .num_ports = 1, .open = ipw_open, .close = ipw_close, .dtr_rts = ipw_dtr_rts, - .port_probe = ipw_probe, - .port_remove = ipw_disconnect, - .write = ipw_write, - .write_bulk_callback = ipw_write_bulk_callback, - .read_bulk_callback = ipw_read_bulk_callback, }; diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 4a0f5197423..ccbce4066d0 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -3,6 +3,7 @@ * * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com) + * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,8 +73,8 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" +#define DRIVER_VERSION "v0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB IR Dongle driver" static int debug; @@ -87,11 +88,9 @@ static int xbof = -1; static int ir_startup (struct usb_serial *serial); static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ir_close(struct usb_serial_port *port); -static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static void ir_write_bulk_callback (struct urb *urb); -static void ir_read_bulk_callback (struct urb *urb); +static int ir_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size); +static void ir_process_read_urb(struct urb *urb); static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -130,10 +129,8 @@ static struct usb_serial_driver ir_device = { .set_termios = ir_set_termios, .attach = ir_startup, .open = ir_open, - .close = ir_close, - .write = ir_write, - .write_bulk_callback = ir_write_bulk_callback, - .read_bulk_callback = ir_read_bulk_callback, + .prepare_write_buffer = ir_prepare_write_buffer, + .process_read_urb = ir_process_read_urb, }; static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) @@ -198,7 +195,6 @@ error: return NULL; } - static u8 ir_xbof_change(u8 xbof) { u8 result; @@ -237,7 +233,6 @@ static u8 ir_xbof_change(u8 xbof) return(result); } - static int ir_startup(struct usb_serial *serial) { struct usb_irda_cs_descriptor *irda_desc; @@ -297,83 +292,22 @@ static int ir_startup(struct usb_serial *serial) static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) { - char *buffer; - int result = 0; + int i; dbg("%s - port %d", __func__, port->number); - if (buffer_size) { - /* override the default buffer sizes */ - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); - return -ENOMEM; - } - kfree(port->read_urb->transfer_buffer); - port->read_urb->transfer_buffer = buffer; - port->read_urb->transfer_buffer_length = buffer_size; - - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); - return -ENOMEM; - } - kfree(port->write_urb->transfer_buffer); - port->write_urb->transfer_buffer = buffer; - port->write_urb->transfer_buffer_length = buffer_size; - port->bulk_out_size = buffer_size; - } + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; /* Start reading from the device */ - usb_fill_bulk_urb( - port->read_urb, - port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ir_read_bulk_callback, - port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - - return result; + return usb_serial_generic_open(tty, port); } -static void ir_close(struct usb_serial_port *port) +static int ir_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) { - dbg("%s - port %d", __func__, port->number); - - /* shutdown our bulk read */ - usb_kill_urb(port->read_urb); -} - -static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - unsigned char *transfer_buffer; - int result; - int transfer_size; - - dbg("%s - port = %d, count = %d", __func__, port->number, count); - - if (count == 0) - return 0; - - spin_lock_bh(&port->lock); - if (port->write_urb_busy) { - spin_unlock_bh(&port->lock); - dbg("%s - already writing", __func__); - return 0; - } - port->write_urb_busy = 1; - spin_unlock_bh(&port->lock); - - transfer_buffer = port->write_urb->transfer_buffer; - transfer_size = min(count, port->bulk_out_size - 1); + unsigned char *buf = dest; + int count; /* * The first byte of the packet we send to the device contains an @@ -382,119 +316,57 @@ static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, * * See section 5.4.2.2 of the USB IrDA spec. */ - *transfer_buffer = ir_xbof | ir_baud; - ++transfer_buffer; - - memcpy(transfer_buffer, buf, transfer_size); + *buf = ir_xbof | ir_baud; - usb_fill_bulk_urb( - port->write_urb, - port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, - transfer_size + 1, - ir_write_bulk_callback, - port); - - port->write_urb->transfer_flags = URB_ZERO_PACKET; - - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - port->write_urb_busy = 0; - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else - result = transfer_size; - - return result; + count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, + &port->lock); + return count + 1; } -static void ir_write_bulk_callback(struct urb *urb) +static void ir_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); + unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; - port->write_urb_busy = 0; - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); + if (!urb->actual_length) return; - } + /* + * The first byte of the packet we get from the device + * contains a busy indicator and baud rate change. + * See section 5.4.1.2 of the USB IrDA spec. + */ + if (*data & 0x0f) + ir_baud = *data & 0x0f; - usb_serial_debug_data( - debug, - &port->dev, - __func__, - urb->actual_length, - urb->transfer_buffer); + if (urb->actual_length == 1) + return; - usb_serial_port_softint(port); + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + tty_insert_flip_string(tty, data + 1, urb->actual_length - 1); + tty_flip_buffer_push(tty); + tty_kref_put(tty); } -static void ir_read_bulk_callback(struct urb *urb) +static void ir_set_termios_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int result; int status = urb->status; dbg("%s - port %d", __func__, port->number); - switch (status) { - case 0: /* Successful */ - /* - * The first byte of the packet we get from the device - * contains a busy indicator and baud rate change. - * See section 5.4.1.2 of the USB IrDA spec. - */ - if ((*data & 0x0f) > 0) - ir_baud = *data & 0x0f; - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - tty = tty_port_tty_get(&port->port); - tty_insert_flip_string(tty, data+1, urb->actual_length - 1); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - - /* - * No break here. - * We want to resubmit the urb so we can read - * again. - */ - - case -EPROTO: /* taking inspiration from pl2303.c */ - /* Continue trying to always read */ - usb_fill_bulk_urb( - port->read_urb, - port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ir_read_bulk_callback, - port); - - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", - __func__, result); - break ; - default: - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - break ; - } - return; + kfree(urb->transfer_buffer); + + if (status) + dbg("%s - non-zero urb status: %d", __func__, status); } static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct urb *urb; unsigned char *transfer_buffer; int result; speed_t baud; @@ -548,41 +420,63 @@ static void ir_set_termios(struct tty_struct *tty, else ir_xbof = ir_xbof_change(xbof) ; - /* FIXME need to check to see if our write urb is busy right - * now, or use a urb pool. - * + /* Only speed changes are supported */ + tty_termios_copy_hw(tty->termios, old_termios); + tty_encode_baud_rate(tty, baud, baud); + + /* * send the baud change out on an "empty" data packet */ - transfer_buffer = port->write_urb->transfer_buffer; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_err(&port->dev, "%s - no more urbs\n", __func__); + return; + } + transfer_buffer = kmalloc(1, GFP_KERNEL); + if (!transfer_buffer) { + dev_err(&port->dev, "%s - out of memory\n", __func__); + goto err_buf; + } + *transfer_buffer = ir_xbof | ir_baud; usb_fill_bulk_urb( - port->write_urb, + urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, + transfer_buffer, 1, - ir_write_bulk_callback, + ir_set_termios_callback, port); - port->write_urb->transfer_flags = URB_ZERO_PACKET; + urb->transfer_flags = URB_ZERO_PACKET; - result = usb_submit_urb(port->write_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); + result = usb_submit_urb(urb, GFP_KERNEL); + if (result) { + dev_err(&port->dev, "%s - failed to submit urb: %d\n", + __func__, result); + goto err_subm; + } - /* Only speed changes are supported */ - tty_termios_copy_hw(tty->termios, old_termios); - tty_encode_baud_rate(tty, baud, baud); + usb_free_urb(urb); + + return; +err_subm: + kfree(transfer_buffer); +err_buf: + usb_free_urb(urb); } static int __init ir_init(void) { int retval; + if (buffer_size) { + ir_device.bulk_in_size = buffer_size; + ir_device.bulk_out_size = buffer_size; + } + retval = usb_serial_register(&ir_device); if (retval) goto failed_usb_serial_register; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 43f13cf2f01..74551cb2e8e 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -1044,34 +1044,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) if (buf == NULL) return -ENOMEM; - /* fixup the endpoint buffer size */ - kfree(port->bulk_out_buffer); - port->bulk_out_buffer = kmalloc(512, GFP_KERNEL); - port->bulk_out_size = 512; - kfree(port->bulk_in_buffer); - port->bulk_in_buffer = kmalloc(512, GFP_KERNEL); - port->bulk_in_size = 512; - - if (!port->bulk_out_buffer || !port->bulk_in_buffer) { - kfree(port->bulk_out_buffer); - kfree(port->bulk_in_buffer); - kfree(buf); - return -ENOMEM; - } - - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->bulk_out_buffer, 512, - NULL, NULL); - - - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->bulk_in_buffer, 512, - NULL, NULL); - priv->poll = 0; /* initialize writebuf */ @@ -1277,6 +1249,8 @@ static struct usb_serial_driver iuu_device = { }, .id_table = id_table, .num_ports = 1, + .bulk_in_size = 512, + .bulk_out_size = 512, .port_probe = iuu_create_sysfs_attrs, .port_remove = iuu_remove_sysfs_attrs, .open = iuu_open, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 8eef91ba4b1..cdbe8bf7f67 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -1,6 +1,7 @@ /* * KLSI KL5KUSB105 chip RS232 converter driver * + * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> * * This program is free software; you can redistribute it and/or modify @@ -34,17 +35,6 @@ * implement handshaking or decide that we do not support it */ -/* History: - * 0.3a - implemented pools of write URBs - * 0.3 - alpha version for public testing - * 0.2 - TIOCMGET works, so autopilot(1) can be used! - * 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l - * - * The driver skeleton is mainly based on mct_u232.c and various other - * pieces of code shamelessly copied from the drivers/usb/serial/ directory. - */ - - #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -64,8 +54,8 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v0.3a" -#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>" +#define DRIVER_VERSION "v0.4" +#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" @@ -73,23 +63,17 @@ static int debug; * Function prototypes */ static int klsi_105_startup(struct usb_serial *serial); -static void klsi_105_disconnect(struct usb_serial *serial); static void klsi_105_release(struct usb_serial *serial); static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); static void klsi_105_close(struct usb_serial_port *port); -static int klsi_105_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count); -static void klsi_105_write_bulk_callback(struct urb *urb); -static int klsi_105_chars_in_buffer(struct tty_struct *tty); -static int klsi_105_write_room(struct tty_struct *tty); -static void klsi_105_read_bulk_callback(struct urb *urb); static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static void klsi_105_throttle(struct tty_struct *tty); -static void klsi_105_unthrottle(struct tty_struct *tty); static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file); static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +static void klsi_105_process_read_urb(struct urb *urb); +static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size); /* * All of the device info needed for the KLSI converters. @@ -107,7 +91,7 @@ static struct usb_driver kl5kusb105d_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; static struct usb_serial_driver kl5kusb105d_device = { @@ -115,26 +99,23 @@ static struct usb_serial_driver kl5kusb105d_device = { .owner = THIS_MODULE, .name = "kl5kusb105d", }, - .description = "KL5KUSB105D / PalmConnect", - .usb_driver = &kl5kusb105d_driver, - .id_table = id_table, - .num_ports = 1, - .open = klsi_105_open, - .close = klsi_105_close, - .write = klsi_105_write, - .write_bulk_callback = klsi_105_write_bulk_callback, - .chars_in_buffer = klsi_105_chars_in_buffer, - .write_room = klsi_105_write_room, - .read_bulk_callback = klsi_105_read_bulk_callback, - .set_termios = klsi_105_set_termios, - /*.break_ctl = klsi_105_break_ctl,*/ - .tiocmget = klsi_105_tiocmget, - .tiocmset = klsi_105_tiocmset, - .attach = klsi_105_startup, - .disconnect = klsi_105_disconnect, - .release = klsi_105_release, - .throttle = klsi_105_throttle, - .unthrottle = klsi_105_unthrottle, + .description = "KL5KUSB105D / PalmConnect", + .usb_driver = &kl5kusb105d_driver, + .id_table = id_table, + .num_ports = 1, + .bulk_out_size = 64, + .open = klsi_105_open, + .close = klsi_105_close, + .set_termios = klsi_105_set_termios, + /*.break_ctl = klsi_105_break_ctl,*/ + .tiocmget = klsi_105_tiocmget, + .tiocmset = klsi_105_tiocmset, + .attach = klsi_105_startup, + .release = klsi_105_release, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, + .process_read_urb = klsi_105_process_read_urb, + .prepare_write_buffer = klsi_105_prepare_write_buffer, }; struct klsi_105_port_settings { @@ -145,18 +126,11 @@ struct klsi_105_port_settings { __u8 unknown2; } __attribute__ ((packed)); -/* we implement a pool of NUM_URBS urbs per usb_serial */ -#define NUM_URBS 1 -#define URB_TRANSFER_BUFFER_SIZE 64 struct klsi_105_private { struct klsi_105_port_settings cfg; struct ktermios termios; unsigned long line_state; /* modem line settings */ - /* write pool */ - struct urb *write_urb_pool[NUM_URBS]; spinlock_t lock; - unsigned long bytes_in; - unsigned long bytes_out; }; @@ -189,7 +163,7 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port, settings->pktlen, settings->baudrate, settings->databits, settings->unknown1, settings->unknown2); return rc; -} /* klsi_105_chg_port_settings */ +} /* translate a 16-bit status value from the device to linux's TIO bits */ static unsigned long klsi_105_status2linestate(const __u16 status) @@ -202,6 +176,7 @@ static unsigned long klsi_105_status2linestate(const __u16 status) return res; } + /* * Read line control via vendor command and return result through * *line_state_p @@ -258,7 +233,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, static int klsi_105_startup(struct usb_serial *serial) { struct klsi_105_private *priv; - int i, j; + int i; /* check if we support the product id (see keyspan.c) * FIXME @@ -282,29 +257,9 @@ static int klsi_105_startup(struct usb_serial *serial) priv->line_state = 0; - priv->bytes_in = 0; - priv->bytes_out = 0; usb_set_serial_port_data(serial->port[i], priv); spin_lock_init(&priv->lock); - for (j = 0; j < NUM_URBS; j++) { - struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); - - priv->write_urb_pool[j] = urb; - if (urb == NULL) { - dev_err(&serial->dev->dev, "No more urbs???\n"); - goto err_cleanup; - } - - urb->transfer_buffer = - kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&serial->dev->dev, - "%s - out of memory for urb buffers.\n", - __func__); - goto err_cleanup; - } - } /* priv->termios is left uninitalized until port opening */ init_waitqueue_head(&serial->port[i]->write_wait); @@ -315,44 +270,11 @@ static int klsi_105_startup(struct usb_serial *serial) err_cleanup: for (; i >= 0; i--) { priv = usb_get_serial_port_data(serial->port[i]); - for (j = 0; j < NUM_URBS; j++) { - if (priv->write_urb_pool[j]) { - kfree(priv->write_urb_pool[j]->transfer_buffer); - usb_free_urb(priv->write_urb_pool[j]); - } - } + kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } return -ENOMEM; -} /* klsi_105_startup */ - - -static void klsi_105_disconnect(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) { - struct klsi_105_private *priv = - usb_get_serial_port_data(serial->port[i]); - - if (priv) { - /* kill our write urb pool */ - int j; - struct urb **write_urbs = priv->write_urb_pool; - - for (j = 0; j < NUM_URBS; j++) { - if (write_urbs[j]) { - usb_kill_urb(write_urbs[j]); - usb_free_urb(write_urbs[j]); - } - } - } - } -} /* klsi_105_disconnect */ - +} static void klsi_105_release(struct usb_serial *serial) { @@ -360,13 +282,9 @@ static void klsi_105_release(struct usb_serial *serial) dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { - struct klsi_105_private *priv = - usb_get_serial_port_data(serial->port[i]); - - kfree(priv); - } -} /* klsi_105_release */ + for (i = 0; i < serial->num_ports; ++i) + kfree(usb_get_serial_port_data(serial->port[i])); +} static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) { @@ -416,18 +334,8 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); /* READ_ON and urb submission */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - klsi_105_read_bulk_callback, - port); - - rc = usb_submit_urb(port->read_urb, GFP_KERNEL); + rc = usb_serial_generic_open(tty, port); if (rc) { - dev_err(&port->dev, "%s - failed submitting read urb, " - "error %d\n", __func__, rc); retval = rc; goto exit; } @@ -460,12 +368,10 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) exit: kfree(cfg); return retval; -} /* klsi_105_open */ - +} static void klsi_105_close(struct usb_serial_port *port) { - struct klsi_105_private *priv = usb_get_serial_port_data(port); int rc; dbg("%s port %d", __func__, port->number); @@ -488,239 +394,62 @@ static void klsi_105_close(struct usb_serial_port *port) mutex_unlock(&port->serial->disc_mutex); /* shutdown our bulk reads and writes */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - /* unlink our write pool */ - /* FIXME */ + usb_serial_generic_close(port); + /* wgg - do I need this? I think so. */ usb_kill_urb(port->interrupt_in_urb); - dev_info(&port->serial->dev->dev, - "port stats: %ld bytes in, %ld bytes out\n", - priv->bytes_in, priv->bytes_out); -} /* klsi_105_close */ - +} /* We need to write a complete 64-byte data block and encode the * number actually sent in the first double-byte, LSB-order. That * leaves at most 62 bytes of payload. */ -#define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */ - - -static int klsi_105_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) +#define KLSI_HDR_LEN 2 +static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) { - struct klsi_105_private *priv = usb_get_serial_port_data(port); - int result, size; - int bytes_sent = 0; - - dbg("%s - port %d", __func__, port->number); - - while (count > 0) { - /* try to find a free urb (write 0 bytes if none) */ - struct urb *urb = NULL; - unsigned long flags; - int i; - /* since the pool is per-port we might not need - the spin lock !? */ - spin_lock_irqsave(&priv->lock, flags); - for (i = 0; i < NUM_URBS; i++) { - if (priv->write_urb_pool[i]->status != -EINPROGRESS) { - urb = priv->write_urb_pool[i]; - dbg("%s - using pool URB %d", __func__, i); - break; - } - } - spin_unlock_irqrestore(&priv->lock, flags); - - if (urb == NULL) { - dbg("%s - no more free urbs", __func__); - goto exit; - } - - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = - kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); - if (urb->transfer_buffer == NULL) { - dev_err(&port->dev, - "%s - no more kernel memory...\n", - __func__); - goto exit; - } - } - - size = min(count, port->bulk_out_size - KLSI_105_DATA_OFFSET); - size = min(size, URB_TRANSFER_BUFFER_SIZE - - KLSI_105_DATA_OFFSET); - - memcpy(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size); - - /* write payload size into transfer buffer */ - ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF); - ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8); - - /* set up our urb */ - usb_fill_bulk_urb(urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, - URB_TRANSFER_BUFFER_SIZE, - klsi_105_write_bulk_callback, - port); - - /* send the data out the bulk port */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - goto exit; - } - buf += size; - bytes_sent += size; - count -= size; - } -exit: - /* lockless, but it's for debug info only... */ - priv->bytes_out += bytes_sent; - - return bytes_sent; /* that's how much we wrote */ -} /* klsi_105_write */ - -static void klsi_105_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", __func__, - status); - return; - } + unsigned char *buf = dest; + int count; - usb_serial_port_softint(port); -} /* klsi_105_write_bulk_completion_callback */ + count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, + &port->lock); + put_unaligned_le16(count, buf); - -/* return number of characters currently in the writing process */ -static int klsi_105_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int chars = 0; - int i; - unsigned long flags; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < NUM_URBS; ++i) { - if (priv->write_urb_pool[i]->status == -EINPROGRESS) - chars += URB_TRANSFER_BUFFER_SIZE; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; + return count + KLSI_HDR_LEN; } -static int klsi_105_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int i; - int room = 0; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - - spin_lock_irqsave(&priv->lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (priv->write_urb_pool[i]->status != -EINPROGRESS) - room += URB_TRANSFER_BUFFER_SIZE; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - - - -static void klsi_105_read_bulk_callback(struct urb *urb) +/* The data received is preceded by a length double-byte in LSB-first order. + */ +static void klsi_105_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; - int rc; - int status = urb->status; + struct tty_struct *tty; + unsigned len; - dbg("%s - port %d", __func__, port->number); + /* empty urbs seem to happen, we ignore them */ + if (!urb->actual_length) + return; - /* The urb might have been killed. */ - if (status) { - dbg("%s - nonzero read bulk status received: %d", __func__, - status); + if (urb->actual_length <= KLSI_HDR_LEN) { + dbg("%s - malformed packet", __func__); return; } - /* The data received is again preceded by a length double-byte in LSB- - * first order (see klsi_105_write() ) - */ - if (urb->actual_length == 0) { - /* empty urbs seem to happen, we ignore them */ - /* dbg("%s - emtpy URB", __func__); */ - ; - } else if (urb->actual_length <= 2) { - dbg("%s - size %d URB not understood", __func__, - urb->actual_length); - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - } else { - int bytes_sent = ((__u8 *) data)[0] + - ((unsigned int) ((__u8 *) data)[1] << 8); - tty = tty_port_tty_get(&port->port); - /* we should immediately resubmit the URB, before attempting - * to pass the data on to the tty layer. But that needs locking - * against re-entry an then mixed-up data because of - * intermixed tty_flip_buffer_push()s - * FIXME - */ - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - if (bytes_sent + 2 > urb->actual_length) { - dbg("%s - trying to read more data than available" - " (%d vs. %d)", __func__, - bytes_sent+2, urb->actual_length); - /* cap at implied limit */ - bytes_sent = urb->actual_length - 2; - } - - tty_insert_flip_string(tty, data + 2, bytes_sent); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty = tty_port_tty_get(&port->port); + if (!tty) + return; - /* again lockless, but debug info only */ - priv->bytes_in += bytes_sent; + len = get_unaligned_le16(data); + if (len > urb->actual_length - KLSI_HDR_LEN) { + dbg("%s - packet length mismatch", __func__); + len = urb->actual_length - KLSI_HDR_LEN; } - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - klsi_105_read_bulk_callback, - port); - rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (rc) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, rc); -} /* klsi_105_read_bulk_callback */ + tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len); + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, @@ -887,8 +616,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, klsi_105_chg_port_settings(port, cfg); err: kfree(cfg); -} /* klsi_105_set_termios */ - +} #if 0 static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) @@ -906,7 +634,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) lcr |= MCT_U232_SET_BREAK; mct_u232_set_line_ctrl(serial, lcr); -} /* mct_u232_break_ctl */ +} #endif static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file) @@ -962,29 +690,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, return retval; } -static void klsi_105_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->read_urb); -} - -static void klsi_105_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int result; - - dbg("%s - port %d", __func__, port->number); - - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); -} - - static int __init klsi_105_init(void) { @@ -1005,7 +710,6 @@ failed_usb_serial_register: return retval; } - static void __exit klsi_105_exit(void) { usb_deregister(&kl5kusb105d_driver); @@ -1023,5 +727,3 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "enable extensive debugging messages"); - -/* vim: set sts=8 ts=8 sw=8: */ diff --git a/drivers/usb/serial/kl5kusb105.h b/drivers/usb/serial/kl5kusb105.h index 1231d9e7839..22a90badc86 100644 --- a/drivers/usb/serial/kl5kusb105.h +++ b/drivers/usb/serial/kl5kusb105.h @@ -17,16 +17,16 @@ /* baud rates */ enum { - kl5kusb105a_sio_b115200 = 0, - kl5kusb105a_sio_b57600 = 1, - kl5kusb105a_sio_b38400 = 2, - kl5kusb105a_sio_b19200 = 4, - kl5kusb105a_sio_b14400 = 5, - kl5kusb105a_sio_b9600 = 6, - kl5kusb105a_sio_b4800 = 8, /* unchecked */ - kl5kusb105a_sio_b2400 = 9, /* unchecked */ - kl5kusb105a_sio_b1200 = 0xa, /* unchecked */ - kl5kusb105a_sio_b600 = 0xb /* unchecked */ + kl5kusb105a_sio_b115200 = 0, + kl5kusb105a_sio_b57600 = 1, + kl5kusb105a_sio_b38400 = 2, + kl5kusb105a_sio_b19200 = 4, + kl5kusb105a_sio_b14400 = 5, + kl5kusb105a_sio_b9600 = 6, + kl5kusb105a_sio_b4800 = 8, /* unchecked */ + kl5kusb105a_sio_b2400 = 9, /* unchecked */ + kl5kusb105a_sio_b1200 = 0xa, /* unchecked */ + kl5kusb105a_sio_b600 = 0xb /* unchecked */ }; /* data bits */ @@ -53,17 +53,16 @@ enum { #define KL5KUSB105A_CTS ((1<<5) | (1<<4)) #define KL5KUSB105A_WANTS_TO_SEND 0x30 -//#define KL5KUSB105A_DTR /* Data Terminal Ready */ -//#define KL5KUSB105A_CTS /* Clear To Send */ -//#define KL5KUSB105A_CD /* Carrier Detect */ -//#define KL5KUSB105A_DSR /* Data Set Ready */ -//#define KL5KUSB105A_RxD /* Receive pin */ - -//#define KL5KUSB105A_LE -//#define KL5KUSB105A_RTS -//#define KL5KUSB105A_ST -//#define KL5KUSB105A_SR -//#define KL5KUSB105A_RI /* Ring Indicator */ - -/* vim: set ts=8 sts=8: */ - +#if 0 +#define KL5KUSB105A_DTR /* Data Terminal Ready */ +#define KL5KUSB105A_CTS /* Clear To Send */ +#define KL5KUSB105A_CD /* Carrier Detect */ +#define KL5KUSB105A_DSR /* Data Set Ready */ +#define KL5KUSB105A_RxD /* Receive pin */ + +#define KL5KUSB105A_LE +#define KL5KUSB105A_RTS +#define KL5KUSB105A_ST +#define KL5KUSB105A_SR +#define KL5KUSB105A_RI /* Ring Indicator */ +#endif diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index c113a2a0e10..bd5bd8589e0 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -345,7 +345,8 @@ static void kobil_close(struct usb_serial_port *port) /* FIXME: Add rts/dtr methods */ if (port->write_urb) { - usb_kill_urb(port->write_urb); + usb_poison_urb(port->write_urb); + kfree(port->write_urb->transfer_buffer); usb_free_urb(port->write_urb); port->write_urb = NULL; } diff --git a/drivers/usb/serial/kobil_sct.h b/drivers/usb/serial/kobil_sct.h index a51fbb5ae45..be207f7156f 100644 --- a/drivers/usb/serial/kobil_sct.h +++ b/drivers/usb/serial/kobil_sct.h @@ -23,38 +23,55 @@ #define SUSBCR_SSL_SETDTR 0x0004 #define SUSBCR_SSL_CLRDTR 0x0010 -#define SUSBCR_SSL_PURGE_TXABORT 0x0100 // Kill the pending/current writes to the comm port. -#define SUSBCR_SSL_PURGE_RXABORT 0x0200 // Kill the pending/current reads to the comm port. -#define SUSBCR_SSL_PURGE_TXCLEAR 0x0400 // Kill the transmit queue if there. -#define SUSBCR_SSL_PURGE_RXCLEAR 0x0800 // Kill the typeahead buffer if there. +/* Kill the pending/current writes to the comm port. */ +#define SUSBCR_SSL_PURGE_TXABORT 0x0100 +/* Kill the pending/current reads to the comm port. */ +#define SUSBCR_SSL_PURGE_RXABORT 0x0200 +/* Kill the transmit queue if there. */ +#define SUSBCR_SSL_PURGE_TXCLEAR 0x0400 +/* Kill the typeahead buffer if there. */ +#define SUSBCR_SSL_PURGE_RXCLEAR 0x0800 #define SUSBCRequest_GetStatusLineState 4 -#define SUSBCR_GSL_RXCHAR 0x0001 // Any Character received -#define SUSBCR_GSL_TXEMPTY 0x0004 // Transmitt Queue Empty -#define SUSBCR_GSL_CTS 0x0008 // CTS changed state -#define SUSBCR_GSL_DSR 0x0010 // DSR changed state -#define SUSBCR_GSL_RLSD 0x0020 // RLSD changed state -#define SUSBCR_GSL_BREAK 0x0040 // BREAK received -#define SUSBCR_GSL_ERR 0x0080 // Line status error occurred -#define SUSBCR_GSL_RING 0x0100 // Ring signal detected +/* Any Character received */ +#define SUSBCR_GSL_RXCHAR 0x0001 +/* Transmitt Queue Empty */ +#define SUSBCR_GSL_TXEMPTY 0x0004 +/* CTS changed state */ +#define SUSBCR_GSL_CTS 0x0008 +/* DSR changed state */ +#define SUSBCR_GSL_DSR 0x0010 +/* RLSD changed state */ +#define SUSBCR_GSL_RLSD 0x0020 +/* BREAK received */ +#define SUSBCR_GSL_BREAK 0x0040 +/* Line status error occurred */ +#define SUSBCR_GSL_ERR 0x0080 +/* Ring signal detected */ +#define SUSBCR_GSL_RING 0x0100 #define SUSBCRequest_Misc 8 -#define SUSBCR_MSC_ResetReader 0x0001 // use a predefined reset sequence -#define SUSBCR_MSC_ResetAllQueues 0x0002 // use a predefined sequence to reset the internal queues +/* use a predefined reset sequence */ +#define SUSBCR_MSC_ResetReader 0x0001 +/* use a predefined sequence to reset the internal queues */ +#define SUSBCR_MSC_ResetAllQueues 0x0002 #define SUSBCRequest_GetMisc 0x10 -#define SUSBCR_MSC_GetFWVersion 0x0001 /* get the firmware version from device, - coded like this 0xHHLLBBPP - with HH = Firmware Version High Byte - LL = Firmware Version Low Byte - BB = Build Number - PP = Further Attributes - */ - -#define SUSBCR_MSC_GetHWVersion 0x0002 /* get the hardware version from device - coded like this 0xHHLLPPRR - with HH = Software Version High Byte - LL = Software Version Low Byte - PP = Further Attributes - RR = Reserved for the hardware ID - */ + +/* + * get the firmware version from device, coded like this 0xHHLLBBPP with + * HH = Firmware Version High Byte + * LL = Firmware Version Low Byte + * BB = Build Number + * PP = Further Attributes + */ +#define SUSBCR_MSC_GetFWVersion 0x0001 + +/* + * get the hardware version from device coded like this 0xHHLLPPRR with + * HH = Software Version High Byte + * LL = Software Version Low Byte + * PP = Further Attributes + * RR = Reserved for the hardware ID + */ +#define SUSBCR_MSC_GetHWVersion 0x0002 diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 2849f8c3201..7aa01b95b1d 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -549,12 +549,9 @@ static void mct_u232_close(struct usb_serial_port *port) { dbg("%s port %d", __func__, port->number); - if (port->serial->dev) { - /* shutdown our urbs */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); + if (port->serial->dev) usb_kill_urb(port->interrupt_in_urb); - } } /* mct_u232_close */ diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h index 7417d5ce1e2..3a3f5e6b8f9 100644 --- a/drivers/usb/serial/mct_u232.h +++ b/drivers/usb/serial/mct_u232.h @@ -42,36 +42,44 @@ #define MCT_U232_SET_REQUEST_TYPE 0x40 #define MCT_U232_GET_REQUEST_TYPE 0xc0 -#define MCT_U232_GET_MODEM_STAT_REQUEST 2 /* Get Modem Status Register (MSR) */ -#define MCT_U232_GET_MODEM_STAT_SIZE 1 +/* Get Modem Status Register (MSR) */ +#define MCT_U232_GET_MODEM_STAT_REQUEST 2 +#define MCT_U232_GET_MODEM_STAT_SIZE 1 -#define MCT_U232_GET_LINE_CTRL_REQUEST 6 /* Get Line Control Register (LCR) */ -#define MCT_U232_GET_LINE_CTRL_SIZE 1 /* ... not used by this driver */ +/* Get Line Control Register (LCR) */ +/* ... not used by this driver */ +#define MCT_U232_GET_LINE_CTRL_REQUEST 6 +#define MCT_U232_GET_LINE_CTRL_SIZE 1 -#define MCT_U232_SET_BAUD_RATE_REQUEST 5 /* Set Baud Rate Divisor */ -#define MCT_U232_SET_BAUD_RATE_SIZE 4 +/* Set Baud Rate Divisor */ +#define MCT_U232_SET_BAUD_RATE_REQUEST 5 +#define MCT_U232_SET_BAUD_RATE_SIZE 4 -#define MCT_U232_SET_LINE_CTRL_REQUEST 7 /* Set Line Control Register (LCR) */ -#define MCT_U232_SET_LINE_CTRL_SIZE 1 +/* Set Line Control Register (LCR) */ +#define MCT_U232_SET_LINE_CTRL_REQUEST 7 +#define MCT_U232_SET_LINE_CTRL_SIZE 1 -#define MCT_U232_SET_MODEM_CTRL_REQUEST 10 /* Set Modem Control Register (MCR) */ -#define MCT_U232_SET_MODEM_CTRL_SIZE 1 +/* Set Modem Control Register (MCR) */ +#define MCT_U232_SET_MODEM_CTRL_REQUEST 10 +#define MCT_U232_SET_MODEM_CTRL_SIZE 1 -/* This USB device request code is not well understood. It is transmitted by - the MCT-supplied Windows driver whenever the baud rate changes. -*/ -#define MCT_U232_SET_UNKNOWN1_REQUEST 11 /* Unknown functionality */ -#define MCT_U232_SET_UNKNOWN1_SIZE 1 +/* + * This USB device request code is not well understood. It is transmitted by + * the MCT-supplied Windows driver whenever the baud rate changes. + */ +#define MCT_U232_SET_UNKNOWN1_REQUEST 11 /* Unknown functionality */ +#define MCT_U232_SET_UNKNOWN1_SIZE 1 -/* This USB device request code appears to control whether CTS is required - during transmission. - - Sending a zero byte allows data transmission to a device which is not - asserting CTS. Sending a '1' byte will cause transmission to be deferred - until the device asserts CTS. -*/ -#define MCT_U232_SET_CTS_REQUEST 12 -#define MCT_U232_SET_CTS_SIZE 1 +/* + * This USB device request code appears to control whether CTS is required + * during transmission. + * + * Sending a zero byte allows data transmission to a device which is not + * asserting CTS. Sending a '1' byte will cause transmission to be deferred + * until the device asserts CTS. + */ +#define MCT_U232_SET_CTS_REQUEST 12 +#define MCT_U232_SET_CTS_SIZE 1 #define MCT_U232_MAX_SIZE 4 /* of MCT_XXX_SIZE */ @@ -81,7 +89,8 @@ * and "Intel solution". They are the regular MCT and "Sitecom" for us. * This is pointless to document in the header, see the code for the bits. */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result); +static int mct_u232_calculate_baud_rate(struct usb_serial *serial, + speed_t value, speed_t *result); /* * Line Control Register (LCR) @@ -125,16 +134,16 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value /* * Line Status Register (LSR) */ -#define MCT_U232_LSR_INDEX 1 /* data[index] */ -#define MCT_U232_LSR_ERR 0x80 /* OE | PE | FE | BI */ -#define MCT_U232_LSR_TEMT 0x40 /* transmit register empty */ -#define MCT_U232_LSR_THRE 0x20 /* transmit holding register empty */ -#define MCT_U232_LSR_BI 0x10 /* break indicator */ -#define MCT_U232_LSR_FE 0x08 /* framing error */ -#define MCT_U232_LSR_OE 0x02 /* overrun error */ -#define MCT_U232_LSR_PE 0x04 /* parity error */ -#define MCT_U232_LSR_OE 0x02 /* overrun error */ -#define MCT_U232_LSR_DR 0x01 /* receive data ready */ +#define MCT_U232_LSR_INDEX 1 /* data[index] */ +#define MCT_U232_LSR_ERR 0x80 /* OE | PE | FE | BI */ +#define MCT_U232_LSR_TEMT 0x40 /* transmit register empty */ +#define MCT_U232_LSR_THRE 0x20 /* transmit holding register empty */ +#define MCT_U232_LSR_BI 0x10 /* break indicator */ +#define MCT_U232_LSR_FE 0x08 /* framing error */ +#define MCT_U232_LSR_OE 0x02 /* overrun error */ +#define MCT_U232_LSR_PE 0x04 /* parity error */ +#define MCT_U232_LSR_OE 0x02 /* overrun error */ +#define MCT_U232_LSR_DR 0x01 /* receive data ready */ /* ----------------------------------------------------------------------------- @@ -143,10 +152,10 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * * The technical details of the device have been acquired be using "SniffUSB" * and the vendor-supplied device driver (version 2.3A) under Windows98. To - * identify the USB vendor-specific requests and to assign them to terminal + * identify the USB vendor-specific requests and to assign them to terminal * settings (flow control, baud rate, etc.) the program "SerialSettings" from * William G. Greathouse has been proven to be very useful. I also used the - * Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and + * Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and * observations are summarized below: * * The USB requests seem to be directly mapped to the registers of a 8250, @@ -186,33 +195,33 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * Data: LCR (see below) * * Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data - * transmit/receive register (THR/RBR) and the Interrupt Enable Register - * (IER) is disabled. Any access to these ports is now redirected to the - * Divisor Latch Registers. Setting this bit, loading the Divisor - * Registers, and clearing DLAB should be done with interrupts disabled. + * transmit/receive register (THR/RBR) and the Interrupt Enable Register + * (IER) is disabled. Any access to these ports is now redirected to the + * Divisor Latch Registers. Setting this bit, loading the Divisor + * Registers, and clearing DLAB should be done with interrupts disabled. * Bit 6: Set Break. When set to "1", the transmitter begins to transmit - * continuous Spacing until this bit is set to "0". This overrides any - * bits of characters that are being transmitted. + * continuous Spacing until this bit is set to "0". This overrides any + * bits of characters that are being transmitted. * Bit 5: Stick Parity. When parity is enabled, setting this bit causes parity - * to always be "1" or "0", based on the value of Bit 4. + * to always be "1" or "0", based on the value of Bit 4. * Bit 4: Even Parity Select (EPS). When parity is enabled and Bit 5 is "0", - * setting this bit causes even parity to be transmitted and expected. - * Otherwise, odd parity is used. + * setting this bit causes even parity to be transmitted and expected. + * Otherwise, odd parity is used. * Bit 3: Parity Enable (PEN). When set to "1", a parity bit is inserted - * between the last bit of the data and the Stop Bit. The UART will also - * expect parity to be present in the received data. + * between the last bit of the data and the Stop Bit. The UART will also + * expect parity to be present in the received data. * Bit 2: Number of Stop Bits (STB). If set to "1" and using 5-bit data words, - * 1.5 Stop Bits are transmitted and expected in each data word. For - * 6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected. - * When this bit is set to "0", one Stop Bit is used on each data word. + * 1.5 Stop Bits are transmitted and expected in each data word. For + * 6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected. + * When this bit is set to "0", one Stop Bit is used on each data word. * Bit 1: Word Length Select Bit #1 (WLSB1) * Bit 0: Word Length Select Bit #0 (WLSB0) - * Together these bits specify the number of bits in each data word. - * 1 0 Word Length - * 0 0 5 Data Bits - * 0 1 6 Data Bits - * 1 0 7 Data Bits - * 1 1 8 Data Bits + * Together these bits specify the number of bits in each data word. + * 1 0 Word Length + * 0 0 5 Data Bits + * 0 1 6 Data Bits + * 1 0 7 Data Bits + * 1 1 8 Data Bits * * SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs * in the Win98 driver: the break does not work (bit 6 is not asserted) and the @@ -234,20 +243,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * Bit 6: Reserved, always 0. * Bit 5: Reserved, always 0. * Bit 4: Loop-Back Enable. When set to "1", the UART transmitter and receiver - * are internally connected together to allow diagnostic operations. In - * addition, the UART modem control outputs are connected to the UART - * modem control inputs. CTS is connected to RTS, DTR is connected to - * DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD. + * are internally connected together to allow diagnostic operations. In + * addition, the UART modem control outputs are connected to the UART + * modem control inputs. CTS is connected to RTS, DTR is connected to + * DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD. * Bit 3: OUT 2. An auxiliary output that the host processor may set high or - * low. In the IBM PC serial adapter (and most clones), OUT 2 is used - * to tri-state (disable) the interrupt signal from the - * 8250/16450/16550 UART. + * low. In the IBM PC serial adapter (and most clones), OUT 2 is used + * to tri-state (disable) the interrupt signal from the + * 8250/16450/16550 UART. * Bit 2: OUT 1. An auxiliary output that the host processor may set high or - * low. This output is not used on the IBM PC serial adapter. + * low. This output is not used on the IBM PC serial adapter. * Bit 1: Request to Send (RTS). When set to "1", the output of the UART -RTS - * line is Low (Active). + * line is Low (Active). * Bit 0: Data Terminal Ready (DTR). When set to "1", the output of the UART - * -DTR line is Low (Active). + * -DTR line is Low (Active). * * SniffUSB observations: Bit 2 and 4 seem not to be used but bit 3 has been * seen _always_ set. @@ -264,22 +273,22 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * Data: MSR (see below) * * Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the - * UART. + * UART. * Bit 6: Ring Indicator (RI). Reflects the state of the RI line on the UART. * Bit 5: Data Set Ready (DSR). Reflects the state of the DSR line on the UART. * Bit 4: Clear To Send (CTS). Reflects the state of the CTS line on the UART. * Bit 3: Delta Data Carrier Detect (DDCD). Set to "1" if the -DCD line has - * changed state one more more times since the last time the MSR was - * read by the host. + * changed state one more more times since the last time the MSR was + * read by the host. * Bit 2: Trailing Edge Ring Indicator (TERI). Set to "1" if the -RI line has - * had a low to high transition since the last time the MSR was read by - * the host. + * had a low to high transition since the last time the MSR was read by + * the host. * Bit 1: Delta Data Set Ready (DDSR). Set to "1" if the -DSR line has changed - * state one more more times since the last time the MSR was read by the - * host. + * state one more more times since the last time the MSR was read by the + * host. * Bit 0: Delta Clear To Send (DCTS). Set to "1" if the -CTS line has changed - * state one more times since the last time the MSR was read by the - * host. + * state one more times since the last time the MSR was read by the + * host. * * SniffUSB observations: the MSR is also returned as first byte on the * interrupt-in endpoint 0x83 to signal changes of modem status lines. The USB @@ -290,31 +299,34 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * -------------------------- * * Bit 7 Error in Receiver FIFO. On the 8250/16450 UART, this bit is zero. - * This bit is set to "1" when any of the bytes in the FIFO have one or - * more of the following error conditions: PE, FE, or BI. + * This bit is set to "1" when any of the bytes in the FIFO have one + * or more of the following error conditions: PE, FE, or BI. * Bit 6 Transmitter Empty (TEMT). When set to "1", there are no words - * remaining in the transmit FIFO or the transmit shift register. The - * transmitter is completely idle. - * Bit 5 Transmitter Holding Register Empty (THRE). When set to "1", the FIFO - * (or holding register) now has room for at least one additional word - * to transmit. The transmitter may still be transmitting when this bit - * is set to "1". + * remaining in the transmit FIFO or the transmit shift register. The + * transmitter is completely idle. + * Bit 5 Transmitter Holding Register Empty (THRE). When set to "1", the + * FIFO (or holding register) now has room for at least one additional + * word to transmit. The transmitter may still be transmitting when + * this bit is set to "1". * Bit 4 Break Interrupt (BI). The receiver has detected a Break signal. - * Bit 3 Framing Error (FE). A Start Bit was detected but the Stop Bit did not - * appear at the expected time. The received word is probably garbled. - * Bit 2 Parity Error (PE). The parity bit was incorrect for the word received. - * Bit 1 Overrun Error (OE). A new word was received and there was no room in - * the receive buffer. The newly-arrived word in the shift register is - * discarded. On 8250/16450 UARTs, the word in the holding register is - * discarded and the newly- arrived word is put in the holding register. + * Bit 3 Framing Error (FE). A Start Bit was detected but the Stop Bit did + * not appear at the expected time. The received word is probably + * garbled. + * Bit 2 Parity Error (PE). The parity bit was incorrect for the word + * received. + * Bit 1 Overrun Error (OE). A new word was received and there was no room + * in the receive buffer. The newly-arrived word in the shift register + * is discarded. On 8250/16450 UARTs, the word in the holding register + * is discarded and the newly- arrived word is put in the holding + * register. * Bit 0 Data Ready (DR). One or more words are in the receive FIFO that the - * host may read. A word must be completely received and moved from the - * shift register into the FIFO (or holding register for 8250/16450 - * designs) before this bit is set. + * host may read. A word must be completely received and moved from + * the shift register into the FIFO (or holding register for + * 8250/16450 designs) before this bit is set. * - * SniffUSB observations: the LSR is returned as second byte on the interrupt-in - * endpoint 0x83 to signal error conditions. Such errors have been seen with - * minicom/zmodem transfers (CRC errors). + * SniffUSB observations: the LSR is returned as second byte on the + * interrupt-in endpoint 0x83 to signal error conditions. Such errors have + * been seen with minicom/zmodem transfers (CRC errors). * * * Unknown #1 @@ -364,16 +376,16 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * -------------- * * SniffUSB observations: the bulk-out endpoint 0x1 and interrupt-in endpoint - * 0x81 is used to transmit and receive characters. The second interrupt-in - * endpoint 0x83 signals exceptional conditions like modem line changes and + * 0x81 is used to transmit and receive characters. The second interrupt-in + * endpoint 0x83 signals exceptional conditions like modem line changes and * errors. The first byte returned is the MSR and the second byte the LSR. * * * Other observations * ------------------ * - * Queued bulk transfers like used in visor.c did not work. - * + * Queued bulk transfers like used in visor.c did not work. + * * * Properties of the USB device used (as found in /var/log/messages) * ----------------------------------------------------------------- @@ -411,26 +423,26 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * bInterface Class:SubClass:Protocol = 00:00:00 * iInterface = 00 * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 81 (in) - * bmAttributes = 03 (Interrupt) - * wMaxPacketSize = 0040 - * bInterval = 02 + * bLength = 7 + * bDescriptorType = 05 + * bEndpointAddress = 81 (in) + * bmAttributes = 03 (Interrupt) + * wMaxPacketSize = 0040 + * bInterval = 02 * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 01 (out) - * bmAttributes = 02 (Bulk) - * wMaxPacketSize = 0040 - * bInterval = 00 + * bLength = 7 + * bDescriptorType = 05 + * bEndpointAddress = 01 (out) + * bmAttributes = 02 (Bulk) + * wMaxPacketSize = 0040 + * bInterval = 00 * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 83 (in) - * bmAttributes = 03 (Interrupt) - * wMaxPacketSize = 0002 - * bInterval = 02 + * bLength = 7 + * bDescriptorType = 05 + * bEndpointAddress = 83 (in) + * bmAttributes = 03 (Interrupt) + * wMaxPacketSize = 0002 + * bInterval = 02 * * * Hardware details (added by Martin Hamilton, 2001/12/06) @@ -440,7 +452,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * adaptor, which turns out to simply be a re-badged U232-P9. We * know this because there is a sticky label on the circuit board * which says "U232-P9" ;-) - * + * * The circuit board inside the adaptor contains a Philips PDIUSBD12 * USB endpoint chip and a Philips P87C52UBAA microcontroller with * embedded UART. Exhaustive documentation for these is available at: @@ -449,7 +461,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value * http://www.semiconductors.philips.com/pip/pdiusbd12 * * Thanks to Julian Highfield for the pointer to the Philips database. - * + * */ #endif /* __LINUX_USB_SERIAL_MCT_U232_H */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 0d47f2c4d59..30922a7e334 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -34,21 +34,18 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/uaccess.h> - +#include <linux/parport.h> /* * Version Information */ -#define DRIVER_VERSION "1.0.0.4F" +#define DRIVER_VERSION "2.1" #define DRIVER_AUTHOR "Aspire Communications pvt Ltd." #define DRIVER_DESC "Moschip USB Serial Driver" /* default urb timeout */ #define MOS_WDR_TIMEOUT (HZ * 5) -#define MOS_PORT1 0x0200 -#define MOS_PORT2 0x0300 -#define MOS_VENREG 0x0000 #define MOS_MAX_PORT 0x02 #define MOS_WRITE 0x0E #define MOS_READ 0x0D @@ -63,7 +60,7 @@ #define NUM_URBS 16 /* URB Count */ #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ -/* This structure holds all of the local port information */ +/* This structure holds all of the local serial port information */ struct moschip_port { __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ @@ -74,11 +71,6 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; }; -/* This structure holds all of the individual serial device information */ -struct moschip_serial { - int interrupt_started; -}; - static int debug; static struct usb_serial_driver moschip7720_2port_driver; @@ -94,6 +86,658 @@ static const struct usb_device_id moschip_port_id_table[] = { }; MODULE_DEVICE_TABLE(usb, moschip_port_id_table); +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + +/* initial values for parport regs */ +#define DCR_INIT_VAL 0x0c /* SLCTIN, nINIT */ +#define ECR_INIT_VAL 0x00 /* SPP mode */ + +struct urbtracker { + struct mos7715_parport *mos_parport; + struct list_head urblist_entry; + struct kref ref_count; + struct urb *urb; +}; + +enum mos7715_pp_modes { + SPP = 0<<5, + PS2 = 1<<5, /* moschip calls this 'NIBBLE' mode */ + PPF = 2<<5, /* moschip calls this 'CB-FIFO mode */ +}; + +struct mos7715_parport { + struct parport *pp; /* back to containing struct */ + struct kref ref_count; /* to instance of this struct */ + struct list_head deferred_urbs; /* list deferred async urbs */ + struct list_head active_urbs; /* list async urbs in flight */ + spinlock_t listlock; /* protects list access */ + bool msg_pending; /* usb sync call pending */ + struct completion syncmsg_compl; /* usb sync call completed */ + struct tasklet_struct urb_tasklet; /* for sending deferred urbs */ + struct usb_serial *serial; /* back to containing struct */ + __u8 shadowECR; /* parallel port regs... */ + __u8 shadowDCR; + atomic_t shadowDSR; /* updated in int-in callback */ +}; + +/* lock guards against dereferencing NULL ptr in parport ops callbacks */ +static DEFINE_SPINLOCK(release_lock); + +#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ + +static const unsigned int dummy; /* for clarity in register access fns */ + +enum mos_regs { + THR, /* serial port regs */ + RHR, + IER, + FCR, + ISR, + LCR, + MCR, + LSR, + MSR, + SPR, + DLL, + DLM, + DPR, /* parallel port regs */ + DSR, + DCR, + ECR, + SP1_REG, /* device control regs */ + SP2_REG, /* serial port 2 (7720 only) */ + PP_REG, + SP_CONTROL_REG, +}; + +/* + * Return the correct value for the Windex field of the setup packet + * for a control endpoint message. See the 7715 datasheet. + */ +static inline __u16 get_reg_index(enum mos_regs reg) +{ + static const __u16 mos7715_index_lookup_table[] = { + 0x00, /* THR */ + 0x00, /* RHR */ + 0x01, /* IER */ + 0x02, /* FCR */ + 0x02, /* ISR */ + 0x03, /* LCR */ + 0x04, /* MCR */ + 0x05, /* LSR */ + 0x06, /* MSR */ + 0x07, /* SPR */ + 0x00, /* DLL */ + 0x01, /* DLM */ + 0x00, /* DPR */ + 0x01, /* DSR */ + 0x02, /* DCR */ + 0x0a, /* ECR */ + 0x01, /* SP1_REG */ + 0x02, /* SP2_REG (7720 only) */ + 0x04, /* PP_REG (7715 only) */ + 0x08, /* SP_CONTROL_REG */ + }; + return mos7715_index_lookup_table[reg]; +} + +/* + * Return the correct value for the upper byte of the Wvalue field of + * the setup packet for a control endpoint message. + */ +static inline __u16 get_reg_value(enum mos_regs reg, + unsigned int serial_portnum) +{ + if (reg >= SP1_REG) /* control reg */ + return 0x0000; + + else if (reg >= DPR) /* parallel port reg (7715 only) */ + return 0x0100; + + else /* serial port reg */ + return (serial_portnum + 2) << 8; +} + +/* + * Write data byte to the specified device register. The data is embedded in + * the value field of the setup packet. serial_portnum is ignored for registers + * not specific to a particular serial port. + */ +static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, + enum mos_regs reg, __u8 data) +{ + struct usb_device *usbdev = serial->dev; + unsigned int pipe = usb_sndctrlpipe(usbdev, 0); + __u8 request = (__u8)0x0e; + __u8 requesttype = (__u8)0x40; + __u16 index = get_reg_index(reg); + __u16 value = get_reg_value(reg, serial_portnum) + data; + int status = usb_control_msg(usbdev, pipe, request, requesttype, value, + index, NULL, 0, MOS_WDR_TIMEOUT); + if (status < 0) + dev_err(&usbdev->dev, + "mos7720: usb_control_msg() failed: %d", status); + return status; +} + +/* + * Read data byte from the specified device register. The data returned by the + * device is embedded in the value field of the setup packet. serial_portnum is + * ignored for registers that are not specific to a particular serial port. + */ +static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, + enum mos_regs reg, __u8 *data) +{ + struct usb_device *usbdev = serial->dev; + unsigned int pipe = usb_rcvctrlpipe(usbdev, 0); + __u8 request = (__u8)0x0d; + __u8 requesttype = (__u8)0xc0; + __u16 index = get_reg_index(reg); + __u16 value = get_reg_value(reg, serial_portnum); + int status = usb_control_msg(usbdev, pipe, request, requesttype, value, + index, data, 1, MOS_WDR_TIMEOUT); + if (status < 0) + dev_err(&usbdev->dev, + "mos7720: usb_control_msg() failed: %d", status); + return status; +} + +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + +static inline int mos7715_change_mode(struct mos7715_parport *mos_parport, + enum mos7715_pp_modes mode) +{ + mos_parport->shadowECR = mode; + write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); + return 0; +} + +static void destroy_mos_parport(struct kref *kref) +{ + struct mos7715_parport *mos_parport = + container_of(kref, struct mos7715_parport, ref_count); + + dbg("%s called", __func__); + kfree(mos_parport); +} + +static void destroy_urbtracker(struct kref *kref) +{ + struct urbtracker *urbtrack = + container_of(kref, struct urbtracker, ref_count); + struct mos7715_parport *mos_parport = urbtrack->mos_parport; + dbg("%s called", __func__); + usb_free_urb(urbtrack->urb); + kfree(urbtrack); + kref_put(&mos_parport->ref_count, destroy_mos_parport); +} + +/* + * This runs as a tasklet when sending an urb in a non-blocking parallel + * port callback had to be deferred because the disconnect mutex could not be + * obtained at the time. + */ +static void send_deferred_urbs(unsigned long _mos_parport) +{ + int ret_val; + unsigned long flags; + struct mos7715_parport *mos_parport = (void *)_mos_parport; + struct urbtracker *urbtrack; + struct list_head *cursor, *next; + + dbg("%s called", __func__); + + /* if release function ran, game over */ + if (unlikely(mos_parport->serial == NULL)) + return; + + /* try again to get the mutex */ + if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { + dbg("%s: rescheduling tasklet", __func__); + tasklet_schedule(&mos_parport->urb_tasklet); + return; + } + + /* if device disconnected, game over */ + if (unlikely(mos_parport->serial->disconnected)) { + mutex_unlock(&mos_parport->serial->disc_mutex); + return; + } + + spin_lock_irqsave(&mos_parport->listlock, flags); + if (list_empty(&mos_parport->deferred_urbs)) { + spin_unlock_irqrestore(&mos_parport->listlock, flags); + mutex_unlock(&mos_parport->serial->disc_mutex); + dbg("%s: deferred_urbs list empty", __func__); + return; + } + + /* move contents of deferred_urbs list to active_urbs list and submit */ + list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) + list_move_tail(cursor, &mos_parport->active_urbs); + list_for_each_entry(urbtrack, &mos_parport->active_urbs, + urblist_entry) { + ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); + dbg("%s: urb submitted", __func__); + if (ret_val) { + dev_err(&mos_parport->serial->dev->dev, + "usb_submit_urb() failed: %d", ret_val); + list_del(&urbtrack->urblist_entry); + kref_put(&urbtrack->ref_count, destroy_urbtracker); + } + } + spin_unlock_irqrestore(&mos_parport->listlock, flags); + mutex_unlock(&mos_parport->serial->disc_mutex); +} + +/* callback for parallel port control urbs submitted asynchronously */ +static void async_complete(struct urb *urb) +{ + struct urbtracker *urbtrack = urb->context; + int status = urb->status; + dbg("%s called", __func__); + if (unlikely(status)) + dbg("%s - nonzero urb status received: %d", __func__, status); + + /* remove the urbtracker from the active_urbs list */ + spin_lock(&urbtrack->mos_parport->listlock); + list_del(&urbtrack->urblist_entry); + spin_unlock(&urbtrack->mos_parport->listlock); + kref_put(&urbtrack->ref_count, destroy_urbtracker); +} + +static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, + enum mos_regs reg, __u8 data) +{ + struct urbtracker *urbtrack; + int ret_val; + unsigned long flags; + struct usb_ctrlrequest setup; + struct usb_serial *serial = mos_parport->serial; + struct usb_device *usbdev = serial->dev; + dbg("%s called", __func__); + + /* create and initialize the control urb and containing urbtracker */ + urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); + if (urbtrack == NULL) { + dev_err(&usbdev->dev, "out of memory"); + return -ENOMEM; + } + kref_get(&mos_parport->ref_count); + urbtrack->mos_parport = mos_parport; + urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urbtrack->urb == NULL) { + dev_err(&usbdev->dev, "out of urbs"); + kfree(urbtrack); + return -ENOMEM; + } + setup.bRequestType = (__u8)0x40; + setup.bRequest = (__u8)0x0e; + setup.wValue = get_reg_value(reg, dummy); + setup.wIndex = get_reg_index(reg); + setup.wLength = 0; + usb_fill_control_urb(urbtrack->urb, usbdev, + usb_sndctrlpipe(usbdev, 0), + (unsigned char *)&setup, + NULL, 0, async_complete, urbtrack); + kref_init(&urbtrack->ref_count); + INIT_LIST_HEAD(&urbtrack->urblist_entry); + + /* + * get the disconnect mutex, or add tracker to the deferred_urbs list + * and schedule a tasklet to try again later + */ + if (!mutex_trylock(&serial->disc_mutex)) { + spin_lock_irqsave(&mos_parport->listlock, flags); + list_add_tail(&urbtrack->urblist_entry, + &mos_parport->deferred_urbs); + spin_unlock_irqrestore(&mos_parport->listlock, flags); + tasklet_schedule(&mos_parport->urb_tasklet); + dbg("tasklet scheduled"); + return 0; + } + + /* bail if device disconnected */ + if (serial->disconnected) { + kref_put(&urbtrack->ref_count, destroy_urbtracker); + mutex_unlock(&serial->disc_mutex); + return -ENODEV; + } + + /* add the tracker to the active_urbs list and submit */ + spin_lock_irqsave(&mos_parport->listlock, flags); + list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs); + spin_unlock_irqrestore(&mos_parport->listlock, flags); + ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); + mutex_unlock(&serial->disc_mutex); + if (ret_val) { + dev_err(&usbdev->dev, + "%s: submit_urb() failed: %d", __func__, ret_val); + spin_lock_irqsave(&mos_parport->listlock, flags); + list_del(&urbtrack->urblist_entry); + spin_unlock_irqrestore(&mos_parport->listlock, flags); + kref_put(&urbtrack->ref_count, destroy_urbtracker); + return ret_val; + } + return 0; +} + +/* + * This is the the common top part of all parallel port callback operations that + * send synchronous messages to the device. This implements convoluted locking + * that avoids two scenarios: (1) a port operation is called after usbserial + * has called our release function, at which point struct mos7715_parport has + * been destroyed, and (2) the device has been disconnected, but usbserial has + * not called the release function yet because someone has a serial port open. + * The shared release_lock prevents the first, and the mutex and disconnected + * flag maintained by usbserial covers the second. We also use the msg_pending + * flag to ensure that all synchronous usb messgage calls have completed before + * our release function can return. + */ +static int parport_prologue(struct parport *pp) +{ + struct mos7715_parport *mos_parport; + + spin_lock(&release_lock); + mos_parport = pp->private_data; + if (unlikely(mos_parport == NULL)) { + /* release fn called, port struct destroyed */ + spin_unlock(&release_lock); + return -1; + } + mos_parport->msg_pending = true; /* synch usb call pending */ + INIT_COMPLETION(mos_parport->syncmsg_compl); + spin_unlock(&release_lock); + + mutex_lock(&mos_parport->serial->disc_mutex); + if (mos_parport->serial->disconnected) { + /* device disconnected */ + mutex_unlock(&mos_parport->serial->disc_mutex); + mos_parport->msg_pending = false; + complete(&mos_parport->syncmsg_compl); + return -1; + } + + return 0; +} + +/* + * This is the the common bottom part of all parallel port functions that send + * synchronous messages to the device. + */ +static inline void parport_epilogue(struct parport *pp) +{ + struct mos7715_parport *mos_parport = pp->private_data; + mutex_unlock(&mos_parport->serial->disc_mutex); + mos_parport->msg_pending = false; + complete(&mos_parport->syncmsg_compl); +} + +static void parport_mos7715_write_data(struct parport *pp, unsigned char d) +{ + struct mos7715_parport *mos_parport = pp->private_data; + dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) + return; + mos7715_change_mode(mos_parport, SPP); + write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d); + parport_epilogue(pp); +} + +static unsigned char parport_mos7715_read_data(struct parport *pp) +{ + struct mos7715_parport *mos_parport = pp->private_data; + unsigned char d; + dbg("%s called", __func__); + if (parport_prologue(pp) < 0) + return 0; + read_mos_reg(mos_parport->serial, dummy, DPR, &d); + parport_epilogue(pp); + return d; +} + +static void parport_mos7715_write_control(struct parport *pp, unsigned char d) +{ + struct mos7715_parport *mos_parport = pp->private_data; + __u8 data; + dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) + return; + data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); + write_mos_reg(mos_parport->serial, dummy, DCR, data); + mos_parport->shadowDCR = data; + parport_epilogue(pp); +} + +static unsigned char parport_mos7715_read_control(struct parport *pp) +{ + struct mos7715_parport *mos_parport = pp->private_data; + __u8 dcr; + dbg("%s called", __func__); + spin_lock(&release_lock); + mos_parport = pp->private_data; + if (unlikely(mos_parport == NULL)) { + spin_unlock(&release_lock); + return 0; + } + dcr = mos_parport->shadowDCR & 0x0f; + spin_unlock(&release_lock); + return dcr; +} + +static unsigned char parport_mos7715_frob_control(struct parport *pp, + unsigned char mask, + unsigned char val) +{ + struct mos7715_parport *mos_parport = pp->private_data; + __u8 dcr; + dbg("%s called", __func__); + mask &= 0x0f; + val &= 0x0f; + if (parport_prologue(pp) < 0) + return 0; + mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val; + write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); + dcr = mos_parport->shadowDCR & 0x0f; + parport_epilogue(pp); + return dcr; +} + +static unsigned char parport_mos7715_read_status(struct parport *pp) +{ + unsigned char status; + struct mos7715_parport *mos_parport = pp->private_data; + dbg("%s called", __func__); + spin_lock(&release_lock); + mos_parport = pp->private_data; + if (unlikely(mos_parport == NULL)) { /* release called */ + spin_unlock(&release_lock); + return 0; + } + status = atomic_read(&mos_parport->shadowDSR) & 0xf8; + spin_unlock(&release_lock); + return status; +} + +static void parport_mos7715_enable_irq(struct parport *pp) +{ + dbg("%s called", __func__); +} +static void parport_mos7715_disable_irq(struct parport *pp) +{ + dbg("%s called", __func__); +} + +static void parport_mos7715_data_forward(struct parport *pp) +{ + struct mos7715_parport *mos_parport = pp->private_data; + dbg("%s called", __func__); + if (parport_prologue(pp) < 0) + return; + mos7715_change_mode(mos_parport, PS2); + mos_parport->shadowDCR &= ~0x20; + write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); + parport_epilogue(pp); +} + +static void parport_mos7715_data_reverse(struct parport *pp) +{ + struct mos7715_parport *mos_parport = pp->private_data; + dbg("%s called", __func__); + if (parport_prologue(pp) < 0) + return; + mos7715_change_mode(mos_parport, PS2); + mos_parport->shadowDCR |= 0x20; + write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); + parport_epilogue(pp); +} + +static void parport_mos7715_init_state(struct pardevice *dev, + struct parport_state *s) +{ + dbg("%s called", __func__); + s->u.pc.ctr = DCR_INIT_VAL; + s->u.pc.ecr = ECR_INIT_VAL; +} + +/* N.B. Parport core code requires that this function not block */ +static void parport_mos7715_save_state(struct parport *pp, + struct parport_state *s) +{ + struct mos7715_parport *mos_parport; + dbg("%s called", __func__); + spin_lock(&release_lock); + mos_parport = pp->private_data; + if (unlikely(mos_parport == NULL)) { /* release called */ + spin_unlock(&release_lock); + return; + } + s->u.pc.ctr = mos_parport->shadowDCR; + s->u.pc.ecr = mos_parport->shadowECR; + spin_unlock(&release_lock); +} + +/* N.B. Parport core code requires that this function not block */ +static void parport_mos7715_restore_state(struct parport *pp, + struct parport_state *s) +{ + struct mos7715_parport *mos_parport; + dbg("%s called", __func__); + spin_lock(&release_lock); + mos_parport = pp->private_data; + if (unlikely(mos_parport == NULL)) { /* release called */ + spin_unlock(&release_lock); + return; + } + write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR); + write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR); + spin_unlock(&release_lock); +} + +static size_t parport_mos7715_write_compat(struct parport *pp, + const void *buffer, + size_t len, int flags) +{ + int retval; + struct mos7715_parport *mos_parport = pp->private_data; + int actual_len; + dbg("%s called: %u chars", __func__, (unsigned int)len); + if (parport_prologue(pp) < 0) + return 0; + mos7715_change_mode(mos_parport, PPF); + retval = usb_bulk_msg(mos_parport->serial->dev, + usb_sndbulkpipe(mos_parport->serial->dev, 2), + (void *)buffer, len, &actual_len, + MOS_WDR_TIMEOUT); + parport_epilogue(pp); + if (retval) { + dev_err(&mos_parport->serial->dev->dev, + "mos7720: usb_bulk_msg() failed: %d", retval); + return 0; + } + return actual_len; +} + +static struct parport_operations parport_mos7715_ops = { + .owner = THIS_MODULE, + .write_data = parport_mos7715_write_data, + .read_data = parport_mos7715_read_data, + + .write_control = parport_mos7715_write_control, + .read_control = parport_mos7715_read_control, + .frob_control = parport_mos7715_frob_control, + + .read_status = parport_mos7715_read_status, + + .enable_irq = parport_mos7715_enable_irq, + .disable_irq = parport_mos7715_disable_irq, + + .data_forward = parport_mos7715_data_forward, + .data_reverse = parport_mos7715_data_reverse, + + .init_state = parport_mos7715_init_state, + .save_state = parport_mos7715_save_state, + .restore_state = parport_mos7715_restore_state, + + .compat_write_data = parport_mos7715_write_compat, + + .nibble_read_data = parport_ieee1284_read_nibble, + .byte_read_data = parport_ieee1284_read_byte, +}; + +/* + * Allocate and initialize parallel port control struct, initialize + * the parallel port hardware device, and register with the parport subsystem. + */ +static int mos7715_parport_init(struct usb_serial *serial) +{ + struct mos7715_parport *mos_parport; + + /* allocate and initialize parallel port control struct */ + mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); + if (mos_parport == NULL) { + dbg("mos7715_parport_init: kzalloc failed"); + return -ENOMEM; + } + mos_parport->msg_pending = false; + kref_init(&mos_parport->ref_count); + spin_lock_init(&mos_parport->listlock); + INIT_LIST_HEAD(&mos_parport->active_urbs); + INIT_LIST_HEAD(&mos_parport->deferred_urbs); + usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ + mos_parport->serial = serial; + tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs, + (unsigned long) mos_parport); + init_completion(&mos_parport->syncmsg_compl); + + /* cycle parallel port reset bit */ + write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80); + write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00); + + /* initialize device registers */ + mos_parport->shadowDCR = DCR_INIT_VAL; + write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); + mos_parport->shadowECR = ECR_INIT_VAL; + write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); + + /* register with parport core */ + mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, + &parport_mos7715_ops); + if (mos_parport->pp == NULL) { + dev_err(&serial->interface->dev, + "Could not register parport\n"); + kref_put(&mos_parport->ref_count, destroy_mos_parport); + return -EIO; + } + mos_parport->pp->private_data = mos_parport; + mos_parport->pp->modes = PARPORT_MODE_COMPAT | PARPORT_MODE_PCSPP; + mos_parport->pp->dev = &serial->interface->dev; + parport_announce_port(mos_parport->pp); + + return 0; +} +#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ /* * mos7720_interrupt_callback @@ -109,8 +753,6 @@ static void mos7720_interrupt_callback(struct urb *urb) __u8 sp1; __u8 sp2; - dbg(" : Entering"); - switch (status) { case 0: /* success */ @@ -161,7 +803,7 @@ static void mos7720_interrupt_callback(struct urb *urb) dbg("Serial Port 1: Receiver time out"); break; case SERIAL_IIR_MS: - dbg("Serial Port 1: Modem status change"); + /* dbg("Serial Port 1: Modem status change"); */ break; } @@ -174,7 +816,7 @@ static void mos7720_interrupt_callback(struct urb *urb) dbg("Serial Port 2: Receiver time out"); break; case SERIAL_IIR_MS: - dbg("Serial Port 2: Modem status change"); + /* dbg("Serial Port 2: Modem status change"); */ break; } } @@ -208,6 +850,7 @@ static void mos7715_interrupt_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: + case -ENODEV: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __func__, status); @@ -243,11 +886,21 @@ static void mos7715_interrupt_callback(struct urb *urb) dbg("Serial Port: Receiver time out"); break; case SERIAL_IIR_MS: - dbg("Serial Port: Modem status change"); + /* dbg("Serial Port: Modem status change"); */ break; } } +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + { /* update local copy of DSR reg */ + struct usb_serial_port *port = urb->context; + struct mos7715_parport *mos_parport = port->serial->private; + if (unlikely(mos_parport == NULL)) + return; + atomic_set(&mos_parport->shadowDSR, data[2]); + } +#endif + exit: result = usb_submit_urb(urb, GFP_ATOMIC); if (result) @@ -267,7 +920,6 @@ static void mos7720_bulk_in_callback(struct urb *urb) int retval; unsigned char *data ; struct usb_serial_port *port; - struct moschip_port *mos7720_port; struct tty_struct *tty; int status = urb->status; @@ -276,13 +928,7 @@ static void mos7720_bulk_in_callback(struct urb *urb) return; } - mos7720_port = urb->context; - if (!mos7720_port) { - dbg("NULL mos7720_port pointer"); - return ; - } - - port = mos7720_port->port; + port = urb->context; dbg("Entering...%s", __func__); @@ -332,8 +978,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) return ; } - dbg("Entering ........."); - tty = tty_port_tty_get(&mos7720_port->port->port); if (tty && mos7720_port->open) @@ -342,56 +986,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) } /* - * send_mos_cmd - * this function will be used for sending command to device - */ -static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, - __u16 index, u8 *data) -{ - int status; - u8 *buf; - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - - if (value < MOS_MAX_PORT) { - if (product == MOSCHIP_DEVICE_ID_7715) - value = 0x0200; /* identifies the 7715's serial port */ - else - value = value*0x100+0x200; - } else { - value = 0x0000; - if ((product == MOSCHIP_DEVICE_ID_7715) && - (index != 0x08)) { - dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); - /* index = 0x01 ; */ - } - } - - if (request == MOS_WRITE) { - value = value + *data; - status = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), MOS_WRITE, - 0x40, value, index, NULL, 0, MOS_WDR_TIMEOUT); - } else { - buf = kmalloc(1, GFP_KERNEL); - if (!buf) { - status = -ENOMEM; - goto out; - } - status = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), MOS_READ, - 0xc0, value, index, buf, 1, MOS_WDR_TIMEOUT); - *data = *buf; - kfree(buf); - } -out: - if (status < 0) - dbg("Command Write failed Value %x index %x", value, index); - - return status; -} - - -/* * mos77xx_probe * this function installs the appropriate read interrupt endpoint callback * depending on whether the device is a 7720 or 7715, thus avoiding costly @@ -424,11 +1018,10 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) struct usb_serial *serial; struct usb_serial_port *port0; struct urb *urb; - struct moschip_serial *mos7720_serial; struct moschip_port *mos7720_port; int response; int port_number; - char data; + __u8 data; int allocated_urbs = 0; int j; @@ -440,11 +1033,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) port0 = serial->port[0]; - mos7720_serial = usb_get_serial_data(serial); - - if (mos7720_serial == NULL || port0 == NULL) - return -ENODEV; - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -489,103 +1077,36 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) * 0x08 : SP1/2 Control Reg */ port_number = port->number - port->serial->minor; - send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); + read_mos_reg(serial, port_number, LSR, &data); + dbg("SS::%p LSR:%x", mos7720_port, data); dbg("Check:Sending Command .........."); - data = 0x02; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); - data = 0x02; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); + write_mos_reg(serial, dummy, SP1_REG, 0x02); + write_mos_reg(serial, dummy, SP2_REG, 0x02); - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + write_mos_reg(serial, port_number, IER, 0x00); + write_mos_reg(serial, port_number, FCR, 0x00); - data = 0xCF; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); - data = 0x03; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); - data = 0x0b; - mos7720_port->shadowMCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - data = 0x0b; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - - data = 0x00; - send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); - -/* data = 0x00; - send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); - data = 0x03; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); - data = 0x00; - send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, - port_number + 1, &data); -*/ - data = 0x00; - send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + write_mos_reg(serial, port_number, FCR, 0xcf); + mos7720_port->shadowLCR = 0x03; + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); + mos7720_port->shadowMCR = 0x0b; + write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); + write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00); + read_mos_reg(serial, dummy, SP_CONTROL_REG, &data); data = data | (port->number - port->serial->minor + 1); - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + write_mos_reg(serial, dummy, SP_CONTROL_REG, data); + mos7720_port->shadowLCR = 0x83; + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); + write_mos_reg(serial, port_number, THR, 0x0c); + write_mos_reg(serial, port_number, IER, 0x00); + mos7720_port->shadowLCR = 0x03; + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); + write_mos_reg(serial, port_number, IER, 0x0c); - data = 0x83; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); - data = 0x0c; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - data = 0x03; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); - data = 0x0c; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - data = 0x0c; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - - /* see if we've set up our endpoint info yet * - * (can't set it up in mos7720_startup as the * - * structures were not set up at that time.) */ - if (!mos7720_serial->interrupt_started) { - dbg("Interrupt buffer NULL !!!"); - - /* not set up yet, so do it now */ - mos7720_serial->interrupt_started = 1; - - dbg("To Submit URB !!!"); - - /* set up our interrupt urb */ - usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, - usb_rcvintpipe(serial->dev, - port->interrupt_in_endpointAddress), - port0->interrupt_in_buffer, - port0->interrupt_in_urb->transfer_buffer_length, - mos7720_interrupt_callback, mos7720_port, - port0->interrupt_in_urb->interval); - - /* start interrupt read for this mos7720 this interrupt * - * will continue as long as the mos7720 is connected */ - dbg("Submit URB over !!!"); - response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); - if (response) - dev_err(&port->dev, - "%s - Error %d submitting control urb\n", - __func__, response); - } - - /* set up our bulk in urb */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->bulk_in_buffer, - port->read_urb->transfer_buffer_length, - mos7720_bulk_in_callback, mos7720_port); response = usb_submit_urb(port->read_urb, GFP_KERNEL); if (response) dev_err(&port->dev, "%s - Error %d submitting read urb\n", @@ -640,7 +1161,6 @@ static void mos7720_close(struct usb_serial_port *port) { struct usb_serial *serial; struct moschip_port *mos7720_port; - char data; int j; dbg("mos7720_close:entering..."); @@ -673,13 +1193,10 @@ static void mos7720_close(struct usb_serial_port *port) /* these commands must not be issued if the device has * been disconnected */ if (!serial->disconnected) { - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, - port->number - port->serial->minor, 0x04, &data); - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, - port->number - port->serial->minor, 0x01, &data); + write_mos_reg(serial, port->number - port->serial->minor, + MCR, 0x00); + write_mos_reg(serial, port->number - port->serial->minor, + IER, 0x00); } mutex_unlock(&serial->disc_mutex); mos7720_port->open = 0; @@ -708,8 +1225,8 @@ static void mos7720_break(struct tty_struct *tty, int break_state) data = mos7720_port->shadowLCR & ~UART_LCR_SBC; mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - 0x03, &data); + write_mos_reg(serial, port->number - port->serial->minor, + LCR, mos7720_port->shadowLCR); return; } @@ -854,9 +1371,8 @@ static void mos7720_throttle(struct tty_struct *tty) /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; - status = send_mos_cmd(port->serial, MOS_WRITE, - port->number - port->serial->minor, - UART_MCR, &mos7720_port->shadowMCR); + write_mos_reg(port->serial, port->number - port->serial->minor, + MCR, mos7720_port->shadowMCR); if (status != 0) return; } @@ -889,22 +1405,21 @@ static void mos7720_unthrottle(struct tty_struct *tty) /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7720_port->shadowMCR |= UART_MCR_RTS; - status = send_mos_cmd(port->serial, MOS_WRITE, - port->number - port->serial->minor, - UART_MCR, &mos7720_port->shadowMCR); + write_mos_reg(port->serial, port->number - port->serial->minor, + MCR, mos7720_port->shadowMCR); if (status != 0) return; } } +/* FIXME: this function does not work */ static int set_higher_rates(struct moschip_port *mos7720_port, unsigned int baud) { - unsigned char data; struct usb_serial_port *port; struct usb_serial *serial; int port_number; - + enum mos_regs sp_reg; if (mos7720_port == NULL) return -EINVAL; @@ -917,58 +1432,35 @@ static int set_higher_rates(struct moschip_port *mos7720_port, dbg("Sending Setting Commands .........."); port_number = port->number - port->serial->minor; - data = 0x000; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - data = 0x000; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); - data = 0x0CF; - send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); - data = 0x00b; - mos7720_port->shadowMCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - data = 0x00b; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - - data = 0x000; - send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); - data = 0x000; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); - + write_mos_reg(serial, port_number, IER, 0x00); + write_mos_reg(serial, port_number, FCR, 0x00); + write_mos_reg(serial, port_number, FCR, 0xcf); + mos7720_port->shadowMCR = 0x0b; + write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); + write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00); /*********************************************** * Set for higher rates * ***********************************************/ - - data = baud * 0x10; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); - - data = 0x003; - send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); - data = 0x003; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); - - data = 0x02b; - mos7720_port->shadowMCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - data = 0x02b; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + /* writing baud rate verbatum into uart clock field clearly not right */ + if (port_number == 0) + sp_reg = SP1_REG; + else + sp_reg = SP2_REG; + write_mos_reg(serial, dummy, sp_reg, baud * 0x10); + write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03); + mos7720_port->shadowMCR = 0x2b; + write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); /*********************************************** * Set DLL/DLM ***********************************************/ - - data = mos7720_port->shadowLCR | UART_LCR_DLAB; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); - - data = 0x001; /* DLL */ - send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); - data = 0x000; /* DLM */ - send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); - - data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); + write_mos_reg(serial, port_number, DLL, 0x01); + write_mos_reg(serial, port_number, DLM, 0x00); + mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); return 0; } @@ -1056,7 +1548,6 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, struct usb_serial *serial; int divisor; int status; - unsigned char data; unsigned char number; if (mos7720_port == NULL) @@ -1078,21 +1569,16 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, } /* Enable access to divisor latch */ - data = mos7720_port->shadowLCR | UART_LCR_DLAB; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); + mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; + write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); /* Write the divisor */ - data = ((unsigned char)(divisor & 0xff)); - send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); - - data = ((unsigned char)((divisor & 0xff00) >> 8)); - send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); + write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff)); + write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8)); /* Disable access to divisor latch */ - data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; - mos7720_port->shadowLCR = data; - send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); + mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); return status; } @@ -1117,7 +1603,6 @@ static void change_port_settings(struct tty_struct *tty, __u8 lStop; int status; int port_number; - char data; if (mos7720_port == NULL) return ; @@ -1196,30 +1681,19 @@ static void change_port_settings(struct tty_struct *tty, /* Update the LCR with the correct value */ mos7720_port->shadowLCR &= - ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); + ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7720_port->shadowLCR |= (lData | lParity | lStop); /* Disable Interrupts */ - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, - UART_IER, &data); - - data = 0x00; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); - - data = 0xcf; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + write_mos_reg(serial, port_number, IER, 0x00); + write_mos_reg(serial, port_number, FCR, 0x00); + write_mos_reg(serial, port_number, FCR, 0xcf); /* Send the updated LCR value to the mos7720 */ - data = mos7720_port->shadowLCR; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); - - data = 0x00b; - mos7720_port->shadowMCR = data; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); - data = 0x00b; - send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); + mos7720_port->shadowMCR = 0x0b; + write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); /* set up the MCR register and send it to the mos7720 */ mos7720_port->shadowMCR = UART_MCR_OUT2; @@ -1230,21 +1704,15 @@ static void change_port_settings(struct tty_struct *tty, mos7720_port->shadowMCR |= (UART_MCR_XONANY); /* To set hardware flow control to the specified * * serial port, in SP1/2_CONTROL_REG */ - if (port->number) { - data = 0x001; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, - 0x08, &data); - } else { - data = 0x002; - send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, - 0x08, &data); - } - } else { + if (port->number) + write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01); + else + write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02); + + } else mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); - } - data = mos7720_port->shadowMCR; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); + write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(tty); @@ -1257,8 +1725,7 @@ static void change_port_settings(struct tty_struct *tty, if (baud >= 230400) { set_higher_rates(mos7720_port, baud); /* Enable Interrupts */ - data = 0x0c; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + write_mos_reg(serial, port_number, IER, 0x0c); return; } @@ -1269,8 +1736,7 @@ static void change_port_settings(struct tty_struct *tty, if (cflag & CBAUD) tty_encode_baud_rate(tty, baud, baud); /* Enable Interrupts */ - data = 0x0c; - send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + write_mos_reg(serial, port_number, IER, 0x0c); if (port->read_urb->status != -EINPROGRESS) { port->read_urb->dev = serial->dev; @@ -1308,7 +1774,7 @@ static void mos7720_set_termios(struct tty_struct *tty, return; } - dbg("setting termios - ASPIRE"); + dbg("%s\n", "setting termios - ASPIRE"); cflag = tty->termios->c_cflag; @@ -1326,7 +1792,7 @@ static void mos7720_set_termios(struct tty_struct *tty, change_port_settings(tty, mos7720_port, old_termios); if (!port->read_urb) { - dbg("URB KILLED !!!!!"); + dbg("%s", "URB KILLED !!!!!"); return; } @@ -1361,8 +1827,7 @@ static int get_lsr_info(struct tty_struct *tty, count = mos7720_chars_in_buffer(tty); if (count == 0) { - send_mos_cmd(port->serial, MOS_READ, port_number, - UART_LSR, &data); + read_mos_reg(port->serial, port_number, LSR, &data); if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) == (UART_LSR_TEMT | UART_LSR_THRE)) { dbg("%s -- Empty", __func__); @@ -1400,13 +1865,11 @@ static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) } static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) + unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port = usb_get_serial_port_data(port); unsigned int mcr ; - unsigned char lmcr; - dbg("%s - port %d", __func__, port->number); dbg("he was at tiocmget"); @@ -1427,10 +1890,8 @@ static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, mcr &= ~UART_MCR_LOOP; mos7720_port->shadowMCR = mcr; - lmcr = mos7720_port->shadowMCR; - - send_mos_cmd(port->serial, MOS_WRITE, - port->number - port->serial->minor, UART_MCR, &lmcr); + write_mos_reg(port->serial, port->number - port->serial->minor, + MCR, mos7720_port->shadowMCR); return 0; } @@ -1440,7 +1901,6 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, { unsigned int mcr ; unsigned int arg; - unsigned char data; struct usb_serial_port *port; @@ -1475,10 +1935,8 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, } mos7720_port->shadowMCR = mcr; - - data = mos7720_port->shadowMCR; - send_mos_cmd(port->serial, MOS_WRITE, - port->number - port->serial->minor, UART_MCR, &data); + write_mos_reg(port->serial, port->number - port->serial->minor, + MCR, mos7720_port->shadowMCR); return 0; } @@ -1590,12 +2048,12 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, static int mos7720_startup(struct usb_serial *serial) { - struct moschip_serial *mos7720_serial; struct moschip_port *mos7720_port; struct usb_device *dev; int i; char data; u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + int ret_val; dbg("%s: Entering ..........", __func__); @@ -1606,15 +2064,6 @@ static int mos7720_startup(struct usb_serial *serial) dev = serial->dev; - /* create our private serial structure */ - mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); - if (mos7720_serial == NULL) { - dev_err(&dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - - usb_set_serial_data(serial, mos7720_serial); - /* * The 7715 uses the first bulk in/out endpoint pair for the parallel * port, and the second for the serial port. Because the usbserial core @@ -1638,16 +2087,12 @@ static int mos7720_startup(struct usb_serial *serial) serial->port[1]->interrupt_in_buffer = NULL; } - /* we set up the pointers to the endpoints in the mos7720_open * - * function, as the structures aren't created yet. */ - /* set up port private structures */ + /* set up serial port private structures */ for (i = 0; i < serial->num_ports; ++i) { mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); if (mos7720_port == NULL) { dev_err(&dev->dev, "%s - Out of memory\n", __func__); - usb_set_serial_data(serial, NULL); - kfree(mos7720_serial); return -ENOMEM; } @@ -1669,12 +2114,22 @@ static int mos7720_startup(struct usb_serial *serial) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); - /* LSR For Port 1 */ - send_mos_cmd(serial, MOS_READ, 0x00, UART_LSR, &data); - dbg("LSR:%x", data); + /* start the interrupt urb */ + ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); + if (ret_val) + dev_err(&dev->dev, + "%s - Error %d submitting control urb\n", + __func__, ret_val); - /* LSR For Port 2 */ - send_mos_cmd(serial, MOS_READ, 0x01, UART_LSR, &data); +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + if (product == MOSCHIP_DEVICE_ID_7715) { + ret_val = mos7715_parport_init(serial); + if (ret_val < 0) + return ret_val; + } +#endif + /* LSR For Port 1 */ + read_mos_reg(serial, 0, LSR, &data); dbg("LSR:%x", data); return 0; @@ -1684,12 +2139,47 @@ static void mos7720_release(struct usb_serial *serial) { int i; +#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT + /* close the parallel port */ + + if (le16_to_cpu(serial->dev->descriptor.idProduct) + == MOSCHIP_DEVICE_ID_7715) { + struct urbtracker *urbtrack; + unsigned long flags; + struct mos7715_parport *mos_parport = + usb_get_serial_data(serial); + + /* prevent NULL ptr dereference in port callbacks */ + spin_lock(&release_lock); + mos_parport->pp->private_data = NULL; + spin_unlock(&release_lock); + + /* wait for synchronous usb calls to return */ + if (mos_parport->msg_pending) + wait_for_completion_timeout(&mos_parport->syncmsg_compl, + MOS_WDR_TIMEOUT); + + parport_remove_port(mos_parport->pp); + usb_set_serial_data(serial, NULL); + mos_parport->serial = NULL; + + /* if tasklet currently scheduled, wait for it to complete */ + tasklet_kill(&mos_parport->urb_tasklet); + + /* unlink any urbs sent by the tasklet */ + spin_lock_irqsave(&mos_parport->listlock, flags); + list_for_each_entry(urbtrack, + &mos_parport->active_urbs, + urblist_entry) + usb_unlink_urb(urbtrack->urb); + spin_unlock_irqrestore(&mos_parport->listlock, flags); + + kref_put(&mos_parport->ref_count, destroy_mos_parport); + } +#endif /* free private structure allocated for serial port */ for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); - - /* free private structure allocated for serial device */ - kfree(usb_get_serial_data(serial)); } static struct usb_driver usb_driver = { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 2fda1c0182b..f8424d1bfc1 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -26,7 +26,6 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ca9d866672a..e280ad8e12f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -42,35 +42,14 @@ #include <linux/bitops.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include "usb-wwan.h" /* Function prototypes */ static int option_probe(struct usb_serial *serial, const struct usb_device_id *id); -static int option_open(struct tty_struct *tty, struct usb_serial_port *port); -static void option_close(struct usb_serial_port *port); -static void option_dtr_rts(struct usb_serial_port *port, int on); - -static int option_startup(struct usb_serial *serial); -static void option_disconnect(struct usb_serial *serial); -static void option_release(struct usb_serial *serial); -static int option_write_room(struct tty_struct *tty); - +static int option_send_setup(struct usb_serial_port *port); static void option_instat_callback(struct urb *urb); -static int option_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int option_chars_in_buffer(struct tty_struct *tty); -static void option_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int option_tiocmget(struct tty_struct *tty, struct file *file); -static int option_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear); -static int option_send_setup(struct usb_serial_port *port); -#ifdef CONFIG_PM -static int option_suspend(struct usb_serial *serial, pm_message_t message); -static int option_resume(struct usb_serial *serial); -#endif - /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 #define OPTION_PRODUCT_COLT 0x5000 @@ -305,6 +284,11 @@ static int option_resume(struct usb_serial *serial); #define ZTE_PRODUCT_CDMA_TECH 0xfffe #define ZTE_PRODUCT_AC8710 0xfff1 #define ZTE_PRODUCT_AC2726 0xfff5 +#define ZTE_PRODUCT_AC8710T 0xffff + +/* ZTE PRODUCTS -- alternate vendor ID */ +#define ZTE_VENDOR_ID2 0x1d6b +#define ZTE_PRODUCT_MF_330 0x0002 #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -373,6 +357,12 @@ static int option_resume(struct usb_serial *serial); #define HAIER_VENDOR_ID 0x201e #define HAIER_PRODUCT_CE100 0x2009 +#define CINTERION_VENDOR_ID 0x0681 + +/* Olivetti products */ +#define OLIVETTI_VENDOR_ID 0x0b3c +#define OLIVETTI_PRODUCT_OLICARD100 0xc000 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -668,6 +658,180 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1060, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1061, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1062, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1063, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1064, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1065, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1066, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1067, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1068, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1069, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1070, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1071, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1072, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1073, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1074, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1075, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1076, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1077, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1078, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1079, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1080, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1081, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1082, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1083, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1084, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1085, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1086, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1087, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1088, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1089, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1090, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1091, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1092, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1093, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1094, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1095, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1096, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1097, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1098, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1099, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1100, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1101, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1102, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1103, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1104, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1105, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1106, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1107, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1108, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1109, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1110, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1111, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1112, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1113, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1114, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1115, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1116, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1117, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1118, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1119, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1120, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1121, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1122, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1123, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1124, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1125, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1126, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1127, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1128, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1129, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1130, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1131, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1132, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1133, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1134, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1135, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1136, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1137, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1138, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1139, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1140, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1141, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1142, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1143, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1144, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1145, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1146, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1147, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1148, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1149, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1150, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1151, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1152, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1153, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1154, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1155, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1156, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1157, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1158, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1159, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1160, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1161, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1162, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1163, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1164, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1165, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1166, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1167, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1168, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1169, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1260, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1261, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1262, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1263, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1264, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1265, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1266, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1274, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1275, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1276, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1279, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1280, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1281, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1282, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1283, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1284, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1285, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1286, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1287, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1288, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1289, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1290, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1291, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1292, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1293, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1294, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1295, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1296, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1297, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, @@ -679,6 +843,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ZTE_VENDOR_ID2, ZTE_PRODUCT_MF_330) }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ @@ -716,6 +882,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, + { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, + + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -747,22 +916,22 @@ static struct usb_serial_driver option_1port_device = { .id_table = option_ids, .num_ports = 1, .probe = option_probe, - .open = option_open, - .close = option_close, - .dtr_rts = option_dtr_rts, - .write = option_write, - .write_room = option_write_room, - .chars_in_buffer = option_chars_in_buffer, - .set_termios = option_set_termios, - .tiocmget = option_tiocmget, - .tiocmset = option_tiocmset, - .attach = option_startup, - .disconnect = option_disconnect, - .release = option_release, + .open = usb_wwan_open, + .close = usb_wwan_close, + .dtr_rts = usb_wwan_dtr_rts, + .write = usb_wwan_write, + .write_room = usb_wwan_write_room, + .chars_in_buffer = usb_wwan_chars_in_buffer, + .set_termios = usb_wwan_set_termios, + .tiocmget = usb_wwan_tiocmget, + .tiocmset = usb_wwan_tiocmset, + .attach = usb_wwan_startup, + .disconnect = usb_wwan_disconnect, + .release = usb_wwan_release, .read_int_callback = option_instat_callback, #ifdef CONFIG_PM - .suspend = option_suspend, - .resume = option_resume, + .suspend = usb_wwan_suspend, + .resume = usb_wwan_resume, #endif }; @@ -775,13 +944,6 @@ static int debug; #define IN_BUFLEN 4096 #define OUT_BUFLEN 4096 -struct option_intf_private { - spinlock_t susp_lock; - unsigned int suspended:1; - int in_flight; - struct option_blacklist_info *blacklist_info; -}; - struct option_port_private { /* Input endpoints and buffer for this port */ struct urb *in_urbs[N_IN_URB]; @@ -838,8 +1000,7 @@ module_exit(option_exit); static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { - struct option_intf_private *data; - + struct usb_wwan_intf_private *data; /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && @@ -852,11 +1013,13 @@ static int option_probe(struct usb_serial *serial, serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) return -ENODEV; - data = serial->private = kzalloc(sizeof(struct option_intf_private), GFP_KERNEL); + data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); + if (!data) return -ENOMEM; + data->send_setup = option_send_setup; spin_lock_init(&data->susp_lock); - data->blacklist_info = (struct option_blacklist_info*) id->driver_info; + data->private = (void *)id->driver_info; return 0; } @@ -877,194 +1040,6 @@ static enum option_blacklist_reason is_blacklisted(const u8 ifnum, return OPTION_BLACKLIST_NONE; } -static void option_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - dbg("%s", __func__); - /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); - option_send_setup(port); -} - -static int option_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int value; - struct option_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - - value = ((portdata->rts_state) ? TIOCM_RTS : 0) | - ((portdata->dtr_state) ? TIOCM_DTR : 0) | - ((portdata->cts_state) ? TIOCM_CTS : 0) | - ((portdata->dsr_state) ? TIOCM_DSR : 0) | - ((portdata->dcd_state) ? TIOCM_CAR : 0) | - ((portdata->ri_state) ? TIOCM_RNG : 0); - - return value; -} - -static int option_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct option_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - - /* FIXME: what locks portdata fields ? */ - if (set & TIOCM_RTS) - portdata->rts_state = 1; - if (set & TIOCM_DTR) - portdata->dtr_state = 1; - - if (clear & TIOCM_RTS) - portdata->rts_state = 0; - if (clear & TIOCM_DTR) - portdata->dtr_state = 0; - return option_send_setup(port); -} - -/* Write */ -static int option_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct option_port_private *portdata; - struct option_intf_private *intfdata; - int i; - int left, todo; - struct urb *this_urb = NULL; /* spurious */ - int err; - unsigned long flags; - - portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; - - dbg("%s: write (%d chars)", __func__, count); - - i = 0; - left = count; - for (i = 0; left > 0 && i < N_OUT_URB; i++) { - todo = left; - if (todo > OUT_BUFLEN) - todo = OUT_BUFLEN; - - this_urb = portdata->out_urbs[i]; - if (test_and_set_bit(i, &portdata->out_busy)) { - if (time_before(jiffies, - portdata->tx_start_time[i] + 10 * HZ)) - continue; - usb_unlink_urb(this_urb); - continue; - } - dbg("%s: endpoint %d buf %d", __func__, - usb_pipeendpoint(this_urb->pipe), i); - - err = usb_autopm_get_interface_async(port->serial->interface); - if (err < 0) - break; - - /* send the data */ - memcpy(this_urb->transfer_buffer, buf, todo); - this_urb->transfer_buffer_length = todo; - - spin_lock_irqsave(&intfdata->susp_lock, flags); - if (intfdata->suspended) { - usb_anchor_urb(this_urb, &portdata->delayed); - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - } else { - intfdata->in_flight++; - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err) { - dbg("usb_submit_urb %p (write bulk) failed " - "(%d)", this_urb, err); - clear_bit(i, &portdata->out_busy); - spin_lock_irqsave(&intfdata->susp_lock, flags); - intfdata->in_flight--; - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - continue; - } - } - - portdata->tx_start_time[i] = jiffies; - buf += todo; - left -= todo; - } - - count -= left; - dbg("%s: wrote (did %d)", __func__, count); - return count; -} - -static void option_indat_callback(struct urb *urb) -{ - int err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s: %p", __func__, urb); - - endpoint = usb_pipeendpoint(urb->pipe); - port = urb->context; - - if (status) { - dbg("%s: nonzero status: %d on endpoint %02x.", - __func__, status, endpoint); - } else { - tty = tty_port_tty_get(&port->port); - if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } else - dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); - - /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err && err != -EPERM) - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - else - usb_mark_last_busy(port->serial->dev); - } - - } - return; -} - -static void option_outdat_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct option_port_private *portdata; - struct option_intf_private *intfdata; - int i; - - dbg("%s", __func__); - - port = urb->context; - intfdata = port->serial->private; - - usb_serial_port_softint(port); - usb_autopm_put_interface_async(port->serial->interface); - portdata = usb_get_serial_port_data(port); - spin_lock(&intfdata->susp_lock); - intfdata->in_flight--; - spin_unlock(&intfdata->susp_lock); - - for (i = 0; i < N_OUT_URB; ++i) { - if (portdata->out_urbs[i] == urb) { - smp_mb__before_clear_bit(); - clear_bit(i, &portdata->out_busy); - break; - } - } -} - static void option_instat_callback(struct urb *urb) { int err; @@ -1121,183 +1096,6 @@ static void option_instat_callback(struct urb *urb) } } -static int option_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct option_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < N_OUT_URB; i++) { - this_urb = portdata->out_urbs[i]; - if (this_urb && !test_bit(i, &portdata->out_busy)) - data_len += OUT_BUFLEN; - } - - dbg("%s: %d", __func__, data_len); - return data_len; -} - -static int option_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct option_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < N_OUT_URB; i++) { - this_urb = portdata->out_urbs[i]; - /* FIXME: This locking is insufficient as this_urb may - go unused during the test */ - if (this_urb && test_bit(i, &portdata->out_busy)) - data_len += this_urb->transfer_buffer_length; - } - dbg("%s: %d", __func__, data_len); - return data_len; -} - -static int option_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct option_port_private *portdata; - struct option_intf_private *intfdata; - struct usb_serial *serial = port->serial; - int i, err; - struct urb *urb; - - portdata = usb_get_serial_port_data(port); - intfdata = serial->private; - - dbg("%s", __func__); - - /* Start reading from the IN endpoint */ - for (i = 0; i < N_IN_URB; i++) { - urb = portdata->in_urbs[i]; - if (!urb) - continue; - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - dbg("%s: submit urb %d failed (%d) %d", - __func__, i, err, - urb->transfer_buffer_length); - } - } - - option_send_setup(port); - - serial->interface->needs_remote_wakeup = 1; - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; - spin_unlock_irq(&intfdata->susp_lock); - usb_autopm_put_interface(serial->interface); - - return 0; -} - -static void option_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_serial *serial = port->serial; - struct option_port_private *portdata; - - dbg("%s", __func__); - portdata = usb_get_serial_port_data(port); - mutex_lock(&serial->disc_mutex); - portdata->rts_state = on; - portdata->dtr_state = on; - if (serial->dev) - option_send_setup(port); - mutex_unlock(&serial->disc_mutex); -} - - -static void option_close(struct usb_serial_port *port) -{ - int i; - struct usb_serial *serial = port->serial; - struct option_port_private *portdata; - struct option_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - portdata = usb_get_serial_port_data(port); - - if (serial->dev) { - /* Stop reading/writing urbs */ - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); - - for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); - for (i = 0; i < N_OUT_URB; i++) - usb_kill_urb(portdata->out_urbs[i]); - usb_autopm_get_interface(serial->interface); - serial->interface->needs_remote_wakeup = 0; - } -} - -/* Helper functions used by option_setup_urbs */ -static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, char *buf, int len, - void (*callback)(struct urb *)) -{ - struct urb *urb; - - if (endpoint == -1) - return NULL; /* endpoint not needed */ - - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); - return NULL; - } - - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); - - return urb; -} - -/* Setup urbs */ -static void option_setup_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct option_port_private *portdata; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* Do indat endpoints first */ - for (j = 0; j < N_IN_URB; ++j) { - portdata->in_urbs[j] = option_setup_urb(serial, - port->bulk_in_endpointAddress, - USB_DIR_IN, port, - portdata->in_buffer[j], - IN_BUFLEN, option_indat_callback); - } - - /* outdat endpoints */ - for (j = 0; j < N_OUT_URB; ++j) { - portdata->out_urbs[j] = option_setup_urb(serial, - port->bulk_out_endpointAddress, - USB_DIR_OUT, port, - portdata->out_buffer[j], - OUT_BUFLEN, option_outdat_callback); - } - } -} - - /** send RTS/DTR state to the port. * * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN @@ -1306,15 +1104,16 @@ static void option_setup_urbs(struct usb_serial *serial) static int option_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - struct option_intf_private *intfdata = - (struct option_intf_private *) serial->private; + struct usb_wwan_intf_private *intfdata = + (struct usb_wwan_intf_private *) serial->private; struct option_port_private *portdata; int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; int val = 0; dbg("%s", __func__); - if (is_blacklisted(ifNum, intfdata->blacklist_info) == - OPTION_BLACKLIST_SENDSETUP) { + if (is_blacklisted(ifNum, + (struct option_blacklist_info *) intfdata->private) + == OPTION_BLACKLIST_SENDSETUP) { dbg("No send_setup on blacklisted interface #%d\n", ifNum); return -EIO; } @@ -1331,224 +1130,6 @@ static int option_send_setup(struct usb_serial_port *port) 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); } -static int option_startup(struct usb_serial *serial) -{ - int i, j, err; - struct usb_serial_port *port; - struct option_port_private *portdata; - u8 *buffer; - - dbg("%s", __func__); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dbg("%s: kmalloc for option_port_private (%d) failed!.", - __func__, i); - return 1; - } - init_usb_anchor(&portdata->delayed); - - for (j = 0; j < N_IN_URB; j++) { - buffer = (u8 *)__get_free_page(GFP_KERNEL); - if (!buffer) - goto bail_out_error; - portdata->in_buffer[j] = buffer; - } - - for (j = 0; j < N_OUT_URB; j++) { - buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); - if (!buffer) - goto bail_out_error2; - portdata->out_buffer[j] = buffer; - } - - usb_set_serial_port_data(port, portdata); - - if (!port->interrupt_in_urb) - continue; - err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (err) - dbg("%s: submit irq_in urb failed %d", - __func__, err); - } - option_setup_urbs(serial); - return 0; - -bail_out_error2: - for (j = 0; j < N_OUT_URB; j++) - kfree(portdata->out_buffer[j]); -bail_out_error: - for (j = 0; j < N_IN_URB; j++) - if (portdata->in_buffer[j]) - free_page((unsigned long)portdata->in_buffer[j]); - kfree(portdata); - return 1; -} - -static void stop_read_write_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct option_port_private *portdata; - - /* Stop reading/writing urbs */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - for (j = 0; j < N_IN_URB; j++) - usb_kill_urb(portdata->in_urbs[j]); - for (j = 0; j < N_OUT_URB; j++) - usb_kill_urb(portdata->out_urbs[j]); - } -} - -static void option_disconnect(struct usb_serial *serial) -{ - dbg("%s", __func__); - - stop_read_write_urbs(serial); -} - -static void option_release(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct option_port_private *portdata; - - dbg("%s", __func__); - - /* Now free them */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - for (j = 0; j < N_IN_URB; j++) { - if (portdata->in_urbs[j]) { - usb_free_urb(portdata->in_urbs[j]); - free_page((unsigned long) - portdata->in_buffer[j]); - portdata->in_urbs[j] = NULL; - } - } - for (j = 0; j < N_OUT_URB; j++) { - if (portdata->out_urbs[j]) { - usb_free_urb(portdata->out_urbs[j]); - kfree(portdata->out_buffer[j]); - portdata->out_urbs[j] = NULL; - } - } - } - - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); - } -} - -#ifdef CONFIG_PM -static int option_suspend(struct usb_serial *serial, pm_message_t message) -{ - struct option_intf_private *intfdata = serial->private; - int b; - - dbg("%s entered", __func__); - - if (message.event & PM_EVENT_AUTO) { - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; - spin_unlock_irq(&intfdata->susp_lock); - - if (b) - return -EBUSY; - } - - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 1; - spin_unlock_irq(&intfdata->susp_lock); - stop_read_write_urbs(serial); - - return 0; -} - -static void play_delayed(struct usb_serial_port *port) -{ - struct option_intf_private *data; - struct option_port_private *portdata; - struct urb *urb; - int err; - - portdata = usb_get_serial_port_data(port); - data = port->serial->private; - while ((urb = usb_get_from_anchor(&portdata->delayed))) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (!err) - data->in_flight++; - } -} - -static int option_resume(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct option_intf_private *intfdata = serial->private; - struct option_port_private *portdata; - struct urb *urb; - int err = 0; - - dbg("%s entered", __func__); - /* get the interrupt URBs resubmitted unconditionally */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - if (!port->interrupt_in_urb) { - dbg("%s: No interrupt URB for port %d", __func__, i); - continue; - } - err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("Submitted interrupt URB for port %d (result %d)", i, err); - if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); - goto err_out; - } - } - - for (i = 0; i < serial->num_ports; i++) { - /* walk all ports */ - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* skip closed ports */ - spin_lock_irq(&intfdata->susp_lock); - if (!portdata->opened) { - spin_unlock_irq(&intfdata->susp_lock); - continue; - } - - for (j = 0; j < N_IN_URB; j++) { - urb = portdata->in_urbs[j]; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); - spin_unlock_irq(&intfdata->susp_lock); - goto err_out; - } - } - play_delayed(port); - spin_unlock_irq(&intfdata->susp_lock); - } - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 0; - spin_unlock_irq(&intfdata->susp_lock); -err_out: - return err; -} -#endif - MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index deeacdea05d..e199b0f4f99 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -51,12 +51,13 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/uaccess.h> +#include <linux/kfifo.h> #include "oti6858.h" #define OTI6858_DESCRIPTION \ "Ours Technology Inc. OTi-6858 USB to serial adapter driver" #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>" -#define OTI6858_VERSION "0.1" +#define OTI6858_VERSION "0.2" static const struct usb_device_id id_table[] = { { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) }, @@ -75,18 +76,6 @@ static struct usb_driver oti6858_driver = { static int debug; - -/* buffering code, copied from pl2303 driver */ -#define PL2303_BUF_SIZE 1024 -#define PL2303_TMP_BUF_SIZE 1024 - -struct oti6858_buf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) #define OTI6858_REQ_T_GET_STATUS 0x01 @@ -161,18 +150,6 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, static int oti6858_startup(struct usb_serial *serial); static void oti6858_release(struct usb_serial *serial); -/* functions operating on buffers */ -static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); -static void oti6858_buf_free(struct oti6858_buf *pb); -static void oti6858_buf_clear(struct oti6858_buf *pb); -static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb); -static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb); -static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, - unsigned int count); -static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, - unsigned int count); - - /* device info */ static struct usb_serial_driver oti6858_device = { .driver = { @@ -201,7 +178,6 @@ static struct usb_serial_driver oti6858_device = { struct oti6858_private { spinlock_t lock; - struct oti6858_buf *buf; struct oti6858_control_pkt status; struct { @@ -295,7 +271,7 @@ static void setup_line(struct work_struct *work) } } -void send_data(struct work_struct *work) +static void send_data(struct work_struct *work) { struct oti6858_private *priv = container_of(work, struct oti6858_private, delayed_write_work.work); @@ -314,9 +290,12 @@ void send_data(struct work_struct *work) return; } priv->flags.write_urb_in_use = 1; - - count = oti6858_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); + + spin_lock_irqsave(&port->lock, flags); + count = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); + if (count > port->bulk_out_size) count = port->bulk_out_size; @@ -350,10 +329,9 @@ void send_data(struct work_struct *work) return; } - spin_lock_irqsave(&priv->lock, flags); - oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count); - spin_unlock_irqrestore(&priv->lock, flags); - + count = kfifo_out_locked(&port->write_fifo, + port->write_urb->transfer_buffer, + count, &port->lock); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; result = usb_submit_urb(port->write_urb, GFP_NOIO); @@ -376,11 +354,6 @@ static int oti6858_startup(struct usb_serial *serial) priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); if (!priv) break; - priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE); - if (priv->buf == NULL) { - kfree(priv); - break; - } spin_lock_init(&priv->lock); init_waitqueue_head(&priv->intr_wait); @@ -397,7 +370,6 @@ static int oti6858_startup(struct usb_serial *serial) for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); - oti6858_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -407,17 +379,12 @@ static int oti6858_startup(struct usb_serial *serial) static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - dbg("%s(port = %d, count = %d)", __func__, port->number, count); if (!count) return count; - spin_lock_irqsave(&priv->lock, flags); - count = oti6858_buf_put(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); + count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); return count; } @@ -425,15 +392,14 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, static int oti6858_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); int room = 0; unsigned long flags; dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); - room = oti6858_buf_space_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); + room = kfifo_avail(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); return room; } @@ -441,15 +407,14 @@ static int oti6858_write_room(struct tty_struct *tty) static int oti6858_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); - chars = oti6858_buf_data_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); + chars = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); return chars; } @@ -640,10 +605,10 @@ static void oti6858_close(struct usb_serial_port *port) dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&port->lock, flags); /* clear out any remaining data in the buffer */ - oti6858_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); dbg("%s(): after buf_clear()", __func__); @@ -785,18 +750,12 @@ static int oti6858_ioctl(struct tty_struct *tty, struct file *file, static void oti6858_release(struct usb_serial *serial) { - struct oti6858_private *priv; int i; dbg("%s()", __func__); - for (i = 0; i < serial->num_ports; ++i) { - priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - oti6858_buf_free(priv->buf); - kfree(priv); - } - } + for (i = 0; i < serial->num_ports; ++i) + kfree(usb_get_serial_port_data(serial->port[i])); } static void oti6858_read_int_callback(struct urb *urb) @@ -889,10 +848,14 @@ static void oti6858_read_int_callback(struct urb *urb) } } else if (!transient) { unsigned long flags; + int count; + + spin_lock_irqsave(&port->lock, flags); + count = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); spin_lock_irqsave(&priv->lock, flags); - if (priv->flags.write_urb_in_use == 0 - && oti6858_buf_data_avail(priv->buf) != 0) { + if (priv->flags.write_urb_in_use == 0 && count != 0) { schedule_delayed_work(&priv->delayed_write_work, 0); resubmit = 0; } @@ -1014,165 +977,6 @@ static void oti6858_write_bulk_callback(struct urb *urb) } } - -/* - * oti6858_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ -static struct oti6858_buf *oti6858_buf_alloc(unsigned int size) -{ - struct oti6858_buf *pb; - - if (size == 0) - return NULL; - - pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL); - if (pb == NULL) - return NULL; - - pb->buf_buf = kmalloc(size, GFP_KERNEL); - if (pb->buf_buf == NULL) { - kfree(pb); - return NULL; - } - - pb->buf_size = size; - pb->buf_get = pb->buf_put = pb->buf_buf; - - return pb; -} - -/* - * oti6858_buf_free - * - * Free the buffer and all associated memory. - */ -static void oti6858_buf_free(struct oti6858_buf *pb) -{ - if (pb) { - kfree(pb->buf_buf); - kfree(pb); - } -} - -/* - * oti6858_buf_clear - * - * Clear out all data in the circular buffer. - */ -static void oti6858_buf_clear(struct oti6858_buf *pb) -{ - if (pb != NULL) { - /* equivalent to a get of all data available */ - pb->buf_get = pb->buf_put; - } -} - -/* - * oti6858_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ -static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; -} - -/* - * oti6858_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ -static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; -} - -/* - * oti6858_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ -static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = oti6858_buf_space_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_put; - if (count > len) { - memcpy(pb->buf_put, buf, len); - memcpy(pb->buf_buf, buf+len, count - len); - pb->buf_put = pb->buf_buf + count - len; - } else { - memcpy(pb->buf_put, buf, count); - if (count < len) - pb->buf_put += count; - else /* count == len */ - pb->buf_put = pb->buf_buf; - } - - return count; -} - -/* - * oti6858_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ -static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = oti6858_buf_data_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_get; - if (count > len) { - memcpy(buf, pb->buf_get, len); - memcpy(buf+len, pb->buf_buf, count - len); - pb->buf_get = pb->buf_buf + count - len; - } else { - memcpy(buf, pb->buf_get, count); - if (count < len) - pb->buf_get += count; - else /* count == len */ - pb->buf_get = pb->buf_buf; - } - - return count; -} - /* module description and (de)initialization */ static int __init oti6858_init(void) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c97a0bb5b6d..6b600182227 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -40,16 +40,6 @@ static int debug; #define PL2303_CLOSING_WAIT (30*HZ) -#define PL2303_BUF_SIZE 1024 -#define PL2303_TMP_BUF_SIZE 1024 - -struct pl2303_buf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, @@ -59,6 +49,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, @@ -156,173 +147,12 @@ enum pl2303_type { struct pl2303_private { spinlock_t lock; - struct pl2303_buf *buf; - int write_urb_in_use; wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; enum pl2303_type type; }; -/* - * pl2303_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ -static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) -{ - struct pl2303_buf *pb; - - if (size == 0) - return NULL; - - pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); - if (pb == NULL) - return NULL; - - pb->buf_buf = kmalloc(size, GFP_KERNEL); - if (pb->buf_buf == NULL) { - kfree(pb); - return NULL; - } - - pb->buf_size = size; - pb->buf_get = pb->buf_put = pb->buf_buf; - - return pb; -} - -/* - * pl2303_buf_free - * - * Free the buffer and all associated memory. - */ -static void pl2303_buf_free(struct pl2303_buf *pb) -{ - if (pb) { - kfree(pb->buf_buf); - kfree(pb); - } -} - -/* - * pl2303_buf_clear - * - * Clear out all data in the circular buffer. - */ -static void pl2303_buf_clear(struct pl2303_buf *pb) -{ - if (pb != NULL) - pb->buf_get = pb->buf_put; - /* equivalent to a get of all data available */ -} - -/* - * pl2303_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ -static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) -{ - if (pb == NULL) - return 0; - - return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; -} - -/* - * pl2303_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ -static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) -{ - if (pb == NULL) - return 0; - - return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; -} - -/* - * pl2303_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ -static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = pl2303_buf_space_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_put; - if (count > len) { - memcpy(pb->buf_put, buf, len); - memcpy(pb->buf_buf, buf+len, count - len); - pb->buf_put = pb->buf_buf + count - len; - } else { - memcpy(pb->buf_put, buf, count); - if (count < len) - pb->buf_put += count; - else /* count == len */ - pb->buf_put = pb->buf_buf; - } - - return count; -} - -/* - * pl2303_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ -static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = pl2303_buf_data_avail(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_get; - if (count > len) { - memcpy(buf, pb->buf_get, len); - memcpy(buf+len, pb->buf_buf, count - len); - pb->buf_get = pb->buf_buf + count - len; - } else { - memcpy(buf, pb->buf_get, count); - if (count < len) - pb->buf_get += count; - else /* count == len */ - pb->buf_get = pb->buf_buf; - } - - return count; -} - static int pl2303_vendor_read(__u16 value, __u16 index, struct usb_serial *serial, unsigned char *buf) { @@ -371,11 +201,6 @@ static int pl2303_startup(struct usb_serial *serial) if (!priv) goto cleanup; spin_lock_init(&priv->lock); - priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); - if (priv->buf == NULL) { - kfree(priv); - goto cleanup; - } init_waitqueue_head(&priv->delta_msr_wait); priv->type = type; usb_set_serial_port_data(serial->port[i], priv); @@ -403,7 +228,6 @@ cleanup: kfree(buf); for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); - pl2303_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } @@ -421,102 +245,6 @@ static int set_control_lines(struct usb_device *dev, u8 value) return retval; } -static void pl2303_send(struct usb_serial_port *port) -{ - int count, result; - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->write_urb_in_use) { - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, - port->bulk_out_size); - - if (count == 0) { - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - - priv->write_urb_in_use = 1; - - spin_unlock_irqrestore(&priv->lock, flags); - - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); - - port->write_urb->transfer_buffer_length = count; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, "%s - failed submitting write urb," - " error %d\n", __func__, result); - priv->write_urb_in_use = 0; - /* TODO: reschedule pl2303_send */ - } - - usb_serial_port_softint(port); -} - -static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d, %d bytes", __func__, port->number, count); - - if (!count) - return count; - - spin_lock_irqsave(&priv->lock, flags); - count = pl2303_buf_put(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); - - pl2303_send(port); - - return count; -} - -static int pl2303_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct pl2303_private *priv = usb_get_serial_port_data(port); - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - room = pl2303_buf_space_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - -static int pl2303_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct pl2303_private *priv = usb_get_serial_port_data(port); - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - chars = pl2303_buf_data_avail(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -728,22 +456,10 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on) static void pl2303_close(struct usb_serial_port *port) { - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); - /* clear out any remaining data in the buffer */ - pl2303_buf_clear(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); - } static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -769,10 +485,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) pl2303_set_termios(tty, port, &tmp_termios); dbg("%s - submitting read urb", __func__); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); if (result) { - dev_err(&port->dev, "%s - failed submitting read urb," - " error %d\n", __func__, result); pl2303_close(port); return -EPROTO; } @@ -952,10 +666,7 @@ static void pl2303_release(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - pl2303_buf_free(priv->buf); - kfree(priv); - } + kfree(priv); } } @@ -1036,13 +747,31 @@ exit: __func__, retval); } -static void pl2303_push_data(struct tty_struct *tty, - struct usb_serial_port *port, struct urb *urb, - u8 line_status) +static void pl2303_process_read_urb(struct urb *urb) { + struct usb_serial_port *port = urb->context; + struct pl2303_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; - /* get tty_flag from status */ char tty_flag = TTY_NORMAL; + unsigned long flags; + u8 line_status; + int i; + + /* update line status */ + spin_lock_irqsave(&priv->lock, flags); + line_status = priv->line_status; + priv->line_status &= ~UART_STATE_TRANSIENT_MASK; + spin_unlock_irqrestore(&priv->lock, flags); + wake_up_interruptible(&priv->delta_msr_wait); + + if (!urb->actual_length) + return; + + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + /* break takes precedence over parity, */ /* which takes precedence over framing errors */ if (line_status & UART_BREAK_ERROR) @@ -1057,107 +786,17 @@ static void pl2303_push_data(struct tty_struct *tty, if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); - if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq)) - tty_insert_flip_string(tty, data, urb->actual_length); - else { - int i; + if (port->port.console && port->sysrq) { for (i = 0; i < urb->actual_length; ++i) if (!usb_serial_handle_sysrq_char(tty, port, data[i])) tty_insert_flip_char(tty, data[i], tty_flag); + } else { + tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + urb->actual_length); } - tty_flip_buffer_push(tty); -} - -static void pl2303_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct pl2303_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned long flags; - int result; - int status = urb->status; - u8 line_status; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - urb status = %d", __func__, status); - if (status == -EPROTO) { - /* PL2303 mysteriously fails with -EPROTO reschedule - * the read */ - dbg("%s - caught -EPROTO, resubmitting the urb", - __func__); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed" - " resubmitting read urb, error %d\n", - __func__, result); - return; - } - dbg("%s - unable to handle the error, exiting.", __func__); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - spin_lock_irqsave(&priv->lock, flags); - line_status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&priv->delta_msr_wait); - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - pl2303_push_data(tty, port, urb, line_status); - } + tty_flip_buffer_push(tty); tty_kref_put(tty); - /* Schedule the next read _if_ we are still open */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result && result != -EPERM) - dev_err(&urb->dev->dev, "%s - failed resubmitting" - " read urb, error %d\n", __func__, result); -} - -static void pl2303_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct pl2303_private *priv = usb_get_serial_port_data(port); - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - priv->write_urb_in_use = 0; - return; - default: - /* error in the urb, so we have to resubmit it */ - dbg("%s - Overflow in write", __func__); - dbg("%s - nonzero write bulk status received: %d", __func__, - status); - port->write_urb->transfer_buffer_length = 1; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, "%s - failed resubmitting write" - " urb, error %d\n", __func__, result); - else - return; - } - - priv->write_urb_in_use = 0; - - /* send any buffered data */ - pl2303_send(port); } /* All of the device info needed for the PL2303 SIO serial converter */ @@ -1169,21 +808,19 @@ static struct usb_serial_driver pl2303_device = { .id_table = id_table, .usb_driver = &pl2303_driver, .num_ports = 1, + .bulk_in_size = 256, + .bulk_out_size = 256, .open = pl2303_open, .close = pl2303_close, .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, - .write = pl2303_write, .ioctl = pl2303_ioctl, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, .tiocmset = pl2303_tiocmset, - .read_bulk_callback = pl2303_read_bulk_callback, + .process_read_urb = pl2303_process_read_urb, .read_int_callback = pl2303_read_int_callback, - .write_bulk_callback = pl2303_write_bulk_callback, - .write_room = pl2303_write_room, - .chars_in_buffer = pl2303_chars_in_buffer, .attach = pl2303_startup, .release = pl2303_release, }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index a352d5f3a59..a871645389d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -5,7 +5,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * */ #define BENQ_VENDOR_ID 0x04a5 @@ -20,6 +20,7 @@ #define PL2303_PRODUCT_ID_ALDIGA 0x0611 #define PL2303_PRODUCT_ID_MMX 0x0612 #define PL2303_PRODUCT_ID_GPRS 0x0609 +#define PL2303_PRODUCT_ID_HCR331 0x331a #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 @@ -136,5 +137,5 @@ #define SANWA_PRODUCT_ID 0x0001 /* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ -#define ADLINK_VENDOR_ID 0x0b63 -#define ADLINK_ND6530_PRODUCT_ID 0x6530 +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 7e3bea23600..214a3e50429 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -50,6 +50,10 @@ #define SANYO_VENDOR_ID 0x0474 #define SANYO_PRODUCT_KATANA_LX 0x0754 /* SCP-3800 (Katana LX) */ +/* Samsung devices */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_U520 0x6640 /* SCH-U520 */ + static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) }, @@ -61,6 +65,7 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 53a2d5a935a..04bb759536b 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -15,6 +15,8 @@ #include <linux/tty_flip.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <linux/slab.h> +#include "usb-wwan.h" #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" @@ -76,6 +78,8 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ + {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ + {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); @@ -92,6 +96,8 @@ static struct usb_driver qcdriver = { static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) { + struct usb_wwan_intf_private *data; + struct usb_host_interface *intf = serial->interface->cur_altsetting; int retval = -ENODEV; __u8 nintf; __u8 ifnum; @@ -100,33 +106,45 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) nintf = serial->dev->actconfig->desc.bNumInterfaces; dbg("Num Interfaces = %d", nintf); - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + ifnum = intf->desc.bInterfaceNumber; dbg("This Interface = %d", ifnum); + data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->susp_lock); + switch (nintf) { case 1: /* QDL mode */ - if (serial->interface->num_altsetting == 2) { - struct usb_host_interface *intf; - + /* Gobi 2000 has a single altsetting, older ones have two */ + if (serial->interface->num_altsetting == 2) intf = &serial->interface->altsetting[1]; - if (intf->desc.bNumEndpoints == 2) { - if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && - usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { - dbg("QDL port found"); - retval = usb_set_interface(serial->dev, ifnum, 1); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - } - return retval; - } + else if (serial->interface->num_altsetting > 2) + break; + + if (intf->desc.bNumEndpoints == 2 && + usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && + usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { + dbg("QDL port found"); + + if (serial->interface->num_altsetting == 1) + return 0; + + retval = usb_set_interface(serial->dev, ifnum, 1); + if (retval < 0) { + dev_err(&serial->dev->dev, + "Could not set interface, error %d\n", + retval); + retval = -ENODEV; } + return retval; } break; + case 3: case 4: /* Composite mode */ if (ifnum == 2) { @@ -161,6 +179,18 @@ static struct usb_serial_driver qcdevice = { .usb_driver = &qcdriver, .num_ports = 1, .probe = qcprobe, + .open = usb_wwan_open, + .close = usb_wwan_close, + .write = usb_wwan_write, + .write_room = usb_wwan_write_room, + .chars_in_buffer = usb_wwan_chars_in_buffer, + .attach = usb_wwan_startup, + .disconnect = usb_wwan_disconnect, + .release = usb_wwan_release, +#ifdef CONFIG_PM + .suspend = usb_wwan_suspend, + .resume = usb_wwan_resume, +#endif }; static int __init qcinit(void) diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 43a0cadd578..a36e2313eed 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -1,6 +1,7 @@ /* * Safe Encapsulated USB Serial Driver * + * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> * Copyright (C) 2001 Lineo * Copyright (C) 2001 Hewlett-Packard * @@ -84,8 +85,8 @@ static int debug; static int safe = 1; static int padded = CONFIG_USB_SERIAL_SAFE_PADDED; -#define DRIVER_VERSION "v0.0b" -#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com" +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB Safe Encapsulated Serial" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -212,191 +213,80 @@ static __u16 __inline__ fcs_compute10(unsigned char *sp, int len, __u16 fcs) return fcs; } -static void safe_read_bulk_callback(struct urb *urb) +static void safe_process_read_urb(struct urb *urb) { - struct usb_serial_port *port = urb->context; + struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; unsigned char length = urb->actual_length; + int actual_length; struct tty_struct *tty; - int result; - int status = urb->status; + __u16 fcs; - dbg("%s", __func__); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); + if (!length) return; - } - dbg("safe_read_bulk_callback length: %d", - port->read_urb->actual_length); -#ifdef ECHO_RCV - { - int i; - unsigned char *cp = port->read_urb->transfer_buffer; - for (i = 0; i < port->read_urb->actual_length; i++) { - if ((i % 32) == 0) - printk("\nru[%02x] ", i); - printk("%02x ", *cp++); - } - printk("\n"); - } -#endif tty = tty_port_tty_get(&port->port); - if (safe) { - __u16 fcs; - fcs = fcs_compute10(data, length, CRC10_INITFCS); - if (!fcs) { - int actual_length = data[length - 2] >> 2; - if (actual_length <= (length - 2)) { - dev_info(&urb->dev->dev, "%s - actual: %d\n", - __func__, actual_length); - tty_insert_flip_string(tty, - data, actual_length); - tty_flip_buffer_push(tty); - } else { - dev_err(&port->dev, - "%s - inconsistent lengths %d:%d\n", - __func__, actual_length, length); - } - } else { - dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); - } - } else { - tty_insert_flip_string(tty, data, length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Continue trying to always read */ - usb_fill_bulk_urb(urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, urb->transfer_buffer_length, - safe_read_bulk_callback, port); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - /* FIXME: Need a mechanism to retry later if this happens */ -} - -static int safe_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - unsigned char *data; - int result; - int i; - int packet_length; - - dbg("safe_write port: %p %d urb: %p count: %d", - port, port->number, port->write_urb, count); - - if (!port->write_urb) { - dbg("%s - write urb NULL", __func__); - return 0; - } - - dbg("safe_write write_urb: %d transfer_buffer_length", - port->write_urb->transfer_buffer_length); - - if (!port->write_urb->transfer_buffer_length) { - dbg("%s - write urb transfer_buffer_length zero", __func__); - return 0; - } - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - spin_lock_bh(&port->lock); - if (port->write_urb_busy) { - spin_unlock_bh(&port->lock); - dbg("%s - already writing", __func__); - return 0; - } - port->write_urb_busy = 1; - spin_unlock_bh(&port->lock); - - packet_length = port->bulk_out_size; /* get max packetsize */ - - i = packet_length - (safe ? 2 : 0); /* get bytes to send */ - count = (count > i) ? i : count; - - - /* get the data into the transfer buffer */ - data = port->write_urb->transfer_buffer; - memset(data, '0', packet_length); - - memcpy(data, buf, count); - - if (safe) { - __u16 fcs; - - /* pad if necessary */ - if (!padded) - packet_length = count + 2; - /* set count */ - data[packet_length - 2] = count << 2; - data[packet_length - 1] = 0; + if (!tty) + return; - /* compute fcs and insert into trailer */ - fcs = fcs_compute10(data, packet_length, CRC10_INITFCS); - data[packet_length - 2] |= fcs >> 8; - data[packet_length - 1] |= fcs & 0xff; + if (!safe) + goto out; - /* set length to send */ - port->write_urb->transfer_buffer_length = packet_length; - } else { - port->write_urb->transfer_buffer_length = count; + fcs = fcs_compute10(data, length, CRC10_INITFCS); + if (fcs) { + dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); + goto err; } - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); -#ifdef ECHO_TX - { - int i; - unsigned char *cp = port->write_urb->transfer_buffer; - for (i = 0; i < port->write_urb->transfer_buffer_length; i++) { - if ((i % 32) == 0) - printk("\nsu[%02x] ", i); - printk("%02x ", *cp++); - } - printk("\n"); - } -#endif - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_KERNEL); - if (result) { - port->write_urb_busy = 0; - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - return 0; + actual_length = data[length - 2] >> 2; + if (actual_length > (length - 2)) { + dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n", + __func__, actual_length, length); + goto err; } - dbg("%s urb: %p submitted", __func__, port->write_urb); - - return count; + dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length); + length = actual_length; +out: + tty_insert_flip_string(tty, data, length); + tty_flip_buffer_push(tty); +err: + tty_kref_put(tty); } -static int safe_write_room(struct tty_struct *tty) +static int safe_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) { - struct usb_serial_port *port = tty->driver_data; - int room = 0; /* Default: no room */ - unsigned long flags; + unsigned char *buf = dest; + int count; + int trailer_len; + int pkt_len; + __u16 fcs; + + trailer_len = safe ? 2 : 0; + + count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len, + &port->lock); + if (!safe) + return count; + + /* pad if necessary */ + if (padded) { + pkt_len = size; + memset(buf + count, '0', pkt_len - count - trailer_len); + } else { + pkt_len = count + trailer_len; + } - dbg("%s", __func__); + /* set count */ + buf[pkt_len - 2] = count << 2; + buf[pkt_len - 1] = 0; - spin_lock_irqsave(&port->lock, flags); - if (port->write_urb_busy) - room = port->bulk_out_size - (safe ? 2 : 0); - spin_unlock_irqrestore(&port->lock, flags); + /* compute fcs and insert into trailer */ + fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS); + buf[pkt_len - 2] |= fcs >> 8; + buf[pkt_len - 1] |= fcs & 0xff; - if (room) - dbg("safe_write_room returns %d", room); - return room; + return pkt_len; } static int safe_startup(struct usb_serial *serial) @@ -421,9 +311,8 @@ static struct usb_serial_driver safe_device = { .id_table = id_table, .usb_driver = &safe_driver, .num_ports = 1, - .write = safe_write, - .write_room = safe_write_room, - .read_bulk_callback = safe_read_bulk_callback, + .process_read_urb = safe_process_read_urb, + .prepare_write_buffer = safe_prepare_write_buffer, .attach = safe_startup, }; diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 5d39191e724..329d311a35d 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -1,6 +1,7 @@ /* * spcp8x5 USB to serial adaptor driver * + * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) * Copyright (C) 2006 S1 Corp. * @@ -29,7 +30,7 @@ /* Version Information */ -#define DRIVER_VERSION "v0.04" +#define DRIVER_VERSION "v0.10" #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" static int debug; @@ -64,11 +65,6 @@ struct spcp8x5_usb_ctrl_arg { u16 length; }; -/* wait 30s before close */ -#define SPCP8x5_CLOSING_WAIT (30*HZ) - -#define SPCP8x5_BUF_SIZE 1024 - /* spcp8x5 spec register define */ #define MCR_CONTROL_LINE_RTS 0x02 @@ -155,133 +151,6 @@ enum spcp8x5_type { SPCP835_TYPE, }; -/* 1st in 1st out buffer 4 driver */ -struct ringbuf { - unsigned int buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - -/* alloc the ring buf and alloc the buffer itself */ -static inline struct ringbuf *alloc_ringbuf(unsigned int size) -{ - struct ringbuf *pb; - - if (size == 0) - return NULL; - - pb = kmalloc(sizeof(*pb), GFP_KERNEL); - if (pb == NULL) - return NULL; - - pb->buf_buf = kmalloc(size, GFP_KERNEL); - if (pb->buf_buf == NULL) { - kfree(pb); - return NULL; - } - - pb->buf_size = size; - pb->buf_get = pb->buf_put = pb->buf_buf; - - return pb; -} - -/* free the ring buf and the buffer itself */ -static inline void free_ringbuf(struct ringbuf *pb) -{ - if (pb != NULL) { - kfree(pb->buf_buf); - kfree(pb); - } -} - -/* clear pipo , juest repoint the pointer here */ -static inline void clear_ringbuf(struct ringbuf *pb) -{ - if (pb != NULL) - pb->buf_get = pb->buf_put; -} - -/* get the number of data in the pipo */ -static inline unsigned int ringbuf_avail_data(struct ringbuf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; -} - -/* get the number of space in the pipo */ -static inline unsigned int ringbuf_avail_space(struct ringbuf *pb) -{ - if (pb == NULL) - return 0; - return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; -} - -/* put count data into pipo */ -static unsigned int put_ringbuf(struct ringbuf *pb, const char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL) - return 0; - - len = ringbuf_avail_space(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_put; - if (count > len) { - memcpy(pb->buf_put, buf, len); - memcpy(pb->buf_buf, buf+len, count - len); - pb->buf_put = pb->buf_buf + count - len; - } else { - memcpy(pb->buf_put, buf, count); - if (count < len) - pb->buf_put += count; - else /* count == len */ - pb->buf_put = pb->buf_buf; - } - return count; -} - -/* get count data from pipo */ -static unsigned int get_ringbuf(struct ringbuf *pb, char *buf, - unsigned int count) -{ - unsigned int len; - - if (pb == NULL || buf == NULL) - return 0; - - len = ringbuf_avail_data(pb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = pb->buf_buf + pb->buf_size - pb->buf_get; - if (count > len) { - memcpy(buf, pb->buf_get, len); - memcpy(buf+len, pb->buf_buf, count - len); - pb->buf_get = pb->buf_buf + count - len; - } else { - memcpy(buf, pb->buf_get, count); - if (count < len) - pb->buf_get += count; - else /* count == len */ - pb->buf_get = pb->buf_buf; - } - - return count; -} - static struct usb_driver spcp8x5_driver = { .name = "spcp8x5", .probe = usb_serial_probe, @@ -293,8 +162,6 @@ static struct usb_driver spcp8x5_driver = { struct spcp8x5_private { spinlock_t lock; - struct ringbuf *buf; - int write_urb_in_use; enum spcp8x5_type type; wait_queue_head_t delta_msr_wait; u8 line_control; @@ -330,24 +197,15 @@ static int spcp8x5_startup(struct usb_serial *serial) goto cleanup; spin_lock_init(&priv->lock); - priv->buf = alloc_ringbuf(SPCP8x5_BUF_SIZE); - if (priv->buf == NULL) - goto cleanup2; - init_waitqueue_head(&priv->delta_msr_wait); priv->type = type; usb_set_serial_port_data(serial->port[i] , priv); - } return 0; - -cleanup2: - kfree(priv); cleanup: for (--i; i >= 0; --i) { priv = usb_get_serial_port_data(serial->port[i]); - free_ringbuf(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i] , NULL); } @@ -358,15 +216,9 @@ cleanup: static void spcp8x5_release(struct usb_serial *serial) { int i; - struct spcp8x5_private *priv; - for (i = 0; i < serial->num_ports; i++) { - priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - free_ringbuf(priv->buf); - kfree(priv); - } - } + for (i = 0; i < serial->num_ports; i++) + kfree(usb_get_serial_port_data(serial->port[i])); } /* set the modem control line of the device. @@ -470,33 +322,6 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); } -/* close the serial port. We should wait for data sending to device 1st and - * then kill all urb. */ -static void spcp8x5_close(struct usb_serial_port *port) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int result; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - /* clear out any remaining data in the buffer */ - clear_ringbuf(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - /* kill urb */ - if (port->write_urb != NULL) { - result = usb_unlink_urb(port->write_urb); - if (result) - dev_dbg(&port->dev, - "usb_unlink_urb(write_urb) = %d\n", result); - } - result = usb_unlink_urb(port->read_urb); - if (result) - dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result); -} - static void spcp8x5_init_termios(struct tty_struct *tty) { /* for the 1st time call this function */ @@ -620,7 +445,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, } /* open the serial port. do some usb system call. set termios and get the line - * status of the device. then submit the read urb */ + * status of the device. */ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) { struct ktermios tmp_termios; @@ -655,52 +480,21 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) priv->line_status = status & 0xf0 ; spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - submitting read urb", __func__); - port->read_urb->dev = serial->dev; - ret = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (ret) { - spcp8x5_close(port); - return -EPROTO; - } port->port.drain_delay = 256; - return 0; + + return usb_serial_generic_open(tty, port); } -/* bulk read call back function. check the status of the urb. if transfer - * failed return. then update the status and the tty send data to tty subsys. - * submit urb again. - */ -static void spcp8x5_read_bulk_callback(struct urb *urb) +static void spcp8x5_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct spcp8x5_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; - int result = urb->status; u8 status; char tty_flag; - dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,", - result, urb->actual_length); - - /* check the urb status */ - if (result) { - if (result == -EPROTO) { - /* spcp8x5 mysteriously fails with -EPROTO */ - /* reschedule the read */ - urb->dev = port->serial->dev; - result = usb_submit_urb(urb , GFP_ATOMIC); - if (result) - dev_dbg(&port->dev, - "failed submitting read urb %d\n", - result); - return; - } - dev_dbg(&port->dev, "unable to handle the error, exiting.\n"); - return; - } - /* get tty_flag from status */ tty_flag = TTY_NORMAL; @@ -711,141 +505,33 @@ static void spcp8x5_read_bulk_callback(struct urb *urb) /* wake up the wait for termios */ wake_up_interruptible(&priv->delta_msr_wait); - /* break takes precedence over parity, which takes precedence over - * framing errors */ - if (status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - tty_insert_flip_string_fixed_flag(tty, data, - urb->actual_length, tty_flag); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Schedule the next read */ - urb->dev = port->serial->dev; - result = usb_submit_urb(urb , GFP_ATOMIC); - if (result) - dev_dbg(&port->dev, "failed submitting read urb %d\n", result); -} - -/* get data from ring buffer and then write to usb bus */ -static void spcp8x5_send(struct usb_serial_port *port) -{ - int count, result; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->write_urb_in_use) { - dev_dbg(&port->dev, "write urb still used\n"); - spin_unlock_irqrestore(&priv->lock, flags); + if (!urb->actual_length) return; - } - - /* send the 1st urb for writting */ - memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size); - count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer, - port->bulk_out_size); - if (count == 0) { - spin_unlock_irqrestore(&priv->lock, flags); + tty = tty_port_tty_get(&port->port); + if (!tty) return; - } - - /* update the urb status */ - priv->write_urb_in_use = 1; - - spin_unlock_irqrestore(&priv->lock, flags); - - port->write_urb->transfer_buffer_length = count; - port->write_urb->dev = port->serial->dev; - - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_dbg(&port->dev, "failed submitting write urb, error %d\n", - result); - priv->write_urb_in_use = 0; - /* TODO: reschedule spcp8x5_send */ - } - - - schedule_work(&port->work); -} -/* this is the call back function for write urb. NOTE we should not sleep in - * this routine. check the urb return code and then submit the write urb again - * to hold the write loop */ -static void spcp8x5_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - int result; - int status = urb->status; + if (status & UART_STATE_TRANSIENT_MASK) { + /* break takes precedence over parity, which takes precedence + * over framing errors */ + if (status & UART_BREAK_ERROR) + tty_flag = TTY_BREAK; + else if (status & UART_PARITY_ERROR) + tty_flag = TTY_PARITY; + else if (status & UART_FRAME_ERROR) + tty_flag = TTY_FRAME; + dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(&port->dev, "urb shutting down with status: %d\n", - status); - priv->write_urb_in_use = 0; - return; - default: - /* error in the urb, so we have to resubmit it */ - dbg("%s - Overflow in write", __func__); - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - port->write_urb->transfer_buffer_length = 1; - port->write_urb->dev = port->serial->dev; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - dev_dbg(&port->dev, - "failed resubmitting write urb %d\n", result); - else - return; + /* overrun is special, not associated with a char */ + if (status & UART_OVERRUN_ERROR) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); } - priv->write_urb_in_use = 0; - - /* send any buffered data */ - spcp8x5_send(port); -} - -/* write data to ring buffer. and then start the write transfer */ -static int spcp8x5_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dev_dbg(&port->dev, "%d bytes\n", count); - - if (!count) - return count; - - spin_lock_irqsave(&priv->lock, flags); - count = put_ringbuf(priv->buf, buf, count); - spin_unlock_irqrestore(&priv->lock, flags); - - spcp8x5_send(port); - - return count; + tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + urb->actual_length); + tty_flip_buffer_push(tty); + tty_kref_put(tty); } static int spcp8x5_wait_modem_info(struct usb_serial_port *port, @@ -953,36 +639,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty, struct file *file) return result; } -/* get the avail space room in ring buffer */ -static int spcp8x5_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - int room = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - room = ringbuf_avail_space(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - return room; -} - -/* get the number of avail data in write ring buffer */ -static int spcp8x5_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - int chars = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - chars = ringbuf_avail_data(priv->buf); - spin_unlock_irqrestore(&priv->lock, flags); - - return chars; -} - /* All of the device info needed for the spcp8x5 SIO serial converter */ static struct usb_serial_driver spcp8x5_device = { .driver = { @@ -992,21 +648,16 @@ static struct usb_serial_driver spcp8x5_device = { .id_table = id_table, .num_ports = 1, .open = spcp8x5_open, - .close = spcp8x5_close, .dtr_rts = spcp8x5_dtr_rts, .carrier_raised = spcp8x5_carrier_raised, - .write = spcp8x5_write, .set_termios = spcp8x5_set_termios, .init_termios = spcp8x5_init_termios, .ioctl = spcp8x5_ioctl, .tiocmget = spcp8x5_tiocmget, .tiocmset = spcp8x5_tiocmset, - .write_room = spcp8x5_write_room, - .read_bulk_callback = spcp8x5_read_bulk_callback, - .write_bulk_callback = spcp8x5_write_bulk_callback, - .chars_in_buffer = spcp8x5_chars_in_buffer, .attach = spcp8x5_startup, .release = spcp8x5_release, + .process_read_urb = spcp8x5_process_read_urb, }; static int __init spcp8x5_init(void) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 880e990abb0..90979a1f531 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -30,7 +30,7 @@ #include <linux/spinlock.h> #include <linux/ioctl.h> #include <linux/serial.h> -#include <linux/circ_buf.h> +#include <linux/kfifo.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/usb.h> @@ -40,7 +40,7 @@ /* Defines */ -#define TI_DRIVER_VERSION "v0.9" +#define TI_DRIVER_VERSION "v0.10" #define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>" #define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" @@ -82,7 +82,7 @@ struct ti_port { spinlock_t tp_lock; int tp_read_urb_state; int tp_write_urb_in_use; - struct circ_buf *tp_write_buf; + struct kfifo write_fifo; }; struct ti_device { @@ -144,15 +144,6 @@ static int ti_write_byte(struct ti_device *tdev, unsigned long addr, static int ti_download_firmware(struct ti_device *tdev); -/* circular buffer */ -static struct circ_buf *ti_buf_alloc(void); -static void ti_buf_free(struct circ_buf *cb); -static void ti_buf_clear(struct circ_buf *cb); -static int ti_buf_data_avail(struct circ_buf *cb); -static int ti_buf_space_avail(struct circ_buf *cb); -static int ti_buf_put(struct circ_buf *cb, const char *buf, int count); -static int ti_buf_get(struct circ_buf *cb, char *buf, int count); - /* Data */ @@ -450,8 +441,8 @@ static int ti_startup(struct usb_serial *serial) tport->tp_closing_wait = closing_wait; init_waitqueue_head(&tport->tp_msr_wait); init_waitqueue_head(&tport->tp_write_wait); - tport->tp_write_buf = ti_buf_alloc(); - if (tport->tp_write_buf == NULL) { + if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, + GFP_KERNEL)) { dev_err(&dev->dev, "%s - out of memory\n", __func__); kfree(tport); status = -ENOMEM; @@ -468,7 +459,7 @@ static int ti_startup(struct usb_serial *serial) free_tports: for (--i; i >= 0; --i) { tport = usb_get_serial_port_data(serial->port[i]); - ti_buf_free(tport->tp_write_buf); + kfifo_free(&tport->write_fifo); kfree(tport); usb_set_serial_port_data(serial->port[i], NULL); } @@ -490,7 +481,7 @@ static void ti_release(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { tport = usb_get_serial_port_data(serial->port[i]); if (tport) { - ti_buf_free(tport->tp_write_buf); + kfifo_free(&tport->write_fifo); kfree(tport); } } @@ -701,7 +692,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count) { struct ti_port *tport = usb_get_serial_port_data(port); - unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -713,10 +703,8 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, if (tport == NULL || !tport->tp_is_open) return -ENODEV; - spin_lock_irqsave(&tport->tp_lock, flags); - count = ti_buf_put(tport->tp_write_buf, data, count); - spin_unlock_irqrestore(&tport->tp_lock, flags); - + count = kfifo_in_locked(&tport->write_fifo, data, count, + &tport->tp_lock); ti_send(tport); return count; @@ -736,7 +724,7 @@ static int ti_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - room = ti_buf_space_avail(tport->tp_write_buf); + room = kfifo_avail(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); dbg("%s - returns %d", __func__, room); @@ -757,7 +745,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - chars = ti_buf_data_avail(tport->tp_write_buf); + chars = kfifo_len(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); dbg("%s - returns %d", __func__, chars); @@ -1309,7 +1297,7 @@ static void ti_send(struct ti_port *tport) if (tport->tp_write_urb_in_use) goto unlock; - count = ti_buf_get(tport->tp_write_buf, + count = kfifo_out(&tport->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -1504,7 +1492,7 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) add_wait_queue(&tport->tp_write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (ti_buf_data_avail(tport->tp_write_buf) == 0 + if (kfifo_len(&tport->write_fifo) == 0 || timeout == 0 || signal_pending(current) || tdev->td_urb_error || port->serial->disconnected) /* disconnect */ @@ -1518,7 +1506,7 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) /* flush any remaining data in the buffer */ if (flush) - ti_buf_clear(tport->tp_write_buf); + kfifo_reset_out(&tport->write_fifo); spin_unlock_irq(&tport->tp_lock); @@ -1735,7 +1723,7 @@ static int ti_download_firmware(struct ti_device *tdev) return -ENOENT; } if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { - dev_err(&dev->dev, "%s - firmware too large %d \n", __func__, fw_p->size); + dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); return -ENOENT; } @@ -1761,142 +1749,3 @@ static int ti_download_firmware(struct ti_device *tdev) return 0; } - - -/* Circular Buffer Functions */ - -/* - * ti_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ - -static struct circ_buf *ti_buf_alloc(void) -{ - struct circ_buf *cb; - - cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL); - if (cb == NULL) - return NULL; - - cb->buf = kmalloc(TI_WRITE_BUF_SIZE, GFP_KERNEL); - if (cb->buf == NULL) { - kfree(cb); - return NULL; - } - - ti_buf_clear(cb); - - return cb; -} - - -/* - * ti_buf_free - * - * Free the buffer and all associated memory. - */ - -static void ti_buf_free(struct circ_buf *cb) -{ - kfree(cb->buf); - kfree(cb); -} - - -/* - * ti_buf_clear - * - * Clear out all data in the circular buffer. - */ - -static void ti_buf_clear(struct circ_buf *cb) -{ - cb->head = cb->tail = 0; -} - - -/* - * ti_buf_data_avail - * - * Return the number of bytes of data available in the circular - * buffer. - */ - -static int ti_buf_data_avail(struct circ_buf *cb) -{ - return CIRC_CNT(cb->head, cb->tail, TI_WRITE_BUF_SIZE); -} - - -/* - * ti_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ - -static int ti_buf_space_avail(struct circ_buf *cb) -{ - return CIRC_SPACE(cb->head, cb->tail, TI_WRITE_BUF_SIZE); -} - - -/* - * ti_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ - -static int ti_buf_put(struct circ_buf *cb, const char *buf, int count) -{ - int c, ret = 0; - - while (1) { - c = CIRC_SPACE_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(cb->buf + cb->head, buf, c); - cb->head = (cb->head + c) & (TI_WRITE_BUF_SIZE-1); - buf += c; - count -= c; - ret += c; - } - - return ret; -} - - -/* - * ti_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ - -static int ti_buf_get(struct circ_buf *cb, char *buf, int count) -{ - int c, ret = 0; - - while (1) { - c = CIRC_CNT_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(buf, cb->buf + cb->tail, c); - cb->tail = (cb->tail + c) & (TI_WRITE_BUF_SIZE-1); - buf += c; - count -= c; - ret += c; - } - - return ret; -} diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 3873660d821..941c2d409f8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -289,7 +289,7 @@ static void serial_down(struct tty_port *tport) * The console is magical. Do not hang up the console hardware * or there will be tears. */ - if (port->console) + if (port->port.console) return; if (drv->close) drv->close(port); @@ -328,7 +328,7 @@ static void serial_cleanup(struct tty_struct *tty) /* The console is magical. Do not hang up the console hardware * or there will be tears. */ - if (port->console) + if (port->port.console) return; dbg("%s - port %d", __func__, port->number); @@ -548,8 +548,12 @@ static void usb_serial_port_work(struct work_struct *work) static void kill_traffic(struct usb_serial_port *port) { + int i; + usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_kill_urb(port->write_urbs[i]); /* * This is tricky. * Some drivers submit the read_urb in the @@ -568,6 +572,7 @@ static void kill_traffic(struct usb_serial_port *port) static void port_release(struct device *dev) { struct usb_serial_port *port = to_usb_serial_port(dev); + int i; dbg ("%s - %s", __func__, dev_name(dev)); @@ -582,6 +587,10 @@ static void port_release(struct device *dev) usb_free_urb(port->write_urb); usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { + usb_free_urb(port->write_urbs[i]); + kfree(port->bulk_out_buffers[i]); + } kfifo_free(&port->write_fifo); kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); @@ -901,7 +910,9 @@ int usb_serial_probe(struct usb_interface *interface, dev_err(&interface->dev, "No free urbs available\n"); goto probe_error; } - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = serial->type->bulk_in_size; + if (!buffer_size) + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->bulk_in_size = buffer_size; port->bulk_in_endpointAddress = endpoint->bEndpointAddress; port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); @@ -918,6 +929,8 @@ int usb_serial_probe(struct usb_interface *interface, } for (i = 0; i < num_bulk_out; ++i) { + int j; + endpoint = bulk_out_endpoint[i]; port = serial->port[i]; port->write_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -927,7 +940,9 @@ int usb_serial_probe(struct usb_interface *interface, } if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) goto probe_error; - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + buffer_size = serial->type->bulk_out_size; + if (!buffer_size) + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); port->bulk_out_size = buffer_size; port->bulk_out_endpointAddress = endpoint->bEndpointAddress; port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); @@ -941,6 +956,28 @@ int usb_serial_probe(struct usb_interface *interface, endpoint->bEndpointAddress), port->bulk_out_buffer, buffer_size, serial->type->write_bulk_callback, port); + for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { + set_bit(j, &port->write_urbs_free); + port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); + if (!port->write_urbs[j]) { + dev_err(&interface->dev, + "No free urbs available\n"); + goto probe_error; + } + port->bulk_out_buffers[j] = kmalloc(buffer_size, + GFP_KERNEL); + if (!port->bulk_out_buffers[j]) { + dev_err(&interface->dev, + "Couldn't allocate bulk_out_buffer\n"); + goto probe_error; + } + usb_fill_bulk_urb(port->write_urbs[j], dev, + usb_sndbulkpipe(dev, + endpoint->bEndpointAddress), + port->bulk_out_buffers[j], buffer_size, + serial->type->write_bulk_callback, + port); + } } if (serial->type->read_int_callback) { @@ -1294,6 +1331,8 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, write_bulk_callback); set_to_generic_if_null(device, disconnect); set_to_generic_if_null(device, release); + set_to_generic_if_null(device, process_read_urb); + set_to_generic_if_null(device, prepare_write_buffer); } int usb_serial_register(struct usb_serial_driver *driver) diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h new file mode 100644 index 00000000000..2be298a1305 --- /dev/null +++ b/drivers/usb/serial/usb-wwan.h @@ -0,0 +1,67 @@ +/* + * Definitions for USB serial mobile broadband cards + */ + +#ifndef __LINUX_USB_USB_WWAN +#define __LINUX_USB_USB_WWAN + +extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); +extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); +extern void usb_wwan_close(struct usb_serial_port *port); +extern int usb_wwan_startup(struct usb_serial *serial); +extern void usb_wwan_disconnect(struct usb_serial *serial); +extern void usb_wwan_release(struct usb_serial *serial); +extern int usb_wwan_write_room(struct tty_struct *tty); +extern void usb_wwan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old); +extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); +extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); +extern int usb_wwan_send_setup(struct usb_serial_port *port); +extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); +#ifdef CONFIG_PM +extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message); +extern int usb_wwan_resume(struct usb_serial *serial); +#endif + +/* per port private data */ + +#define N_IN_URB 4 +#define N_OUT_URB 4 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 4096 + +struct usb_wwan_intf_private { + spinlock_t susp_lock; + unsigned int suspended:1; + int in_flight; + int (*send_setup) (struct usb_serial_port *port); + void *private; +}; + +struct usb_wwan_port_private { + /* Input endpoints and buffer for this port */ + struct urb *in_urbs[N_IN_URB]; + u8 *in_buffer[N_IN_URB]; + /* Output endpoints and buffer for this port */ + struct urb *out_urbs[N_OUT_URB]; + u8 *out_buffer[N_OUT_URB]; + unsigned long out_busy; /* Bit vector of URBs in use */ + int opened; + struct usb_anchor delayed; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[N_OUT_URB]; +}; + +#endif /* __LINUX_USB_USB_WWAN */ diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 28026b47344..f2ed6a31be7 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -16,7 +16,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -#define URB_DEBUG_MAX_IN_FLIGHT_URBS 4000 #define USB_DEBUG_MAX_PACKET_SIZE 8 #define USB_DEBUG_BRK_SIZE 8 static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { @@ -44,12 +43,6 @@ static struct usb_driver debug_driver = { .no_dynamic_id = 1, }; -static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE; - return usb_serial_generic_open(tty, port); -} - /* This HW really does not support a serial break, so one will be * emulated when ever the break state is set to true. */ @@ -69,7 +62,7 @@ static void usb_debug_read_bulk_callback(struct urb *urb) memcmp(urb->transfer_buffer, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE) == 0) { usb_serial_handle_break(port); - usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); + usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); return; } @@ -83,8 +76,7 @@ static struct usb_serial_driver debug_device = { }, .id_table = id_table, .num_ports = 1, - .open = usb_debug_open, - .max_in_flight_urbs = URB_DEBUG_MAX_IN_FLIGHT_URBS, + .bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE, .break_ctl = usb_debug_break_ctl, .read_bulk_callback = usb_debug_read_bulk_callback, }; diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c new file mode 100644 index 00000000000..0c70b4a621b --- /dev/null +++ b/drivers/usb/serial/usb_wwan.c @@ -0,0 +1,665 @@ +/* + USB Driver layer for GSM modems + + Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> + + This driver is free software; you can redistribute it and/or modify + it under the terms of Version 2 of the GNU General Public License as + published by the Free Software Foundation. + + Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org> + + History: see the git log. + + Work sponsored by: Sigos GmbH, Germany <info@sigos.de> + + This driver exists because the "normal" serial driver doesn't work too well + with GSM modems. Issues: + - data loss -- one single Receive URB is not nearly enough + - controlling the baud rate doesn't make sense +*/ + +#define DRIVER_VERSION "v0.7.2" +#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" +#define DRIVER_DESC "USB Driver for GSM modems" + +#include <linux/kernel.h> +#include <linux/jiffies.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include "usb-wwan.h" + +static int debug; + +void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + + struct usb_wwan_intf_private *intfdata; + + dbg("%s", __func__); + + intfdata = port->serial->private; + + if (!intfdata->send_setup) + return; + + portdata = usb_get_serial_port_data(port); + mutex_lock(&serial->disc_mutex); + portdata->rts_state = on; + portdata->dtr_state = on; + if (serial->dev) + intfdata->send_setup(port); + mutex_unlock(&serial->disc_mutex); +} +EXPORT_SYMBOL(usb_wwan_dtr_rts); + +void usb_wwan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_wwan_intf_private *intfdata = port->serial->private; + + dbg("%s", __func__); + + /* Doesn't support option setting */ + tty_termios_copy_hw(tty->termios, old_termios); + + if (intfdata->send_setup) + intfdata->send_setup(port); +} +EXPORT_SYMBOL(usb_wwan_set_termios); + +int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned int value; + struct usb_wwan_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + value = ((portdata->rts_state) ? TIOCM_RTS : 0) | + ((portdata->dtr_state) ? TIOCM_DTR : 0) | + ((portdata->cts_state) ? TIOCM_CTS : 0) | + ((portdata->dsr_state) ? TIOCM_DSR : 0) | + ((portdata->dcd_state) ? TIOCM_CAR : 0) | + ((portdata->ri_state) ? TIOCM_RNG : 0); + + return value; +} +EXPORT_SYMBOL(usb_wwan_tiocmget); + +int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + + portdata = usb_get_serial_port_data(port); + intfdata = port->serial->private; + + if (!intfdata->send_setup) + return -EINVAL; + + /* FIXME: what locks portdata fields ? */ + if (set & TIOCM_RTS) + portdata->rts_state = 1; + if (set & TIOCM_DTR) + portdata->dtr_state = 1; + + if (clear & TIOCM_RTS) + portdata->rts_state = 0; + if (clear & TIOCM_DTR) + portdata->dtr_state = 0; + return intfdata->send_setup(port); +} +EXPORT_SYMBOL(usb_wwan_tiocmset); + +/* Write */ +int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; + unsigned long flags; + + portdata = usb_get_serial_port_data(port); + intfdata = port->serial->private; + + dbg("%s: write (%d chars)", __func__, count); + + i = 0; + left = count; + for (i = 0; left > 0 && i < N_OUT_URB; i++) { + todo = left; + if (todo > OUT_BUFLEN) + todo = OUT_BUFLEN; + + this_urb = portdata->out_urbs[i]; + if (test_and_set_bit(i, &portdata->out_busy)) { + if (time_before(jiffies, + portdata->tx_start_time[i] + 10 * HZ)) + continue; + usb_unlink_urb(this_urb); + continue; + } + dbg("%s: endpoint %d buf %d", __func__, + usb_pipeendpoint(this_urb->pipe), i); + + err = usb_autopm_get_interface_async(port->serial->interface); + if (err < 0) + break; + + /* send the data */ + memcpy(this_urb->transfer_buffer, buf, todo); + this_urb->transfer_buffer_length = todo; + + spin_lock_irqsave(&intfdata->susp_lock, flags); + if (intfdata->suspended) { + usb_anchor_urb(this_urb, &portdata->delayed); + spin_unlock_irqrestore(&intfdata->susp_lock, flags); + } else { + intfdata->in_flight++; + spin_unlock_irqrestore(&intfdata->susp_lock, flags); + err = usb_submit_urb(this_urb, GFP_ATOMIC); + if (err) { + dbg("usb_submit_urb %p (write bulk) failed " + "(%d)", this_urb, err); + clear_bit(i, &portdata->out_busy); + spin_lock_irqsave(&intfdata->susp_lock, flags); + intfdata->in_flight--; + spin_unlock_irqrestore(&intfdata->susp_lock, + flags); + continue; + } + } + + portdata->tx_start_time[i] = jiffies; + buf += todo; + left -= todo; + } + + count -= left; + dbg("%s: wrote (did %d)", __func__, count); + return count; +} +EXPORT_SYMBOL(usb_wwan_write); + +static void usb_wwan_indat_callback(struct urb *urb) +{ + int err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int status = urb->status; + + dbg("%s: %p", __func__, urb); + + endpoint = usb_pipeendpoint(urb->pipe); + port = urb->context; + + if (status) { + dbg("%s: nonzero status: %d on endpoint %02x.", + __func__, status, endpoint); + } else { + tty = tty_port_tty_get(&port->port); + if (urb->actual_length) { + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } else + dbg("%s: empty read urb received", __func__); + tty_kref_put(tty); + + /* Resubmit urb so we continue receiving */ + if (status != -ESHUTDOWN) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err && err != -EPERM) + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __func__, err); + else + usb_mark_last_busy(port->serial->dev); + } + + } + return; +} + +static void usb_wwan_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + int i; + + dbg("%s", __func__); + + port = urb->context; + intfdata = port->serial->private; + + usb_serial_port_softint(port); + usb_autopm_put_interface_async(port->serial->interface); + portdata = usb_get_serial_port_data(port); + spin_lock(&intfdata->susp_lock); + intfdata->in_flight--; + spin_unlock(&intfdata->susp_lock); + + for (i = 0; i < N_OUT_URB; ++i) { + if (portdata->out_urbs[i] == urb) { + smp_mb__before_clear_bit(); + clear_bit(i, &portdata->out_busy); + break; + } + } +} + +int usb_wwan_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i = 0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && !test_bit(i, &portdata->out_busy)) + data_len += OUT_BUFLEN; + } + + dbg("%s: %d", __func__, data_len); + return data_len; +} +EXPORT_SYMBOL(usb_wwan_write_room); + +int usb_wwan_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_wwan_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i = 0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + /* FIXME: This locking is insufficient as this_urb may + go unused during the test */ + if (this_urb && test_bit(i, &portdata->out_busy)) + data_len += this_urb->transfer_buffer_length; + } + dbg("%s: %d", __func__, data_len); + return data_len; +} +EXPORT_SYMBOL(usb_wwan_chars_in_buffer); + +int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + intfdata = serial->private; + + dbg("%s", __func__); + + /* Start reading from the IN endpoint */ + for (i = 0; i < N_IN_URB; i++) { + urb = portdata->in_urbs[i]; + if (!urb) + continue; + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + dbg("%s: submit urb %d failed (%d) %d", + __func__, i, err, urb->transfer_buffer_length); + } + } + + if (intfdata->send_setup) + intfdata->send_setup(port); + + serial->interface->needs_remote_wakeup = 1; + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 1; + spin_unlock_irq(&intfdata->susp_lock); + usb_autopm_put_interface(serial->interface); + + return 0; +} +EXPORT_SYMBOL(usb_wwan_open); + +void usb_wwan_close(struct usb_serial_port *port) +{ + int i; + struct usb_serial *serial = port->serial; + struct usb_wwan_port_private *portdata; + struct usb_wwan_intf_private *intfdata = port->serial->private; + + dbg("%s", __func__); + portdata = usb_get_serial_port_data(port); + + if (serial->dev) { + /* Stop reading/writing urbs */ + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); + + for (i = 0; i < N_IN_URB; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + usb_kill_urb(portdata->out_urbs[i]); + usb_autopm_get_interface(serial->interface); + serial->interface->needs_remote_wakeup = 0; + } +} +EXPORT_SYMBOL(usb_wwan_close); + +/* Helper functions used by usb_wwan_setup_urbs */ +static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + void (*callback) (struct urb *)) +{ + struct urb *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ + if (urb == NULL) { + dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +/* Setup urbs */ +static void usb_wwan_setup_urbs(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ + for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = usb_wwan_setup_urb(serial, + port-> + bulk_in_endpointAddress, + USB_DIR_IN, + port, + portdata-> + in_buffer[j], + IN_BUFLEN, + usb_wwan_indat_callback); + } + + /* outdat endpoints */ + for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = usb_wwan_setup_urb(serial, + port-> + bulk_out_endpointAddress, + USB_DIR_OUT, + port, + portdata-> + out_buffer + [j], + OUT_BUFLEN, + usb_wwan_outdat_callback); + } + } +} + +int usb_wwan_startup(struct usb_serial *serial) +{ + int i, j, err; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + u8 *buffer; + + dbg("%s", __func__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", + __func__, i); + return 1; + } + init_usb_anchor(&portdata->delayed); + + for (j = 0; j < N_IN_URB; j++) { + buffer = (u8 *) __get_free_page(GFP_KERNEL); + if (!buffer) + goto bail_out_error; + portdata->in_buffer[j] = buffer; + } + + for (j = 0; j < N_OUT_URB; j++) { + buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); + if (!buffer) + goto bail_out_error2; + portdata->out_buffer[j] = buffer; + } + + usb_set_serial_port_data(port, portdata); + + if (!port->interrupt_in_urb) + continue; + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) + dbg("%s: submit irq_in urb failed %d", __func__, err); + } + usb_wwan_setup_urbs(serial); + return 0; + +bail_out_error2: + for (j = 0; j < N_OUT_URB; j++) + kfree(portdata->out_buffer[j]); +bail_out_error: + for (j = 0; j < N_IN_URB; j++) + if (portdata->in_buffer[j]) + free_page((unsigned long)portdata->in_buffer[j]); + kfree(portdata); + return 1; +} +EXPORT_SYMBOL(usb_wwan_startup); + +static void stop_read_write_urbs(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + /* Stop reading/writing urbs */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + for (j = 0; j < N_IN_URB; j++) + usb_kill_urb(portdata->in_urbs[j]); + for (j = 0; j < N_OUT_URB; j++) + usb_kill_urb(portdata->out_urbs[j]); + } +} + +void usb_wwan_disconnect(struct usb_serial *serial) +{ + dbg("%s", __func__); + + stop_read_write_urbs(serial); +} +EXPORT_SYMBOL(usb_wwan_disconnect); + +void usb_wwan_release(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + + dbg("%s", __func__); + + /* Now free them */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + for (j = 0; j < N_IN_URB; j++) { + usb_free_urb(portdata->in_urbs[j]); + free_page((unsigned long) + portdata->in_buffer[j]); + portdata->in_urbs[j] = NULL; + } + for (j = 0; j < N_OUT_URB; j++) { + usb_free_urb(portdata->out_urbs[j]); + kfree(portdata->out_buffer[j]); + portdata->out_urbs[j] = NULL; + } + } + + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + kfree(usb_get_serial_port_data(port)); + } +} +EXPORT_SYMBOL(usb_wwan_release); + +#ifdef CONFIG_PM +int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct usb_wwan_intf_private *intfdata = serial->private; + int b; + + dbg("%s entered", __func__); + + if (message.event & PM_EVENT_AUTO) { + spin_lock_irq(&intfdata->susp_lock); + b = intfdata->in_flight; + spin_unlock_irq(&intfdata->susp_lock); + + if (b) + return -EBUSY; + } + + spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 1; + spin_unlock_irq(&intfdata->susp_lock); + stop_read_write_urbs(serial); + + return 0; +} +EXPORT_SYMBOL(usb_wwan_suspend); + +static void play_delayed(struct usb_serial_port *port) +{ + struct usb_wwan_intf_private *data; + struct usb_wwan_port_private *portdata; + struct urb *urb; + int err; + + portdata = usb_get_serial_port_data(port); + data = port->serial->private; + while ((urb = usb_get_from_anchor(&portdata->delayed))) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (!err) + data->in_flight++; + } +} + +int usb_wwan_resume(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct usb_wwan_intf_private *intfdata = serial->private; + struct usb_wwan_port_private *portdata; + struct urb *urb; + int err = 0; + + dbg("%s entered", __func__); + /* get the interrupt URBs resubmitted unconditionally */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + if (!port->interrupt_in_urb) { + dbg("%s: No interrupt URB for port %d", __func__, i); + continue; + } + err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); + dbg("Submitted interrupt URB for port %d (result %d)", i, err); + if (err < 0) { + err("%s: Error %d for interrupt URB of port%d", + __func__, err, i); + goto err_out; + } + } + + for (i = 0; i < serial->num_ports; i++) { + /* walk all ports */ + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* skip closed ports */ + spin_lock_irq(&intfdata->susp_lock); + if (!portdata->opened) { + spin_unlock_irq(&intfdata->susp_lock); + continue; + } + + for (j = 0; j < N_IN_URB; j++) { + urb = portdata->in_urbs[j]; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) { + err("%s: Error %d for bulk URB %d", + __func__, err, i); + spin_unlock_irq(&intfdata->susp_lock); + goto err_out; + } + } + play_delayed(port); + spin_unlock_irq(&intfdata->susp_lock); + } + spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 0; + spin_unlock_irq(&intfdata->susp_lock); +err_out: + return err; +} +EXPORT_SYMBOL(usb_wwan_resume); +#endif + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 094942707c7..eb76aaef426 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -38,17 +38,9 @@ /* function prototypes for a handspring visor */ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port); static void visor_close(struct usb_serial_port *port); -static int visor_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int visor_write_room(struct tty_struct *tty); -static void visor_throttle(struct tty_struct *tty); -static void visor_unthrottle(struct tty_struct *tty); static int visor_probe(struct usb_serial *serial, const struct usb_device_id *id); static int visor_calc_num_ports(struct usb_serial *serial); -static void visor_release(struct usb_serial *serial); -static void visor_write_bulk_callback(struct urb *urb); -static void visor_read_bulk_callback(struct urb *urb); static void visor_read_int_callback(struct urb *urb); static int clie_3_5_startup(struct usb_serial *serial); static int treo_attach(struct usb_serial *serial); @@ -194,18 +186,14 @@ static struct usb_serial_driver handspring_device = { .usb_driver = &visor_driver, .id_table = id_table, .num_ports = 2, + .bulk_out_size = 256, .open = visor_open, .close = visor_close, - .throttle = visor_throttle, - .unthrottle = visor_unthrottle, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .attach = treo_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .release = visor_release, - .write = visor_write, - .write_room = visor_write_room, - .write_bulk_callback = visor_write_bulk_callback, - .read_bulk_callback = visor_read_bulk_callback, .read_int_callback = visor_read_int_callback, }; @@ -219,18 +207,14 @@ static struct usb_serial_driver clie_5_device = { .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_ports = 2, + .bulk_out_size = 256, .open = visor_open, .close = visor_close, - .throttle = visor_throttle, - .unthrottle = visor_unthrottle, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .attach = clie_5_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .release = visor_release, - .write = visor_write, - .write_room = visor_write_room, - .write_bulk_callback = visor_write_bulk_callback, - .read_bulk_callback = visor_read_bulk_callback, .read_int_callback = visor_read_int_callback, }; @@ -244,39 +228,19 @@ static struct usb_serial_driver clie_3_5_device = { .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_ports = 1, + .bulk_out_size = 256, .open = visor_open, .close = visor_close, - .throttle = visor_throttle, - .unthrottle = visor_unthrottle, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .attach = clie_3_5_startup, - .write = visor_write, - .write_room = visor_write_room, - .write_bulk_callback = visor_write_bulk_callback, - .read_bulk_callback = visor_read_bulk_callback, }; -struct visor_private { - spinlock_t lock; - int bytes_in; - int bytes_out; - int outstanding_urbs; - unsigned char throttled; - unsigned char actually_throttled; -}; - -/* number of outstanding urbs to prevent userspace DoS from happening */ -#define URB_UPPER_LIMIT 42 - -static int stats; - /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - struct visor_private *priv = usb_get_serial_port_data(port); - unsigned long flags; int result = 0; dbg("%s - port %d", __func__, port->number); @@ -287,26 +251,10 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) return -ENODEV; } - spin_lock_irqsave(&priv->lock, flags); - priv->bytes_in = 0; - priv->bytes_out = 0; - priv->throttled = 0; - spin_unlock_irqrestore(&priv->lock, flags); - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - visor_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); + result = usb_serial_generic_open(tty, port); + if (result) goto exit; - } if (port->interrupt_in_urb) { dbg("%s - adding interrupt input for treo", __func__); @@ -323,13 +271,12 @@ exit: static void visor_close(struct usb_serial_port *port) { - struct visor_private *priv = usb_get_serial_port_data(port); unsigned char *transfer_buffer; dbg("%s - port %d", __func__, port->number); /* shutdown our urbs */ - usb_kill_urb(port->read_urb); + usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); mutex_lock(&port->serial->disc_mutex); @@ -346,192 +293,6 @@ static void visor_close(struct usb_serial_port *port) } } mutex_unlock(&port->serial->disc_mutex); - - if (stats) - dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n", - priv->bytes_in, priv->bytes_out); -} - - -static int visor_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct visor_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct urb *urb; - unsigned char *buffer; - unsigned long flags; - int status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->outstanding_urbs > URB_UPPER_LIMIT) { - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); - return 0; - } - priv->outstanding_urbs++; - spin_unlock_irqrestore(&priv->lock, flags); - - buffer = kmalloc(count, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "out of memory\n"); - count = -ENOMEM; - goto error_no_buffer; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); - count = -ENOMEM; - goto error_no_urb; - } - - memcpy(buffer, buf, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); - - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - buffer, count, - visor_write_bulk_callback, port); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - usb_submit_urb(write bulk) failed with status = %d\n", - __func__, status); - count = status; - goto error; - } else { - spin_lock_irqsave(&priv->lock, flags); - priv->bytes_out += count; - spin_unlock_irqrestore(&priv->lock, flags); - } - - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb(urb); - - return count; -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&priv->lock, flags); - --priv->outstanding_urbs; - spin_unlock_irqrestore(&priv->lock, flags); - return count; -} - - -static int visor_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct visor_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - /* - * We really can take anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space, unless we don't. - */ - - spin_lock_irqsave(&priv->lock, flags); - if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); - return 0; - } - spin_unlock_irqrestore(&priv->lock, flags); - - return 2048; -} - - -static void visor_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct visor_private *priv = usb_get_serial_port_data(port); - int status = urb->status; - unsigned long flags; - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - - dbg("%s - port %d", __func__, port->number); - - if (status) - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - - spin_lock_irqsave(&priv->lock, flags); - --priv->outstanding_urbs; - spin_unlock_irqrestore(&priv->lock, flags); - - usb_serial_port_softint(port); -} - - -static void visor_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct visor_private *priv = usb_get_serial_port_data(port); - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - struct tty_struct *tty; - int result; - int available_room = 0; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - spin_lock(&priv->lock); - if (tty) - priv->bytes_in += available_room; - - } else { - spin_lock(&priv->lock); - } - - /* Continue trying to always read if we should */ - if (!priv->throttled) { - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - visor_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - } else - priv->actually_throttled = 1; - spin_unlock(&priv->lock); } static void visor_read_int_callback(struct urb *urb) @@ -575,41 +336,6 @@ exit: __func__, result); } -static void visor_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct visor_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); - priv->throttled = 1; - spin_unlock_irq(&priv->lock); -} - - -static void visor_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct visor_private *priv = usb_get_serial_port_data(port); - int result, was_throttled; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); - priv->throttled = 0; - was_throttled = priv->actually_throttled; - priv->actually_throttled = 0; - spin_unlock_irq(&priv->lock); - - if (was_throttled) { - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - } -} - static int palm_os_3_probe(struct usb_serial *serial, const struct usb_device_id *id) { @@ -777,28 +503,6 @@ static int visor_calc_num_ports(struct usb_serial *serial) return num_ports; } -static int generic_startup(struct usb_serial *serial) -{ - struct usb_serial_port **ports = serial->port; - struct visor_private *priv; - int i; - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - while (i-- != 0) { - priv = usb_get_serial_port_data(ports[i]); - usb_set_serial_port_data(ports[i], NULL); - kfree(priv); - } - return -ENOMEM; - } - spin_lock_init(&priv->lock); - usb_set_serial_port_data(ports[i], priv); - } - return 0; -} - static int clie_3_5_startup(struct usb_serial *serial) { struct device *dev = &serial->dev->dev; @@ -849,7 +553,7 @@ static int clie_3_5_startup(struct usb_serial *serial) goto out; } - result = generic_startup(serial); + result = 0; out: kfree(data); @@ -867,7 +571,7 @@ static int treo_attach(struct usb_serial *serial) (le16_to_cpu(serial->dev->descriptor.idVendor) == KYOCERA_VENDOR_ID)) || (serial->num_interrupt_in == 0)) - goto generic_startup; + return 0; dbg("%s", __func__); @@ -897,8 +601,7 @@ static int treo_attach(struct usb_serial *serial) COPY_PORT(serial->port[1], swap_port); kfree(swap_port); -generic_startup: - return generic_startup(serial); + return 0; } static int clie_5_attach(struct usb_serial *serial) @@ -921,20 +624,7 @@ static int clie_5_attach(struct usb_serial *serial) serial->port[0]->bulk_out_endpointAddress = serial->port[1]->bulk_out_endpointAddress; - return generic_startup(serial); -} - -static void visor_release(struct usb_serial *serial) -{ - struct visor_private *priv; - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; i++) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } + return 0; } static int __init visor_init(void) @@ -1018,8 +708,6 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(stats, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(stats, "Enables statistics or not"); module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified vendor ID"); diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 57229cf6647..88db4d06aef 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -9,8 +9,9 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * See Documentation/usb/usb-serial.txt for more information on using this driver - * + * See Documentation/usb/usb-serial.txt for more information on using this + * driver. + * */ #ifndef __LINUX_USB_SERIAL_VISOR_H @@ -65,7 +66,7 @@ #define ACEECA_MEZ1000_ID 0x0001 #define KYOCERA_VENDOR_ID 0x0C88 -#define KYOCERA_7135_ID 0x0021 +#define KYOCERA_7135_ID 0x0021 #define FOSSIL_VENDOR_ID 0x0E67 #define FOSSIL_ABACUS_ID 0x0002 @@ -145,7 +146,7 @@ struct visor_connection_info { * The maximum number of connections currently supported is 2 */ struct palm_ext_connection_info { - __u8 num_ports; + __u8 num_ports; __u8 endpoint_numbers_different; __le16 reserved1; struct { diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c new file mode 100644 index 00000000000..f5796727883 --- /dev/null +++ b/drivers/usb/serial/zio.c @@ -0,0 +1,64 @@ +/* + * ZIO Motherboard USB driver + * + * Copyright (C) 2010 Zilogic Systems <code@zilogic.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x1CBE, 0x0103) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver zio_driver = { + .name = "zio", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver zio_device = { + .driver = { + .owner = THIS_MODULE, + .name = "zio", + }, + .id_table = id_table, + .usb_driver = &zio_driver, + .num_ports = 1, +}; + +static int __init zio_init(void) +{ + int retval; + + retval = usb_serial_register(&zio_device); + if (retval) + return retval; + retval = usb_register(&zio_driver); + if (retval) + usb_serial_deregister(&zio_device); + return retval; +} + +static void __exit zio_exit(void) +{ + usb_deregister(&zio_driver); + usb_serial_deregister(&zio_device); +} + +module_init(zio_init); +module_exit(zio_exit); +MODULE_LICENSE("GPL"); |