================================================================================
-                       README for USB8388
+                       README for Libertas
 
  (c) Copyright © 2003-2006, Marvell International Ltd.
  All Rights Reserved
     All entries in the scan table (not just the new scan data when keep=1)
     will be displayed upon completion by use of the getscantable ioctl.
 
+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+       This command is used to configure the station in deep sleep mode /
+       auto deep sleep mode.
+
+       The timer is implemented to monitor the activities (command, event,
+       etc.). When an activity is detected station will exit from deep
+       sleep mode automatically and restart the timer. At timer expiry
+       (no activity for defined time period) the deep sleep mode is entered
+       automatically.
+
+       Note: this command is for SDIO interface only.
+
+       Usage:
+       To enable deep sleep mode do:
+               iwconfig wlan0 power period 0
+       To enable auto deep sleep mode with idle time period 5 seconds do:
+               iwconfig wlan0 power period 5
+       To disable deep sleep/auto deep sleep mode do:
+               iwconfig wlan0 power period -1
+
 ==============================================================================
 
 
 static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
 
-
 /**
  *  @brief Simple callback that copies response back into command
  *
        return 0;
 }
 
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (priv->is_deep_sleep) {
+               if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+                                       !priv->is_deep_sleep, (10 * HZ))) {
+                       lbs_pr_err("ds_awake_q: timer expired\n");
+                       ret = -1;
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+       int ret =  0;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (deep_sleep) {
+               if (priv->is_deep_sleep != 1) {
+                       lbs_deb_cmd("deep sleep: sleep\n");
+                       BUG_ON(!priv->enter_deep_sleep);
+                       ret = priv->enter_deep_sleep(priv);
+                       if (!ret) {
+                               netif_stop_queue(priv->dev);
+                               netif_carrier_off(priv->dev);
+                       }
+               } else {
+                       lbs_pr_err("deep sleep: already enabled\n");
+               }
+       } else {
+               if (priv->is_deep_sleep) {
+                       lbs_deb_cmd("deep sleep: wakeup\n");
+                       BUG_ON(!priv->exit_deep_sleep);
+                       ret = priv->exit_deep_sleep(priv);
+                       if (!ret) {
+                               ret = lbs_wait_for_ds_awake(priv);
+                               if (ret)
+                                       lbs_pr_err("deep sleep: wakeup"
+                                                       "failed\n");
+                       }
+               }
+       }
+
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
+}
+
 int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
                           struct assoc_request *assoc)
 {
                timeo = HZ/4;
        }
 
-       /* Setup the timer after transmit command */
-       mod_timer(&priv->command_timer, jiffies + timeo);
+       if (command == CMD_802_11_DEEP_SLEEP) {
+               if (priv->is_auto_deep_sleep_enabled) {
+                       priv->wakeup_dev_required = 1;
+                       priv->dnld_sent = 0;
+               }
+               priv->is_deep_sleep = 1;
+               lbs_complete_command(priv, cmdnode, 0);
+       } else {
+               /* Setup the timer after transmit command */
+               mod_timer(&priv->command_timer, jiffies + timeo);
+       }
 
        lbs_deb_leave(LBS_DEB_HOST);
 }
        case CMD_802_11_BEACON_CTRL:
                ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
                break;
+       case CMD_802_11_DEEP_SLEEP:
+               cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+               cmdptr->size = cpu_to_le16(S_DS_GEN);
+               break;
        default:
                lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
                ret = -1;
 
 
        case MACREG_INT_CODE_HOST_AWAKE:
                lbs_deb_cmd("EVENT: host awake\n");
+               if (priv->reset_deep_sleep_wakeup)
+                       priv->reset_deep_sleep_wakeup(priv);
+               priv->is_deep_sleep = 0;
                lbs_send_confirmwake(priv);
                break;
 
