vserver 1.9.3
[linux-2.6.git] / drivers / usb / serial / usb-serial.c
index 609c1d1..03e8a7e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2004 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
  *
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-
-
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
 #include "usb-serial.h"
 #include "pl2303.h"
 
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
 #define DRIVER_DESC "USB Serial Driver core"
 
-
-#ifdef CONFIG_USB_SERIAL_GENERIC
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-       {.driver_info = 42},
-       {}
-};
-
-#endif /* CONFIG_USB_SERIAL_GENERIC */
-
 /* Driver structure we register with the USB core */
 static struct usb_driver usb_serial_driver = {
        .owner =        THIS_MODULE,
        .name =         "usbserial",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
-#ifdef CONFIG_USB_SERIAL_GENERIC
-       .id_table =     generic_serial_ids,
-#endif
 };
 
 /* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead
@@ -382,10 +361,10 @@ static struct usb_driver usb_serial_driver = {
    drivers depend on it.
 */
 
-static struct usb_serial       *serial_table[SERIAL_TTY_MINORS];       /* initially all NULL */
+static int debug;
+static struct usb_serial *serial_table[SERIAL_TTY_MINORS];     /* initially all NULL */
 static LIST_HEAD(usb_serial_driver_list);
 
-
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
        struct usb_serial *serial = serial_table[index];
@@ -416,8 +395,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
                        }
                if (good_spot == 0)
                        continue;
-                       
-               serial->magic = USB_SERIAL_MAGIC;
+
                *minor = i;
                dbg("%s - minor base = %d", __FUNCTION__, *minor);
                for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
@@ -443,6 +421,63 @@ static void return_serial (struct usb_serial *serial)
        return;
 }
 
+static void destroy_serial(struct kref *kref)
+{
+       struct usb_serial *serial;
+       struct usb_serial_port *port;
+       int i;
+
+       serial = to_usb_serial(kref);
+
+       dbg ("%s - %s", __FUNCTION__, serial->type->name);
+
+       serial->type->shutdown(serial);
+
+       /* return the minor range that this device had */
+       return_serial(serial);
+
+       for (i = 0; i < serial->num_ports; ++i)
+               serial->port[i]->open_count = 0;
+
+       /* the ports are cleaned up and released in port_release() */
+       for (i = 0; i < serial->num_ports; ++i)
+               if (serial->port[i]->dev.parent != NULL) {
+                       device_unregister(&serial->port[i]->dev);
+                       serial->port[i] = NULL;
+               }
+
+       /* If this is a "fake" port, we have to clean it up here, as it will
+        * not get cleaned up in port_release() as it was never registered with
+        * the driver core */
+       if (serial->num_ports < serial->num_port_pointers) {
+               for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
+                       port = serial->port[i];
+                       if (!port)
+                               continue;
+                       if (port->read_urb) {
+                               usb_unlink_urb(port->read_urb);
+                               usb_free_urb(port->read_urb);
+                       }
+                       if (port->write_urb) {
+                               usb_unlink_urb(port->write_urb);
+                               usb_free_urb(port->write_urb);
+                       }
+                       if (port->interrupt_in_urb) {
+                               usb_unlink_urb(port->interrupt_in_urb);
+                               usb_free_urb(port->interrupt_in_urb);
+                       }
+                       kfree(port->bulk_in_buffer);
+                       kfree(port->bulk_out_buffer);
+                       kfree(port->interrupt_in_buffer);
+               }
+       }
+
+       usb_put_dev(serial->dev);
+
+       /* free up any memory that we allocated */
+       kfree (serial);
+}
+
 /*****************************************************************************
  * Driver tty interface functions
  *****************************************************************************/
@@ -460,9 +495,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
 
        /* get the serial object associated with this tty pointer */
        serial = usb_serial_get_by_index(tty->index);
-
-       if (serial_paranoia_check (serial, __FUNCTION__))
-               return -ENODEV;
+       if (!serial) {
+               retval = -ENODEV;
+               goto bailout;
+       }
 
        /* set up our port structure making the tty driver remember our port object, and us it */
        portNumber = tty->index - serial->minor;
@@ -486,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
                if (retval) {
                        port->open_count = 0;
                        module_put(serial->type->owner);
-                       kref_put(&serial->kref);
+                       kref_put(&serial->kref, destroy_serial);
                }
        }
 bailout:
@@ -496,9 +532,8 @@ bailout:
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-       if (!serial)
+       if (!port)
                return;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
@@ -518,18 +553,14 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
        }
 
        module_put(port->serial->type->owner);
-       kref_put(&port->serial->kref);
+       kref_put(&port->serial->kref, destroy_serial);
 }
 
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        int retval = -EINVAL;
 
-       if (!serial)
-               return -ENODEV;
-
        dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
        if (!port->open_count) {
@@ -538,7 +569,7 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
        }
 
        /* pass on to the driver specific version of this function */
-       retval = serial->type->write(port, from_user, buf, count);
+       retval = port->serial->type->write(port, from_user, buf, count);
 
 exit:
        return retval;
@@ -547,12 +578,8 @@ exit:
 static int serial_write_room (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        int retval = -EINVAL;
 
-       if (!serial)
-               return -ENODEV;
-
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (!port->open_count) {
@@ -561,7 +588,7 @@ static int serial_write_room (struct tty_struct *tty)
        }
 
        /* pass on to the driver specific version of this function */
-       retval = serial->type->write_room(port);
+       retval = port->serial->type->write_room(port);
 
 exit:
        return retval;
@@ -570,12 +597,8 @@ exit:
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        int retval = -EINVAL;
 
-       if (!serial)
-               return -ENODEV;
-
        dbg("%s = port %d", __FUNCTION__, port->number);
 
        if (!port->open_count) {
@@ -584,7 +607,7 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
        }
 
        /* pass on to the driver specific version of this function */
-       retval = serial->type->chars_in_buffer(port);
+       retval = port->serial->type->chars_in_buffer(port);
 
 exit:
        return retval;
@@ -593,10 +616,6 @@ exit:
 static void serial_throttle (struct tty_struct * tty)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               return;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -606,8 +625,8 @@ static void serial_throttle (struct tty_struct * tty)
        }
 
        /* pass on to the driver specific version of this function */
-       if (serial->type->throttle)
-               serial->type->throttle(port);
+       if (port->serial->type->throttle)
+               port->serial->type->throttle(port);
 
 exit:
        ;
@@ -616,10 +635,6 @@ exit:
 static void serial_unthrottle (struct tty_struct * tty)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               return;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -629,8 +644,8 @@ static void serial_unthrottle (struct tty_struct * tty)
        }
 
        /* pass on to the driver specific version of this function */
-       if (serial->type->unthrottle)
-               serial->type->unthrottle(port);
+       if (port->serial->type->unthrottle)
+               port->serial->type->unthrottle(port);
 
 exit:
        ;
@@ -639,12 +654,8 @@ exit:
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        int retval = -ENODEV;
 
-       if (!serial)
-               return -ENODEV;
-
        dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
        if (!port->open_count) {
@@ -653,8 +664,8 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
        }
 
        /* pass on to the driver specific version of this function if it is available */
-       if (serial->type->ioctl)
-               retval = serial->type->ioctl(port, file, cmd, arg);
+       if (port->serial->type->ioctl)
+               retval = port->serial->type->ioctl(port, file, cmd, arg);
        else
                retval = -ENOIOCTLCMD;
 
@@ -665,10 +676,6 @@ exit:
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               return;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -678,8 +685,8 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
        }
 
        /* pass on to the driver specific version of this function if it is available */
-       if (serial->type->set_termios)
-               serial->type->set_termios(port, old);
+       if (port->serial->type->set_termios)
+               port->serial->type->set_termios(port, old);
 
 exit:
        ;
@@ -688,10 +695,6 @@ exit:
 static void serial_break (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               return;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -701,20 +704,13 @@ static void serial_break (struct tty_struct *tty, int break_state)
        }
 
        /* pass on to the driver specific version of this function if it is available */
-       if (serial->type->break_ctl)
-               serial->type->break_ctl(port, break_state);
+       if (port->serial->type->break_ctl)
+               port->serial->type->break_ctl(port, break_state);
 
 exit:
        ;
 }
 
-static void serial_shutdown (struct usb_serial *serial)
-{
-       dbg ("%s", __FUNCTION__);
-
-       serial->type->shutdown(serial);
-}
-
 static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        struct usb_serial *serial;
@@ -748,7 +744,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
                        begin += length;
                        length = 0;
                }
-               kref_put(&serial->kref);
+               kref_put(&serial->kref, destroy_serial);
        }
        *eof = 1;
 done:
@@ -761,10 +757,6 @@ done:
 static int serial_tiocmget (struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               goto exit;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -773,8 +765,8 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
                goto exit;
        }
 
-       if (serial->type->tiocmget)
-               return serial->type->tiocmget(port, file);
+       if (port->serial->type->tiocmget)
+               return port->serial->type->tiocmget(port, file);
 
 exit:
        return -EINVAL;
@@ -784,10 +776,6 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
                            unsigned int set, unsigned int clear)
 {
        struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-
-       if (!serial)
-               goto exit;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -796,8 +784,8 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
                goto exit;
        }
 
-       if (serial->type->tiocmset)
-               return serial->type->tiocmset(port, file, set, clear);
+       if (port->serial->type->tiocmset)
+               return port->serial->type->tiocmset(port, file, set, clear);
 
 exit:
        return -EINVAL;
