Exemplo n.º 1
0
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 = " ";
	}
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
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);
    }
Exemplo n.º 6
0
/*
 * 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
}
Exemplo n.º 7
0
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 */