2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/relay.h>
18 #include <linux/random.h>
21 static s8
fix_rssi_inv_only(u8 rssi_val
)
28 static void ath_debug_send_fft_sample(struct ath_spec_scan_priv
*spec_priv
,
29 struct fft_sample_tlv
*fft_sample_tlv
)
32 if (!spec_priv
->rfs_chan_spec_scan
)
35 length
= __be16_to_cpu(fft_sample_tlv
->length
) +
36 sizeof(*fft_sample_tlv
);
37 relay_write(spec_priv
->rfs_chan_spec_scan
, fft_sample_tlv
, length
);
40 typedef int (ath_cmn_fft_idx_validator
) (u8
*sample_end
, int bytes_read
);
43 ath_cmn_max_idx_verify_ht20_fft(u8
*sample_end
, int bytes_read
)
45 struct ath_ht20_mag_info
*mag_info
;
51 /* Sanity check so that we don't read outside the read
54 if (bytes_read
< SPECTRAL_HT20_SAMPLE_LEN
- 1)
57 mag_info
= (struct ath_ht20_mag_info
*) (sample_end
-
58 sizeof(struct ath_ht20_mag_info
) + 1);
60 sample
= sample_end
- SPECTRAL_HT20_SAMPLE_LEN
+ 1;
62 max_index
= spectral_max_index(mag_info
->all_bins
,
63 SPECTRAL_HT20_NUM_BINS
);
64 max_magnitude
= spectral_max_magnitude(mag_info
->all_bins
);
66 max_exp
= mag_info
->max_exp
& 0xf;
68 /* Don't try to read something outside the read buffer
69 * in case of a missing byte (so bins[0] will be outside
72 if (bytes_read
< SPECTRAL_HT20_SAMPLE_LEN
&& max_index
< 1)
75 if (sample
[max_index
] != (max_magnitude
>> max_exp
))
82 ath_cmn_max_idx_verify_ht20_40_fft(u8
*sample_end
, int bytes_read
)
84 struct ath_ht20_40_mag_info
*mag_info
;
86 u16 lower_mag
, upper_mag
;
87 u8 lower_max_index
, upper_max_index
;
89 int dc_pos
= SPECTRAL_HT20_40_NUM_BINS
/ 2;
91 /* Sanity check so that we don't read outside the read
94 if (bytes_read
< SPECTRAL_HT20_40_SAMPLE_LEN
- 1)
97 mag_info
= (struct ath_ht20_40_mag_info
*) (sample_end
-
98 sizeof(struct ath_ht20_40_mag_info
) + 1);
100 sample
= sample_end
- SPECTRAL_HT20_40_SAMPLE_LEN
+ 1;
102 lower_mag
= spectral_max_magnitude(mag_info
->lower_bins
);
103 lower_max_index
= spectral_max_index(mag_info
->lower_bins
,
104 SPECTRAL_HT20_40_NUM_BINS
);
106 upper_mag
= spectral_max_magnitude(mag_info
->upper_bins
);
107 upper_max_index
= spectral_max_index(mag_info
->upper_bins
,
108 SPECTRAL_HT20_40_NUM_BINS
);
110 max_exp
= mag_info
->max_exp
& 0xf;
112 /* Don't try to read something outside the read buffer
113 * in case of a missing byte (so bins[0] will be outside
116 if (bytes_read
< SPECTRAL_HT20_40_SAMPLE_LEN
&&
117 ((upper_max_index
< 1) || (lower_max_index
< 1)))
120 /* Some time hardware messes up the index and adds
121 * the index of the middle point (dc_pos). Try to fix it.
123 if ((upper_max_index
- dc_pos
> 0) &&
124 (sample
[upper_max_index
] == (upper_mag
>> max_exp
)))
125 upper_max_index
-= dc_pos
;
127 if ((lower_max_index
- dc_pos
> 0) &&
128 (sample
[lower_max_index
- dc_pos
] == (lower_mag
>> max_exp
)))
129 lower_max_index
-= dc_pos
;
131 if ((sample
[upper_max_index
+ dc_pos
] != (upper_mag
>> max_exp
)) ||
132 (sample
[lower_max_index
] != (lower_mag
>> max_exp
)))
138 typedef int (ath_cmn_fft_sample_handler
) (struct ath_rx_status
*rs
,
139 struct ath_spec_scan_priv
*spec_priv
,
140 u8
*sample_buf
, u64 tsf
, u16 freq
, int chan_type
);
143 ath_cmn_process_ht20_fft(struct ath_rx_status
*rs
,
144 struct ath_spec_scan_priv
*spec_priv
,
146 u64 tsf
, u16 freq
, int chan_type
)
148 struct fft_sample_ht20 fft_sample_20
;
149 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
150 struct ath_hw
*ah
= spec_priv
->ah
;
151 struct ath_ht20_mag_info
*mag_info
;
152 struct fft_sample_tlv
*tlv
;
155 int dc_pos
= SPECTRAL_HT20_NUM_BINS
/ 2;
156 u16 magnitude
, tmp_mag
, length
;
157 u8 max_index
, bitmap_w
, max_exp
;
159 length
= sizeof(fft_sample_20
) - sizeof(struct fft_sample_tlv
);
160 fft_sample_20
.tlv
.type
= ATH_FFT_SAMPLE_HT20
;
161 fft_sample_20
.tlv
.length
= __cpu_to_be16(length
);
162 fft_sample_20
.freq
= __cpu_to_be16(freq
);
163 fft_sample_20
.rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
164 fft_sample_20
.noise
= ah
->noise
;
166 mag_info
= (struct ath_ht20_mag_info
*) (sample_buf
+
167 SPECTRAL_HT20_NUM_BINS
);
169 magnitude
= spectral_max_magnitude(mag_info
->all_bins
);
170 fft_sample_20
.max_magnitude
= __cpu_to_be16(magnitude
);
172 max_index
= spectral_max_index(mag_info
->all_bins
,
173 SPECTRAL_HT20_NUM_BINS
);
174 fft_sample_20
.max_index
= max_index
;
176 bitmap_w
= spectral_bitmap_weight(mag_info
->all_bins
);
177 fft_sample_20
.bitmap_weight
= bitmap_w
;
179 max_exp
= mag_info
->max_exp
& 0xf;
180 fft_sample_20
.max_exp
= max_exp
;
182 fft_sample_20
.tsf
= __cpu_to_be64(tsf
);
184 memcpy(fft_sample_20
.data
, sample_buf
, SPECTRAL_HT20_NUM_BINS
);
186 ath_dbg(common
, SPECTRAL_SCAN
, "FFT HT20 frame: max mag 0x%X,"
188 magnitude
>> max_exp
,
191 if (fft_sample_20
.data
[max_index
] != (magnitude
>> max_exp
)) {
192 ath_dbg(common
, SPECTRAL_SCAN
, "Magnitude mismatch !\n");
196 /* DC value (value in the middle) is the blind spot of the spectral
197 * sample and invalid, interpolate it.
199 fft_sample_20
.data
[dc_pos
] = (fft_sample_20
.data
[dc_pos
+ 1] +
200 fft_sample_20
.data
[dc_pos
- 1]) / 2;
202 /* Check if the maximum magnitude is indeed maximum,
203 * also if the maximum value was at dc_pos, calculate
204 * a new one (since value at dc_pos is invalid).
206 if (max_index
== dc_pos
) {
208 for (i
= 0; i
< dc_pos
; i
++) {
209 if (fft_sample_20
.data
[i
] > tmp_mag
) {
210 tmp_mag
= fft_sample_20
.data
[i
];
211 fft_sample_20
.max_index
= i
;
215 magnitude
= tmp_mag
<< max_exp
;
216 fft_sample_20
.max_magnitude
= __cpu_to_be16(magnitude
);
218 ath_dbg(common
, SPECTRAL_SCAN
,
219 "Calculated new lower max 0x%X at %i\n",
220 tmp_mag
, fft_sample_20
.max_index
);
222 for (i
= 0; i
< SPECTRAL_HT20_NUM_BINS
; i
++) {
223 if (fft_sample_20
.data
[i
] == (magnitude
>> max_exp
))
224 ath_dbg(common
, SPECTRAL_SCAN
,
225 "Got max: 0x%X at index %i\n",
226 fft_sample_20
.data
[i
], i
);
228 if (fft_sample_20
.data
[i
] > (magnitude
>> max_exp
)) {
229 ath_dbg(common
, SPECTRAL_SCAN
,
230 "Got bin %i greater than max: 0x%X\n",
231 i
, fft_sample_20
.data
[i
]);
239 tlv
= (struct fft_sample_tlv
*)&fft_sample_20
;
241 ath_debug_send_fft_sample(spec_priv
, tlv
);
247 ath_cmn_process_ht20_40_fft(struct ath_rx_status
*rs
,
248 struct ath_spec_scan_priv
*spec_priv
,
250 u64 tsf
, u16 freq
, int chan_type
)
252 struct fft_sample_ht20_40 fft_sample_40
;
253 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
254 struct ath_hw
*ah
= spec_priv
->ah
;
255 struct ath9k_hw_cal_data
*caldata
= ah
->caldata
;
256 struct ath_ht20_40_mag_info
*mag_info
;
257 struct fft_sample_tlv
*tlv
;
258 int dc_pos
= SPECTRAL_HT20_40_NUM_BINS
/ 2;
262 u16 lower_mag
, upper_mag
, tmp_mag
, length
;
263 s8 lower_rssi
, upper_rssi
;
264 u8 lower_max_index
, upper_max_index
;
265 u8 lower_bitmap_w
, upper_bitmap_w
, max_exp
;
268 ext_nf
= ath9k_hw_getchan_noise(ah
, ah
->curchan
,
269 caldata
->nfCalHist
[3].privNF
);
271 ext_nf
= ATH_DEFAULT_NOISE_FLOOR
;
273 length
= sizeof(fft_sample_40
) - sizeof(struct fft_sample_tlv
);
274 fft_sample_40
.tlv
.type
= ATH_FFT_SAMPLE_HT20_40
;
275 fft_sample_40
.tlv
.length
= __cpu_to_be16(length
);
276 fft_sample_40
.freq
= __cpu_to_be16(freq
);
277 fft_sample_40
.channel_type
= chan_type
;
279 if (chan_type
== NL80211_CHAN_HT40PLUS
) {
280 lower_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
281 upper_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ext
[0]);
283 fft_sample_40
.lower_noise
= ah
->noise
;
284 fft_sample_40
.upper_noise
= ext_nf
;
286 lower_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ext
[0]);
287 upper_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
289 fft_sample_40
.lower_noise
= ext_nf
;
290 fft_sample_40
.upper_noise
= ah
->noise
;
293 fft_sample_40
.lower_rssi
= lower_rssi
;
294 fft_sample_40
.upper_rssi
= upper_rssi
;
296 mag_info
= (struct ath_ht20_40_mag_info
*) (sample_buf
+
297 SPECTRAL_HT20_40_NUM_BINS
);
299 lower_mag
= spectral_max_magnitude(mag_info
->lower_bins
);
300 fft_sample_40
.lower_max_magnitude
= __cpu_to_be16(lower_mag
);
302 upper_mag
= spectral_max_magnitude(mag_info
->upper_bins
);
303 fft_sample_40
.upper_max_magnitude
= __cpu_to_be16(upper_mag
);
305 lower_max_index
= spectral_max_index(mag_info
->lower_bins
,
306 SPECTRAL_HT20_40_NUM_BINS
);
307 fft_sample_40
.lower_max_index
= lower_max_index
;
309 upper_max_index
= spectral_max_index(mag_info
->upper_bins
,
310 SPECTRAL_HT20_40_NUM_BINS
);
311 fft_sample_40
.upper_max_index
= upper_max_index
;
313 lower_bitmap_w
= spectral_bitmap_weight(mag_info
->lower_bins
);
314 fft_sample_40
.lower_bitmap_weight
= lower_bitmap_w
;
316 upper_bitmap_w
= spectral_bitmap_weight(mag_info
->upper_bins
);
317 fft_sample_40
.upper_bitmap_weight
= upper_bitmap_w
;
319 max_exp
= mag_info
->max_exp
& 0xf;
320 fft_sample_40
.max_exp
= max_exp
;
322 fft_sample_40
.tsf
= __cpu_to_be64(tsf
);
324 memcpy(fft_sample_40
.data
, sample_buf
, SPECTRAL_HT20_40_NUM_BINS
);
326 ath_dbg(common
, SPECTRAL_SCAN
, "FFT HT20/40 frame: lower mag 0x%X,"
327 "lower_mag_idx %i, upper mag 0x%X,"
328 "upper_mag_idx %i\n",
329 lower_mag
>> max_exp
,
331 upper_mag
>> max_exp
,
334 /* Some time hardware messes up the index and adds
335 * the index of the middle point (dc_pos). Try to fix it.
337 if ((upper_max_index
- dc_pos
> 0) &&
338 (fft_sample_40
.data
[upper_max_index
] == (upper_mag
>> max_exp
))) {
339 upper_max_index
-= dc_pos
;
340 fft_sample_40
.upper_max_index
= upper_max_index
;
343 if ((lower_max_index
- dc_pos
> 0) &&
344 (fft_sample_40
.data
[lower_max_index
- dc_pos
] ==
345 (lower_mag
>> max_exp
))) {
346 lower_max_index
-= dc_pos
;
347 fft_sample_40
.lower_max_index
= lower_max_index
;
350 /* Check if we got the expected magnitude values at
353 if ((fft_sample_40
.data
[upper_max_index
+ dc_pos
]
354 != (upper_mag
>> max_exp
)) ||
355 (fft_sample_40
.data
[lower_max_index
]
356 != (lower_mag
>> max_exp
))) {
357 ath_dbg(common
, SPECTRAL_SCAN
, "Magnitude mismatch !\n");
361 /* DC value (value in the middle) is the blind spot of the spectral
362 * sample and invalid, interpolate it.
364 fft_sample_40
.data
[dc_pos
] = (fft_sample_40
.data
[dc_pos
+ 1] +
365 fft_sample_40
.data
[dc_pos
- 1]) / 2;
367 /* Check if the maximum magnitudes are indeed maximum,
368 * also if the maximum value was at dc_pos, calculate
369 * a new one (since value at dc_pos is invalid).
371 if (lower_max_index
== dc_pos
) {
373 for (i
= 0; i
< dc_pos
; i
++) {
374 if (fft_sample_40
.data
[i
] > tmp_mag
) {
375 tmp_mag
= fft_sample_40
.data
[i
];
376 fft_sample_40
.lower_max_index
= i
;
380 lower_mag
= tmp_mag
<< max_exp
;
381 fft_sample_40
.lower_max_magnitude
= __cpu_to_be16(lower_mag
);
383 ath_dbg(common
, SPECTRAL_SCAN
,
384 "Calculated new lower max 0x%X at %i\n",
385 tmp_mag
, fft_sample_40
.lower_max_index
);
387 for (i
= 0; i
< dc_pos
; i
++) {
388 if (fft_sample_40
.data
[i
] == (lower_mag
>> max_exp
))
389 ath_dbg(common
, SPECTRAL_SCAN
,
390 "Got lower mag: 0x%X at index %i\n",
391 fft_sample_40
.data
[i
], i
);
393 if (fft_sample_40
.data
[i
] > (lower_mag
>> max_exp
)) {
394 ath_dbg(common
, SPECTRAL_SCAN
,
395 "Got lower bin %i higher than max: 0x%X\n",
396 i
, fft_sample_40
.data
[i
]);
401 if (upper_max_index
== dc_pos
) {
403 for (i
= dc_pos
; i
< SPECTRAL_HT20_40_NUM_BINS
; i
++) {
404 if (fft_sample_40
.data
[i
] > tmp_mag
) {
405 tmp_mag
= fft_sample_40
.data
[i
];
406 fft_sample_40
.upper_max_index
= i
;
409 upper_mag
= tmp_mag
<< max_exp
;
410 fft_sample_40
.upper_max_magnitude
= __cpu_to_be16(upper_mag
);
412 ath_dbg(common
, SPECTRAL_SCAN
,
413 "Calculated new upper max 0x%X at %i\n",
416 for (i
= dc_pos
; i
< SPECTRAL_HT20_40_NUM_BINS
; i
++) {
417 if (fft_sample_40
.data
[i
] == (upper_mag
>> max_exp
))
418 ath_dbg(common
, SPECTRAL_SCAN
,
419 "Got upper mag: 0x%X at index %i\n",
420 fft_sample_40
.data
[i
], i
);
422 if (fft_sample_40
.data
[i
] > (upper_mag
>> max_exp
)) {
423 ath_dbg(common
, SPECTRAL_SCAN
,
424 "Got upper bin %i higher than max: 0x%X\n",
425 i
, fft_sample_40
.data
[i
]);
434 tlv
= (struct fft_sample_tlv
*)&fft_sample_40
;
436 ath_debug_send_fft_sample(spec_priv
, tlv
);
442 ath_cmn_copy_fft_frame(u8
*in
, u8
*out
, int sample_len
, int sample_bytes
)
444 switch (sample_bytes
- sample_len
) {
446 /* First byte missing */
451 /* Length correct, nothing to do. */
452 memcpy(out
, in
, sample_len
);
455 /* MAC added 2 extra bytes AND first byte
458 memcpy(&out
[1], in
, 30);
460 memcpy(&out
[32], &in
[33],
464 /* MAC added 2 extra bytes at bin 30 and 32,
469 memcpy(&out
[31], &in
[33],
478 ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv
*spec_priv
)
482 struct rchan
*rc
= spec_priv
->rfs_chan_spec_scan
;
484 for_each_online_cpu(i
)
485 ret
+= relay_buf_full(rc
->buf
[i
]);
487 i
= num_online_cpus();
495 /* returns 1 if this was a spectral frame, even if not handled. */
496 int ath_cmn_process_fft(struct ath_spec_scan_priv
*spec_priv
, struct ieee80211_hdr
*hdr
,
497 struct ath_rx_status
*rs
, u64 tsf
)
499 u8 sample_buf
[SPECTRAL_SAMPLE_MAX_LEN
] = {0};
500 struct ath_hw
*ah
= spec_priv
->ah
;
501 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
502 u8 num_bins
, *vdata
= (u8
*)hdr
;
503 struct ath_radar_info
*radar_info
;
504 int len
= rs
->rs_datalen
;
508 int sample_bytes
= 0;
510 u16 fft_len
, sample_len
, freq
= ah
->curchan
->chan
->center_freq
;
511 enum nl80211_channel_type chan_type
;
512 ath_cmn_fft_idx_validator
*fft_idx_validator
;
513 ath_cmn_fft_sample_handler
*fft_handler
;
515 /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
516 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
517 * yet, but this is supposed to be possible as well.
519 if (rs
->rs_phyerr
!= ATH9K_PHYERR_RADAR
&&
520 rs
->rs_phyerr
!= ATH9K_PHYERR_FALSE_RADAR_EXT
&&
521 rs
->rs_phyerr
!= ATH9K_PHYERR_SPECTRAL
)
524 /* check if spectral scan bit is set. This does not have to be checked
525 * if received through a SPECTRAL phy error, but shouldn't hurt.
527 radar_info
= ((struct ath_radar_info
*)&vdata
[len
]) - 1;
528 if (!(radar_info
->pulse_bw_info
& SPECTRAL_SCAN_BITMASK
))
531 if (!spec_priv
->rfs_chan_spec_scan
)
534 /* Output buffers are full, no need to process anything
535 * since there is no space to put the result anyway
537 ret
= ath_cmn_is_fft_buf_full(spec_priv
);
539 ath_dbg(common
, SPECTRAL_SCAN
, "FFT report ignored, no space "
540 "left on output buffers\n");
544 chan_type
= cfg80211_get_chandef_type(&common
->hw
->conf
.chandef
);
545 if ((chan_type
== NL80211_CHAN_HT40MINUS
) ||
546 (chan_type
== NL80211_CHAN_HT40PLUS
)) {
547 fft_len
= SPECTRAL_HT20_40_TOTAL_DATA_LEN
;
548 sample_len
= SPECTRAL_HT20_40_SAMPLE_LEN
;
549 num_bins
= SPECTRAL_HT20_40_NUM_BINS
;
550 fft_idx_validator
= &ath_cmn_max_idx_verify_ht20_40_fft
;
551 fft_handler
= &ath_cmn_process_ht20_40_fft
;
553 fft_len
= SPECTRAL_HT20_TOTAL_DATA_LEN
;
554 sample_len
= SPECTRAL_HT20_SAMPLE_LEN
;
555 num_bins
= SPECTRAL_HT20_NUM_BINS
;
556 fft_idx_validator
= ath_cmn_max_idx_verify_ht20_fft
;
557 fft_handler
= &ath_cmn_process_ht20_fft
;
560 ath_dbg(common
, SPECTRAL_SCAN
, "Got radar dump bw_info: 0x%X,"
561 "len: %i fft_len: %i\n",
562 radar_info
->pulse_bw_info
,
565 sample_start
= vdata
;
566 for (i
= 0; i
< len
- 2; i
++) {
569 /* Only a single sample received, no need to look
570 * for the sample's end, do the correction based
571 * on the packet's length instead. Note that hw
572 * will always put the radar_info structure on
575 if (len
<= fft_len
+ 2) {
576 sample_bytes
= len
- sizeof(struct ath_radar_info
);
580 /* Search for the end of the FFT frame between
581 * sample_len - 1 and sample_len + 2. exp_max is 3
582 * bits long and it's the only value on the last
583 * byte of the frame so since it'll be smaller than
584 * the next byte (the first bin of the next sample)
585 * 90% of the time, we can use it as a separator.
587 if (vdata
[i
] <= 0x7 && sample_bytes
>= sample_len
- 1) {
589 /* Got a frame length within boundaries, there are
590 * four scenarios here:
592 * a) sample_len -> We got the correct length
593 * b) sample_len + 2 -> 2 bytes added around bin[31]
594 * c) sample_len - 1 -> The first byte is missing
595 * d) sample_len + 1 -> b + c at the same time
597 * When MAC adds 2 extra bytes, bin[31] and bin[32]
598 * have the same value, so we can use that for further
599 * verification in cases b and d.
602 /* Did we go too far ? If so we couldn't determine
603 * this sample's boundaries, discard any further
606 if ((sample_bytes
> sample_len
+ 2) ||
607 ((sample_bytes
> sample_len
) &&
608 (sample_start
[31] != sample_start
[32])))
611 /* See if we got a valid frame by checking the
612 * consistency of mag_info fields. This is to
613 * prevent from "fixing" a correct frame.
614 * Failure is non-fatal, later frames may
617 if (!fft_idx_validator(&vdata
[i
], i
)) {
618 ath_dbg(common
, SPECTRAL_SCAN
,
619 "Found valid fft frame at %i\n", i
);
623 /* We expect 1 - 2 more bytes */
624 else if ((sample_start
[31] == sample_start
[32]) &&
625 (sample_bytes
>= sample_len
) &&
626 (sample_bytes
< sample_len
+ 2) &&
627 (vdata
[i
+ 1] <= 0x7))
630 /* Try to distinguish cases a and c */
631 else if ((sample_bytes
== sample_len
- 1) &&
632 (vdata
[i
+ 1] <= 0x7))
639 ath_dbg(common
, SPECTRAL_SCAN
, "FFT frame len: %i\n",
642 /* Only try to fix a frame if it's the only one
643 * on the report, else just skip it.
645 if (sample_bytes
!= sample_len
&& len
<= fft_len
+ 2) {
646 ath_cmn_copy_fft_frame(sample_start
,
647 sample_buf
, sample_len
,
650 fft_handler(rs
, spec_priv
, sample_buf
,
651 tsf
, freq
, chan_type
);
653 memset(sample_buf
, 0, SPECTRAL_SAMPLE_MAX_LEN
);
655 /* Mix the received bins to the /dev/random
658 add_device_randomness(sample_buf
, num_bins
);
661 /* Process a normal frame */
662 if (sample_bytes
== sample_len
) {
663 ret
= fft_handler(rs
, spec_priv
, sample_start
,
664 tsf
, freq
, chan_type
);
666 /* Mix the received bins to the /dev/random
669 add_device_randomness(sample_start
, num_bins
);
672 /* Short report processed, break out of the
675 if (len
<= fft_len
+ 2)
678 sample_start
= &vdata
[i
+ 1];
680 /* -1 to grab sample_len -1, -2 since
681 * they 'll get increased by one. In case
682 * of failure try to recover by going byte
687 sample_bytes
= num_bins
- 2;
694 if (len
- i
!= sizeof(struct ath_radar_info
))
695 ath_dbg(common
, SPECTRAL_SCAN
, "FFT report truncated"
696 "(bytes left: %i)\n",
700 EXPORT_SYMBOL(ath_cmn_process_fft
);
702 /*********************/
703 /* spectral_scan_ctl */
704 /*********************/
706 static ssize_t
read_file_spec_scan_ctl(struct file
*file
, char __user
*user_buf
,
707 size_t count
, loff_t
*ppos
)
709 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
713 switch (spec_priv
->spectral_mode
) {
714 case SPECTRAL_DISABLED
:
717 case SPECTRAL_BACKGROUND
:
720 case SPECTRAL_CHANSCAN
:
723 case SPECTRAL_MANUAL
:
728 return simple_read_from_buffer(user_buf
, count
, ppos
, mode
, len
);
731 void ath9k_cmn_spectral_scan_trigger(struct ath_common
*common
,
732 struct ath_spec_scan_priv
*spec_priv
)
734 struct ath_hw
*ah
= spec_priv
->ah
;
737 if (config_enabled(CONFIG_ATH9K_TX99
))
740 if (!ath9k_hw_ops(ah
)->spectral_scan_trigger
) {
741 ath_err(common
, "spectrum analyzer not implemented on this hardware\n");
745 ath_ps_ops(common
)->wakeup(common
);
746 rxfilter
= ath9k_hw_getrxfilter(ah
);
747 ath9k_hw_setrxfilter(ah
, rxfilter
|
748 ATH9K_RX_FILTER_PHYRADAR
|
749 ATH9K_RX_FILTER_PHYERR
);
751 /* TODO: usually this should not be neccesary, but for some reason
752 * (or in some mode?) the trigger must be called after the
753 * configuration, otherwise the register will have its values reset
754 * (on my ar9220 to value 0x01002310)
756 ath9k_cmn_spectral_scan_config(common
, spec_priv
, spec_priv
->spectral_mode
);
757 ath9k_hw_ops(ah
)->spectral_scan_trigger(ah
);
758 ath_ps_ops(common
)->restore(common
);
760 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger
);
762 int ath9k_cmn_spectral_scan_config(struct ath_common
*common
,
763 struct ath_spec_scan_priv
*spec_priv
,
764 enum spectral_mode spectral_mode
)
766 struct ath_hw
*ah
= spec_priv
->ah
;
768 if (!ath9k_hw_ops(ah
)->spectral_scan_trigger
) {
769 ath_err(common
, "spectrum analyzer not implemented on this hardware\n");
773 switch (spectral_mode
) {
774 case SPECTRAL_DISABLED
:
775 spec_priv
->spec_config
.enabled
= 0;
777 case SPECTRAL_BACKGROUND
:
778 /* send endless samples.
779 * TODO: is this really useful for "background"?
781 spec_priv
->spec_config
.endless
= 1;
782 spec_priv
->spec_config
.enabled
= 1;
784 case SPECTRAL_CHANSCAN
:
785 case SPECTRAL_MANUAL
:
786 spec_priv
->spec_config
.endless
= 0;
787 spec_priv
->spec_config
.enabled
= 1;
793 ath_ps_ops(common
)->wakeup(common
);
794 ath9k_hw_ops(ah
)->spectral_scan_config(ah
, &spec_priv
->spec_config
);
795 ath_ps_ops(common
)->restore(common
);
797 spec_priv
->spectral_mode
= spectral_mode
;
801 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config
);
803 static ssize_t
write_file_spec_scan_ctl(struct file
*file
,
804 const char __user
*user_buf
,
805 size_t count
, loff_t
*ppos
)
807 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
808 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
812 if (config_enabled(CONFIG_ATH9K_TX99
))
815 len
= min(count
, sizeof(buf
) - 1);
816 if (copy_from_user(buf
, user_buf
, len
))
821 if (strncmp("trigger", buf
, 7) == 0) {
822 ath9k_cmn_spectral_scan_trigger(common
, spec_priv
);
823 } else if (strncmp("background", buf
, 10) == 0) {
824 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_BACKGROUND
);
825 ath_dbg(common
, CONFIG
, "spectral scan: background mode enabled\n");
826 } else if (strncmp("chanscan", buf
, 8) == 0) {
827 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_CHANSCAN
);
828 ath_dbg(common
, CONFIG
, "spectral scan: channel scan mode enabled\n");
829 } else if (strncmp("manual", buf
, 6) == 0) {
830 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_MANUAL
);
831 ath_dbg(common
, CONFIG
, "spectral scan: manual mode enabled\n");
832 } else if (strncmp("disable", buf
, 7) == 0) {
833 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_DISABLED
);
834 ath_dbg(common
, CONFIG
, "spectral scan: disabled\n");
842 static const struct file_operations fops_spec_scan_ctl
= {
843 .read
= read_file_spec_scan_ctl
,
844 .write
= write_file_spec_scan_ctl
,
846 .owner
= THIS_MODULE
,
847 .llseek
= default_llseek
,
850 /*************************/
851 /* spectral_short_repeat */
852 /*************************/
854 static ssize_t
read_file_spectral_short_repeat(struct file
*file
,
855 char __user
*user_buf
,
856 size_t count
, loff_t
*ppos
)
858 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
862 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.short_repeat
);
863 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
866 static ssize_t
write_file_spectral_short_repeat(struct file
*file
,
867 const char __user
*user_buf
,
868 size_t count
, loff_t
*ppos
)
870 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
875 len
= min(count
, sizeof(buf
) - 1);
876 if (copy_from_user(buf
, user_buf
, len
))
880 if (kstrtoul(buf
, 0, &val
))
886 spec_priv
->spec_config
.short_repeat
= val
;
890 static const struct file_operations fops_spectral_short_repeat
= {
891 .read
= read_file_spectral_short_repeat
,
892 .write
= write_file_spectral_short_repeat
,
894 .owner
= THIS_MODULE
,
895 .llseek
= default_llseek
,
902 static ssize_t
read_file_spectral_count(struct file
*file
,
903 char __user
*user_buf
,
904 size_t count
, loff_t
*ppos
)
906 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
910 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.count
);
911 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
914 static ssize_t
write_file_spectral_count(struct file
*file
,
915 const char __user
*user_buf
,
916 size_t count
, loff_t
*ppos
)
918 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
923 len
= min(count
, sizeof(buf
) - 1);
924 if (copy_from_user(buf
, user_buf
, len
))
928 if (kstrtoul(buf
, 0, &val
))
934 spec_priv
->spec_config
.count
= val
;
938 static const struct file_operations fops_spectral_count
= {
939 .read
= read_file_spectral_count
,
940 .write
= write_file_spectral_count
,
942 .owner
= THIS_MODULE
,
943 .llseek
= default_llseek
,
946 /*******************/
947 /* spectral_period */
948 /*******************/
950 static ssize_t
read_file_spectral_period(struct file
*file
,
951 char __user
*user_buf
,
952 size_t count
, loff_t
*ppos
)
954 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
958 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.period
);
959 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
962 static ssize_t
write_file_spectral_period(struct file
*file
,
963 const char __user
*user_buf
,
964 size_t count
, loff_t
*ppos
)
966 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
971 len
= min(count
, sizeof(buf
) - 1);
972 if (copy_from_user(buf
, user_buf
, len
))
976 if (kstrtoul(buf
, 0, &val
))
982 spec_priv
->spec_config
.period
= val
;
986 static const struct file_operations fops_spectral_period
= {
987 .read
= read_file_spectral_period
,
988 .write
= write_file_spectral_period
,
990 .owner
= THIS_MODULE
,
991 .llseek
= default_llseek
,
994 /***********************/
995 /* spectral_fft_period */
996 /***********************/
998 static ssize_t
read_file_spectral_fft_period(struct file
*file
,
999 char __user
*user_buf
,
1000 size_t count
, loff_t
*ppos
)
1002 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
1006 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.fft_period
);
1007 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
1010 static ssize_t
write_file_spectral_fft_period(struct file
*file
,
1011 const char __user
*user_buf
,
1012 size_t count
, loff_t
*ppos
)
1014 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
1019 len
= min(count
, sizeof(buf
) - 1);
1020 if (copy_from_user(buf
, user_buf
, len
))
1024 if (kstrtoul(buf
, 0, &val
))
1030 spec_priv
->spec_config
.fft_period
= val
;
1034 static const struct file_operations fops_spectral_fft_period
= {
1035 .read
= read_file_spectral_fft_period
,
1036 .write
= write_file_spectral_fft_period
,
1037 .open
= simple_open
,
1038 .owner
= THIS_MODULE
,
1039 .llseek
= default_llseek
,
1042 /*******************/
1043 /* Relay interface */
1044 /*******************/
1046 static struct dentry
*create_buf_file_handler(const char *filename
,
1047 struct dentry
*parent
,
1049 struct rchan_buf
*buf
,
1052 struct dentry
*buf_file
;
1054 buf_file
= debugfs_create_file(filename
, mode
, parent
, buf
,
1055 &relay_file_operations
);
1060 static int remove_buf_file_handler(struct dentry
*dentry
)
1062 debugfs_remove(dentry
);
1067 static struct rchan_callbacks rfs_spec_scan_cb
= {
1068 .create_buf_file
= create_buf_file_handler
,
1069 .remove_buf_file
= remove_buf_file_handler
,
1072 /*********************/
1073 /* Debug Init/Deinit */
1074 /*********************/
1076 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv
*spec_priv
)
1078 if (config_enabled(CONFIG_ATH9K_DEBUGFS
) && spec_priv
->rfs_chan_spec_scan
) {
1079 relay_close(spec_priv
->rfs_chan_spec_scan
);
1080 spec_priv
->rfs_chan_spec_scan
= NULL
;
1083 EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug
);
1085 void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv
*spec_priv
,
1086 struct dentry
*debugfs_phy
)
1088 spec_priv
->rfs_chan_spec_scan
= relay_open("spectral_scan",
1090 1024, 256, &rfs_spec_scan_cb
,
1092 if (!spec_priv
->rfs_chan_spec_scan
)
1095 debugfs_create_file("spectral_scan_ctl",
1097 debugfs_phy
, spec_priv
,
1098 &fops_spec_scan_ctl
);
1099 debugfs_create_file("spectral_short_repeat",
1101 debugfs_phy
, spec_priv
,
1102 &fops_spectral_short_repeat
);
1103 debugfs_create_file("spectral_count",
1105 debugfs_phy
, spec_priv
,
1106 &fops_spectral_count
);
1107 debugfs_create_file("spectral_period",
1109 debugfs_phy
, spec_priv
,
1110 &fops_spectral_period
);
1111 debugfs_create_file("spectral_fft_period",
1113 debugfs_phy
, spec_priv
,
1114 &fops_spectral_fft_period
);
1116 EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug
);