]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/serial/visor.c
USB: serial: aircable: clean up urb->status usage
[linux-2.6-omap-h63xx.git] / drivers / usb / serial / visor.c
index 95a2936e902e22a00c4360ec819292d0c531e73d..81ae76f15bf0b3d27c240260ffa5622c3be0d2aa 100644 (file)
@@ -5,9 +5,9 @@
  *     Copyright (C) 1999 - 2004
  *         Greg Kroah-Hartman (greg@kroah.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.
+ *     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.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
@@ -25,7 +25,7 @@
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
 #include "visor.h"
 
 /*
@@ -46,10 +46,10 @@ static int  visor_probe             (struct usb_serial *serial, const struct usb_device_id
 static int  visor_calc_num_ports(struct usb_serial *serial);
 static void visor_shutdown     (struct usb_serial *serial);
 static int  visor_ioctl                (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios  (struct usb_serial_port *port, struct termios *old_termios);
-static void visor_write_bulk_callback  (struct urb *urb, struct pt_regs *regs);
-static void visor_read_bulk_callback   (struct urb *urb, struct pt_regs *regs);
-static void visor_read_int_callback    (struct urb *urb, struct pt_regs *regs);
+static void visor_set_termios  (struct usb_serial_port *port, struct ktermios *old_termios);
+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);
 static int clie_5_attach (struct usb_serial *serial);
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
-               .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
                .name =         "visor",
        },
        .description =          "Handspring Visor / Palm OS",
+       .usb_driver =           &visor_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
                .name =         "clie_5",
        },
        .description =          "Sony Clie 5.0",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_5_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
                .name =         "clie_3.5",
        },
        .description =          "Sony Clie 3.5",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_3_5_table,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
@@ -273,7 +273,8 @@ struct visor_private {
        int bytes_in;
        int bytes_out;
        int outstanding_urbs;
-       int throttled;
+       unsigned char throttled;
+       unsigned char actually_throttled;
 };
 
 /* number of outstanding urbs to prevent userspace DoS from happening */
@@ -302,7 +303,6 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
        spin_lock_irqsave(&priv->lock, flags);
        priv->bytes_in = 0;
        priv->bytes_out = 0;
-       priv->outstanding_urbs = 0;
        priv->throttled = 0;
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -349,8 +349,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
                         
        /* shutdown our urbs */
        usb_kill_urb(port->read_urb);
-       if (port->interrupt_in_urb)
-               usb_kill_urb(port->interrupt_in_urb);
+       usb_kill_urb(port->interrupt_in_urb);
 
        /* Try to send shutdown message, if the device is gone, this will just fail. */
        transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -386,19 +385,21 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
                dbg("%s - write limit hit\n", __FUNCTION__);
                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");
-               return -ENOMEM;
+               count = -ENOMEM;
+               goto error_no_buffer;
        }
 
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                dev_err(&port->dev, "no more free urbs\n");
-               kfree (buffer);
-               return -ENOMEM;
+               count = -ENOMEM;
+               goto error_no_urb;
        }
 
        memcpy (buffer, buf, count);
@@ -417,31 +418,51 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
                dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
                        __FUNCTION__, status);
                count = status;
-               kfree (buffer);
+               goto error;
        } else {
                spin_lock_irqsave(&priv->lock, flags);
-               ++priv->outstanding_urbs;
                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);
+       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 usb_serial_port *port)
 {
+       struct visor_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+
        dbg("%s - port %d", __FUNCTION__, 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
+        * 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\n", __FUNCTION__);
+               return 0;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
        return 2048;
 }
 
@@ -460,7 +481,7 @@ static int visor_chars_in_buffer (struct usb_serial_port *port)
 }
 
 
-static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_write_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct visor_private *priv = usb_get_serial_port_data(port);
@@ -483,15 +504,14 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 }
 
 
-static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_read_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct visor_private *priv = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        struct tty_struct *tty;
-       unsigned long flags;
-       int throttled;
        int result;
+       int available_room;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -504,17 +524,20 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
        tty = port->tty;
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
-               tty_insert_flip_string(tty, data, urb->actual_length);
-               tty_flip_buffer_push(tty);
+               available_room = tty_buffer_request_room(tty, urb->actual_length);
+               if (available_room) {
+                       tty_insert_flip_string(tty, data, available_room);
+                       tty_flip_buffer_push(tty);
+               }
+               spin_lock(&priv->lock);
+               priv->bytes_in += available_room;
+
+       } else {
+               spin_lock(&priv->lock);
        }
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->bytes_in += urb->actual_length;
-       throttled = priv->throttled;
-       spin_unlock_irqrestore(&priv->lock, flags);
 
        /* Continue trying to always read if we should */
-       if (!throttled) {
+       if (!priv->throttled) {
                usb_fill_bulk_urb (port->read_urb, port->serial->dev,
                                   usb_rcvbulkpipe(port->serial->dev,
                                                   port->bulk_in_endpointAddress),
@@ -524,11 +547,13 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
                result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (result)
                        dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+       } else {
+               priv->actually_throttled = 1;
        }
-       return;
+       spin_unlock(&priv->lock);
 }
 
-static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_read_int_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        int result;
@@ -588,6 +613,7 @@ static void visor_unthrottle (struct usb_serial_port *port)
        dbg("%s - port %d", __FUNCTION__, port->number);
        spin_lock_irqsave(&priv->lock, flags);
        priv->throttled = 0;
+       priv->actually_throttled = 0;
        spin_unlock_irqrestore(&priv->lock, flags);
 
        port->read_urb->dev = port->serial->dev;
@@ -758,15 +784,22 @@ static int visor_calc_num_ports (struct usb_serial *serial)
 
 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)
+               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(serial->port[i], priv);
+               usb_set_serial_port_data(ports[i], priv);
        }
        return 0;
 }
@@ -876,7 +909,18 @@ static int clie_5_attach (struct usb_serial *serial)
 
 static void visor_shutdown (struct usb_serial *serial)
 {
+       struct visor_private *priv;
+       int i;
+
        dbg("%s", __FUNCTION__);
+
+       for (i = 0; i < serial->num_ports; i++) {
+               priv = usb_get_serial_port_data(serial->port[i]);
+               if (priv) {
+                       usb_set_serial_port_data(serial->port[i], NULL);
+                       kfree(priv);
+               }
+       }
 }
 
 static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
@@ -888,7 +932,7 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
 
 
 /* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
 {
        unsigned int cflag;