This is still a WIP, only compile tested so far, but I just wanted to 
make sure I'm heading in the right direction.  It's pretty similar to 
the way b43 does things which was the only user of mac80211 LEDs that
I saw in the tree.

Salient notes:

- mac80211 just sets up a trigger for the regular led code, with brightness
  full on or off on every other packet.  Thus the stuff that did longer 
  blink times for slower rates went out the window.

- I noticed HP compaq comment didn't match the code for pin selection.  I
  assume it was a copy/paste bug.

- I guess we only have one gpio total?  If there are cards with multiple
  physical LEDs we could roll led_pin etc. into struct ath5k_led.

- might want to move the led stuff into its own file, again like b43.

---
 drivers/net/wireless/ath5k/base.c |  245 +++++++++++++++++--------------------
 drivers/net/wireless/ath5k/base.h |   16 +++
 2 files changed, 127 insertions(+), 134 deletions(-)

diff --git a/drivers/net/wireless/ath5k/base.c 
b/drivers/net/wireless/ath5k/base.c
index 635b9ac..1d6c98b 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -58,11 +58,6 @@
 #include "reg.h"
 #include "debug.h"
 
-enum {
-       ATH_LED_TX,
-       ATH_LED_RX,
-};
-
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: 
Fixme) */
 
 
@@ -314,13 +309,10 @@ static void       ath5k_tasklet_reset(unsigned long data);
 
 static void    ath5k_calibrate(unsigned long data);
 /* LED functions */
-static void    ath5k_led_off(unsigned long data);
-static void    ath5k_led_blink(struct ath5k_softc *sc,
-                               unsigned int on,
-                               unsigned int off);
-static void    ath5k_led_event(struct ath5k_softc *sc,
-                               int event);
-
+static int     ath5k_init_leds(struct ath5k_softc *sc);
+static void    ath5k_led_enable(struct ath5k_softc *sc);
+static void    ath5k_led_off(struct ath5k_softc *sc);
+static void    ath5k_unregister_leds(struct ath5k_softc *sc);
 
 /*
  * Module init/exit functions
@@ -603,8 +595,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath5k_softc *sc = hw->priv;
 
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status))
-               ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
+       ath5k_led_off(sc);
 
        ath5k_stop_hw(sc);
        pci_save_state(pdev);
@@ -639,10 +630,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
        pci_write_config_byte(pdev, 0x41, 0);
 
        ath5k_init(sc);
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-               ath5k_hw_set_gpio_output(ah, sc->led_pin);
-               ath5k_hw_set_gpio(ah, sc->led_pin, 0);
-       }
+       ath5k_led_enable(sc);
 
        /*
         * Reset the key cache since some parts do not
@@ -749,27 +737,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
        tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
        setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
-       setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
 
-       sc->led_on = 0; /* low true */
-       /*
-        * Auto-enable soft led processing for IBM cards and for
-        * 5211 minipci cards.
-        */
-       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
-                       pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 0;
-       }
-       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
-       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 0;
-       }
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-               ath5k_hw_set_gpio_output(ah, sc->led_pin);
-               ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
-       }
+       ath5k_init_leds(sc);
 
        ath5k_hw_get_lladdr(ah, mac);
        SET_IEEE80211_PERM_ADDR(hw, mac);
