static void dumpchannels(struct ath_hal *ah, int nc, const struct ieee80211_channel *chans, int16_t *txpow) { int i; for (i = 0; i < nc; i++) { const struct ieee80211_channel *c = &chans[i]; int type; if (showchannels) printf("%s%3d", sep, ath_hal_mhz2ieee(ah, c->ic_freq, c->ic_flags)); else printf("%s%u", sep, c->ic_freq); if (IEEE80211_IS_CHAN_HALF(c)) type = 'H'; else if (IEEE80211_IS_CHAN_QUARTER(c)) type = 'Q'; else if (IEEE80211_IS_CHAN_TURBO(c)) type = 'T'; else if (IEEE80211_IS_CHAN_HT(c)) type = 'N'; else if (IEEE80211_IS_CHAN_A(c)) type = 'A'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'T'; else if (IEEE80211_IS_CHAN_G(c)) type = 'G'; else type = 'B'; if (dopassive && IEEE80211_IS_CHAN_PASSIVE(c)) type = tolower(type); if (isdfs && is4ms) printf("%c%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (isdfs) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (is4ms) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5); if ((n++ % (showchannels ? 7 : 6)) == 0) sep = "\n"; else sep = " "; } }
static int tx99_channel_setup(struct ath_softc *sc) { struct ath_tx99 *tx99 = sc->sc_tx99; struct ieee80211com *ic = (struct ieee80211com *)sc->sc_ieee; struct ath_hal *ah; u_int8_t ieee; struct ieee80211_channel *c; if(tx99_set_cwm_param(tx99) != EOK) { adf_os_print("%s: set cwm parm fail\n", __FUNCTION__); return -EINVAL; } /* * Locate the channel to use if user-specified; otherwise * user the current channel. */ if (tx99->txfreq != 0) { ah = sc->sc_ah; ieee = ath_hal_mhz2ieee(ah, tx99->txfreq, 0); adf_os_print("%s: ieee = %d\n", __FUNCTION__, ieee); adf_os_print("%s: tx99->txfreq=%d,tx99->txmode=%d\n", __FUNCTION__, tx99->txfreq, tx99->txmode); c = sc->sc_ieee_ops->ath_net80211_find_channel(sc, ieee, tx99->txmode); if (c == NULL) { adf_os_print("%s: channel %u mode %u not available\n", __FUNCTION__, tx99->txfreq, tx99->txmode); return -EINVAL; } adf_os_print("%s: switching to channel %u (flags 0x%x mode %u)\n", __FUNCTION__, c->ic_freq, c->ic_flags, tx99->txmode); ic->ic_curchan = c; if(ic->ic_set_channel(ic)) { adf_os_print("%s: reset channel fail, check frequency settings\n", __FUNCTION__); return -EINVAL; } } return EOK; }
static int tx99_channel_setup(struct ath_softc *sc) { struct ath_tx99 *tx99 = sc->sc_tx99; struct ieee80211com *ic = (struct ieee80211com *)sc->sc_ieee; struct ath_hal *ah; u_int8_t ieee; if(tx99_set_cwm_param(sc, tx99)) { DPRINTF(sc, ATH_DEBUG_TX99, "%s: set cwm parm fail!\n", __func__); return -EINVAL; } /* * Locate the channel to use if user-specified; otherwise * user the current channel. */ if (tx99->txfreq != 0) { ah = sc->sc_ah; ieee = ath_hal_mhz2ieee(ah, tx99->txfreq, 0); DPRINTF(sc, ATH_DEBUG_TX99, "%s: ieee channel %d!\n", __func__, ieee); struct ieee80211_channel *c = sc->sc_ieee_ops->ath_net80211_find_channel(sc, ieee, tx99->txmode); if (c == NULL) { DPRINTF(sc, ATH_DEBUG_TX99, "%s: channel %u mode %u not available\n", __func__, tx99->txfreq, tx99->txmode); return -EINVAL; } DPRINTF(sc, ATH_DEBUG_TX99, "%s: switching to channel %u (flags 0x%x mode %u)\n", __func__, c->ic_freq, c->ic_flags, tx99->txmode); ic->ic_curchan = c; if(ic->ic_set_channel(ic)) { DPRINTF(sc, ATH_DEBUG_TX99, "%s: reset channel fail, check frequency settings!\n", __func__); return -EINVAL; } } return 0; }
int spectral_enter_raw_capture_mode(ath_dev_t dev, void *indata) { struct ath_softc *sc = ATH_DEV_TO_SC(dev); SPECTRAL_ADC_CAPTURE_PARAMS *params = (SPECTRAL_ADC_CAPTURE_PARAMS*)indata; HAL_CHANNEL hchan; int error = 0; if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_RAW_ADC_CAPTURE, 0, NULL) != HAL_OK) { DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: called but raw capture mode not supported!\n", __func__, __LINE__); return -ENOTSUP; } /* sanity check input version */ if (params->version != SPECTRAL_ADC_API_VERSION) { DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: version mismatch: expect %d got %d\n", __func__, __LINE__, params->version, SPECTRAL_ADC_API_VERSION); return -EINVAL; } if (sc->sc_invalid) { DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: called but device is invalid or removed!\n", __func__, __LINE__); return -ENXIO; } if (sc->sc_raw_adc_capture_enabled) { DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: already raw capture mode - calling spectral_exit_raw_capture_mode() first\n", __func__, __LINE__); spectral_exit_raw_capture_mode(dev); } /* save current channel and chain mask so we can restore later */ sc->sc_save_rx_chainmask = sc->sc_rx_chainmask; sc->sc_save_current_chan = sc->sc_curchan; sc->sc_save_current_opmode = sc->sc_opmode; /* ensure chain mask is valid */ params->chain_info.chain_mask &= sc->sc_rx_chainmask; /* store requested capture params */ sc->sc_adc_chain_mask = params->chain_info.chain_mask; sc->sc_adc_num_chains = sc->sc_mask2chains[params->chain_info.chain_mask]; sc->sc_adc_capture_flags = params->capture_flags; /* set new chain mask */ ath_set_rx_chainmask(dev, params->chain_info.chain_mask); /* change channel to that requested */ OS_MEMZERO(&hchan, sizeof(hchan)); hchan.channel = params->freq; if (hchan.channel > 5000) hchan.channel_flags = CHANNEL_A_HT20; else hchan.channel_flags = CHANNEL_G_HT20; sc->sc_full_reset = 1; /* ensure we do a full reset */ ath_set_channel(dev, &hchan, 0, 0, 0); /* save channel info to return with capture data later */ sc->sc_adc_chan_flags = sc->sc_curchan.channel_flags; sc->sc_adc_freq = sc->sc_curchan.channel; sc->sc_adc_ieee = ath_hal_mhz2ieee(sc->sc_ah, sc->sc_adc_freq, sc->sc_adc_chan_flags); /* did the channel change succeed ?*/ if (sc->sc_curchan.channel != hchan.channel || sc->sc_curchan.channel_flags != hchan.channel_flags) { DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: set chan to %dMhz[%x] FAILED! current chan=%dMhz[0x%x]\n", __func__, __LINE__, hchan.channel, hchan.channel_flags, sc->sc_curchan.channel, sc->sc_curchan.channel_flags); error = -EINVAL; } else { /* ok, all set up - enter raw capture mode */ DPRINTF(sc, ATH_DEBUG_ANY, "%s[%d]: chan is now %dMhz flags=0x%x mask=0x%x\n", __func__, __LINE__, sc->sc_curchan.channel, sc->sc_curchan.channel_flags, params->chain_info.chain_mask); sc->sc_raw_adc_capture_enabled = 1; sc->sc_opmode = HAL_M_RAW_ADC_CAPTURE; ath_hal_enable_test_addac_mode(sc->sc_ah); } return error; }
void ar5416FillRadiotapHdr(struct ath_hal *ah, struct ah_rx_radiotap_header *rh, struct ah_ppi_data *ppi, struct ath_desc *ds, void *buf_addr) { struct ath_rx_status *rx_stats = &ds->ds_rxstat; struct ar5416_desc *adsp = AR5416DESC(ds); int i, j; if (rh != NULL) { OS_MEMZERO(rh, sizeof(struct ah_rx_radiotap_header)); rh->tsf = ar5416GetTsf64(ah); /* AR5416 specific */ rh->wr_rate = RXSTATUS_RATE(ah, adsp); rh->wr_chan_freq = (AH_PRIVATE(ah)->ah_curchan) ? AH_PRIVATE(ah)->ah_curchan->channel : 0; rh->wr_antsignal = MS(adsp->ds_rxstatus4, AR_RxRSSICombined); // Fill out extended channel info. rh->wr_xchannel.freq = rh->wr_chan_freq; rh->wr_xchannel.flags = AH_PRIVATE(ah)->ah_curchan->channelFlags; rh->wr_xchannel.maxpower = AH_PRIVATE(ah)->ah_curchan->maxRegTxPower; rh->wr_xchannel.chan = ath_hal_mhz2ieee(ah, rh->wr_chan_freq, rh->wr_xchannel.flags); /* Radiotap Rx flags */ if (AH5416(ah)->ah_getPlcpHdr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PLCP; } if (adsp->ds_rxstatus8 & AR_CRCErr) { /* for now, set both values */ rh->wr_flags |= AH_RADIOTAP_F_BADFCS; rh->wr_rx_flags |= AH_RADIOTAP_F_RX_BADFCS; } if (adsp->ds_rxstatus3 & AR_GI) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_HALFGI; rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_SHORT_GI; } if (adsp->ds_rxstatus3 & AR_2040 ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40; rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_40MHZ; } if (adsp->ds_rxstatus3 & AR_Parallel40 ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40P; } if (adsp->ds_rxstatus8 & AR_RxAggr ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_AGGR; } if (adsp->ds_rxstatus8 & AR_RxFirstAggr ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_FIRSTAGGR; } if (adsp->ds_rxstatus8 & AR_RxMoreAggr ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MOREAGGR; } if (adsp->ds_rxstatus1 & AR_RxMore ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MORE; } if (adsp->ds_rxstatus8 & AR_PreDelimCRCErr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PREDELIM_CRCERR; } if (adsp->ds_rxstatus8 & AR_PostDelimCRCErr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_POSTDELIM_CRCERR; } if (adsp->ds_rxstatus8 & AR_DecryptCRCErr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_DECRYPTCRCERR; } if (adsp->ds_rxstatus3 & AR_STBC ) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_STBC; } if (adsp->ds_rxstatus8 & AR_PHYErr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PHYERR; rh->ath_ext.phyerr_code = rx_stats->rs_phyerr; } /* add the extension part */ rh->vendor_ext.oui[0] = (ATH_OUI & 0xff); rh->vendor_ext.oui[1] = ((ATH_OUI >> 8) & 0xff); rh->vendor_ext.oui[2] = ((ATH_OUI >> 16) & 0xff); rh->vendor_ext.skip_length = sizeof(struct ah_rx_vendor_radiotap_header); /* sub_namespace - simply set to 0 since we don't use multiple namespaces */ rh->vendor_ext.sub_namespace = 0; rh->ath_ext.version = AH_RADIOTAP_VERSION; rh->ath_ext.ch_info.num_chains = owl_get_ntxchains(AH5416(ah)->ah_rxchainmask); /* * Two-pass strategy to fill in RSSI and EVM: * First pass: copy the info from each chain from the * descriptor into the corresponding index of the * radiotap header's ch_info array. * Second pass: use the rxchainmask to determine * which chains are valid. Shift ch_info array * elements down to fill in indices that were off * in the rxchainmask. */ rh->ath_ext.ch_info.rssi_ctl[0] = rx_stats->rs_rssi_ctl0; rh->ath_ext.ch_info.rssi_ext[0] = rx_stats->rs_rssi_ext0; rh->ath_ext.ch_info.evm[0] = rx_stats->evm0; rh->ath_ext.ch_info.rssi_ctl[1] = rx_stats->rs_rssi_ctl1; rh->ath_ext.ch_info.rssi_ext[1] = rx_stats->rs_rssi_ext1; rh->ath_ext.ch_info.evm[1] = rx_stats->evm1; rh->ath_ext.ch_info.rssi_ctl[2] = rx_stats->rs_rssi_ctl2; rh->ath_ext.ch_info.rssi_ext[2] = rx_stats->rs_rssi_ext2; rh->ath_ext.ch_info.evm[2] = rx_stats->evm2; for (i = 0, j = 0; i < RADIOTAP_MAX_CHAINS ; i++ ) { if (AH5416(ah)->ah_rxchainmask & (0x1 << i)) { /* * This chain is enabled. Does its data need * to be shifted down into a lower array index? */ if (i != j) { rh->ath_ext.ch_info.rssi_ctl[j] = rh->ath_ext.ch_info.rssi_ctl[i]; rh->ath_ext.ch_info.rssi_ext[j] = rh->ath_ext.ch_info.rssi_ext[i]; /* * EVM fields only need to be shifted if PCU_SEL_EVM bit is set. * Otherwise EVM fields hold the value of PLCP headers which * are not related to chainmask. */ if (!(AH5416(ah)->ah_getPlcpHdr)) { rh->ath_ext.ch_info.evm[j] = rh->ath_ext.ch_info.evm[i]; } } j++; } } rh->ath_ext.n_delims = MS(adsp->ds_rxstatus1, AR_NumDelim); }
/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus */ static HAL_BOOL ar5111SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) { #define CI_2GHZ_INDEX_CORRECTION 19 u_int32_t refClk, reg32, data2111; int16_t chan5111, chanIEEE; /* * Structure to hold 11b tuning information for 5111/2111 * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 */ typedef struct { u_int32_t refClkSel; /* reference clock, 1 for 16 MHz */ u_int32_t channelSelect; /* P[7:4]S[3:0] bits */ u_int16_t channel5111; /* 11a channel for 5111 */ } CHAN_INFO_2GHZ; const static CHAN_INFO_2GHZ chan2GHzData[] = { { 1, 0x46, 96 }, /* 2312 -19 */ { 1, 0x46, 97 }, /* 2317 -18 */ { 1, 0x46, 98 }, /* 2322 -17 */ { 1, 0x46, 99 }, /* 2327 -16 */ { 1, 0x46, 100 }, /* 2332 -15 */ { 1, 0x46, 101 }, /* 2337 -14 */ { 1, 0x46, 102 }, /* 2342 -13 */ { 1, 0x46, 103 }, /* 2347 -12 */ { 1, 0x46, 104 }, /* 2352 -11 */ { 1, 0x46, 105 }, /* 2357 -10 */ { 1, 0x46, 106 }, /* 2362 -9 */ { 1, 0x46, 107 }, /* 2367 -8 */ { 1, 0x46, 108 }, /* 2372 -7 */ /* index -6 to 0 are pad to make this a nolookup table */ { 1, 0x46, 116 }, /* -6 */ { 1, 0x46, 116 }, /* -5 */ { 1, 0x46, 116 }, /* -4 */ { 1, 0x46, 116 }, /* -3 */ { 1, 0x46, 116 }, /* -2 */ { 1, 0x46, 116 }, /* -1 */ { 1, 0x46, 116 }, /* 0 */ { 1, 0x46, 116 }, /* 2412 1 */ { 1, 0x46, 117 }, /* 2417 2 */ { 1, 0x46, 118 }, /* 2422 3 */ { 1, 0x46, 119 }, /* 2427 4 */ { 1, 0x46, 120 }, /* 2432 5 */ { 1, 0x46, 121 }, /* 2437 6 */ { 1, 0x46, 122 }, /* 2442 7 */ { 1, 0x46, 123 }, /* 2447 8 */ { 1, 0x46, 124 }, /* 2452 9 */ { 1, 0x46, 125 }, /* 2457 10 */ { 1, 0x46, 126 }, /* 2462 11 */ { 1, 0x46, 127 }, /* 2467 12 */ { 1, 0x46, 128 }, /* 2472 13 */ { 1, 0x44, 124 }, /* 2484 14 */ { 1, 0x46, 136 }, /* 2512 15 */ { 1, 0x46, 140 }, /* 2532 16 */ { 1, 0x46, 144 }, /* 2552 17 */ { 1, 0x46, 148 }, /* 2572 18 */ { 1, 0x46, 152 }, /* 2592 19 */ { 1, 0x46, 156 }, /* 2612 20 */ { 1, 0x46, 160 }, /* 2632 21 */ { 1, 0x46, 164 }, /* 2652 22 */ { 1, 0x46, 168 }, /* 2672 23 */ { 1, 0x46, 172 }, /* 2692 24 */ { 1, 0x46, 176 }, /* 2712 25 */ { 1, 0x46, 180 } /* 2732 26 */ }; OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); chanIEEE = ath_hal_mhz2ieee(ah, chan->channel, chan->channelFlags); if (IS_CHAN_2GHZ(chan)) { const CHAN_INFO_2GHZ* ci = &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; u_int32_t txctl; data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) << 5) | (ci->refClkSel << 4); chan5111 = ci->channel5111; txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); if (chan->channel == 2484) { /* Enable channel spreading for channel 14 */ OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl | AR_PHY_CCK_TX_CTRL_JAPAN); } else { OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); } } else { chan5111 = chanIEEE; /* no conversion needed */ data2111 = 0; } /* Rest of the code is common for 5 GHz and 2.4 GHz. */ if (chan5111 >= 145 || (chan5111 & 0x1)) { reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xff; refClk = 1; } else { reg32 = ath_hal_reverseBits(((chan5111 - 24)/2), 8) & 0xff; refClk = 0; } reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); reg32 >>= 8; OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); AH_PRIVATE(ah)->ah_curchan = chan; #ifdef AH_SUPPORT_DFS if (chan->privFlags & CHANNEL_DFS) { struct ar5212RadarState *rs; u_int8_t index; rs = ar5212GetRadarChanState(ah, &index); if (rs != AH_NULL) { AH5212(ah)->ah_curchanRadIndex = (int16_t) index; } else { HDPRINTF(ah, HAL_DBG_DFS, "%s: Couldn't find radar state information\n", __func__); return AH_FALSE; } } else #endif AH5212(ah)->ah_curchanRadIndex = -1; return AH_TRUE; #undef CI_2GHZ_INDEX_CORRECTION }
void ar9300_fill_radiotap_hdr(struct ath_hal *ah, struct ah_rx_radiotap_header *rh, struct ah_ppi_data *ppi, struct ath_desc *ds, void *buf_addr) { struct ar9300_rxs *rxsp = AR9300RXS(buf_addr); int i, j; if (rh != NULL) { /* Fill out Radiotap header */ OS_MEMZERO(rh, sizeof(struct ah_rx_radiotap_header)); rh->tsf = ar9300_get_tsf64(ah); rh->wr_rate = MS(rxsp->status1, AR_rx_rate); rh->wr_chan_freq = (AH_PRIVATE(ah)->ah_curchan) ? AH_PRIVATE(ah)->ah_curchan->channel : 0; /* Fill out extended channel info. */ rh->wr_xchannel.freq = rh->wr_chan_freq; /* Modify for static analysis, prevent AH_PRIVATE(ah)->ah_curchan is NULL */ rh->wr_xchannel.flags = (AH_PRIVATE(ah)->ah_curchan) ? AH_PRIVATE(ah)->ah_curchan->channel_flags : 0; rh->wr_xchannel.maxpower = (AH_PRIVATE(ah)->ah_curchan) ? AH_PRIVATE(ah)->ah_curchan->max_reg_tx_power : 0; rh->wr_xchannel.chan = ath_hal_mhz2ieee(ah, rh->wr_chan_freq, rh->wr_xchannel.flags); rh->wr_antsignal = MS(rxsp->status5, AR_rx_rssi_combined); /* Radiotap Rx flags */ if (AH9300(ah)->ah_get_plcp_hdr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PLCP; } if (rxsp->status11 & AR_crc_err) { /* for now set both */ rh->wr_flags |= AH_RADIOTAP_F_BADFCS; rh->wr_rx_flags |= AH_RADIOTAP_F_RX_BADFCS; } if (rxsp->status4 & AR_gi) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_HALFGI; rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_SHORT_GI; } if (rxsp->status4 & AR_2040) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40; rh->wr_mcs.flags |= RADIOTAP_MCS_FLAGS_40MHZ; } if (rxsp->status4 & AR_parallel40) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_40P; } if (rxsp->status11 & AR_rx_aggr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_AGGR; } if (rxsp->status11 & AR_rx_first_aggr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_FIRSTAGGR; } if (rxsp->status11 & AR_rx_more_aggr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MOREAGGR; } if (rxsp->status2 & AR_rx_more) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_MORE; } if (rxsp->status11 & AR_pre_delim_crc_err) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PREDELIM_CRCERR; } if (rxsp->status11 & AR_post_delim_crc_err) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_POSTDELIM_CRCERR; } if (rxsp->status11 & AR_decrypt_crc_err) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_DECRYPTCRCERR; } if (rxsp->status4 & AR_rx_stbc) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_STBC; } if (rxsp->status11 & AR_phyerr) { rh->wr_rx_flags |= AH_RADIOTAP_11NF_RX_PHYERR; rh->ath_ext.phyerr_code = MS(rxsp->status11, AR_phy_err_code); } /* add the extension part */ rh->vendor_ext.oui[0] = (ATH_OUI & 0xff); rh->vendor_ext.oui[1] = ((ATH_OUI >> 8) & 0xff); rh->vendor_ext.oui[2] = ((ATH_OUI >> 16) & 0xff); rh->vendor_ext.skip_length = sizeof(struct ah_rx_vendor_radiotap_header); /* sub_namespace - * simply set to 0 since we don't use multiple namespaces */ rh->vendor_ext.sub_namespace = 0; rh->ath_ext.version = AH_RADIOTAP_VERSION; rh->ath_ext.ch_info.num_chains = AR9300_NUM_CHAINS(AH9300(ah)->ah_rx_chainmask); /* * Two-pass strategy to fill in RSSI and EVM: * First pass: copy the info from each chain from the * descriptor into the corresponding index of the * radiotap header's ch_info array. * Second pass: use the rxchainmask to determine * which chains are valid. Shift ch_info array * elements down to fill in indices that were off * in the rxchainmask. */ if (rxsp->status11 & AR_post_delim_crc_err) { for (i = 0; i < RADIOTAP_MAX_CHAINS ; i++) { rh->ath_ext.ch_info.rssi_ctl[i] = HAL_RSSI_BAD; rh->ath_ext.ch_info.rssi_ext[i] = HAL_RSSI_BAD; } } else { rh->ath_ext.ch_info.rssi_ctl[0] = MS(rxsp->status1, AR_rx_rssi_ant00); rh->ath_ext.ch_info.rssi_ctl[1] = MS(rxsp->status1, AR_rx_rssi_ant01); rh->ath_ext.ch_info.rssi_ctl[2] = MS(rxsp->status1, AR_rx_rssi_ant02); rh->ath_ext.ch_info.rssi_ext[0] = MS(rxsp->status5, AR_rx_rssi_ant10); rh->ath_ext.ch_info.rssi_ext[1] = MS(rxsp->status5, AR_rx_rssi_ant11); rh->ath_ext.ch_info.rssi_ext[2] = MS(rxsp->status5, AR_rx_rssi_ant12); rh->ath_ext.ch_info.evm[0] = rxsp->AR_rx_evm0; rh->ath_ext.ch_info.evm[1] = rxsp->AR_rx_evm1; rh->ath_ext.ch_info.evm[2] = rxsp->AR_rx_evm2; } for (i = 0, j = 0; i < RADIOTAP_MAX_CHAINS ; i++) { if (AH9300(ah)->ah_rx_chainmask & (0x1 << i)) { /* * This chain is enabled. Does its data need * to be shifted down into a lower array index? */ if (i != j) { rh->ath_ext.ch_info.rssi_ctl[j] = rh->ath_ext.ch_info.rssi_ctl[i]; rh->ath_ext.ch_info.rssi_ext[j] = rh->ath_ext.ch_info.rssi_ext[i]; /* * EVM fields only need to be shifted if * PCU_SEL_EVM bit is set. * Otherwise EVM fields hold the value of PLCP headers * which are not related to chainmask. */ if (!(AH9300(ah)->ah_get_plcp_hdr)) { rh->ath_ext.ch_info.evm[j] = rh->ath_ext.ch_info.evm[i]; } } j++; } } rh->ath_ext.n_delims = MS(rxsp->status2, AR_num_delim); } /* if rh != NULL */