0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0045
0046 #include <net/mac80211.h>
0047 #include <asm/unaligned.h>
0048
0049 #include "ath5k.h"
0050 #include "base.h"
0051 #include "reg.h"
0052
0053
0054
0055
0056
0057 static void
0058 ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
0059 struct sk_buff *skb)
0060 {
0061 struct ath5k_hw *ah = hw->priv;
0062 u16 qnum = skb_get_queue_mapping(skb);
0063
0064 if (WARN_ON(qnum >= ah->ah_capabilities.cap_queues.q_tx_num)) {
0065 ieee80211_free_txskb(hw, skb);
0066 return;
0067 }
0068
0069 ath5k_tx_queue(hw, skb, &ah->txqs[qnum], control);
0070 }
0071
0072
0073 static int
0074 ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0075 {
0076 struct ath5k_hw *ah = hw->priv;
0077 int ret;
0078 struct ath5k_vif *avf = (void *)vif->drv_priv;
0079
0080 mutex_lock(&ah->lock);
0081
0082 if ((vif->type == NL80211_IFTYPE_AP ||
0083 vif->type == NL80211_IFTYPE_ADHOC)
0084 && (ah->num_ap_vifs + ah->num_adhoc_vifs) >= ATH_BCBUF) {
0085 ret = -ELNRNG;
0086 goto end;
0087 }
0088
0089
0090
0091
0092
0093
0094 if (ah->num_adhoc_vifs ||
0095 (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
0096 ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");
0097 ret = -ELNRNG;
0098 goto end;
0099 }
0100
0101 switch (vif->type) {
0102 case NL80211_IFTYPE_AP:
0103 case NL80211_IFTYPE_STATION:
0104 case NL80211_IFTYPE_ADHOC:
0105 case NL80211_IFTYPE_MESH_POINT:
0106 avf->opmode = vif->type;
0107 break;
0108 default:
0109 ret = -EOPNOTSUPP;
0110 goto end;
0111 }
0112
0113 ah->nvifs++;
0114 ATH5K_DBG(ah, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
0115
0116
0117 if ((avf->opmode == NL80211_IFTYPE_AP) ||
0118 (avf->opmode == NL80211_IFTYPE_ADHOC) ||
0119 (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
0120 int slot;
0121
0122 WARN_ON(list_empty(&ah->bcbuf));
0123 avf->bbuf = list_first_entry(&ah->bcbuf, struct ath5k_buf,
0124 list);
0125 list_del(&avf->bbuf->list);
0126
0127 avf->bslot = 0;
0128 for (slot = 0; slot < ATH_BCBUF; slot++) {
0129 if (!ah->bslot[slot]) {
0130 avf->bslot = slot;
0131 break;
0132 }
0133 }
0134 BUG_ON(ah->bslot[avf->bslot] != NULL);
0135 ah->bslot[avf->bslot] = vif;
0136 if (avf->opmode == NL80211_IFTYPE_AP)
0137 ah->num_ap_vifs++;
0138 else if (avf->opmode == NL80211_IFTYPE_ADHOC)
0139 ah->num_adhoc_vifs++;
0140 else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
0141 ah->num_mesh_vifs++;
0142 }
0143
0144
0145
0146
0147 ath5k_hw_set_lladdr(ah, vif->addr);
0148
0149 ath5k_update_bssid_mask_and_opmode(ah, vif);
0150 ret = 0;
0151 end:
0152 mutex_unlock(&ah->lock);
0153 return ret;
0154 }
0155
0156
0157 static void
0158 ath5k_remove_interface(struct ieee80211_hw *hw,
0159 struct ieee80211_vif *vif)
0160 {
0161 struct ath5k_hw *ah = hw->priv;
0162 struct ath5k_vif *avf = (void *)vif->drv_priv;
0163 unsigned int i;
0164
0165 mutex_lock(&ah->lock);
0166 ah->nvifs--;
0167
0168 if (avf->bbuf) {
0169 ath5k_txbuf_free_skb(ah, avf->bbuf);
0170 list_add_tail(&avf->bbuf->list, &ah->bcbuf);
0171 for (i = 0; i < ATH_BCBUF; i++) {
0172 if (ah->bslot[i] == vif) {
0173 ah->bslot[i] = NULL;
0174 break;
0175 }
0176 }
0177 avf->bbuf = NULL;
0178 }
0179 if (avf->opmode == NL80211_IFTYPE_AP)
0180 ah->num_ap_vifs--;
0181 else if (avf->opmode == NL80211_IFTYPE_ADHOC)
0182 ah->num_adhoc_vifs--;
0183 else if (avf->opmode == NL80211_IFTYPE_MESH_POINT)
0184 ah->num_mesh_vifs--;
0185
0186 ath5k_update_bssid_mask_and_opmode(ah, NULL);
0187 mutex_unlock(&ah->lock);
0188 }
0189
0190
0191
0192
0193
0194 static int
0195 ath5k_config(struct ieee80211_hw *hw, u32 changed)
0196 {
0197 struct ath5k_hw *ah = hw->priv;
0198 struct ieee80211_conf *conf = &hw->conf;
0199 int ret = 0;
0200 int i;
0201
0202 mutex_lock(&ah->lock);
0203
0204 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
0205 ret = ath5k_chan_set(ah, &conf->chandef);
0206 if (ret < 0)
0207 goto unlock;
0208 }
0209
0210 if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
0211 (ah->ah_txpower.txp_requested != conf->power_level)) {
0212 ah->ah_txpower.txp_requested = conf->power_level;
0213
0214
0215 ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
0216 }
0217
0218 if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
0219 ah->ah_retry_long = conf->long_frame_max_tx_count;
0220 ah->ah_retry_short = conf->short_frame_max_tx_count;
0221
0222 for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++)
0223 ath5k_hw_set_tx_retry_limits(ah, i);
0224 }
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
0244
0245 unlock:
0246 mutex_unlock(&ah->lock);
0247 return ret;
0248 }
0249
0250
0251 static void
0252 ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0253 struct ieee80211_bss_conf *bss_conf, u64 changes)
0254 {
0255 struct ath5k_vif *avf = (void *)vif->drv_priv;
0256 struct ath5k_hw *ah = hw->priv;
0257 struct ath_common *common = ath5k_hw_common(ah);
0258
0259 mutex_lock(&ah->lock);
0260
0261 if (changes & BSS_CHANGED_BSSID) {
0262
0263 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
0264 common->curaid = 0;
0265 ath5k_hw_set_bssid(ah);
0266 }
0267
0268 if (changes & BSS_CHANGED_BEACON_INT)
0269 ah->bintval = bss_conf->beacon_int;
0270
0271 if (changes & BSS_CHANGED_ERP_SLOT) {
0272 int slot_time;
0273
0274 ah->ah_short_slot = bss_conf->use_short_slot;
0275 slot_time = ath5k_hw_get_default_slottime(ah) +
0276 3 * ah->ah_coverage_class;
0277 ath5k_hw_set_ifs_intervals(ah, slot_time);
0278 }
0279
0280 if (changes & BSS_CHANGED_ASSOC) {
0281 avf->assoc = vif->cfg.assoc;
0282 if (vif->cfg.assoc)
0283 ah->assoc = vif->cfg.assoc;
0284 else
0285 ah->assoc = ath5k_any_vif_assoc(ah);
0286
0287 if (ah->opmode == NL80211_IFTYPE_STATION)
0288 ath5k_set_beacon_filter(hw, ah->assoc);
0289 ath5k_hw_set_ledstate(ah, ah->assoc ?
0290 AR5K_LED_ASSOC : AR5K_LED_INIT);
0291 if (vif->cfg.assoc) {
0292 ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
0293 "Bss Info ASSOC %d, bssid: %pM\n",
0294 vif->cfg.aid, common->curbssid);
0295 common->curaid = vif->cfg.aid;
0296 ath5k_hw_set_bssid(ah);
0297
0298 }
0299 }
0300
0301 if (changes & BSS_CHANGED_BEACON) {
0302 spin_lock_bh(&ah->block);
0303 ath5k_beacon_update(hw, vif);
0304 spin_unlock_bh(&ah->block);
0305 }
0306
0307 if (changes & BSS_CHANGED_BEACON_ENABLED)
0308 ah->enable_beacon = bss_conf->enable_beacon;
0309
0310 if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
0311 BSS_CHANGED_BEACON_INT))
0312 ath5k_beacon_config(ah);
0313
0314 mutex_unlock(&ah->lock);
0315 }
0316
0317
0318 static u64
0319 ath5k_prepare_multicast(struct ieee80211_hw *hw,
0320 struct netdev_hw_addr_list *mc_list)
0321 {
0322 u32 mfilt[2], val;
0323 u8 pos;
0324 struct netdev_hw_addr *ha;
0325
0326 mfilt[0] = 0;
0327 mfilt[1] = 0;
0328
0329 netdev_hw_addr_list_for_each(ha, mc_list) {
0330
0331 val = get_unaligned_le32(ha->addr + 0);
0332 pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
0333 val = get_unaligned_le32(ha->addr + 3);
0334 pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
0335 pos &= 0x3f;
0336 mfilt[pos / 32] |= (1 << (pos % 32));
0337
0338
0339
0340
0341
0342 }
0343
0344 return ((u64)(mfilt[1]) << 32) | mfilt[0];
0345 }
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 static void
0367 ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
0368 unsigned int *new_flags, u64 multicast)
0369 {
0370 #define SUPPORTED_FIF_FLAGS \
0371 (FIF_ALLMULTI | FIF_FCSFAIL | \
0372 FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
0373 FIF_BCN_PRBRESP_PROMISC)
0374
0375 struct ath5k_hw *ah = hw->priv;
0376 u32 mfilt[2], rfilt;
0377 struct ath5k_vif_iter_data iter_data;
0378
0379 mutex_lock(&ah->lock);
0380
0381 mfilt[0] = multicast;
0382 mfilt[1] = multicast >> 32;
0383
0384
0385 changed_flags &= SUPPORTED_FIF_FLAGS;
0386 *new_flags &= SUPPORTED_FIF_FLAGS;
0387
0388
0389
0390
0391 rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
0392 (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
0393 AR5K_RX_FILTER_MCAST);
0394
0395
0396 if (*new_flags & FIF_ALLMULTI) {
0397 mfilt[0] = ~0;
0398 mfilt[1] = ~0;
0399 }
0400
0401
0402 if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
0403 rfilt |= AR5K_RX_FILTER_PHYERR;
0404
0405
0406
0407 if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
0408 rfilt |= AR5K_RX_FILTER_BEACON;
0409
0410
0411
0412
0413
0414 if (*new_flags & FIF_CONTROL)
0415 rfilt |= AR5K_RX_FILTER_CONTROL;
0416
0417
0418
0419
0420
0421 switch (ah->opmode) {
0422 case NL80211_IFTYPE_MESH_POINT:
0423 rfilt |= AR5K_RX_FILTER_CONTROL |
0424 AR5K_RX_FILTER_BEACON |
0425 AR5K_RX_FILTER_PROBEREQ |
0426 AR5K_RX_FILTER_PROM;
0427 break;
0428 case NL80211_IFTYPE_AP:
0429 case NL80211_IFTYPE_ADHOC:
0430 rfilt |= AR5K_RX_FILTER_PROBEREQ |
0431 AR5K_RX_FILTER_BEACON;
0432 break;
0433 case NL80211_IFTYPE_STATION:
0434 if (ah->assoc)
0435 rfilt |= AR5K_RX_FILTER_BEACON;
0436 break;
0437 default:
0438 break;
0439 }
0440
0441 iter_data.hw_macaddr = NULL;
0442 iter_data.n_stas = 0;
0443 iter_data.need_set_hw_addr = false;
0444 ieee80211_iterate_active_interfaces_atomic(
0445 ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
0446 ath5k_vif_iter, &iter_data);
0447
0448
0449 if (iter_data.n_stas > 1) {
0450
0451
0452
0453
0454 rfilt |= AR5K_RX_FILTER_PROM;
0455 }
0456
0457
0458 ath5k_hw_set_rx_filter(ah, rfilt);
0459
0460
0461 ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
0462
0463
0464 ah->filter_flags = rfilt;
0465
0466 ah->fif_filter_flags = *new_flags;
0467
0468 mutex_unlock(&ah->lock);
0469 }
0470
0471
0472 static int
0473 ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
0474 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
0475 struct ieee80211_key_conf *key)
0476 {
0477 struct ath5k_hw *ah = hw->priv;
0478 struct ath_common *common = ath5k_hw_common(ah);
0479 int ret = 0;
0480
0481 if (ath5k_modparam_nohwcrypt)
0482 return -EOPNOTSUPP;
0483
0484 if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT)
0485 return -EOPNOTSUPP;
0486
0487 if (vif->type == NL80211_IFTYPE_ADHOC &&
0488 (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
0489 key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
0490 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
0491
0492 return -EOPNOTSUPP;
0493 }
0494
0495 switch (key->cipher) {
0496 case WLAN_CIPHER_SUITE_WEP40:
0497 case WLAN_CIPHER_SUITE_WEP104:
0498 case WLAN_CIPHER_SUITE_TKIP:
0499 break;
0500 case WLAN_CIPHER_SUITE_CCMP:
0501 if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)
0502 break;
0503 return -EOPNOTSUPP;
0504 default:
0505 return -EOPNOTSUPP;
0506 }
0507
0508 mutex_lock(&ah->lock);
0509
0510 switch (cmd) {
0511 case SET_KEY:
0512 ret = ath_key_config(common, vif, sta, key);
0513 if (ret >= 0) {
0514 key->hw_key_idx = ret;
0515
0516 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
0517 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
0518 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
0519 if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
0520 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
0521 ret = 0;
0522 }
0523 break;
0524 case DISABLE_KEY:
0525 ath_key_delete(common, key->hw_key_idx);
0526 break;
0527 default:
0528 ret = -EINVAL;
0529 }
0530
0531 mutex_unlock(&ah->lock);
0532 return ret;
0533 }
0534
0535
0536 static void
0537 ath5k_sw_scan_start(struct ieee80211_hw *hw,
0538 struct ieee80211_vif *vif,
0539 const u8 *mac_addr)
0540 {
0541 struct ath5k_hw *ah = hw->priv;
0542 if (!ah->assoc)
0543 ath5k_hw_set_ledstate(ah, AR5K_LED_SCAN);
0544 }
0545
0546
0547 static void
0548 ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0549 {
0550 struct ath5k_hw *ah = hw->priv;
0551 ath5k_hw_set_ledstate(ah, ah->assoc ?
0552 AR5K_LED_ASSOC : AR5K_LED_INIT);
0553 }
0554
0555
0556 static int
0557 ath5k_get_stats(struct ieee80211_hw *hw,
0558 struct ieee80211_low_level_stats *stats)
0559 {
0560 struct ath5k_hw *ah = hw->priv;
0561
0562
0563 ath5k_hw_update_mib_counters(ah);
0564
0565 stats->dot11ACKFailureCount = ah->stats.ack_fail;
0566 stats->dot11RTSFailureCount = ah->stats.rts_fail;
0567 stats->dot11RTSSuccessCount = ah->stats.rts_ok;
0568 stats->dot11FCSErrorCount = ah->stats.fcs_error;
0569
0570 return 0;
0571 }
0572
0573
0574 static int
0575 ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0576 unsigned int link_id, u16 queue,
0577 const struct ieee80211_tx_queue_params *params)
0578 {
0579 struct ath5k_hw *ah = hw->priv;
0580 struct ath5k_txq_info qi;
0581 int ret = 0;
0582
0583 if (queue >= ah->ah_capabilities.cap_queues.q_tx_num)
0584 return 0;
0585
0586 mutex_lock(&ah->lock);
0587
0588 ath5k_hw_get_tx_queueprops(ah, queue, &qi);
0589
0590 qi.tqi_aifs = params->aifs;
0591 qi.tqi_cw_min = params->cw_min;
0592 qi.tqi_cw_max = params->cw_max;
0593 qi.tqi_burst_time = params->txop * 32;
0594
0595 ATH5K_DBG(ah, ATH5K_DEBUG_ANY,
0596 "Configure tx [queue %d], "
0597 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
0598 queue, params->aifs, params->cw_min,
0599 params->cw_max, params->txop);
0600
0601 if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) {
0602 ATH5K_ERR(ah,
0603 "Unable to update hardware queue %u!\n", queue);
0604 ret = -EIO;
0605 } else
0606 ath5k_hw_reset_tx_queue(ah, queue);
0607
0608 mutex_unlock(&ah->lock);
0609
0610 return ret;
0611 }
0612
0613
0614 static u64
0615 ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0616 {
0617 struct ath5k_hw *ah = hw->priv;
0618
0619 return ath5k_hw_get_tsf64(ah);
0620 }
0621
0622
0623 static void
0624 ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
0625 {
0626 struct ath5k_hw *ah = hw->priv;
0627
0628 ath5k_hw_set_tsf64(ah, tsf);
0629 }
0630
0631
0632 static void
0633 ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0634 {
0635 struct ath5k_hw *ah = hw->priv;
0636
0637
0638
0639
0640
0641 if (ah->opmode == NL80211_IFTYPE_ADHOC)
0642 ath5k_beacon_update_timers(ah, 0);
0643 else
0644 ath5k_hw_reset_tsf(ah);
0645 }
0646
0647
0648 static int
0649 ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
0650 {
0651 struct ath5k_hw *ah = hw->priv;
0652 struct ieee80211_conf *conf = &hw->conf;
0653 struct ath_common *common = ath5k_hw_common(ah);
0654 struct ath_cycle_counters *cc = &common->cc_survey;
0655 unsigned int div = common->clockrate * 1000;
0656
0657 if (idx != 0)
0658 return -ENOENT;
0659
0660 spin_lock_bh(&common->cc_lock);
0661 ath_hw_cycle_counters_update(common);
0662 if (cc->cycles > 0) {
0663 ah->survey.time += cc->cycles / div;
0664 ah->survey.time_busy += cc->rx_busy / div;
0665 ah->survey.time_rx += cc->rx_frame / div;
0666 ah->survey.time_tx += cc->tx_frame / div;
0667 }
0668 memset(cc, 0, sizeof(*cc));
0669 spin_unlock_bh(&common->cc_lock);
0670
0671 memcpy(survey, &ah->survey, sizeof(*survey));
0672
0673 survey->channel = conf->chandef.chan;
0674 survey->noise = ah->ah_noise_floor;
0675 survey->filled = SURVEY_INFO_NOISE_DBM |
0676 SURVEY_INFO_IN_USE |
0677 SURVEY_INFO_TIME |
0678 SURVEY_INFO_TIME_BUSY |
0679 SURVEY_INFO_TIME_RX |
0680 SURVEY_INFO_TIME_TX;
0681
0682 return 0;
0683 }
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696 static void
0697 ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
0698 {
0699 struct ath5k_hw *ah = hw->priv;
0700
0701 mutex_lock(&ah->lock);
0702 ath5k_hw_set_coverage_class(ah, coverage_class);
0703 mutex_unlock(&ah->lock);
0704 }
0705
0706
0707 static int
0708 ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
0709 {
0710 struct ath5k_hw *ah = hw->priv;
0711
0712 if (tx_ant == 1 && rx_ant == 1)
0713 ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A);
0714 else if (tx_ant == 2 && rx_ant == 2)
0715 ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B);
0716 else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
0717 ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
0718 else
0719 return -EINVAL;
0720 return 0;
0721 }
0722
0723
0724 static int
0725 ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
0726 {
0727 struct ath5k_hw *ah = hw->priv;
0728
0729 switch (ah->ah_ant_mode) {
0730 case AR5K_ANTMODE_FIXED_A:
0731 *tx_ant = 1; *rx_ant = 1; break;
0732 case AR5K_ANTMODE_FIXED_B:
0733 *tx_ant = 2; *rx_ant = 2; break;
0734 case AR5K_ANTMODE_DEFAULT:
0735 *tx_ant = 3; *rx_ant = 3; break;
0736 }
0737 return 0;
0738 }
0739
0740
0741 static void ath5k_get_ringparam(struct ieee80211_hw *hw,
0742 u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
0743 {
0744 struct ath5k_hw *ah = hw->priv;
0745
0746 *tx = ah->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;
0747
0748 *tx_max = ATH5K_TXQ_LEN_MAX;
0749 *rx = *rx_max = ATH_RXBUF;
0750 }
0751
0752
0753 static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
0754 {
0755 struct ath5k_hw *ah = hw->priv;
0756 u16 qnum;
0757
0758
0759 if (rx != ATH_RXBUF)
0760 return -EINVAL;
0761
0762
0763 if (!tx || tx > ATH5K_TXQ_LEN_MAX)
0764 return -EINVAL;
0765
0766 for (qnum = 0; qnum < ARRAY_SIZE(ah->txqs); qnum++) {
0767 if (!ah->txqs[qnum].setup)
0768 continue;
0769 if (ah->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
0770 ah->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
0771 continue;
0772
0773 ah->txqs[qnum].txq_max = tx;
0774 if (ah->txqs[qnum].txq_len >= ah->txqs[qnum].txq_max)
0775 ieee80211_stop_queue(hw, ah->txqs[qnum].qnum);
0776 }
0777
0778 return 0;
0779 }
0780
0781
0782 const struct ieee80211_ops ath5k_hw_ops = {
0783 .tx = ath5k_tx,
0784 .start = ath5k_start,
0785 .stop = ath5k_stop,
0786 .add_interface = ath5k_add_interface,
0787
0788 .remove_interface = ath5k_remove_interface,
0789 .config = ath5k_config,
0790 .bss_info_changed = ath5k_bss_info_changed,
0791 .prepare_multicast = ath5k_prepare_multicast,
0792 .configure_filter = ath5k_configure_filter,
0793
0794 .set_key = ath5k_set_key,
0795
0796
0797 .sw_scan_start = ath5k_sw_scan_start,
0798 .sw_scan_complete = ath5k_sw_scan_complete,
0799 .get_stats = ath5k_get_stats,
0800
0801
0802
0803
0804
0805 .conf_tx = ath5k_conf_tx,
0806 .get_tsf = ath5k_get_tsf,
0807 .set_tsf = ath5k_set_tsf,
0808 .reset_tsf = ath5k_reset_tsf,
0809
0810
0811 .get_survey = ath5k_get_survey,
0812 .set_coverage_class = ath5k_set_coverage_class,
0813
0814
0815
0816
0817 .set_antenna = ath5k_set_antenna,
0818 .get_antenna = ath5k_get_antenna,
0819 .set_ringparam = ath5k_set_ringparam,
0820 .get_ringparam = ath5k_get_ringparam,
0821 };