@@ -806,7 +794,6 @@ exit:
 void usb_serial_port_softint(void *private)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)private;
-       struct usb_serial *serial;
        struct tty_struct *tty;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
@@ -814,76 +801,11 @@ void usb_serial_port_softint(void *private)
        if (!port)
                return;
 
-       serial = get_usb_serial (port, __FUNCTION__);
-       if (!serial)
-               return;
-
        tty = port->tty;
        if (!tty)
                return;
 
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-               dbg("%s - write wakeup call.", __FUNCTION__);
-               (tty->ldisc.write_wakeup)(tty);
-       }
-
-       wake_up_interruptible(&tty->write_wait);
-}
-
-static void destroy_serial(struct kref *kref)
-{
-       struct usb_serial *serial;
-       struct usb_serial_port *port;
-       int i;
-
-       serial = to_usb_serial(kref);
-
-       dbg ("%s - %s", __FUNCTION__, serial->type->name);
-       serial_shutdown (serial);
-
-       /* return the minor range that this device had */
-       return_serial(serial);
-
-       for (i = 0; i < serial->num_ports; ++i)
-               serial->port[i]->open_count = 0;
-
-       /* the ports are cleaned up and released in port_release() */
-       for (i = 0; i < serial->num_ports; ++i)
-               if (serial->port[i]->dev.parent != NULL) {
-                       device_unregister(&serial->port[i]->dev);
-                       serial->port[i] = NULL;
-               }
-
-       /* If this is a "fake" port, we have to clean it up here, as it will
-        * not get cleaned up in port_release() as it was never registered with
-        * the driver core */
-       if (serial->num_ports < serial->num_port_pointers) {
-               for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
-                       port = serial->port[i];
-                       if (!port)
-                               continue;
-                       if (port->read_urb) {
-                               usb_unlink_urb(port->read_urb);
-                               usb_free_urb(port->read_urb);
-                       }
-                       if (port->write_urb) {
-                               usb_unlink_urb(port->write_urb);
-                               usb_free_urb(port->write_urb);
-                       }
-                       if (port->interrupt_in_urb) {
-                               usb_unlink_urb(port->interrupt_in_urb);
-                               usb_free_urb(port->interrupt_in_urb);
-                       }
-                       kfree(port->bulk_in_buffer);
-                       kfree(port->bulk_out_buffer);
-                       kfree(port->interrupt_in_buffer);
-               }
-       }
-
-       usb_put_dev(serial->dev);
-
-       /* free up any memory that we allocated */
-       kfree (serial);
+       tty_wakeup(tty);
 }
 
 static void port_release(struct device *dev)
@@ -926,7 +848,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
        serial->interface = interface;
        serial->vendor = dev->descriptor.idVendor;
        serial->product = dev->descriptor.idProduct;
-       kref_init(&serial->kref, destroy_serial);
+       kref_init(&serial->kref);
 
        return serial;
 }
@@ -1037,7 +959,7 @@ int usb_serial_probe(struct usb_interface *interface,
             (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
                if (interface != dev->actconfig->interface[0]) {
                        /* check out the endpoints of the other interface*/
-                       iface_desc = &dev->actconfig->interface[0]->altsetting[0];
+                       iface_desc = dev->actconfig->interface[0]->cur_altsetting;
                        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                                endpoint = &iface_desc->endpoint[i].desc;
                                if ((endpoint->bEndpointAddress & 0x80) &&
@@ -1117,7 +1039,6 @@ int usb_serial_probe(struct usb_interface *interface,
                memset(port, 0x00, sizeof(struct usb_serial_port));
                port->number = i + serial->minor;
                port->serial = serial;
-               port->magic = USB_SERIAL_PORT_MAGIC;
                INIT_WORK(&port->work, usb_serial_port_softint, port);
                serial->port[i] = port;
        }
@@ -1277,7 +1198,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
        if (serial) {
                /* let the last holder of this object 
                 * cause it to be cleaned up */
-               kref_put(&serial->kref);
+               kref_put(&serial->kref, destroy_serial);
        }
        dev_info(dev, "device disconnected\n");
 }
@@ -1429,22 +1350,9 @@ error:
 
 void usb_serial_deregister(struct usb_serial_device_type *device)
 {
-       struct usb_serial *serial;
-       int i;
-
        info("USB Serial deregistering driver %s", device->name);
-
-       /* clear out the serial_table if the device is attached to a port */
-       for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
-               serial = serial_table[i];
-               if ((serial != NULL) && (serial->type == device)) {
-                       usb_driver_release_interface (&usb_serial_driver, serial->interface);
-                       usb_serial_disconnect (serial->interface);
-               }
-       }
-
        list_del(&device->driver_list);
-       usb_serial_bus_deregister (device);
+       usb_serial_bus_deregister(device);
 }
 
 
@@ -1463,5 +1371,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");