diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 855 |
1 files changed, 396 insertions, 459 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 2a864b24291d..6036d0206fec 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -22,22 +22,18 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
28 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
29 | #include <linux/irq.h> | ||
30 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
31 | #include <linux/crc32.h> | 28 | #include <linux/crc32.h> |
32 | #include <linux/etherdevice.h> | 29 | #include <linux/etherdevice.h> |
33 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
34 | #include <linux/spi/wl12xx.h> | ||
35 | #include <linux/inetdevice.h> | 31 | #include <linux/inetdevice.h> |
32 | #include <linux/platform_device.h> | ||
36 | 33 | ||
37 | #include "wl1271.h" | 34 | #include "wl1271.h" |
38 | #include "wl12xx_80211.h" | 35 | #include "wl12xx_80211.h" |
39 | #include "wl1271_reg.h" | 36 | #include "wl1271_reg.h" |
40 | #include "wl1271_spi.h" | ||
41 | #include "wl1271_io.h" | 37 | #include "wl1271_io.h" |
42 | #include "wl1271_event.h" | 38 | #include "wl1271_event.h" |
43 | #include "wl1271_tx.h" | 39 | #include "wl1271_tx.h" |
@@ -53,17 +49,57 @@ | |||
53 | 49 | ||
54 | static struct conf_drv_settings default_conf = { | 50 | static struct conf_drv_settings default_conf = { |
55 | .sg = { | 51 | .sg = { |
56 | .per_threshold = 7500, | 52 | .params = { |
57 | .max_scan_compensation_time = 120000, | 53 | [CONF_SG_BT_PER_THRESHOLD] = 7500, |
58 | .nfs_sample_interval = 400, | 54 | [CONF_SG_HV3_MAX_OVERRIDE] = 0, |
59 | .load_ratio = 50, | 55 | [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, |
60 | .auto_ps_mode = 0, | 56 | [CONF_SG_BT_LOAD_RATIO] = 50, |
61 | .probe_req_compensation = 170, | 57 | [CONF_SG_AUTO_PS_MODE] = 0, |
62 | .scan_window_compensation = 50, | 58 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, |
63 | .antenna_config = 0, | 59 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, |
64 | .beacon_miss_threshold = 60, | 60 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, |
65 | .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, | 61 | [CONF_SG_BEACON_MISS_PERCENT] = 60, |
66 | .rate_adaptation_snr = 0 | 62 | [CONF_SG_RATE_ADAPT_THRESH] = 12, |
63 | [CONF_SG_RATE_ADAPT_SNR] = 0, | ||
64 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, | ||
65 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30, | ||
66 | [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8, | ||
67 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, | ||
68 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50, | ||
69 | /* Note: with UPSD, this should be 4 */ | ||
70 | [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8, | ||
71 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, | ||
72 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, | ||
73 | [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20, | ||
74 | /* Note: with UPDS, this should be 15 */ | ||
75 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, | ||
76 | /* Note: with UPDS, this should be 50 */ | ||
77 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40, | ||
78 | /* Note: with UPDS, this should be 10 */ | ||
79 | [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20, | ||
80 | [CONF_SG_RXT] = 1200, | ||
81 | [CONF_SG_TXT] = 1000, | ||
82 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | ||
83 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | ||
84 | [CONF_SG_UPSD_TIMEOUT] = 10, | ||
85 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, | ||
86 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, | ||
87 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, | ||
88 | [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, | ||
89 | [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, | ||
90 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, | ||
91 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, | ||
92 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, | ||
93 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, | ||
94 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | ||
95 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, | ||
96 | [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, | ||
97 | [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, | ||
98 | [CONF_SG_HV3_MAX_SERVED] = 6, | ||
99 | [CONF_SG_DHCP_TIME] = 5000, | ||
100 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | ||
101 | }, | ||
102 | .state = CONF_SG_PROTECTIVE, | ||
67 | }, | 103 | }, |
68 | .rx = { | 104 | .rx = { |
69 | .rx_msdu_life_time = 512000, | 105 | .rx_msdu_life_time = 512000, |
@@ -245,6 +281,21 @@ static struct conf_drv_settings default_conf = { | |||
245 | } | 281 | } |
246 | }; | 282 | }; |
247 | 283 | ||
284 | static void wl1271_device_release(struct device *dev) | ||
285 | { | ||
286 | |||
287 | } | ||
288 | |||
289 | static struct platform_device wl1271_device = { | ||
290 | .name = "wl1271", | ||
291 | .id = -1, | ||
292 | |||
293 | /* device model insists to have a release function */ | ||
294 | .dev = { | ||
295 | .release = wl1271_device_release, | ||
296 | }, | ||
297 | }; | ||
298 | |||
248 | static LIST_HEAD(wl_list); | 299 | static LIST_HEAD(wl_list); |
249 | 300 | ||
250 | static void wl1271_conf_init(struct wl1271 *wl) | 301 | static void wl1271_conf_init(struct wl1271 *wl) |
@@ -364,30 +415,14 @@ static int wl1271_plt_init(struct wl1271 *wl) | |||
364 | return ret; | 415 | return ret; |
365 | } | 416 | } |
366 | 417 | ||
367 | static void wl1271_disable_interrupts(struct wl1271 *wl) | ||
368 | { | ||
369 | disable_irq(wl->irq); | ||
370 | } | ||
371 | |||
372 | static void wl1271_power_off(struct wl1271 *wl) | ||
373 | { | ||
374 | wl->set_power(false); | ||
375 | clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
376 | } | ||
377 | |||
378 | static void wl1271_power_on(struct wl1271 *wl) | ||
379 | { | ||
380 | wl->set_power(true); | ||
381 | set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
382 | } | ||
383 | |||
384 | static void wl1271_fw_status(struct wl1271 *wl, | 418 | static void wl1271_fw_status(struct wl1271 *wl, |
385 | struct wl1271_fw_status *status) | 419 | struct wl1271_fw_status *status) |
386 | { | 420 | { |
421 | struct timespec ts; | ||
387 | u32 total = 0; | 422 | u32 total = 0; |
388 | int i; | 423 | int i; |
389 | 424 | ||
390 | wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); | 425 | wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); |
391 | 426 | ||
392 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " | 427 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " |
393 | "drv_rx_counter = %d, tx_results_counter = %d)", | 428 | "drv_rx_counter = %d, tx_results_counter = %d)", |
@@ -412,14 +447,19 @@ static void wl1271_fw_status(struct wl1271 *wl, | |||
412 | ieee80211_queue_work(wl->hw, &wl->tx_work); | 447 | ieee80211_queue_work(wl->hw, &wl->tx_work); |
413 | 448 | ||
414 | /* update the host-chipset time offset */ | 449 | /* update the host-chipset time offset */ |
415 | wl->time_offset = jiffies_to_usecs(jiffies) - | 450 | getnstimeofday(&ts); |
416 | le32_to_cpu(status->fw_localtime); | 451 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - |
452 | (s64)le32_to_cpu(status->fw_localtime); | ||
417 | } | 453 | } |
418 | 454 | ||
455 | #define WL1271_IRQ_MAX_LOOPS 10 | ||
456 | |||
419 | static void wl1271_irq_work(struct work_struct *work) | 457 | static void wl1271_irq_work(struct work_struct *work) |
420 | { | 458 | { |
421 | int ret; | 459 | int ret; |
422 | u32 intr; | 460 | u32 intr; |
461 | int loopcount = WL1271_IRQ_MAX_LOOPS; | ||
462 | unsigned long flags; | ||
423 | struct wl1271 *wl = | 463 | struct wl1271 *wl = |
424 | container_of(work, struct wl1271, irq_work); | 464 | container_of(work, struct wl1271, irq_work); |
425 | 465 | ||
@@ -427,91 +467,77 @@ static void wl1271_irq_work(struct work_struct *work) | |||
427 | 467 | ||
428 | wl1271_debug(DEBUG_IRQ, "IRQ work"); | 468 | wl1271_debug(DEBUG_IRQ, "IRQ work"); |
429 | 469 | ||
430 | if (wl->state == WL1271_STATE_OFF) | 470 | if (unlikely(wl->state == WL1271_STATE_OFF)) |
431 | goto out; | 471 | goto out; |
432 | 472 | ||
433 | ret = wl1271_ps_elp_wakeup(wl, true); | 473 | ret = wl1271_ps_elp_wakeup(wl, true); |
434 | if (ret < 0) | 474 | if (ret < 0) |
435 | goto out; | 475 | goto out; |
436 | 476 | ||
437 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | 477 | spin_lock_irqsave(&wl->wl_lock, flags); |
438 | 478 | while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) { | |
439 | wl1271_fw_status(wl, wl->fw_status); | 479 | clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags); |
440 | intr = le32_to_cpu(wl->fw_status->intr); | 480 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
441 | if (!intr) { | 481 | loopcount--; |
442 | wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); | 482 | |
443 | goto out_sleep; | 483 | wl1271_fw_status(wl, wl->fw_status); |
444 | } | 484 | intr = le32_to_cpu(wl->fw_status->intr); |
485 | if (!intr) { | ||
486 | wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); | ||
487 | continue; | ||
488 | } | ||
445 | 489 | ||
446 | intr &= WL1271_INTR_MASK; | 490 | intr &= WL1271_INTR_MASK; |
447 | 491 | ||
448 | if (intr & WL1271_ACX_INTR_EVENT_A) { | 492 | if (intr & WL1271_ACX_INTR_DATA) { |
449 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); | 493 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); |
450 | wl1271_event_handle(wl, 0); | ||
451 | } | ||
452 | 494 | ||
453 | if (intr & WL1271_ACX_INTR_EVENT_B) { | 495 | /* check for tx results */ |
454 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); | 496 | if (wl->fw_status->tx_results_counter != |
455 | wl1271_event_handle(wl, 1); | 497 | (wl->tx_results_count & 0xff)) |
456 | } | 498 | wl1271_tx_complete(wl); |
457 | 499 | ||
458 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) | 500 | wl1271_rx(wl, wl->fw_status); |
459 | wl1271_debug(DEBUG_IRQ, | 501 | } |
460 | "WL1271_ACX_INTR_INIT_COMPLETE"); | ||
461 | 502 | ||
462 | if (intr & WL1271_ACX_INTR_HW_AVAILABLE) | 503 | if (intr & WL1271_ACX_INTR_EVENT_A) { |
463 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); | 504 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); |
505 | wl1271_event_handle(wl, 0); | ||
506 | } | ||
464 | 507 | ||
465 | if (intr & WL1271_ACX_INTR_DATA) { | 508 | if (intr & WL1271_ACX_INTR_EVENT_B) { |
466 | u8 tx_res_cnt = wl->fw_status->tx_results_counter - | 509 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); |
467 | wl->tx_results_count; | 510 | wl1271_event_handle(wl, 1); |
511 | } | ||
468 | 512 | ||
469 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); | 513 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) |
514 | wl1271_debug(DEBUG_IRQ, | ||
515 | "WL1271_ACX_INTR_INIT_COMPLETE"); | ||
470 | 516 | ||
471 | /* check for tx results */ | 517 | if (intr & WL1271_ACX_INTR_HW_AVAILABLE) |
472 | if (tx_res_cnt) | 518 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); |
473 | wl1271_tx_complete(wl, tx_res_cnt); | ||
474 | 519 | ||
475 | wl1271_rx(wl, wl->fw_status); | 520 | spin_lock_irqsave(&wl->wl_lock, flags); |
476 | } | 521 | } |
477 | 522 | ||
478 | out_sleep: | 523 | if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags)) |
479 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, | 524 | ieee80211_queue_work(wl->hw, &wl->irq_work); |
480 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | 525 | else |
526 | clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
527 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
528 | |||
481 | wl1271_ps_elp_sleep(wl); | 529 | wl1271_ps_elp_sleep(wl); |
482 | 530 | ||
483 | out: | 531 | out: |
484 | mutex_unlock(&wl->mutex); | 532 | mutex_unlock(&wl->mutex); |
485 | } | 533 | } |
486 | 534 | ||
487 | static irqreturn_t wl1271_irq(int irq, void *cookie) | ||
488 | { | ||
489 | struct wl1271 *wl; | ||
490 | unsigned long flags; | ||
491 | |||
492 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
493 | |||
494 | wl = cookie; | ||
495 | |||
496 | /* complete the ELP completion */ | ||
497 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
498 | if (wl->elp_compl) { | ||
499 | complete(wl->elp_compl); | ||
500 | wl->elp_compl = NULL; | ||
501 | } | ||
502 | |||
503 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
504 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
505 | |||
506 | return IRQ_HANDLED; | ||
507 | } | ||
508 | |||
509 | static int wl1271_fetch_firmware(struct wl1271 *wl) | 535 | static int wl1271_fetch_firmware(struct wl1271 *wl) |
510 | { | 536 | { |
511 | const struct firmware *fw; | 537 | const struct firmware *fw; |
512 | int ret; | 538 | int ret; |
513 | 539 | ||
514 | ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev); | 540 | ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); |
515 | 541 | ||
516 | if (ret < 0) { | 542 | if (ret < 0) { |
517 | wl1271_error("could not get firmware: %d", ret); | 543 | wl1271_error("could not get firmware: %d", ret); |
@@ -544,46 +570,12 @@ out: | |||
544 | return ret; | 570 | return ret; |
545 | } | 571 | } |
546 | 572 | ||
547 | static int wl1271_update_mac_addr(struct wl1271 *wl) | ||
548 | { | ||
549 | int ret = 0; | ||
550 | u8 *nvs_ptr = (u8 *)wl->nvs->nvs; | ||
551 | |||
552 | /* get mac address from the NVS */ | ||
553 | wl->mac_addr[0] = nvs_ptr[11]; | ||
554 | wl->mac_addr[1] = nvs_ptr[10]; | ||
555 | wl->mac_addr[2] = nvs_ptr[6]; | ||
556 | wl->mac_addr[3] = nvs_ptr[5]; | ||
557 | wl->mac_addr[4] = nvs_ptr[4]; | ||
558 | wl->mac_addr[5] = nvs_ptr[3]; | ||
559 | |||
560 | /* FIXME: if it is a zero-address, we should bail out. Now, instead, | ||
561 | we randomize an address */ | ||
562 | if (is_zero_ether_addr(wl->mac_addr)) { | ||
563 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
564 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
565 | get_random_bytes(wl->mac_addr + 3, 3); | ||
566 | |||
567 | /* update this address to the NVS */ | ||
568 | nvs_ptr[11] = wl->mac_addr[0]; | ||
569 | nvs_ptr[10] = wl->mac_addr[1]; | ||
570 | nvs_ptr[6] = wl->mac_addr[2]; | ||
571 | nvs_ptr[5] = wl->mac_addr[3]; | ||
572 | nvs_ptr[4] = wl->mac_addr[4]; | ||
573 | nvs_ptr[3] = wl->mac_addr[5]; | ||
574 | } | ||
575 | |||
576 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
577 | |||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | static int wl1271_fetch_nvs(struct wl1271 *wl) | 573 | static int wl1271_fetch_nvs(struct wl1271 *wl) |
582 | { | 574 | { |
583 | const struct firmware *fw; | 575 | const struct firmware *fw; |
584 | int ret; | 576 | int ret; |
585 | 577 | ||
586 | ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev); | 578 | ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); |
587 | 579 | ||
588 | if (ret < 0) { | 580 | if (ret < 0) { |
589 | wl1271_error("could not get nvs file: %d", ret); | 581 | wl1271_error("could not get nvs file: %d", ret); |
@@ -607,8 +599,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
607 | 599 | ||
608 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); | 600 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); |
609 | 601 | ||
610 | ret = wl1271_update_mac_addr(wl); | ||
611 | |||
612 | out: | 602 | out: |
613 | release_firmware(fw); | 603 | release_firmware(fw); |
614 | 604 | ||
@@ -825,15 +815,13 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
825 | * The workqueue is slow to process the tx_queue and we need stop | 815 | * The workqueue is slow to process the tx_queue and we need stop |
826 | * the queue here, otherwise the queue will get too long. | 816 | * the queue here, otherwise the queue will get too long. |
827 | */ | 817 | */ |
828 | if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) { | 818 | if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { |
829 | ieee80211_stop_queues(wl->hw); | 819 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); |
830 | 820 | ||
831 | /* | 821 | spin_lock_irqsave(&wl->wl_lock, flags); |
832 | * FIXME: this is racy, the variable is not properly | 822 | ieee80211_stop_queues(wl->hw); |
833 | * protected. Maybe fix this by removing the stupid | ||
834 | * variable altogether and checking the real queue state? | ||
835 | */ | ||
836 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | 823 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); |
824 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
837 | } | 825 | } |
838 | 826 | ||
839 | return NETDEV_TX_OK; | 827 | return NETDEV_TX_OK; |
@@ -928,13 +916,58 @@ static struct notifier_block wl1271_dev_notifier = { | |||
928 | 916 | ||
929 | static int wl1271_op_start(struct ieee80211_hw *hw) | 917 | static int wl1271_op_start(struct ieee80211_hw *hw) |
930 | { | 918 | { |
919 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
920 | |||
921 | /* | ||
922 | * We have to delay the booting of the hardware because | ||
923 | * we need to know the local MAC address before downloading and | ||
924 | * initializing the firmware. The MAC address cannot be changed | ||
925 | * after boot, and without the proper MAC address, the firmware | ||
926 | * will not function properly. | ||
927 | * | ||
928 | * The MAC address is first known when the corresponding interface | ||
929 | * is added. That is where we will initialize the hardware. | ||
930 | */ | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
936 | { | ||
937 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
938 | } | ||
939 | |||
940 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
941 | struct ieee80211_vif *vif) | ||
942 | { | ||
931 | struct wl1271 *wl = hw->priv; | 943 | struct wl1271 *wl = hw->priv; |
932 | int retries = WL1271_BOOT_RETRIES; | 944 | int retries = WL1271_BOOT_RETRIES; |
933 | int ret = 0; | 945 | int ret = 0; |
934 | 946 | ||
935 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | 947 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", |
948 | vif->type, vif->addr); | ||
936 | 949 | ||
937 | mutex_lock(&wl->mutex); | 950 | mutex_lock(&wl->mutex); |
951 | if (wl->vif) { | ||
952 | ret = -EBUSY; | ||
953 | goto out; | ||
954 | } | ||
955 | |||
956 | wl->vif = vif; | ||
957 | |||
958 | switch (vif->type) { | ||
959 | case NL80211_IFTYPE_STATION: | ||
960 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
961 | break; | ||
962 | case NL80211_IFTYPE_ADHOC: | ||
963 | wl->bss_type = BSS_TYPE_IBSS; | ||
964 | break; | ||
965 | default: | ||
966 | ret = -EOPNOTSUPP; | ||
967 | goto out; | ||
968 | } | ||
969 | |||
970 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||
938 | 971 | ||
939 | if (wl->state != WL1271_STATE_OFF) { | 972 | if (wl->state != WL1271_STATE_OFF) { |
940 | wl1271_error("cannot start because not in off state: %d", | 973 | wl1271_error("cannot start because not in off state: %d", |
@@ -990,19 +1023,20 @@ out: | |||
990 | return ret; | 1023 | return ret; |
991 | } | 1024 | } |
992 | 1025 | ||
993 | static void wl1271_op_stop(struct ieee80211_hw *hw) | 1026 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, |
1027 | struct ieee80211_vif *vif) | ||
994 | { | 1028 | { |
995 | struct wl1271 *wl = hw->priv; | 1029 | struct wl1271 *wl = hw->priv; |
996 | int i; | 1030 | int i; |
997 | 1031 | ||
998 | wl1271_info("down"); | ||
999 | |||
1000 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
1001 | |||
1002 | unregister_inetaddr_notifier(&wl1271_dev_notifier); | 1032 | unregister_inetaddr_notifier(&wl1271_dev_notifier); |
1003 | list_del(&wl->list); | ||
1004 | 1033 | ||
1005 | mutex_lock(&wl->mutex); | 1034 | mutex_lock(&wl->mutex); |
1035 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1036 | |||
1037 | wl1271_info("down"); | ||
1038 | |||
1039 | list_del(&wl->list); | ||
1006 | 1040 | ||
1007 | WARN_ON(wl->state != WL1271_STATE_ON); | 1041 | WARN_ON(wl->state != WL1271_STATE_ON); |
1008 | 1042 | ||
@@ -1040,13 +1074,14 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1040 | wl->tx_results_count = 0; | 1074 | wl->tx_results_count = 0; |
1041 | wl->tx_packets_count = 0; | 1075 | wl->tx_packets_count = 0; |
1042 | wl->tx_security_last_seq = 0; | 1076 | wl->tx_security_last_seq = 0; |
1043 | wl->tx_security_seq_16 = 0; | 1077 | wl->tx_security_seq = 0; |
1044 | wl->tx_security_seq_32 = 0; | ||
1045 | wl->time_offset = 0; | 1078 | wl->time_offset = 0; |
1046 | wl->session_counter = 0; | 1079 | wl->session_counter = 0; |
1047 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; | 1080 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; |
1048 | wl->sta_rate_set = 0; | 1081 | wl->sta_rate_set = 0; |
1049 | wl->flags = 0; | 1082 | wl->flags = 0; |
1083 | wl->vif = NULL; | ||
1084 | wl->filters = 0; | ||
1050 | 1085 | ||
1051 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1086 | for (i = 0; i < NUM_TX_QUEUES; i++) |
1052 | wl->tx_blocks_freed[i] = 0; | 1087 | wl->tx_blocks_freed[i] = 0; |
@@ -1055,119 +1090,39 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1055 | mutex_unlock(&wl->mutex); | 1090 | mutex_unlock(&wl->mutex); |
1056 | } | 1091 | } |
1057 | 1092 | ||
1058 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | 1093 | static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) |
1059 | struct ieee80211_vif *vif) | ||
1060 | { | 1094 | { |
1061 | struct wl1271 *wl = hw->priv; | 1095 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; |
1062 | int ret = 0; | 1096 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; |
1063 | |||
1064 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||
1065 | vif->type, vif->addr); | ||
1066 | 1097 | ||
1067 | mutex_lock(&wl->mutex); | 1098 | /* combine requested filters with current filter config */ |
1068 | if (wl->vif) { | 1099 | filters = wl->filters | filters; |
1069 | ret = -EBUSY; | ||
1070 | goto out; | ||
1071 | } | ||
1072 | 1100 | ||
1073 | wl->vif = vif; | 1101 | wl1271_debug(DEBUG_FILTERS, "RX filters set: "); |
1074 | 1102 | ||
1075 | switch (vif->type) { | 1103 | if (filters & FIF_PROMISC_IN_BSS) { |
1076 | case NL80211_IFTYPE_STATION: | 1104 | wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS"); |
1077 | wl->bss_type = BSS_TYPE_STA_BSS; | 1105 | wl->rx_config &= ~CFG_UNI_FILTER_EN; |
1078 | break; | 1106 | wl->rx_config |= CFG_BSSID_FILTER_EN; |
1079 | case NL80211_IFTYPE_ADHOC: | ||
1080 | wl->bss_type = BSS_TYPE_IBSS; | ||
1081 | break; | ||
1082 | default: | ||
1083 | ret = -EOPNOTSUPP; | ||
1084 | goto out; | ||
1085 | } | 1107 | } |
1086 | 1108 | if (filters & FIF_BCN_PRBRESP_PROMISC) { | |
1087 | /* FIXME: what if conf->mac_addr changes? */ | 1109 | wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC"); |
1088 | 1110 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | |
1089 | out: | 1111 | wl->rx_config &= ~CFG_SSID_FILTER_EN; |
1090 | mutex_unlock(&wl->mutex); | ||
1091 | return ret; | ||
1092 | } | ||
1093 | |||
1094 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
1095 | struct ieee80211_vif *vif) | ||
1096 | { | ||
1097 | struct wl1271 *wl = hw->priv; | ||
1098 | |||
1099 | mutex_lock(&wl->mutex); | ||
1100 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1101 | wl->vif = NULL; | ||
1102 | mutex_unlock(&wl->mutex); | ||
1103 | } | ||
1104 | |||
1105 | #if 0 | ||
1106 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, | ||
1107 | struct ieee80211_vif *vif, | ||
1108 | struct ieee80211_if_conf *conf) | ||
1109 | { | ||
1110 | struct wl1271 *wl = hw->priv; | ||
1111 | struct sk_buff *beacon; | ||
1112 | int ret; | ||
1113 | |||
1114 | wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM", | ||
1115 | conf->bssid); | ||
1116 | wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, | ||
1117 | conf->ssid_len); | ||
1118 | |||
1119 | mutex_lock(&wl->mutex); | ||
1120 | |||
1121 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1122 | if (ret < 0) | ||
1123 | goto out; | ||
1124 | |||
1125 | if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) { | ||
1126 | wl1271_debug(DEBUG_MAC80211, "bssid changed"); | ||
1127 | |||
1128 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | ||
1129 | |||
1130 | ret = wl1271_cmd_join(wl); | ||
1131 | if (ret < 0) | ||
1132 | goto out_sleep; | ||
1133 | |||
1134 | ret = wl1271_cmd_build_null_data(wl); | ||
1135 | if (ret < 0) | ||
1136 | goto out_sleep; | ||
1137 | } | 1112 | } |
1138 | 1113 | if (filters & FIF_OTHER_BSS) { | |
1139 | wl->ssid_len = conf->ssid_len; | 1114 | wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS"); |
1140 | if (wl->ssid_len) | 1115 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; |
1141 | memcpy(wl->ssid, conf->ssid, wl->ssid_len); | 1116 | } |
1142 | 1117 | if (filters & FIF_CONTROL) { | |
1143 | if (conf->changed & IEEE80211_IFCC_BEACON) { | 1118 | wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL"); |
1144 | beacon = ieee80211_beacon_get(hw, vif); | 1119 | wl->rx_filter |= CFG_RX_CTL_EN; |
1145 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | 1120 | } |
1146 | beacon->data, beacon->len); | 1121 | if (filters & FIF_FCSFAIL) { |
1147 | 1122 | wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL"); | |
1148 | if (ret < 0) { | 1123 | wl->rx_filter |= CFG_RX_FCS_ERROR; |
1149 | dev_kfree_skb(beacon); | ||
1150 | goto out_sleep; | ||
1151 | } | ||
1152 | |||
1153 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, | ||
1154 | beacon->data, beacon->len); | ||
1155 | |||
1156 | dev_kfree_skb(beacon); | ||
1157 | |||
1158 | if (ret < 0) | ||
1159 | goto out_sleep; | ||
1160 | } | 1124 | } |
1161 | |||
1162 | out_sleep: | ||
1163 | wl1271_ps_elp_sleep(wl); | ||
1164 | |||
1165 | out: | ||
1166 | mutex_unlock(&wl->mutex); | ||
1167 | |||
1168 | return ret; | ||
1169 | } | 1125 | } |
1170 | #endif | ||
1171 | 1126 | ||
1172 | static int wl1271_join_channel(struct wl1271 *wl, int channel) | 1127 | static int wl1271_join_channel(struct wl1271 *wl, int channel) |
1173 | { | 1128 | { |
@@ -1176,17 +1131,16 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel) | |||
1176 | static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, | 1131 | static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, |
1177 | 0xad, 0xbe, 0xef }; | 1132 | 0xad, 0xbe, 0xef }; |
1178 | 1133 | ||
1179 | /* the dummy join is not required for ad-hoc */ | ||
1180 | if (wl->bss_type == BSS_TYPE_IBSS) | ||
1181 | goto out; | ||
1182 | |||
1183 | /* disable mac filter, so we hear everything */ | ||
1184 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
1185 | |||
1186 | wl->channel = channel; | 1134 | wl->channel = channel; |
1187 | memcpy(wl->bssid, dummy_bssid, ETH_ALEN); | 1135 | memcpy(wl->bssid, dummy_bssid, ETH_ALEN); |
1188 | 1136 | ||
1189 | ret = wl1271_cmd_join(wl); | 1137 | /* pass through frames from all BSS */ |
1138 | wl1271_configure_filters(wl, FIF_OTHER_BSS); | ||
1139 | |||
1140 | /* the dummy join is performed always with STATION BSS type to allow | ||
1141 | also ad-hoc mode to listen to the surroundings without sending any | ||
1142 | beacons yet. */ | ||
1143 | ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS); | ||
1190 | if (ret < 0) | 1144 | if (ret < 0) |
1191 | goto out; | 1145 | goto out; |
1192 | 1146 | ||
@@ -1208,7 +1162,9 @@ static int wl1271_unjoin_channel(struct wl1271 *wl) | |||
1208 | clear_bit(WL1271_FLAG_JOINED, &wl->flags); | 1162 | clear_bit(WL1271_FLAG_JOINED, &wl->flags); |
1209 | wl->channel = 0; | 1163 | wl->channel = 0; |
1210 | memset(wl->bssid, 0, ETH_ALEN); | 1164 | memset(wl->bssid, 0, ETH_ALEN); |
1211 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | 1165 | |
1166 | /* stop filterting packets based on bssid */ | ||
1167 | wl1271_configure_filters(wl, FIF_OTHER_BSS); | ||
1212 | 1168 | ||
1213 | out: | 1169 | out: |
1214 | return ret; | 1170 | return ret; |
@@ -1255,7 +1211,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1255 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) { | 1211 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) { |
1256 | wl->channel = channel; | 1212 | wl->channel = channel; |
1257 | /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */ | 1213 | /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */ |
1258 | ret = wl1271_cmd_join(wl); | 1214 | ret = wl1271_cmd_join(wl, wl->bss_type); |
1259 | if (ret < 0) | 1215 | if (ret < 0) |
1260 | wl1271_warning("cmd join to update channel failed %d", | 1216 | wl1271_warning("cmd join to update channel failed %d", |
1261 | ret); | 1217 | ret); |
@@ -1272,13 +1228,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1272 | * through the bss_info_changed() hook. | 1228 | * through the bss_info_changed() hook. |
1273 | */ | 1229 | */ |
1274 | if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { | 1230 | if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { |
1275 | wl1271_info("psm enabled"); | 1231 | wl1271_debug(DEBUG_PSM, "psm enabled"); |
1276 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, | 1232 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, |
1277 | true); | 1233 | true); |
1278 | } | 1234 | } |
1279 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | 1235 | } else if (!(conf->flags & IEEE80211_CONF_PS) && |
1280 | test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | 1236 | test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { |
1281 | wl1271_info("psm disabled"); | 1237 | wl1271_debug(DEBUG_PSM, "psm disabled"); |
1282 | 1238 | ||
1283 | clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); | 1239 | clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); |
1284 | 1240 | ||
@@ -1310,11 +1266,11 @@ struct wl1271_filter_params { | |||
1310 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; | 1266 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; |
1311 | }; | 1267 | }; |
1312 | 1268 | ||
1313 | static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, | 1269 | static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, |
1314 | struct dev_addr_list *mc_list) | 1270 | struct netdev_hw_addr_list *mc_list) |
1315 | { | 1271 | { |
1316 | struct wl1271_filter_params *fp; | 1272 | struct wl1271_filter_params *fp; |
1317 | int i; | 1273 | struct netdev_hw_addr *ha; |
1318 | 1274 | ||
1319 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); | 1275 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); |
1320 | if (!fp) { | 1276 | if (!fp) { |
@@ -1323,21 +1279,16 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, | |||
1323 | } | 1279 | } |
1324 | 1280 | ||
1325 | /* update multicast filtering parameters */ | 1281 | /* update multicast filtering parameters */ |
1326 | fp->enabled = true; | ||
1327 | if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) { | ||
1328 | mc_count = 0; | ||
1329 | fp->enabled = false; | ||
1330 | } | ||
1331 | |||
1332 | fp->mc_list_length = 0; | 1282 | fp->mc_list_length = 0; |
1333 | for (i = 0; i < mc_count; i++) { | 1283 | if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { |
1334 | if (mc_list->da_addrlen == ETH_ALEN) { | 1284 | fp->enabled = false; |
1285 | } else { | ||
1286 | fp->enabled = true; | ||
1287 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
1335 | memcpy(fp->mc_list[fp->mc_list_length], | 1288 | memcpy(fp->mc_list[fp->mc_list_length], |
1336 | mc_list->da_addr, ETH_ALEN); | 1289 | ha->addr, ETH_ALEN); |
1337 | fp->mc_list_length++; | 1290 | fp->mc_list_length++; |
1338 | } else | 1291 | } |
1339 | wl1271_warning("Unknown mc address length."); | ||
1340 | mc_list = mc_list->next; | ||
1341 | } | 1292 | } |
1342 | 1293 | ||
1343 | return (u64)(unsigned long)fp; | 1294 | return (u64)(unsigned long)fp; |
@@ -1381,14 +1332,14 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | |||
1381 | if (ret < 0) | 1332 | if (ret < 0) |
1382 | goto out_sleep; | 1333 | goto out_sleep; |
1383 | 1334 | ||
1384 | kfree(fp); | ||
1385 | |||
1386 | /* FIXME: We still need to set our filters properly */ | ||
1387 | |||
1388 | /* determine, whether supported filter values have changed */ | 1335 | /* determine, whether supported filter values have changed */ |
1389 | if (changed == 0) | 1336 | if (changed == 0) |
1390 | goto out_sleep; | 1337 | goto out_sleep; |
1391 | 1338 | ||
1339 | /* configure filters */ | ||
1340 | wl->filters = *total; | ||
1341 | wl1271_configure_filters(wl, 0); | ||
1342 | |||
1392 | /* apply configured filters */ | 1343 | /* apply configured filters */ |
1393 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); | 1344 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); |
1394 | if (ret < 0) | 1345 | if (ret < 0) |
@@ -1399,6 +1350,7 @@ out_sleep: | |||
1399 | 1350 | ||
1400 | out: | 1351 | out: |
1401 | mutex_unlock(&wl->mutex); | 1352 | mutex_unlock(&wl->mutex); |
1353 | kfree(fp); | ||
1402 | } | 1354 | } |
1403 | 1355 | ||
1404 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 1356 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
@@ -1449,15 +1401,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1449 | key_type = KEY_TKIP; | 1401 | key_type = KEY_TKIP; |
1450 | 1402 | ||
1451 | key_conf->hw_key_idx = key_conf->keyidx; | 1403 | key_conf->hw_key_idx = key_conf->keyidx; |
1452 | tx_seq_32 = wl->tx_security_seq_32; | 1404 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); |
1453 | tx_seq_16 = wl->tx_security_seq_16; | 1405 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); |
1454 | break; | 1406 | break; |
1455 | case ALG_CCMP: | 1407 | case ALG_CCMP: |
1456 | key_type = KEY_AES; | 1408 | key_type = KEY_AES; |
1457 | 1409 | ||
1458 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 1410 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
1459 | tx_seq_32 = wl->tx_security_seq_32; | 1411 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); |
1460 | tx_seq_16 = wl->tx_security_seq_16; | 1412 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); |
1461 | break; | 1413 | break; |
1462 | default: | 1414 | default: |
1463 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); | 1415 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); |
@@ -1544,10 +1496,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | |||
1544 | goto out; | 1496 | goto out; |
1545 | 1497 | ||
1546 | if (wl1271_11a_enabled()) | 1498 | if (wl1271_11a_enabled()) |
1547 | ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, | 1499 | ret = wl1271_cmd_scan(hw->priv, ssid, len, |
1500 | req->ie, req->ie_len, 1, 0, | ||
1548 | WL1271_SCAN_BAND_DUAL, 3); | 1501 | WL1271_SCAN_BAND_DUAL, 3); |
1549 | else | 1502 | else |
1550 | ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, | 1503 | ret = wl1271_cmd_scan(hw->priv, ssid, len, |
1504 | req->ie, req->ie_len, 1, 0, | ||
1551 | WL1271_SCAN_BAND_2_4_GHZ, 3); | 1505 | WL1271_SCAN_BAND_2_4_GHZ, 3); |
1552 | 1506 | ||
1553 | wl1271_ps_elp_sleep(wl); | 1507 | wl1271_ps_elp_sleep(wl); |
@@ -1660,14 +1614,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1660 | * and enable the BSSID filter | 1614 | * and enable the BSSID filter |
1661 | */ | 1615 | */ |
1662 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { | 1616 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { |
1663 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
1664 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | 1617 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); |
1618 | |||
1665 | ret = wl1271_cmd_build_null_data(wl); | 1619 | ret = wl1271_cmd_build_null_data(wl); |
1666 | if (ret < 0) { | 1620 | if (ret < 0) |
1667 | wl1271_warning("cmd buld null data failed %d", | ||
1668 | ret); | ||
1669 | goto out_sleep; | 1621 | goto out_sleep; |
1670 | } | 1622 | |
1623 | /* filter out all packets not from this BSSID */ | ||
1624 | wl1271_configure_filters(wl, 0); | ||
1671 | 1625 | ||
1672 | /* Need to update the BSSID (for filtering etc) */ | 1626 | /* Need to update the BSSID (for filtering etc) */ |
1673 | do_join = true; | 1627 | do_join = true; |
@@ -1738,7 +1692,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1738 | } | 1692 | } |
1739 | 1693 | ||
1740 | if (do_join) { | 1694 | if (do_join) { |
1741 | ret = wl1271_cmd_join(wl); | 1695 | ret = wl1271_cmd_join(wl, wl->bss_type); |
1742 | if (ret < 0) { | 1696 | if (ret < 0) { |
1743 | wl1271_warning("cmd join failed %d", ret); | 1697 | wl1271_warning("cmd join failed %d", ret); |
1744 | goto out_sleep; | 1698 | goto out_sleep; |
@@ -1757,6 +1711,7 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1757 | const struct ieee80211_tx_queue_params *params) | 1711 | const struct ieee80211_tx_queue_params *params) |
1758 | { | 1712 | { |
1759 | struct wl1271 *wl = hw->priv; | 1713 | struct wl1271 *wl = hw->priv; |
1714 | u8 ps_scheme; | ||
1760 | int ret; | 1715 | int ret; |
1761 | 1716 | ||
1762 | mutex_lock(&wl->mutex); | 1717 | mutex_lock(&wl->mutex); |
@@ -1767,17 +1722,22 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1767 | if (ret < 0) | 1722 | if (ret < 0) |
1768 | goto out; | 1723 | goto out; |
1769 | 1724 | ||
1725 | /* the txop is confed in units of 32us by the mac80211, we need us */ | ||
1770 | ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), | 1726 | ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), |
1771 | params->cw_min, params->cw_max, | 1727 | params->cw_min, params->cw_max, |
1772 | params->aifs, params->txop); | 1728 | params->aifs, params->txop << 5); |
1773 | if (ret < 0) | 1729 | if (ret < 0) |
1774 | goto out_sleep; | 1730 | goto out_sleep; |
1775 | 1731 | ||
1732 | if (params->uapsd) | ||
1733 | ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; | ||
1734 | else | ||
1735 | ps_scheme = CONF_PS_SCHEME_LEGACY; | ||
1736 | |||
1776 | ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), | 1737 | ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), |
1777 | CONF_CHANNEL_TYPE_EDCF, | 1738 | CONF_CHANNEL_TYPE_EDCF, |
1778 | wl1271_tx_get_queue(queue), | 1739 | wl1271_tx_get_queue(queue), |
1779 | CONF_PS_SCHEME_LEGACY_PSPOLL, | 1740 | ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0); |
1780 | CONF_ACK_POLICY_LEGACY, 0, 0); | ||
1781 | if (ret < 0) | 1741 | if (ret < 0) |
1782 | goto out_sleep; | 1742 | goto out_sleep; |
1783 | 1743 | ||
@@ -1947,7 +1907,6 @@ static const struct ieee80211_ops wl1271_ops = { | |||
1947 | .add_interface = wl1271_op_add_interface, | 1907 | .add_interface = wl1271_op_add_interface, |
1948 | .remove_interface = wl1271_op_remove_interface, | 1908 | .remove_interface = wl1271_op_remove_interface, |
1949 | .config = wl1271_op_config, | 1909 | .config = wl1271_op_config, |
1950 | /* .config_interface = wl1271_op_config_interface, */ | ||
1951 | .prepare_multicast = wl1271_op_prepare_multicast, | 1910 | .prepare_multicast = wl1271_op_prepare_multicast, |
1952 | .configure_filter = wl1271_op_configure_filter, | 1911 | .configure_filter = wl1271_op_configure_filter, |
1953 | .tx = wl1271_op_tx, | 1912 | .tx = wl1271_op_tx, |
@@ -1959,7 +1918,69 @@ static const struct ieee80211_ops wl1271_ops = { | |||
1959 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 1918 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
1960 | }; | 1919 | }; |
1961 | 1920 | ||
1962 | static int wl1271_register_hw(struct wl1271 *wl) | 1921 | static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, |
1922 | struct device_attribute *attr, | ||
1923 | char *buf) | ||
1924 | { | ||
1925 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
1926 | ssize_t len; | ||
1927 | |||
1928 | /* FIXME: what's the maximum length of buf? page size?*/ | ||
1929 | len = 500; | ||
1930 | |||
1931 | mutex_lock(&wl->mutex); | ||
1932 | len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", | ||
1933 | wl->sg_enabled); | ||
1934 | mutex_unlock(&wl->mutex); | ||
1935 | |||
1936 | return len; | ||
1937 | |||
1938 | } | ||
1939 | |||
1940 | static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, | ||
1941 | struct device_attribute *attr, | ||
1942 | const char *buf, size_t count) | ||
1943 | { | ||
1944 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
1945 | unsigned long res; | ||
1946 | int ret; | ||
1947 | |||
1948 | ret = strict_strtoul(buf, 10, &res); | ||
1949 | |||
1950 | if (ret < 0) { | ||
1951 | wl1271_warning("incorrect value written to bt_coex_mode"); | ||
1952 | return count; | ||
1953 | } | ||
1954 | |||
1955 | mutex_lock(&wl->mutex); | ||
1956 | |||
1957 | res = !!res; | ||
1958 | |||
1959 | if (res == wl->sg_enabled) | ||
1960 | goto out; | ||
1961 | |||
1962 | wl->sg_enabled = res; | ||
1963 | |||
1964 | if (wl->state == WL1271_STATE_OFF) | ||
1965 | goto out; | ||
1966 | |||
1967 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1968 | if (ret < 0) | ||
1969 | goto out; | ||
1970 | |||
1971 | wl1271_acx_sg_enable(wl, wl->sg_enabled); | ||
1972 | wl1271_ps_elp_sleep(wl); | ||
1973 | |||
1974 | out: | ||
1975 | mutex_unlock(&wl->mutex); | ||
1976 | return count; | ||
1977 | } | ||
1978 | |||
1979 | static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, | ||
1980 | wl1271_sysfs_show_bt_coex_state, | ||
1981 | wl1271_sysfs_store_bt_coex_state); | ||
1982 | |||
1983 | int wl1271_register_hw(struct wl1271 *wl) | ||
1963 | { | 1984 | { |
1964 | int ret; | 1985 | int ret; |
1965 | 1986 | ||
@@ -1980,8 +2001,17 @@ static int wl1271_register_hw(struct wl1271 *wl) | |||
1980 | 2001 | ||
1981 | return 0; | 2002 | return 0; |
1982 | } | 2003 | } |
2004 | EXPORT_SYMBOL_GPL(wl1271_register_hw); | ||
1983 | 2005 | ||
1984 | static int wl1271_init_ieee80211(struct wl1271 *wl) | 2006 | void wl1271_unregister_hw(struct wl1271 *wl) |
2007 | { | ||
2008 | ieee80211_unregister_hw(wl->hw); | ||
2009 | wl->mac80211_registered = false; | ||
2010 | |||
2011 | } | ||
2012 | EXPORT_SYMBOL_GPL(wl1271_unregister_hw); | ||
2013 | |||
2014 | int wl1271_init_ieee80211(struct wl1271 *wl) | ||
1985 | { | 2015 | { |
1986 | /* The tx descriptor buffer and the TKIP space. */ | 2016 | /* The tx descriptor buffer and the TKIP space. */ |
1987 | wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + | 2017 | wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + |
@@ -1994,7 +2024,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
1994 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | 2024 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | |
1995 | IEEE80211_HW_NOISE_DBM | | 2025 | IEEE80211_HW_NOISE_DBM | |
1996 | IEEE80211_HW_BEACON_FILTER | | 2026 | IEEE80211_HW_BEACON_FILTER | |
1997 | IEEE80211_HW_SUPPORTS_PS; | 2027 | IEEE80211_HW_SUPPORTS_PS | |
2028 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
2029 | IEEE80211_HW_HAS_RATE_CONTROL; | ||
1998 | 2030 | ||
1999 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 2031 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
2000 | BIT(NL80211_IFTYPE_ADHOC); | 2032 | BIT(NL80211_IFTYPE_ADHOC); |
@@ -2004,46 +2036,47 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | |||
2004 | if (wl1271_11a_enabled()) | 2036 | if (wl1271_11a_enabled()) |
2005 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; | 2037 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; |
2006 | 2038 | ||
2007 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | 2039 | wl->hw->queues = 4; |
2008 | |||
2009 | return 0; | ||
2010 | } | ||
2011 | 2040 | ||
2012 | static void wl1271_device_release(struct device *dev) | 2041 | SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); |
2013 | { | ||
2014 | 2042 | ||
2043 | return 0; | ||
2015 | } | 2044 | } |
2016 | 2045 | EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); | |
2017 | static struct platform_device wl1271_device = { | ||
2018 | .name = "wl1271", | ||
2019 | .id = -1, | ||
2020 | |||
2021 | /* device model insists to have a release function */ | ||
2022 | .dev = { | ||
2023 | .release = wl1271_device_release, | ||
2024 | }, | ||
2025 | }; | ||
2026 | 2046 | ||
2027 | #define WL1271_DEFAULT_CHANNEL 0 | 2047 | #define WL1271_DEFAULT_CHANNEL 0 |
2028 | 2048 | ||
2029 | static struct ieee80211_hw *wl1271_alloc_hw(void) | 2049 | struct ieee80211_hw *wl1271_alloc_hw(void) |
2030 | { | 2050 | { |
2031 | struct ieee80211_hw *hw; | 2051 | struct ieee80211_hw *hw; |
2052 | struct platform_device *plat_dev = NULL; | ||
2032 | struct wl1271 *wl; | 2053 | struct wl1271 *wl; |
2033 | int i; | 2054 | int i, ret; |
2055 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
2034 | 2056 | ||
2035 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | 2057 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); |
2036 | if (!hw) { | 2058 | if (!hw) { |
2037 | wl1271_error("could not alloc ieee80211_hw"); | 2059 | wl1271_error("could not alloc ieee80211_hw"); |
2038 | return ERR_PTR(-ENOMEM); | 2060 | ret = -ENOMEM; |
2061 | goto err_hw_alloc; | ||
2039 | } | 2062 | } |
2040 | 2063 | ||
2064 | plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL); | ||
2065 | if (!plat_dev) { | ||
2066 | wl1271_error("could not allocate platform_device"); | ||
2067 | ret = -ENOMEM; | ||
2068 | goto err_plat_alloc; | ||
2069 | } | ||
2070 | |||
2071 | memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device)); | ||
2072 | |||
2041 | wl = hw->priv; | 2073 | wl = hw->priv; |
2042 | memset(wl, 0, sizeof(*wl)); | 2074 | memset(wl, 0, sizeof(*wl)); |
2043 | 2075 | ||
2044 | INIT_LIST_HEAD(&wl->list); | 2076 | INIT_LIST_HEAD(&wl->list); |
2045 | 2077 | ||
2046 | wl->hw = hw; | 2078 | wl->hw = hw; |
2079 | wl->plat_dev = plat_dev; | ||
2047 | 2080 | ||
2048 | skb_queue_head_init(&wl->tx_queue); | 2081 | skb_queue_head_init(&wl->tx_queue); |
2049 | 2082 | ||
@@ -2061,6 +2094,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2061 | wl->band = IEEE80211_BAND_2GHZ; | 2094 | wl->band = IEEE80211_BAND_2GHZ; |
2062 | wl->vif = NULL; | 2095 | wl->vif = NULL; |
2063 | wl->flags = 0; | 2096 | wl->flags = 0; |
2097 | wl->sg_enabled = true; | ||
2064 | 2098 | ||
2065 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 2099 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
2066 | wl->tx_frames[i] = NULL; | 2100 | wl->tx_frames[i] = NULL; |
@@ -2070,15 +2104,55 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2070 | wl->state = WL1271_STATE_OFF; | 2104 | wl->state = WL1271_STATE_OFF; |
2071 | mutex_init(&wl->mutex); | 2105 | mutex_init(&wl->mutex); |
2072 | 2106 | ||
2107 | /* | ||
2108 | * FIXME: we should use a zero MAC address here, but for now we | ||
2109 | * generate a random Nokia address. | ||
2110 | */ | ||
2111 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
2112 | get_random_bytes(wl->mac_addr + 3, 3); | ||
2113 | |||
2073 | /* Apply default driver configuration. */ | 2114 | /* Apply default driver configuration. */ |
2074 | wl1271_conf_init(wl); | 2115 | wl1271_conf_init(wl); |
2075 | 2116 | ||
2117 | wl1271_debugfs_init(wl); | ||
2118 | |||
2119 | /* Register platform device */ | ||
2120 | ret = platform_device_register(wl->plat_dev); | ||
2121 | if (ret) { | ||
2122 | wl1271_error("couldn't register platform device"); | ||
2123 | goto err_hw; | ||
2124 | } | ||
2125 | dev_set_drvdata(&wl->plat_dev->dev, wl); | ||
2126 | |||
2127 | /* Create sysfs file to control bt coex state */ | ||
2128 | ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); | ||
2129 | if (ret < 0) { | ||
2130 | wl1271_error("failed to create sysfs file bt_coex_state"); | ||
2131 | goto err_platform; | ||
2132 | } | ||
2133 | |||
2076 | return hw; | 2134 | return hw; |
2135 | |||
2136 | err_platform: | ||
2137 | platform_device_unregister(wl->plat_dev); | ||
2138 | |||
2139 | err_hw: | ||
2140 | wl1271_debugfs_exit(wl); | ||
2141 | kfree(plat_dev); | ||
2142 | |||
2143 | err_plat_alloc: | ||
2144 | ieee80211_free_hw(hw); | ||
2145 | |||
2146 | err_hw_alloc: | ||
2147 | |||
2148 | return ERR_PTR(ret); | ||
2077 | } | 2149 | } |
2150 | EXPORT_SYMBOL_GPL(wl1271_alloc_hw); | ||
2078 | 2151 | ||
2079 | int wl1271_free_hw(struct wl1271 *wl) | 2152 | int wl1271_free_hw(struct wl1271 *wl) |
2080 | { | 2153 | { |
2081 | ieee80211_unregister_hw(wl->hw); | 2154 | platform_device_unregister(wl->plat_dev); |
2155 | kfree(wl->plat_dev); | ||
2082 | 2156 | ||
2083 | wl1271_debugfs_exit(wl); | 2157 | wl1271_debugfs_exit(wl); |
2084 | 2158 | ||
@@ -2095,145 +2169,8 @@ int wl1271_free_hw(struct wl1271 *wl) | |||
2095 | 2169 | ||
2096 | return 0; | 2170 | return 0; |
2097 | } | 2171 | } |
2098 | 2172 | EXPORT_SYMBOL_GPL(wl1271_free_hw); | |
2099 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
2100 | { | ||
2101 | struct wl12xx_platform_data *pdata; | ||
2102 | struct ieee80211_hw *hw; | ||
2103 | struct wl1271 *wl; | ||
2104 | int ret; | ||
2105 | |||
2106 | pdata = spi->dev.platform_data; | ||
2107 | if (!pdata) { | ||
2108 | wl1271_error("no platform data"); | ||
2109 | return -ENODEV; | ||
2110 | } | ||
2111 | |||
2112 | hw = wl1271_alloc_hw(); | ||
2113 | if (IS_ERR(hw)) | ||
2114 | return PTR_ERR(hw); | ||
2115 | |||
2116 | wl = hw->priv; | ||
2117 | |||
2118 | dev_set_drvdata(&spi->dev, wl); | ||
2119 | wl->spi = spi; | ||
2120 | |||
2121 | /* This is the only SPI value that we need to set here, the rest | ||
2122 | * comes from the board-peripherals file */ | ||
2123 | spi->bits_per_word = 32; | ||
2124 | |||
2125 | ret = spi_setup(spi); | ||
2126 | if (ret < 0) { | ||
2127 | wl1271_error("spi_setup failed"); | ||
2128 | goto out_free; | ||
2129 | } | ||
2130 | |||
2131 | wl->set_power = pdata->set_power; | ||
2132 | if (!wl->set_power) { | ||
2133 | wl1271_error("set power function missing in platform data"); | ||
2134 | ret = -ENODEV; | ||
2135 | goto out_free; | ||
2136 | } | ||
2137 | |||
2138 | wl->irq = spi->irq; | ||
2139 | if (wl->irq < 0) { | ||
2140 | wl1271_error("irq missing in platform data"); | ||
2141 | ret = -ENODEV; | ||
2142 | goto out_free; | ||
2143 | } | ||
2144 | |||
2145 | ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); | ||
2146 | if (ret < 0) { | ||
2147 | wl1271_error("request_irq() failed: %d", ret); | ||
2148 | goto out_free; | ||
2149 | } | ||
2150 | |||
2151 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
2152 | |||
2153 | disable_irq(wl->irq); | ||
2154 | |||
2155 | ret = platform_device_register(&wl1271_device); | ||
2156 | if (ret) { | ||
2157 | wl1271_error("couldn't register platform device"); | ||
2158 | goto out_irq; | ||
2159 | } | ||
2160 | dev_set_drvdata(&wl1271_device.dev, wl); | ||
2161 | |||
2162 | ret = wl1271_init_ieee80211(wl); | ||
2163 | if (ret) | ||
2164 | goto out_platform; | ||
2165 | |||
2166 | ret = wl1271_register_hw(wl); | ||
2167 | if (ret) | ||
2168 | goto out_platform; | ||
2169 | |||
2170 | wl1271_debugfs_init(wl); | ||
2171 | |||
2172 | wl1271_notice("initialized"); | ||
2173 | |||
2174 | return 0; | ||
2175 | |||
2176 | out_platform: | ||
2177 | platform_device_unregister(&wl1271_device); | ||
2178 | |||
2179 | out_irq: | ||
2180 | free_irq(wl->irq, wl); | ||
2181 | |||
2182 | out_free: | ||
2183 | ieee80211_free_hw(hw); | ||
2184 | |||
2185 | return ret; | ||
2186 | } | ||
2187 | |||
2188 | static int __devexit wl1271_remove(struct spi_device *spi) | ||
2189 | { | ||
2190 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | ||
2191 | |||
2192 | platform_device_unregister(&wl1271_device); | ||
2193 | free_irq(wl->irq, wl); | ||
2194 | |||
2195 | wl1271_free_hw(wl); | ||
2196 | |||
2197 | return 0; | ||
2198 | } | ||
2199 | |||
2200 | |||
2201 | static struct spi_driver wl1271_spi_driver = { | ||
2202 | .driver = { | ||
2203 | .name = "wl1271", | ||
2204 | .bus = &spi_bus_type, | ||
2205 | .owner = THIS_MODULE, | ||
2206 | }, | ||
2207 | |||
2208 | .probe = wl1271_probe, | ||
2209 | .remove = __devexit_p(wl1271_remove), | ||
2210 | }; | ||
2211 | |||
2212 | static int __init wl1271_init(void) | ||
2213 | { | ||
2214 | int ret; | ||
2215 | |||
2216 | ret = spi_register_driver(&wl1271_spi_driver); | ||
2217 | if (ret < 0) { | ||
2218 | wl1271_error("failed to register spi driver: %d", ret); | ||
2219 | goto out; | ||
2220 | } | ||
2221 | |||
2222 | out: | ||
2223 | return ret; | ||
2224 | } | ||
2225 | |||
2226 | static void __exit wl1271_exit(void) | ||
2227 | { | ||
2228 | spi_unregister_driver(&wl1271_spi_driver); | ||
2229 | |||
2230 | wl1271_notice("unloaded"); | ||
2231 | } | ||
2232 | |||
2233 | module_init(wl1271_init); | ||
2234 | module_exit(wl1271_exit); | ||
2235 | 2173 | ||
2236 | MODULE_LICENSE("GPL"); | 2174 | MODULE_LICENSE("GPL"); |
2237 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | 2175 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); |
2238 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 2176 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
2239 | MODULE_FIRMWARE(WL1271_FW_NAME); | ||