net: wireless: bcmdhd: Add SETSUSPENDMODE command
Dmitry Shmidt [Tue, 28 Feb 2012 19:03:37 +0000 (11:03 -0800)]
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>

drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_iw.c
drivers/net/wireless/bcmdhd/wl_iw.h
drivers/net/wireless/bcmdhd/wldev_common.h

index fc94634..35f9c60 100644 (file)
@@ -8,7 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER                     \
        -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT          \
        -DKEEP_ALIVE -DPKT_FILTER_SUPPORT     \
        -DEMBEDDED_PLATFORM           \
-       -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE          \
+       -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE -DDHD_USE_EARLYSUSPEND \
        -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
 
 ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC),y)
index 5be539d..54e7279 100644 (file)
@@ -155,11 +155,10 @@ print_tainted()
 extern wl_iw_extra_params_t  g_wl_iw_params;
 #endif /* defined(CONFIG_BCMDHD_WEXT) */
 
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
-extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
 
 #ifdef PKT_FILTER_SUPPORT
 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
@@ -260,6 +259,7 @@ typedef struct dhd_info {
         * calls and wifi_on or wifi_off
         */
        struct mutex dhd_net_if_mutex;
+       struct mutex dhd_suspend_mutex;
 #endif
        spinlock_t wakelock_spinlock;
        int wakelock_counter;
@@ -272,7 +272,7 @@ typedef struct dhd_info {
        atomic_t pend_8021x_cnt;
        dhd_attach_states_t dhd_state;
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
        struct early_suspend early_suspend;
 #endif /* CONFIG_HAS_EARLYSUSPEND */
 
@@ -425,6 +425,8 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
 ;
 static void dhd_net_if_lock_local(dhd_info_t *dhd);
 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+static void dhd_suspend_lock(dhd_pub_t *dhdp);
+static void dhd_suspend_unlock(dhd_pub_t *dhdp);
 #if !defined(AP) && defined(WLP2P)
 static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
 #endif 
@@ -514,7 +516,6 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
 #endif
 }
 
-#if defined(CONFIG_HAS_EARLYSUSPEND)
 static int dhd_set_suspend(int value, dhd_pub_t *dhd)
 {
        int power_mode = PM_MAX;
@@ -526,70 +527,75 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
        DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
                __FUNCTION__, value, dhd->in_suspend));
 
+       dhd_suspend_lock(dhd);
        if (dhd && dhd->up) {
                if (value && dhd->in_suspend) {
 
-                               /* Kernel suspended */
-                               DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
+                       /* Kernel suspended */
+                       DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
 
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
-                                                sizeof(power_mode), TRUE, 0);
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+                                        sizeof(power_mode), TRUE, 0);
 
-                               /* Enable packet filter, only allow unicast packet to send up */
-                               dhd_set_packet_filter(1, dhd);
+                       /* Enable packet filter, only allow unicast packet to send up */
+                       dhd_set_packet_filter(1, dhd);
 
-                               /* If DTIM skip is set up as default, force it to wake
-                                * each third DTIM for better power savings.  Note that
-                                * one side effect is a chance to miss BC/MC packet.
-                                */
-                               bcn_li_dtim = dhd_get_dtim_skip(dhd);
-                               bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
-                                       4, iovbuf, sizeof(iovbuf));
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
-                               /* Disable firmware roaming during suspend */
-                               bcm_mkiovar("roam_off", (char *)&roamvar, 4,
-                                       iovbuf, sizeof(iovbuf));
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-                       } else {
+                       /* If DTIM skip is set up as default, force it to wake
+                        * each third DTIM for better power savings.  Note that
+                        * one side effect is a chance to miss BC/MC packet.
+                        */
+                       bcn_li_dtim = dhd_get_dtim_skip(dhd);
+                       bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+                               4, iovbuf, sizeof(iovbuf));
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+                       /* Disable firmware roaming during suspend */
+                       bcm_mkiovar("roam_off", (char *)&roamvar, 4,
+                               iovbuf, sizeof(iovbuf));
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+               } else {
 
-                               /* Kernel resumed  */
-                               DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
+                       /* Kernel resumed  */
+                       DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
 
-                               power_mode = PM_FAST;
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
-                                                sizeof(power_mode), TRUE, 0);
+                       power_mode = PM_FAST;
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+                                        sizeof(power_mode), TRUE, 0);
 
-                               /* disable pkt filter */
-                               dhd_set_packet_filter(0, dhd);
+                       /* disable pkt filter */
+                       dhd_set_packet_filter(0, dhd);
 
