|
@@ -58,11 +58,6 @@
|
|
#include "reg.h"
|
|
#include "reg.h"
|
|
#include "debug.h"
|
|
#include "debug.h"
|
|
|
|
|
|
-enum {
|
|
|
|
- ATH_LED_TX,
|
|
|
|
- ATH_LED_RX,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
|
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
|
|
|
|
|
|
|
|
|
|
@@ -309,13 +304,10 @@ static void ath5k_tasklet_reset(unsigned long data);
|
|
|
|
|
|
static void ath5k_calibrate(unsigned long data);
|
|
static void ath5k_calibrate(unsigned long data);
|
|
/* LED functions */
|
|
/* 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
|
|
* Module init/exit functions
|
|
@@ -596,8 +588,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
|
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
|
struct ath5k_softc *sc = hw->priv;
|
|
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);
|
|
ath5k_stop_hw(sc);
|
|
pci_save_state(pdev);
|
|
pci_save_state(pdev);
|
|
@@ -632,10 +623,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
|
pci_write_config_byte(pdev, 0x41, 0);
|
|
pci_write_config_byte(pdev, 0x41, 0);
|
|
|
|
|
|
ath5k_init(sc);
|
|
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
|
|
* Reset the key cache since some parts do not
|
|
@@ -742,27 +730,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
|
|
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
|
|
tasklet_init(&sc->restq, ath5k_tasklet_reset, (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->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_hw_get_lladdr(ah, mac);
|
|
ath5k_hw_get_lladdr(ah, mac);
|
|
SET_IEEE80211_PERM_ADDR(hw, mac);
|
|
SET_IEEE80211_PERM_ADDR(hw, mac);
|
|
@@ -776,6 +743,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|
goto err_queues;
|
|
goto err_queues;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ath5k_init_leds(sc);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
err_queues:
|
|
err_queues:
|
|
ath5k_txq_release(sc);
|
|
ath5k_txq_release(sc);
|
|
@@ -809,6 +778,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|
ath5k_desc_free(sc, pdev);
|
|
ath5k_desc_free(sc, pdev);
|
|
ath5k_txq_release(sc);
|
|
ath5k_txq_release(sc);
|
|
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
|
|
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
|
|
|
|
+ ath5k_unregister_leds(sc);
|
|
|
|
|
|
/*
|
|
/*
|
|
* NB: can't reclaim these until after ieee80211_ifdetach
|
|
* NB: can't reclaim these until after ieee80211_ifdetach
|
|
@@ -1060,65 +1030,9 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * TODO: CLEAN THIS !!!
|
|
|
|
- */
|
|
|
|
static void
|
|
static void
|
|
ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
|
|
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;
|
|
sc->curmode = mode;
|
|
|
|
|
|
if (mode == AR5K_MODE_11A) {
|
|
if (mode == AR5K_MODE_11A) {
|
|
@@ -1900,8 +1814,6 @@ accept:
|
|
ath5k_check_ibss_tsf(sc, skb, &rxs);
|
|
ath5k_check_ibss_tsf(sc, skb, &rxs);
|
|
|
|
|
|
__ieee80211_rx(sc->hw, skb, &rxs);
|
|
__ieee80211_rx(sc->hw, skb, &rxs);
|
|
- sc->led_rxrate = rs.rs_rate;
|
|
|
|
- ath5k_led_event(sc, ATH_LED_RX);
|
|
|
|
next:
|
|
next:
|
|
list_move_tail(&bf->list, &sc->rxbuf);
|
|
list_move_tail(&bf->list, &sc->rxbuf);
|
|
} while (ath5k_rxbuf_setup(sc, bf) == 0);
|
|
} while (ath5k_rxbuf_setup(sc, bf) == 0);
|
|
@@ -1982,13 +1894,9 @@ ath5k_tasklet_tx(unsigned long data)
|
|
struct ath5k_softc *sc = (void *)data;
|
|
struct ath5k_softc *sc = (void *)data;
|
|
|
|
|
|
ath5k_tx_processq(sc, sc->txq);
|
|
ath5k_tx_processq(sc, sc->txq);
|
|
-
|
|
|
|
- ath5k_led_event(sc, ATH_LED_TX);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
-
|
|
|
|
/*****************\
|
|
/*****************\
|
|
* Beacon handling *
|
|
* Beacon handling *
|
|
\*****************/
|
|
\*****************/
|
|
@@ -2363,11 +2271,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
|
|
ieee80211_stop_queues(sc->hw);
|
|
ieee80211_stop_queues(sc->hw);
|
|
|
|
|
|
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
|
|
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
|
|
- if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
|
|
|
- del_timer_sync(&sc->led_tim);
|
|
|
|
- ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
|
|
|
|
- __clear_bit(ATH_STAT_LEDBLINKING, sc->status);
|
|
|
|
- }
|
|
|
|
|
|
+ ath5k_led_off(sc);
|
|
ath5k_hw_set_intr(ah, 0);
|
|
ath5k_hw_set_intr(ah, 0);
|
|
}
|
|
}
|
|
ath5k_txq_cleanup(sc);
|
|
ath5k_txq_cleanup(sc);
|
|
@@ -2563,54 +2467,123 @@ ath5k_calibrate(unsigned long data)
|
|
\***************/
|
|
\***************/
|
|
|
|
|
|
static void
|
|
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_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);
|
|
|
|
|
|
+ if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
|
|
|
|
+ ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
|
|
|
|
+ ath5k_led_off(sc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * Blink the LED according to the specified on/off times.
|
|
|
|
- */
|
|
|
|
static void
|
|
static void
|
|
-ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
|
|
|
|
- unsigned int off)
|
|
|
|
|
|
+ath5k_led_on(struct ath5k_softc *sc)
|
|
{
|
|
{
|
|
- ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
|
|
|
|
|
|
+ if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
|
|
|
+ return;
|
|
ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
|
|
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);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-ath5k_led_event(struct ath5k_softc *sc, int event)
|
|
|
|
|
|
+ath5k_led_off(struct ath5k_softc *sc)
|
|
{
|
|
{
|
|
- if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
|
|
|
|
|
|
+ if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
|
return;
|
|
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_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;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+ath5k_unregister_led(struct ath5k_led *led)
|
|
|
|
+{
|
|
|
|
+ if (!led->sc)
|
|
|
|
+ return;
|
|
|
|
+ led_classdev_unregister(&led->led_dev);
|
|
|
|
+ ath5k_led_off(led->sc);
|
|
|
|
+ led->sc = NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+ath5k_unregister_leds(struct ath5k_softc *sc)
|
|
|
|
+{
|
|
|
|
+ ath5k_unregister_led(&sc->rx_led);
|
|
|
|
+ ath5k_unregister_led(&sc->tx_led);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+ath5k_init_leds(struct ath5k_softc *sc)
|
|
|
|
+{
|
|
|
|
+ int ret = 0;
|
|
|
|
+ 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;
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
/********************\
|
|
/********************\
|
|
@@ -2648,8 +2621,6 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
memmove(skb->data, skb->data+pad, hdrlen);
|
|
memmove(skb->data, skb->data+pad, hdrlen);
|
|
}
|
|
}
|
|
|
|
|
|
- sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
|
|
|
|
-
|
|
|
|
spin_lock_irqsave(&sc->txbuflock, flags);
|
|
spin_lock_irqsave(&sc->txbuflock, flags);
|
|
if (list_empty(&sc->txbuf)) {
|
|
if (list_empty(&sc->txbuf)) {
|
|
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
|
|
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
|