net: wireless: bcm4329: Fix "setsuspend" behavior
authorDmitry Shmidt <dimitrysh@google.com>
Fri, 13 Aug 2010 21:37:03 +0000 (14:37 -0700)
committerColin Cross <ccross@android.com>
Thu, 30 Sep 2010 00:49:44 +0000 (17:49 -0700)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/net/wireless/bcm4329/dhd.h
drivers/net/wireless/bcm4329/dhd_linux.c
drivers/net/wireless/bcm4329/wl_iw.c
drivers/net/wireless/bcm4329/wl_iw.h

index 838b3adf80b37df52404433b217a875937890499..727760885fbc09f0b28ac3d7872ffa6545a1a4f1 100644 (file)
@@ -150,8 +150,9 @@ typedef struct dhd_pub {
        /* Last error from dongle */
        int dongle_error;
 
-       /* Suspend disable flag */
+       /* Suspend disable flag and "in suspend" flag */
        int suspend_disable_flag;
+       int in_suspend;
 
        /* Pkt filter defination */
        char * pktfilter[100];
index 8b424e58308c112b9a6ff5a967fbe1157d7d9659..900ca7a5b755239b5b5dda5f75869deecc6b4604 100644 (file)
@@ -217,11 +217,12 @@ print_tainted()
 #include <wl_iw.h>
 #endif /* defined(CONFIG_WIRELESS_EXT) */
 
-#if defined(CONFIG_HAS_EARLYSUSPEND)
-#include <linux/earlysuspend.h>
 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
 /* Interface control information */
@@ -495,10 +496,7 @@ extern int register_pm_notifier(struct notifier_block *nb);
 extern int unregister_pm_notifier(struct notifier_block *nb);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
 
-
-#if defined(CONFIG_HAS_EARLYSUSPEND)
-
-int dhd_set_suspend(int value, dhd_pub_t *dhd)
+static int dhd_set_suspend(int value, dhd_pub_t *dhd)
 {
        int power_mode = PM_MAX;
        /* wl_pkt_filter_enable_t       enable_parm; */
@@ -510,10 +508,10 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd)
        int i;
 
 #define htod32(i) i
+       DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
 
-       if (dhd && (dhd->up && !dhd->suspend_disable_flag)) {
-               dhd_os_proto_block(dhd);
-               if (value) {
+       if (dhd && dhd->up) {
+               if (value && dhd->in_suspend) {
 
                        /* Kernel suspended */
                        dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
@@ -564,30 +562,43 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd)
                        dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
 #endif /* CUSTOMER_HW2 */
                }
-               dhd_os_proto_unblock(dhd);
        }
 
        return 0;
 }
 
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
+{
+       dhd_pub_t *dhdp = &dhd->pub;
+
+       dhd_os_wake_lock(dhdp);
+       dhd_os_proto_block(dhdp);
+       dhdp->in_suspend = val;
+       if (!dhdp->suspend_disable_flag)
+               dhd_set_suspend(val, dhdp);
+       dhd_os_proto_unblock(dhdp);
+       dhd_os_wake_unlock(dhdp);
+}
+
 static void dhd_early_suspend(struct early_suspend *h)
 {
-       struct dhd_info *dhdp;
-       dhdp = container_of(h, struct dhd_info, early_suspend);
+       struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
 
        DHD_TRACE(("%s: enter\n", __FUNCTION__));
 
-       dhd_set_suspend(1, &dhdp->pub);
+       if (dhd)
+               dhd_suspend_resume_helper(dhd, 1);
 }
 
 static void dhd_late_resume(struct early_suspend *h)
 {
-       struct dhd_info *dhdp;
-       dhdp = container_of(h, struct dhd_info, early_suspend);
+       struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
 
        DHD_TRACE(("%s: enter\n", __FUNCTION__));
 
-       dhd_set_suspend(0, &dhdp->pub);
+       if (dhd)
+               dhd_suspend_resume_helper(dhd, 0);
 }
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
@@ -3056,8 +3067,24 @@ int net_os_wake_unlock(struct net_device *dev)
 int net_os_set_suspend_disable(struct net_device *dev, int val)
 {
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+       int ret = 0;
 
-       if (dhd)
+       if (dhd) {
+               ret = dhd->pub.suspend_disable_flag;
                dhd->pub.suspend_disable_flag = val;
-       return 0;
+       }
+       return ret;
+}
+
+int net_os_set_suspend(struct net_device *dev, int val)
+{
+       dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+       int ret = 0;
+
+       if (dhd) {
+               dhd_os_proto_block(&dhd->pub);
+               ret = dhd_set_suspend(val, &dhd->pub);
+               dhd_os_proto_unblock(&dhd->pub);
+       }
+       return ret;
 }
index 9d9f55c5c5d59dbae78fe0e701fb3c6285d0d8ef..b845d0cc7a80aeee23390b60ab0e021990d078a3 100644 (file)
@@ -849,9 +849,18 @@ wl_iw_set_suspend(
 )
 {
        int suspend_flag;
+       int ret;
 
        suspend_flag = *(extra + strlen("SETSUSPEND") + 1) - '0';
-       return net_os_set_suspend_disable(dev, suspend_flag);
+       if (suspend_flag != 0)
+               suspend_flag = 1;
+
+       ret = net_os_set_suspend_disable(dev, suspend_flag);
+       WL_TRACE(("%s: Suspend Flag %d -> %d\n", __func__, ret, suspend_flag));
+
+       if (ret != suspend_flag)
+               net_os_set_suspend(dev, ret);
+       return 0;
 }
 
 int
index d49ce240b78cdc51a9fe417825a4a0495f2133d5..ebe9af7489ca825c2838d99b1616d53ff1b61fd0 100644 (file)
@@ -178,6 +178,7 @@ extern int net_os_wake_unlock(struct net_device *dev);
 extern int net_os_wake_lock_timeout(struct net_device *dev);
 extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
 extern int net_os_set_suspend_disable(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
 #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \