USB: usb_wwan: fix remote wakeup
authorJohan Hovold <jhovold@gmail.com>
Mon, 26 May 2014 17:23:20 +0000 (19:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 May 2014 22:04:06 +0000 (15:04 -0700)
Make sure that needs_remote_wake up is always set when there are open
ports.

Currently close() would unconditionally set needs_remote_wakeup to 0
even though there might still be open ports. This could lead to blocked
input and possibly dropped data on devices that do not support remote
wakeup (and which must therefore not be runtime suspended while open).

Add an open_ports counter (protected by the susp_lock) and only clear
needs_remote_wakeup when the last port is closed.

Note that there are currently no multi-port drivers using the usb_wwan
implementation.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/serial/usb-wwan.h
drivers/usb/serial/usb_wwan.c

index 684739b8efd05b15a5646585d94417f3aa20a53d..aca45efbd6749a6c92c34e1fdf820b345def3f5b 100644 (file)
@@ -39,6 +39,7 @@ struct usb_wwan_intf_private {
        spinlock_t susp_lock;
        unsigned int suspended:1;
        int in_flight;
+       unsigned int open_ports;
        int (*send_setup) (struct usb_serial_port *port);
        void *private;
 };
index ab8c17536534dfd9c4a0ad7fa7e440790146fade..daaa5d7959465a7b46f89a63fba7a2d30e6bccf7 100644 (file)
@@ -411,9 +411,10 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (intfdata->send_setup)
                intfdata->send_setup(port);
 
-       serial->interface->needs_remote_wakeup = 1;
        spin_lock_irq(&intfdata->susp_lock);
        portdata->opened = 1;
+       if (++intfdata->open_ports == 1)
+               serial->interface->needs_remote_wakeup = 1;
        spin_unlock_irq(&intfdata->susp_lock);
        /* this balances a get in the generic USB serial code */
        usb_autopm_put_interface(serial->interface);
@@ -448,6 +449,8 @@ void usb_wwan_close(struct usb_serial_port *port)
        /* Stop reading/writing urbs */
        spin_lock_irq(&intfdata->susp_lock);
        portdata->opened = 0;
+       if (--intfdata->open_ports == 0)
+               serial->interface->needs_remote_wakeup = 0;
        spin_unlock_irq(&intfdata->susp_lock);
 
        for (;;) {
@@ -466,7 +469,6 @@ void usb_wwan_close(struct usb_serial_port *port)
 
        /* balancing - important as an error cannot be handled*/
        usb_autopm_get_interface_no_resume(serial->interface);
-       serial->interface->needs_remote_wakeup = 0;
 }
 EXPORT_SYMBOL(usb_wwan_close);