USB: io_ti: use kfifo to implement write buffering
[safe/jmp/linux-2.6] / drivers / usb / serial / io_ti.c
index 513b25e..0fca265 100644 (file)
@@ -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>
 #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;
@@ -102,13 +91,12 @@ struct edgeport_port {
        __u8 shadow_mcr;
        __u8 shadow_lsr;
        __u8 lsr_mask;
-       __u32 ump_read_timeout;         /* Number of miliseconds the UMP will
+       __u32 ump_read_timeout;         /* Number of milliseconds the UMP will
                                           wait without data before completing
                                           a read short */
        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 {
@@ -134,7 +122,7 @@ struct edgeport_serial {
 
 
 /* Devices that this driver supports */
-static struct usb_device_id edgeport_1port_id_table [] = {
+static const struct usb_device_id edgeport_1port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -154,7 +142,7 @@ static struct usb_device_id edgeport_1port_id_table [] = {
        { }
 };
 
-static struct usb_device_id edgeport_2port_id_table [] = {
+static const struct usb_device_id edgeport_2port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
@@ -177,7 +165,7 @@ static struct usb_device_id edgeport_2port_id_table [] = {
 };
 
 /* Devices that this driver supports */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -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)
@@ -413,11 +390,18 @@ static int write_boot_mem(struct edgeport_serial *serial,
 {
        int status = 0;
        int i;
-       __u8 temp;
+       u8 *temp;
 
        /* Must do a read before write */
        if (!serial->TiReadI2C) {
-               status = read_boot_mem(serial, 0, 1, &temp);
+               temp = kmalloc(1, GFP_KERNEL);
+               if (!temp) {
+                       dev_err(&serial->serial->dev->dev,
+                                       "%s - out of memory\n", __func__);
+                       return -ENOMEM;
+               }
+               status = read_boot_mem(serial, 0, 1, temp);
+               kfree(temp);
                if (status)
                        return status;
        }
@@ -583,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 */
@@ -595,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);
 
@@ -935,37 +919,47 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
 static int i2c_type_bootmode(struct edgeport_serial *serial)
 {
        int status;
-       __u8 data;
+       u8 *data;
+
+       data = kmalloc(1, GFP_KERNEL);
+       if (!data) {
+               dev_err(&serial->serial->dev->dev,
+                               "%s - out of memory\n", __func__);
+               return -ENOMEM;
+       }
 
        /* Try to read type 2 */
        status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
-                               DTK_ADDR_SPACE_I2C_TYPE_II, 0, &data, 0x01);
+                               DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01);
        if (status)
                dbg("%s - read 2 status error = %d", __func__, status);
        else
-               dbg("%s - read 2 data = 0x%x", __func__, data);
-       if ((!status) && (data == UMP5152 || data == UMP3410)) {
+               dbg("%s - read 2 data = 0x%x", __func__, *data);
+       if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
                dbg("%s - ROM_TYPE_II", __func__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
-               return 0;
+               goto out;
        }
 
        /* Try to read type 3 */
        status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
-                               DTK_ADDR_SPACE_I2C_TYPE_III, 0, &data, 0x01);
+                               DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01);
        if (status)
                dbg("%s - read 3 status error = %d", __func__, status);
        else
-               dbg("%s - read 2 data = 0x%x", __func__, data);
-       if ((!status) && (data == UMP5152 || data == UMP3410)) {
+               dbg("%s - read 2 data = 0x%x", __func__, *data);
+       if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
                dbg("%s - ROM_TYPE_III", __func__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
-               return 0;
+               goto out;
        }
 
        dbg("%s - Unknown", __func__);
        serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
-       return -ENODEV;
+       status = -ENODEV;
+out:
+       kfree(data);
+       return status;
 }
 
 static int bulk_xfer(struct usb_serial *serial, void *buffer,
@@ -1113,7 +1107,7 @@ static int download_fw(struct edgeport_serial *serial)
                                I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc);
                if (start_address != 0) {
                        struct ti_i2c_firmware_rec *firmware_version;
-                       __u8 record;
+                       u8 *record;
 
                        dbg("%s - Found Type FIRMWARE (Type 2) record",
                                                                __func__);
@@ -1165,6 +1159,15 @@ static int download_fw(struct edgeport_serial *serial)
                                    OperationalMajorVersion,
                                    OperationalMinorVersion);
 
+                               record = kmalloc(1, GFP_KERNEL);
+                               if (!record) {
+                                       dev_err(dev, "%s - out of memory.\n",
+                                                       __func__);
+                                       kfree(firmware_version);
+                                       kfree(rom_desc);
+                                       kfree(ti_manuf_desc);
+                                       return -ENOMEM;
+                               }
                                /* In order to update the I2C firmware we must
                                 * change the type 2 record to type 0xF2. This
                                 * will force the UMP to come up in Boot Mode.
@@ -1177,13 +1180,14 @@ static int download_fw(struct edgeport_serial *serial)
                                 * firmware will update the record type from
                                 * 0xf2 to 0x02.
                                 */
-                               record = I2C_DESC_TYPE_FIRMWARE_BLANK;
+                               *record = I2C_DESC_TYPE_FIRMWARE_BLANK;
 
                                /* Change the I2C Firmware record type to
                                   0xf2 to trigger an update */
                                status = write_rom(serial, start_address,
-                                               sizeof(record), &record);
+                                               sizeof(*record), record);
                                if (status) {
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
@@ -1196,19 +1200,21 @@ static int download_fw(struct edgeport_serial *serial)
                                 */
                                status = read_rom(serial,
                                                        start_address,
-                                                       sizeof(record),
-                                                       &record);
+                                                       sizeof(*record),
+                                                       record);
                                if (status) {
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
                                        return status;
                                }
 
-                               if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
+                               if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
                                        dev_err(dev,
                                                "%s - error resetting device\n",
                                                __func__);
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
@@ -1226,6 +1232,7 @@ static int download_fw(struct edgeport_serial *serial)
                                                __func__, status);
 
                                /* return an error on purpose. */
+                               kfree(record);
                                kfree(firmware_version);
                                kfree(rom_desc);
                                kfree(ti_manuf_desc);
@@ -1686,7 +1693,7 @@ static void edge_interrupt_callback(struct urb *urb)
        case TIUMP_INTERRUPT_CODE_MSR:  /* MSR */
                /* Copy MSR from UMP */
                msr = data[1];
-               dbg("%s - ===== Port %u MSR Status = %02x ======\n",
+               dbg("%s - ===== Port %u MSR Status = %02x ======",
                     __func__, port_number, msr);
                handle_new_msr(edge_port, msr);
                break;
@@ -1790,7 +1797,6 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
 {
        int queued;
 
-       tty_buffer_request_room(tty, length);
        queued = tty_insert_flip_string(tty, data, length);
        if (queued < length)
                dev_err(dev, "%s - dropping data, %d bytes lost\n",
@@ -1831,8 +1837,7 @@ static void edge_bulk_out_callback(struct urb *urb)
        tty_kref_put(tty);
 }
 
-static int edge_open(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        struct edgeport_serial *edge_serial;
@@ -2009,8 +2014,7 @@ release_es_lock:
        return status;
 }
 
-static void edge_close(struct tty_struct *tty,
-                       struct usb_serial_port *port, struct file *filp)
+static void edge_close(struct usb_serial_port *port)
 {
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
@@ -2062,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);
 
@@ -2076,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;
@@ -2102,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);
 
@@ -2158,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);
@@ -2180,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);
@@ -2637,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);
@@ -2655,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);
        }
