if ((fft_sample_20.data[max_index] & 0xf8) !=
((magnitude >> max_exp) & 0xf8)) {
ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
ret = -1;
}
/* DC value (value in the middle) is the blind spot of the spectral *sampleandinvalid,interpolateit.
*/
fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] +
fft_sample_20.data[dc_pos - 1]) / 2;
/* Check if the maximum magnitude is indeed maximum, *alsoifthemaximumvaluewasatdc_pos,calculate *anewone(sincevalueatdc_posisinvalid).
*/ if (max_index == dc_pos) {
tmp_mag = 0; for (i = 0; i < dc_pos; i++) { if (fft_sample_20.data[i] > tmp_mag) {
tmp_mag = fft_sample_20.data[i];
fft_sample_20.max_index = i;
}
}
ath_dbg(common, SPECTRAL_SCAN, "Calculated new lower max 0x%X at %i\n",
tmp_mag, fft_sample_20.max_index);
} else for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) { if (fft_sample_20.data[i] == (magnitude >> max_exp))
ath_dbg(common, SPECTRAL_SCAN, "Got max: 0x%X at index %i\n",
fft_sample_20.data[i], i);
if (fft_sample_20.data[i] > (magnitude >> max_exp)) {
ath_dbg(common, SPECTRAL_SCAN, "Got bin %i greater than max: 0x%X\n",
i, fft_sample_20.data[i]);
ret = -1;
}
}
/* Check if we got the expected magnitude values at *theexpectedbins
*/ if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8)
!= ((upper_mag >> max_exp) & 0xf8)) ||
((fft_sample_40.data[lower_max_index] & 0xf8)
!= ((lower_mag >> max_exp) & 0xf8))) {
ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
ret = -1;
}
/* DC value (value in the middle) is the blind spot of the spectral *sampleandinvalid,interpolateit.
*/
fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] +
fft_sample_40.data[dc_pos - 1]) / 2;
/* Check if the maximum magnitudes are indeed maximum, *alsoifthemaximumvaluewasatdc_pos,calculate *anewone(sincevalueatdc_posisinvalid).
*/ if (lower_max_index == dc_pos) {
tmp_mag = 0; for (i = 0; i < dc_pos; i++) { if (fft_sample_40.data[i] > tmp_mag) {
tmp_mag = fft_sample_40.data[i];
fft_sample_40.lower_max_index = i;
}
}
ath_dbg(common, SPECTRAL_SCAN, "Calculated new lower max 0x%X at %i\n",
tmp_mag, fft_sample_40.lower_max_index);
} else for (i = 0; i < dc_pos; i++) { if (fft_sample_40.data[i] == (lower_mag >> max_exp))
ath_dbg(common, SPECTRAL_SCAN, "Got lower mag: 0x%X at index %i\n",
fft_sample_40.data[i], i);
if (fft_sample_40.data[i] > (lower_mag >> max_exp)) {
ath_dbg(common, SPECTRAL_SCAN, "Got lower bin %i higher than max: 0x%X\n",
i, fft_sample_40.data[i]);
ret = -1;
}
}
if (upper_max_index == dc_pos) {
tmp_mag = 0; for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { if (fft_sample_40.data[i] > tmp_mag) {
tmp_mag = fft_sample_40.data[i];
fft_sample_40.upper_max_index = i;
}
}
upper_mag = tmp_mag << max_exp;
fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
ath_dbg(common, SPECTRAL_SCAN, "Calculated new upper max 0x%X at %i\n",
tmp_mag, fft_sample_40.upper_max_index);
} else for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { if (fft_sample_40.data[i] == (upper_mag >> max_exp))
ath_dbg(common, SPECTRAL_SCAN, "Got upper mag: 0x%X at index %i\n",
fft_sample_40.data[i], i);
if (fft_sample_40.data[i] > (upper_mag >> max_exp)) {
ath_dbg(common, SPECTRAL_SCAN, "Got upper bin %i higher than max: 0x%X\n",
i, fft_sample_40.data[i]);
ret = -1;
}
}
if (ret < 0) return ret;
tlv = (struct fft_sample_tlv *)&fft_sample_40;
ath_debug_send_fft_sample(spec_priv, tlv);
return0;
}
staticinlinevoid
ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
{ switch (sample_bytes - sample_len) { case -1: /* First byte missing */
memcpy(&out[1], in,
sample_len - 1); break; case0: /* Length correct, nothing to do. */
memcpy(out, in, sample_len); break; case1: /* MAC added 2 extra bytes AND first byte *ismissing.
*/
memcpy(&out[1], in, 30);
out[31] = in[31];
memcpy(&out[32], &in[33],
sample_len - 32); break; case2: /* MAC added 2 extra bytes at bin 30 and 32, *removethem.
*/
memcpy(out, in, 30);
out[30] = in[31];
memcpy(&out[31], &in[33],
sample_len - 31); break; default: break;
}
}
staticint
ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
{ int i = 0; int ret = 0; struct rchan_buf *buf; struct rchan *rc = spec_priv->rfs_chan_spec_scan;
for_each_possible_cpu(i) { if ((buf = *per_cpu_ptr(rc->buf, i))) {
ret += relay_buf_full(buf);
}
}
if (ret) return1; else return0;
}
/* returns 1 if this was a spectral frame, even if not handled. */ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf)
{
u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; struct ath_hw *ah = spec_priv->ah; struct ath_common *common = ath9k_hw_common(spec_priv->ah); struct ath_softc *sc = common->priv;
u8 num_bins, *vdata = (u8 *)hdr; struct ath_radar_info *radar_info; int len = rs->rs_datalen; int i; int got_slen = 0;
u8 *sample_start; int sample_bytes = 0; int ret = 0;
u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq; enum nl80211_channel_type chan_type;
ath_cmn_fft_idx_validator *fft_idx_validator;
ath_cmn_fft_sample_handler *fft_handler;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer *viaATH9K_PHYERR_SPECTRAL.Haven'tseenATH9K_PHYERR_FALSE_RADAR_EXT *yet,butthisissupposedtobepossibleaswell.
*/ if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) return0;
/* check if spectral scan bit is set. This does not have to be checked *ifreceivedthroughaSPECTRALphyerror,butshouldn'thurt.
*/
radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) return0;
if (!spec_priv->rfs_chan_spec_scan) return1;
/* Output buffers are full, no need to process anything *sincethereisnospacetoputtheresultanyway
*/
ret = ath_cmn_is_fft_buf_full(spec_priv); if (ret == 1) {
ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space " "left on output buffers\n"); return1;
}
ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X," "len: %i fft_len: %i\n",
radar_info->pulse_bw_info,
len,
fft_len);
sample_start = vdata; for (i = 0; i < len - 2; i++) {
sample_bytes++;
/* Only a single sample received, no need to look *forthesample'send,dothecorrectionbased *onthepacket'slengthinstead.Notethathw *willalwaysputtheradar_infostructureon *theend.
*/ if (len <= fft_len + 2) {
sample_bytes = len - sizeof(struct ath_radar_info);
got_slen = 1;
}
/* Search for the end of the FFT frame between *sample_len-1andsample_len+2.exp_maxis3 *bitslongandit'stheonlyvalueonthelast *byteoftheframesosinceit'llbesmallerthan *thenextbyte(thefirstbinofthenextsample) *90%ofthetime,wecanuseitasaseparator.
*/ if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) {
/* Got a frame length within boundaries, there are *fourscenarioshere: * *a)sample_len->Wegotthecorrectlength *b)sample_len+2->2bytesaddedaroundbin[31] *c)sample_len-1->Thefirstbyteismissing *d)sample_len+1->b+catthesametime * *WhenMACadds2extrabytes,bin[31]andbin[32] *havethesamevalue,sowecanusethatforfurther *verificationincasesbandd.
*/
/* Did we go too far ? If so we couldn't determine *thissample'sboundaries,discardanyfurther *data
*/ if ((sample_bytes > sample_len + 2) ||
((sample_bytes > sample_len) &&
(sample_start[31] != sample_start[32]))) break;
/* See if we got a valid frame by checking the *consistencyofmag_infofields.Thisisto *preventfrom"fixing"acorrectframe. *Failureisnon-fatal,laterframesmay *bevalid.
*/ if (!fft_idx_validator(&vdata[i], i)) {
ath_dbg(common, SPECTRAL_SCAN, "Found valid fft frame at %i\n", i);
got_slen = 1;
}
/* Try to distinguish cases a and c */ elseif ((sample_bytes == sample_len - 1) &&
(vdata[i + 1] <= 0x7)) continue;
got_slen = 1;
}
if (got_slen) {
ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
sample_bytes);
/* Only try to fix a frame if it's the only one *onthereport,elsejustskipit.
*/ if (sample_bytes != sample_len && len <= fft_len + 2) {
ath_cmn_copy_fft_frame(sample_start,
sample_buf, sample_len,
sample_bytes);
ret = fft_handler(rs, spec_priv, sample_buf,
tsf, freq, chan_type);
if (ret == 0)
RX_STAT_INC(sc, rx_spectral_sample_good); else
RX_STAT_INC(sc, rx_spectral_sample_err);
/* Mix the received bins to the /dev/random *pool
*/
add_device_randomness(sample_buf, num_bins);
memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
}
/* Process a normal frame */ if (sample_bytes == sample_len) {
ret = fft_handler(rs, spec_priv, sample_start,
tsf, freq, chan_type);
if (ret == 0)
RX_STAT_INC(sc, rx_spectral_sample_good); else
RX_STAT_INC(sc, rx_spectral_sample_err);
/* Mix the received bins to the /dev/random *pool
*/
add_device_randomness(sample_start, num_bins);
}
/* Short report processed, break out of the *loop.
*/ if (len <= fft_len + 2) return1;
sample_start = &vdata[i + 1];
/* -1 to grab sample_len -1, -2 since *they'llgetincreasedbyone.Incase *offailuretrytorecoverbygoingbyte *bybyteinstead.
*/ if (ret == 0) {
i += num_bins - 2;
sample_bytes = num_bins - 2;
}
got_slen = 0;
}
}
i -= num_bins - 2; if (len - i != sizeof(struct ath_radar_info))
ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated" "(bytes left: %i)\n",
len - i); return1;
}
EXPORT_SYMBOL(ath_cmn_process_fft);
/* TODO: usually this should not be necessary, but for some reason *(orinsomemode?)thetriggermustbecalledafterthe *configuration,otherwisetheregisterwillhaveitsvaluesreset *(onmyar9220tovalue0x01002310)
*/
ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode);
ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
ath_ps_ops(common)->restore(common);
}
EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.