diff options
Diffstat (limited to 'drivers/net/wireless/ath5k')
-rw-r--r-- | drivers/net/wireless/ath5k/Kconfig | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 377 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.h | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/hw.c | 4 |
4 files changed, 194 insertions, 226 deletions
diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath5k/Kconfig index f1f2aea2eab..75383a5df99 100644 --- a/drivers/net/wireless/ath5k/Kconfig +++ b/drivers/net/wireless/ath5k/Kconfig @@ -1,6 +1,9 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS ---help--- This module adds support for wireless adapters based on Atheros 5xxx chipset. diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 635b9ac9aaa..217d506527a 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) */ @@ -167,8 +162,7 @@ static struct pci_driver ath5k_pci_driver = { /* * Prototypes - MAC 802.11 stack related functions */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl); +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); static int ath5k_reset(struct ieee80211_hw *hw); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); @@ -196,8 +190,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl); + struct sk_buff *skb); static struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -214,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = { .get_tx_stats = ath5k_get_tx_stats, .get_tsf = ath5k_get_tsf, .reset_tsf = ath5k_reset_tsf, - .beacon_update = ath5k_beacon_update, }; /* @@ -251,9 +243,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); - + struct ath5k_buf *bf); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -289,8 +279,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc, static void ath5k_tasklet_tx(unsigned long data); /* Beacon handling */ static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl); + struct ath5k_buf *bf); static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); @@ -314,13 +303,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 @@ -458,13 +444,11 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; - /* these names are misleading */ - hw->max_rssi = -110; /* signal in dBm */ - hw->max_noise = -110; /* noise in dBm */ - hw->max_signal = 100; /* we will provide a percentage based on rssi */ sc = hw->priv; sc->hw = hw; sc->pdev = pdev; @@ -603,8 +587,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 +622,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 +729,6 @@ 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_hw_get_lladdr(ah, mac); SET_IEEE80211_PERM_ADDR(hw, mac); @@ -783,6 +742,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } + ath5k_init_leds(sc); + return 0; err_queues: ath5k_txq_release(sc); @@ -816,6 +777,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 +1029,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) { @@ -1297,36 +1203,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_hw *ah = sc->ah; struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; int ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; - bf->ctl = *ctl; + /* XXX endianness */ bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; pktlen = skb->len; - if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { - keyidx = ctl->key_idx; - pktlen += ctl->icv_len; + if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { + keyidx = info->control.hw_key->hw_key_idx; + pktlen += info->control.icv_len; } - ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), ctl->tx_rate->hw_value, - ctl->retry_limit, keyidx, 0, flags, 0, 0); + (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + info->control.retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1335,7 +1241,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, spin_lock_bh(&txq->lock); list_add_tail(&bf->list, &txq->q); - sc->tx_stats.data[txq->qnum].len++; + sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); else /* no, so only link it */ @@ -1566,7 +1472,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) ath5k_txbuf_free(sc, bf); spin_lock_bh(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock_bh(&sc->txbuflock); @@ -1601,7 +1507,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_start_queues(sc->hw); /* XXX move to callers */ + ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) @@ -1698,9 +1604,9 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, /* Apparently when a default key is used to decrypt the packet the hw does not set the index used to decrypt. In such cases get the index from the packet. */ - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && - !(rs->rs_status & AR5K_RXERR_DECRYPT) && - skb->len >= hlen + 4) { + if (ieee80211_has_protected(hdr->frame_control) && + !(rs->rs_status & AR5K_RXERR_DECRYPT) && + skb->len >= hlen + 4) { keyix = skb->data[hlen + 3] >> 6; if (test_bit(keyix, sc->keymap)) @@ -1719,10 +1625,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, u32 hw_tu; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - if ((le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_FTYPE) == - IEEE80211_FTYPE_MGMT && - (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) == - IEEE80211_STYPE_BEACON && + if (ieee80211_is_beacon(mgmt->frame_control) && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { /* @@ -1895,20 +1798,9 @@ accept: rxs.freq = sc->curchan->center_freq; rxs.band = sc->curband->band; - /* - * signal quality: - * the names here are misleading and the usage of these - * values by iwconfig makes it even worse - */ - /* noise floor in dBm, from the last noise calibration */ rxs.noise = sc->ah->ah_noise_floor; - /* signal level in dBm */ - rxs.ssi = rxs.noise + rs.rs_rssi; - /* - * "signal" is actually displayed as Link Quality by iwconfig - * we provide a percentage based on rssi (assuming max rssi 64) - */ - rxs.signal = rs.rs_rssi * 100 / 64; + rxs.signal = rxs.noise + rs.rs_rssi; + rxs.qual = rs.rs_rssi * 100 / 64; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); @@ -1921,8 +1813,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); @@ -1939,11 +1829,11 @@ next: static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) { - struct ieee80211_tx_status txs = {}; struct ath5k_tx_status ts = {}; struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; + struct ieee80211_tx_info *info; int ret; spin_lock(&txq->lock); @@ -1963,28 +1853,29 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } skb = bf->skb; + info = IEEE80211_SKB_CB(skb); bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - txs.control = bf->ctl; - txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) - txs.excessive_retries = 1; + info->status.excessive_retries = 1; else if (ts.ts_status & AR5K_TXERR_FILT) - txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { - txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ts.ts_rssi; + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts.ts_rssi; } - ieee80211_tx_status(sc->hw, skb, &txs); - sc->tx_stats.data[txq->qnum].count++; + ieee80211_tx_status(sc->hw, skb); + sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock(&sc->txbuflock); @@ -2002,13 +1893,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 * \*****************/ @@ -2017,10 +1904,10 @@ ath5k_tasklet_tx(unsigned long data) * Setup the beacon frame for transmit. */ static int -ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ieee80211_tx_control *ctl) +ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct sk_buff *skb = bf->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; int ret, antenna = 0; @@ -2059,7 +1946,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + ieee80211_get_tx_rate(sc->hw, info)->hw_value, + 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2382,11 +2270,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) ieee80211_stop_queues(sc->hw); 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_txq_cleanup(sc); @@ -2582,54 +2466,123 @@ ath5k_calibrate(unsigned long data) \***************/ 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 -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); - __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 -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; - 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; +} /********************\ @@ -2637,8 +2590,7 @@ ath5k_led_event(struct ath5k_softc *sc, int event) \********************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; @@ -2667,13 +2619,11 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate->hw_value; - spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, ctl->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); @@ -2685,7 +2635,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf, ctl)) { + if (ath5k_txbuf_setup(sc, bf)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); @@ -2834,6 +2784,18 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * a clean way of letting us retrieve this yet. */ ath5k_hw_set_associd(ah, ah->ah_bssid, 0); } + + if (conf->changed & IEEE80211_IFCC_BEACON && + vif->type == IEEE80211_IF_TYPE_IBSS) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) { + ret = -ENOMEM; + goto unlock; + } + /* call old handler for now */ + ath5k_beacon_update(hw, beacon); + } + mutex_unlock(&sc->lock); return ath5k_reset(hw); @@ -3063,8 +3025,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; int ret; @@ -3080,7 +3041,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); + ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; else diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 3a975589301..47f414b09e6 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" @@ -60,7 +61,6 @@ struct ath5k_buf { dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ dma_addr_t skbaddr;/* physical addr of skb data */ - struct ieee80211_tx_control ctl; }; /* @@ -80,6 +80,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 @@ -92,7 +105,8 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - struct ieee80211_tx_queue_stats tx_stats; + /* FIXME: how many does it really need? */ + struct ieee80211_tx_queue_stats tx_stats[16]; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; @@ -118,13 +132,11 @@ struct ath5k_softc { size_t desc_len; /* size of TX/RX descriptors */ u16 cachelsz; /* cache line size */ - DECLARE_BITMAP(status, 6); + DECLARE_BITMAP(status, 4); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 2 -#define ATH_STAT_LEDBLINKING 3 /* LED blink operation active */ -#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */ -#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */ +#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int curmode; /* current phy mode */ @@ -132,13 +144,6 @@ struct ath5k_softc { struct ieee80211_vif *vif; - struct { - u8 rxflags; /* radiotap rx flags */ - u8 txflags; /* radiotap tx flags */ - u16 ledon; /* softled on time */ - u16 ledoff; /* softled off time */ - } hwmap[32]; /* h/w rate ix mappings */ - enum ath5k_int imask; /* interrupt mask copy */ DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ @@ -148,9 +153,6 @@ struct ath5k_softc { unsigned int led_pin, /* GPIO pin for driving LED */ led_on, /* pin setting for LED on */ led_off; /* off time for current blink */ - struct timer_list led_tim; /* led off timer */ - u8 led_rxrate; /* current rx rate for LED */ - u8 led_txrate; /* current tx rate for LED */ struct tasklet_struct restq; /* reset tasklet */ @@ -159,6 +161,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 +170,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 */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 77990b56860..c6d12c53bda 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -31,14 +31,14 @@ #include "base.h" #include "debug.h" -/*Rate tables*/ +/* Rate tables */ static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; -/*Prototypes*/ +/* Prototypes */ static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, |