From e078a22b6f226ecf4cf3add7e5a7cb09b458bff1 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 28 Feb 2012 11:03:37 -0800 Subject: net: wireless: bcmdhd: Add SETSUSPENDMODE command Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 131 +++++++++++++++++------------ drivers/net/wireless/bcmdhd/wl_android.c | 26 +++++- drivers/net/wireless/bcmdhd/wl_iw.c | 39 +++++++-- drivers/net/wireless/bcmdhd/wl_iw.h | 5 +- drivers/net/wireless/bcmdhd/wldev_common.h | 2 +- 6 files changed, 142 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index a8b135d..ead28f5 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -8,7 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ - -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 DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 6418e38..9654719 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -154,11 +154,10 @@ print_tainted() extern wl_iw_extra_params_t g_wl_iw_params; #endif /* defined(WL_WIRELESS_EXT) */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include -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); @@ -259,6 +258,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; @@ -271,7 +271,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 */ @@ -424,6 +424,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 @@ -513,7 +515,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; @@ -525,70 +526,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); @@ -596,7 +602,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) @@ -606,7 +612,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) */ @@ -2645,6 +2651,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #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; @@ -2730,7 +2737,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) 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; @@ -3563,7 +3570,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); @@ -4255,16 +4262,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; } @@ -4440,6 +4449,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); diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 8f6b198..3b75448 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -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); diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index e724aa3..f5494f3 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -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) diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h index faca5f7..273dcf1 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/bcmdhd/wl_iw.h @@ -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); diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 6a1ba15..773235e 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -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); -- cgit v1.1