aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2009-09-30 23:04:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-07 16:39:43 -0400
commit4912545472d71e3dd546b18b397aec4c89fd7403 (patch)
treeb7b0d520cdbee35303caf69881f7898e38966bc7 /drivers/net/wireless/libertas
parent125b181aec7a67c71234284ecf6d9c729d05deda (diff)
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 <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/README26
-rw-r--r--drivers/net/wireless/libertas/cmd.c72
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c12
-rw-r--r--drivers/net/wireless/libertas/debugfs.c46
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/dev.h18
-rw-r--r--drivers/net/wireless/libertas/host.h1
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c56
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h3
-rw-r--r--drivers/net/wireless/libertas/if_spi.c3
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/main.c111
-rw-r--r--drivers/net/wireless/libertas/scan.c11
-rw-r--r--drivers/net/wireless/libertas/wext.c185
15 files changed, 533 insertions, 21 deletions
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d518af0..2726c044430f 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
1================================================================================ 1================================================================================
2 README for USB8388 2 README for Libertas
3 3
4 (c) Copyright © 2003-2006, Marvell International Ltd. 4 (c) Copyright © 2003-2006, Marvell International Ltd.
5 All Rights Reserved 5 All Rights Reserved
@@ -226,4 +226,28 @@ setuserscan
226 All entries in the scan table (not just the new scan data when keep=1) 226 All entries in the scan table (not just the new scan data when keep=1)
227 will be displayed upon completion by use of the getscantable ioctl. 227 will be displayed upon completion by use of the getscantable ioctl.
228 228
229========================
230IWCONFIG COMMANDS
231========================
232power period
233
234 This command is used to configure the station in deep sleep mode /
235 auto deep sleep mode.
236
237 The timer is implemented to monitor the activities (command, event,
238 etc.). When an activity is detected station will exit from deep
239 sleep mode automatically and restart the timer. At timer expiry
240 (no activity for defined time period) the deep sleep mode is entered
241 automatically.
242
243 Note: this command is for SDIO interface only.
244
245 Usage:
246 To enable deep sleep mode do:
247 iwconfig wlan0 power period 0
248 To enable auto deep sleep mode with idle time period 5 seconds do:
249 iwconfig wlan0 power period 5
250 To disable deep sleep/auto deep sleep mode do:
251 iwconfig wlan0 power period -1
252
229============================================================================== 253==============================================================================
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 685098148e10..3a3e8947e84a 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -17,7 +17,6 @@
17 17
18static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); 18static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
19 19
20
21/** 20/**
22 * @brief Simple callback that copies response back into command 21 * @brief Simple callback that copies response back into command
23 * 22 *
@@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
319 return 0; 318 return 0;
320} 319}
321 320
321static int lbs_wait_for_ds_awake(struct lbs_private *priv)
322{
323 int ret = 0;
324
325 lbs_deb_enter(LBS_DEB_CMD);
326
327 if (priv->is_deep_sleep) {
328 if (!wait_event_interruptible_timeout(priv->ds_awake_q,
329 !priv->is_deep_sleep, (10 * HZ))) {
330 lbs_pr_err("ds_awake_q: timer expired\n");
331 ret = -1;
332 }
333 }
334
335 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
336 return ret;
337}
338
339int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
340{
341 int ret = 0;
342
343 lbs_deb_enter(LBS_DEB_CMD);
344
345 if (deep_sleep) {
346 if (priv->is_deep_sleep != 1) {
347 lbs_deb_cmd("deep sleep: sleep\n");
348 BUG_ON(!priv->enter_deep_sleep);
349 ret = priv->enter_deep_sleep(priv);
350 if (!ret) {
351 netif_stop_queue(priv->dev);
352 netif_carrier_off(priv->dev);
353 }
354 } else {
355 lbs_pr_err("deep sleep: already enabled\n");
356 }
357 } else {
358 if (priv->is_deep_sleep) {
359 lbs_deb_cmd("deep sleep: wakeup\n");
360 BUG_ON(!priv->exit_deep_sleep);
361 ret = priv->exit_deep_sleep(priv);
362 if (!ret) {
363 ret = lbs_wait_for_ds_awake(priv);
364 if (ret)
365 lbs_pr_err("deep sleep: wakeup"
366 "failed\n");
367 }
368 }
369 }
370
371 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
372 return ret;
373}
374
322int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, 375int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
323 struct assoc_request *assoc) 376 struct assoc_request *assoc)
324{ 377{
@@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv,
1242 timeo = HZ/4; 1295 timeo = HZ/4;
1243 } 1296 }
1244 1297
1245 /* Setup the timer after transmit command */ 1298 if (command == CMD_802_11_DEEP_SLEEP) {
1246 mod_timer(&priv->command_timer, jiffies + timeo); 1299 if (priv->is_auto_deep_sleep_enabled) {
1300 priv->wakeup_dev_required = 1;
1301 priv->dnld_sent = 0;
1302 }
1303 priv->is_deep_sleep = 1;
1304 lbs_complete_command(priv, cmdnode, 0);
1305 } else {
1306 /* Setup the timer after transmit command */
1307 mod_timer(&priv->command_timer, jiffies + timeo);
1308 }
1247 1309
1248 lbs_deb_leave(LBS_DEB_HOST); 1310 lbs_deb_leave(LBS_DEB_HOST);
1249} 1311}
@@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
1505 case CMD_802_11_BEACON_CTRL: 1567 case CMD_802_11_BEACON_CTRL:
1506 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); 1568 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
1507 break; 1569 break;
1570 case CMD_802_11_DEEP_SLEEP:
1571 cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
1572 cmdptr->size = cpu_to_le16(S_DS_GEN);
1573 break;
1508 default: 1574 default:
1509 lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); 1575 lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
1510 ret = -1; 1576 ret = -1;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index c42d3faa2660..47d2b1909d69 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
504 504
505 case MACREG_INT_CODE_HOST_AWAKE: 505 case MACREG_INT_CODE_HOST_AWAKE:
506 lbs_deb_cmd("EVENT: host awake\n"); 506 lbs_deb_cmd("EVENT: host awake\n");
507 if (priv->reset_deep_sleep_wakeup)
508 priv->reset_deep_sleep_wakeup(priv);
509 priv->is_deep_sleep = 0;
507 lbs_send_confirmwake(priv); 510 lbs_send_confirmwake(priv);
508 break; 511 break;
509 512
513 case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
514 if (priv->reset_deep_sleep_wakeup)
515 priv->reset_deep_sleep_wakeup(priv);
516 lbs_deb_cmd("EVENT: ds awake\n");
517 priv->is_deep_sleep = 0;
518 priv->wakeup_dev_required = 0;
519 wake_up_interruptible(&priv->ds_awake_q);
520 break;
521
510 case MACREG_INT_CODE_PS_AWAKE: 522 case MACREG_INT_CODE_PS_AWAKE:
511 lbs_deb_cmd("EVENT: ps awake\n"); 523 lbs_deb_cmd("EVENT: ps awake\n");
512 /* handle unexpected PS AWAKE event */ 524 /* handle unexpected PS AWAKE event */
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55ca344a..8a7e9319c9e5 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file,
117 if (!buf) 117 if (!buf)
118 return -ENOMEM; 118 return -ENOMEM;
119 119
120 if (!lbs_is_cmd_allowed(priv)) {
121 ret = -EBUSY;
122 goto out_unlock;
123 }
124
120 buf_size = min(count, len - 1); 125 buf_size = min(count, len - 1);
121 if (copy_from_user(buf, user_buf, buf_size)) { 126 if (copy_from_user(buf, user_buf, buf_size)) {
122 ret = -EFAULT; 127 ret = -EFAULT;
@@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
157 if (!buf) 162 if (!buf)
158 return -ENOMEM; 163 return -ENOMEM;
159 164
165 if (!lbs_is_cmd_allowed(priv)) {
166 ret = -EBUSY;
167 goto out_unlock;
168 }
169
160 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); 170 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
161 if (ret) 171 if (ret)
162 goto out_unlock; 172 goto out_unlock;
@@ -223,6 +233,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
223 u8 freq; 233 u8 freq;
224 int events = 0; 234 int events = 0;
225 235
236 if (!lbs_is_cmd_allowed(priv))
237 return -EBUSY;
238
226 buf = (char *)get_zeroed_page(GFP_KERNEL); 239 buf = (char *)get_zeroed_page(GFP_KERNEL);
227 if (!buf) 240 if (!buf)
228 return -ENOMEM; 241 return -ENOMEM;
@@ -275,6 +288,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
275 char *buf; 288 char *buf;
276 int ret; 289 int ret;
277 290
291 if (!lbs_is_cmd_allowed(priv))
292 return -EBUSY;
293
278 buf = (char *)get_zeroed_page(GFP_KERNEL); 294 buf = (char *)get_zeroed_page(GFP_KERNEL);
279 if (!buf) 295 if (!buf)
280 return -ENOMEM; 296 return -ENOMEM;
@@ -444,6 +460,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
444 if (!buf) 460 if (!buf)
445 return -ENOMEM; 461 return -ENOMEM;
446 462
463 if (!lbs_is_cmd_allowed(priv)) {
464 free_page(addr);
465 return -EBUSY;
466 }
467
447 offval.offset = priv->mac_offset; 468 offval.offset = priv->mac_offset;
448 offval.value = 0; 469 offval.value = 0;
449 470
@@ -496,6 +517,11 @@ static ssize_t lbs_wrmac_write(struct file *file,
496 if (!buf) 517 if (!buf)
497 return -ENOMEM; 518 return -ENOMEM;
498 519
520 if (!lbs_is_cmd_allowed(priv)) {
521 res = -EBUSY;
522 goto out_unlock;
523 }
524
499 buf_size = min(count, len - 1); 525 buf_size = min(count, len - 1);
500 if (copy_from_user(buf, userbuf, buf_size)) { 526 if (copy_from_user(buf, userbuf, buf_size)) {
501 res = -EFAULT; 527 res = -EFAULT;
@@ -532,6 +558,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
532 if (!buf) 558 if (!buf)
533 return -ENOMEM; 559 return -ENOMEM;
534 560
561 if (!lbs_is_cmd_allowed(priv)) {
562 free_page(addr);
563 return -EBUSY;
564 }
565
535 offval.offset = priv->bbp_offset; 566 offval.offset = priv->bbp_offset;
536 offval.value = 0; 567 offval.value = 0;
537 568
@@ -585,6 +616,11 @@ static ssize_t lbs_wrbbp_write(struct file *file,
585 if (!buf) 616 if (!buf)
586 return -ENOMEM; 617 return -ENOMEM;
587 618
619 if (!lbs_is_cmd_allowed(priv)) {
620 res = -EBUSY;
621 goto out_unlock;
622 }
623
588 buf_size = min(count, len - 1); 624 buf_size = min(count, len - 1);
589 if (copy_from_user(buf, userbuf, buf_size)) { 625 if (copy_from_user(buf, userbuf, buf_size)) {
590 res = -EFAULT; 626 res = -EFAULT;
@@ -621,6 +657,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
621 if (!buf) 657 if (!buf)
622 return -ENOMEM; 658 return -ENOMEM;
623 659
660 if (!lbs_is_cmd_allowed(priv)) {
661 free_page(addr);
662 return -EBUSY;
663 }
664
624 offval.offset = priv->rf_offset; 665 offval.offset = priv->rf_offset;
625 offval.value = 0; 666 offval.value = 0;
626 667
@@ -674,6 +715,11 @@ static ssize_t lbs_wrrf_write(struct file *file,
674 if (!buf) 715 if (!buf)
675 return -ENOMEM; 716 return -ENOMEM;
676 717
718 if (!lbs_is_cmd_allowed(priv)) {
719 res = -EBUSY;
720 goto out_unlock;
721 }
722
677 buf_size = min(count, len - 1); 723 buf_size = min(count, len - 1);
678 if (copy_from_user(buf, userbuf, buf_size)) { 724 if (copy_from_user(buf, userbuf, buf_size)) {
679 res = -EFAULT; 725 res = -EFAULT;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 8b15380ae6e1..44f0b248ace9 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv);
33int lbs_process_event(struct lbs_private *priv, u32 event); 33int lbs_process_event(struct lbs_private *priv, u32 event);
34void lbs_queue_event(struct lbs_private *priv, u32 event); 34void lbs_queue_event(struct lbs_private *priv, u32 event);
35void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); 35void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
36int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
37int lbs_is_cmd_allowed(struct lbs_private *priv);
38int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
39int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
36 40
37u32 lbs_fw_index_to_data_rate(u8 index); 41u32 lbs_fw_index_to_data_rate(u8 index);
38u8 lbs_data_rate_to_fw_index(u32 rate); 42u8 lbs_data_rate_to_fw_index(u32 rate);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index d3b69a4b4b5e..0018df14fad9 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -129,6 +129,20 @@ struct lbs_private {
129 u32 bbp_offset; 129 u32 bbp_offset;
130 u32 rf_offset; 130 u32 rf_offset;
131 131
132 /** Deep sleep flag */
133 int is_deep_sleep;
134 /** Auto deep sleep enabled flag */
135 int is_auto_deep_sleep_enabled;
136 /** Device wakeup required flag */
137 int wakeup_dev_required;
138 /** Auto deep sleep flag*/
139 int is_activity_detected;
140 /** Auto deep sleep timeout (in miliseconds) */
141 int auto_deep_sleep_timeout;
142
143 /** Deep sleep wait queue */
144 wait_queue_head_t ds_awake_q;
145
132 /* Download sent: 146 /* Download sent:
133 bit0 1/0=data_sent/data_tx_done, 147 bit0 1/0=data_sent/data_tx_done,
134 bit1 1/0=cmd_sent/cmd_tx_done, 148 bit1 1/0=cmd_sent/cmd_tx_done,
@@ -154,6 +168,9 @@ struct lbs_private {
154 /** Hardware access */ 168 /** Hardware access */
155 int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); 169 int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
156 void (*reset_card) (struct lbs_private *priv); 170 void (*reset_card) (struct lbs_private *priv);
171 int (*enter_deep_sleep) (struct lbs_private *priv);
172 int (*exit_deep_sleep) (struct lbs_private *priv);
173 int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
157 174
158 /* Wake On LAN */ 175 /* Wake On LAN */
159 uint32_t wol_criteria; 176 uint32_t wol_criteria;
@@ -204,6 +221,7 @@ struct lbs_private {
204 221
205 /** Timers */ 222 /** Timers */
206 struct timer_list command_timer; 223 struct timer_list command_timer;
224 struct timer_list auto_deepsleep_timer;
207 int nr_retries; 225 int nr_retries;
208 int cmd_timed_out; 226 int cmd_timed_out;
209 227
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb737bc..c055daabea13 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -57,6 +57,7 @@
57#define CMD_802_11_ENABLE_RSN 0x002f 57#define CMD_802_11_ENABLE_RSN 0x002f
58#define CMD_802_11_SET_AFC 0x003c 58#define CMD_802_11_SET_AFC 0x003c
59#define CMD_802_11_GET_AFC 0x003d 59#define CMD_802_11_GET_AFC 0x003d
60#define CMD_802_11_DEEP_SLEEP 0x003e
60#define CMD_802_11_AD_HOC_STOP 0x0040 61#define CMD_802_11_AD_HOC_STOP 0x0040
61#define CMD_802_11_HOST_SLEEP_CFG 0x0043 62#define CMD_802_11_HOST_SLEEP_CFG 0x0043
62#define CMD_802_11_WAKEUP_CONFIRM 0x0044 63#define CMD_802_11_WAKEUP_CONFIRM 0x0044
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 62381768f2d5..465742f19ecb 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
946 card->priv = priv; 946 card->priv = priv;
947 priv->card = card; 947 priv->card = card;
948 priv->hw_host_to_card = if_cs_host_to_card; 948 priv->hw_host_to_card = if_cs_host_to_card;
949 priv->enter_deep_sleep = NULL;
950 priv->exit_deep_sleep = NULL;
951 priv->reset_deep_sleep_wakeup = NULL;
949 priv->fw_ready = 1; 952 priv->fw_ready = 1;
950 953
951 /* Now actually get the IRQ */ 954 /* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d406525..9716728a33cb 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -831,6 +831,58 @@ out:
831 return ret; 831 return ret;
832} 832}
833 833
834static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
835{
836 int ret = -1;
837 struct cmd_header cmd;
838
839 memset(&cmd, 0, sizeof(cmd));
840
841 lbs_deb_sdio("send DEEP_SLEEP command\n");
842 ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
843 lbs_cmd_copyback, (unsigned long) &cmd);
844 if (ret)
845 lbs_pr_err("DEEP_SLEEP cmd failed\n");
846
847 mdelay(200);
848 return ret;
849}
850
851static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
852{
853 struct if_sdio_card *card = priv->card;
854 int ret = -1;
855
856 lbs_deb_enter(LBS_DEB_SDIO);
857 sdio_claim_host(card->func);
858
859 sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
860 if (ret)
861 lbs_pr_err("sdio_writeb failed!\n");
862
863 sdio_release_host(card->func);
864 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
865 return ret;
866}
867
868static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
869{
870 struct if_sdio_card *card = priv->card;
871 int ret = -1;
872
873 lbs_deb_enter(LBS_DEB_SDIO);
874 sdio_claim_host(card->func);
875
876 sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
877 if (ret)
878 lbs_pr_err("sdio_writeb failed!\n");
879
880 sdio_release_host(card->func);
881 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
882 return ret;
883
884}
885
834/*******************************************************************/ 886/*******************************************************************/
835/* SDIO callbacks */ 887/* SDIO callbacks */
836/*******************************************************************/ 888/*******************************************************************/
@@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
859 * Ignore the define name, this really means the card has 911 * Ignore the define name, this really means the card has
860 * successfully received the command. 912 * successfully received the command.
861 */ 913 */
914 card->priv->is_activity_detected = 1;
862 if (cause & IF_SDIO_H_INT_DNLD) 915 if (cause & IF_SDIO_H_INT_DNLD)
863 lbs_host_to_card_done(card->priv); 916 lbs_host_to_card_done(card->priv);
864 917
@@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
998 1051
999 priv->card = card; 1052 priv->card = card;
1000 priv->hw_host_to_card = if_sdio_host_to_card; 1053 priv->hw_host_to_card = if_sdio_host_to_card;
1054 priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
1055 priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
1056 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
1001 1057
1002 priv->fw_ready = 1; 1058 priv->fw_ready = 1;
1003 1059
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2fcef03..12179c1dc9c9 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
51#define IF_SDIO_EVENT 0x80fc 51#define IF_SDIO_EVENT 0x80fc
52 52
53#define IF_SDIO_BLOCK_SIZE 256 53#define IF_SDIO_BLOCK_SIZE 256
54 54#define CONFIGURATION_REG 0x03
55#define HOST_POWER_UP (0x1U << 1)
55#endif 56#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index cb8be8d7abc1..06df2e174b50 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
1117 card->priv = priv; 1117 card->priv = priv;
1118 priv->card = card; 1118 priv->card = card;
1119 priv->hw_host_to_card = if_spi_host_to_card; 1119 priv->hw_host_to_card = if_spi_host_to_card;
1120 priv->enter_deep_sleep = NULL;
1121 priv->exit_deep_sleep = NULL;
1122 priv->reset_deep_sleep_wakeup = NULL;
1120 priv->fw_ready = 1; 1123 priv->fw_ready = 1;
1121 1124
1122 /* Initialize interrupt handling stuff. */ 1125 /* Initialize interrupt handling stuff. */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 92bc8c5f1ca2..a8262dea9b1f 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
300 cardp->priv->fw_ready = 1; 300 cardp->priv->fw_ready = 1;
301 301
302 priv->hw_host_to_card = if_usb_host_to_card; 302 priv->hw_host_to_card = if_usb_host_to_card;
303 priv->enter_deep_sleep = NULL;
304 priv->exit_deep_sleep = NULL;
305 priv->reset_deep_sleep_wakeup = NULL;
303#ifdef CONFIG_OLPC 306#ifdef CONFIG_OLPC
304 if (machine_is_olpc()) 307 if (machine_is_olpc())
305 priv->reset_card = if_usb_reset_olpc_card; 308 priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 87b4e497faa2..9b2a9174a017 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
574 priv->dnld_sent = DNLD_RES_RECEIVED; 574 priv->dnld_sent = DNLD_RES_RECEIVED;
575 575
576 /* Wake main thread if commands are pending */ 576 /* Wake main thread if commands are pending */
577 if (!priv->cur_cmd || priv->tx_pending_len > 0) 577 if (!priv->cur_cmd || priv->tx_pending_len > 0) {
578 wake_up_interruptible(&priv->waitq); 578 if (!priv->wakeup_dev_required)
579 wake_up_interruptible(&priv->waitq);
580 }
579 581
580 spin_unlock_irqrestore(&priv->driver_lock, flags); 582 spin_unlock_irqrestore(&priv->driver_lock, flags);
581 lbs_deb_leave(LBS_DEB_THREAD); 583 lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +772,8 @@ static int lbs_thread(void *data)
770 shouldsleep = 0; /* We have a command response */ 772 shouldsleep = 0; /* We have a command response */
771 else if (priv->cur_cmd) 773 else if (priv->cur_cmd)
772 shouldsleep = 1; /* Can't send a command; one already running */ 774 shouldsleep = 1; /* Can't send a command; one already running */
773 else if (!list_empty(&priv->cmdpendingq)) 775 else if (!list_empty(&priv->cmdpendingq) &&
776 !(priv->wakeup_dev_required))
774 shouldsleep = 0; /* We have a command to send */ 777 shouldsleep = 0; /* We have a command to send */
775 else if (__kfifo_len(priv->event_fifo)) 778 else if (__kfifo_len(priv->event_fifo))
776 shouldsleep = 0; /* We have an event to process */ 779 shouldsleep = 0; /* We have an event to process */
@@ -822,6 +825,26 @@ static int lbs_thread(void *data)
822 } 825 }
823 spin_unlock_irq(&priv->driver_lock); 826 spin_unlock_irq(&priv->driver_lock);
824 827
828 /* Process hardware events, e.g. card removed, link lost */
829 spin_lock_irq(&priv->driver_lock);
830 while (__kfifo_len(priv->event_fifo)) {
831 u32 event;
832 __kfifo_get(priv->event_fifo, (unsigned char *) &event,
833 sizeof(event));
834 spin_unlock_irq(&priv->driver_lock);
835 lbs_process_event(priv, event);
836 spin_lock_irq(&priv->driver_lock);
837 }
838 spin_unlock_irq(&priv->driver_lock);
839
840 if (priv->wakeup_dev_required) {
841 lbs_deb_thread("Waking up device...\n");
842 /* Wake up device */
843 if (priv->exit_deep_sleep(priv))
844 lbs_deb_thread("Wakeup device failed\n");
845 continue;
846 }
847
825 /* command timeout stuff */ 848 /* command timeout stuff */
826 if (priv->cmd_timed_out && priv->cur_cmd) { 849 if (priv->cmd_timed_out && priv->cur_cmd) {
827 struct cmd_ctrl_node *cmdnode = priv->cur_cmd; 850 struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +872,7 @@ static int lbs_thread(void *data)
849 } 872 }
850 priv->cmd_timed_out = 0; 873 priv->cmd_timed_out = 0;
851 874
852 /* Process hardware events, e.g. card removed, link lost */
853 spin_lock_irq(&priv->driver_lock);
854 while (__kfifo_len(priv->event_fifo)) {
855 u32 event;
856 875
857 __kfifo_get(priv->event_fifo, (unsigned char *) &event,
858 sizeof(event));
859 spin_unlock_irq(&priv->driver_lock);
860 lbs_process_event(priv, event);
861 spin_lock_irq(&priv->driver_lock);
862 }
863 spin_unlock_irq(&priv->driver_lock);
864 876
865 if (!priv->fw_ready) 877 if (!priv->fw_ready)
866 continue; 878 continue;
@@ -894,6 +906,9 @@ static int lbs_thread(void *data)
894 (priv->psstate == PS_STATE_PRE_SLEEP)) 906 (priv->psstate == PS_STATE_PRE_SLEEP))
895 continue; 907 continue;
896 908
909 if (priv->is_deep_sleep)
910 continue;
911
897 /* Execute the next command */ 912 /* Execute the next command */
898 if (!priv->dnld_sent && !priv->cur_cmd) 913 if (!priv->dnld_sent && !priv->cur_cmd)
899 lbs_execute_next_command(priv); 914 lbs_execute_next_command(priv);
@@ -928,6 +943,7 @@ static int lbs_thread(void *data)
928 } 943 }
929 944
930 del_timer(&priv->command_timer); 945 del_timer(&priv->command_timer);
946 del_timer(&priv->auto_deepsleep_timer);
931 wake_up_all(&priv->cmd_pending); 947 wake_up_all(&priv->cmd_pending);
932 948
933 lbs_deb_leave(LBS_DEB_THREAD); 949 lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +1066,60 @@ out:
1050 lbs_deb_leave(LBS_DEB_CMD); 1066 lbs_deb_leave(LBS_DEB_CMD);
1051} 1067}
1052 1068
1069/**
1070 * This function put the device back to deep sleep mode when timer expires
1071 * and no activity (command, event, data etc.) is detected.
1072 */
1073static void auto_deepsleep_timer_fn(unsigned long data)
1074{
1075 struct lbs_private *priv = (struct lbs_private *)data;
1076 int ret;
1077
1078 lbs_deb_enter(LBS_DEB_CMD);
1079
1080 if (priv->is_activity_detected) {
1081 priv->is_activity_detected = 0;
1082 } else {
1083 if (priv->is_auto_deep_sleep_enabled &&
1084 (!priv->wakeup_dev_required) &&
1085 (priv->connect_status != LBS_CONNECTED)) {
1086 lbs_deb_main("Entering auto deep sleep mode...\n");
1087 ret = lbs_prepare_and_send_command(priv,
1088 CMD_802_11_DEEP_SLEEP, 0,
1089 0, 0, NULL);
1090 }
1091 }
1092 mod_timer(&priv->auto_deepsleep_timer , jiffies +
1093 (priv->auto_deep_sleep_timeout * HZ)/1000);
1094 lbs_deb_leave(LBS_DEB_CMD);
1095}
1096
1097int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
1098{
1099 lbs_deb_enter(LBS_DEB_SDIO);
1100
1101 priv->is_auto_deep_sleep_enabled = 1;
1102 if (priv->is_deep_sleep)
1103 priv->wakeup_dev_required = 1;
1104 mod_timer(&priv->auto_deepsleep_timer ,
1105 jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
1106
1107 lbs_deb_leave(LBS_DEB_SDIO);
1108 return 0;
1109}
1110
1111int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
1112{
1113 lbs_deb_enter(LBS_DEB_SDIO);
1114
1115 priv->is_auto_deep_sleep_enabled = 0;
1116 priv->auto_deep_sleep_timeout = 0;
1117 del_timer(&priv->auto_deepsleep_timer);
1118
1119 lbs_deb_leave(LBS_DEB_SDIO);
1120 return 0;
1121}
1122
1053static void lbs_sync_channel_worker(struct work_struct *work) 1123static void lbs_sync_channel_worker(struct work_struct *work)
1054{ 1124{
1055 struct lbs_private *priv = container_of(work, struct lbs_private, 1125 struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
1099 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; 1169 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
1100 priv->psmode = LBS802_11POWERMODECAM; 1170 priv->psmode = LBS802_11POWERMODECAM;
1101 priv->psstate = PS_STATE_FULL_POWER; 1171 priv->psstate = PS_STATE_FULL_POWER;
1172 priv->is_deep_sleep = 0;
1173 priv->is_auto_deep_sleep_enabled = 0;
1174 priv->wakeup_dev_required = 0;
1175 init_waitqueue_head(&priv->ds_awake_q);
1102 1176
1103 mutex_init(&priv->lock); 1177 mutex_init(&priv->lock);
1104 1178
1105 setup_timer(&priv->command_timer, command_timer_fn, 1179 setup_timer(&priv->command_timer, command_timer_fn,
1106 (unsigned long)priv); 1180 (unsigned long)priv);
1181 setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
1182 (unsigned long)priv);
1107 1183
1108 INIT_LIST_HEAD(&priv->cmdfreeq); 1184 INIT_LIST_HEAD(&priv->cmdfreeq);
1109 INIT_LIST_HEAD(&priv->cmdpendingq); 1185 INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
1142 if (priv->event_fifo) 1218 if (priv->event_fifo)
1143 kfifo_free(priv->event_fifo); 1219 kfifo_free(priv->event_fifo);
1144 del_timer(&priv->command_timer); 1220 del_timer(&priv->command_timer);
1221 del_timer(&priv->auto_deepsleep_timer);
1145 kfree(priv->networks); 1222 kfree(priv->networks);
1146 priv->networks = NULL; 1223 priv->networks = NULL;
1147 1224
@@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
1272 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 1349 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1273 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); 1350 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
1274 1351
1352 if (priv->is_deep_sleep) {
1353 priv->is_deep_sleep = 0;
1354 wake_up_interruptible(&priv->ds_awake_q);
1355 }
1356
1275 /* Stop the thread servicing the interrupts */ 1357 /* Stop the thread servicing the interrupts */
1276 priv->surpriseremoved = 1; 1358 priv->surpriseremoved = 1;
1277 kthread_stop(priv->main_thread); 1359 kthread_stop(priv->main_thread);
@@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)
1392 1474
1393 /* Delete the timeout of the currently processing command */ 1475 /* Delete the timeout of the currently processing command */
1394 del_timer_sync(&priv->command_timer); 1476 del_timer_sync(&priv->command_timer);
1477 del_timer_sync(&priv->auto_deepsleep_timer);
1395 1478
1396 /* Flush pending command nodes */ 1479 /* Flush pending command nodes */
1397 spin_lock_irqsave(&priv->driver_lock, flags); 1480 spin_lock_irqsave(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3023cc..e468e155e8be 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
950 950
951 lbs_deb_enter(LBS_DEB_WEXT); 951 lbs_deb_enter(LBS_DEB_WEXT);
952 952
953 if (!lbs_is_cmd_allowed(priv)) {
954 ret = -EBUSY;
955 goto out;
956 }
957
953 if (!priv->radio_on) { 958 if (!priv->radio_on) {
954 ret = -EINVAL; 959 ret = -EINVAL;
955 goto out; 960 goto out;
@@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
1017 1022
1018 lbs_deb_enter(LBS_DEB_WEXT); 1023 lbs_deb_enter(LBS_DEB_WEXT);
1019 1024
1025 if (!lbs_is_cmd_allowed(priv)) {
1026 err = -EBUSY;
1027 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
1028 return err;
1029 }
1030
1020 /* iwlist should wait until the current scan is finished */ 1031 /* iwlist should wait until the current scan is finished */
1021 if (priv->scan_channel) 1032 if (priv->scan_channel)
1022 return -EAGAIN; 1033 return -EAGAIN;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0d2517..38a451edb703 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)
45 priv->pending_assoc_req = NULL; 45 priv->pending_assoc_req = NULL;
46} 46}
47 47
48/**
49 * @brief This function checks if the command is allowed.
50 *
51 * @param priv A pointer to lbs_private structure
52 * @return allowed or not allowed.
53 */
54
55int lbs_is_cmd_allowed(struct lbs_private *priv)
56{
57 int ret = 1;
58
59 lbs_deb_enter(LBS_DEB_WEXT);
60
61 if (!priv->is_auto_deep_sleep_enabled) {
62 if (priv->is_deep_sleep) {
63 lbs_deb_wext("IOCTLS called when station"
64 "is in deep sleep\n");
65 ret = 0;
66 }
67 }
68
69 lbs_deb_leave(LBS_DEB_WEXT);
70 return ret;
71}
72
48 73
49/** 74/**
50 * @brief Find the channel frequency power info with specific channel 75 * @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,
168 193
169 lbs_deb_enter(LBS_DEB_WEXT); 194 lbs_deb_enter(LBS_DEB_WEXT);
170 195
196 if (!lbs_is_cmd_allowed(priv)) {
197 lbs_deb_leave(LBS_DEB_WEXT);
198 return -EBUSY;
199 }
200
171 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, 201 cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
172 priv->curbssparams.channel); 202 priv->curbssparams.channel);
173 203
@@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
278 308
279 lbs_deb_enter(LBS_DEB_WEXT); 309 lbs_deb_enter(LBS_DEB_WEXT);
280 310
311 if (!lbs_is_cmd_allowed(priv)) {
312 ret = -EBUSY;
313 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
314 return ret;
315 }
316
281 if (vwrq->disabled) 317 if (vwrq->disabled)
282 val = MRVDRV_RTS_MAX_VALUE; 318 val = MRVDRV_RTS_MAX_VALUE;
283 319
@@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
299 335
300 lbs_deb_enter(LBS_DEB_WEXT); 336 lbs_deb_enter(LBS_DEB_WEXT);
301 337
338 if (!lbs_is_cmd_allowed(priv)) {
339 ret = -EBUSY;
340 goto out;
341 }
342
302 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); 343 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
303 if (ret) 344 if (ret)
304 goto out; 345 goto out;
@@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
321 362
322 lbs_deb_enter(LBS_DEB_WEXT); 363 lbs_deb_enter(LBS_DEB_WEXT);
323 364
365 if (!lbs_is_cmd_allowed(priv)) {
366 ret = -EBUSY;
367 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
368 return ret;
369 }
370
324 if (vwrq->disabled) 371 if (vwrq->disabled)
325 val = MRVDRV_FRAG_MAX_VALUE; 372 val = MRVDRV_FRAG_MAX_VALUE;
326 373
@@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
342 389
343 lbs_deb_enter(LBS_DEB_WEXT); 390 lbs_deb_enter(LBS_DEB_WEXT);
344 391
392 if (!lbs_is_cmd_allowed(priv)) {
393 ret = -EBUSY;
394 goto out;
395 }
396
345 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); 397 ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
346 if (ret) 398 if (ret)
347 goto out; 399 goto out;
@@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev,
391 443
392 lbs_deb_enter(LBS_DEB_WEXT); 444 lbs_deb_enter(LBS_DEB_WEXT);
393 445
446 if (!lbs_is_cmd_allowed(priv)) {
447 ret = -EBUSY;
448 goto out;
449 }
450
394 if (!priv->radio_on) { 451 if (!priv->radio_on) {
395 lbs_deb_wext("tx power off\n"); 452 lbs_deb_wext("tx power off\n");
396 vwrq->value = 0; 453 vwrq->value = 0;
@@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
424 481
425 lbs_deb_enter(LBS_DEB_WEXT); 482 lbs_deb_enter(LBS_DEB_WEXT);
426 483
484 if (!lbs_is_cmd_allowed(priv)) {
485 ret = -EBUSY;
486 goto out;
487 }
488
427 if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) 489 if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
428 return -EOPNOTSUPP; 490 return -EOPNOTSUPP;
429 491
@@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
472 534
473 lbs_deb_enter(LBS_DEB_WEXT); 535 lbs_deb_enter(LBS_DEB_WEXT);
474 536
537 if (!lbs_is_cmd_allowed(priv)) {
538 ret = -EBUSY;
539 goto out;
540 }
541
475 vwrq->disabled = 0; 542 vwrq->disabled = 0;
476 543
477 if (vwrq->flags & IW_RETRY_LONG) { 544 if (vwrq->flags & IW_RETRY_LONG) {
@@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
709 struct iw_param *vwrq, char *extra) 776 struct iw_param *vwrq, char *extra)
710{ 777{
711 struct lbs_private *priv = dev->ml_priv; 778 struct lbs_private *priv = dev->ml_priv;
779 int ret = 0;
712 780
713 lbs_deb_enter(LBS_DEB_WEXT); 781 lbs_deb_enter(LBS_DEB_WEXT);
714 782
@@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
737 "setting power timeout is not supported\n"); 805 "setting power timeout is not supported\n");
738 return -EINVAL; 806 return -EINVAL;
739 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { 807 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
740 lbs_deb_wext("setting power period not supported\n"); 808 vwrq->value = vwrq->value / 1000;
741 return -EINVAL; 809 if (!priv->enter_deep_sleep) {
810 lbs_pr_err("deep sleep feature is not implemented "
811 "for this interface driver\n");
812 return -EINVAL;
813 }
814
815 if (priv->connect_status == LBS_CONNECTED) {
816 if ((priv->is_auto_deep_sleep_enabled) &&
817 (vwrq->value == -1000)) {
818 lbs_exit_auto_deep_sleep(priv);
819 return 0;
820 } else {
821 lbs_pr_err("can't use deep sleep cmd in "
822 "connected state\n");
823 return -EINVAL;
824 }
825 }
826
827 if ((vwrq->value < 0) && (vwrq->value != -1000)) {
828 lbs_pr_err("unknown option\n");
829 return -EINVAL;
830 }
831
832 if (vwrq->value > 0) {
833 if (!priv->is_auto_deep_sleep_enabled) {
834 priv->is_activity_detected = 0;
835 priv->auto_deep_sleep_timeout = vwrq->value;
836 lbs_enter_auto_deep_sleep(priv);
837 } else {
838 priv->auto_deep_sleep_timeout = vwrq->value;
839 lbs_deb_debugfs("auto deep sleep: "
840 "already enabled\n");
841 }
842 return 0;
843 } else {
844 if (priv->is_auto_deep_sleep_enabled) {
845 lbs_exit_auto_deep_sleep(priv);
846 /* Try to exit deep sleep if auto */
847 /*deep sleep disabled */
848 ret = lbs_set_deep_sleep(priv, 0);
849 }
850 if (vwrq->value == 0)
851 ret = lbs_set_deep_sleep(priv, 1);
852 else if (vwrq->value == -1000)
853 ret = lbs_set_deep_sleep(priv, 0);
854 return ret;
855 }
742 } 856 }
743 857
744 if (priv->psmode != LBS802_11POWERMODECAM) { 858 if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
752 } 866 }
753 867
754 lbs_deb_leave(LBS_DEB_WEXT); 868 lbs_deb_leave(LBS_DEB_WEXT);
869
755 return 0; 870 return 0;
756} 871}
757 872
@@ -792,6 +907,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
792 907
793 lbs_deb_enter(LBS_DEB_WEXT); 908 lbs_deb_enter(LBS_DEB_WEXT);
794 909
910 if (!lbs_is_cmd_allowed(priv))
911 return NULL;
912
795 priv->wstats.status = priv->mode; 913 priv->wstats.status = priv->mode;
796 914
797 /* If we're not associated, all quality values are meaningless */ 915 /* 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,
892 1010
893 lbs_deb_enter(LBS_DEB_WEXT); 1011 lbs_deb_enter(LBS_DEB_WEXT);
894 1012
1013 if (!lbs_is_cmd_allowed(priv)) {
1014 ret = -EBUSY;
1015 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1016 return ret;
1017 }
1018
895 mutex_lock(&priv->lock); 1019 mutex_lock(&priv->lock);
896 assoc_req = lbs_get_association_request(priv); 1020 assoc_req = lbs_get_association_request(priv);
897 if (!assoc_req) { 1021 if (!assoc_req) {
@@ -1000,6 +1124,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
1000 u8 rates[MAX_RATES + 1]; 1124 u8 rates[MAX_RATES + 1];
1001 1125
1002 lbs_deb_enter(LBS_DEB_WEXT); 1126 lbs_deb_enter(LBS_DEB_WEXT);
1127
1128 if (!lbs_is_cmd_allowed(priv)) {
1129 ret = -EBUSY;
1130 goto out;
1131 }
1132
1003 lbs_deb_wext("vwrq->value %d\n", vwrq->value); 1133 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1004 lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); 1134 lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
1005 1135
@@ -1058,6 +1188,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
1058 1188
1059 lbs_deb_enter(LBS_DEB_WEXT); 1189 lbs_deb_enter(LBS_DEB_WEXT);
1060 1190
1191 if (!lbs_is_cmd_allowed(priv)) {
1192 lbs_deb_leave(LBS_DEB_WEXT);
1193 return -EBUSY;
1194 }
1195
1061 if (priv->connect_status == LBS_CONNECTED) { 1196 if (priv->connect_status == LBS_CONNECTED) {
1062 vwrq->value = priv->cur_rate * 500000; 1197 vwrq->value = priv->cur_rate * 500000;
1063 1198
@@ -1084,6 +1219,11 @@ static int lbs_set_mode(struct net_device *dev,
1084 1219
1085 lbs_deb_enter(LBS_DEB_WEXT); 1220 lbs_deb_enter(LBS_DEB_WEXT);
1086 1221
1222 if (!lbs_is_cmd_allowed(priv)) {
1223 ret = -EBUSY;
1224 goto out;
1225 }
1226
1087 if ( (*uwrq != IW_MODE_ADHOC) 1227 if ( (*uwrq != IW_MODE_ADHOC)
1088 && (*uwrq != IW_MODE_INFRA) 1228 && (*uwrq != IW_MODE_INFRA)
1089 && (*uwrq != IW_MODE_AUTO)) { 1229 && (*uwrq != IW_MODE_AUTO)) {
@@ -1325,6 +1465,12 @@ static int lbs_set_encode(struct net_device *dev,
1325 1465
1326 lbs_deb_enter(LBS_DEB_WEXT); 1466 lbs_deb_enter(LBS_DEB_WEXT);
1327 1467
1468 if (!lbs_is_cmd_allowed(priv)) {
1469 ret = -EBUSY;
1470 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1471 return ret;
1472 }
1473
1328 mutex_lock(&priv->lock); 1474 mutex_lock(&priv->lock);
1329 assoc_req = lbs_get_association_request(priv); 1475 assoc_req = lbs_get_association_request(priv);
1330 if (!assoc_req) { 1476 if (!assoc_req) {
@@ -1508,6 +1654,12 @@ static int lbs_set_encodeext(struct net_device *dev,
1508 1654
1509 lbs_deb_enter(LBS_DEB_WEXT); 1655 lbs_deb_enter(LBS_DEB_WEXT);
1510 1656
1657 if (!lbs_is_cmd_allowed(priv)) {
1658 ret = -EBUSY;
1659 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1660 return ret;
1661 }
1662
1511 mutex_lock(&priv->lock); 1663 mutex_lock(&priv->lock);
1512 assoc_req = lbs_get_association_request(priv); 1664 assoc_req = lbs_get_association_request(priv);
1513 if (!assoc_req) { 1665 if (!assoc_req) {
@@ -1720,6 +1872,12 @@ static int lbs_set_auth(struct net_device *dev,
1720 1872
1721 lbs_deb_enter(LBS_DEB_WEXT); 1873 lbs_deb_enter(LBS_DEB_WEXT);
1722 1874
1875 if (!lbs_is_cmd_allowed(priv)) {
1876 ret = -EBUSY;
1877 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1878 return ret;
1879 }
1880
1723 mutex_lock(&priv->lock); 1881 mutex_lock(&priv->lock);
1724 assoc_req = lbs_get_association_request(priv); 1882 assoc_req = lbs_get_association_request(priv);
1725 if (!assoc_req) { 1883 if (!assoc_req) {
@@ -1822,6 +1980,12 @@ static int lbs_get_auth(struct net_device *dev,
1822 1980
1823 lbs_deb_enter(LBS_DEB_WEXT); 1981 lbs_deb_enter(LBS_DEB_WEXT);
1824 1982
1983 if (!lbs_is_cmd_allowed(priv)) {
1984 ret = -EBUSY;
1985 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1986 return ret;
1987 }
1988
1825 switch (dwrq->flags & IW_AUTH_INDEX) { 1989 switch (dwrq->flags & IW_AUTH_INDEX) {
1826 case IW_AUTH_KEY_MGMT: 1990 case IW_AUTH_KEY_MGMT:
1827 dwrq->value = priv->secinfo.key_mgmt; 1991 dwrq->value = priv->secinfo.key_mgmt;
@@ -1864,6 +2028,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
1864 2028
1865 lbs_deb_enter(LBS_DEB_WEXT); 2029 lbs_deb_enter(LBS_DEB_WEXT);
1866 2030
2031 if (!lbs_is_cmd_allowed(priv)) {
2032 ret = -EBUSY;
2033 goto out;
2034 }
2035
1867 if (vwrq->disabled) { 2036 if (vwrq->disabled) {
1868 lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); 2037 lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
1869 goto out; 2038 goto out;
@@ -1983,6 +2152,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
1983 2152
1984 lbs_deb_enter(LBS_DEB_WEXT); 2153 lbs_deb_enter(LBS_DEB_WEXT);
1985 2154
2155 if (!lbs_is_cmd_allowed(priv)) {
2156 ret = -EBUSY;
2157 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2158 return ret;
2159 }
2160
1986 if (!priv->radio_on) { 2161 if (!priv->radio_on) {
1987 ret = -EINVAL; 2162 ret = -EINVAL;
1988 goto out; 2163 goto out;
@@ -2110,6 +2285,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
2110 2285
2111 lbs_deb_enter(LBS_DEB_WEXT); 2286 lbs_deb_enter(LBS_DEB_WEXT);
2112 2287
2288 if (!lbs_is_cmd_allowed(priv)) {
2289 ret = -EBUSY;
2290 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2291 return ret;
2292 }
2293
2113 if (!priv->radio_on) 2294 if (!priv->radio_on)
2114 return -EINVAL; 2295 return -EINVAL;
2115 2296