Skip to content

Commit

Permalink
USB: fix bug in serial driver unregistration
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Apr 9, 2012
1 parent 3a45085 commit 891a3b1
Show file tree
Hide file tree
Showing 3 changed files with 2 additions and 34 deletions.
5 changes: 0 additions & 5 deletions drivers/usb/serial/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 2 additions & 21 deletions drivers/usb/serial/usb-serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 0 additions & 8 deletions include/linux/usb/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@
/* 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

Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit 891a3b1

Please sign in to comment.