diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-17 00:06:10 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-17 00:06:10 +0400 |
commit | e1f5b94fd0c93c3e27ede88b7ab652d086dc960f (patch) | |
tree | e8de7a132eb88521dd1c19e128eba2d5349bdf4f /drivers/usb/serial/usb-serial.c | |
parent | 6fd03301d76bc439382710e449f58efbb233df1b (diff) | |
parent | 1b6ed69f974f6f32c8be0d9a7fc952822eb83b6f (diff) | |
download | linux-e1f5b94fd0c93c3e27ede88b7ab652d086dc960f.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (143 commits)
USB: xhci depends on PCI.
USB: xhci: Add Makefile, MAINTAINERS, and Kconfig entries.
USB: xhci: Respect critical sections.
USB: xHCI: Fix interrupt moderation.
USB: xhci: Remove packed attribute from structures.
usb; xhci: Fix TRB offset calculations.
USB: xhci: replace if-elseif-else with switch-case
USB: xhci: Make xhci-mem.c include linux/dmapool.h
USB: xhci: drop spinlock in xhci_urb_enqueue() error path.
USB: Change names of SuperSpeed ep companion descriptor structs.
USB: xhci: Avoid compiler reordering in Link TRB giveback.
USB: xhci: Clean up xhci_irq() function.
USB: xhci: Avoid global namespace pollution.
USB: xhci: Fix Link TRB handoff bit twiddling.
USB: xhci: Fix register write order.
USB: xhci: fix some compiler warnings in xhci.h
USB: xhci: fix lots of compiler warnings.
USB: xhci: use xhci_handle_event instead of handle_event
USB: xhci: URB cancellation support.
USB: xhci: Scatter gather list support for bulk transfers.
...
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1967a7edc10c..d595aa5586a7 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -141,6 +141,14 @@ static void destroy_serial(struct kref *kref) if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); + serial->type->release(serial); + + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) + put_device(&port->dev); + } + /* 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 */ @@ -148,9 +156,8 @@ static void destroy_serial(struct kref *kref) for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { port = serial->port[i]; - if (!port) - continue; - port_free(port); + if (port) + port_free(port); } } @@ -1046,10 +1053,15 @@ int usb_serial_probe(struct usb_interface *interface, dev_set_name(&port->dev, "ttyUSB%d", port->number); dbg ("%s - registering %s", __func__, dev_name(&port->dev)); + port->dev_state = PORT_REGISTERING; retval = device_register(&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); @@ -1113,10 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface) serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); - /* Unfortunately, many of the sub-drivers expect the port structures - * to exist when their shutdown method is called, so we have to go - * through this awkward two-step unregistration procedure. - */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) { @@ -1130,17 +1138,25 @@ void usb_serial_disconnect(struct usb_interface *interface) } kill_traffic(port); cancel_work_sync(&port->work); - device_del(&port->dev); - } - } - serial->type->shutdown(serial); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - put_device(&port->dev); - serial->port[i] = NULL; + 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; + device_del(&port->dev); + port->dev_state = PORT_UNREGISTERED; + } } } + serial->type->disconnect(serial); /* let the last holder of this object * cause it to be cleaned up */ @@ -1318,7 +1334,8 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, chars_in_buffer); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, shutdown); + set_to_generic_if_null(device, disconnect); + set_to_generic_if_null(device, release); } int usb_serial_register(struct usb_serial_driver *driver) |