static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
+static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
static int ath5k_beacon_update(struct ath5k_softc *sc,
struct sk_buff *skb);
.conf_tx = NULL,
.get_tx_stats = ath5k_get_tx_stats,
.get_tsf = ath5k_get_tsf,
+ .set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
};
}
/* Interrupt handling */
-static int ath5k_init(struct ath5k_softc *sc, bool is_resume);
+static int ath5k_init(struct ath5k_softc *sc);
static int ath5k_stop_locked(struct ath5k_softc *sc);
-static int ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend);
+static int ath5k_stop_hw(struct ath5k_softc *sc);
static irqreturn_t ath5k_intr(int irq, void *dev_id);
static void ath5k_tasklet_reset(unsigned long data);
ath5k_led_off(sc);
- ath5k_stop_hw(sc, true);
-
free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
goto err_no_irq;
}
- err = ath5k_init(sc, true);
- if (err)
- goto err_irq;
ath5k_led_enable(sc);
-
return 0;
-err_irq:
- free_irq(pdev->irq, sc);
+
err_no_irq:
pci_disable_device(pdev);
return err;
* it's done by reseting the chip. To accomplish this we must
* first cleanup any pending DMA, then restart stuff after a la
* ath5k_init.
+ *
+ * Called with sc->lock.
*/
static int
ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
struct ieee80211_rate *rate;
unsigned int mrr_rate[3], mrr_tries[3];
int i, ret;
+ u16 hw_rate;
+ u16 cts_rate = 0;
+ u16 duration = 0;
+ u8 rc_flags;
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
+ rate = ieee80211_get_tx_rate(sc->hw, info);
+
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK;
+ rc_flags = info->control.rates[0].flags;
+ hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ?
+ rate->hw_value_short : rate->hw_value;
+
pktlen = skb->len;
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ flags |= AR5K_TXDESC_RTSENA;
+ cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
+ duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
+ sc->vif, pktlen, info));
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ flags |= AR5K_TXDESC_CTSENA;
+ cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
+ duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
+ sc->vif, pktlen, info));
+ }
+
if (info->control.hw_key) {
keyidx = info->control.hw_key->hw_key_idx;
pktlen += info->control.hw_key->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),
- ieee80211_get_tx_rate(sc->hw, info)->hw_value,
- info->control.rates[0].count, keyidx, 0, flags, 0, 0);
+ hw_rate,
+ info->control.rates[0].count, keyidx, 0, flags,
+ cts_rate, duration);
if (ret)
goto err_unmap;
\********************/
static int
-ath5k_init(struct ath5k_softc *sc, bool is_resume)
+ath5k_init(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
int ret, i;
mutex_lock(&sc->lock);
- if (is_resume && !test_bit(ATH_STAT_STARTED, sc->status))
- goto out_ok;
-
- __clear_bit(ATH_STAT_STARTED, sc->status);
-
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
/*
for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
ath5k_hw_reset_key(ah, i);
- __set_bit(ATH_STAT_STARTED, sc->status);
-
/* Set ack to be sent at low bit-rates */
ath5k_hw_set_ack_bitrate_high(ah, false);
mod_timer(&sc->calib_tim, round_jiffies(jiffies +
msecs_to_jiffies(ath5k_calinterval * 1000)));
-out_ok:
ret = 0;
done:
mmiowb();
* stop is preempted).
*/
static int
-ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend)
+ath5k_stop_hw(struct ath5k_softc *sc)
{
int ret;
}
}
ath5k_txbuf_free(sc, sc->bbuf);
- if (!is_suspend)
- __clear_bit(ATH_STAT_STARTED, sc->status);
mmiowb();
mutex_unlock(&sc->lock);
sc->led_pin = 1;
sc->led_on = 1; /* active high */
}
- /* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) */
- if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN) {
+ /*
+ * Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) and
+ * in emachines notebooks with AMBIT subsystem.
+ */
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN ||
+ pdev->subsystem_vendor == PCI_VENDOR_ID_AMBIT) {
__set_bit(ATH_STAT_LEDSOFT, sc->status);
sc->led_pin = 3;
sc->led_on = 0; /* active low */
static int ath5k_start(struct ieee80211_hw *hw)
{
- return ath5k_init(hw->priv, false);
+ return ath5k_init(hw->priv);
}
static void ath5k_stop(struct ieee80211_hw *hw)
{
- ath5k_stop_hw(hw->priv, false);
+ ath5k_stop_hw(hw->priv);
}
static int ath5k_add_interface(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
+ int ret;
+
+ mutex_lock(&sc->lock);
sc->bintval = conf->beacon_int;
sc->power_level = conf->power_level;
- return ath5k_chan_set(sc, conf->channel);
+ ret = ath5k_chan_set(sc, conf->channel);
+
+ mutex_unlock(&sc->lock);
+ return ret;
}
static int
}
static void
+ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+ struct ath5k_softc *sc = hw->priv;
+
+ ath5k_hw_set_tsf64(sc->ah, tsf);
+}
+
+static void
ath5k_reset_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;