From 4912545472d71e3dd546b18b397aec4c89fd7403 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 30 Sep 2009 20:04:38 -0700 Subject: libertas: Add auto deep sleep support for SD8385/SD8686/SD8688 Add timer based auto deep sleep feature in libertas driver which can be configured using iwconfig command. This is tested on SD8688, SD8686 cards with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit platforms. Tests have been done for USB/CS cards to make sure that the patch won't break USB/CS code. We didn't test the if_spi driver. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 185 ++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/libertas/wext.c') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index be837a0d251..38a451edb70 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv) priv->pending_assoc_req = NULL; } +/** + * @brief This function checks if the command is allowed. + * + * @param priv A pointer to lbs_private structure + * @return allowed or not allowed. + */ + +int lbs_is_cmd_allowed(struct lbs_private *priv) +{ + int ret = 1; + + lbs_deb_enter(LBS_DEB_WEXT); + + if (!priv->is_auto_deep_sleep_enabled) { + if (priv->is_deep_sleep) { + lbs_deb_wext("IOCTLS called when station" + "is in deep sleep\n"); + ret = 0; + } + } + + lbs_deb_leave(LBS_DEB_WEXT); + return ret; +} + /** * @brief Find the channel frequency power info with specific channel @@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + lbs_deb_leave(LBS_DEB_WEXT); + return -EBUSY; + } + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, priv->curbssparams.channel); @@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (vwrq->disabled) val = MRVDRV_RTS_MAX_VALUE; @@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); if (ret) goto out; @@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (vwrq->disabled) val = MRVDRV_FRAG_MAX_VALUE; @@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); if (ret) goto out; @@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if (!priv->radio_on) { lbs_deb_wext("tx power off\n"); vwrq->value = 0; @@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) return -EOPNOTSUPP; @@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + vwrq->disabled = 0; if (vwrq->flags & IW_RETRY_LONG) { @@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { struct lbs_private *priv = dev->ml_priv; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, "setting power timeout is not supported\n"); return -EINVAL; } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - lbs_deb_wext("setting power period not supported\n"); - return -EINVAL; + vwrq->value = vwrq->value / 1000; + if (!priv->enter_deep_sleep) { + lbs_pr_err("deep sleep feature is not implemented " + "for this interface driver\n"); + return -EINVAL; + } + + if (priv->connect_status == LBS_CONNECTED) { + if ((priv->is_auto_deep_sleep_enabled) && + (vwrq->value == -1000)) { + lbs_exit_auto_deep_sleep(priv); + return 0; + } else { + lbs_pr_err("can't use deep sleep cmd in " + "connected state\n"); + return -EINVAL; + } + } + + if ((vwrq->value < 0) && (vwrq->value != -1000)) { + lbs_pr_err("unknown option\n"); + return -EINVAL; + } + + if (vwrq->value > 0) { + if (!priv->is_auto_deep_sleep_enabled) { + priv->is_activity_detected = 0; + priv->auto_deep_sleep_timeout = vwrq->value; + lbs_enter_auto_deep_sleep(priv); + } else { + priv->auto_deep_sleep_timeout = vwrq->value; + lbs_deb_debugfs("auto deep sleep: " + "already enabled\n"); + } + return 0; + } else { + if (priv->is_auto_deep_sleep_enabled) { + lbs_exit_auto_deep_sleep(priv); + /* Try to exit deep sleep if auto */ + /*deep sleep disabled */ + ret = lbs_set_deep_sleep(priv, 0); + } + if (vwrq->value == 0) + ret = lbs_set_deep_sleep(priv, 1); + else if (vwrq->value == -1000) + ret = lbs_set_deep_sleep(priv, 0); + return ret; + } } if (priv->psmode != LBS802_11POWERMODECAM) { @@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, } lbs_deb_leave(LBS_DEB_WEXT); + return 0; } @@ -792,6 +907,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) + return NULL; + priv->wstats.status = priv->mode; /* If we're not associated, all quality values are meaningless */ @@ -892,6 +1010,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1000,6 +1124,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, u8 rates[MAX_RATES + 1]; lbs_deb_enter(LBS_DEB_WEXT); + + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + lbs_deb_wext("vwrq->value %d\n", vwrq->value); lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); @@ -1058,6 +1188,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + lbs_deb_leave(LBS_DEB_WEXT); + return -EBUSY; + } + if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; @@ -1084,6 +1219,11 @@ static int lbs_set_mode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if ( (*uwrq != IW_MODE_ADHOC) && (*uwrq != IW_MODE_INFRA) && (*uwrq != IW_MODE_AUTO)) { @@ -1325,6 +1465,12 @@ static int lbs_set_encode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1508,6 +1654,12 @@ static int lbs_set_encodeext(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1720,6 +1872,12 @@ static int lbs_set_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1822,6 +1980,12 @@ static int lbs_get_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + switch (dwrq->flags & IW_AUTH_INDEX) { case IW_AUTH_KEY_MGMT: dwrq->value = priv->secinfo.key_mgmt; @@ -1864,6 +2028,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if (vwrq->disabled) { lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); goto out; @@ -1983,6 +2152,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (!priv->radio_on) { ret = -EINVAL; goto out; @@ -2110,6 +2285,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (!priv->radio_on) return -EINVAL; -- cgit v1.2.3-70-g09d2