Cancel pending URBs during suspend operation to avoid receiving ESHUTDOWN
in read/write completion callbacks while the device is suspended.

Receiving ESHUTDOWN in read/write completion callbacks will cause the
driver to enter a non-functioning "stopped" state from which the driver is
unable to recover without reloading the module.

Signed-off-by: Hemmo Nieminen <hemmo.niemi...@iki.fi>
---

Notes:
    Tested on x86_64 with RTL8191SU 802.11n WLAN Adapter.

 drivers/staging/rtl8712/drv_types.h     |  1 +
 drivers/staging/rtl8712/usb_intf.c      | 12 ++++++++++++
 drivers/staging/rtl8712/usb_ops_linux.c |  5 ++++-
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/rtl8712/drv_types.h 
b/drivers/staging/rtl8712/drv_types.h
index 3d64fee..29e47e1 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -159,6 +159,7 @@ struct _adapter {
        struct mp_priv  mppriv;
        s32     bDriverStopped;
        s32     bSurpriseRemoved;
+       s32     bSuspended;
        u32     IsrContent;
        u32     ImrContent;
        u8      EepromAddressSize;
diff --git a/drivers/staging/rtl8712/usb_intf.c 
b/drivers/staging/rtl8712/usb_intf.c
index c71333f..b64f10b 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -205,12 +205,15 @@ struct drv_priv {
 static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state)
 {
        struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
+       struct _adapter *padapter = netdev_priv(pnetdev);
 
        netdev_info(pnetdev, "Suspending...\n");
        if (!pnetdev || !netif_running(pnetdev)) {
                netdev_info(pnetdev, "Unable to suspend\n");
                return 0;
        }
+       padapter->bSuspended = true;
+       rtl871x_intf_stop(padapter);
        if (pnetdev->netdev_ops->ndo_stop)
                pnetdev->netdev_ops->ndo_stop(pnetdev);
        mdelay(10);
@@ -218,9 +221,16 @@ static int r871x_suspend(struct usb_interface *pusb_intf, 
pm_message_t state)
        return 0;
 }
 
+void rtl871x_intf_resume(struct _adapter *padapter)
+{
+       if (padapter->dvobjpriv.inirp_init)
+               padapter->dvobjpriv.inirp_init(padapter);
+}
+
 static int r871x_resume(struct usb_interface *pusb_intf)
 {
        struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
+       struct _adapter *padapter = netdev_priv(pnetdev);
 
        netdev_info(pnetdev,  "Resuming...\n");
        if (!pnetdev || !netif_running(pnetdev)) {
@@ -230,6 +240,8 @@ static int r871x_resume(struct usb_interface *pusb_intf)
        netif_device_attach(pnetdev);
        if (pnetdev->netdev_ops->ndo_open)
                pnetdev->netdev_ops->ndo_open(pnetdev);
+       padapter->bSuspended = false;
+       rtl871x_intf_resume(padapter);
        return 0;
 }
 
diff --git a/drivers/staging/rtl8712/usb_ops_linux.c 
b/drivers/staging/rtl8712/usb_ops_linux.c
index 489a9e6..e77be2a 100644
--- a/drivers/staging/rtl8712/usb_ops_linux.c
+++ b/drivers/staging/rtl8712/usb_ops_linux.c
@@ -228,11 +228,14 @@ static void r8712_usb_read_port_complete(struct urb *purb)
                }
        } else {
                switch (purb->status) {
+               case -ENOENT:
+                       if (padapter->bSuspended)
+                               break;
+                       /* Fall through. */
                case -EINVAL:
                case -EPIPE:
                case -ENODEV:
                case -ESHUTDOWN:
-               case -ENOENT:
                        padapter->bDriverStopped = true;
                        break;
                case -EPROTO:
-- 
2.6.3

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to