@@ -816,6 +785,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        ath5k_desc_free(sc, pdev);
        ath5k_txq_release(sc);
        ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+       ath5k_unregister_leds(sc);
 
        /*
         * NB: can't reclaim these until after ieee80211_ifdetach
@@ -1067,65 +1037,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct 
ieee80211_channel *chan)
        return 0;
 }
 
-/*
- * TODO: CLEAN THIS !!!
- */
 static void
 ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
 {
-       if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
-               /* from Atheros NDIS driver, w/ permission */
-               static const struct {
-                       u16 rate;       /* tx/rx 802.11 rate */
-                       u16 timeOn;     /* LED on time (ms) */
-                       u16 timeOff;    /* LED off time (ms) */
-               } blinkrates[] = {
-                       { 108,  40,  10 },
-                       {  96,  44,  11 },
-                       {  72,  50,  13 },
-                       {  48,  57,  14 },
-                       {  36,  67,  16 },
-                       {  24,  80,  20 },
-                       {  22, 100,  25 },
-                       {  18, 133,  34 },
-                       {  12, 160,  40 },
-                       {  10, 200,  50 },
-                       {   6, 240,  58 },
-                       {   4, 267,  66 },
-                       {   2, 400, 100 },
-                       {   0, 500, 130 }
-               };
-               const struct ath5k_rate_table *rt =
-                               ath5k_hw_get_rate_table(sc->ah, mode);
-               unsigned int i, j;
-
-               BUG_ON(rt == NULL);
-
-               memset(sc->hwmap, 0, sizeof(sc->hwmap));
-               for (i = 0; i < 32; i++) {
-                       u8 ix = rt->rate_code_to_index[i];
-                       if (ix == 0xff) {
-                               sc->hwmap[i].ledon = msecs_to_jiffies(500);
-                               sc->hwmap[i].ledoff = msecs_to_jiffies(130);
-                               continue;
-                       }
-                       sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
-                       /* receive frames include FCS */
-                       sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
-                                       IEEE80211_RADIOTAP_F_FCS;
-                       /* setup blink rate table to avoid per-packet lookup */
-                       for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
-                               if (blinkrates[j].rate == /* XXX why 7f? */
-                                               (rt->rates[ix].dot11_rate&0x7f))
-                                       break;
-
-                       sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
-                                       timeOn);
-                       sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
-                                       timeOff);
-               }
-       }
-
        sc->curmode = mode;
 
        if (mode == AR5K_MODE_11A) {
@@ -1921,8 +1835,6 @@ accept:
                        ath5k_check_ibss_tsf(sc, skb, &rxs);
 
                __ieee80211_rx(sc->hw, skb, &rxs);
-               sc->led_rxrate = rs.rs_rate;
-               ath5k_led_event(sc, ATH_LED_RX);
 next:
                list_move_tail(&bf->list, &sc->rxbuf);
        } while (ath5k_rxbuf_setup(sc, bf) == 0);
@@ -2002,13 +1914,9 @@ ath5k_tasklet_tx(unsigned long data)
        struct ath5k_softc *sc = (void *)data;
 
        ath5k_tx_processq(sc, sc->txq);
-
-       ath5k_led_event(sc, ATH_LED_TX);
 }
 
 
-
-
 /*****************\
 * Beacon handling *
 \*****************/
@@ -2581,55 +2489,124 @@ ath5k_calibrate(unsigned long data)
 * LED functions *
 \***************/
 
+static void 
+ath5k_led_on(struct ath5k_softc *sc)
+{
+       if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
+               return;
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
+}
+
 static void
-ath5k_led_off(unsigned long data)
+ath5k_led_enable(struct ath5k_softc *sc)
 {
-       struct ath5k_softc *sc = (void *)data;
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+               ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
+               ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0);
+       }
+}
 
-       if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
-               __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
-       else {
-               __set_bit(ATH_STAT_LEDENDBLINK, sc->status);
-               ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
-               mod_timer(&sc->led_tim, jiffies + sc->led_off);
+static void 
+ath5k_led_off(struct ath5k_softc *sc)
+{
+       if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
+               return;
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
+}
+
+static void 
+ath5k_led_brightness_set(struct led_classdev *led_dev,
+       enum led_brightness brightness)
+{
+       struct ath5k_led *led = container_of(led_dev, struct ath5k_led, 
+               led_dev);
+
+       if (brightness == LED_OFF)
+               ath5k_led_off(led->sc);
+       else
+               ath5k_led_on(led->sc);
+}
+
+static int
+ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, 
+                  const char *name, char *trigger)
+{
+       int err;
+
+       led->sc = sc;
+       strncpy(led->name, name, sizeof(led->name));
+       led->led_dev.name = led->name;
+       led->led_dev.default_trigger = trigger;
+       led->led_dev.brightness_set = ath5k_led_brightness_set;
+
+       err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
+       if (err)
+       {
+               ATH5K_WARN(sc, "could not register LED %s\n", name);
+               led->sc = NULL;
        }
+       return err;
 }
 
