diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/libertas/README | 26 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 72 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/debugfs.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/decl.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_cs.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_sdio.c | 56 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_sdio.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_spi.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 111 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 185 |
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 | ======================== | ||
230 | IWCONFIG COMMANDS | ||
231 | ======================== | ||
232 | power 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 | ||
18 | static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); | 18 | static 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 | ||
321 | static 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 | |||
339 | int 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 | |||
322 | int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, | 375 | int 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); | |||
33 | int lbs_process_event(struct lbs_private *priv, u32 event); | 33 | int lbs_process_event(struct lbs_private *priv, u32 event); |
34 | void lbs_queue_event(struct lbs_private *priv, u32 event); | 34 | void lbs_queue_event(struct lbs_private *priv, u32 event); |
35 | void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); | 35 | void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); |
36 | int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); | ||
37 | int lbs_is_cmd_allowed(struct lbs_private *priv); | ||
38 | int lbs_enter_auto_deep_sleep(struct lbs_private *priv); | ||
39 | int lbs_exit_auto_deep_sleep(struct lbs_private *priv); | ||
36 | 40 | ||
37 | u32 lbs_fw_index_to_data_rate(u8 index); | 41 | u32 lbs_fw_index_to_data_rate(u8 index); |
38 | u8 lbs_data_rate_to_fw_index(u32 rate); | 42 | u8 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 | ||
834 | static 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 | |||
851 | static 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 | |||
868 | static 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 | */ | ||
1073 | static 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 | |||
1097 | int 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 | |||
1111 | int 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 | |||
1053 | static void lbs_sync_channel_worker(struct work_struct *work) | 1123 | static 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 | |||
55 | int 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 | ||