+       case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+               if (priv->reset_deep_sleep_wakeup)
+                       priv->reset_deep_sleep_wakeup(priv);
+               lbs_deb_cmd("EVENT: ds awake\n");
+               priv->is_deep_sleep = 0;
+               priv->wakeup_dev_required = 0;
+               wake_up_interruptible(&priv->ds_awake_q);
+               break;
+
        case MACREG_INT_CODE_PS_AWAKE:
                lbs_deb_cmd("EVENT: ps awake\n");
                /* handle unexpected PS AWAKE event */
 
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
        buf_size = min(count, len - 1);
        if (copy_from_user(buf, user_buf, buf_size)) {
                ret = -EFAULT;
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
        ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
        if (ret)
                goto out_unlock;
        u8 freq;
        int events = 0;
 
+       if (!lbs_is_cmd_allowed(priv))
+               return -EBUSY;
+
        buf = (char *)get_zeroed_page(GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        char *buf;
        int ret;
 
+       if (!lbs_is_cmd_allowed(priv))
+               return -EBUSY;
+
        buf = (char *)get_zeroed_page(GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               free_page(addr);
+               return -EBUSY;
+       }
+
        offval.offset = priv->mac_offset;
        offval.value = 0;
 
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               res = -EBUSY;
+               goto out_unlock;
+       }
+
        buf_size = min(count, len - 1);
        if (copy_from_user(buf, userbuf, buf_size)) {
                res = -EFAULT;
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               free_page(addr);
+               return -EBUSY;
+       }
+
        offval.offset = priv->bbp_offset;
        offval.value = 0;
 
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               res = -EBUSY;
+               goto out_unlock;
+       }
+
        buf_size = min(count, len - 1);
        if (copy_from_user(buf, userbuf, buf_size)) {
                res = -EFAULT;
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               free_page(addr);
+               return -EBUSY;
+       }
+
        offval.offset = priv->rf_offset;
        offval.value = 0;
 
        if (!buf)
                return -ENOMEM;
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               res = -EBUSY;
+               goto out_unlock;
+       }
+
        buf_size = min(count, len - 1);
        if (copy_from_user(buf, userbuf, buf_size)) {
                res = -EFAULT;
 
 int lbs_process_event(struct lbs_private *priv, u32 event);
 void lbs_queue_event(struct lbs_private *priv, u32 event);
 void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+int lbs_is_cmd_allowed(struct lbs_private *priv);
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
 
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
        u32 bbp_offset;
        u32 rf_offset;
 
+       /** Deep sleep flag */
+       int is_deep_sleep;
+       /** Auto deep sleep enabled flag */
+       int is_auto_deep_sleep_enabled;
+       /** Device wakeup required flag */
+       int wakeup_dev_required;
+       /** Auto deep sleep flag*/
+       int is_activity_detected;
+       /** Auto deep sleep timeout (in miliseconds) */
+       int auto_deep_sleep_timeout;
+
+       /** Deep sleep wait queue */
+       wait_queue_head_t       ds_awake_q;
+
        /* Download sent:
           bit0 1/0=data_sent/data_tx_done,
           bit1 1/0=cmd_sent/cmd_tx_done,
        /** Hardware access */
        int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
        void (*reset_card) (struct lbs_private *priv);
+       int (*enter_deep_sleep) (struct lbs_private *priv);
+       int (*exit_deep_sleep) (struct lbs_private *priv);
+       int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
 
        /* Wake On LAN */
        uint32_t wol_criteria;
 
        /** Timers */
        struct timer_list command_timer;
+       struct timer_list auto_deepsleep_timer;
        int nr_retries;
        int cmd_timed_out;
 
 
 #define CMD_802_11_ENABLE_RSN                  0x002f
 #define CMD_802_11_SET_AFC                     0x003c
 #define CMD_802_11_GET_AFC                     0x003d
+#define CMD_802_11_DEEP_SLEEP                  0x003e
 #define CMD_802_11_AD_HOC_STOP                 0x0040
 #define CMD_802_11_HOST_SLEEP_CFG              0x0043
 #define CMD_802_11_WAKEUP_CONFIRM              0x0044
 
        card->priv = priv;
        priv->card = card;
        priv->hw_host_to_card = if_cs_host_to_card;
+       priv->enter_deep_sleep = NULL;
+       priv->exit_deep_sleep = NULL;
+       priv->reset_deep_sleep_wakeup = NULL;
        priv->fw_ready = 1;
 
        /* Now actually get the IRQ */
 
        return ret;
 }
 
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+       int ret = -1;
+       struct cmd_header cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       lbs_deb_sdio("send DEEP_SLEEP command\n");
+       ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+                       lbs_cmd_copyback, (unsigned long) &cmd);
+       if (ret)
+               lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+       mdelay(200);
+       return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+       sdio_claim_host(card->func);
+
+       sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+       if (ret)
+               lbs_pr_err("sdio_writeb failed!\n");
+
+       sdio_release_host(card->func);
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+       struct if_sdio_card *card = priv->card;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_SDIO);
+       sdio_claim_host(card->func);
+
+       sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+       if (ret)
+               lbs_pr_err("sdio_writeb failed!\n");
+
+       sdio_release_host(card->func);
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       return ret;
+
+}
+
 /*******************************************************************/
 /* SDIO callbacks                                                  */
 /*******************************************************************/
         * Ignore the define name, this really means the card has
         * successfully received the command.
         */
