libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
[pandora-kernel.git] / drivers / net / wireless / libertas / wext.c
index be837a0..38a451e 100644 (file)
@@ -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;