-/*
- * Blink the LED according to the specified on/off times.
- */
 static void
-ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
-               unsigned int off)
+ath5k_unregister_led(struct ath5k_led *led)
 {
-       ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
-       ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
-       __set_bit(ATH_STAT_LEDBLINKING, sc->status);
-       __clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
-       sc->led_off = off;
-       mod_timer(&sc->led_tim, jiffies + on);
+       if (!led->sc)
+               return;
+       led_classdev_unregister(&led->led_dev);
+       ath5k_led_off(led->sc);
+       led->sc = NULL;
 }
 
 static void
-ath5k_led_event(struct ath5k_softc *sc, int event)
+ath5k_unregister_leds(struct ath5k_softc *sc)
 {
-       if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
-               return;
-       if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
-               return; /* don't interrupt active blink */
-       switch (event) {
-       case ATH_LED_TX:
-               ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
-                       sc->hwmap[sc->led_txrate].ledoff);
-               break;
-       case ATH_LED_RX:
-               ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
-                       sc->hwmap[sc->led_rxrate].ledoff);
-               break;
-       }
+       ath5k_unregister_led(&sc->rx_led);
+       ath5k_unregister_led(&sc->tx_led);
 }
+                       
 
+static int
+ath5k_init_leds(struct ath5k_softc *sc)
+{
+       int ret;
+       struct ieee80211_hw *hw = sc->hw;
+       struct pci_dev *pdev = sc->pdev;
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];
+
+       sc->led_on = 0;  /* active low */
 
+       /*
+        * Auto-enable soft led processing for IBM cards and for
+        * 5211 minipci cards.
+        */
+       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
+                       pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 0;
+       }
+       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = 1;
+       }
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               goto out;
+
+       ath5k_led_enable(sc);
+
+       snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->rx_led, name, 
+               ieee80211_get_rx_led_name(hw));
+       if (ret)
+               goto out;
+
+       snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->tx_led, name, 
+               ieee80211_get_tx_led_name(hw));
+out:
+       return ret;
+}
 
 
 /********************\
diff --git a/drivers/net/wireless/ath5k/base.h 
b/drivers/net/wireless/ath5k/base.h
index 3a97558..171448b 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -45,6 +45,7 @@
 #include <linux/list.h>
 #include <linux/wireless.h>
 #include <linux/if_ether.h>
+#include <linux/leds.h>
 
 #include "ath5k.h"
 #include "debug.h"
@@ -80,6 +81,19 @@ struct ath5k_txq {
        bool                    setup;
 };
 
+#define ATH5K_LED_MAX_NAME_LEN 31
+
+/*
+ * State for LED triggers
+ */
+struct ath5k_led
+{
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];  /* name of the LED in sysfs */
+       struct ath5k_softc *sc;                 /* driver state */
+       struct led_classdev led_dev;            /* led classdev */
+};
+
+
 #if CHAN_DEBUG
 #define ATH_CHAN_MAX   (26+26+26+200+200)
 #else
@@ -159,6 +173,7 @@ struct ath5k_softc {
        spinlock_t              rxbuflock;
        u32                     *rxlink;        /* link ptr in last RX desc */
        struct tasklet_struct   rxtq;           /* rx intr tasklet */
+       struct ath5k_led        rx_led;         /* rx led */
 
        struct list_head        txbuf;          /* transmit buffer */
        spinlock_t              txbuflock;
@@ -167,6 +182,7 @@ struct ath5k_softc {
 
        struct ath5k_txq        *txq;           /* beacon and tx*/
        struct tasklet_struct   txtq;           /* tx intr tasklet */
+       struct ath5k_led        tx_led;         /* tx led */
 
        struct ath5k_buf        *bbuf;          /* beacon buffer */
        unsigned int            bhalq,          /* SW q for outgoing beacons */
-- 
1.5.4.2.182.gb3092




-- 
Bob Copeland %% www.bobcopeland.com


_______________________________________________
ath5k-devel mailing list
ath5k-devel@lists.ath5k.org
https://lists.ath5k.org/mailman/listinfo/ath5k-devel

Reply via email to