USB: fix bug in serial driver unregistration
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 28 Mar 2012 20:10:49 +0000 (16:10 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Apr 2012 22:36:20 +0000 (15:36 -0700)
This patch (as1536) fixes a bug in the USB serial core.  Unloading and
reloading a serial driver while a serial device is plugged in causes
errors because of the code in usb_serial_disconnect() that tries to
make sure the port_remove method is called.  With the new order of
driver registration introduced in the 3.4 kernel, this is definitely
not the right thing to do (if indeed it ever was).

The patch removes that whole section code, along with the mechanism
for keeping track of each port's registration state, which is no
longer needed.  The driver core can handle all that stuff for us.

Note: This has been tested only with one or two USB serial drivers.
In theory, other drivers might still run into trouble.  But if they
do, it will be the fault of the drivers, not of this patch -- that is,
the drivers will need to be fixed.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-and-tested-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/serial/bus.c
drivers/usb/serial/usb-serial.c
include/linux/usb/serial.h

index 7f547dc3a5903fd25e0837441115007320ae122d..ed8adb052ca74f136a14a423dea5cbe397c4d381 100644 (file)
@@ -60,8 +60,6 @@ static int usb_serial_device_probe(struct device *dev)
                retval = -ENODEV;
                goto exit;
        }
-       if (port->dev_state != PORT_REGISTERING)
-               goto exit;
 
        driver = port->serial->type;
        if (driver->port_probe) {
@@ -98,9 +96,6 @@ static int usb_serial_device_remove(struct device *dev)
        if (!port)
                return -ENODEV;
 
-       if (port->dev_state != PORT_UNREGISTERING)
-               return retval;
-
        device_remove_file(&port->dev, &dev_attr_port_number);
 
        driver = port->serial->type;
index 69230f01056ab32f551c2a0e8e953e1fee03649e..5413bd50078101b6de6333ca5a7256ad6d1dc36d 100644 (file)
@@ -1070,17 +1070,12 @@ int usb_serial_probe(struct usb_interface *interface,
                port = serial->port[i];
                dev_set_name(&port->dev, "ttyUSB%d", port->number);
                dbg ("%s - registering %s", __func__, dev_name(&port->dev));
-               port->dev_state = PORT_REGISTERING;
                device_enable_async_suspend(&port->dev);
 
                retval = device_add(&port->dev);
-               if (retval) {
+               if (retval)
                        dev_err(&port->dev, "Error registering port device, "
                                "continuing\n");
-                       port->dev_state = PORT_UNREGISTERED;
-               } else {
-                       port->dev_state = PORT_REGISTERED;
-               }
        }
 
        usb_serial_console_init(debug, minor);
@@ -1124,22 +1119,8 @@ void usb_serial_disconnect(struct usb_interface *interface)
                        }
                        kill_traffic(port);
                        cancel_work_sync(&port->work);
-                       if (port->dev_state == PORT_REGISTERED) {
-
-                               /* Make sure the port is bound so that the
-                                * driver's port_remove method is called.
-                                */
-                               if (!port->dev.driver) {
-                                       int rc;
-
-                                       port->dev.driver =
-                                                       &serial->type->driver;
-                                       rc = device_bind_driver(&port->dev);
-                               }
-                               port->dev_state = PORT_UNREGISTERING;
+                       if (device_is_registered(&port->dev))
                                device_del(&port->dev);
-                               port->dev_state = PORT_UNREGISTERED;
-                       }
                }
        }
        serial->type->disconnect(serial);
index fbb666b1b67008ef38d9f7c2b0e9682e924fbae7..4742838882332ac766a97ddc9c582afde6127457 100644 (file)
 /* parity check flag */
 #define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
-enum port_dev_state {
-       PORT_UNREGISTERED,
-       PORT_REGISTERING,
-       PORT_REGISTERED,
-       PORT_UNREGISTERING,
-};
-
 /* USB serial flags */
 #define USB_SERIAL_WRITE_BUSY  0
 
@@ -124,7 +117,6 @@ struct usb_serial_port {
        char                    throttle_req;
        unsigned long           sysrq; /* sysrq timeout */
        struct device           dev;
-       enum port_dev_state     dev_state;
 };
 #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)