diff options
author | Bob Copeland <me@bobcopeland.com> | 2008-06-25 22:35:28 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-27 09:09:17 -0400 |
commit | 3a078876caee9634dbb9b41e6269262e30e8b535 (patch) | |
tree | cd7e285d0de6d6172b5e5f0f6377c5c6dbadafef /drivers/net/wireless/ath5k/base.c | |
parent | ffd7891dc909b3648e87f7cf8f84a6dc12fc1cc6 (diff) |
ath5k: convert LED code to use mac80211 triggers
This change cleans up the ath5k LED code and converts it to use
the standard LED device class along with the rx/tx LED triggers
provided by mac80211.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 251 |
1 files changed, 111 insertions, 140 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 010c66555950..a80a3a4744ab 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -58,11 +58,6 @@ | |||
58 | #include "reg.h" | 58 | #include "reg.h" |
59 | #include "debug.h" | 59 | #include "debug.h" |
60 | 60 | ||
61 | enum { | ||
62 | ATH_LED_TX, | ||
63 | ATH_LED_RX, | ||
64 | }; | ||
65 | |||
66 | static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ | 61 | static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ |
67 | 62 | ||
68 | 63 | ||
@@ -309,13 +304,10 @@ static void ath5k_tasklet_reset(unsigned long data); | |||
309 | 304 | ||
310 | static void ath5k_calibrate(unsigned long data); | 305 | static void ath5k_calibrate(unsigned long data); |
311 | /* LED functions */ | 306 | /* LED functions */ |
312 | static void ath5k_led_off(unsigned long data); | 307 | static int ath5k_init_leds(struct ath5k_softc *sc); |
313 | static void ath5k_led_blink(struct ath5k_softc *sc, | 308 | static void ath5k_led_enable(struct ath5k_softc *sc); |
314 | unsigned int on, | 309 | static void ath5k_led_off(struct ath5k_softc *sc); |
315 | unsigned int off); | 310 | static void ath5k_unregister_leds(struct ath5k_softc *sc); |
316 | static void ath5k_led_event(struct ath5k_softc *sc, | ||
317 | int event); | ||
318 | |||
319 | 311 | ||
320 | /* | 312 | /* |
321 | * Module init/exit functions | 313 | * Module init/exit functions |
@@ -596,8 +588,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
596 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 588 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
597 | struct ath5k_softc *sc = hw->priv; | 589 | struct ath5k_softc *sc = hw->priv; |
598 | 590 | ||
599 | if (test_bit(ATH_STAT_LEDSOFT, sc->status)) | 591 | ath5k_led_off(sc); |
600 | ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1); | ||
601 | 592 | ||
602 | ath5k_stop_hw(sc); | 593 | ath5k_stop_hw(sc); |
603 | pci_save_state(pdev); | 594 | pci_save_state(pdev); |
@@ -632,10 +623,7 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
632 | pci_write_config_byte(pdev, 0x41, 0); | 623 | pci_write_config_byte(pdev, 0x41, 0); |
633 | 624 | ||
634 | ath5k_init(sc); | 625 | ath5k_init(sc); |
635 | if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { | 626 | ath5k_led_enable(sc); |
636 | ath5k_hw_set_gpio_output(ah, sc->led_pin); | ||
637 | ath5k_hw_set_gpio(ah, sc->led_pin, 0); | ||
638 | } | ||
639 | 627 | ||
640 | /* | 628 | /* |
641 | * Reset the key cache since some parts do not | 629 | * Reset the key cache since some parts do not |
@@ -742,27 +730,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
742 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); | 730 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); |
743 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 731 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
744 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); | 732 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); |
745 | setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc); | ||
746 | |||
747 | sc->led_on = 0; /* low true */ | ||
748 | /* | ||
749 | * Auto-enable soft led processing for IBM cards and for | ||
750 | * 5211 minipci cards. | ||
751 | */ | ||
752 | if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || | ||
753 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { | ||
754 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | ||
755 | sc->led_pin = 0; | ||
756 | } | ||
757 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ | ||
758 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { | ||
759 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | ||
760 | sc->led_pin = 0; | ||
761 | } | ||
762 | if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { | ||
763 | ath5k_hw_set_gpio_output(ah, sc->led_pin); | ||
764 | ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); | ||
765 | } | ||
766 | 733 | ||
767 | ath5k_hw_get_lladdr(ah, mac); | 734 | ath5k_hw_get_lladdr(ah, mac); |
768 | SET_IEEE80211_PERM_ADDR(hw, mac); | 735 | SET_IEEE80211_PERM_ADDR(hw, mac); |
@@ -776,6 +743,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
776 | goto err_queues; | 743 | goto err_queues; |
777 | } | 744 | } |
778 | 745 | ||
746 | ath5k_init_leds(sc); | ||
747 | |||
779 | return 0; | 748 | return 0; |
780 | err_queues: | 749 | err_queues: |
781 | ath5k_txq_release(sc); | 750 | ath5k_txq_release(sc); |
@@ -809,6 +778,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
809 | ath5k_desc_free(sc, pdev); | 778 | ath5k_desc_free(sc, pdev); |
810 | ath5k_txq_release(sc); | 779 | ath5k_txq_release(sc); |
811 | ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); | 780 | ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); |
781 | ath5k_unregister_leds(sc); | ||
812 | 782 | ||
813 | /* | 783 | /* |
814 | * NB: can't reclaim these until after ieee80211_ifdetach | 784 | * NB: can't reclaim these until after ieee80211_ifdetach |
@@ -1060,65 +1030,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) | |||
1060 | return 0; | 1030 | return 0; |
1061 | } | 1031 | } |
1062 | 1032 | ||
1063 | /* | ||
1064 | * TODO: CLEAN THIS !!! | ||
1065 | */ | ||
1066 | static void | 1033 | static void |
1067 | ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) | 1034 | ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) |
1068 | { | 1035 | { |
1069 | if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) { | ||
1070 | /* from Atheros NDIS driver, w/ permission */ | ||
1071 | static const struct { | ||
1072 | u16 rate; /* tx/rx 802.11 rate */ | ||
1073 | u16 timeOn; /* LED on time (ms) */ | ||
1074 | u16 timeOff; /* LED off time (ms) */ | ||
1075 | } blinkrates[] = { | ||
1076 | { 108, 40, 10 }, | ||
1077 | { 96, 44, 11 }, | ||
1078 | { 72, 50, 13 }, | ||
1079 | { 48, 57, 14 }, | ||
1080 | { 36, 67, 16 }, | ||
1081 | { 24, 80, 20 }, | ||
1082 | { 22, 100, 25 }, | ||
1083 | { 18, 133, 34 }, | ||
1084 | { 12, 160, 40 }, | ||
1085 | { 10, 200, 50 }, | ||
1086 | { 6, 240, 58 }, | ||
1087 | { 4, 267, 66 }, | ||
1088 | { 2, 400, 100 }, | ||
1089 | { 0, 500, 130 } | ||
1090 | }; | ||
1091 | const struct ath5k_rate_table *rt = | ||
1092 | ath5k_hw_get_rate_table(sc->ah, mode); | ||
1093 | unsigned int i, j; | ||
1094 | |||
1095 | BUG_ON(rt == NULL); | ||
1096 | |||
1097 | memset(sc->hwmap, 0, sizeof(sc->hwmap)); | ||
1098 | for (i = 0; i < 32; i++) { | ||
1099 | u8 ix = rt->rate_code_to_index[i]; | ||
1100 | if (ix == 0xff) { | ||
1101 | sc->hwmap[i].ledon = msecs_to_jiffies(500); | ||
1102 | sc->hwmap[i].ledoff = msecs_to_jiffies(130); | ||
1103 | continue; | ||
1104 | } | ||
1105 | sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; | ||
1106 | /* receive frames include FCS */ | ||
1107 | sc->hwmap[i].rxflags = sc->hwmap[i].txflags | | ||
1108 | IEEE80211_RADIOTAP_F_FCS; | ||
1109 | /* setup blink rate table to avoid per-packet lookup */ | ||
1110 | for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++) | ||
1111 | if (blinkrates[j].rate == /* XXX why 7f? */ | ||
1112 | (rt->rates[ix].dot11_rate&0x7f)) | ||
1113 | break; | ||
1114 | |||
1115 | sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j]. | ||
1116 | timeOn); | ||
1117 | sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j]. | ||
1118 | timeOff); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | sc->curmode = mode; | 1036 | sc->curmode = mode; |
1123 | 1037 | ||
1124 | if (mode == AR5K_MODE_11A) { | 1038 | if (mode == AR5K_MODE_11A) { |
@@ -1900,8 +1814,6 @@ accept: | |||
1900 | ath5k_check_ibss_tsf(sc, skb, &rxs); | 1814 | ath5k_check_ibss_tsf(sc, skb, &rxs); |
1901 | 1815 | ||
1902 | __ieee80211_rx(sc->hw, skb, &rxs); | 1816 | __ieee80211_rx(sc->hw, skb, &rxs); |
1903 | sc->led_rxrate = rs.rs_rate; | ||
1904 | ath5k_led_event(sc, ATH_LED_RX); | ||
1905 | next: | 1817 | next: |
1906 | list_move_tail(&bf->list, &sc->rxbuf); | 1818 | list_move_tail(&bf->list, &sc->rxbuf); |
1907 | } while (ath5k_rxbuf_setup(sc, bf) == 0); | 1819 | } while (ath5k_rxbuf_setup(sc, bf) == 0); |
@@ -1982,13 +1894,9 @@ ath5k_tasklet_tx(unsigned long data) | |||
1982 | struct ath5k_softc *sc = (void *)data; | 1894 | struct ath5k_softc *sc = (void *)data; |
1983 | 1895 | ||
1984 | ath5k_tx_processq(sc, sc->txq); | 1896 | ath5k_tx_processq(sc, sc->txq); |
1985 | |||
1986 | ath5k_led_event(sc, ATH_LED_TX); | ||
1987 | } | 1897 | } |
1988 | 1898 | ||
1989 | 1899 | ||
1990 | |||
1991 | |||
1992 | /*****************\ | 1900 | /*****************\ |
1993 | * Beacon handling * | 1901 | * Beacon handling * |
1994 | \*****************/ | 1902 | \*****************/ |
@@ -2363,11 +2271,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) | |||
2363 | ieee80211_stop_queues(sc->hw); | 2271 | ieee80211_stop_queues(sc->hw); |
2364 | 2272 | ||
2365 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { | 2273 | if (!test_bit(ATH_STAT_INVALID, sc->status)) { |
2366 | if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { | 2274 | ath5k_led_off(sc); |
2367 | del_timer_sync(&sc->led_tim); | ||
2368 | ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); | ||
2369 | __clear_bit(ATH_STAT_LEDBLINKING, sc->status); | ||
2370 | } | ||
2371 | ath5k_hw_set_intr(ah, 0); | 2275 | ath5k_hw_set_intr(ah, 0); |
2372 | } | 2276 | } |
2373 | ath5k_txq_cleanup(sc); | 2277 | ath5k_txq_cleanup(sc); |
@@ -2563,54 +2467,123 @@ ath5k_calibrate(unsigned long data) | |||
2563 | \***************/ | 2467 | \***************/ |
2564 | 2468 | ||
2565 | static void | 2469 | static void |
2566 | ath5k_led_off(unsigned long data) | 2470 | ath5k_led_enable(struct ath5k_softc *sc) |
2567 | { | 2471 | { |
2568 | struct ath5k_softc *sc = (void *)data; | 2472 | if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { |
2569 | 2473 | ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); | |
2570 | if (test_bit(ATH_STAT_LEDENDBLINK, sc->status)) | 2474 | ath5k_led_off(sc); |
2571 | __clear_bit(ATH_STAT_LEDBLINKING, sc->status); | ||
2572 | else { | ||
2573 | __set_bit(ATH_STAT_LEDENDBLINK, sc->status); | ||
2574 | ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); | ||
2575 | mod_timer(&sc->led_tim, jiffies + sc->led_off); | ||
2576 | } | 2475 | } |
2577 | } | 2476 | } |
2578 | 2477 | ||
2579 | /* | ||
2580 | * Blink the LED according to the specified on/off times. | ||
2581 | */ | ||
2582 | static void | 2478 | static void |
2583 | ath5k_led_blink(struct ath5k_softc *sc, unsigned int on, | 2479 | ath5k_led_on(struct ath5k_softc *sc) |
2584 | unsigned int off) | ||
2585 | { | 2480 | { |
2586 | ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off); | 2481 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) |
2482 | return; | ||
2587 | ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); | 2483 | ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); |
2588 | __set_bit(ATH_STAT_LEDBLINKING, sc->status); | ||
2589 | __clear_bit(ATH_STAT_LEDENDBLINK, sc->status); | ||
2590 | sc->led_off = off; | ||
2591 | mod_timer(&sc->led_tim, jiffies + on); | ||
2592 | } | 2484 | } |
2593 | 2485 | ||
2594 | static void | 2486 | static void |
2595 | ath5k_led_event(struct ath5k_softc *sc, int event) | 2487 | ath5k_led_off(struct ath5k_softc *sc) |
2596 | { | 2488 | { |
2597 | if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status))) | 2489 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) |
2598 | return; | 2490 | return; |
2599 | if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status))) | 2491 | ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); |
2600 | return; /* don't interrupt active blink */ | 2492 | } |
2601 | switch (event) { | 2493 | |
2602 | case ATH_LED_TX: | 2494 | static void |
2603 | ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon, | 2495 | ath5k_led_brightness_set(struct led_classdev *led_dev, |
2604 | sc->hwmap[sc->led_txrate].ledoff); | 2496 | enum led_brightness brightness) |
2605 | break; | 2497 | { |
2606 | case ATH_LED_RX: | 2498 | struct ath5k_led *led = container_of(led_dev, struct ath5k_led, |
2607 | ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon, | 2499 | led_dev); |
2608 | sc->hwmap[sc->led_rxrate].ledoff); | 2500 | |
2609 | break; | 2501 | if (brightness == LED_OFF) |
2502 | ath5k_led_off(led->sc); | ||
2503 | else | ||
2504 | ath5k_led_on(led->sc); | ||
2505 | } | ||
2506 | |||
2507 | static int | ||
2508 | ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, | ||
2509 | const char *name, char *trigger) | ||
2510 | { | ||
2511 | int err; | ||
2512 | |||
2513 | led->sc = sc; | ||
2514 | strncpy(led->name, name, sizeof(led->name)); | ||
2515 | led->led_dev.name = led->name; | ||
2516 | led->led_dev.default_trigger = trigger; | ||
2517 | led->led_dev.brightness_set = ath5k_led_brightness_set; | ||
2518 | |||
2519 | err = led_classdev_register(&sc->pdev->dev, &led->led_dev); | ||
2520 | if (err) | ||
2521 | { | ||
2522 | ATH5K_WARN(sc, "could not register LED %s\n", name); | ||
2523 | led->sc = NULL; | ||
2610 | } | 2524 | } |
2525 | return err; | ||
2526 | } | ||
2527 | |||
2528 | static void | ||
2529 | ath5k_unregister_led(struct ath5k_led *led) | ||
2530 | { | ||
2531 | if (!led->sc) | ||
2532 | return; | ||
2533 | led_classdev_unregister(&led->led_dev); | ||
2534 | ath5k_led_off(led->sc); | ||
2535 | led->sc = NULL; | ||
2536 | } | ||
2537 | |||
2538 | static void | ||
2539 | ath5k_unregister_leds(struct ath5k_softc *sc) | ||
2540 | { | ||
2541 | ath5k_unregister_led(&sc->rx_led); | ||
2542 | ath5k_unregister_led(&sc->tx_led); | ||
2611 | } | 2543 | } |
2612 | 2544 | ||
2613 | 2545 | ||
2546 | static int | ||
2547 | ath5k_init_leds(struct ath5k_softc *sc) | ||
2548 | { | ||
2549 | int ret = 0; | ||
2550 | struct ieee80211_hw *hw = sc->hw; | ||
2551 | struct pci_dev *pdev = sc->pdev; | ||
2552 | char name[ATH5K_LED_MAX_NAME_LEN + 1]; | ||
2553 | |||
2554 | sc->led_on = 0; /* active low */ | ||
2555 | |||
2556 | /* | ||
2557 | * Auto-enable soft led processing for IBM cards and for | ||
2558 | * 5211 minipci cards. | ||
2559 | */ | ||
2560 | if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || | ||
2561 | pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { | ||
2562 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | ||
2563 | sc->led_pin = 0; | ||
2564 | } | ||
2565 | /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ | ||
2566 | if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { | ||
2567 | __set_bit(ATH_STAT_LEDSOFT, sc->status); | ||
2568 | sc->led_pin = 1; | ||
2569 | } | ||
2570 | if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) | ||
2571 | goto out; | ||
2572 | |||
2573 | ath5k_led_enable(sc); | ||
2574 | |||
2575 | snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy)); | ||
2576 | ret = ath5k_register_led(sc, &sc->rx_led, name, | ||
2577 | ieee80211_get_rx_led_name(hw)); | ||
2578 | if (ret) | ||
2579 | goto out; | ||
2580 | |||
2581 | snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy)); | ||
2582 | ret = ath5k_register_led(sc, &sc->tx_led, name, | ||
2583 | ieee80211_get_tx_led_name(hw)); | ||
2584 | out: | ||
2585 | return ret; | ||
2586 | } | ||
2614 | 2587 | ||
2615 | 2588 | ||
2616 | /********************\ | 2589 | /********************\ |
@@ -2648,8 +2621,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2648 | memmove(skb->data, skb->data+pad, hdrlen); | 2621 | memmove(skb->data, skb->data+pad, hdrlen); |
2649 | } | 2622 | } |
2650 | 2623 | ||
2651 | sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value; | ||
2652 | |||
2653 | spin_lock_irqsave(&sc->txbuflock, flags); | 2624 | spin_lock_irqsave(&sc->txbuflock, flags); |
2654 | if (list_empty(&sc->txbuf)) { | 2625 | if (list_empty(&sc->txbuf)) { |
2655 | ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); | 2626 | ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); |