From sarah.a.sharp@intel.com Mon Nov 26 22:53:36 2007 From: Sarah Sharp Date: Tue, 13 Nov 2007 17:10:09 -0800 Subject: USB: Prepare serial core for autosuspend. To: Greg KH Cc: linux-usb-devel@lists.sourceforge.net Message-ID: <20071114011009.GA30481@localdomain> Content-Disposition: inline Claim the interface for a USB to serial converter when the tty is open, and release the interface when the tty is closed. If a driver doesn't provide a resume function, use the generic resume instead. Make sure the generic resume function does not submit the URBs if we're coming back from autosuspend. On autoresume, we know that the open function will be called next, which will attempt to submit the URBs. If we submit them in the resume function, the open will fail. This works for: - autosuspend - suspending with the tty open or closed - hibernate with the tty closed A hibernate (or a suspend that causes the USB subsystem to lose power) has issues. If you have the tty open when you hibernate, a new tty will be created when the device re-enumerates during resume. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 8 ++++++++ drivers/usb/serial/usb-serial.c | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb struct usb_serial_port *port; int i, c = 0, r; +#ifdef CONFIG_PM + /* + * If this is an autoresume, don't submit URBs. + * They will be submitted in the open function instead. + */ + if (serial->dev->auto_pm) + return 0; +#endif for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; if (port->open_count && port->read_urb) { --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,16 +225,21 @@ static int serial_open (struct tty_struc goto bailout_mutex_unlock; } + retval = usb_autopm_get_interface(serial->interface); + if (retval) + goto bailout_module_put; /* only call the device specific open if this * is the first time the port is opened */ retval = serial->type->open(port, filp); if (retval) - goto bailout_module_put; + goto bailout_interface_put; } mutex_unlock(&port->mutex); return 0; +bailout_interface_put: + usb_autopm_put_interface(serial->interface); bailout_module_put: module_put(serial->type->driver.owner); bailout_mutex_unlock: @@ -277,8 +282,10 @@ static void serial_close(struct tty_stru } } - if (port->open_count == 0) + if (port->open_count == 0) { + usb_autopm_put_interface(port->serial->interface); module_put(port->serial->type->driver.owner); + } mutex_unlock(&port->mutex); usb_serial_put(port->serial); @@ -1255,6 +1262,7 @@ static void fixup_generic(struct usb_ser 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, resume); } int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */