diff options
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/Kconfig | 39 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/Makefile | 15 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/README | 26 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 198 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cfg.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 106 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/decl.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/defs.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 19 | ||||
-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 | 171 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 54 |
18 files changed, 689 insertions, 41 deletions
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig new file mode 100644 index 000000000000..8f8d75b61ea9 --- /dev/null +++ b/drivers/net/wireless/libertas/Kconfig | |||
@@ -0,0 +1,39 @@ | |||
1 | config LIBERTAS | ||
2 | tristate "Marvell 8xxx Libertas WLAN driver support" | ||
3 | depends on WLAN_80211 && CFG80211 | ||
4 | select WIRELESS_EXT | ||
5 | select WEXT_SPY | ||
6 | select LIB80211 | ||
7 | select FW_LOADER | ||
8 | ---help--- | ||
9 | A library for Marvell Libertas 8xxx devices. | ||
10 | |||
11 | config LIBERTAS_USB | ||
12 | tristate "Marvell Libertas 8388 USB 802.11b/g cards" | ||
13 | depends on LIBERTAS && USB | ||
14 | ---help--- | ||
15 | A driver for Marvell Libertas 8388 USB devices. | ||
16 | |||
17 | config LIBERTAS_CS | ||
18 | tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" | ||
19 | depends on LIBERTAS && PCMCIA | ||
20 | ---help--- | ||
21 | A driver for Marvell Libertas 8385 CompactFlash devices. | ||
22 | |||
23 | config LIBERTAS_SDIO | ||
24 | tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" | ||
25 | depends on LIBERTAS && MMC | ||
26 | ---help--- | ||
27 | A driver for Marvell Libertas 8385/8686/8688 SDIO devices. | ||
28 | |||
29 | config LIBERTAS_SPI | ||
30 | tristate "Marvell Libertas 8686 SPI 802.11b/g cards" | ||
31 | depends on LIBERTAS && SPI | ||
32 | ---help--- | ||
33 | A driver for Marvell Libertas 8686 SPI devices. | ||
34 | |||
35 | config LIBERTAS_DEBUG | ||
36 | bool "Enable full debugging output in the Libertas module." | ||
37 | depends on LIBERTAS | ||
38 | ---help--- | ||
39 | Debugging support. | ||
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 0b6918584503..e5584dd1c79a 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile | |||
@@ -1,5 +1,16 @@ | |||
1 | libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \ | 1 | libertas-y += 11d.o |
2 | debugfs.o persistcfg.o ethtool.o assoc.o | 2 | libertas-y += assoc.o |
3 | libertas-y += cfg.o | ||
4 | libertas-y += cmd.o | ||
5 | libertas-y += cmdresp.o | ||
6 | libertas-y += debugfs.o | ||
7 | libertas-y += ethtool.o | ||
8 | libertas-y += main.o | ||
9 | libertas-y += persistcfg.o | ||
10 | libertas-y += rx.o | ||
11 | libertas-y += scan.o | ||
12 | libertas-y += tx.o | ||
13 | libertas-y += wext.o | ||
3 | 14 | ||
4 | usb8xxx-objs += if_usb.o | 15 | usb8xxx-objs += if_usb.o |
5 | libertas_cs-objs += if_cs.o | 16 | libertas_cs-objs += if_cs.o |
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/cfg.c b/drivers/net/wireless/libertas/cfg.c new file mode 100644 index 000000000000..4396dccd12ac --- /dev/null +++ b/drivers/net/wireless/libertas/cfg.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Implement cfg80211 ("iw") support. | ||
3 | * | ||
4 | * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany | ||
5 | * Holger Schurig <hs4233@mail.mn-solutions.de> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <net/cfg80211.h> | ||
10 | |||
11 | #include "cfg.h" | ||
12 | #include "cmd.h" | ||
13 | |||
14 | |||
15 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
16 | .band = IEEE80211_BAND_2GHZ, \ | ||
17 | .center_freq = (_freq), \ | ||
18 | .hw_value = (_channel), \ | ||
19 | .flags = (_flags), \ | ||
20 | .max_antenna_gain = 0, \ | ||
21 | .max_power = 30, \ | ||
22 | } | ||
23 | |||
24 | static struct ieee80211_channel lbs_2ghz_channels[] = { | ||
25 | CHAN2G(1, 2412, 0), | ||
26 | CHAN2G(2, 2417, 0), | ||
27 | CHAN2G(3, 2422, 0), | ||
28 | CHAN2G(4, 2427, 0), | ||
29 | CHAN2G(5, 2432, 0), | ||
30 | CHAN2G(6, 2437, 0), | ||
31 | CHAN2G(7, 2442, 0), | ||
32 | CHAN2G(8, 2447, 0), | ||
33 | CHAN2G(9, 2452, 0), | ||
34 | CHAN2G(10, 2457, 0), | ||
35 | CHAN2G(11, 2462, 0), | ||
36 | CHAN2G(12, 2467, 0), | ||
37 | CHAN2G(13, 2472, 0), | ||
38 | CHAN2G(14, 2484, 0), | ||
39 | }; | ||
40 | |||
41 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | ||
42 | .bitrate = (_rate), \ | ||
43 | .hw_value = (_rateid), \ | ||
44 | .flags = (_flags), \ | ||
45 | } | ||
46 | |||
47 | |||
48 | static struct ieee80211_rate lbs_rates[] = { | ||
49 | RATETAB_ENT(10, 0x1, 0), | ||
50 | RATETAB_ENT(20, 0x2, 0), | ||
51 | RATETAB_ENT(55, 0x4, 0), | ||
52 | RATETAB_ENT(110, 0x8, 0), | ||
53 | RATETAB_ENT(60, 0x10, 0), | ||
54 | RATETAB_ENT(90, 0x20, 0), | ||
55 | RATETAB_ENT(120, 0x40, 0), | ||
56 | RATETAB_ENT(180, 0x80, 0), | ||
57 | RATETAB_ENT(240, 0x100, 0), | ||
58 | RATETAB_ENT(360, 0x200, 0), | ||
59 | RATETAB_ENT(480, 0x400, 0), | ||
60 | RATETAB_ENT(540, 0x800, 0), | ||
61 | }; | ||
62 | |||
63 | static struct ieee80211_supported_band lbs_band_2ghz = { | ||
64 | .channels = lbs_2ghz_channels, | ||
65 | .n_channels = ARRAY_SIZE(lbs_2ghz_channels), | ||
66 | .bitrates = lbs_rates, | ||
67 | .n_bitrates = ARRAY_SIZE(lbs_rates), | ||
68 | }; | ||
69 | |||
70 | |||
71 | static const u32 cipher_suites[] = { | ||
72 | WLAN_CIPHER_SUITE_WEP40, | ||
73 | WLAN_CIPHER_SUITE_WEP104, | ||
74 | WLAN_CIPHER_SUITE_TKIP, | ||
75 | WLAN_CIPHER_SUITE_CCMP, | ||
76 | }; | ||
77 | |||
78 | |||
79 | |||
80 | static int lbs_cfg_set_channel(struct wiphy *wiphy, | ||
81 | struct ieee80211_channel *chan, | ||
82 | enum nl80211_channel_type channel_type) | ||
83 | { | ||
84 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
85 | int ret = -ENOTSUPP; | ||
86 | |||
87 | lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type); | ||
88 | |||
89 | if (channel_type != NL80211_CHAN_NO_HT) | ||
90 | goto out; | ||
91 | |||
92 | ret = lbs_set_channel(priv, chan->hw_value); | ||
93 | |||
94 | out: | ||
95 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | |||
100 | |||
101 | |||
102 | static struct cfg80211_ops lbs_cfg80211_ops = { | ||
103 | .set_channel = lbs_cfg_set_channel, | ||
104 | }; | ||
105 | |||
106 | |||
107 | /* | ||
108 | * At this time lbs_private *priv doesn't even exist, so we just allocate | ||
109 | * memory and don't initialize the wiphy further. This is postponed until we | ||
110 | * can talk to the firmware and happens at registration time in | ||
111 | * lbs_cfg_wiphy_register(). | ||
112 | */ | ||
113 | struct wireless_dev *lbs_cfg_alloc(struct device *dev) | ||
114 | { | ||
115 | int ret = 0; | ||
116 | struct wireless_dev *wdev; | ||
117 | |||
118 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
119 | |||
120 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
121 | if (!wdev) { | ||
122 | dev_err(dev, "cannot allocate wireless device\n"); | ||
123 | return ERR_PTR(-ENOMEM); | ||
124 | } | ||
125 | |||
126 | wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private)); | ||
127 | if (!wdev->wiphy) { | ||
128 | dev_err(dev, "cannot allocate wiphy\n"); | ||
129 | ret = -ENOMEM; | ||
130 | goto err_wiphy_new; | ||
131 | } | ||
132 | |||
133 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
134 | return wdev; | ||
135 | |||
136 | err_wiphy_new: | ||
137 | kfree(wdev); | ||
138 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
139 | return ERR_PTR(ret); | ||
140 | } | ||
141 | |||
142 | |||
143 | /* | ||
144 | * This function get's called after lbs_setup_firmware() determined the | ||
145 | * firmware capabities. So we can setup the wiphy according to our | ||
146 | * hardware/firmware. | ||
147 | */ | ||
148 | int lbs_cfg_register(struct lbs_private *priv) | ||
149 | { | ||
150 | struct wireless_dev *wdev = priv->wdev; | ||
151 | int ret; | ||
152 | |||
153 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
154 | |||
155 | wdev->wiphy->max_scan_ssids = 1; | ||
156 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
157 | |||
158 | /* TODO: BIT(NL80211_IFTYPE_ADHOC); */ | ||
159 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
160 | |||
161 | /* TODO: honor priv->regioncode */ | ||
162 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; | ||
163 | |||
164 | /* | ||
165 | * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have | ||
166 | * never seen a firmware without WPA | ||
167 | */ | ||
168 | wdev->wiphy->cipher_suites = cipher_suites; | ||
169 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
170 | |||
171 | ret = wiphy_register(wdev->wiphy); | ||
172 | if (ret < 0) | ||
173 | lbs_pr_err("cannot register wiphy device\n"); | ||
174 | |||
175 | ret = register_netdev(priv->dev); | ||
176 | if (ret) | ||
177 | lbs_pr_err("cannot register network device\n"); | ||
178 | |||
179 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | |||
184 | void lbs_cfg_free(struct lbs_private *priv) | ||
185 | { | ||
186 | struct wireless_dev *wdev = priv->wdev; | ||
187 | |||
188 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
189 | |||
190 | if (!wdev) | ||
191 | return; | ||
192 | |||
193 | if (wdev->wiphy) { | ||
194 | wiphy_unregister(wdev->wiphy); | ||
195 | wiphy_free(wdev->wiphy); | ||
196 | } | ||
197 | kfree(wdev); | ||
198 | } | ||
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h new file mode 100644 index 000000000000..e09a193a34d6 --- /dev/null +++ b/drivers/net/wireless/libertas/cfg.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef __LBS_CFG80211_H__ | ||
2 | #define __LBS_CFG80211_H__ | ||
3 | |||
4 | #include "dev.h" | ||
5 | |||
6 | struct wireless_dev *lbs_cfg_alloc(struct device *dev); | ||
7 | int lbs_cfg_register(struct lbs_private *priv); | ||
8 | void lbs_cfg_free(struct lbs_private *priv); | ||
9 | |||
10 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, | ||
11 | u8 ssid_len); | ||
12 | int lbs_scan_networks(struct lbs_private *priv, int full_scan); | ||
13 | void lbs_cfg_scan_worker(struct work_struct *work); | ||
14 | |||
15 | |||
16 | #endif | ||
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 685098148e10..0fb312576b8d 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 | * |
@@ -76,6 +75,30 @@ static u8 is_command_allowed_in_ps(u16 cmd) | |||
76 | } | 75 | } |
77 | 76 | ||
78 | /** | 77 | /** |
78 | * @brief This function checks if the command is allowed. | ||
79 | * | ||
80 | * @param priv A pointer to lbs_private structure | ||
81 | * @return allowed or not allowed. | ||
82 | */ | ||
83 | |||
84 | static int lbs_is_cmd_allowed(struct lbs_private *priv) | ||
85 | { | ||
86 | int ret = 1; | ||
87 | |||
88 | lbs_deb_enter(LBS_DEB_CMD); | ||
89 | |||
90 | if (!priv->is_auto_deep_sleep_enabled) { | ||
91 | if (priv->is_deep_sleep) { | ||
92 | lbs_deb_cmd("command not allowed in deep sleep\n"); | ||
93 | ret = 0; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | lbs_deb_leave(LBS_DEB_CMD); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | /** | ||
79 | * @brief Updates the hardware details like MAC address and regulatory region | 102 | * @brief Updates the hardware details like MAC address and regulatory region |
80 | * | 103 | * |
81 | * @param priv A pointer to struct lbs_private structure | 104 | * @param priv A pointer to struct lbs_private structure |
@@ -319,6 +342,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, | |||
319 | return 0; | 342 | return 0; |
320 | } | 343 | } |
321 | 344 | ||
345 | static int lbs_wait_for_ds_awake(struct lbs_private *priv) | ||
346 | { | ||
347 | int ret = 0; | ||
348 | |||
349 | lbs_deb_enter(LBS_DEB_CMD); | ||
350 | |||
351 | if (priv->is_deep_sleep) { | ||
352 | if (!wait_event_interruptible_timeout(priv->ds_awake_q, | ||
353 | !priv->is_deep_sleep, (10 * HZ))) { | ||
354 | lbs_pr_err("ds_awake_q: timer expired\n"); | ||
355 | ret = -1; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) | ||
364 | { | ||
365 | int ret = 0; | ||
366 | |||
367 | lbs_deb_enter(LBS_DEB_CMD); | ||
368 | |||
369 | if (deep_sleep) { | ||
370 | if (priv->is_deep_sleep != 1) { | ||
371 | lbs_deb_cmd("deep sleep: sleep\n"); | ||
372 | BUG_ON(!priv->enter_deep_sleep); | ||
373 | ret = priv->enter_deep_sleep(priv); | ||
374 | if (!ret) { | ||
375 | netif_stop_queue(priv->dev); | ||
376 | netif_carrier_off(priv->dev); | ||
377 | } | ||
378 | } else { | ||
379 | lbs_pr_err("deep sleep: already enabled\n"); | ||
380 | } | ||
381 | } else { | ||
382 | if (priv->is_deep_sleep) { | ||
383 | lbs_deb_cmd("deep sleep: wakeup\n"); | ||
384 | BUG_ON(!priv->exit_deep_sleep); | ||
385 | ret = priv->exit_deep_sleep(priv); | ||
386 | if (!ret) { | ||
387 | ret = lbs_wait_for_ds_awake(priv); | ||
388 | if (ret) | ||
389 | lbs_pr_err("deep sleep: wakeup" | ||
390 | "failed\n"); | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | |||
395 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
396 | return ret; | ||
397 | } | ||
398 | |||
322 | int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, | 399 | int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, |
323 | struct assoc_request *assoc) | 400 | struct assoc_request *assoc) |
324 | { | 401 | { |
@@ -1242,8 +1319,17 @@ static void lbs_submit_command(struct lbs_private *priv, | |||
1242 | timeo = HZ/4; | 1319 | timeo = HZ/4; |
1243 | } | 1320 | } |
1244 | 1321 | ||
1245 | /* Setup the timer after transmit command */ | 1322 | if (command == CMD_802_11_DEEP_SLEEP) { |
1246 | mod_timer(&priv->command_timer, jiffies + timeo); | 1323 | if (priv->is_auto_deep_sleep_enabled) { |
1324 | priv->wakeup_dev_required = 1; | ||
1325 | priv->dnld_sent = 0; | ||
1326 | } | ||
1327 | priv->is_deep_sleep = 1; | ||
1328 | lbs_complete_command(priv, cmdnode, 0); | ||
1329 | } else { | ||
1330 | /* Setup the timer after transmit command */ | ||
1331 | mod_timer(&priv->command_timer, jiffies + timeo); | ||
1332 | } | ||
1247 | 1333 | ||
1248 | lbs_deb_leave(LBS_DEB_HOST); | 1334 | lbs_deb_leave(LBS_DEB_HOST); |
1249 | } | 1335 | } |
@@ -1390,6 +1476,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1390 | goto done; | 1476 | goto done; |
1391 | } | 1477 | } |
1392 | 1478 | ||
1479 | if (!lbs_is_cmd_allowed(priv)) { | ||
1480 | ret = -EBUSY; | ||
1481 | goto done; | ||
1482 | } | ||
1483 | |||
1393 | cmdnode = lbs_get_cmd_ctrl_node(priv); | 1484 | cmdnode = lbs_get_cmd_ctrl_node(priv); |
1394 | 1485 | ||
1395 | if (cmdnode == NULL) { | 1486 | if (cmdnode == NULL) { |
@@ -1505,6 +1596,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1505 | case CMD_802_11_BEACON_CTRL: | 1596 | case CMD_802_11_BEACON_CTRL: |
1506 | ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); | 1597 | ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); |
1507 | break; | 1598 | break; |
1599 | case CMD_802_11_DEEP_SLEEP: | ||
1600 | cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP); | ||
1601 | cmdptr->size = cpu_to_le16(S_DS_GEN); | ||
1602 | break; | ||
1508 | default: | 1603 | default: |
1509 | lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); | 1604 | lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); |
1510 | ret = -1; | 1605 | ret = -1; |
@@ -2038,6 +2133,11 @@ static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, | |||
2038 | goto done; | 2133 | goto done; |
2039 | } | 2134 | } |
2040 | 2135 | ||
2136 | if (!lbs_is_cmd_allowed(priv)) { | ||
2137 | cmdnode = ERR_PTR(-EBUSY); | ||
2138 | goto done; | ||
2139 | } | ||
2140 | |||
2041 | cmdnode = lbs_get_cmd_ctrl_node(priv); | 2141 | cmdnode = lbs_get_cmd_ctrl_node(priv); |
2042 | if (cmdnode == NULL) { | 2142 | if (cmdnode == NULL) { |
2043 | lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); | 2143 | lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); |
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/decl.h b/drivers/net/wireless/libertas/decl.h index 8b15380ae6e1..fb91c3639fc1 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h | |||
@@ -33,6 +33,9 @@ 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_enter_auto_deep_sleep(struct lbs_private *priv); | ||
38 | int lbs_exit_auto_deep_sleep(struct lbs_private *priv); | ||
36 | 39 | ||
37 | u32 lbs_fw_index_to_data_rate(u8 index); | 40 | u32 lbs_fw_index_to_data_rate(u8 index); |
38 | u8 lbs_data_rate_to_fw_index(u32 rate); | 41 | u8 lbs_data_rate_to_fw_index(u32 rate); |
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 72f3479a4d70..1cf5d5985dac 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #define LBS_DEB_SDIO 0x00400000 | 42 | #define LBS_DEB_SDIO 0x00400000 |
43 | #define LBS_DEB_SYSFS 0x00800000 | 43 | #define LBS_DEB_SYSFS 0x00800000 |
44 | #define LBS_DEB_SPI 0x01000000 | 44 | #define LBS_DEB_SPI 0x01000000 |
45 | #define LBS_DEB_CFG80211 0x02000000 | ||
45 | 46 | ||
46 | extern unsigned int lbs_debug; | 47 | extern unsigned int lbs_debug; |
47 | 48 | ||
@@ -86,6 +87,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \ | |||
86 | #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) | 87 | #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) |
87 | #define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) | 88 | #define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) |
88 | #define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args) | 89 | #define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args) |
90 | #define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args) | ||
89 | 91 | ||
90 | #define lbs_pr_info(format, args...) \ | 92 | #define lbs_pr_info(format, args...) \ |
91 | printk(KERN_INFO DRV_NAME": " format, ## args) | 93 | printk(KERN_INFO DRV_NAME": " format, ## args) |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index d3b69a4b4b5e..8abb28af5afa 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -100,6 +100,7 @@ struct lbs_mesh_stats { | |||
100 | 100 | ||
101 | /** Private structure for the MV device */ | 101 | /** Private structure for the MV device */ |
102 | struct lbs_private { | 102 | struct lbs_private { |
103 | struct wireless_dev *wdev; | ||
103 | int mesh_open; | 104 | int mesh_open; |
104 | int mesh_fw_ver; | 105 | int mesh_fw_ver; |
105 | int infra_open; | 106 | int infra_open; |
@@ -129,6 +130,20 @@ struct lbs_private { | |||
129 | u32 bbp_offset; | 130 | u32 bbp_offset; |
130 | u32 rf_offset; | 131 | u32 rf_offset; |
131 | 132 | ||
133 | /** Deep sleep flag */ | ||
134 | int is_deep_sleep; | ||
135 | /** Auto deep sleep enabled flag */ | ||
136 | int is_auto_deep_sleep_enabled; | ||
137 | /** Device wakeup required flag */ | ||
138 | int wakeup_dev_required; | ||
139 | /** Auto deep sleep flag*/ | ||
140 | int is_activity_detected; | ||
141 | /** Auto deep sleep timeout (in miliseconds) */ | ||
142 | int auto_deep_sleep_timeout; | ||
143 | |||
144 | /** Deep sleep wait queue */ | ||
145 | wait_queue_head_t ds_awake_q; | ||
146 | |||
132 | /* Download sent: | 147 | /* Download sent: |
133 | bit0 1/0=data_sent/data_tx_done, | 148 | bit0 1/0=data_sent/data_tx_done, |
134 | bit1 1/0=cmd_sent/cmd_tx_done, | 149 | bit1 1/0=cmd_sent/cmd_tx_done, |
@@ -154,6 +169,9 @@ struct lbs_private { | |||
154 | /** Hardware access */ | 169 | /** Hardware access */ |
155 | int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); | 170 | int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); |
156 | void (*reset_card) (struct lbs_private *priv); | 171 | void (*reset_card) (struct lbs_private *priv); |
172 | int (*enter_deep_sleep) (struct lbs_private *priv); | ||
173 | int (*exit_deep_sleep) (struct lbs_private *priv); | ||
174 | int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); | ||
157 | 175 | ||
158 | /* Wake On LAN */ | 176 | /* Wake On LAN */ |
159 | uint32_t wol_criteria; | 177 | uint32_t wol_criteria; |
@@ -204,6 +222,7 @@ struct lbs_private { | |||
204 | 222 | ||
205 | /** Timers */ | 223 | /** Timers */ |
206 | struct timer_list command_timer; | 224 | struct timer_list command_timer; |
225 | struct timer_list auto_deepsleep_timer; | ||
207 | int nr_retries; | 226 | int nr_retries; |
208 | int cmd_timed_out; | 227 | int cmd_timed_out; |
209 | 228 | ||
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..87bfd17b9c8c 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -14,11 +14,13 @@ | |||
14 | #include <linux/stddef.h> | 14 | #include <linux/stddef.h> |
15 | #include <linux/ieee80211.h> | 15 | #include <linux/ieee80211.h> |
16 | #include <net/iw_handler.h> | 16 | #include <net/iw_handler.h> |
17 | #include <net/cfg80211.h> | ||
17 | 18 | ||
18 | #include "host.h" | 19 | #include "host.h" |
19 | #include "decl.h" | 20 | #include "decl.h" |
20 | #include "dev.h" | 21 | #include "dev.h" |
21 | #include "wext.h" | 22 | #include "wext.h" |
23 | #include "cfg.h" | ||
22 | #include "debugfs.h" | 24 | #include "debugfs.h" |
23 | #include "scan.h" | 25 | #include "scan.h" |
24 | #include "assoc.h" | 26 | #include "assoc.h" |
@@ -574,8 +576,10 @@ void lbs_host_to_card_done(struct lbs_private *priv) | |||
574 | priv->dnld_sent = DNLD_RES_RECEIVED; | 576 | priv->dnld_sent = DNLD_RES_RECEIVED; |
575 | 577 | ||
576 | /* Wake main thread if commands are pending */ | 578 | /* Wake main thread if commands are pending */ |
577 | if (!priv->cur_cmd || priv->tx_pending_len > 0) | 579 | if (!priv->cur_cmd || priv->tx_pending_len > 0) { |
578 | wake_up_interruptible(&priv->waitq); | 580 | if (!priv->wakeup_dev_required) |
581 | wake_up_interruptible(&priv->waitq); | ||
582 | } | ||
579 | 583 | ||
580 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 584 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
581 | lbs_deb_leave(LBS_DEB_THREAD); | 585 | lbs_deb_leave(LBS_DEB_THREAD); |
@@ -770,7 +774,8 @@ static int lbs_thread(void *data) | |||
770 | shouldsleep = 0; /* We have a command response */ | 774 | shouldsleep = 0; /* We have a command response */ |
771 | else if (priv->cur_cmd) | 775 | else if (priv->cur_cmd) |
772 | shouldsleep = 1; /* Can't send a command; one already running */ | 776 | shouldsleep = 1; /* Can't send a command; one already running */ |
773 | else if (!list_empty(&priv->cmdpendingq)) | 777 | else if (!list_empty(&priv->cmdpendingq) && |
778 | !(priv->wakeup_dev_required)) | ||
774 | shouldsleep = 0; /* We have a command to send */ | 779 | shouldsleep = 0; /* We have a command to send */ |
775 | else if (__kfifo_len(priv->event_fifo)) | 780 | else if (__kfifo_len(priv->event_fifo)) |
776 | shouldsleep = 0; /* We have an event to process */ | 781 | shouldsleep = 0; /* We have an event to process */ |
@@ -822,6 +827,26 @@ static int lbs_thread(void *data) | |||
822 | } | 827 | } |
823 | spin_unlock_irq(&priv->driver_lock); | 828 | spin_unlock_irq(&priv->driver_lock); |
824 | 829 | ||
830 | /* Process hardware events, e.g. card removed, link lost */ | ||
831 | spin_lock_irq(&priv->driver_lock); | ||
832 | while (__kfifo_len(priv->event_fifo)) { | ||
833 | u32 event; | ||
834 | __kfifo_get(priv->event_fifo, (unsigned char *) &event, | ||
835 | sizeof(event)); | ||
836 | spin_unlock_irq(&priv->driver_lock); | ||
837 | lbs_process_event(priv, event); | ||
838 | spin_lock_irq(&priv->driver_lock); | ||
839 | } | ||
840 | spin_unlock_irq(&priv->driver_lock); | ||
841 | |||
842 | if (priv->wakeup_dev_required) { | ||
843 | lbs_deb_thread("Waking up device...\n"); | ||
844 | /* Wake up device */ | ||
845 | if (priv->exit_deep_sleep(priv)) | ||
846 | lbs_deb_thread("Wakeup device failed\n"); | ||
847 | continue; | ||
848 | } | ||
849 | |||
825 | /* command timeout stuff */ | 850 | /* command timeout stuff */ |
826 | if (priv->cmd_timed_out && priv->cur_cmd) { | 851 | if (priv->cmd_timed_out && priv->cur_cmd) { |
827 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; | 852 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; |
@@ -849,18 +874,7 @@ static int lbs_thread(void *data) | |||
849 | } | 874 | } |
850 | priv->cmd_timed_out = 0; | 875 | priv->cmd_timed_out = 0; |
851 | 876 | ||
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 | 877 | ||
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 | 878 | ||
865 | if (!priv->fw_ready) | 879 | if (!priv->fw_ready) |
866 | continue; | 880 | continue; |
@@ -894,6 +908,9 @@ static int lbs_thread(void *data) | |||
894 | (priv->psstate == PS_STATE_PRE_SLEEP)) | 908 | (priv->psstate == PS_STATE_PRE_SLEEP)) |
895 | continue; | 909 | continue; |
896 | 910 | ||
911 | if (priv->is_deep_sleep) | ||
912 | continue; | ||
913 | |||
897 | /* Execute the next command */ | 914 | /* Execute the next command */ |
898 | if (!priv->dnld_sent && !priv->cur_cmd) | 915 | if (!priv->dnld_sent && !priv->cur_cmd) |
899 | lbs_execute_next_command(priv); | 916 | lbs_execute_next_command(priv); |
@@ -928,6 +945,7 @@ static int lbs_thread(void *data) | |||
928 | } | 945 | } |
929 | 946 | ||
930 | del_timer(&priv->command_timer); | 947 | del_timer(&priv->command_timer); |
948 | del_timer(&priv->auto_deepsleep_timer); | ||
931 | wake_up_all(&priv->cmd_pending); | 949 | wake_up_all(&priv->cmd_pending); |
932 | 950 | ||
933 | lbs_deb_leave(LBS_DEB_THREAD); | 951 | lbs_deb_leave(LBS_DEB_THREAD); |
@@ -1050,6 +1068,60 @@ out: | |||
1050 | lbs_deb_leave(LBS_DEB_CMD); | 1068 | lbs_deb_leave(LBS_DEB_CMD); |
1051 | } | 1069 | } |
1052 | 1070 | ||
1071 | /** | ||
1072 | * This function put the device back to deep sleep mode when timer expires | ||
1073 | * and no activity (command, event, data etc.) is detected. | ||
1074 | */ | ||
1075 | static void auto_deepsleep_timer_fn(unsigned long data) | ||
1076 | { | ||
1077 | struct lbs_private *priv = (struct lbs_private *)data; | ||
1078 | int ret; | ||
1079 | |||
1080 | lbs_deb_enter(LBS_DEB_CMD); | ||
1081 | |||
1082 | if (priv->is_activity_detected) { | ||
1083 | priv->is_activity_detected = 0; | ||
1084 | } else { | ||
1085 | if (priv->is_auto_deep_sleep_enabled && | ||
1086 | (!priv->wakeup_dev_required) && | ||
1087 | (priv->connect_status != LBS_CONNECTED)) { | ||
1088 | lbs_deb_main("Entering auto deep sleep mode...\n"); | ||
1089 | ret = lbs_prepare_and_send_command(priv, | ||
1090 | CMD_802_11_DEEP_SLEEP, 0, | ||
1091 | 0, 0, NULL); | ||
1092 | } | ||
1093 | } | ||
1094 | mod_timer(&priv->auto_deepsleep_timer , jiffies + | ||
1095 | (priv->auto_deep_sleep_timeout * HZ)/1000); | ||
1096 | lbs_deb_leave(LBS_DEB_CMD); | ||
1097 | } | ||
1098 | |||
1099 | int lbs_enter_auto_deep_sleep(struct lbs_private *priv) | ||
1100 | { | ||
1101 | lbs_deb_enter(LBS_DEB_SDIO); | ||
1102 | |||
1103 | priv->is_auto_deep_sleep_enabled = 1; | ||
1104 | if (priv->is_deep_sleep) | ||
1105 | priv->wakeup_dev_required = 1; | ||
1106 | mod_timer(&priv->auto_deepsleep_timer , | ||
1107 | jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); | ||
1108 | |||
1109 | lbs_deb_leave(LBS_DEB_SDIO); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | int lbs_exit_auto_deep_sleep(struct lbs_private *priv) | ||
1114 | { | ||
1115 | lbs_deb_enter(LBS_DEB_SDIO); | ||
1116 | |||
1117 | priv->is_auto_deep_sleep_enabled = 0; | ||
1118 | priv->auto_deep_sleep_timeout = 0; | ||
1119 | del_timer(&priv->auto_deepsleep_timer); | ||
1120 | |||
1121 | lbs_deb_leave(LBS_DEB_SDIO); | ||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1053 | static void lbs_sync_channel_worker(struct work_struct *work) | 1125 | static void lbs_sync_channel_worker(struct work_struct *work) |
1054 | { | 1126 | { |
1055 | struct lbs_private *priv = container_of(work, struct lbs_private, | 1127 | struct lbs_private *priv = container_of(work, struct lbs_private, |
@@ -1099,11 +1171,17 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
1099 | priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; | 1171 | priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; |
1100 | priv->psmode = LBS802_11POWERMODECAM; | 1172 | priv->psmode = LBS802_11POWERMODECAM; |
1101 | priv->psstate = PS_STATE_FULL_POWER; | 1173 | priv->psstate = PS_STATE_FULL_POWER; |
1174 | priv->is_deep_sleep = 0; | ||
1175 | priv->is_auto_deep_sleep_enabled = 0; | ||
1176 | priv->wakeup_dev_required = 0; | ||
1177 | init_waitqueue_head(&priv->ds_awake_q); | ||
1102 | 1178 | ||
1103 | mutex_init(&priv->lock); | 1179 | mutex_init(&priv->lock); |
1104 | 1180 | ||
1105 | setup_timer(&priv->command_timer, command_timer_fn, | 1181 | setup_timer(&priv->command_timer, command_timer_fn, |
1106 | (unsigned long)priv); | 1182 | (unsigned long)priv); |
1183 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, | ||
1184 | (unsigned long)priv); | ||
1107 | 1185 | ||
1108 | INIT_LIST_HEAD(&priv->cmdfreeq); | 1186 | INIT_LIST_HEAD(&priv->cmdfreeq); |
1109 | INIT_LIST_HEAD(&priv->cmdpendingq); | 1187 | INIT_LIST_HEAD(&priv->cmdpendingq); |
@@ -1142,6 +1220,7 @@ static void lbs_free_adapter(struct lbs_private *priv) | |||
1142 | if (priv->event_fifo) | 1220 | if (priv->event_fifo) |
1143 | kfifo_free(priv->event_fifo); | 1221 | kfifo_free(priv->event_fifo); |
1144 | del_timer(&priv->command_timer); | 1222 | del_timer(&priv->command_timer); |
1223 | del_timer(&priv->auto_deepsleep_timer); | ||
1145 | kfree(priv->networks); | 1224 | kfree(priv->networks); |
1146 | priv->networks = NULL; | 1225 | priv->networks = NULL; |
1147 | 1226 | ||
@@ -1168,31 +1247,41 @@ static const struct net_device_ops lbs_netdev_ops = { | |||
1168 | */ | 1247 | */ |
1169 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | 1248 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) |
1170 | { | 1249 | { |
1171 | struct net_device *dev = NULL; | 1250 | struct net_device *dev; |
1251 | struct wireless_dev *wdev; | ||
1172 | struct lbs_private *priv = NULL; | 1252 | struct lbs_private *priv = NULL; |
1173 | 1253 | ||
1174 | lbs_deb_enter(LBS_DEB_MAIN); | 1254 | lbs_deb_enter(LBS_DEB_MAIN); |
1175 | 1255 | ||
1176 | /* Allocate an Ethernet device and register it */ | 1256 | /* Allocate an Ethernet device and register it */ |
1177 | dev = alloc_etherdev(sizeof(struct lbs_private)); | 1257 | wdev = lbs_cfg_alloc(dmdev); |
1178 | if (!dev) { | 1258 | if (IS_ERR(wdev)) { |
1179 | lbs_pr_err("init wlanX device failed\n"); | 1259 | lbs_pr_err("cfg80211 init failed\n"); |
1180 | goto done; | 1260 | goto done; |
1181 | } | 1261 | } |
1182 | priv = netdev_priv(dev); | 1262 | /* TODO? */ |
1183 | dev->ml_priv = priv; | 1263 | wdev->iftype = NL80211_IFTYPE_STATION; |
1264 | priv = wdev_priv(wdev); | ||
1265 | priv->wdev = wdev; | ||
1184 | 1266 | ||
1185 | if (lbs_init_adapter(priv)) { | 1267 | if (lbs_init_adapter(priv)) { |
1186 | lbs_pr_err("failed to initialize adapter structure.\n"); | 1268 | lbs_pr_err("failed to initialize adapter structure.\n"); |
1187 | goto err_init_adapter; | 1269 | goto err_wdev; |
1270 | } | ||
1271 | |||
1272 | //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); | ||
1273 | dev = alloc_netdev(0, "wlan%d", ether_setup); | ||
1274 | if (!dev) { | ||
1275 | dev_err(dmdev, "no memory for network device instance\n"); | ||
1276 | goto err_adapter; | ||
1188 | } | 1277 | } |
1189 | 1278 | ||
1279 | dev->ieee80211_ptr = wdev; | ||
1280 | dev->ml_priv = priv; | ||
1281 | SET_NETDEV_DEV(dev, dmdev); | ||
1282 | wdev->netdev = dev; | ||
1190 | priv->dev = dev; | 1283 | priv->dev = dev; |
1191 | priv->card = card; | ||
1192 | priv->mesh_open = 0; | ||
1193 | priv->infra_open = 0; | ||
1194 | 1284 | ||
1195 | /* Setup the OS Interface to our functions */ | ||
1196 | dev->netdev_ops = &lbs_netdev_ops; | 1285 | dev->netdev_ops = &lbs_netdev_ops; |
1197 | dev->watchdog_timeo = 5 * HZ; | 1286 | dev->watchdog_timeo = 5 * HZ; |
1198 | dev->ethtool_ops = &lbs_ethtool_ops; | 1287 | dev->ethtool_ops = &lbs_ethtool_ops; |
@@ -1201,7 +1290,14 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1201 | #endif | 1290 | #endif |
1202 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | 1291 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; |
1203 | 1292 | ||
1204 | SET_NETDEV_DEV(dev, dmdev); | 1293 | |
1294 | // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ?? | ||
1295 | |||
1296 | |||
1297 | priv->card = card; | ||
1298 | priv->mesh_open = 0; | ||
1299 | priv->infra_open = 0; | ||
1300 | |||
1205 | 1301 | ||
1206 | priv->rtap_net_dev = NULL; | 1302 | priv->rtap_net_dev = NULL; |
1207 | strcpy(dev->name, "wlan%d"); | 1303 | strcpy(dev->name, "wlan%d"); |
@@ -1211,7 +1307,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1211 | priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); | 1307 | priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); |
1212 | if (IS_ERR(priv->main_thread)) { | 1308 | if (IS_ERR(priv->main_thread)) { |
1213 | lbs_deb_thread("Error creating main thread.\n"); | 1309 | lbs_deb_thread("Error creating main thread.\n"); |
1214 | goto err_init_adapter; | 1310 | goto err_ndev; |
1215 | } | 1311 | } |
1216 | 1312 | ||
1217 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); | 1313 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); |
@@ -1228,9 +1324,15 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1228 | 1324 | ||
1229 | goto done; | 1325 | goto done; |
1230 | 1326 | ||
1231 | err_init_adapter: | 1327 | err_ndev: |
1232 | lbs_free_adapter(priv); | ||
1233 | free_netdev(dev); | 1328 | free_netdev(dev); |
1329 | |||
1330 | err_adapter: | ||
1331 | lbs_free_adapter(priv); | ||
1332 | |||
1333 | err_wdev: | ||
1334 | lbs_cfg_free(priv); | ||
1335 | |||
1234 | priv = NULL; | 1336 | priv = NULL; |
1235 | 1337 | ||
1236 | done: | 1338 | done: |
@@ -1272,11 +1374,17 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1272 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 1374 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
1273 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | 1375 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); |
1274 | 1376 | ||
1377 | if (priv->is_deep_sleep) { | ||
1378 | priv->is_deep_sleep = 0; | ||
1379 | wake_up_interruptible(&priv->ds_awake_q); | ||
1380 | } | ||
1381 | |||
1275 | /* Stop the thread servicing the interrupts */ | 1382 | /* Stop the thread servicing the interrupts */ |
1276 | priv->surpriseremoved = 1; | 1383 | priv->surpriseremoved = 1; |
1277 | kthread_stop(priv->main_thread); | 1384 | kthread_stop(priv->main_thread); |
1278 | 1385 | ||
1279 | lbs_free_adapter(priv); | 1386 | lbs_free_adapter(priv); |
1387 | lbs_cfg_free(priv); | ||
1280 | 1388 | ||
1281 | priv->dev = NULL; | 1389 | priv->dev = NULL; |
1282 | free_netdev(dev); | 1390 | free_netdev(dev); |
@@ -1301,8 +1409,8 @@ int lbs_start_card(struct lbs_private *priv) | |||
1301 | /* init 802.11d */ | 1409 | /* init 802.11d */ |
1302 | lbs_init_11d(priv); | 1410 | lbs_init_11d(priv); |
1303 | 1411 | ||
1304 | if (register_netdev(dev)) { | 1412 | if (lbs_cfg_register(priv)) { |
1305 | lbs_pr_err("cannot register ethX device\n"); | 1413 | lbs_pr_err("cannot register device\n"); |
1306 | goto done; | 1414 | goto done; |
1307 | } | 1415 | } |
1308 | 1416 | ||
@@ -1392,6 +1500,7 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1392 | 1500 | ||
1393 | /* Delete the timeout of the currently processing command */ | 1501 | /* Delete the timeout of the currently processing command */ |
1394 | del_timer_sync(&priv->command_timer); | 1502 | del_timer_sync(&priv->command_timer); |
1503 | del_timer_sync(&priv->auto_deepsleep_timer); | ||
1395 | 1504 | ||
1396 | /* Flush pending command nodes */ | 1505 | /* Flush pending command nodes */ |
1397 | spin_lock_irqsave(&priv->driver_lock, flags); | 1506 | spin_lock_irqsave(&priv->driver_lock, flags); |
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index be837a0d2517..69dd19bf9558 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -45,7 +45,6 @@ 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 | /** | 48 | /** |
50 | * @brief Find the channel frequency power info with specific channel | 49 | * @brief Find the channel frequency power info with specific channel |
51 | * | 50 | * |
@@ -709,6 +708,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, | |||
709 | struct iw_param *vwrq, char *extra) | 708 | struct iw_param *vwrq, char *extra) |
710 | { | 709 | { |
711 | struct lbs_private *priv = dev->ml_priv; | 710 | struct lbs_private *priv = dev->ml_priv; |
711 | int ret = 0; | ||
712 | 712 | ||
713 | lbs_deb_enter(LBS_DEB_WEXT); | 713 | lbs_deb_enter(LBS_DEB_WEXT); |
714 | 714 | ||
@@ -737,8 +737,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, | |||
737 | "setting power timeout is not supported\n"); | 737 | "setting power timeout is not supported\n"); |
738 | return -EINVAL; | 738 | return -EINVAL; |
739 | } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { | 739 | } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { |
740 | lbs_deb_wext("setting power period not supported\n"); | 740 | vwrq->value = vwrq->value / 1000; |
741 | return -EINVAL; | 741 | if (!priv->enter_deep_sleep) { |
742 | lbs_pr_err("deep sleep feature is not implemented " | ||
743 | "for this interface driver\n"); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | if (priv->connect_status == LBS_CONNECTED) { | ||
748 | if ((priv->is_auto_deep_sleep_enabled) && | ||
749 | (vwrq->value == -1000)) { | ||
750 | lbs_exit_auto_deep_sleep(priv); | ||
751 | return 0; | ||
752 | } else { | ||
753 | lbs_pr_err("can't use deep sleep cmd in " | ||
754 | "connected state\n"); | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | } | ||
758 | |||
759 | if ((vwrq->value < 0) && (vwrq->value != -1000)) { | ||
760 | lbs_pr_err("unknown option\n"); | ||
761 | return -EINVAL; | ||
762 | } | ||
763 | |||
764 | if (vwrq->value > 0) { | ||
765 | if (!priv->is_auto_deep_sleep_enabled) { | ||
766 | priv->is_activity_detected = 0; | ||
767 | priv->auto_deep_sleep_timeout = vwrq->value; | ||
768 | lbs_enter_auto_deep_sleep(priv); | ||
769 | } else { | ||
770 | priv->auto_deep_sleep_timeout = vwrq->value; | ||
771 | lbs_deb_debugfs("auto deep sleep: " | ||
772 | "already enabled\n"); | ||
773 | } | ||
774 | return 0; | ||
775 | } else { | ||
776 | if (priv->is_auto_deep_sleep_enabled) { | ||
777 | lbs_exit_auto_deep_sleep(priv); | ||
778 | /* Try to exit deep sleep if auto */ | ||
779 | /*deep sleep disabled */ | ||
780 | ret = lbs_set_deep_sleep(priv, 0); | ||
781 | } | ||
782 | if (vwrq->value == 0) | ||
783 | ret = lbs_set_deep_sleep(priv, 1); | ||
784 | else if (vwrq->value == -1000) | ||
785 | ret = lbs_set_deep_sleep(priv, 0); | ||
786 | return ret; | ||
787 | } | ||
742 | } | 788 | } |
743 | 789 | ||
744 | if (priv->psmode != LBS802_11POWERMODECAM) { | 790 | if (priv->psmode != LBS802_11POWERMODECAM) { |
@@ -752,6 +798,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, | |||
752 | } | 798 | } |
753 | 799 | ||
754 | lbs_deb_leave(LBS_DEB_WEXT); | 800 | lbs_deb_leave(LBS_DEB_WEXT); |
801 | |||
755 | return 0; | 802 | return 0; |
756 | } | 803 | } |
757 | 804 | ||
@@ -1000,6 +1047,7 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, | |||
1000 | u8 rates[MAX_RATES + 1]; | 1047 | u8 rates[MAX_RATES + 1]; |
1001 | 1048 | ||
1002 | lbs_deb_enter(LBS_DEB_WEXT); | 1049 | lbs_deb_enter(LBS_DEB_WEXT); |
1050 | |||
1003 | lbs_deb_wext("vwrq->value %d\n", vwrq->value); | 1051 | lbs_deb_wext("vwrq->value %d\n", vwrq->value); |
1004 | lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); | 1052 | lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); |
1005 | 1053 | ||