-                               /* restore pre-suspend setting for dtim_skip */
-                               bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
-                                       4, iovbuf, sizeof(iovbuf));
+                       /* restore pre-suspend setting for dtim_skip */
+                       bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
+                               4, iovbuf, sizeof(iovbuf));
 
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-                               roamvar = dhd_roam_disable;
-                               bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
-                                       sizeof(iovbuf));
-                               dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-                       }
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+                       roamvar = dhd_roam_disable;
+                       bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
+                               sizeof(iovbuf));
+                       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+               }
        }
-
+       dhd_suspend_unlock(dhd);
        return 0;
 }
 
-static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
+static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
 {
        dhd_pub_t *dhdp = &dhd->pub;
+       int ret = 0;
 
        DHD_OS_WAKE_LOCK(dhdp);
        /* Set flag when early suspend was called */
        dhdp->in_suspend = val;
-       if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
-               dhd_set_suspend(val, dhdp);
+       if ((force || !dhdp->suspend_disable_flag) &&
+           (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
+               ret = dhd_set_suspend(val, dhdp);
        DHD_OS_WAKE_UNLOCK(dhdp);
+       return ret;
 }
 
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
 static void dhd_early_suspend(struct early_suspend *h)
 {
        struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
@@ -597,7 +603,7 @@ static void dhd_early_suspend(struct early_suspend *h)
        DHD_TRACE(("%s: enter\n", __FUNCTION__));
 
        if (dhd)
-               dhd_suspend_resume_helper(dhd, 1);
+               dhd_suspend_resume_helper(dhd, 1, 0);
 }
 
 static void dhd_late_resume(struct early_suspend *h)
@@ -607,7 +613,7 @@ static void dhd_late_resume(struct early_suspend *h)
        DHD_TRACE(("%s: enter\n", __FUNCTION__));
 
        if (dhd)
-               dhd_suspend_resume_helper(dhd, 0);
+               dhd_suspend_resume_helper(dhd, 0, 0);
 }
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
@@ -2647,6 +2653,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
 #endif
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
        mutex_init(&dhd->dhd_net_if_mutex);
+       mutex_init(&dhd->dhd_suspend_mutex);
 #endif
        dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
 
@@ -2732,7 +2739,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
        register_pm_notifier(&dhd_sleep_pm_notifier);
 #endif /*  (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
        dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
        dhd->early_suspend.suspend = dhd_early_suspend;
        dhd->early_suspend.resume = dhd_late_resume;
@@ -3565,7 +3572,7 @@ void dhd_detach(dhd_pub_t *dhdp)
        unregister_inetaddr_notifier(&dhd_notifier);
 #endif /* ARP_OFFLOAD_SUPPORT */
 
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
        if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
                if (dhd->early_suspend.suspend)
                        unregister_early_suspend(&dhd->early_suspend);
@@ -4257,16 +4264,18 @@ int net_os_set_suspend_disable(struct net_device *dev, int val)
        return ret;
 }
 
-int net_os_set_suspend(struct net_device *dev, int val)
+int net_os_set_suspend(struct net_device *dev, int val, int force)
 {
        int ret = 0;
-#if defined(CONFIG_HAS_EARLYSUSPEND)
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
 
        if (dhd) {
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
                ret = dhd_set_suspend(val, &dhd->pub);
+#else
+               ret = dhd_suspend_resume_helper(dhd, val, force);
+#endif
        }
-#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
        return ret;
 }
 
@@ -4442,6 +4451,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd)
 #endif
 }
 
