diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/libertas/main.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 795 |
1 files changed, 188 insertions, 607 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 87b4e497faa2..598080414b17 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -13,12 +13,15 @@ | |||
13 | #include <linux/kfifo.h> | 13 | #include <linux/kfifo.h> |
14 | #include <linux/stddef.h> | 14 | #include <linux/stddef.h> |
15 | #include <linux/ieee80211.h> | 15 | #include <linux/ieee80211.h> |
16 | #include <linux/slab.h> | ||
16 | #include <net/iw_handler.h> | 17 | #include <net/iw_handler.h> |
18 | #include <net/cfg80211.h> | ||
17 | 19 | ||
18 | #include "host.h" | 20 | #include "host.h" |
19 | #include "decl.h" | 21 | #include "decl.h" |
20 | #include "dev.h" | 22 | #include "dev.h" |
21 | #include "wext.h" | 23 | #include "wext.h" |
24 | #include "cfg.h" | ||
22 | #include "debugfs.h" | 25 | #include "debugfs.h" |
23 | #include "scan.h" | 26 | #include "scan.h" |
24 | #include "assoc.h" | 27 | #include "assoc.h" |
@@ -43,119 +46,6 @@ module_param_named(libertas_debug, lbs_debug, int, 0644); | |||
43 | struct cmd_confirm_sleep confirm_sleep; | 46 | struct cmd_confirm_sleep confirm_sleep; |
44 | 47 | ||
45 | 48 | ||
46 | #define LBS_TX_PWR_DEFAULT 20 /*100mW */ | ||
47 | #define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ | ||
48 | #define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ | ||
49 | #define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ | ||
50 | #define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ | ||
51 | |||
52 | /* Format { channel, frequency (MHz), maxtxpower } */ | ||
53 | /* band: 'B/G', region: USA FCC/Canada IC */ | ||
54 | static struct chan_freq_power channel_freq_power_US_BG[] = { | ||
55 | {1, 2412, LBS_TX_PWR_US_DEFAULT}, | ||
56 | {2, 2417, LBS_TX_PWR_US_DEFAULT}, | ||
57 | {3, 2422, LBS_TX_PWR_US_DEFAULT}, | ||
58 | {4, 2427, LBS_TX_PWR_US_DEFAULT}, | ||
59 | {5, 2432, LBS_TX_PWR_US_DEFAULT}, | ||
60 | {6, 2437, LBS_TX_PWR_US_DEFAULT}, | ||
61 | {7, 2442, LBS_TX_PWR_US_DEFAULT}, | ||
62 | {8, 2447, LBS_TX_PWR_US_DEFAULT}, | ||
63 | {9, 2452, LBS_TX_PWR_US_DEFAULT}, | ||
64 | {10, 2457, LBS_TX_PWR_US_DEFAULT}, | ||
65 | {11, 2462, LBS_TX_PWR_US_DEFAULT} | ||
66 | }; | ||
67 | |||
68 | /* band: 'B/G', region: Europe ETSI */ | ||
69 | static struct chan_freq_power channel_freq_power_EU_BG[] = { | ||
70 | {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, | ||
71 | {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, | ||
72 | {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, | ||
73 | {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, | ||
74 | {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, | ||
75 | {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, | ||
76 | {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, | ||
77 | {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, | ||
78 | {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, | ||
79 | {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, | ||
80 | {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, | ||
81 | {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, | ||
82 | {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} | ||
83 | }; | ||
84 | |||
85 | /* band: 'B/G', region: Spain */ | ||
86 | static struct chan_freq_power channel_freq_power_SPN_BG[] = { | ||
87 | {10, 2457, LBS_TX_PWR_DEFAULT}, | ||
88 | {11, 2462, LBS_TX_PWR_DEFAULT} | ||
89 | }; | ||
90 | |||
91 | /* band: 'B/G', region: France */ | ||
92 | static struct chan_freq_power channel_freq_power_FR_BG[] = { | ||
93 | {10, 2457, LBS_TX_PWR_FR_DEFAULT}, | ||
94 | {11, 2462, LBS_TX_PWR_FR_DEFAULT}, | ||
95 | {12, 2467, LBS_TX_PWR_FR_DEFAULT}, | ||
96 | {13, 2472, LBS_TX_PWR_FR_DEFAULT} | ||
97 | }; | ||
98 | |||
99 | /* band: 'B/G', region: Japan */ | ||
100 | static struct chan_freq_power channel_freq_power_JPN_BG[] = { | ||
101 | {1, 2412, LBS_TX_PWR_JP_DEFAULT}, | ||
102 | {2, 2417, LBS_TX_PWR_JP_DEFAULT}, | ||
103 | {3, 2422, LBS_TX_PWR_JP_DEFAULT}, | ||
104 | {4, 2427, LBS_TX_PWR_JP_DEFAULT}, | ||
105 | {5, 2432, LBS_TX_PWR_JP_DEFAULT}, | ||
106 | {6, 2437, LBS_TX_PWR_JP_DEFAULT}, | ||
107 | {7, 2442, LBS_TX_PWR_JP_DEFAULT}, | ||
108 | {8, 2447, LBS_TX_PWR_JP_DEFAULT}, | ||
109 | {9, 2452, LBS_TX_PWR_JP_DEFAULT}, | ||
110 | {10, 2457, LBS_TX_PWR_JP_DEFAULT}, | ||
111 | {11, 2462, LBS_TX_PWR_JP_DEFAULT}, | ||
112 | {12, 2467, LBS_TX_PWR_JP_DEFAULT}, | ||
113 | {13, 2472, LBS_TX_PWR_JP_DEFAULT}, | ||
114 | {14, 2484, LBS_TX_PWR_JP_DEFAULT} | ||
115 | }; | ||
116 | |||
117 | /** | ||
118 | * the structure for channel, frequency and power | ||
119 | */ | ||
120 | struct region_cfp_table { | ||
121 | u8 region; | ||
122 | struct chan_freq_power *cfp_BG; | ||
123 | int cfp_no_BG; | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * the structure for the mapping between region and CFP | ||
128 | */ | ||
129 | static struct region_cfp_table region_cfp_table[] = { | ||
130 | {0x10, /*US FCC */ | ||
131 | channel_freq_power_US_BG, | ||
132 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
133 | } | ||
134 | , | ||
135 | {0x20, /*CANADA IC */ | ||
136 | channel_freq_power_US_BG, | ||
137 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
138 | } | ||
139 | , | ||
140 | {0x30, /*EU*/ channel_freq_power_EU_BG, | ||
141 | ARRAY_SIZE(channel_freq_power_EU_BG), | ||
142 | } | ||
143 | , | ||
144 | {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, | ||
145 | ARRAY_SIZE(channel_freq_power_SPN_BG), | ||
146 | } | ||
147 | , | ||
148 | {0x32, /*FRANCE*/ channel_freq_power_FR_BG, | ||
149 | ARRAY_SIZE(channel_freq_power_FR_BG), | ||
150 | } | ||
151 | , | ||
152 | {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, | ||
153 | ARRAY_SIZE(channel_freq_power_JPN_BG), | ||
154 | } | ||
155 | , | ||
156 | /*Add new region here */ | ||
157 | }; | ||
158 | |||
159 | /** | 49 | /** |
160 | * the table to keep region code | 50 | * the table to keep region code |
161 | */ | 51 | */ |
@@ -163,13 +53,6 @@ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = | |||
163 | { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; | 53 | { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; |
164 | 54 | ||
165 | /** | 55 | /** |
166 | * 802.11b/g supported bitrates (in 500Kb/s units) | ||
167 | */ | ||
168 | u8 lbs_bg_rates[MAX_RATES] = | ||
169 | { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, | ||
170 | 0x00, 0x00 }; | ||
171 | |||
172 | /** | ||
173 | * FW rate table. FW refers to rates by their index in this table, not by the | 56 | * FW rate table. FW refers to rates by their index in this table, not by the |
174 | * rate value itself. Values of 0x00 are | 57 | * rate value itself. Values of 0x00 are |
175 | * reserved positions. | 58 | * reserved positions. |
@@ -212,107 +95,9 @@ u8 lbs_data_rate_to_fw_index(u32 rate) | |||
212 | return 0; | 95 | return 0; |
213 | } | 96 | } |
214 | 97 | ||
215 | /** | ||
216 | * Attributes exported through sysfs | ||
217 | */ | ||
218 | |||
219 | /** | ||
220 | * @brief Get function for sysfs attribute anycast_mask | ||
221 | */ | ||
222 | static ssize_t lbs_anycast_get(struct device *dev, | ||
223 | struct device_attribute *attr, char * buf) | ||
224 | { | ||
225 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
226 | struct cmd_ds_mesh_access mesh_access; | ||
227 | int ret; | ||
228 | |||
229 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
230 | |||
231 | ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access); | ||
232 | if (ret) | ||
233 | return ret; | ||
234 | |||
235 | return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * @brief Set function for sysfs attribute anycast_mask | ||
240 | */ | ||
241 | static ssize_t lbs_anycast_set(struct device *dev, | ||
242 | struct device_attribute *attr, const char * buf, size_t count) | ||
243 | { | ||
244 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
245 | struct cmd_ds_mesh_access mesh_access; | ||
246 | uint32_t datum; | ||
247 | int ret; | ||
248 | |||
249 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
250 | sscanf(buf, "%x", &datum); | ||
251 | mesh_access.data[0] = cpu_to_le32(datum); | ||
252 | |||
253 | ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access); | ||
254 | if (ret) | ||
255 | return ret; | ||
256 | |||
257 | return strlen(buf); | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * @brief Get function for sysfs attribute prb_rsp_limit | ||
262 | */ | ||
263 | static ssize_t lbs_prb_rsp_limit_get(struct device *dev, | ||
264 | struct device_attribute *attr, char *buf) | ||
265 | { | ||
266 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
267 | struct cmd_ds_mesh_access mesh_access; | ||
268 | int ret; | ||
269 | u32 retry_limit; | ||
270 | |||
271 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
272 | mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); | ||
273 | |||
274 | ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, | ||
275 | &mesh_access); | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | |||
279 | retry_limit = le32_to_cpu(mesh_access.data[1]); | ||
280 | return snprintf(buf, 10, "%d\n", retry_limit); | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * @brief Set function for sysfs attribute prb_rsp_limit | ||
285 | */ | ||
286 | static ssize_t lbs_prb_rsp_limit_set(struct device *dev, | ||
287 | struct device_attribute *attr, const char *buf, size_t count) | ||
288 | { | ||
289 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
290 | struct cmd_ds_mesh_access mesh_access; | ||
291 | int ret; | ||
292 | unsigned long retry_limit; | ||
293 | |||
294 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
295 | mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); | ||
296 | |||
297 | if (!strict_strtoul(buf, 10, &retry_limit)) | ||
298 | return -ENOTSUPP; | ||
299 | if (retry_limit > 15) | ||
300 | return -ENOTSUPP; | ||
301 | |||
302 | mesh_access.data[1] = cpu_to_le32(retry_limit); | ||
303 | |||
304 | ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, | ||
305 | &mesh_access); | ||
306 | if (ret) | ||
307 | return ret; | ||
308 | |||
309 | return strlen(buf); | ||
310 | } | ||
311 | 98 | ||
312 | static int lbs_add_rtap(struct lbs_private *priv); | 99 | static int lbs_add_rtap(struct lbs_private *priv); |
313 | static void lbs_remove_rtap(struct lbs_private *priv); | 100 | static void lbs_remove_rtap(struct lbs_private *priv); |
314 | static int lbs_add_mesh(struct lbs_private *priv); | ||
315 | static void lbs_remove_mesh(struct lbs_private *priv); | ||
316 | 101 | ||
317 | 102 | ||
318 | /** | 103 | /** |
@@ -339,7 +124,7 @@ static ssize_t lbs_rtap_set(struct device *dev, | |||
339 | if (priv->monitormode == monitor_mode) | 124 | if (priv->monitormode == monitor_mode) |
340 | return strlen(buf); | 125 | return strlen(buf); |
341 | if (!priv->monitormode) { | 126 | if (!priv->monitormode) { |
342 | if (priv->infra_open || priv->mesh_open) | 127 | if (priv->infra_open || lbs_mesh_open(priv)) |
343 | return -EBUSY; | 128 | return -EBUSY; |
344 | if (priv->mode == IW_MODE_INFRA) | 129 | if (priv->mode == IW_MODE_INFRA) |
345 | lbs_cmd_80211_deauthenticate(priv, | 130 | lbs_cmd_80211_deauthenticate(priv, |
@@ -378,74 +163,7 @@ static ssize_t lbs_rtap_set(struct device *dev, | |||
378 | static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); | 163 | static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); |
379 | 164 | ||
380 | /** | 165 | /** |
381 | * Get function for sysfs attribute mesh | 166 | * @brief This function opens the ethX interface |
382 | */ | ||
383 | static ssize_t lbs_mesh_get(struct device *dev, | ||
384 | struct device_attribute *attr, char * buf) | ||
385 | { | ||
386 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
387 | return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * Set function for sysfs attribute mesh | ||
392 | */ | ||
393 | static ssize_t lbs_mesh_set(struct device *dev, | ||
394 | struct device_attribute *attr, const char * buf, size_t count) | ||
395 | { | ||
396 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
397 | int enable; | ||
398 | int ret, action = CMD_ACT_MESH_CONFIG_STOP; | ||
399 | |||
400 | sscanf(buf, "%x", &enable); | ||
401 | enable = !!enable; | ||
402 | if (enable == !!priv->mesh_dev) | ||
403 | return count; | ||
404 | if (enable) | ||
405 | action = CMD_ACT_MESH_CONFIG_START; | ||
406 | ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); | ||
407 | if (ret) | ||
408 | return ret; | ||
409 | |||
410 | if (enable) | ||
411 | lbs_add_mesh(priv); | ||
412 | else | ||
413 | lbs_remove_mesh(priv); | ||
414 | |||
415 | return count; | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * lbs_mesh attribute to be exported per ethX interface | ||
420 | * through sysfs (/sys/class/net/ethX/lbs_mesh) | ||
421 | */ | ||
422 | static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); | ||
423 | |||
424 | /** | ||
425 | * anycast_mask attribute to be exported per mshX interface | ||
426 | * through sysfs (/sys/class/net/mshX/anycast_mask) | ||
427 | */ | ||
428 | static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); | ||
429 | |||
430 | /** | ||
431 | * prb_rsp_limit attribute to be exported per mshX interface | ||
432 | * through sysfs (/sys/class/net/mshX/prb_rsp_limit) | ||
433 | */ | ||
434 | static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, | ||
435 | lbs_prb_rsp_limit_set); | ||
436 | |||
437 | static struct attribute *lbs_mesh_sysfs_entries[] = { | ||
438 | &dev_attr_anycast_mask.attr, | ||
439 | &dev_attr_prb_rsp_limit.attr, | ||
440 | NULL, | ||
441 | }; | ||
442 | |||
443 | static struct attribute_group lbs_mesh_attr_group = { | ||
444 | .attrs = lbs_mesh_sysfs_entries, | ||
445 | }; | ||
446 | |||
447 | /** | ||
448 | * @brief This function opens the ethX or mshX interface | ||
449 | * | 167 | * |
450 | * @param dev A pointer to net_device structure | 168 | * @param dev A pointer to net_device structure |
451 | * @return 0 or -EBUSY if monitor mode active | 169 | * @return 0 or -EBUSY if monitor mode active |
@@ -464,18 +182,12 @@ static int lbs_dev_open(struct net_device *dev) | |||
464 | goto out; | 182 | goto out; |
465 | } | 183 | } |
466 | 184 | ||
467 | if (dev == priv->mesh_dev) { | 185 | priv->infra_open = 1; |
468 | priv->mesh_open = 1; | ||
469 | priv->mesh_connect_status = LBS_CONNECTED; | ||
470 | netif_carrier_on(dev); | ||
471 | } else { | ||
472 | priv->infra_open = 1; | ||
473 | 186 | ||
474 | if (priv->connect_status == LBS_CONNECTED) | 187 | if (priv->connect_status == LBS_CONNECTED) |
475 | netif_carrier_on(dev); | 188 | netif_carrier_on(dev); |
476 | else | 189 | else |
477 | netif_carrier_off(dev); | 190 | netif_carrier_off(dev); |
478 | } | ||
479 | 191 | ||
480 | if (!priv->tx_pending_len) | 192 | if (!priv->tx_pending_len) |
481 | netif_wake_queue(dev); | 193 | netif_wake_queue(dev); |
@@ -487,33 +199,6 @@ static int lbs_dev_open(struct net_device *dev) | |||
487 | } | 199 | } |
488 | 200 | ||
489 | /** | 201 | /** |
490 | * @brief This function closes the mshX interface | ||
491 | * | ||
492 | * @param dev A pointer to net_device structure | ||
493 | * @return 0 | ||
494 | */ | ||
495 | static int lbs_mesh_stop(struct net_device *dev) | ||
496 | { | ||
497 | struct lbs_private *priv = dev->ml_priv; | ||
498 | |||
499 | lbs_deb_enter(LBS_DEB_MESH); | ||
500 | spin_lock_irq(&priv->driver_lock); | ||
501 | |||
502 | priv->mesh_open = 0; | ||
503 | priv->mesh_connect_status = LBS_DISCONNECTED; | ||
504 | |||
505 | netif_stop_queue(dev); | ||
506 | netif_carrier_off(dev); | ||
507 | |||
508 | spin_unlock_irq(&priv->driver_lock); | ||
509 | |||
510 | schedule_work(&priv->mcast_work); | ||
511 | |||
512 | lbs_deb_leave(LBS_DEB_MESH); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * @brief This function closes the ethX interface | 202 | * @brief This function closes the ethX interface |
518 | * | 203 | * |
519 | * @param dev A pointer to net_device structure | 204 | * @param dev A pointer to net_device structure |
@@ -574,15 +259,17 @@ void lbs_host_to_card_done(struct lbs_private *priv) | |||
574 | priv->dnld_sent = DNLD_RES_RECEIVED; | 259 | priv->dnld_sent = DNLD_RES_RECEIVED; |
575 | 260 | ||
576 | /* Wake main thread if commands are pending */ | 261 | /* Wake main thread if commands are pending */ |
577 | if (!priv->cur_cmd || priv->tx_pending_len > 0) | 262 | if (!priv->cur_cmd || priv->tx_pending_len > 0) { |
578 | wake_up_interruptible(&priv->waitq); | 263 | if (!priv->wakeup_dev_required) |
264 | wake_up_interruptible(&priv->waitq); | ||
265 | } | ||
579 | 266 | ||
580 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 267 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
581 | lbs_deb_leave(LBS_DEB_THREAD); | 268 | lbs_deb_leave(LBS_DEB_THREAD); |
582 | } | 269 | } |
583 | EXPORT_SYMBOL_GPL(lbs_host_to_card_done); | 270 | EXPORT_SYMBOL_GPL(lbs_host_to_card_done); |
584 | 271 | ||
585 | static int lbs_set_mac_address(struct net_device *dev, void *addr) | 272 | int lbs_set_mac_address(struct net_device *dev, void *addr) |
586 | { | 273 | { |
587 | int ret = 0; | 274 | int ret = 0; |
588 | struct lbs_private *priv = dev->ml_priv; | 275 | struct lbs_private *priv = dev->ml_priv; |
@@ -633,15 +320,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, | |||
633 | { | 320 | { |
634 | int i = nr_addrs; | 321 | int i = nr_addrs; |
635 | struct dev_mc_list *mc_list; | 322 | struct dev_mc_list *mc_list; |
323 | int cnt; | ||
636 | 324 | ||
637 | if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) | 325 | if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) |
638 | return nr_addrs; | 326 | return nr_addrs; |
639 | 327 | ||
640 | netif_addr_lock_bh(dev); | 328 | netif_addr_lock_bh(dev); |
641 | for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { | 329 | cnt = netdev_mc_count(dev); |
330 | netdev_for_each_mc_addr(mc_list, dev) { | ||
642 | if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { | 331 | if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { |
643 | lbs_deb_net("mcast address %s:%pM skipped\n", dev->name, | 332 | lbs_deb_net("mcast address %s:%pM skipped\n", dev->name, |
644 | mc_list->dmi_addr); | 333 | mc_list->dmi_addr); |
334 | cnt--; | ||
645 | continue; | 335 | continue; |
646 | } | 336 | } |
647 | 337 | ||
@@ -651,9 +341,10 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, | |||
651 | lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name, | 341 | lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name, |
652 | mc_list->dmi_addr); | 342 | mc_list->dmi_addr); |
653 | i++; | 343 | i++; |
344 | cnt--; | ||
654 | } | 345 | } |
655 | netif_addr_unlock_bh(dev); | 346 | netif_addr_unlock_bh(dev); |
656 | if (mc_list) | 347 | if (cnt) |
657 | return -EOVERFLOW; | 348 | return -EOVERFLOW; |
658 | 349 | ||
659 | return i; | 350 | return i; |
@@ -716,7 +407,7 @@ static void lbs_set_mcast_worker(struct work_struct *work) | |||
716 | lbs_deb_leave(LBS_DEB_NET); | 407 | lbs_deb_leave(LBS_DEB_NET); |
717 | } | 408 | } |
718 | 409 | ||
719 | static void lbs_set_multicast_list(struct net_device *dev) | 410 | void lbs_set_multicast_list(struct net_device *dev) |
720 | { | 411 | { |
721 | struct lbs_private *priv = dev->ml_priv; | 412 | struct lbs_private *priv = dev->ml_priv; |
722 | 413 | ||
@@ -770,9 +461,10 @@ static int lbs_thread(void *data) | |||
770 | shouldsleep = 0; /* We have a command response */ | 461 | shouldsleep = 0; /* We have a command response */ |
771 | else if (priv->cur_cmd) | 462 | else if (priv->cur_cmd) |
772 | shouldsleep = 1; /* Can't send a command; one already running */ | 463 | shouldsleep = 1; /* Can't send a command; one already running */ |
773 | else if (!list_empty(&priv->cmdpendingq)) | 464 | else if (!list_empty(&priv->cmdpendingq) && |
465 | !(priv->wakeup_dev_required)) | ||
774 | shouldsleep = 0; /* We have a command to send */ | 466 | shouldsleep = 0; /* We have a command to send */ |
775 | else if (__kfifo_len(priv->event_fifo)) | 467 | else if (kfifo_len(&priv->event_fifo)) |
776 | shouldsleep = 0; /* We have an event to process */ | 468 | shouldsleep = 0; /* We have an event to process */ |
777 | else | 469 | else |
778 | shouldsleep = 1; /* No command */ | 470 | shouldsleep = 1; /* No command */ |
@@ -822,46 +514,41 @@ static int lbs_thread(void *data) | |||
822 | } | 514 | } |
823 | spin_unlock_irq(&priv->driver_lock); | 515 | spin_unlock_irq(&priv->driver_lock); |
824 | 516 | ||
825 | /* command timeout stuff */ | ||
826 | if (priv->cmd_timed_out && priv->cur_cmd) { | ||
827 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; | ||
828 | |||
829 | if (++priv->nr_retries > 3) { | ||
830 | lbs_pr_info("Excessive timeouts submitting " | ||
831 | "command 0x%04x\n", | ||
832 | le16_to_cpu(cmdnode->cmdbuf->command)); | ||
833 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); | ||
834 | priv->nr_retries = 0; | ||
835 | if (priv->reset_card) | ||
836 | priv->reset_card(priv); | ||
837 | } else { | ||
838 | priv->cur_cmd = NULL; | ||
839 | priv->dnld_sent = DNLD_RES_RECEIVED; | ||
840 | lbs_pr_info("requeueing command 0x%04x due " | ||
841 | "to timeout (#%d)\n", | ||
842 | le16_to_cpu(cmdnode->cmdbuf->command), | ||
843 | priv->nr_retries); | ||
844 | |||
845 | /* Stick it back at the _top_ of the pending queue | ||
846 | for immediate resubmission */ | ||
847 | list_add(&cmdnode->list, &priv->cmdpendingq); | ||
848 | } | ||
849 | } | ||
850 | priv->cmd_timed_out = 0; | ||
851 | |||
852 | /* Process hardware events, e.g. card removed, link lost */ | 517 | /* Process hardware events, e.g. card removed, link lost */ |
853 | spin_lock_irq(&priv->driver_lock); | 518 | spin_lock_irq(&priv->driver_lock); |
854 | while (__kfifo_len(priv->event_fifo)) { | 519 | while (kfifo_len(&priv->event_fifo)) { |
855 | u32 event; | 520 | u32 event; |
856 | 521 | ||
857 | __kfifo_get(priv->event_fifo, (unsigned char *) &event, | 522 | if (kfifo_out(&priv->event_fifo, |
858 | sizeof(event)); | 523 | (unsigned char *) &event, sizeof(event)) != |
524 | sizeof(event)) | ||
525 | break; | ||
859 | spin_unlock_irq(&priv->driver_lock); | 526 | spin_unlock_irq(&priv->driver_lock); |
860 | lbs_process_event(priv, event); | 527 | lbs_process_event(priv, event); |
861 | spin_lock_irq(&priv->driver_lock); | 528 | spin_lock_irq(&priv->driver_lock); |
862 | } | 529 | } |
863 | spin_unlock_irq(&priv->driver_lock); | 530 | spin_unlock_irq(&priv->driver_lock); |
864 | 531 | ||
532 | if (priv->wakeup_dev_required) { | ||
533 | lbs_deb_thread("Waking up device...\n"); | ||
534 | /* Wake up device */ | ||
535 | if (priv->exit_deep_sleep(priv)) | ||
536 | lbs_deb_thread("Wakeup device failed\n"); | ||
537 | continue; | ||
538 | } | ||
539 | |||
540 | /* command timeout stuff */ | ||
541 | if (priv->cmd_timed_out && priv->cur_cmd) { | ||
542 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; | ||
543 | |||
544 | lbs_pr_info("Timeout submitting command 0x%04x\n", | ||
545 | le16_to_cpu(cmdnode->cmdbuf->command)); | ||
546 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); | ||
547 | if (priv->reset_card) | ||
548 | priv->reset_card(priv); | ||
549 | } | ||
550 | priv->cmd_timed_out = 0; | ||
551 | |||
865 | if (!priv->fw_ready) | 552 | if (!priv->fw_ready) |
866 | continue; | 553 | continue; |
867 | 554 | ||
@@ -894,6 +581,9 @@ static int lbs_thread(void *data) | |||
894 | (priv->psstate == PS_STATE_PRE_SLEEP)) | 581 | (priv->psstate == PS_STATE_PRE_SLEEP)) |
895 | continue; | 582 | continue; |
896 | 583 | ||
584 | if (priv->is_deep_sleep) | ||
585 | continue; | ||
586 | |||
897 | /* Execute the next command */ | 587 | /* Execute the next command */ |
898 | if (!priv->dnld_sent && !priv->cur_cmd) | 588 | if (!priv->dnld_sent && !priv->cur_cmd) |
899 | lbs_execute_next_command(priv); | 589 | lbs_execute_next_command(priv); |
@@ -920,7 +610,7 @@ static int lbs_thread(void *data) | |||
920 | if (priv->connect_status == LBS_CONNECTED) | 610 | if (priv->connect_status == LBS_CONNECTED) |
921 | netif_wake_queue(priv->dev); | 611 | netif_wake_queue(priv->dev); |
922 | if (priv->mesh_dev && | 612 | if (priv->mesh_dev && |
923 | priv->mesh_connect_status == LBS_CONNECTED) | 613 | lbs_mesh_connected(priv)) |
924 | netif_wake_queue(priv->mesh_dev); | 614 | netif_wake_queue(priv->mesh_dev); |
925 | } | 615 | } |
926 | } | 616 | } |
@@ -928,6 +618,7 @@ static int lbs_thread(void *data) | |||
928 | } | 618 | } |
929 | 619 | ||
930 | del_timer(&priv->command_timer); | 620 | del_timer(&priv->command_timer); |
621 | del_timer(&priv->auto_deepsleep_timer); | ||
931 | wake_up_all(&priv->cmd_pending); | 622 | wake_up_all(&priv->cmd_pending); |
932 | 623 | ||
933 | lbs_deb_leave(LBS_DEB_THREAD); | 624 | lbs_deb_leave(LBS_DEB_THREAD); |
@@ -1029,7 +720,7 @@ done: | |||
1029 | * This function handles the timeout of command sending. | 720 | * This function handles the timeout of command sending. |
1030 | * It will re-send the same command again. | 721 | * It will re-send the same command again. |
1031 | */ | 722 | */ |
1032 | static void command_timer_fn(unsigned long data) | 723 | static void lbs_cmd_timeout_handler(unsigned long data) |
1033 | { | 724 | { |
1034 | struct lbs_private *priv = (struct lbs_private *)data; | 725 | struct lbs_private *priv = (struct lbs_private *)data; |
1035 | unsigned long flags; | 726 | unsigned long flags; |
@@ -1050,17 +741,61 @@ out: | |||
1050 | lbs_deb_leave(LBS_DEB_CMD); | 741 | lbs_deb_leave(LBS_DEB_CMD); |
1051 | } | 742 | } |
1052 | 743 | ||
1053 | static void lbs_sync_channel_worker(struct work_struct *work) | 744 | /** |
745 | * This function put the device back to deep sleep mode when timer expires | ||
746 | * and no activity (command, event, data etc.) is detected. | ||
747 | */ | ||
748 | static void auto_deepsleep_timer_fn(unsigned long data) | ||
1054 | { | 749 | { |
1055 | struct lbs_private *priv = container_of(work, struct lbs_private, | 750 | struct lbs_private *priv = (struct lbs_private *)data; |
1056 | sync_channel); | 751 | int ret; |
1057 | 752 | ||
1058 | lbs_deb_enter(LBS_DEB_MAIN); | 753 | lbs_deb_enter(LBS_DEB_CMD); |
1059 | if (lbs_update_channel(priv)) | 754 | |
1060 | lbs_pr_info("Channel synchronization failed."); | 755 | if (priv->is_activity_detected) { |
1061 | lbs_deb_leave(LBS_DEB_MAIN); | 756 | priv->is_activity_detected = 0; |
757 | } else { | ||
758 | if (priv->is_auto_deep_sleep_enabled && | ||
759 | (!priv->wakeup_dev_required) && | ||
760 | (priv->connect_status != LBS_CONNECTED)) { | ||
761 | lbs_deb_main("Entering auto deep sleep mode...\n"); | ||
762 | ret = lbs_prepare_and_send_command(priv, | ||
763 | CMD_802_11_DEEP_SLEEP, 0, | ||
764 | 0, 0, NULL); | ||
765 | if (ret) | ||
766 | lbs_pr_err("Enter Deep Sleep command failed\n"); | ||
767 | } | ||
768 | } | ||
769 | mod_timer(&priv->auto_deepsleep_timer , jiffies + | ||
770 | (priv->auto_deep_sleep_timeout * HZ)/1000); | ||
771 | lbs_deb_leave(LBS_DEB_CMD); | ||
772 | } | ||
773 | |||
774 | int lbs_enter_auto_deep_sleep(struct lbs_private *priv) | ||
775 | { | ||
776 | lbs_deb_enter(LBS_DEB_SDIO); | ||
777 | |||
778 | priv->is_auto_deep_sleep_enabled = 1; | ||
779 | if (priv->is_deep_sleep) | ||
780 | priv->wakeup_dev_required = 1; | ||
781 | mod_timer(&priv->auto_deepsleep_timer , | ||
782 | jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); | ||
783 | |||
784 | lbs_deb_leave(LBS_DEB_SDIO); | ||
785 | return 0; | ||
1062 | } | 786 | } |
1063 | 787 | ||
788 | int lbs_exit_auto_deep_sleep(struct lbs_private *priv) | ||
789 | { | ||
790 | lbs_deb_enter(LBS_DEB_SDIO); | ||
791 | |||
792 | priv->is_auto_deep_sleep_enabled = 0; | ||
793 | priv->auto_deep_sleep_timeout = 0; | ||
794 | del_timer(&priv->auto_deepsleep_timer); | ||
795 | |||
796 | lbs_deb_leave(LBS_DEB_SDIO); | ||
797 | return 0; | ||
798 | } | ||
1064 | 799 | ||
1065 | static int lbs_init_adapter(struct lbs_private *priv) | 800 | static int lbs_init_adapter(struct lbs_private *priv) |
1066 | { | 801 | { |
@@ -1089,21 +824,25 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
1089 | memset(priv->current_addr, 0xff, ETH_ALEN); | 824 | memset(priv->current_addr, 0xff, ETH_ALEN); |
1090 | 825 | ||
1091 | priv->connect_status = LBS_DISCONNECTED; | 826 | priv->connect_status = LBS_DISCONNECTED; |
1092 | priv->mesh_connect_status = LBS_DISCONNECTED; | ||
1093 | priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | 827 | priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; |
1094 | priv->mode = IW_MODE_INFRA; | 828 | priv->mode = IW_MODE_INFRA; |
1095 | priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; | 829 | priv->channel = DEFAULT_AD_HOC_CHANNEL; |
1096 | priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; | 830 | priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; |
1097 | priv->radio_on = 1; | 831 | priv->radio_on = 1; |
1098 | priv->enablehwauto = 1; | 832 | priv->enablehwauto = 1; |
1099 | priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
1100 | priv->psmode = LBS802_11POWERMODECAM; | 833 | priv->psmode = LBS802_11POWERMODECAM; |
1101 | priv->psstate = PS_STATE_FULL_POWER; | 834 | priv->psstate = PS_STATE_FULL_POWER; |
835 | priv->is_deep_sleep = 0; | ||
836 | priv->is_auto_deep_sleep_enabled = 0; | ||
837 | priv->wakeup_dev_required = 0; | ||
838 | init_waitqueue_head(&priv->ds_awake_q); | ||
1102 | 839 | ||
1103 | mutex_init(&priv->lock); | 840 | mutex_init(&priv->lock); |
1104 | 841 | ||
1105 | setup_timer(&priv->command_timer, command_timer_fn, | 842 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, |
1106 | (unsigned long)priv); | 843 | (unsigned long)priv); |
844 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, | ||
845 | (unsigned long)priv); | ||
1107 | 846 | ||
1108 | INIT_LIST_HEAD(&priv->cmdfreeq); | 847 | INIT_LIST_HEAD(&priv->cmdfreeq); |
1109 | INIT_LIST_HEAD(&priv->cmdpendingq); | 848 | INIT_LIST_HEAD(&priv->cmdpendingq); |
@@ -1121,10 +860,9 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
1121 | priv->resp_len[0] = priv->resp_len[1] = 0; | 860 | priv->resp_len[0] = priv->resp_len[1] = 0; |
1122 | 861 | ||
1123 | /* Create the event FIFO */ | 862 | /* Create the event FIFO */ |
1124 | priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL); | 863 | ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); |
1125 | if (IS_ERR(priv->event_fifo)) { | 864 | if (ret) { |
1126 | lbs_pr_err("Out of memory allocating event FIFO buffer\n"); | 865 | lbs_pr_err("Out of memory allocating event FIFO buffer\n"); |
1127 | ret = -ENOMEM; | ||
1128 | goto out; | 866 | goto out; |
1129 | } | 867 | } |
1130 | 868 | ||
@@ -1139,9 +877,9 @@ static void lbs_free_adapter(struct lbs_private *priv) | |||
1139 | lbs_deb_enter(LBS_DEB_MAIN); | 877 | lbs_deb_enter(LBS_DEB_MAIN); |
1140 | 878 | ||
1141 | lbs_free_cmd_buffer(priv); | 879 | lbs_free_cmd_buffer(priv); |
1142 | if (priv->event_fifo) | 880 | kfifo_free(&priv->event_fifo); |
1143 | kfifo_free(priv->event_fifo); | ||
1144 | del_timer(&priv->command_timer); | 881 | del_timer(&priv->command_timer); |
882 | del_timer(&priv->auto_deepsleep_timer); | ||
1145 | kfree(priv->networks); | 883 | kfree(priv->networks); |
1146 | priv->networks = NULL; | 884 | priv->networks = NULL; |
1147 | 885 | ||
@@ -1168,31 +906,41 @@ static const struct net_device_ops lbs_netdev_ops = { | |||
1168 | */ | 906 | */ |
1169 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | 907 | struct lbs_private *lbs_add_card(void *card, struct device *dmdev) |
1170 | { | 908 | { |
1171 | struct net_device *dev = NULL; | 909 | struct net_device *dev; |
910 | struct wireless_dev *wdev; | ||
1172 | struct lbs_private *priv = NULL; | 911 | struct lbs_private *priv = NULL; |
1173 | 912 | ||
1174 | lbs_deb_enter(LBS_DEB_MAIN); | 913 | lbs_deb_enter(LBS_DEB_MAIN); |
1175 | 914 | ||
1176 | /* Allocate an Ethernet device and register it */ | 915 | /* Allocate an Ethernet device and register it */ |
1177 | dev = alloc_etherdev(sizeof(struct lbs_private)); | 916 | wdev = lbs_cfg_alloc(dmdev); |
1178 | if (!dev) { | 917 | if (IS_ERR(wdev)) { |
1179 | lbs_pr_err("init wlanX device failed\n"); | 918 | lbs_pr_err("cfg80211 init failed\n"); |
1180 | goto done; | 919 | goto done; |
1181 | } | 920 | } |
1182 | priv = netdev_priv(dev); | 921 | /* TODO? */ |
1183 | dev->ml_priv = priv; | 922 | wdev->iftype = NL80211_IFTYPE_STATION; |
923 | priv = wdev_priv(wdev); | ||
924 | priv->wdev = wdev; | ||
1184 | 925 | ||
1185 | if (lbs_init_adapter(priv)) { | 926 | if (lbs_init_adapter(priv)) { |
1186 | lbs_pr_err("failed to initialize adapter structure.\n"); | 927 | lbs_pr_err("failed to initialize adapter structure.\n"); |
1187 | goto err_init_adapter; | 928 | goto err_wdev; |
1188 | } | 929 | } |
1189 | 930 | ||
931 | //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); | ||
932 | dev = alloc_netdev(0, "wlan%d", ether_setup); | ||
933 | if (!dev) { | ||
934 | dev_err(dmdev, "no memory for network device instance\n"); | ||
935 | goto err_adapter; | ||
936 | } | ||
937 | |||
938 | dev->ieee80211_ptr = wdev; | ||
939 | dev->ml_priv = priv; | ||
940 | SET_NETDEV_DEV(dev, dmdev); | ||
941 | wdev->netdev = dev; | ||
1190 | priv->dev = dev; | 942 | priv->dev = dev; |
1191 | priv->card = card; | ||
1192 | priv->mesh_open = 0; | ||
1193 | priv->infra_open = 0; | ||
1194 | 943 | ||
1195 | /* Setup the OS Interface to our functions */ | ||
1196 | dev->netdev_ops = &lbs_netdev_ops; | 944 | dev->netdev_ops = &lbs_netdev_ops; |
1197 | dev->watchdog_timeo = 5 * HZ; | 945 | dev->watchdog_timeo = 5 * HZ; |
1198 | dev->ethtool_ops = &lbs_ethtool_ops; | 946 | dev->ethtool_ops = &lbs_ethtool_ops; |
@@ -1201,7 +949,13 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1201 | #endif | 949 | #endif |
1202 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | 950 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; |
1203 | 951 | ||
1204 | SET_NETDEV_DEV(dev, dmdev); | 952 | |
953 | // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ?? | ||
954 | |||
955 | |||
956 | priv->card = card; | ||
957 | priv->infra_open = 0; | ||
958 | |||
1205 | 959 | ||
1206 | priv->rtap_net_dev = NULL; | 960 | priv->rtap_net_dev = NULL; |
1207 | strcpy(dev->name, "wlan%d"); | 961 | strcpy(dev->name, "wlan%d"); |
@@ -1211,26 +965,28 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1211 | priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); | 965 | priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); |
1212 | if (IS_ERR(priv->main_thread)) { | 966 | if (IS_ERR(priv->main_thread)) { |
1213 | lbs_deb_thread("Error creating main thread.\n"); | 967 | lbs_deb_thread("Error creating main thread.\n"); |
1214 | goto err_init_adapter; | 968 | goto err_ndev; |
1215 | } | 969 | } |
1216 | 970 | ||
1217 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); | 971 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); |
1218 | INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); | 972 | INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); |
1219 | INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); | 973 | INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); |
1220 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); | 974 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); |
1221 | INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); | ||
1222 | |||
1223 | sprintf(priv->mesh_ssid, "mesh"); | ||
1224 | priv->mesh_ssid_len = 4; | ||
1225 | 975 | ||
1226 | priv->wol_criteria = 0xffffffff; | 976 | priv->wol_criteria = 0xffffffff; |
1227 | priv->wol_gpio = 0xff; | 977 | priv->wol_gpio = 0xff; |
1228 | 978 | ||
1229 | goto done; | 979 | goto done; |
1230 | 980 | ||
1231 | err_init_adapter: | 981 | err_ndev: |
1232 | lbs_free_adapter(priv); | ||
1233 | free_netdev(dev); | 982 | free_netdev(dev); |
983 | |||
984 | err_adapter: | ||
985 | lbs_free_adapter(priv); | ||
986 | |||
987 | err_wdev: | ||
988 | lbs_cfg_free(priv); | ||
989 | |||
1234 | priv = NULL; | 990 | priv = NULL; |
1235 | 991 | ||
1236 | done: | 992 | done: |
@@ -1243,7 +999,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card); | |||
1243 | void lbs_remove_card(struct lbs_private *priv) | 999 | void lbs_remove_card(struct lbs_private *priv) |
1244 | { | 1000 | { |
1245 | struct net_device *dev = priv->dev; | 1001 | struct net_device *dev = priv->dev; |
1246 | union iwreq_data wrqu; | ||
1247 | 1002 | ||
1248 | lbs_deb_enter(LBS_DEB_MAIN); | 1003 | lbs_deb_enter(LBS_DEB_MAIN); |
1249 | 1004 | ||
@@ -1268,15 +1023,19 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1268 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); | 1023 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); |
1269 | } | 1024 | } |
1270 | 1025 | ||
1271 | memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); | 1026 | lbs_send_disconnect_notification(priv); |
1272 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 1027 | |
1273 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | 1028 | if (priv->is_deep_sleep) { |
1029 | priv->is_deep_sleep = 0; | ||
1030 | wake_up_interruptible(&priv->ds_awake_q); | ||
1031 | } | ||
1274 | 1032 | ||
1275 | /* Stop the thread servicing the interrupts */ | 1033 | /* Stop the thread servicing the interrupts */ |
1276 | priv->surpriseremoved = 1; | 1034 | priv->surpriseremoved = 1; |
1277 | kthread_stop(priv->main_thread); | 1035 | kthread_stop(priv->main_thread); |
1278 | 1036 | ||
1279 | lbs_free_adapter(priv); | 1037 | lbs_free_adapter(priv); |
1038 | lbs_cfg_free(priv); | ||
1280 | 1039 | ||
1281 | priv->dev = NULL; | 1040 | priv->dev = NULL; |
1282 | free_netdev(dev); | 1041 | free_netdev(dev); |
@@ -1286,6 +1045,17 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1286 | EXPORT_SYMBOL_GPL(lbs_remove_card); | 1045 | EXPORT_SYMBOL_GPL(lbs_remove_card); |
1287 | 1046 | ||
1288 | 1047 | ||
1048 | static int lbs_rtap_supported(struct lbs_private *priv) | ||
1049 | { | ||
1050 | if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) | ||
1051 | return 1; | ||
1052 | |||
1053 | /* newer firmware use a capability mask */ | ||
1054 | return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && | ||
1055 | (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)); | ||
1056 | } | ||
1057 | |||
1058 | |||
1289 | int lbs_start_card(struct lbs_private *priv) | 1059 | int lbs_start_card(struct lbs_private *priv) |
1290 | { | 1060 | { |
1291 | struct net_device *dev = priv->dev; | 1061 | struct net_device *dev = priv->dev; |
@@ -1298,60 +1068,21 @@ int lbs_start_card(struct lbs_private *priv) | |||
1298 | if (ret) | 1068 | if (ret) |
1299 | goto done; | 1069 | goto done; |
1300 | 1070 | ||
1301 | /* init 802.11d */ | 1071 | if (lbs_cfg_register(priv)) { |
1302 | lbs_init_11d(priv); | 1072 | lbs_pr_err("cannot register device\n"); |
1303 | |||
1304 | if (register_netdev(dev)) { | ||
1305 | lbs_pr_err("cannot register ethX device\n"); | ||
1306 | goto done; | 1073 | goto done; |
1307 | } | 1074 | } |
1308 | 1075 | ||
1309 | lbs_update_channel(priv); | 1076 | lbs_update_channel(priv); |
1310 | 1077 | ||
1311 | /* Check mesh FW version and appropriately send the mesh start | 1078 | lbs_init_mesh(priv); |
1312 | * command | ||
1313 | */ | ||
1314 | if (priv->mesh_fw_ver == MESH_FW_OLD) { | ||
1315 | /* Enable mesh, if supported, and work out which TLV it uses. | ||
1316 | 0x100 + 291 is an unofficial value used in 5.110.20.pXX | ||
1317 | 0x100 + 37 is the official value used in 5.110.21.pXX | ||
1318 | but we check them in that order because 20.pXX doesn't | ||
1319 | give an error -- it just silently fails. */ | ||
1320 | |||
1321 | /* 5.110.20.pXX firmware will fail the command if the channel | ||
1322 | doesn't match the existing channel. But only if the TLV | ||
1323 | is correct. If the channel is wrong, _BOTH_ versions will | ||
1324 | give an error to 0x100+291, and allow 0x100+37 to succeed. | ||
1325 | It's just that 5.110.20.pXX will not have done anything | ||
1326 | useful */ | ||
1327 | |||
1328 | priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; | ||
1329 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | ||
1330 | priv->curbssparams.channel)) { | ||
1331 | priv->mesh_tlv = TLV_TYPE_MESH_ID; | ||
1332 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | ||
1333 | priv->curbssparams.channel)) | ||
1334 | priv->mesh_tlv = 0; | ||
1335 | } | ||
1336 | } else if (priv->mesh_fw_ver == MESH_FW_NEW) { | ||
1337 | /* 10.0.0.pXX new firmwares should succeed with TLV | ||
1338 | * 0x100+37; Do not invoke command with old TLV. | ||
1339 | */ | ||
1340 | priv->mesh_tlv = TLV_TYPE_MESH_ID; | ||
1341 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | ||
1342 | priv->curbssparams.channel)) | ||
1343 | priv->mesh_tlv = 0; | ||
1344 | } | ||
1345 | if (priv->mesh_tlv) { | ||
1346 | lbs_add_mesh(priv); | ||
1347 | |||
1348 | if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) | ||
1349 | lbs_pr_err("cannot register lbs_mesh attribute\n"); | ||
1350 | 1079 | ||
1351 | /* While rtap isn't related to mesh, only mesh-enabled | 1080 | /* |
1352 | * firmware implements the rtap functionality via | 1081 | * While rtap isn't related to mesh, only mesh-enabled |
1353 | * CMD_802_11_MONITOR_MODE. | 1082 | * firmware implements the rtap functionality via |
1354 | */ | 1083 | * CMD_802_11_MONITOR_MODE. |
1084 | */ | ||
1085 | if (lbs_rtap_supported(priv)) { | ||
1355 | if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) | 1086 | if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) |
1356 | lbs_pr_err("cannot register lbs_rtap attribute\n"); | 1087 | lbs_pr_err("cannot register lbs_rtap attribute\n"); |
1357 | } | 1088 | } |
@@ -1385,13 +1116,14 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1385 | netif_carrier_off(dev); | 1116 | netif_carrier_off(dev); |
1386 | 1117 | ||
1387 | lbs_debugfs_remove_one(priv); | 1118 | lbs_debugfs_remove_one(priv); |
1388 | if (priv->mesh_tlv) { | 1119 | lbs_deinit_mesh(priv); |
1389 | device_remove_file(&dev->dev, &dev_attr_lbs_mesh); | 1120 | |
1121 | if (lbs_rtap_supported(priv)) | ||
1390 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); | 1122 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); |
1391 | } | ||
1392 | 1123 | ||
1393 | /* Delete the timeout of the currently processing command */ | 1124 | /* Delete the timeout of the currently processing command */ |
1394 | del_timer_sync(&priv->command_timer); | 1125 | del_timer_sync(&priv->command_timer); |
1126 | del_timer_sync(&priv->auto_deepsleep_timer); | ||
1395 | 1127 | ||
1396 | /* Flush pending command nodes */ | 1128 | /* Flush pending command nodes */ |
1397 | spin_lock_irqsave(&priv->driver_lock, flags); | 1129 | spin_lock_irqsave(&priv->driver_lock, flags); |
@@ -1420,157 +1152,6 @@ out: | |||
1420 | EXPORT_SYMBOL_GPL(lbs_stop_card); | 1152 | EXPORT_SYMBOL_GPL(lbs_stop_card); |
1421 | 1153 | ||
1422 | 1154 | ||
1423 | static const struct net_device_ops mesh_netdev_ops = { | ||
1424 | .ndo_open = lbs_dev_open, | ||
1425 | .ndo_stop = lbs_mesh_stop, | ||
1426 | .ndo_start_xmit = lbs_hard_start_xmit, | ||
1427 | .ndo_set_mac_address = lbs_set_mac_address, | ||
1428 | .ndo_set_multicast_list = lbs_set_multicast_list, | ||
1429 | }; | ||
1430 | |||
1431 | /** | ||
1432 | * @brief This function adds mshX interface | ||
1433 | * | ||
1434 | * @param priv A pointer to the struct lbs_private structure | ||
1435 | * @return 0 if successful, -X otherwise | ||
1436 | */ | ||
1437 | static int lbs_add_mesh(struct lbs_private *priv) | ||
1438 | { | ||
1439 | struct net_device *mesh_dev = NULL; | ||
1440 | int ret = 0; | ||
1441 | |||
1442 | lbs_deb_enter(LBS_DEB_MESH); | ||
1443 | |||
1444 | /* Allocate a virtual mesh device */ | ||
1445 | if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { | ||
1446 | lbs_deb_mesh("init mshX device failed\n"); | ||
1447 | ret = -ENOMEM; | ||
1448 | goto done; | ||
1449 | } | ||
1450 | mesh_dev->ml_priv = priv; | ||
1451 | priv->mesh_dev = mesh_dev; | ||
1452 | |||
1453 | mesh_dev->netdev_ops = &mesh_netdev_ops; | ||
1454 | mesh_dev->ethtool_ops = &lbs_ethtool_ops; | ||
1455 | memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, | ||
1456 | sizeof(priv->dev->dev_addr)); | ||
1457 | |||
1458 | SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); | ||
1459 | |||
1460 | #ifdef WIRELESS_EXT | ||
1461 | mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; | ||
1462 | #endif | ||
1463 | mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | ||
1464 | /* Register virtual mesh interface */ | ||
1465 | ret = register_netdev(mesh_dev); | ||
1466 | if (ret) { | ||
1467 | lbs_pr_err("cannot register mshX virtual interface\n"); | ||
1468 | goto err_free; | ||
1469 | } | ||
1470 | |||
1471 | ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); | ||
1472 | if (ret) | ||
1473 | goto err_unregister; | ||
1474 | |||
1475 | lbs_persist_config_init(mesh_dev); | ||
1476 | |||
1477 | /* Everything successful */ | ||
1478 | ret = 0; | ||
1479 | goto done; | ||
1480 | |||
1481 | err_unregister: | ||
1482 | unregister_netdev(mesh_dev); | ||
1483 | |||
1484 | err_free: | ||
1485 | free_netdev(mesh_dev); | ||
1486 | |||
1487 | done: | ||
1488 | lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); | ||
1489 | return ret; | ||
1490 | } | ||
1491 | |||
1492 | static void lbs_remove_mesh(struct lbs_private *priv) | ||
1493 | { | ||
1494 | struct net_device *mesh_dev; | ||
1495 | |||
1496 | |||
1497 | mesh_dev = priv->mesh_dev; | ||
1498 | if (!mesh_dev) | ||
1499 | return; | ||
1500 | |||
1501 | lbs_deb_enter(LBS_DEB_MESH); | ||
1502 | netif_stop_queue(mesh_dev); | ||
1503 | netif_carrier_off(mesh_dev); | ||
1504 | sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); | ||
1505 | lbs_persist_config_remove(mesh_dev); | ||
1506 | unregister_netdev(mesh_dev); | ||
1507 | priv->mesh_dev = NULL; | ||
1508 | free_netdev(mesh_dev); | ||
1509 | lbs_deb_leave(LBS_DEB_MESH); | ||
1510 | } | ||
1511 | |||
1512 | /** | ||
1513 | * @brief This function finds the CFP in | ||
1514 | * region_cfp_table based on region and band parameter. | ||
1515 | * | ||
1516 | * @param region The region code | ||
1517 | * @param band The band | ||
1518 | * @param cfp_no A pointer to CFP number | ||
1519 | * @return A pointer to CFP | ||
1520 | */ | ||
1521 | struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) | ||
1522 | { | ||
1523 | int i, end; | ||
1524 | |||
1525 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1526 | |||
1527 | end = ARRAY_SIZE(region_cfp_table); | ||
1528 | |||
1529 | for (i = 0; i < end ; i++) { | ||
1530 | lbs_deb_main("region_cfp_table[i].region=%d\n", | ||
1531 | region_cfp_table[i].region); | ||
1532 | if (region_cfp_table[i].region == region) { | ||
1533 | *cfp_no = region_cfp_table[i].cfp_no_BG; | ||
1534 | lbs_deb_leave(LBS_DEB_MAIN); | ||
1535 | return region_cfp_table[i].cfp_BG; | ||
1536 | } | ||
1537 | } | ||
1538 | |||
1539 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); | ||
1540 | return NULL; | ||
1541 | } | ||
1542 | |||
1543 | int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) | ||
1544 | { | ||
1545 | int ret = 0; | ||
1546 | int i = 0; | ||
1547 | |||
1548 | struct chan_freq_power *cfp; | ||
1549 | int cfp_no; | ||
1550 | |||
1551 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1552 | |||
1553 | memset(priv->region_channel, 0, sizeof(priv->region_channel)); | ||
1554 | |||
1555 | cfp = lbs_get_region_cfp_table(region, &cfp_no); | ||
1556 | if (cfp != NULL) { | ||
1557 | priv->region_channel[i].nrcfp = cfp_no; | ||
1558 | priv->region_channel[i].CFP = cfp; | ||
1559 | } else { | ||
1560 | lbs_deb_main("wrong region code %#x in band B/G\n", | ||
1561 | region); | ||
1562 | ret = -1; | ||
1563 | goto out; | ||
1564 | } | ||
1565 | priv->region_channel[i].valid = 1; | ||
1566 | priv->region_channel[i].region = region; | ||
1567 | priv->region_channel[i].band = band; | ||
1568 | i++; | ||
1569 | out: | ||
1570 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); | ||
1571 | return ret; | ||
1572 | } | ||
1573 | |||
1574 | void lbs_queue_event(struct lbs_private *priv, u32 event) | 1155 | void lbs_queue_event(struct lbs_private *priv, u32 event) |
1575 | { | 1156 | { |
1576 | unsigned long flags; | 1157 | unsigned long flags; |
@@ -1581,7 +1162,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) | |||
1581 | if (priv->psstate == PS_STATE_SLEEP) | 1162 | if (priv->psstate == PS_STATE_SLEEP) |
1582 | priv->psstate = PS_STATE_AWAKE; | 1163 | priv->psstate = PS_STATE_AWAKE; |
1583 | 1164 | ||
1584 | __kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32)); | 1165 | kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); |
1585 | 1166 | ||
1586 | wake_up_interruptible(&priv->waitq); | 1167 | wake_up_interruptible(&priv->waitq); |
1587 | 1168 | ||