+       card->priv->is_activity_detected = 1;
        if (cause & IF_SDIO_H_INT_DNLD)
                lbs_host_to_card_done(card->priv);
 
 
        priv->card = card;
        priv->hw_host_to_card = if_sdio_host_to_card;
+       priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+       priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+       priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
 
        priv->fw_ready = 1;
 
 
 #define IF_SDIO_EVENT           0x80fc
 
 #define IF_SDIO_BLOCK_SIZE     256
-
+#define CONFIGURATION_REG               0x03
+#define HOST_POWER_UP                   (0x1U << 1)
 #endif
 
        card->priv = priv;
        priv->card = card;
        priv->hw_host_to_card = if_spi_host_to_card;
+       priv->enter_deep_sleep = NULL;
+       priv->exit_deep_sleep = NULL;
+       priv->reset_deep_sleep_wakeup = NULL;
        priv->fw_ready = 1;
 
        /* Initialize interrupt handling stuff. */
 
        cardp->priv->fw_ready = 1;
 
        priv->hw_host_to_card = if_usb_host_to_card;
+       priv->enter_deep_sleep = NULL;
+       priv->exit_deep_sleep = NULL;
+       priv->reset_deep_sleep_wakeup = NULL;
 #ifdef CONFIG_OLPC
        if (machine_is_olpc())
                priv->reset_card = if_usb_reset_olpc_card;
 
        priv->dnld_sent = DNLD_RES_RECEIVED;
 
        /* Wake main thread if commands are pending */
-       if (!priv->cur_cmd || priv->tx_pending_len > 0)
-               wake_up_interruptible(&priv->waitq);
+       if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+               if (!priv->wakeup_dev_required)
+                       wake_up_interruptible(&priv->waitq);
+       }
 
        spin_unlock_irqrestore(&priv->driver_lock, flags);
        lbs_deb_leave(LBS_DEB_THREAD);
                        shouldsleep = 0;        /* We have a command response */
                else if (priv->cur_cmd)
                        shouldsleep = 1;        /* Can't send a command; one already running */
-               else if (!list_empty(&priv->cmdpendingq))
+               else if (!list_empty(&priv->cmdpendingq) &&
+                                       !(priv->wakeup_dev_required))
                        shouldsleep = 0;        /* We have a command to send */
                else if (__kfifo_len(priv->event_fifo))
                        shouldsleep = 0;        /* We have an event to process */
                }
                spin_unlock_irq(&priv->driver_lock);
 
+               /* Process hardware events, e.g. card removed, link lost */
+               spin_lock_irq(&priv->driver_lock);
+               while (__kfifo_len(priv->event_fifo)) {
+                       u32 event;
+                       __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+                               sizeof(event));
+                       spin_unlock_irq(&priv->driver_lock);
+                       lbs_process_event(priv, event);
+                       spin_lock_irq(&priv->driver_lock);
+               }
+               spin_unlock_irq(&priv->driver_lock);
+
+               if (priv->wakeup_dev_required) {
+                       lbs_deb_thread("Waking up device...\n");
+                       /* Wake up device */
+                       if (priv->exit_deep_sleep(priv))
+                               lbs_deb_thread("Wakeup device failed\n");
+                       continue;
+               }
+
                /* command timeout stuff */
                if (priv->cmd_timed_out && priv->cur_cmd) {
                        struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
                }
                priv->cmd_timed_out = 0;
 
-               /* Process hardware events, e.g. card removed, link lost */
-               spin_lock_irq(&priv->driver_lock);
-               while (__kfifo_len(priv->event_fifo)) {
-                       u32 event;
 
-                       __kfifo_get(priv->event_fifo, (unsigned char *) &event,
-                               sizeof(event));
-                       spin_unlock_irq(&priv->driver_lock);
-                       lbs_process_event(priv, event);
-                       spin_lock_irq(&priv->driver_lock);
-               }
-               spin_unlock_irq(&priv->driver_lock);
 
                if (!priv->fw_ready)
                        continue;
                    (priv->psstate == PS_STATE_PRE_SLEEP))
                        continue;
 
+               if (priv->is_deep_sleep)
+                       continue;
+
                /* Execute the next command */
                if (!priv->dnld_sent && !priv->cur_cmd)
                        lbs_execute_next_command(priv);
        }
 
        del_timer(&priv->command_timer);
+       del_timer(&priv->auto_deepsleep_timer);
        wake_up_all(&priv->cmd_pending);
 
        lbs_deb_leave(LBS_DEB_THREAD);
        lbs_deb_leave(LBS_DEB_CMD);
 }
 
+/**
+ *  This function put the device back to deep sleep mode when timer expires
+ *  and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+       struct lbs_private *priv = (struct lbs_private *)data;
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (priv->is_activity_detected) {
+               priv->is_activity_detected = 0;
+       } else {
+               if (priv->is_auto_deep_sleep_enabled &&
+                               (!priv->wakeup_dev_required) &&
+                               (priv->connect_status != LBS_CONNECTED)) {
+                       lbs_deb_main("Entering auto deep sleep mode...\n");
+                       ret = lbs_prepare_and_send_command(priv,
+                                       CMD_802_11_DEEP_SLEEP, 0,
+                                       0, 0, NULL);
+               }
+       }
+       mod_timer(&priv->auto_deepsleep_timer , jiffies +
+                               (priv->auto_deep_sleep_timeout * HZ)/1000);
+       lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       priv->is_auto_deep_sleep_enabled = 1;
+       if (priv->is_deep_sleep)
+               priv->wakeup_dev_required = 1;
+       mod_timer(&priv->auto_deepsleep_timer ,
+                       jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+       return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+       lbs_deb_enter(LBS_DEB_SDIO);
+
+       priv->is_auto_deep_sleep_enabled = 0;
+       priv->auto_deep_sleep_timeout = 0;
+       del_timer(&priv->auto_deepsleep_timer);
+
+       lbs_deb_leave(LBS_DEB_SDIO);
+       return 0;
+}
+
 static void lbs_sync_channel_worker(struct work_struct *work)
 {
        struct lbs_private *priv = container_of(work, struct lbs_private,
        priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
        priv->psmode = LBS802_11POWERMODECAM;
        priv->psstate = PS_STATE_FULL_POWER;
+       priv->is_deep_sleep = 0;
+       priv->is_auto_deep_sleep_enabled = 0;
+       priv->wakeup_dev_required = 0;
+       init_waitqueue_head(&priv->ds_awake_q);
 
        mutex_init(&priv->lock);
 
        setup_timer(&priv->command_timer, command_timer_fn,
                (unsigned long)priv);
+       setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+                       (unsigned long)priv);
 
        INIT_LIST_HEAD(&priv->cmdfreeq);
        INIT_LIST_HEAD(&priv->cmdpendingq);
        if (priv->event_fifo)
                kfifo_free(priv->event_fifo);
        del_timer(&priv->command_timer);
+       del_timer(&priv->auto_deepsleep_timer);
        kfree(priv->networks);
        priv->networks = NULL;
 
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
+       if (priv->is_deep_sleep) {
+               priv->is_deep_sleep = 0;
+               wake_up_interruptible(&priv->ds_awake_q);
+       }
+
        /* Stop the thread servicing the interrupts */
        priv->surpriseremoved = 1;
        kthread_stop(priv->main_thread);
 
        /* Delete the timeout of the currently processing command */
        del_timer_sync(&priv->command_timer);
+       del_timer_sync(&priv->auto_deepsleep_timer);
 
        /* Flush pending command nodes */
        spin_lock_irqsave(&priv->driver_lock, flags);
 
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
        if (!priv->radio_on) {
                ret = -EINVAL;
                goto out;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
+       if (!lbs_is_cmd_allowed(priv)) {
+               err = -EBUSY;
+               lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
+               return err;
+       }
+
        /* iwlist should wait until the current scan is finished */
        if (priv->scan_channel)
                return -EAGAIN;
 
        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
 
        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);
 
 
        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;
 
 
        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;
 
        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;
 
 
        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;
 
        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;
 
        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;
 
 
        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) {
                          struct iw_param *vwrq, char *extra)
 {
        struct lbs_private *priv = dev->ml_priv;
+       int ret = 0;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
                       "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) {
        }
 
        lbs_deb_leave(LBS_DEB_WEXT);
+
        return 0;
 }
 
 
        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 */
 
        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) {
        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);
 
 
        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;
 
 
        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)) {
 
        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) {
 
        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) {
 
        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) {
 
        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;
 
        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;
 
        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;
 
        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;