+static void dhd_suspend_lock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+       dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+       if (dhd)
+               mutex_lock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
+static void dhd_suspend_unlock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+       dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+       if (dhd)
+               mutex_unlock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
 unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
 {
        dhd_info_t *dhd = (dhd_info_t *)(pub->info);
index 8f6b198..3b75448 100644 (file)
@@ -67,6 +67,7 @@
 #define CMD_BTCOEXSCAN_STOP            "BTCOEXSCAN-STOP"
 #define CMD_BTCOEXMODE                 "BTCOEXMODE"
 #define CMD_SETSUSPENDOPT              "SETSUSPENDOPT"
+#define CMD_SETSUSPENDMODE             "SETSUSPENDMODE"
 #define CMD_P2P_DEV_ADDR               "P2P_DEV_ADDR"
 #define CMD_SETFWPATH                  "SETFWPATH"
 #define CMD_SETBAND                            "SETBAND"
@@ -201,7 +202,7 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int
        ret_now = net_os_set_suspend_disable(dev, suspend_flag);
 
        if (ret_now != suspend_flag) {
-               if (!(ret = net_os_set_suspend(dev, ret_now)))
+               if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
                        DHD_INFO(("%s: Suspend Flag %d -> %d\n",
                                __FUNCTION__, ret_now, suspend_flag));
                else
@@ -210,6 +211,26 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int
        return ret;
 }
 
+static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
+{
+       int ret = 0;
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
+       int suspend_flag;
+
+       suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
+
+       if (suspend_flag != 0)
+               suspend_flag = 1;
+
+       if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
+               DHD_INFO(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
+       else
+               DHD_ERROR(("%s: failed %d\n",__FUNCTION__,ret));
+#endif
+       return ret;
+}
+
 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
 {
        uint band;
@@ -505,6 +526,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
        else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
                bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
        }
+       else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
+               bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
+       }
        else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
                uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
                bytes_written = wldev_set_band(net, band);
index 4d813ba..25db3ca 100644 (file)
@@ -1119,7 +1119,7 @@ wl_iw_set_btcoex_dhcp(
 }
 
 static int
-wl_iw_set_suspend(
+wl_iw_set_suspend_opt(
 struct net_device *dev,
 struct iw_request_info *info,
 union iwreq_data *wrqu,
@@ -1130,16 +1130,15 @@ char *extra
        int ret_now;
        int ret = 0;
 
-       suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
+       suspend_flag = *(extra + strlen(SETSUSPENDOPT_CMD) + 1) - '0';
 
        if (suspend_flag != 0)
                suspend_flag = 1;
 
        ret_now = net_os_set_suspend_disable(dev, suspend_flag);
 
-       
        if (ret_now != suspend_flag) {
-               if (!(ret = net_os_set_suspend(dev, ret_now)))
+               if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
                        WL_ERROR(("%s: Suspend Flag %d -> %d\n",
                                  __FUNCTION__, ret_now, suspend_flag));
                else
@@ -1150,6 +1149,32 @@ char *extra
 }
 
 static int
+wl_iw_set_suspend_mode(
+struct net_device *dev,
+struct iw_request_info *info,
+union iwreq_data *wrqu,
+char *extra
+)
+{
+       int ret = 0;
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
+       int suspend_flag;
+
+       suspend_flag = *(extra + strlen(SETSUSPENDMODE_CMD) + 1) - '0';
+
+       if (suspend_flag != 0)
+               suspend_flag = 1;
+
+       if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
+               WL_ERROR(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
+       else
+               WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+#endif
+       return ret;
+}
+
+static int
 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
 {
        int i, c;
@@ -7601,8 +7626,10 @@ wl_iw_set_priv(
                        ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
                else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
                        ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
-               else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
-                       ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
+               else if (strnicmp(extra, SETSUSPENDOPT_CMD, strlen(SETSUSPENDOPT_CMD)) == 0)
+                       ret = wl_iw_set_suspend_opt(dev, info, (union iwreq_data *)dwrq, extra);
+               else if (strnicmp(extra, SETSUSPENDMODE_CMD, strlen(SETSUSPENDMODE_CMD)) == 0)
+                       ret = wl_iw_set_suspend_mode(dev, info, (union iwreq_data *)dwrq, extra);
                else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
                        ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
 #if defined(PNO_SUPPORT)
index faca5f7..273dcf1 100644 (file)
@@ -47,7 +47,8 @@
 #define BAND_SET_CMD                           "SETBAND"
 #define DTIM_SKIP_GET_CMD                      "DTIMSKIPGET"
 #define DTIM_SKIP_SET_CMD                      "DTIMSKIPSET"
-#define SETSUSPEND_CMD                         "SETSUSPENDOPT"
+#define SETSUSPENDOPT_CMD                      "SETSUSPENDOPT"
+#define SETSUSPENDMODE_CMD                     "SETSUSPENDMODE"
 #define PNOSSIDCLR_SET_CMD                     "PNOSSIDCLR"
 
 #define PNOSETUP_SET_CMD                       "PNOSETUP " 
@@ -206,7 +207,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, int val);
 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);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
 extern int net_os_set_dtim_skip(struct net_device *dev, int val);
 extern int net_os_send_hang_message(struct net_device *dev);
 extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
index 6a1ba15..773235e 100644 (file)
@@ -92,7 +92,7 @@ extern int net_os_wake_lock_timeout(struct net_device *dev);
 extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
 extern int net_os_set_dtim_skip(struct net_device *dev, int val);
 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);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
 extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
        int max, int *bytes_left);