OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | --- a/drivers/net/wireless/ath/ath9k/channel.c |
2 | +++ b/drivers/net/wireless/ath/ath9k/channel.c |
||
3 | @@ -15,6 +15,8 @@ |
||
4 | */ |
||
5 | |||
6 | #include "ath9k.h" |
||
7 | +#include <linux/ath9k_platform.h> |
||
8 | +#include "hsr.h" |
||
9 | |||
10 | /* Set/change channels. If the channel is really being changed, it's done |
||
11 | * by reseting the chip. To accomplish this we must first cleanup any pending |
||
12 | @@ -22,6 +24,7 @@ |
||
13 | */ |
||
14 | static int ath_set_channel(struct ath_softc *sc) |
||
15 | { |
||
16 | + struct ath9k_platform_data *pdata = sc->dev->platform_data; |
||
17 | struct ath_hw *ah = sc->sc_ah; |
||
18 | struct ath_common *common = ath9k_hw_common(ah); |
||
19 | struct ieee80211_hw *hw = sc->hw; |
||
20 | @@ -42,6 +45,11 @@ static int ath_set_channel(struct ath_so |
||
21 | ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", |
||
22 | chan->center_freq, chandef->width); |
||
23 | |||
24 | + if (pdata && pdata->ubnt_hsr) { |
||
25 | + ath9k_hsr_enable(ah, chandef->width, chan->center_freq); |
||
26 | + ath9k_hsr_status(ah); |
||
27 | + } |
||
28 | + |
||
29 | /* update survey stats for the old channel before switching */ |
||
30 | spin_lock_irqsave(&common->cc_lock, flags); |
||
31 | ath_update_survey_stats(sc); |
||
32 | --- /dev/null |
||
33 | +++ b/drivers/net/wireless/ath/ath9k/hsr.c |
||
34 | @@ -0,0 +1,247 @@ |
||
35 | +/* |
||
36 | + * |
||
37 | + * The MIT License (MIT) |
||
38 | + * |
||
39 | + * Copyright (c) 2015 Kirill Berezin |
||
40 | + * |
||
41 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
||
42 | + * of this software and associated documentation files (the "Software"), to deal |
||
43 | + * in the Software without restriction, including without limitation the rights |
||
44 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||
45 | + * copies of the Software, and to permit persons to whom the Software is |
||
46 | + * furnished to do so, subject to the following conditions: |
||
47 | + * |
||
48 | + * The above copyright notice and this permission notice shall be included in |
||
49 | + * all copies or substantial portions of the Software. |
||
50 | + * |
||
51 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
52 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
53 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||
54 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
55 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
56 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
57 | + * SOFTWARE. |
||
58 | + * |
||
59 | + */ |
||
60 | + |
||
61 | +#include <linux/io.h> |
||
62 | +#include <linux/slab.h> |
||
63 | +#include <linux/module.h> |
||
64 | +#include <linux/time.h> |
||
65 | +#include <linux/bitops.h> |
||
66 | +#include <linux/etherdevice.h> |
||
67 | +#include <linux/rtnetlink.h> |
||
68 | +#include <asm/unaligned.h> |
||
69 | + |
||
70 | +#include "hw.h" |
||
71 | +#include "ath9k.h" |
||
72 | + |
||
73 | +#define HSR_GPIO_CSN 8 |
||
74 | +#define HSR_GPIO_CLK 6 |
||
75 | +#define HSR_GPIO_DOUT 7 |
||
76 | +#define HSR_GPIO_DIN 5 |
||
77 | + |
||
78 | +/* delays are in useconds */ |
||
79 | +#define HSR_DELAY_HALF_TICK 100 |
||
80 | +#define HSR_DELAY_PRE_WRITE 75 |
||
81 | +#define HSR_DELAY_FINAL 20000 |
||
82 | +#define HSR_DELAY_TRAILING 200 |
||
83 | + |
||
84 | +void ath9k_hsr_init(struct ath_hw *ah) |
||
85 | +{ |
||
86 | + ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL); |
||
87 | + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL, |
||
88 | + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
||
89 | + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL, |
||
90 | + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
||
91 | + ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL, |
||
92 | + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
||
93 | + |
||
94 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); |
||
95 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); |
||
96 | + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0); |
||
97 | + |
||
98 | + udelay(HSR_DELAY_TRAILING); |
||
99 | +} |
||
100 | + |
||
101 | +static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value) |
||
102 | +{ |
||
103 | + struct ath_common *common = ath9k_hw_common(ah); |
||
104 | + int i; |
||
105 | + u32 rval = 0; |
||
106 | + |
||
107 | + udelay(delay); |
||
108 | + |
||
109 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); |
||
110 | + udelay(HSR_DELAY_HALF_TICK); |
||
111 | + |
||
112 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); |
||
113 | + udelay(HSR_DELAY_HALF_TICK); |
||
114 | + |
||
115 | + for (i = 0; i < 8; ++i) { |
||
116 | + rval = rval << 1; |
||
117 | + |
||
118 | + /* pattern is left to right, that is 7-th bit runs first */ |
||
119 | + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); |
||
120 | + udelay(HSR_DELAY_HALF_TICK); |
||
121 | + |
||
122 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); |
||
123 | + udelay(HSR_DELAY_HALF_TICK); |
||
124 | + |
||
125 | + rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); |
||
126 | + |
||
127 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); |
||
128 | + udelay(HSR_DELAY_HALF_TICK); |
||
129 | + } |
||
130 | + |
||
131 | + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); |
||
132 | + udelay(HSR_DELAY_HALF_TICK); |
||
133 | + |
||
134 | + ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n", |
||
135 | + value, rval, rval > 32 ? rval : '-'); |
||
136 | + |
||
137 | + return rval & 0xff; |
||
138 | +} |
||
139 | + |
||
140 | +static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items) |
||
141 | +{ |
||
142 | + int status = 0; |
||
143 | + int i = 0; |
||
144 | + int err; |
||
145 | + |
||
146 | + /* a preamble */ |
||
147 | + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); |
||
148 | + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); |
||
149 | + |
||
150 | + /* clear HSR's reply buffer */ |
||
151 | + if (status) { |
||
152 | + int loop = 0; |
||
153 | + |
||
154 | + for (loop = 0; (loop < 42) && status; ++loop) |
||
155 | + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, |
||
156 | + 0); |
||
157 | + |
||
158 | + if (loop >= 42) { |
||
159 | + ATH_DBG_WARN(1, |
||
160 | + "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n"); |
||
161 | + return -1; |
||
162 | + } |
||
163 | + } |
||
164 | + |
||
165 | + for (i = 0; (i < items) && (chain[i] != 0); ++i) |
||
166 | + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); |
||
167 | + |
||
168 | + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); |
||
169 | + mdelay(HSR_DELAY_FINAL / 1000); |
||
170 | + |
||
171 | + /* reply */ |
||
172 | + memset(chain, 0, items); |
||
173 | + |
||
174 | + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); |
||
175 | + udelay(HSR_DELAY_TRAILING); |
||
176 | + |
||
177 | + for (i = 0; i < (items - 1); ++i) { |
||
178 | + u32 ret; |
||
179 | + |
||
180 | + ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); |
||
181 | + if (ret != 0) |
||
182 | + chain[i] = (char)ret; |
||
183 | + else |
||
184 | + break; |
||
185 | + |
||
186 | + udelay(HSR_DELAY_TRAILING); |
||
187 | + } |
||
188 | + |
||
189 | + if (i <= 1) |
||
190 | + return 0; |
||
191 | + |
||
192 | + err = kstrtoint(chain + 1, 10, &i); |
||
193 | + if (err) |
||
194 | + return err; |
||
195 | + |
||
196 | + return i; |
||
197 | +} |
||
198 | + |
||
199 | +int ath9k_hsr_disable(struct ath_hw *ah) |
||
200 | +{ |
||
201 | + char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0}; |
||
202 | + int ret; |
||
203 | + |
||
204 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
205 | + if ((ret > 0) && (*cmd == 'B')) |
||
206 | + return 0; |
||
207 | + |
||
208 | + return -1; |
||
209 | +} |
||
210 | + |
||
211 | +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) |
||
212 | +{ |
||
213 | + char cmd[10]; |
||
214 | + int ret; |
||
215 | + |
||
216 | + /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn |
||
217 | + * 20MHz on invalid values |
||
218 | + */ |
||
219 | + if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40)) |
||
220 | + bw = 20; |
||
221 | + |
||
222 | + memset(cmd, 0, sizeof(cmd)); |
||
223 | + *cmd = 'b'; |
||
224 | + snprintf(cmd + 1, 3, "%02d", bw); |
||
225 | + |
||
226 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
227 | + if ((*cmd != 'B') || (ret != bw)) { |
||
228 | + ATH_DBG_WARN(1, |
||
229 | + "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n", |
||
230 | + 'b', bw, *cmd, ret); |
||
231 | + return -1; |
||
232 | + } |
||
233 | + |
||
234 | + memset(cmd, 0, sizeof(cmd)); |
||
235 | + *cmd = 'x'; |
||
236 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
237 | + if (*cmd != 'X') { |
||
238 | + ATH_DBG_WARN(1, |
||
239 | + "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n", |
||
240 | + *cmd, ret); |
||
241 | + return -1; |
||
242 | + } |
||
243 | + |
||
244 | + memset(cmd, 0, sizeof(cmd)); |
||
245 | + *cmd = 'm'; |
||
246 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
247 | + if (*cmd != 'M') { |
||
248 | + ATH_DBG_WARN(1, |
||
249 | + "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n", |
||
250 | + *cmd, ret); |
||
251 | + return -1; |
||
252 | + } |
||
253 | + |
||
254 | + memset(cmd, 0, sizeof(cmd)); |
||
255 | + *cmd = 'f'; |
||
256 | + snprintf(cmd + 1, 6, "%05d", fq); |
||
257 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
258 | + if ((*cmd != 'F') && (ret != fq)) { |
||
259 | + ATH_DBG_WARN(1, |
||
260 | + "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n", |
||
261 | + *cmd, ret); |
||
262 | + return -1; |
||
263 | + } |
||
264 | + |
||
265 | + return 0; |
||
266 | +} |
||
267 | + |
||
268 | +int ath9k_hsr_status(struct ath_hw *ah) |
||
269 | +{ |
||
270 | + char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
||
271 | + int ret; |
||
272 | + |
||
273 | + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); |
||
274 | + if (*cmd != 'S') { |
||
275 | + ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd, |
||
276 | + ret); |
||
277 | + return -1; |
||
278 | + } |
||
279 | + |
||
280 | + return 0; |
||
281 | +} |
||
282 | --- /dev/null |
||
283 | +++ b/drivers/net/wireless/ath/ath9k/hsr.h |
||
284 | @@ -0,0 +1,48 @@ |
||
285 | +/* |
||
286 | + * The MIT License (MIT) |
||
287 | + * |
||
288 | + * Copyright (c) 2015 Kirill Berezin |
||
289 | + * |
||
290 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
||
291 | + * of this software and associated documentation files (the "Software"), to deal |
||
292 | + * in the Software without restriction, including without limitation the rights |
||
293 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||
294 | + * copies of the Software, and to permit persons to whom the Software is |
||
295 | + * furnished to do so, subject to the following conditions: |
||
296 | + * |
||
297 | + * The above copyright notice and this permission notice shall be included in |
||
298 | + * all copies or substantial portions of the Software. |
||
299 | + * |
||
300 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
301 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
302 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||
303 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
304 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
305 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
306 | + * SOFTWARE. |
||
307 | + */ |
||
308 | + |
||
309 | +#ifndef HSR_H |
||
310 | +#define HSR_H |
||
311 | + |
||
312 | +#ifdef CPTCFG_ATH9K_UBNTHSR |
||
313 | + |
||
314 | +void ath9k_hsr_init(struct ath_hw *ah); |
||
315 | +int ath9k_hsr_disable(struct ath_hw *ah); |
||
316 | +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq); |
||
317 | +int ath9k_hsr_status(struct ath_hw *ah); |
||
318 | + |
||
319 | +#else |
||
320 | +static inline void ath9k_hsr_init(struct ath_hw *ah) {} |
||
321 | + |
||
322 | +static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) |
||
323 | +{ |
||
324 | + return 0; |
||
325 | +} |
||
326 | + |
||
327 | +static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; } |
||
328 | +static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; } |
||
329 | + |
||
330 | +#endif |
||
331 | + |
||
332 | +#endif /* HSR_H */ |
||
333 | --- a/drivers/net/wireless/ath/ath9k/main.c |
||
334 | +++ b/drivers/net/wireless/ath/ath9k/main.c |
||
335 | @@ -16,8 +16,10 @@ |
||
336 | |||
337 | #include <linux/nl80211.h> |
||
338 | #include <linux/delay.h> |
||
339 | +#include <linux/ath9k_platform.h> |
||
340 | #include "ath9k.h" |
||
341 | #include "btcoex.h" |
||
342 | +#include "hsr.h" |
||
343 | |||
344 | u8 ath9k_parse_mpdudensity(u8 mpdudensity) |
||
345 | { |
||
346 | @@ -649,6 +651,7 @@ void ath_reset_work(struct work_struct * |
||
347 | static int ath9k_start(struct ieee80211_hw *hw) |
||
348 | { |
||
349 | struct ath_softc *sc = hw->priv; |
||
350 | + struct ath9k_platform_data *pdata = sc->dev->platform_data; |
||
351 | struct ath_hw *ah = sc->sc_ah; |
||
352 | struct ath_common *common = ath9k_hw_common(ah); |
||
353 | struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; |
||
354 | @@ -727,6 +730,11 @@ static int ath9k_start(struct ieee80211_ |
||
355 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
||
356 | } |
||
357 | |||
358 | + if (pdata && pdata->ubnt_hsr) { |
||
359 | + ath9k_hsr_init(ah); |
||
360 | + ath9k_hsr_disable(ah); |
||
361 | + } |
||
362 | + |
||
363 | /* |
||
364 | * Reset key cache to sane defaults (all entries cleared) instead of |
||
365 | * semi-random values after suspend/resume. |
||
366 | --- a/drivers/net/wireless/ath/ath9k/Makefile |
||
367 | +++ b/drivers/net/wireless/ath/ath9k/Makefile |
||
368 | @@ -16,6 +16,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d |
||
369 | ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o |
||
370 | ath9k-$(CPTCFG_ATH9K_WOW) += wow.o |
||
371 | ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o |
||
372 | +ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o |
||
373 | |||
374 | ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o |
||
375 | |||
376 | --- a/include/linux/ath9k_platform.h |
||
377 | +++ b/include/linux/ath9k_platform.h |
||
378 | @@ -53,6 +53,8 @@ struct ath9k_platform_data { |
||
379 | unsigned num_btns; |
||
380 | const struct gpio_keys_button *btns; |
||
381 | unsigned btn_poll_interval; |
||
382 | + |
||
383 | + bool ubnt_hsr; |
||
384 | }; |
||
385 | |||
386 | #endif /* _LINUX_ATH9K_PLATFORM_H */ |
||
387 | --- a/local-symbols |
||
388 | +++ b/local-symbols |
||
389 | @@ -114,6 +114,7 @@ ATH9K_WOW= |
||
390 | ATH9K_RFKILL= |
||
391 | ATH9K_CHANNEL_CONTEXT= |
||
392 | ATH9K_PCOEM= |
||
393 | +ATH9K_UBNTHSR= |
||
394 | ATH9K_HTC= |
||
395 | ATH9K_HTC_DEBUGFS= |
||
396 | ATH9K_HWRNG= |
||
397 | --- a/drivers/net/wireless/ath/ath9k/Kconfig |
||
398 | +++ b/drivers/net/wireless/ath/ath9k/Kconfig |
||
399 | @@ -59,6 +59,19 @@ config ATH9K_AHB |
||
400 | Say Y, if you have a SoC with a compatible built-in |
||
401 | wireless MAC. Say N if unsure. |
||
402 | |||
403 | +config ATH9K_UBNTHSR |
||
404 | + bool "Ubiquiti UniFi Outdoor Plus HSR support" |
||
405 | + depends on ATH9K |
||
406 | + ---help--- |
||
407 | + This options enables code to control the HSR RF |
||
408 | + filter in the receive path of the Ubiquiti UniFi |
||
409 | + Outdoor Plus access point. |
||
410 | + |
||
411 | + Say Y if you want to use the access point. The |
||
412 | + code will only be used if the device is detected, |
||
413 | + so it does not harm other setup other than occupying |
||
414 | + a bit of memory. |
||
415 | + |
||
416 | config ATH9K_DEBUGFS |
||
417 | bool "Atheros ath9k debugging" |
||
418 | depends on ATH9K && DEBUG_FS |