]> err.no Git - linux-2.6/blobdiff - drivers/usb/serial/usb-serial.c
Pull thinkpad-2.6.24 into release branch
[linux-2.6] / drivers / usb / serial / usb-serial.c
index 9bf01a5efc84adaaec0145ca24076421b64db558..497e29a700ca8dccb20049e0aa0abf983dcbf40c 100644 (file)
@@ -429,6 +429,8 @@ static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
        /* pass on to the driver specific version of this function if it is available */
        if (port->serial->type->set_termios)
                port->serial->type->set_termios(port, old);
+       else
+               tty_termios_copy_hw(tty->termios, old);
 }
 
 static void serial_break (struct tty_struct *tty, int break_state)
@@ -578,6 +580,17 @@ static void kill_traffic(struct usb_serial_port *port)
 {
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
+       /*
+        * This is tricky.
+        * Some drivers submit the read_urb in the
+        * handler for the write_urb or vice versa
+        * this order determines the order in which
+        * usb_kill_urb() must be used to reliably
+        * kill the URBs. As it is unknown here,
+        * both orders must be used in turn.
+        * The call below is not redundant.
+        */
+       usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
 }
@@ -651,16 +664,14 @@ exit:
 
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
-       struct list_head *p;
        const struct usb_device_id *id;
-       struct usb_serial_driver *t;
+       struct usb_serial_driver *drv;
 
        /* Check if the usb id matches a known device */
-       list_for_each(p, &usb_serial_driver_list) {
-               t = list_entry(p, struct usb_serial_driver, driver_list);
-               id = get_iface_id(t, iface);
+       list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+               id = get_iface_id(drv, iface);
                if (id)
-                       return t;
+                       return drv;
        }
 
        return NULL;
@@ -800,9 +811,6 @@ int usb_serial_probe(struct usb_interface *interface,
        /* END HORRIBLE HACK FOR PL2303 */
 #endif
 
-       /* found all that we need */
-       dev_info(&interface->dev, "%s converter detected\n", type->description);
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
        if (type == &usb_serial_generic_device) {
                num_ports = num_bulk_out;
@@ -836,6 +844,24 @@ int usb_serial_probe(struct usb_interface *interface,
        serial->num_interrupt_in = num_interrupt_in;
        serial->num_interrupt_out = num_interrupt_out;
 
+       /* check that the device meets the driver's requirements */
+       if ((type->num_interrupt_in != NUM_DONT_CARE &&
+                               type->num_interrupt_in != num_interrupt_in)
+                       || (type->num_interrupt_out != NUM_DONT_CARE &&
+                               type->num_interrupt_out != num_interrupt_out)
+                       || (type->num_bulk_in != NUM_DONT_CARE &&
+                               type->num_bulk_in != num_bulk_in)
+                       || (type->num_bulk_out != NUM_DONT_CARE &&
+                               type->num_bulk_out != num_bulk_out)) {
+               dbg("wrong number of endpoints");
+               kfree(serial);
+               return -EIO;
+       }
+
+       /* found all that we need */
+       dev_info(&interface->dev, "%s converter detected\n",
+                       type->description);
+
        /* create our ports, we need as many as the max endpoints */
        /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
        max_endpoints = max(num_bulk_in, num_bulk_out);
@@ -1097,7 +1123,9 @@ int usb_serial_resume(struct usb_interface *intf)
 {
        struct usb_serial *serial = usb_get_intfdata(intf);
 
-       return serial->type->resume(serial);
+       if (serial->type->resume)
+               return serial->type->resume(serial);
+       return 0;
 }
 EXPORT_SYMBOL(usb_serial_resume);