@@ -2664,7 +2665,7 @@ cleanup:
        return -ENOMEM;
 }
 
-static void edge_shutdown(struct usb_serial *serial)
+static void edge_disconnect(struct usb_serial *serial)
 {
        int i;
        struct edgeport_port *edge_port;
@@ -2674,12 +2675,22 @@ static void edge_shutdown(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                edge_port = usb_get_serial_port_data(serial->port[i]);
                edge_remove_sysfs_attrs(edge_port->port);
-               edge_buf_free(edge_port->ep_out_buf);
+       }
+}
+
+static void edge_release(struct usb_serial *serial)
+{
+       int i;
+       struct edgeport_port *edge_port;
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               edge_port = usb_get_serial_port_data(serial->port[i]);
+               kfifo_free(&edge_port->write_fifo);
                kfree(edge_port);
-               usb_set_serial_port_data(serial->port[i], NULL);
        }
        kfree(usb_get_serial_data(serial));
-       usb_set_serial_data(serial, NULL);
 }
 
 
@@ -2726,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,
@@ -2916,7 +2751,8 @@ static struct usb_serial_driver edgeport_1port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .port_probe             = edge_create_sysfs_attrs,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
@@ -2945,7 +2781,8 @@ static struct usb_serial_driver edgeport_2port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .port_probe             = edge_create_sysfs_attrs,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,