1 | /* $OpenBSD: if_urtwn.c,v 1.22 2012/04/08 12:17:20 jsg Exp $ */
|
---|
2 |
|
---|
3 | /*-
|
---|
4 | * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
|
---|
5 | *
|
---|
6 | * Permission to use, copy, modify, and distribute this software for any
|
---|
7 | * purpose with or without fee is hereby granted, provided that the above
|
---|
8 | * copyright notice and this permission notice appear in all copies.
|
---|
9 | *
|
---|
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
---|
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
---|
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
---|
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
---|
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
---|
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
---|
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
---|
17 | */
|
---|
18 |
|
---|
19 | /*
|
---|
20 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188RU/RTL8192CU.
|
---|
21 | */
|
---|
22 |
|
---|
23 | #include "bpfilter.h"
|
---|
24 |
|
---|
25 | #include <sys/param.h>
|
---|
26 | #include <sys/sockio.h>
|
---|
27 | #include <sys/mbuf.h>
|
---|
28 | #include <sys/kernel.h>
|
---|
29 | #include <sys/socket.h>
|
---|
30 | #include <sys/systm.h>
|
---|
31 | #include <sys/timeout.h>
|
---|
32 | #include <sys/conf.h>
|
---|
33 | #include <sys/device.h>
|
---|
34 |
|
---|
35 | #include <machine/bus.h>
|
---|
36 | #include <machine/endian.h>
|
---|
37 | #include <machine/intr.h>
|
---|
38 |
|
---|
39 | #if NBPFILTER > 0
|
---|
40 | #include <net/bpf.h>
|
---|
41 | #endif
|
---|
42 | #include <net/if.h>
|
---|
43 | #include <net/if_arp.h>
|
---|
44 | #include <net/if_dl.h>
|
---|
45 | #include <net/if_media.h>
|
---|
46 | #include <net/if_types.h>
|
---|
47 |
|
---|
48 | #include <netinet/in.h>
|
---|
49 | #include <netinet/in_systm.h>
|
---|
50 | #include <netinet/in_var.h>
|
---|
51 | #include <netinet/if_ether.h>
|
---|
52 | #include <netinet/ip.h>
|
---|
53 |
|
---|
54 | #include <net80211/ieee80211_var.h>
|
---|
55 | #include <net80211/ieee80211_radiotap.h>
|
---|
56 |
|
---|
57 | #include <dev/usb/usb.h>
|
---|
58 | #include <dev/usb/usbdi.h>
|
---|
59 | #include <dev/usb/usbdi_util.h>
|
---|
60 | #include <dev/usb/usbdevs.h>
|
---|
61 |
|
---|
62 | #include <dev/usb/if_urtwnreg.h>
|
---|
63 |
|
---|
64 | #ifdef USB_DEBUG
|
---|
65 | #define URTWN_DEBUG
|
---|
66 | #endif
|
---|
67 |
|
---|
68 | #ifdef URTWN_DEBUG
|
---|
69 | #define DPRINTF(x) do { if (urtwn_debug) printf x; } while (0)
|
---|
70 | #define DPRINTFN(n, x) do { if (urtwn_debug >= (n)) printf x; } while (0)
|
---|
71 | int urtwn_debug = 4;
|
---|
72 | #else
|
---|
73 | #define DPRINTF(x)
|
---|
74 | #define DPRINTFN(n, x)
|
---|
75 | #endif
|
---|
76 |
|
---|
77 | static const struct usb_devno urtwn_devs[] = {
|
---|
78 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8188CU_1 },
|
---|
79 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8188CU_2 },
|
---|
80 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8192CU },
|
---|
81 | { USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RTL8192CU },
|
---|
82 | { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8188CE_1 },
|
---|
83 | { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8188CE_2 },
|
---|
84 | { USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RTL8188CU },
|
---|
85 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F7D2102 },
|
---|
86 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8188CU },
|
---|
87 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8192CU },
|
---|
88 | { USB_VENDOR_CHICONY, USB_PRODUCT_CHICONY_RTL8188CUS_1 },
|
---|
89 | { USB_VENDOR_CHICONY, USB_PRODUCT_CHICONY_RTL8188CUS_2 },
|
---|
90 | { USB_VENDOR_CHICONY, USB_PRODUCT_CHICONY_RTL8188CUS_3 },
|
---|
91 | { USB_VENDOR_CHICONY, USB_PRODUCT_CHICONY_RTL8188CUS_4 },
|
---|
92 | { USB_VENDOR_CHICONY, USB_PRODUCT_CHICONY_RTL8188CUS_5 },
|
---|
93 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RTL8192CU },
|
---|
94 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8188CU },
|
---|
95 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8192CU_1 },
|
---|
96 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8192CU_2 },
|
---|
97 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8192CU_3 },
|
---|
98 | { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RTL8188CU },
|
---|
99 | { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RTL8192CU },
|
---|
100 | { USB_VENDOR_FEIXUN, USB_PRODUCT_FEIXUN_RTL8188CU },
|
---|
101 | { USB_VENDOR_FEIXUN, USB_PRODUCT_FEIXUN_RTL8192CU },
|
---|
102 | { USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWNUP150 },
|
---|
103 | { USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RTL8192CU },
|
---|
104 | { USB_VENDOR_HP3, USB_PRODUCT_HP3_RTL8188CU },
|
---|
105 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WNA1000M },
|
---|
106 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_RTL8192CU },
|
---|
107 | { USB_VENDOR_NETGEAR4, USB_PRODUCT_NETGEAR4_RTL8188CU },
|
---|
108 | { USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_RTL8188CU },
|
---|
109 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8188CU_1 },
|
---|
110 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8188CU_2 },
|
---|
111 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8188CU_3 },
|
---|
112 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8188CU_4 },
|
---|
113 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8188CUS },
|
---|
114 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RTL8192CU },
|
---|
115 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CE_0 },
|
---|
116 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CE_1 },
|
---|
117 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CTV },
|
---|
118 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CU_0 },
|
---|
119 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CU_1 },
|
---|
120 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CU_2 },
|
---|
121 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CU_COMBO },
|
---|
122 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188CUS },
|
---|
123 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188RU },
|
---|
124 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8188RU_2 },
|
---|
125 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8191CU },
|
---|
126 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8192CE },
|
---|
127 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8192CU },
|
---|
128 | { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RTL8188CU },
|
---|
129 | { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RTL8188CU_2 },
|
---|
130 | { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RTL8192CU },
|
---|
131 | { USB_VENDOR_TRENDNET, USB_PRODUCT_TRENDNET_RTL8188CU },
|
---|
132 | { USB_VENDOR_TRENDNET, USB_PRODUCT_TRENDNET_RTL8192CU },
|
---|
133 | { USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_RTL8192CU }
|
---|
134 | };
|
---|
135 |
|
---|
136 | int urtwn_match(struct device *, void *, void *);
|
---|
137 | void urtwn_attach(struct device *, struct device *, void *);
|
---|
138 | int urtwn_detach(struct device *, int);
|
---|
139 | int urtwn_activate(struct device *, int);
|
---|
140 | int urtwn_open_pipes(struct urtwn_softc *);
|
---|
141 | void urtwn_close_pipes(struct urtwn_softc *);
|
---|
142 | int urtwn_alloc_rx_list(struct urtwn_softc *);
|
---|
143 | void urtwn_free_rx_list(struct urtwn_softc *);
|
---|
144 | int urtwn_alloc_tx_list(struct urtwn_softc *);
|
---|
145 | void urtwn_free_tx_list(struct urtwn_softc *);
|
---|
146 | void urtwn_task(void *);
|
---|
147 | void urtwn_do_async(struct urtwn_softc *,
|
---|
148 | void (*)(struct urtwn_softc *, void *), void *, int);
|
---|
149 | void urtwn_wait_async(struct urtwn_softc *);
|
---|
150 | int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *,
|
---|
151 | int);
|
---|
152 | void urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t);
|
---|
153 | void urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t);
|
---|
154 | void urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t);
|
---|
155 | int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *,
|
---|
156 | int);
|
---|
157 | uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t);
|
---|
158 | uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t);
|
---|
159 | uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t);
|
---|
160 | int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, const void *, int);
|
---|
161 | void urtwn_rf_write(struct urtwn_softc *, int, uint8_t, uint32_t);
|
---|
162 | uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t);
|
---|
163 | void urtwn_cam_write(struct urtwn_softc *, uint32_t, uint32_t);
|
---|
164 | int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t);
|
---|
165 | uint8_t urtwn_efuse_read_1(struct urtwn_softc *, uint16_t);
|
---|
166 | void urtwn_efuse_read(struct urtwn_softc *);
|
---|
167 | int urtwn_read_chipid(struct urtwn_softc *);
|
---|
168 | void urtwn_read_rom(struct urtwn_softc *);
|
---|
169 | int urtwn_media_change(struct ifnet *);
|
---|
170 | int urtwn_ra_init(struct urtwn_softc *);
|
---|
171 | void urtwn_tsf_sync_enable(struct urtwn_softc *);
|
---|
172 | void urtwn_set_led(struct urtwn_softc *, int, int);
|
---|
173 | void urtwn_calib_to(void *);
|
---|
174 | void urtwn_calib_cb(struct urtwn_softc *, void *);
|
---|
175 | void urtwn_next_scan(void *);
|
---|
176 | int urtwn_newstate(struct ieee80211com *, enum ieee80211_state,
|
---|
177 | int);
|
---|
178 | void urtwn_newstate_cb(struct urtwn_softc *, void *);
|
---|
179 | void urtwn_updateedca(struct ieee80211com *);
|
---|
180 | void urtwn_updateedca_cb(struct urtwn_softc *, void *);
|
---|
181 | int urtwn_set_key(struct ieee80211com *, struct ieee80211_node *,
|
---|
182 | struct ieee80211_key *);
|
---|
183 | void urtwn_set_key_cb(struct urtwn_softc *, void *);
|
---|
184 | void urtwn_delete_key(struct ieee80211com *,
|
---|
185 | struct ieee80211_node *, struct ieee80211_key *);
|
---|
186 | void urtwn_delete_key_cb(struct urtwn_softc *, void *);
|
---|
187 | void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t);
|
---|
188 | int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *);
|
---|
189 | void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int);
|
---|
190 | void urtwn_rxeof(usbd_xfer_handle, usbd_private_handle,
|
---|
191 | usbd_status);
|
---|
192 | void urtwn_txeof(usbd_xfer_handle, usbd_private_handle,
|
---|
193 | usbd_status);
|
---|
194 | int urtwn_tx(struct urtwn_softc *, struct mbuf *,
|
---|
195 | struct ieee80211_node *);
|
---|
196 | void urtwn_start(struct ifnet *);
|
---|
197 | void urtwn_watchdog(struct ifnet *);
|
---|
198 | int urtwn_ioctl(struct ifnet *, u_long, caddr_t);
|
---|
199 | int urtwn_power_on(struct urtwn_softc *);
|
---|
200 | int urtwn_llt_init(struct urtwn_softc *);
|
---|
201 | void urtwn_fw_reset(struct urtwn_softc *);
|
---|
202 | int urtwn_fw_loadpage(struct urtwn_softc *, int, uint8_t *, int);
|
---|
203 | int urtwn_load_firmware(struct urtwn_softc *);
|
---|
204 | int urtwn_dma_init(struct urtwn_softc *);
|
---|
205 | void urtwn_mac_init(struct urtwn_softc *);
|
---|
206 | void urtwn_bb_init(struct urtwn_softc *);
|
---|
207 | void urtwn_rf_init(struct urtwn_softc *);
|
---|
208 | void urtwn_cam_init(struct urtwn_softc *);
|
---|
209 | void urtwn_pa_bias_init(struct urtwn_softc *);
|
---|
210 | void urtwn_rxfilter_init(struct urtwn_softc *);
|
---|
211 | void urtwn_edca_init(struct urtwn_softc *);
|
---|
212 | void urtwn_write_txpower(struct urtwn_softc *, int, uint16_t[]);
|
---|
213 | void urtwn_get_txpower(struct urtwn_softc *, int,
|
---|
214 | struct ieee80211_channel *, struct ieee80211_channel *,
|
---|
215 | uint16_t[]);
|
---|
216 | void urtwn_set_txpower(struct urtwn_softc *,
|
---|
217 | struct ieee80211_channel *, struct ieee80211_channel *);
|
---|
218 | void urtwn_set_chan(struct urtwn_softc *,
|
---|
219 | struct ieee80211_channel *, struct ieee80211_channel *);
|
---|
220 | int urtwn_iq_calib_chain(struct urtwn_softc *, int, uint16_t[],
|
---|
221 | uint16_t[]);
|
---|
222 | void urtwn_iq_calib(struct urtwn_softc *);
|
---|
223 | void urtwn_lc_calib(struct urtwn_softc *);
|
---|
224 | void urtwn_temp_calib(struct urtwn_softc *);
|
---|
225 | int urtwn_init(struct ifnet *);
|
---|
226 | void urtwn_stop(struct ifnet *);
|
---|
227 |
|
---|
228 | /* Aliases. */
|
---|
229 | #define urtwn_bb_write urtwn_write_4
|
---|
230 | #define urtwn_bb_read urtwn_read_4
|
---|
231 |
|
---|
232 | struct cfdriver urtwn_cd = {
|
---|
233 | NULL, "urtwn", DV_IFNET
|
---|
234 | };
|
---|
235 |
|
---|
236 | const struct cfattach urtwn_ca = {
|
---|
237 | sizeof(struct urtwn_softc),
|
---|
238 | urtwn_match,
|
---|
239 | urtwn_attach,
|
---|
240 | urtwn_detach,
|
---|
241 | urtwn_activate
|
---|
242 | };
|
---|
243 |
|
---|
244 | int
|
---|
245 | urtwn_match(struct device *parent, void *match, void *aux)
|
---|
246 | {
|
---|
247 | struct usb_attach_arg *uaa = aux;
|
---|
248 |
|
---|
249 | if (uaa->iface != NULL)
|
---|
250 | return (UMATCH_NONE);
|
---|
251 |
|
---|
252 | return ((usb_lookup(urtwn_devs, uaa->vendor, uaa->product) != NULL) ?
|
---|
253 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
|
---|
254 | }
|
---|
255 |
|
---|
256 | void
|
---|
257 | urtwn_attach(struct device *parent, struct device *self, void *aux)
|
---|
258 | {
|
---|
259 | struct urtwn_softc *sc = (struct urtwn_softc *)self;
|
---|
260 | struct usb_attach_arg *uaa = aux;
|
---|
261 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
262 | struct ifnet *ifp = &ic->ic_if;
|
---|
263 | int i, error;
|
---|
264 |
|
---|
265 | sc->sc_udev = uaa->device;
|
---|
266 |
|
---|
267 | usb_init_task(&sc->sc_task, urtwn_task, sc, USB_TASK_TYPE_GENERIC);
|
---|
268 | timeout_set(&sc->scan_to, urtwn_next_scan, sc);
|
---|
269 | timeout_set(&sc->calib_to, urtwn_calib_to, sc);
|
---|
270 |
|
---|
271 | if (usbd_set_config_no(sc->sc_udev, 1, 0) != 0) {
|
---|
272 | printf("%s: could not set configuration no\n",
|
---|
273 | sc->sc_dev.dv_xname);
|
---|
274 | return;
|
---|
275 | }
|
---|
276 |
|
---|
277 | /* Get the first interface handle. */
|
---|
278 | error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
|
---|
279 | if (error != 0) {
|
---|
280 | printf("%s: could not get interface handle\n",
|
---|
281 | sc->sc_dev.dv_xname);
|
---|
282 | return;
|
---|
283 | }
|
---|
284 |
|
---|
285 | error = urtwn_read_chipid(sc);
|
---|
286 | if (error != 0) {
|
---|
287 | printf("%s: unsupported test chip\n", sc->sc_dev.dv_xname);
|
---|
288 | return;
|
---|
289 | }
|
---|
290 |
|
---|
291 | /* Determine number of Tx/Rx chains. */
|
---|
292 | if (sc->chip & URTWN_CHIP_92C) {
|
---|
293 | sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2;
|
---|
294 | sc->nrxchains = 2;
|
---|
295 | } else {
|
---|
296 | sc->ntxchains = 1;
|
---|
297 | sc->nrxchains = 1;
|
---|
298 | }
|
---|
299 | urtwn_read_rom(sc);
|
---|
300 |
|
---|
301 | printf("%s: MAC/BB RTL%s, RF 6052 %dT%dR, address %s\n",
|
---|
302 | sc->sc_dev.dv_xname,
|
---|
303 | (sc->chip & URTWN_CHIP_92C) ? "8192CU" :
|
---|
304 | (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" :
|
---|
305 | (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" :
|
---|
306 | "8188CUS", sc->ntxchains, sc->nrxchains,
|
---|
307 | ether_sprintf(ic->ic_myaddr));
|
---|
308 |
|
---|
309 | if (urtwn_open_pipes(sc) != 0)
|
---|
310 | return;
|
---|
311 |
|
---|
312 | ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */
|
---|
313 | ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */
|
---|
314 | ic->ic_state = IEEE80211_S_INIT;
|
---|
315 |
|
---|
316 | /* Set device capabilities. */
|
---|
317 | ic->ic_caps =
|
---|
318 | IEEE80211_C_MONITOR | /* Monitor mode supported. */
|
---|
319 | IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
|
---|
320 | IEEE80211_C_SHSLOT | /* Short slot time supported. */
|
---|
321 | IEEE80211_C_WEP | /* WEP. */
|
---|
322 | IEEE80211_C_RSN; /* WPA/RSN. */
|
---|
323 |
|
---|
324 | #ifndef IEEE80211_NO_HT
|
---|
325 | /* Set HT capabilities. */
|
---|
326 | ic->ic_htcaps =
|
---|
327 | IEEE80211_HTCAP_CBW20_40 |
|
---|
328 | IEEE80211_HTCAP_DSSSCCK40;
|
---|
329 | /* Set supported HT rates. */
|
---|
330 | for (i = 0; i < sc->nrxchains; i++)
|
---|
331 | ic->ic_sup_mcs[i] = 0xff;
|
---|
332 | #endif
|
---|
333 |
|
---|
334 | /* Set supported .11b and .11g rates. */
|
---|
335 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
|
---|
336 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
|
---|
337 |
|
---|
338 | /* Set supported .11b and .11g channels (1 through 14). */
|
---|
339 | for (i = 1; i <= 14; i++) {
|
---|
340 | ic->ic_channels[i].ic_freq =
|
---|
341 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
|
---|
342 | ic->ic_channels[i].ic_flags =
|
---|
343 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
|
---|
344 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
|
---|
345 | }
|
---|
346 | /*
|
---|
347 | * The number of STAs that we can support is limited by the number
|
---|
348 | * of CAM entries used for hardware crypto.
|
---|
349 | */
|
---|
350 | ic->ic_max_nnodes = R92C_CAM_ENTRY_COUNT - 4;
|
---|
351 | if (ic->ic_max_nnodes > IEEE80211_CACHE_SIZE)
|
---|
352 | ic->ic_max_nnodes = IEEE80211_CACHE_SIZE;
|
---|
353 |
|
---|
354 | ifp->if_softc = sc;
|
---|
355 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
---|
356 | ifp->if_ioctl = urtwn_ioctl;
|
---|
357 | ifp->if_start = urtwn_start;
|
---|
358 | ifp->if_watchdog = urtwn_watchdog;
|
---|
359 | IFQ_SET_READY(&ifp->if_snd);
|
---|
360 | memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
|
---|
361 |
|
---|
362 | if_attach(ifp);
|
---|
363 | ieee80211_ifattach(ifp);
|
---|
364 | ic->ic_updateedca = urtwn_updateedca;
|
---|
365 | #ifdef notyet
|
---|
366 | ic->ic_set_key = urtwn_set_key;
|
---|
367 | ic->ic_delete_key = urtwn_delete_key;
|
---|
368 | #endif
|
---|
369 | /* Override state transition machine. */
|
---|
370 | sc->sc_newstate = ic->ic_newstate;
|
---|
371 | ic->ic_newstate = urtwn_newstate;
|
---|
372 | ieee80211_media_init(ifp, urtwn_media_change, ieee80211_media_status);
|
---|
373 |
|
---|
374 | #if NBPFILTER > 0
|
---|
375 | bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
|
---|
376 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
|
---|
377 |
|
---|
378 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
|
---|
379 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
|
---|
380 | sc->sc_rxtap.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT);
|
---|
381 |
|
---|
382 | sc->sc_txtap_len = sizeof(sc->sc_txtapu);
|
---|
383 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
|
---|
384 | sc->sc_txtap.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT);
|
---|
385 | #endif
|
---|
386 | }
|
---|
387 |
|
---|
388 | int
|
---|
389 | urtwn_detach(struct device *self, int flags)
|
---|
390 | {
|
---|
391 | struct urtwn_softc *sc = (struct urtwn_softc *)self;
|
---|
392 | struct ifnet *ifp = &sc->sc_ic.ic_if;
|
---|
393 | int s;
|
---|
394 |
|
---|
395 | s = splusb();
|
---|
396 |
|
---|
397 | if (timeout_initialized(&sc->scan_to))
|
---|
398 | timeout_del(&sc->scan_to);
|
---|
399 | if (timeout_initialized(&sc->calib_to))
|
---|
400 | timeout_del(&sc->calib_to);
|
---|
401 |
|
---|
402 | /* Wait for all async commands to complete. */
|
---|
403 | usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
|
---|
404 |
|
---|
405 | usbd_ref_wait(sc->sc_udev);
|
---|
406 |
|
---|
407 | if (ifp->if_softc != NULL) {
|
---|
408 | ieee80211_ifdetach(ifp);
|
---|
409 | if_detach(ifp);
|
---|
410 | }
|
---|
411 |
|
---|
412 | /* Abort and close Tx/Rx pipes. */
|
---|
413 | urtwn_close_pipes(sc);
|
---|
414 |
|
---|
415 | /* Free Tx/Rx buffers. */
|
---|
416 | urtwn_free_tx_list(sc);
|
---|
417 | urtwn_free_rx_list(sc);
|
---|
418 | splx(s);
|
---|
419 |
|
---|
420 | return (0);
|
---|
421 | }
|
---|
422 |
|
---|
423 | int
|
---|
424 | urtwn_activate(struct device *self, int act)
|
---|
425 | {
|
---|
426 | struct urtwn_softc *sc = (struct urtwn_softc *)self;
|
---|
427 |
|
---|
428 | switch (act) {
|
---|
429 | case DVACT_DEACTIVATE:
|
---|
430 | usbd_deactivate(sc->sc_udev);
|
---|
431 | break;
|
---|
432 | }
|
---|
433 | return (0);
|
---|
434 | }
|
---|
435 |
|
---|
436 | int
|
---|
437 | urtwn_open_pipes(struct urtwn_softc *sc)
|
---|
438 | {
|
---|
439 | /* Bulk-out endpoints addresses (from highest to lowest prio). */
|
---|
440 | const uint8_t epaddr[] = { 0x02, 0x03, 0x05 };
|
---|
441 | usb_interface_descriptor_t *id;
|
---|
442 | usb_endpoint_descriptor_t *ed;
|
---|
443 | int i, ntx = 0, error;
|
---|
444 |
|
---|
445 | /* Determine the number of bulk-out pipes. */
|
---|
446 | id = usbd_get_interface_descriptor(sc->sc_iface);
|
---|
447 | for (i = 0; i < id->bNumEndpoints; i++) {
|
---|
448 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
|
---|
449 | if (ed != NULL &&
|
---|
450 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
|
---|
451 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
|
---|
452 | ntx++;
|
---|
453 | }
|
---|
454 | DPRINTF(("found %d bulk-out pipes\n", ntx));
|
---|
455 | if (ntx == 0 || ntx > R92C_MAX_EPOUT) {
|
---|
456 | printf("%s: %d: invalid number of Tx bulk pipes\n",
|
---|
457 | sc->sc_dev.dv_xname, ntx);
|
---|
458 | return (EIO);
|
---|
459 | }
|
---|
460 |
|
---|
461 | /* Open bulk-in pipe at address 0x81. */
|
---|
462 | error = usbd_open_pipe(sc->sc_iface, 0x81, 0, &sc->rx_pipe);
|
---|
463 | if (error != 0) {
|
---|
464 | printf("%s: could not open Rx bulk pipe\n",
|
---|
465 | sc->sc_dev.dv_xname);
|
---|
466 | goto fail;
|
---|
467 | }
|
---|
468 |
|
---|
469 | /* Open bulk-out pipes (up to 3). */
|
---|
470 | for (i = 0; i < ntx; i++) {
|
---|
471 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], 0,
|
---|
472 | &sc->tx_pipe[i]);
|
---|
473 | if (error != 0) {
|
---|
474 | printf("%s: could not open Tx bulk pipe 0x%02x\n",
|
---|
475 | sc->sc_dev.dv_xname, epaddr[i]);
|
---|
476 | goto fail;
|
---|
477 | }
|
---|
478 | }
|
---|
479 |
|
---|
480 | /* Map 802.11 access categories to USB pipes. */
|
---|
481 | sc->ac2idx[EDCA_AC_BK] =
|
---|
482 | sc->ac2idx[EDCA_AC_BE] = (ntx == 3) ? 2 : ((ntx == 2) ? 1 : 0);
|
---|
483 | sc->ac2idx[EDCA_AC_VI] = (ntx == 3) ? 1 : 0;
|
---|
484 | sc->ac2idx[EDCA_AC_VO] = 0; /* Always use highest prio. */
|
---|
485 |
|
---|
486 | if (error != 0)
|
---|
487 | fail: urtwn_close_pipes(sc);
|
---|
488 | return (error);
|
---|
489 | }
|
---|
490 |
|
---|
491 | void
|
---|
492 | urtwn_close_pipes(struct urtwn_softc *sc)
|
---|
493 | {
|
---|
494 | int i;
|
---|
495 |
|
---|
496 | /* Close Rx pipe. */
|
---|
497 | if (sc->rx_pipe != NULL) {
|
---|
498 | usbd_abort_pipe(sc->rx_pipe);
|
---|
499 | usbd_close_pipe(sc->rx_pipe);
|
---|
500 | }
|
---|
501 | /* Close Tx pipes. */
|
---|
502 | for (i = 0; i < R92C_MAX_EPOUT; i++) {
|
---|
503 | if (sc->tx_pipe[i] == NULL)
|
---|
504 | continue;
|
---|
505 | usbd_abort_pipe(sc->tx_pipe[i]);
|
---|
506 | usbd_close_pipe(sc->tx_pipe[i]);
|
---|
507 | }
|
---|
508 | }
|
---|
509 |
|
---|
510 | int
|
---|
511 | urtwn_alloc_rx_list(struct urtwn_softc *sc)
|
---|
512 | {
|
---|
513 | struct urtwn_rx_data *data;
|
---|
514 | int i, error = 0;
|
---|
515 |
|
---|
516 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) {
|
---|
517 | data = &sc->rx_data[i];
|
---|
518 |
|
---|
519 | data->sc = sc; /* Backpointer for callbacks. */
|
---|
520 |
|
---|
521 | data->xfer = usbd_alloc_xfer(sc->sc_udev);
|
---|
522 | if (data->xfer == NULL) {
|
---|
523 | printf("%s: could not allocate xfer\n",
|
---|
524 | sc->sc_dev.dv_xname);
|
---|
525 | error = ENOMEM;
|
---|
526 | break;
|
---|
527 | }
|
---|
528 | data->buf = usbd_alloc_buffer(data->xfer, URTWN_RXBUFSZ);
|
---|
529 | if (data->buf == NULL) {
|
---|
530 | printf("%s: could not allocate xfer buffer\n",
|
---|
531 | sc->sc_dev.dv_xname);
|
---|
532 | error = ENOMEM;
|
---|
533 | break;
|
---|
534 | }
|
---|
535 | }
|
---|
536 | if (error != 0)
|
---|
537 | urtwn_free_rx_list(sc);
|
---|
538 | return (error);
|
---|
539 | }
|
---|
540 |
|
---|
541 | void
|
---|
542 | urtwn_free_rx_list(struct urtwn_softc *sc)
|
---|
543 | {
|
---|
544 | int i;
|
---|
545 |
|
---|
546 | /* NB: Caller must abort pipe first. */
|
---|
547 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) {
|
---|
548 | if (sc->rx_data[i].xfer != NULL)
|
---|
549 | usbd_free_xfer(sc->rx_data[i].xfer);
|
---|
550 | sc->rx_data[i].xfer = NULL;
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 | int
|
---|
555 | urtwn_alloc_tx_list(struct urtwn_softc *sc)
|
---|
556 | {
|
---|
557 | struct urtwn_tx_data *data;
|
---|
558 | int i, error = 0;
|
---|
559 |
|
---|
560 | TAILQ_INIT(&sc->tx_free_list);
|
---|
561 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) {
|
---|
562 | data = &sc->tx_data[i];
|
---|
563 |
|
---|
564 | data->sc = sc; /* Backpointer for callbacks. */
|
---|
565 |
|
---|
566 | data->xfer = usbd_alloc_xfer(sc->sc_udev);
|
---|
567 | if (data->xfer == NULL) {
|
---|
568 | printf("%s: could not allocate xfer\n",
|
---|
569 | sc->sc_dev.dv_xname);
|
---|
570 | error = ENOMEM;
|
---|
571 | break;
|
---|
572 | }
|
---|
573 | data->buf = usbd_alloc_buffer(data->xfer, URTWN_TXBUFSZ);
|
---|
574 | if (data->buf == NULL) {
|
---|
575 | printf("%s: could not allocate xfer buffer\n",
|
---|
576 | sc->sc_dev.dv_xname);
|
---|
577 | error = ENOMEM;
|
---|
578 | break;
|
---|
579 | }
|
---|
580 | /* Append this Tx buffer to our free list. */
|
---|
581 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
|
---|
582 | }
|
---|
583 | if (error != 0)
|
---|
584 | urtwn_free_tx_list(sc);
|
---|
585 | return (error);
|
---|
586 | }
|
---|
587 |
|
---|
588 | void
|
---|
589 | urtwn_free_tx_list(struct urtwn_softc *sc)
|
---|
590 | {
|
---|
591 | int i;
|
---|
592 |
|
---|
593 | /* NB: Caller must abort pipe first. */
|
---|
594 | for (i = 0; i < URTWN_TX_LIST_COUNT; i++) {
|
---|
595 | if (sc->tx_data[i].xfer != NULL)
|
---|
596 | usbd_free_xfer(sc->tx_data[i].xfer);
|
---|
597 | sc->tx_data[i].xfer = NULL;
|
---|
598 | }
|
---|
599 | }
|
---|
600 |
|
---|
601 | void
|
---|
602 | urtwn_task(void *arg)
|
---|
603 | {
|
---|
604 | struct urtwn_softc *sc = arg;
|
---|
605 | struct urtwn_host_cmd_ring *ring = &sc->cmdq;
|
---|
606 | struct urtwn_host_cmd *cmd;
|
---|
607 | int s;
|
---|
608 |
|
---|
609 | /* Process host commands. */
|
---|
610 | s = splusb();
|
---|
611 | while (ring->next != ring->cur) {
|
---|
612 | cmd = &ring->cmd[ring->next];
|
---|
613 | splx(s);
|
---|
614 | /* Invoke callback. */
|
---|
615 | cmd->cb(sc, cmd->data);
|
---|
616 | s = splusb();
|
---|
617 | ring->queued--;
|
---|
618 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT;
|
---|
619 | }
|
---|
620 | splx(s);
|
---|
621 | }
|
---|
622 |
|
---|
623 | void
|
---|
624 | urtwn_do_async(struct urtwn_softc *sc,
|
---|
625 | void (*cb)(struct urtwn_softc *, void *), void *arg, int len)
|
---|
626 | {
|
---|
627 | struct urtwn_host_cmd_ring *ring = &sc->cmdq;
|
---|
628 | struct urtwn_host_cmd *cmd;
|
---|
629 | int s;
|
---|
630 |
|
---|
631 | s = splusb();
|
---|
632 | cmd = &ring->cmd[ring->cur];
|
---|
633 | cmd->cb = cb;
|
---|
634 | KASSERT(len <= sizeof(cmd->data));
|
---|
635 | memcpy(cmd->data, arg, len);
|
---|
636 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT;
|
---|
637 |
|
---|
638 | /* If there is no pending command already, schedule a task. */
|
---|
639 | if (++ring->queued == 1)
|
---|
640 | usb_add_task(sc->sc_udev, &sc->sc_task);
|
---|
641 | splx(s);
|
---|
642 | }
|
---|
643 |
|
---|
644 | void
|
---|
645 | urtwn_wait_async(struct urtwn_softc *sc)
|
---|
646 | {
|
---|
647 | /* Wait for all queued asynchronous commands to complete. */
|
---|
648 | usb_wait_task(sc->sc_udev, &sc->sc_task);
|
---|
649 | }
|
---|
650 |
|
---|
651 | int
|
---|
652 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf,
|
---|
653 | int len)
|
---|
654 | {
|
---|
655 | usb_device_request_t req;
|
---|
656 |
|
---|
657 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
|
---|
658 | req.bRequest = R92C_REQ_REGS;
|
---|
659 | USETW(req.wValue, addr);
|
---|
660 | USETW(req.wIndex, 0);
|
---|
661 | USETW(req.wLength, len);
|
---|
662 | return (usbd_do_request(sc->sc_udev, &req, buf));
|
---|
663 | }
|
---|
664 |
|
---|
665 | void
|
---|
666 | urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val)
|
---|
667 | {
|
---|
668 | urtwn_write_region_1(sc, addr, &val, 1);
|
---|
669 | }
|
---|
670 |
|
---|
671 | void
|
---|
672 | urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val)
|
---|
673 | {
|
---|
674 | val = htole16(val);
|
---|
675 | urtwn_write_region_1(sc, addr, (uint8_t *)&val, 2);
|
---|
676 | }
|
---|
677 |
|
---|
678 | void
|
---|
679 | urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val)
|
---|
680 | {
|
---|
681 | val = htole32(val);
|
---|
682 | urtwn_write_region_1(sc, addr, (uint8_t *)&val, 4);
|
---|
683 | }
|
---|
684 |
|
---|
685 | int
|
---|
686 | urtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf,
|
---|
687 | int len)
|
---|
688 | {
|
---|
689 | usb_device_request_t req;
|
---|
690 |
|
---|
691 | req.bmRequestType = UT_READ_VENDOR_DEVICE;
|
---|
692 | req.bRequest = R92C_REQ_REGS;
|
---|
693 | USETW(req.wValue, addr);
|
---|
694 | USETW(req.wIndex, 0);
|
---|
695 | USETW(req.wLength, len);
|
---|
696 | return (usbd_do_request(sc->sc_udev, &req, buf));
|
---|
697 | }
|
---|
698 |
|
---|
699 | uint8_t
|
---|
700 | urtwn_read_1(struct urtwn_softc *sc, uint16_t addr)
|
---|
701 | {
|
---|
702 | uint8_t val;
|
---|
703 |
|
---|
704 | if (urtwn_read_region_1(sc, addr, &val, 1) != 0)
|
---|
705 | return (0xff);
|
---|
706 | return (val);
|
---|
707 | }
|
---|
708 |
|
---|
709 | uint16_t
|
---|
710 | urtwn_read_2(struct urtwn_softc *sc, uint16_t addr)
|
---|
711 | {
|
---|
712 | uint16_t val;
|
---|
713 |
|
---|
714 | if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
|
---|
715 | return (0xffff);
|
---|
716 | return (letoh16(val));
|
---|
717 | }
|
---|
718 |
|
---|
719 | uint32_t
|
---|
720 | urtwn_read_4(struct urtwn_softc *sc, uint16_t addr)
|
---|
721 | {
|
---|
722 | uint32_t val;
|
---|
723 |
|
---|
724 | if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
|
---|
725 | return (0xffffffff);
|
---|
726 | return (letoh32(val));
|
---|
727 | }
|
---|
728 |
|
---|
729 | int
|
---|
730 | urtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len)
|
---|
731 | {
|
---|
732 | struct r92c_fw_cmd cmd;
|
---|
733 | int ntries;
|
---|
734 |
|
---|
735 | /* Wait for current FW box to be empty. */
|
---|
736 | for (ntries = 0; ntries < 100; ntries++) {
|
---|
737 | if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
|
---|
738 | break;
|
---|
739 | DELAY(1);
|
---|
740 | }
|
---|
741 | if (ntries == 100) {
|
---|
742 | printf("%s: could not send firmware command %d\n",
|
---|
743 | sc->sc_dev.dv_xname, id);
|
---|
744 | return (ETIMEDOUT);
|
---|
745 | }
|
---|
746 | memset(&cmd, 0, sizeof(cmd));
|
---|
747 | cmd.id = id;
|
---|
748 | if (len > 3)
|
---|
749 | cmd.id |= R92C_CMD_FLAG_EXT;
|
---|
750 | KASSERT(len <= sizeof(cmd.msg));
|
---|
751 | memcpy(cmd.msg, buf, len);
|
---|
752 |
|
---|
753 | /* Write the first word last since that will trigger the FW. */
|
---|
754 | urtwn_write_region_1(sc, R92C_HMEBOX_EXT(sc->fwcur),
|
---|
755 | (uint8_t *)&cmd + 4, 2);
|
---|
756 | urtwn_write_region_1(sc, R92C_HMEBOX(sc->fwcur),
|
---|
757 | (uint8_t *)&cmd + 0, 4);
|
---|
758 |
|
---|
759 | sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
|
---|
760 | return (0);
|
---|
761 | }
|
---|
762 |
|
---|
763 | void
|
---|
764 | urtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
|
---|
765 | {
|
---|
766 | urtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
|
---|
767 | SM(R92C_LSSI_PARAM_ADDR, addr) |
|
---|
768 | SM(R92C_LSSI_PARAM_DATA, val));
|
---|
769 | }
|
---|
770 |
|
---|
771 | uint32_t
|
---|
772 | urtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr)
|
---|
773 | {
|
---|
774 | uint32_t reg[R92C_MAX_CHAINS], val;
|
---|
775 |
|
---|
776 | reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
|
---|
777 | if (chain != 0)
|
---|
778 | reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
|
---|
779 |
|
---|
780 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
|
---|
781 | reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
|
---|
782 | DELAY(1000);
|
---|
783 |
|
---|
784 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
|
---|
785 | RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
|
---|
786 | R92C_HSSI_PARAM2_READ_EDGE);
|
---|
787 | DELAY(1000);
|
---|
788 |
|
---|
789 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
|
---|
790 | reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
|
---|
791 | DELAY(1000);
|
---|
792 |
|
---|
793 | if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
|
---|
794 | val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
|
---|
795 | else
|
---|
796 | val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
|
---|
797 | return (MS(val, R92C_LSSI_READBACK_DATA));
|
---|
798 | }
|
---|
799 |
|
---|
800 | void
|
---|
801 | urtwn_cam_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data)
|
---|
802 | {
|
---|
803 | urtwn_write_4(sc, R92C_CAMWRITE, data);
|
---|
804 | urtwn_write_4(sc, R92C_CAMCMD,
|
---|
805 | R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
|
---|
806 | SM(R92C_CAMCMD_ADDR, addr));
|
---|
807 | }
|
---|
808 |
|
---|
809 | int
|
---|
810 | urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data)
|
---|
811 | {
|
---|
812 | int ntries;
|
---|
813 |
|
---|
814 | urtwn_write_4(sc, R92C_LLT_INIT,
|
---|
815 | SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
|
---|
816 | SM(R92C_LLT_INIT_ADDR, addr) |
|
---|
817 | SM(R92C_LLT_INIT_DATA, data));
|
---|
818 | /* Wait for write operation to complete. */
|
---|
819 | for (ntries = 0; ntries < 20; ntries++) {
|
---|
820 | if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
|
---|
821 | R92C_LLT_INIT_OP_NO_ACTIVE)
|
---|
822 | return (0);
|
---|
823 | DELAY(5);
|
---|
824 | }
|
---|
825 | return (ETIMEDOUT);
|
---|
826 | }
|
---|
827 |
|
---|
828 | uint8_t
|
---|
829 | urtwn_efuse_read_1(struct urtwn_softc *sc, uint16_t addr)
|
---|
830 | {
|
---|
831 | uint32_t reg;
|
---|
832 | int ntries;
|
---|
833 |
|
---|
834 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL);
|
---|
835 | reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr);
|
---|
836 | reg &= ~R92C_EFUSE_CTRL_VALID;
|
---|
837 | urtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
|
---|
838 | /* Wait for read operation to complete. */
|
---|
839 | for (ntries = 0; ntries < 100; ntries++) {
|
---|
840 | reg = urtwn_read_4(sc, R92C_EFUSE_CTRL);
|
---|
841 | if (reg & R92C_EFUSE_CTRL_VALID)
|
---|
842 | return (MS(reg, R92C_EFUSE_CTRL_DATA));
|
---|
843 | DELAY(5);
|
---|
844 | }
|
---|
845 | printf("%s: could not read efuse byte at address 0x%x\n",
|
---|
846 | sc->sc_dev.dv_xname, addr);
|
---|
847 | return (0xff);
|
---|
848 | }
|
---|
849 |
|
---|
850 | void
|
---|
851 | urtwn_efuse_read(struct urtwn_softc *sc)
|
---|
852 | {
|
---|
853 | uint8_t *rom = (uint8_t *)&sc->rom;
|
---|
854 | uint16_t addr = 0;
|
---|
855 | uint32_t reg;
|
---|
856 | uint8_t off, msk;
|
---|
857 | int i;
|
---|
858 |
|
---|
859 | reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL);
|
---|
860 | if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
|
---|
861 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL,
|
---|
862 | reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
|
---|
863 | }
|
---|
864 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN);
|
---|
865 | if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
|
---|
866 | urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
---|
867 | reg | R92C_SYS_FUNC_EN_ELDR);
|
---|
868 | }
|
---|
869 | reg = urtwn_read_2(sc, R92C_SYS_CLKR);
|
---|
870 | if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
|
---|
871 | (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
|
---|
872 | urtwn_write_2(sc, R92C_SYS_CLKR,
|
---|
873 | reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
|
---|
874 | }
|
---|
875 | memset(&sc->rom, 0xff, sizeof(sc->rom));
|
---|
876 | while (addr < 512) {
|
---|
877 | reg = urtwn_efuse_read_1(sc, addr);
|
---|
878 | if (reg == 0xff)
|
---|
879 | break;
|
---|
880 | addr++;
|
---|
881 | off = reg >> 4;
|
---|
882 | msk = reg & 0xf;
|
---|
883 | for (i = 0; i < 4; i++) {
|
---|
884 | if (msk & (1 << i))
|
---|
885 | continue;
|
---|
886 | rom[off * 8 + i * 2 + 0] =
|
---|
887 | urtwn_efuse_read_1(sc, addr);
|
---|
888 | addr++;
|
---|
889 | rom[off * 8 + i * 2 + 1] =
|
---|
890 | urtwn_efuse_read_1(sc, addr);
|
---|
891 | addr++;
|
---|
892 | }
|
---|
893 | }
|
---|
894 | #ifdef URTWN_DEBUG
|
---|
895 | if (urtwn_debug >= 2) {
|
---|
896 | /* Dump ROM content. */
|
---|
897 | printf("\n");
|
---|
898 | for (i = 0; i < sizeof(sc->rom); i++)
|
---|
899 | printf("%02x:", rom[i]);
|
---|
900 | printf("\n");
|
---|
901 | }
|
---|
902 | #endif
|
---|
903 | }
|
---|
904 |
|
---|
905 | int
|
---|
906 | urtwn_read_chipid(struct urtwn_softc *sc)
|
---|
907 | {
|
---|
908 | uint32_t reg;
|
---|
909 |
|
---|
910 | reg = urtwn_read_4(sc, R92C_SYS_CFG);
|
---|
911 | if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
|
---|
912 | return (EIO);
|
---|
913 |
|
---|
914 | if (reg & R92C_SYS_CFG_TYPE_92C) {
|
---|
915 | sc->chip |= URTWN_CHIP_92C;
|
---|
916 | /* Check if it is a castrated 8192C. */
|
---|
917 | if (MS(urtwn_read_4(sc, R92C_HPON_FSM),
|
---|
918 | R92C_HPON_FSM_CHIP_BONDING_ID) ==
|
---|
919 | R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
|
---|
920 | sc->chip |= URTWN_CHIP_92C_1T2R;
|
---|
921 | }
|
---|
922 | if (reg & R92C_SYS_CFG_VENDOR_UMC) {
|
---|
923 | sc->chip |= URTWN_CHIP_UMC;
|
---|
924 | if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
|
---|
925 | sc->chip |= URTWN_CHIP_UMC_A_CUT;
|
---|
926 | }
|
---|
927 | return (0);
|
---|
928 | }
|
---|
929 |
|
---|
930 | void
|
---|
931 | urtwn_read_rom(struct urtwn_softc *sc)
|
---|
932 | {
|
---|
933 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
934 | struct r92c_rom *rom = &sc->rom;
|
---|
935 |
|
---|
936 | /* Read full ROM image. */
|
---|
937 | urtwn_efuse_read(sc);
|
---|
938 |
|
---|
939 | /* XXX Weird but this is what the vendor driver does. */
|
---|
940 | sc->pa_setting = urtwn_efuse_read_1(sc, 0x1fa);
|
---|
941 | DPRINTF(("PA setting=0x%x\n", sc->pa_setting));
|
---|
942 |
|
---|
943 | sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
|
---|
944 |
|
---|
945 | sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
|
---|
946 | DPRINTF(("regulatory type=%d\n", sc->regulatory));
|
---|
947 |
|
---|
948 | IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr);
|
---|
949 | }
|
---|
950 |
|
---|
951 | int
|
---|
952 | urtwn_media_change(struct ifnet *ifp)
|
---|
953 | {
|
---|
954 | int error;
|
---|
955 |
|
---|
956 | error = ieee80211_media_change(ifp);
|
---|
957 | if (error != ENETRESET)
|
---|
958 | return (error);
|
---|
959 |
|
---|
960 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
|
---|
961 | (IFF_UP | IFF_RUNNING)) {
|
---|
962 | urtwn_stop(ifp);
|
---|
963 | urtwn_init(ifp);
|
---|
964 | }
|
---|
965 | return (0);
|
---|
966 | }
|
---|
967 |
|
---|
968 | /*
|
---|
969 | * Initialize rate adaptation in firmware.
|
---|
970 | */
|
---|
971 | int
|
---|
972 | urtwn_ra_init(struct urtwn_softc *sc)
|
---|
973 | {
|
---|
974 | static const uint8_t map[] =
|
---|
975 | { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
|
---|
976 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
977 | struct ieee80211_node *ni = ic->ic_bss;
|
---|
978 | struct ieee80211_rateset *rs = &ni->ni_rates;
|
---|
979 | struct r92c_fw_cmd_macid_cfg cmd;
|
---|
980 | uint32_t rates, basicrates;
|
---|
981 | uint8_t mode;
|
---|
982 | int maxrate, maxbasicrate, error, i, j;
|
---|
983 |
|
---|
984 | /* Get normal and basic rates mask. */
|
---|
985 | rates = basicrates = 0;
|
---|
986 | maxrate = maxbasicrate = 0;
|
---|
987 | for (i = 0; i < rs->rs_nrates; i++) {
|
---|
988 | /* Convert 802.11 rate to HW rate index. */
|
---|
989 | for (j = 0; j < nitems(map); j++)
|
---|
990 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j])
|
---|
991 | break;
|
---|
992 | if (j == nitems(map)) /* Unknown rate, skip. */
|
---|
993 | continue;
|
---|
994 | rates |= 1 << j;
|
---|
995 | if (j > maxrate)
|
---|
996 | maxrate = j;
|
---|
997 | if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) {
|
---|
998 | basicrates |= 1 << j;
|
---|
999 | if (j > maxbasicrate)
|
---|
1000 | maxbasicrate = j;
|
---|
1001 | }
|
---|
1002 | }
|
---|
1003 | if (ic->ic_curmode == IEEE80211_MODE_11B)
|
---|
1004 | mode = R92C_RAID_11B;
|
---|
1005 | else
|
---|
1006 | mode = R92C_RAID_11BG;
|
---|
1007 | DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n",
|
---|
1008 | mode, rates, basicrates));
|
---|
1009 |
|
---|
1010 | /* Set rates mask for group addressed frames. */
|
---|
1011 | cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID;
|
---|
1012 | cmd.mask = htole32(mode << 28 | basicrates);
|
---|
1013 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
|
---|
1014 | if (error != 0) {
|
---|
1015 | printf("%s: could not add broadcast station\n",
|
---|
1016 | sc->sc_dev.dv_xname);
|
---|
1017 | return (error);
|
---|
1018 | }
|
---|
1019 | /* Set initial MRR rate. */
|
---|
1020 | DPRINTF(("maxbasicrate=%d\n", maxbasicrate));
|
---|
1021 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC),
|
---|
1022 | maxbasicrate);
|
---|
1023 |
|
---|
1024 | /* Set rates mask for unicast frames. */
|
---|
1025 | cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID;
|
---|
1026 | cmd.mask = htole32(mode << 28 | rates);
|
---|
1027 | error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
|
---|
1028 | if (error != 0) {
|
---|
1029 | printf("%s: could not add BSS station\n",
|
---|
1030 | sc->sc_dev.dv_xname);
|
---|
1031 | return (error);
|
---|
1032 | }
|
---|
1033 | /* Set initial MRR rate. */
|
---|
1034 | DPRINTF(("maxrate=%d\n", maxrate));
|
---|
1035 | urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS),
|
---|
1036 | maxrate);
|
---|
1037 |
|
---|
1038 | /* Indicate highest supported rate. */
|
---|
1039 | ni->ni_txrate = rs->rs_nrates - 1;
|
---|
1040 | return (0);
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | void
|
---|
1044 | urtwn_tsf_sync_enable(struct urtwn_softc *sc)
|
---|
1045 | {
|
---|
1046 | struct ieee80211_node *ni = sc->sc_ic.ic_bss;
|
---|
1047 | uint64_t tsf;
|
---|
1048 |
|
---|
1049 | /* Enable TSF synchronization. */
|
---|
1050 | urtwn_write_1(sc, R92C_BCN_CTRL,
|
---|
1051 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0);
|
---|
1052 |
|
---|
1053 | urtwn_write_1(sc, R92C_BCN_CTRL,
|
---|
1054 | urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN);
|
---|
1055 |
|
---|
1056 | /* Set initial TSF. */
|
---|
1057 | memcpy(&tsf, ni->ni_tstamp, 8);
|
---|
1058 | tsf = letoh64(tsf);
|
---|
1059 | tsf = tsf - (tsf % (ni->ni_intval * IEEE80211_DUR_TU));
|
---|
1060 | tsf -= IEEE80211_DUR_TU;
|
---|
1061 | urtwn_write_4(sc, R92C_TSFTR + 0, tsf);
|
---|
1062 | urtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32);
|
---|
1063 |
|
---|
1064 | urtwn_write_1(sc, R92C_BCN_CTRL,
|
---|
1065 | urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN);
|
---|
1066 | }
|
---|
1067 |
|
---|
1068 | void
|
---|
1069 | urtwn_set_led(struct urtwn_softc *sc, int led, int on)
|
---|
1070 | {
|
---|
1071 | uint8_t reg;
|
---|
1072 |
|
---|
1073 | if (led == URTWN_LED_LINK) {
|
---|
1074 | reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70;
|
---|
1075 | if (!on)
|
---|
1076 | reg |= R92C_LEDCFG0_DIS;
|
---|
1077 | urtwn_write_1(sc, R92C_LEDCFG0, reg);
|
---|
1078 | sc->ledlink = on; /* Save LED state. */
|
---|
1079 | }
|
---|
1080 | }
|
---|
1081 |
|
---|
1082 | void
|
---|
1083 | urtwn_calib_to(void *arg)
|
---|
1084 | {
|
---|
1085 | struct urtwn_softc *sc = arg;
|
---|
1086 |
|
---|
1087 | if (usbd_is_dying(sc->sc_udev))
|
---|
1088 | return;
|
---|
1089 |
|
---|
1090 | usbd_ref_incr(sc->sc_udev);
|
---|
1091 |
|
---|
1092 | /* Do it in a process context. */
|
---|
1093 | urtwn_do_async(sc, urtwn_calib_cb, NULL, 0);
|
---|
1094 |
|
---|
1095 | usbd_ref_decr(sc->sc_udev);
|
---|
1096 | }
|
---|
1097 |
|
---|
1098 | /* ARGSUSED */
|
---|
1099 | void
|
---|
1100 | urtwn_calib_cb(struct urtwn_softc *sc, void *arg)
|
---|
1101 | {
|
---|
1102 | struct r92c_fw_cmd_rssi cmd;
|
---|
1103 |
|
---|
1104 | if (sc->avg_pwdb != -1) {
|
---|
1105 | /* Indicate Rx signal strength to FW for rate adaptation. */
|
---|
1106 | memset(&cmd, 0, sizeof(cmd));
|
---|
1107 | cmd.macid = 0; /* BSS. */
|
---|
1108 | cmd.pwdb = sc->avg_pwdb;
|
---|
1109 | DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb));
|
---|
1110 | urtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
|
---|
1111 | }
|
---|
1112 |
|
---|
1113 | /* Do temperature compensation. */
|
---|
1114 | urtwn_temp_calib(sc);
|
---|
1115 |
|
---|
1116 | if (!usbd_is_dying(sc->sc_udev))
|
---|
1117 | timeout_add_sec(&sc->calib_to, 2);
|
---|
1118 | }
|
---|
1119 |
|
---|
1120 | void
|
---|
1121 | urtwn_next_scan(void *arg)
|
---|
1122 | {
|
---|
1123 | struct urtwn_softc *sc = arg;
|
---|
1124 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1125 | int s;
|
---|
1126 |
|
---|
1127 | if (usbd_is_dying(sc->sc_udev))
|
---|
1128 | return;
|
---|
1129 |
|
---|
1130 | usbd_ref_incr(sc->sc_udev);
|
---|
1131 |
|
---|
1132 | s = splnet();
|
---|
1133 | if (ic->ic_state == IEEE80211_S_SCAN)
|
---|
1134 | ieee80211_next_scan(&ic->ic_if);
|
---|
1135 | splx(s);
|
---|
1136 |
|
---|
1137 | usbd_ref_decr(sc->sc_udev);
|
---|
1138 | }
|
---|
1139 |
|
---|
1140 | int
|
---|
1141 | urtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
|
---|
1142 | {
|
---|
1143 | struct urtwn_softc *sc = ic->ic_softc;
|
---|
1144 | struct urtwn_cmd_newstate cmd;
|
---|
1145 |
|
---|
1146 | /* Do it in a process context. */
|
---|
1147 | cmd.state = nstate;
|
---|
1148 | cmd.arg = arg;
|
---|
1149 | urtwn_do_async(sc, urtwn_newstate_cb, &cmd, sizeof(cmd));
|
---|
1150 | return (0);
|
---|
1151 | }
|
---|
1152 |
|
---|
1153 | void
|
---|
1154 | urtwn_newstate_cb(struct urtwn_softc *sc, void *arg)
|
---|
1155 | {
|
---|
1156 | struct urtwn_cmd_newstate *cmd = arg;
|
---|
1157 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1158 | struct ieee80211_node *ni;
|
---|
1159 | enum ieee80211_state ostate;
|
---|
1160 | uint32_t reg;
|
---|
1161 | int s;
|
---|
1162 |
|
---|
1163 | s = splnet();
|
---|
1164 | ostate = ic->ic_state;
|
---|
1165 | DPRINTF(("newstate %d -> %d\n", ostate, cmd->state));
|
---|
1166 |
|
---|
1167 | if (ostate == IEEE80211_S_RUN) {
|
---|
1168 | /* Stop calibration. */
|
---|
1169 | timeout_del(&sc->calib_to);
|
---|
1170 |
|
---|
1171 | /* Turn link LED off. */
|
---|
1172 | urtwn_set_led(sc, URTWN_LED_LINK, 0);
|
---|
1173 |
|
---|
1174 | /* Set media status to 'No Link'. */
|
---|
1175 | reg = urtwn_read_4(sc, R92C_CR);
|
---|
1176 | reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK);
|
---|
1177 | urtwn_write_4(sc, R92C_CR, reg);
|
---|
1178 |
|
---|
1179 | /* Stop Rx of data frames. */
|
---|
1180 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0);
|
---|
1181 |
|
---|
1182 | /* Rest TSF. */
|
---|
1183 | urtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03);
|
---|
1184 |
|
---|
1185 | /* Disable TSF synchronization. */
|
---|
1186 | urtwn_write_1(sc, R92C_BCN_CTRL,
|
---|
1187 | urtwn_read_1(sc, R92C_BCN_CTRL) |
|
---|
1188 | R92C_BCN_CTRL_DIS_TSF_UDT0);
|
---|
1189 |
|
---|
1190 | /* Reset EDCA parameters. */
|
---|
1191 | urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
|
---|
1192 | urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
|
---|
1193 | urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
|
---|
1194 | urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
|
---|
1195 | }
|
---|
1196 | switch (cmd->state) {
|
---|
1197 | case IEEE80211_S_INIT:
|
---|
1198 | /* Turn link LED off. */
|
---|
1199 | urtwn_set_led(sc, URTWN_LED_LINK, 0);
|
---|
1200 | break;
|
---|
1201 | case IEEE80211_S_SCAN:
|
---|
1202 | if (ostate != IEEE80211_S_SCAN) {
|
---|
1203 | /* Allow Rx from any BSSID. */
|
---|
1204 | urtwn_write_4(sc, R92C_RCR,
|
---|
1205 | urtwn_read_4(sc, R92C_RCR) &
|
---|
1206 | ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN));
|
---|
1207 |
|
---|
1208 | /* Set gain for scanning. */
|
---|
1209 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
|
---|
1210 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
|
---|
1211 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
|
---|
1212 |
|
---|
1213 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
|
---|
1214 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
|
---|
1215 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
|
---|
1216 | }
|
---|
1217 |
|
---|
1218 | /* Make link LED blink during scan. */
|
---|
1219 | urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink);
|
---|
1220 |
|
---|
1221 | /* Pause AC Tx queues. */
|
---|
1222 | urtwn_write_1(sc, R92C_TXPAUSE,
|
---|
1223 | urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f);
|
---|
1224 |
|
---|
1225 | urtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
|
---|
1226 | if (!usbd_is_dying(sc->sc_udev))
|
---|
1227 | timeout_add_msec(&sc->scan_to, 200);
|
---|
1228 | break;
|
---|
1229 |
|
---|
1230 | case IEEE80211_S_AUTH:
|
---|
1231 | /* Set initial gain under link. */
|
---|
1232 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
|
---|
1233 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
|
---|
1234 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
|
---|
1235 |
|
---|
1236 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
|
---|
1237 | reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
|
---|
1238 | urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
|
---|
1239 |
|
---|
1240 | urtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
|
---|
1241 | break;
|
---|
1242 | case IEEE80211_S_ASSOC:
|
---|
1243 | break;
|
---|
1244 | case IEEE80211_S_RUN:
|
---|
1245 | if (ic->ic_opmode == IEEE80211_M_MONITOR) {
|
---|
1246 | urtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
|
---|
1247 |
|
---|
1248 | /* Enable Rx of data frames. */
|
---|
1249 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
|
---|
1250 |
|
---|
1251 | /* Turn link LED on. */
|
---|
1252 | urtwn_set_led(sc, URTWN_LED_LINK, 1);
|
---|
1253 | break;
|
---|
1254 | }
|
---|
1255 | ni = ic->ic_bss;
|
---|
1256 |
|
---|
1257 | /* Set media status to 'Associated'. */
|
---|
1258 | reg = urtwn_read_4(sc, R92C_CR);
|
---|
1259 | reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
|
---|
1260 | urtwn_write_4(sc, R92C_CR, reg);
|
---|
1261 |
|
---|
1262 | /* Set BSSID. */
|
---|
1263 | urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
|
---|
1264 | urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
|
---|
1265 |
|
---|
1266 | if (ic->ic_curmode == IEEE80211_MODE_11B)
|
---|
1267 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
|
---|
1268 | else /* 802.11b/g */
|
---|
1269 | urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
|
---|
1270 |
|
---|
1271 | /* Enable Rx of data frames. */
|
---|
1272 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
|
---|
1273 |
|
---|
1274 | /* Flush all AC queues. */
|
---|
1275 | urtwn_write_1(sc, R92C_TXPAUSE, 0);
|
---|
1276 |
|
---|
1277 | /* Set beacon interval. */
|
---|
1278 | urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
|
---|
1279 |
|
---|
1280 | /* Allow Rx from our BSSID only. */
|
---|
1281 | urtwn_write_4(sc, R92C_RCR,
|
---|
1282 | urtwn_read_4(sc, R92C_RCR) |
|
---|
1283 | R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
|
---|
1284 |
|
---|
1285 | /* Enable TSF synchronization. */
|
---|
1286 | urtwn_tsf_sync_enable(sc);
|
---|
1287 |
|
---|
1288 | urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
|
---|
1289 | urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
|
---|
1290 | urtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
|
---|
1291 | urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
|
---|
1292 | urtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
|
---|
1293 | urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
|
---|
1294 |
|
---|
1295 | /* Intialize rate adaptation. */
|
---|
1296 | urtwn_ra_init(sc);
|
---|
1297 | /* Turn link LED on. */
|
---|
1298 | urtwn_set_led(sc, URTWN_LED_LINK, 1);
|
---|
1299 |
|
---|
1300 | sc->avg_pwdb = -1; /* Reset average RSSI. */
|
---|
1301 | /* Reset temperature calibration state machine. */
|
---|
1302 | sc->thcal_state = 0;
|
---|
1303 | sc->thcal_lctemp = 0;
|
---|
1304 | /* Start periodic calibration. */
|
---|
1305 | if (!usbd_is_dying(sc->sc_udev))
|
---|
1306 | timeout_add_sec(&sc->calib_to, 2);
|
---|
1307 | break;
|
---|
1308 | }
|
---|
1309 | (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
|
---|
1310 | splx(s);
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | void
|
---|
1314 | urtwn_updateedca(struct ieee80211com *ic)
|
---|
1315 | {
|
---|
1316 | /* Do it in a process context. */
|
---|
1317 | urtwn_do_async(ic->ic_softc, urtwn_updateedca_cb, NULL, 0);
|
---|
1318 | }
|
---|
1319 |
|
---|
1320 | /* ARGSUSED */
|
---|
1321 | void
|
---|
1322 | urtwn_updateedca_cb(struct urtwn_softc *sc, void *arg)
|
---|
1323 | {
|
---|
1324 | const uint16_t aci2reg[EDCA_NUM_AC] = {
|
---|
1325 | R92C_EDCA_BE_PARAM,
|
---|
1326 | R92C_EDCA_BK_PARAM,
|
---|
1327 | R92C_EDCA_VI_PARAM,
|
---|
1328 | R92C_EDCA_VO_PARAM
|
---|
1329 | };
|
---|
1330 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1331 | struct ieee80211_edca_ac_params *ac;
|
---|
1332 | int s, aci, aifs, slottime;
|
---|
1333 |
|
---|
1334 | s = splnet();
|
---|
1335 | slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
|
---|
1336 | for (aci = 0; aci < EDCA_NUM_AC; aci++) {
|
---|
1337 | ac = &ic->ic_edca_ac[aci];
|
---|
1338 | /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
|
---|
1339 | aifs = ac->ac_aifsn * slottime + 10;
|
---|
1340 | urtwn_write_4(sc, aci2reg[aci],
|
---|
1341 | SM(R92C_EDCA_PARAM_TXOP, ac->ac_txoplimit) |
|
---|
1342 | SM(R92C_EDCA_PARAM_ECWMIN, ac->ac_ecwmin) |
|
---|
1343 | SM(R92C_EDCA_PARAM_ECWMAX, ac->ac_ecwmax) |
|
---|
1344 | SM(R92C_EDCA_PARAM_AIFS, aifs));
|
---|
1345 | }
|
---|
1346 | splx(s);
|
---|
1347 | }
|
---|
1348 |
|
---|
1349 | int
|
---|
1350 | urtwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
|
---|
1351 | struct ieee80211_key *k)
|
---|
1352 | {
|
---|
1353 | struct urtwn_softc *sc = ic->ic_softc;
|
---|
1354 | struct urtwn_cmd_key cmd;
|
---|
1355 |
|
---|
1356 | /* Defer setting of WEP keys until interface is brought up. */
|
---|
1357 | if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
|
---|
1358 | (IFF_UP | IFF_RUNNING))
|
---|
1359 | return (0);
|
---|
1360 |
|
---|
1361 | /* Do it in a process context. */
|
---|
1362 | cmd.key = *k;
|
---|
1363 | cmd.associd = (ni != NULL) ? ni->ni_associd : 0;
|
---|
1364 | urtwn_do_async(sc, urtwn_set_key_cb, &cmd, sizeof(cmd));
|
---|
1365 | return (0);
|
---|
1366 | }
|
---|
1367 |
|
---|
1368 | void
|
---|
1369 | urtwn_set_key_cb(struct urtwn_softc *sc, void *arg)
|
---|
1370 | {
|
---|
1371 | static const uint8_t etherzeroaddr[6] = { 0 };
|
---|
1372 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1373 | struct urtwn_cmd_key *cmd = arg;
|
---|
1374 | struct ieee80211_key *k = &cmd->key;
|
---|
1375 | const uint8_t *macaddr;
|
---|
1376 | uint8_t keybuf[16], algo;
|
---|
1377 | int i, entry;
|
---|
1378 |
|
---|
1379 | /* Map net80211 cipher to HW crypto algorithm. */
|
---|
1380 | switch (k->k_cipher) {
|
---|
1381 | case IEEE80211_CIPHER_WEP40:
|
---|
1382 | algo = R92C_CAM_ALGO_WEP40;
|
---|
1383 | break;
|
---|
1384 | case IEEE80211_CIPHER_WEP104:
|
---|
1385 | algo = R92C_CAM_ALGO_WEP104;
|
---|
1386 | break;
|
---|
1387 | case IEEE80211_CIPHER_TKIP:
|
---|
1388 | algo = R92C_CAM_ALGO_TKIP;
|
---|
1389 | break;
|
---|
1390 | case IEEE80211_CIPHER_CCMP:
|
---|
1391 | algo = R92C_CAM_ALGO_AES;
|
---|
1392 | break;
|
---|
1393 | default:
|
---|
1394 | return;
|
---|
1395 | }
|
---|
1396 | if (k->k_flags & IEEE80211_KEY_GROUP) {
|
---|
1397 | macaddr = etherzeroaddr;
|
---|
1398 | entry = k->k_id;
|
---|
1399 | } else {
|
---|
1400 | macaddr = ic->ic_bss->ni_macaddr;
|
---|
1401 | entry = 4;
|
---|
1402 | }
|
---|
1403 | /* Write key. */
|
---|
1404 | memset(keybuf, 0, sizeof(keybuf));
|
---|
1405 | memcpy(keybuf, k->k_key, MIN(k->k_len, sizeof(keybuf)));
|
---|
1406 | for (i = 0; i < 4; i++) {
|
---|
1407 | urtwn_cam_write(sc, R92C_CAM_KEY(entry, i),
|
---|
1408 | LE_READ_4(&keybuf[i * 4]));
|
---|
1409 | }
|
---|
1410 | /* Write CTL0 last since that will validate the CAM entry. */
|
---|
1411 | urtwn_cam_write(sc, R92C_CAM_CTL1(entry),
|
---|
1412 | LE_READ_4(&macaddr[2]));
|
---|
1413 | urtwn_cam_write(sc, R92C_CAM_CTL0(entry),
|
---|
1414 | SM(R92C_CAM_ALGO, algo) |
|
---|
1415 | SM(R92C_CAM_KEYID, k->k_id) |
|
---|
1416 | SM(R92C_CAM_MACLO, LE_READ_2(&macaddr[0])) |
|
---|
1417 | R92C_CAM_VALID);
|
---|
1418 | }
|
---|
1419 |
|
---|
1420 | void
|
---|
1421 | urtwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
|
---|
1422 | struct ieee80211_key *k)
|
---|
1423 | {
|
---|
1424 | struct urtwn_softc *sc = ic->ic_softc;
|
---|
1425 | struct urtwn_cmd_key cmd;
|
---|
1426 |
|
---|
1427 | if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
|
---|
1428 | ic->ic_state != IEEE80211_S_RUN)
|
---|
1429 | return; /* Nothing to do. */
|
---|
1430 |
|
---|
1431 | /* Do it in a process context. */
|
---|
1432 | cmd.key = *k;
|
---|
1433 | cmd.associd = (ni != NULL) ? ni->ni_associd : 0;
|
---|
1434 | urtwn_do_async(sc, urtwn_delete_key_cb, &cmd, sizeof(cmd));
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | void
|
---|
1438 | urtwn_delete_key_cb(struct urtwn_softc *sc, void *arg)
|
---|
1439 | {
|
---|
1440 | struct urtwn_cmd_key *cmd = arg;
|
---|
1441 | struct ieee80211_key *k = &cmd->key;
|
---|
1442 | int i, entry;
|
---|
1443 |
|
---|
1444 | if (k->k_flags & IEEE80211_KEY_GROUP)
|
---|
1445 | entry = k->k_id;
|
---|
1446 | else
|
---|
1447 | entry = 4;
|
---|
1448 | urtwn_cam_write(sc, R92C_CAM_CTL0(entry), 0);
|
---|
1449 | urtwn_cam_write(sc, R92C_CAM_CTL1(entry), 0);
|
---|
1450 | /* Clear key. */
|
---|
1451 | for (i = 0; i < 4; i++)
|
---|
1452 | urtwn_cam_write(sc, R92C_CAM_KEY(entry, i), 0);
|
---|
1453 | }
|
---|
1454 |
|
---|
1455 | void
|
---|
1456 | urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi)
|
---|
1457 | {
|
---|
1458 | int pwdb;
|
---|
1459 |
|
---|
1460 | /* Convert antenna signal to percentage. */
|
---|
1461 | if (rssi <= -100 || rssi >= 20)
|
---|
1462 | pwdb = 0;
|
---|
1463 | else if (rssi >= 0)
|
---|
1464 | pwdb = 100;
|
---|
1465 | else
|
---|
1466 | pwdb = 100 + rssi;
|
---|
1467 | if (rate <= 3) {
|
---|
1468 | /* CCK gain is smaller than OFDM/MCS gain. */
|
---|
1469 | pwdb += 6;
|
---|
1470 | if (pwdb > 100)
|
---|
1471 | pwdb = 100;
|
---|
1472 | if (pwdb <= 14)
|
---|
1473 | pwdb -= 4;
|
---|
1474 | else if (pwdb <= 26)
|
---|
1475 | pwdb -= 8;
|
---|
1476 | else if (pwdb <= 34)
|
---|
1477 | pwdb -= 6;
|
---|
1478 | else if (pwdb <= 42)
|
---|
1479 | pwdb -= 2;
|
---|
1480 | }
|
---|
1481 | if (sc->avg_pwdb == -1) /* Init. */
|
---|
1482 | sc->avg_pwdb = pwdb;
|
---|
1483 | else if (sc->avg_pwdb < pwdb)
|
---|
1484 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
|
---|
1485 | else
|
---|
1486 | sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
|
---|
1487 | DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb));
|
---|
1488 | }
|
---|
1489 |
|
---|
1490 | int8_t
|
---|
1491 | urtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
|
---|
1492 | {
|
---|
1493 | static const int8_t cckoff[] = { 16, -12, -26, -46 };
|
---|
1494 | struct r92c_rx_phystat *phy;
|
---|
1495 | struct r92c_rx_cck *cck;
|
---|
1496 | uint8_t rpt;
|
---|
1497 | int8_t rssi;
|
---|
1498 |
|
---|
1499 | if (rate <= 3) {
|
---|
1500 | cck = (struct r92c_rx_cck *)physt;
|
---|
1501 | if (sc->sc_flags & URTWN_FLAG_CCK_HIPWR) {
|
---|
1502 | rpt = (cck->agc_rpt >> 5) & 0x3;
|
---|
1503 | rssi = (cck->agc_rpt & 0x1f) << 1;
|
---|
1504 | } else {
|
---|
1505 | rpt = (cck->agc_rpt >> 6) & 0x3;
|
---|
1506 | rssi = cck->agc_rpt & 0x3e;
|
---|
1507 | }
|
---|
1508 | rssi = cckoff[rpt] - rssi;
|
---|
1509 | } else { /* OFDM/HT. */
|
---|
1510 | phy = (struct r92c_rx_phystat *)physt;
|
---|
1511 | rssi = ((letoh32(phy->phydw1) >> 1) & 0x7f) - 110;
|
---|
1512 | }
|
---|
1513 | return (rssi);
|
---|
1514 | }
|
---|
1515 |
|
---|
1516 | void
|
---|
1517 | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen)
|
---|
1518 | {
|
---|
1519 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1520 | struct ifnet *ifp = &ic->ic_if;
|
---|
1521 | struct ieee80211_rxinfo rxi;
|
---|
1522 | struct ieee80211_frame *wh;
|
---|
1523 | struct ieee80211_node *ni;
|
---|
1524 | struct r92c_rx_stat *stat;
|
---|
1525 | uint32_t rxdw0, rxdw3;
|
---|
1526 | struct mbuf *m;
|
---|
1527 | uint8_t rate;
|
---|
1528 | int8_t rssi = 0;
|
---|
1529 | int s, infosz;
|
---|
1530 |
|
---|
1531 | stat = (struct r92c_rx_stat *)buf;
|
---|
1532 | rxdw0 = letoh32(stat->rxdw0);
|
---|
1533 | rxdw3 = letoh32(stat->rxdw3);
|
---|
1534 |
|
---|
1535 | if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
|
---|
1536 | /*
|
---|
1537 | * This should not happen since we setup our Rx filter
|
---|
1538 | * to not receive these frames.
|
---|
1539 | */
|
---|
1540 | ifp->if_ierrors++;
|
---|
1541 | return;
|
---|
1542 | }
|
---|
1543 | if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
|
---|
1544 | ifp->if_ierrors++;
|
---|
1545 | return;
|
---|
1546 | }
|
---|
1547 |
|
---|
1548 | rate = MS(rxdw3, R92C_RXDW3_RATE);
|
---|
1549 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
|
---|
1550 |
|
---|
1551 | /* Get RSSI from PHY status descriptor if present. */
|
---|
1552 | if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
|
---|
1553 | rssi = urtwn_get_rssi(sc, rate, &stat[1]);
|
---|
1554 | /* Update our average RSSI. */
|
---|
1555 | urtwn_update_avgrssi(sc, rate, rssi);
|
---|
1556 | }
|
---|
1557 |
|
---|
1558 | DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
|
---|
1559 | pktlen, rate, infosz, rssi));
|
---|
1560 |
|
---|
1561 | MGETHDR(m, M_DONTWAIT, MT_DATA);
|
---|
1562 | if (__predict_false(m == NULL)) {
|
---|
1563 | ifp->if_ierrors++;
|
---|
1564 | return;
|
---|
1565 | }
|
---|
1566 | if (pktlen > MHLEN) {
|
---|
1567 | MCLGET(m, M_DONTWAIT);
|
---|
1568 | if (__predict_false(!(m->m_flags & M_EXT))) {
|
---|
1569 | ifp->if_ierrors++;
|
---|
1570 | m_freem(m);
|
---|
1571 | return;
|
---|
1572 | }
|
---|
1573 | }
|
---|
1574 | /* Finalize mbuf. */
|
---|
1575 | m->m_pkthdr.rcvif = ifp;
|
---|
1576 | wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
|
---|
1577 | memcpy(mtod(m, uint8_t *), wh, pktlen);
|
---|
1578 | m->m_pkthdr.len = m->m_len = pktlen;
|
---|
1579 |
|
---|
1580 | s = splnet();
|
---|
1581 | #if NBPFILTER > 0
|
---|
1582 | if (__predict_false(sc->sc_drvbpf != NULL)) {
|
---|
1583 | struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
|
---|
1584 | struct mbuf mb;
|
---|
1585 |
|
---|
1586 | tap->wr_flags = 0;
|
---|
1587 | /* Map HW rate index to 802.11 rate. */
|
---|
1588 | tap->wr_flags = 2;
|
---|
1589 | if (!(rxdw3 & R92C_RXDW3_HT)) {
|
---|
1590 | switch (rate) {
|
---|
1591 | /* CCK. */
|
---|
1592 | case 0: tap->wr_rate = 2; break;
|
---|
1593 | case 1: tap->wr_rate = 4; break;
|
---|
1594 | case 2: tap->wr_rate = 11; break;
|
---|
1595 | case 3: tap->wr_rate = 22; break;
|
---|
1596 | /* OFDM. */
|
---|
1597 | case 4: tap->wr_rate = 12; break;
|
---|
1598 | case 5: tap->wr_rate = 18; break;
|
---|
1599 | case 6: tap->wr_rate = 24; break;
|
---|
1600 | case 7: tap->wr_rate = 36; break;
|
---|
1601 | case 8: tap->wr_rate = 48; break;
|
---|
1602 | case 9: tap->wr_rate = 72; break;
|
---|
1603 | case 10: tap->wr_rate = 96; break;
|
---|
1604 | case 11: tap->wr_rate = 108; break;
|
---|
1605 | }
|
---|
1606 | } else if (rate >= 12) { /* MCS0~15. */
|
---|
1607 | /* Bit 7 set means HT MCS instead of rate. */
|
---|
1608 | tap->wr_rate = 0x80 | (rate - 12);
|
---|
1609 | }
|
---|
1610 | tap->wr_dbm_antsignal = rssi;
|
---|
1611 | tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
|
---|
1612 | tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
|
---|
1613 |
|
---|
1614 | mb.m_data = (caddr_t)tap;
|
---|
1615 | mb.m_len = sc->sc_rxtap_len;
|
---|
1616 | mb.m_next = m;
|
---|
1617 | mb.m_nextpkt = NULL;
|
---|
1618 | mb.m_type = 0;
|
---|
1619 | mb.m_flags = 0;
|
---|
1620 | bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
|
---|
1621 | }
|
---|
1622 | #endif
|
---|
1623 |
|
---|
1624 | ni = ieee80211_find_rxnode(ic, wh);
|
---|
1625 | rxi.rxi_flags = 0;
|
---|
1626 | rxi.rxi_rssi = rssi;
|
---|
1627 | rxi.rxi_tstamp = 0; /* Unused. */
|
---|
1628 | ieee80211_input(ifp, m, ni, &rxi);
|
---|
1629 | /* Node is no longer needed. */
|
---|
1630 | ieee80211_release_node(ic, ni);
|
---|
1631 | splx(s);
|
---|
1632 | }
|
---|
1633 |
|
---|
1634 | void
|
---|
1635 | urtwn_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
|
---|
1636 | usbd_status status)
|
---|
1637 | {
|
---|
1638 | struct urtwn_rx_data *data = priv;
|
---|
1639 | struct urtwn_softc *sc = data->sc;
|
---|
1640 | struct r92c_rx_stat *stat;
|
---|
1641 | uint32_t rxdw0;
|
---|
1642 | uint8_t *buf;
|
---|
1643 | int len, totlen, pktlen, infosz, npkts;
|
---|
1644 |
|
---|
1645 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
|
---|
1646 | DPRINTF(("RX status=%d\n", status));
|
---|
1647 | if (status == USBD_STALLED)
|
---|
1648 | usbd_clear_endpoint_stall_async(sc->rx_pipe);
|
---|
1649 | if (status != USBD_CANCELLED)
|
---|
1650 | goto resubmit;
|
---|
1651 | return;
|
---|
1652 | }
|
---|
1653 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
|
---|
1654 |
|
---|
1655 | if (__predict_false(len < sizeof(*stat))) {
|
---|
1656 | DPRINTF(("xfer too short %d\n", len));
|
---|
1657 | goto resubmit;
|
---|
1658 | }
|
---|
1659 | buf = data->buf;
|
---|
1660 |
|
---|
1661 | /* Get the number of encapsulated frames. */
|
---|
1662 | stat = (struct r92c_rx_stat *)buf;
|
---|
1663 | npkts = MS(letoh32(stat->rxdw2), R92C_RXDW2_PKTCNT);
|
---|
1664 | DPRINTFN(6, ("Rx %d frames in one chunk\n", npkts));
|
---|
1665 |
|
---|
1666 | /* Process all of them. */
|
---|
1667 | while (npkts-- > 0) {
|
---|
1668 | if (__predict_false(len < sizeof(*stat)))
|
---|
1669 | break;
|
---|
1670 | stat = (struct r92c_rx_stat *)buf;
|
---|
1671 | rxdw0 = letoh32(stat->rxdw0);
|
---|
1672 |
|
---|
1673 | pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
|
---|
1674 | if (__predict_false(pktlen == 0))
|
---|
1675 | break;
|
---|
1676 |
|
---|
1677 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
|
---|
1678 |
|
---|
1679 | /* Make sure everything fits in xfer. */
|
---|
1680 | totlen = sizeof(*stat) + infosz + pktlen;
|
---|
1681 | if (__predict_false(totlen > len))
|
---|
1682 | break;
|
---|
1683 |
|
---|
1684 | /* Process 802.11 frame. */
|
---|
1685 | urtwn_rx_frame(sc, buf, pktlen);
|
---|
1686 |
|
---|
1687 | /* Next chunk is 128-byte aligned. */
|
---|
1688 | totlen = (totlen + 127) & ~127;
|
---|
1689 | buf += totlen;
|
---|
1690 | len -= totlen;
|
---|
1691 | }
|
---|
1692 |
|
---|
1693 | resubmit:
|
---|
1694 | /* Setup a new transfer. */
|
---|
1695 | usbd_setup_xfer(xfer, sc->rx_pipe, data, data->buf, URTWN_RXBUFSZ,
|
---|
1696 | USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, urtwn_rxeof);
|
---|
1697 | (void)usbd_transfer(xfer);
|
---|
1698 | }
|
---|
1699 |
|
---|
1700 | void
|
---|
1701 | urtwn_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
|
---|
1702 | usbd_status status)
|
---|
1703 | {
|
---|
1704 | struct urtwn_tx_data *data = priv;
|
---|
1705 | struct urtwn_softc *sc = data->sc;
|
---|
1706 | struct ifnet *ifp = &sc->sc_ic.ic_if;
|
---|
1707 | int s;
|
---|
1708 |
|
---|
1709 | s = splnet();
|
---|
1710 | /* Put this Tx buffer back to our free list. */
|
---|
1711 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
|
---|
1712 |
|
---|
1713 | if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
|
---|
1714 | DPRINTF(("TX status=%d\n", status));
|
---|
1715 | if (status == USBD_STALLED)
|
---|
1716 | usbd_clear_endpoint_stall_async(data->pipe);
|
---|
1717 | ifp->if_oerrors++;
|
---|
1718 | splx(s);
|
---|
1719 | return;
|
---|
1720 | }
|
---|
1721 | sc->sc_tx_timer = 0;
|
---|
1722 | ifp->if_opackets++;
|
---|
1723 |
|
---|
1724 | /* We just released a Tx buffer, notify Tx. */
|
---|
1725 | if (ifp->if_flags & IFF_OACTIVE) {
|
---|
1726 | ifp->if_flags &= ~IFF_OACTIVE;
|
---|
1727 | urtwn_start(ifp);
|
---|
1728 | }
|
---|
1729 | splx(s);
|
---|
1730 | }
|
---|
1731 |
|
---|
1732 | int
|
---|
1733 | urtwn_tx(struct urtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
|
---|
1734 | {
|
---|
1735 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1736 | struct ieee80211_frame *wh;
|
---|
1737 | struct ieee80211_key *k = NULL;
|
---|
1738 | struct urtwn_tx_data *data;
|
---|
1739 | struct r92c_tx_desc *txd;
|
---|
1740 | usbd_pipe_handle pipe;
|
---|
1741 | uint16_t qos, sum;
|
---|
1742 | uint8_t raid, type, tid, qid;
|
---|
1743 | int i, hasqos, xferlen, error;
|
---|
1744 |
|
---|
1745 | wh = mtod(m, struct ieee80211_frame *);
|
---|
1746 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
|
---|
1747 |
|
---|
1748 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
|
---|
1749 | k = ieee80211_get_txkey(ic, wh, ni);
|
---|
1750 | if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
|
---|
1751 | return (ENOBUFS);
|
---|
1752 | wh = mtod(m, struct ieee80211_frame *);
|
---|
1753 | }
|
---|
1754 |
|
---|
1755 | if ((hasqos = ieee80211_has_qos(wh))) {
|
---|
1756 | qos = ieee80211_get_qos(wh);
|
---|
1757 | tid = qos & IEEE80211_QOS_TID;
|
---|
1758 | qid = ieee80211_up_to_ac(ic, tid);
|
---|
1759 | } else if (type != IEEE80211_FC0_TYPE_DATA) {
|
---|
1760 | /* Use AC VO for management frames. */
|
---|
1761 | qid = EDCA_AC_VO;
|
---|
1762 | } else
|
---|
1763 | qid = EDCA_AC_BE;
|
---|
1764 |
|
---|
1765 | /* Get the USB pipe to use for this AC. */
|
---|
1766 | pipe = sc->tx_pipe[sc->ac2idx[qid]];
|
---|
1767 |
|
---|
1768 | /* Grab a Tx buffer from our free list. */
|
---|
1769 | data = TAILQ_FIRST(&sc->tx_free_list);
|
---|
1770 | TAILQ_REMOVE(&sc->tx_free_list, data, next);
|
---|
1771 |
|
---|
1772 | /* Fill Tx descriptor. */
|
---|
1773 | txd = (struct r92c_tx_desc *)data->buf;
|
---|
1774 | memset(txd, 0, sizeof(*txd));
|
---|
1775 |
|
---|
1776 | txd->txdw0 |= htole32(
|
---|
1777 | SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) |
|
---|
1778 | SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |
|
---|
1779 | R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG);
|
---|
1780 | if (IEEE80211_IS_MULTICAST(wh->i_addr1))
|
---|
1781 | txd->txdw0 |= htole32(R92C_TXDW0_BMCAST);
|
---|
1782 |
|
---|
1783 | #ifdef notyet
|
---|
1784 | if (k != NULL) {
|
---|
1785 | switch (k->k_cipher) {
|
---|
1786 | case IEEE80211_CIPHER_WEP40:
|
---|
1787 | case IEEE80211_CIPHER_WEP104:
|
---|
1788 | case IEEE80211_CIPHER_TKIP:
|
---|
1789 | cipher = R92C_TXDW1_CIPHER_RC4;
|
---|
1790 | break;
|
---|
1791 | case IEEE80211_CIPHER_CCMP:
|
---|
1792 | cipher = R92C_TXDW1_CIPHER_AES;
|
---|
1793 | break;
|
---|
1794 | default:
|
---|
1795 | cipher = R92C_TXDW1_CIPHER_NONE;
|
---|
1796 | }
|
---|
1797 | txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
|
---|
1798 | }
|
---|
1799 | #endif
|
---|
1800 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
|
---|
1801 | type == IEEE80211_FC0_TYPE_DATA) {
|
---|
1802 | if (ic->ic_curmode == IEEE80211_MODE_11B)
|
---|
1803 | raid = R92C_RAID_11B;
|
---|
1804 | else
|
---|
1805 | raid = R92C_RAID_11BG;
|
---|
1806 | txd->txdw1 |= htole32(
|
---|
1807 | SM(R92C_TXDW1_MACID, URTWN_MACID_BSS) |
|
---|
1808 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |
|
---|
1809 | SM(R92C_TXDW1_RAID, raid) |
|
---|
1810 | R92C_TXDW1_AGGBK);
|
---|
1811 |
|
---|
1812 | if (ic->ic_flags & IEEE80211_F_USEPROT) {
|
---|
1813 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
|
---|
1814 | txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF |
|
---|
1815 | R92C_TXDW4_HWRTSEN);
|
---|
1816 | } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
|
---|
1817 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |
|
---|
1818 | R92C_TXDW4_HWRTSEN);
|
---|
1819 | }
|
---|
1820 | }
|
---|
1821 | /* Send RTS at OFDM24. */
|
---|
1822 | txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 8));
|
---|
1823 | txd->txdw5 |= htole32(0x0001ff00);
|
---|
1824 | /* Send data at OFDM54. */
|
---|
1825 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11));
|
---|
1826 |
|
---|
1827 | } else {
|
---|
1828 | txd->txdw1 |= htole32(
|
---|
1829 | SM(R92C_TXDW1_MACID, 0) |
|
---|
1830 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |
|
---|
1831 | SM(R92C_TXDW1_RAID, R92C_RAID_11B));
|
---|
1832 |
|
---|
1833 | /* Force CCK1. */
|
---|
1834 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
|
---|
1835 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0));
|
---|
1836 | }
|
---|
1837 | /* Set sequence number (already little endian). */
|
---|
1838 | txd->txdseq |= *(uint16_t *)wh->i_seq;
|
---|
1839 |
|
---|
1840 | if (!hasqos) {
|
---|
1841 | /* Use HW sequence numbering for non-QoS frames. */
|
---|
1842 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ);
|
---|
1843 | txd->txdseq |= htole16(0x8000); /* WTF? */
|
---|
1844 | } else
|
---|
1845 | txd->txdw4 |= htole32(R92C_TXDW4_QOS);
|
---|
1846 |
|
---|
1847 | /* Compute Tx descriptor checksum. */
|
---|
1848 | sum = 0;
|
---|
1849 | for (i = 0; i < sizeof(*txd) / 2; i++)
|
---|
1850 | sum ^= ((uint16_t *)txd)[i];
|
---|
1851 | txd->txdsum = sum; /* NB: already little endian. */
|
---|
1852 |
|
---|
1853 | #if NBPFILTER > 0
|
---|
1854 | if (__predict_false(sc->sc_drvbpf != NULL)) {
|
---|
1855 | struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap;
|
---|
1856 | struct mbuf mb;
|
---|
1857 |
|
---|
1858 | tap->wt_flags = 0;
|
---|
1859 | tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
|
---|
1860 | tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
|
---|
1861 |
|
---|
1862 | mb.m_data = (caddr_t)tap;
|
---|
1863 | mb.m_len = sc->sc_txtap_len;
|
---|
1864 | mb.m_next = m;
|
---|
1865 | mb.m_nextpkt = NULL;
|
---|
1866 | mb.m_type = 0;
|
---|
1867 | mb.m_flags = 0;
|
---|
1868 | bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
|
---|
1869 | }
|
---|
1870 | #endif
|
---|
1871 |
|
---|
1872 | xferlen = sizeof(*txd) + m->m_pkthdr.len;
|
---|
1873 | m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]);
|
---|
1874 | m_freem(m);
|
---|
1875 |
|
---|
1876 | data->pipe = pipe;
|
---|
1877 | usbd_setup_xfer(data->xfer, pipe, data, data->buf, xferlen,
|
---|
1878 | USBD_FORCE_SHORT_XFER | USBD_NO_COPY, URTWN_TX_TIMEOUT,
|
---|
1879 | urtwn_txeof);
|
---|
1880 | error = usbd_transfer(data->xfer);
|
---|
1881 | if (__predict_false(error != USBD_IN_PROGRESS && error != 0)) {
|
---|
1882 | /* Put this Tx buffer back to our free list. */
|
---|
1883 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
|
---|
1884 | return (error);
|
---|
1885 | }
|
---|
1886 | ieee80211_release_node(ic, ni);
|
---|
1887 | return (0);
|
---|
1888 | }
|
---|
1889 |
|
---|
1890 | void
|
---|
1891 | urtwn_start(struct ifnet *ifp)
|
---|
1892 | {
|
---|
1893 | struct urtwn_softc *sc = ifp->if_softc;
|
---|
1894 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1895 | struct ieee80211_node *ni;
|
---|
1896 | struct mbuf *m;
|
---|
1897 |
|
---|
1898 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
|
---|
1899 | return;
|
---|
1900 |
|
---|
1901 | for (;;) {
|
---|
1902 | if (TAILQ_EMPTY(&sc->tx_free_list)) {
|
---|
1903 | ifp->if_flags |= IFF_OACTIVE;
|
---|
1904 | break;
|
---|
1905 | }
|
---|
1906 | /* Send pending management frames first. */
|
---|
1907 | IF_DEQUEUE(&ic->ic_mgtq, m);
|
---|
1908 | if (m != NULL) {
|
---|
1909 | ni = (void *)m->m_pkthdr.rcvif;
|
---|
1910 | goto sendit;
|
---|
1911 | }
|
---|
1912 | if (ic->ic_state != IEEE80211_S_RUN)
|
---|
1913 | break;
|
---|
1914 |
|
---|
1915 | /* Encapsulate and send data frames. */
|
---|
1916 | IFQ_DEQUEUE(&ifp->if_snd, m);
|
---|
1917 | if (m == NULL)
|
---|
1918 | break;
|
---|
1919 | #if NBPFILTER > 0
|
---|
1920 | if (ifp->if_bpf != NULL)
|
---|
1921 | bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
|
---|
1922 | #endif
|
---|
1923 | if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
|
---|
1924 | continue;
|
---|
1925 | sendit:
|
---|
1926 | #if NBPFILTER > 0
|
---|
1927 | if (ic->ic_rawbpf != NULL)
|
---|
1928 | bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
|
---|
1929 | #endif
|
---|
1930 | if (urtwn_tx(sc, m, ni) != 0) {
|
---|
1931 | ieee80211_release_node(ic, ni);
|
---|
1932 | ifp->if_oerrors++;
|
---|
1933 | continue;
|
---|
1934 | }
|
---|
1935 |
|
---|
1936 | sc->sc_tx_timer = 5;
|
---|
1937 | ifp->if_timer = 1;
|
---|
1938 | }
|
---|
1939 | }
|
---|
1940 |
|
---|
1941 | void
|
---|
1942 | urtwn_watchdog(struct ifnet *ifp)
|
---|
1943 | {
|
---|
1944 | struct urtwn_softc *sc = ifp->if_softc;
|
---|
1945 |
|
---|
1946 | ifp->if_timer = 0;
|
---|
1947 |
|
---|
1948 | if (sc->sc_tx_timer > 0) {
|
---|
1949 | if (--sc->sc_tx_timer == 0) {
|
---|
1950 | printf("%s: device timeout\n", sc->sc_dev.dv_xname);
|
---|
1951 | /* urtwn_init(ifp); XXX needs a process context! */
|
---|
1952 | ifp->if_oerrors++;
|
---|
1953 | return;
|
---|
1954 | }
|
---|
1955 | ifp->if_timer = 1;
|
---|
1956 | }
|
---|
1957 | ieee80211_watchdog(ifp);
|
---|
1958 | }
|
---|
1959 |
|
---|
1960 | int
|
---|
1961 | urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
---|
1962 | {
|
---|
1963 | struct urtwn_softc *sc = ifp->if_softc;
|
---|
1964 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
1965 | struct ifaddr *ifa;
|
---|
1966 | struct ifreq *ifr;
|
---|
1967 | int s, error = 0;
|
---|
1968 |
|
---|
1969 | if (usbd_is_dying(sc->sc_udev))
|
---|
1970 | return ENXIO;
|
---|
1971 |
|
---|
1972 | usbd_ref_incr(sc->sc_udev);
|
---|
1973 |
|
---|
1974 | s = splnet();
|
---|
1975 |
|
---|
1976 | switch (cmd) {
|
---|
1977 | case SIOCSIFADDR:
|
---|
1978 | ifa = (struct ifaddr *)data;
|
---|
1979 | ifp->if_flags |= IFF_UP;
|
---|
1980 | #ifdef INET
|
---|
1981 | if (ifa->ifa_addr->sa_family == AF_INET)
|
---|
1982 | arp_ifinit(&ic->ic_ac, ifa);
|
---|
1983 | #endif
|
---|
1984 | /* FALLTHROUGH */
|
---|
1985 | case SIOCSIFFLAGS:
|
---|
1986 | if (ifp->if_flags & IFF_UP) {
|
---|
1987 | if (!(ifp->if_flags & IFF_RUNNING))
|
---|
1988 | urtwn_init(ifp);
|
---|
1989 | } else {
|
---|
1990 | if (ifp->if_flags & IFF_RUNNING)
|
---|
1991 | urtwn_stop(ifp);
|
---|
1992 | }
|
---|
1993 | break;
|
---|
1994 | case SIOCADDMULTI:
|
---|
1995 | case SIOCDELMULTI:
|
---|
1996 | ifr = (struct ifreq *)data;
|
---|
1997 | error = (cmd == SIOCADDMULTI) ?
|
---|
1998 | ether_addmulti(ifr, &ic->ic_ac) :
|
---|
1999 | ether_delmulti(ifr, &ic->ic_ac);
|
---|
2000 | if (error == ENETRESET)
|
---|
2001 | error = 0;
|
---|
2002 | break;
|
---|
2003 | case SIOCS80211CHANNEL:
|
---|
2004 | error = ieee80211_ioctl(ifp, cmd, data);
|
---|
2005 | if (error == ENETRESET &&
|
---|
2006 | ic->ic_opmode == IEEE80211_M_MONITOR) {
|
---|
2007 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
|
---|
2008 | (IFF_UP | IFF_RUNNING))
|
---|
2009 | urtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
|
---|
2010 | error = 0;
|
---|
2011 | }
|
---|
2012 | break;
|
---|
2013 | default:
|
---|
2014 | error = ieee80211_ioctl(ifp, cmd, data);
|
---|
2015 | }
|
---|
2016 |
|
---|
2017 | if (error == ENETRESET) {
|
---|
2018 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
|
---|
2019 | (IFF_UP | IFF_RUNNING)) {
|
---|
2020 | urtwn_stop(ifp);
|
---|
2021 | urtwn_init(ifp);
|
---|
2022 | }
|
---|
2023 | error = 0;
|
---|
2024 | }
|
---|
2025 | splx(s);
|
---|
2026 |
|
---|
2027 | usbd_ref_decr(sc->sc_udev);
|
---|
2028 |
|
---|
2029 | return (error);
|
---|
2030 | }
|
---|
2031 |
|
---|
2032 | int
|
---|
2033 | urtwn_power_on(struct urtwn_softc *sc)
|
---|
2034 | {
|
---|
2035 | uint32_t reg;
|
---|
2036 | int ntries;
|
---|
2037 |
|
---|
2038 | /* Wait for autoload done bit. */
|
---|
2039 | for (ntries = 0; ntries < 1000; ntries++) {
|
---|
2040 | if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
|
---|
2041 | break;
|
---|
2042 | DELAY(5);
|
---|
2043 | }
|
---|
2044 | if (ntries == 1000) {
|
---|
2045 | printf("%s: timeout waiting for chip autoload\n",
|
---|
2046 | sc->sc_dev.dv_xname);
|
---|
2047 | return (ETIMEDOUT);
|
---|
2048 | }
|
---|
2049 |
|
---|
2050 | /* Unlock ISO/CLK/Power control register. */
|
---|
2051 | urtwn_write_1(sc, R92C_RSV_CTRL, 0);
|
---|
2052 | /* Move SPS into PWM mode. */
|
---|
2053 | urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
|
---|
2054 | DELAY(100);
|
---|
2055 |
|
---|
2056 | reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL);
|
---|
2057 | if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) {
|
---|
2058 | urtwn_write_1(sc, R92C_LDOV12D_CTRL,
|
---|
2059 | reg | R92C_LDOV12D_CTRL_LDV12_EN);
|
---|
2060 | DELAY(100);
|
---|
2061 | urtwn_write_1(sc, R92C_SYS_ISO_CTRL,
|
---|
2062 | urtwn_read_1(sc, R92C_SYS_ISO_CTRL) &
|
---|
2063 | ~R92C_SYS_ISO_CTRL_MD2PP);
|
---|
2064 | }
|
---|
2065 |
|
---|
2066 | /* Auto enable WLAN. */
|
---|
2067 | urtwn_write_2(sc, R92C_APS_FSMCO,
|
---|
2068 | urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
|
---|
2069 | for (ntries = 0; ntries < 1000; ntries++) {
|
---|
2070 | if (urtwn_read_2(sc, R92C_APS_FSMCO) &
|
---|
2071 | R92C_APS_FSMCO_APFM_ONMAC)
|
---|
2072 | break;
|
---|
2073 | DELAY(5);
|
---|
2074 | }
|
---|
2075 | if (ntries == 1000) {
|
---|
2076 | printf("%s: timeout waiting for MAC auto ON\n",
|
---|
2077 | sc->sc_dev.dv_xname);
|
---|
2078 | return (ETIMEDOUT);
|
---|
2079 | }
|
---|
2080 |
|
---|
2081 | /* Enable radio, GPIO and LED functions. */
|
---|
2082 | urtwn_write_2(sc, R92C_APS_FSMCO,
|
---|
2083 | R92C_APS_FSMCO_AFSM_HSUS |
|
---|
2084 | R92C_APS_FSMCO_PDN_EN |
|
---|
2085 | R92C_APS_FSMCO_PFM_ALDN);
|
---|
2086 | /* Release RF digital isolation. */
|
---|
2087 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL,
|
---|
2088 | urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
|
---|
2089 |
|
---|
2090 | /* Initialize MAC. */
|
---|
2091 | urtwn_write_1(sc, R92C_APSD_CTRL,
|
---|
2092 | urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
|
---|
2093 | for (ntries = 0; ntries < 200; ntries++) {
|
---|
2094 | if (!(urtwn_read_1(sc, R92C_APSD_CTRL) &
|
---|
2095 | R92C_APSD_CTRL_OFF_STATUS))
|
---|
2096 | break;
|
---|
2097 | DELAY(5);
|
---|
2098 | }
|
---|
2099 | if (ntries == 200) {
|
---|
2100 | printf("%s: timeout waiting for MAC initialization\n",
|
---|
2101 | sc->sc_dev.dv_xname);
|
---|
2102 | return (ETIMEDOUT);
|
---|
2103 | }
|
---|
2104 |
|
---|
2105 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
|
---|
2106 | reg = urtwn_read_2(sc, R92C_CR);
|
---|
2107 | reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
|
---|
2108 | R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
|
---|
2109 | R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
|
---|
2110 | R92C_CR_ENSEC;
|
---|
2111 | urtwn_write_2(sc, R92C_CR, reg);
|
---|
2112 |
|
---|
2113 | urtwn_write_1(sc, 0xfe10, 0x19);
|
---|
2114 | return (0);
|
---|
2115 | }
|
---|
2116 |
|
---|
2117 | int
|
---|
2118 | urtwn_llt_init(struct urtwn_softc *sc)
|
---|
2119 | {
|
---|
2120 | int i, error;
|
---|
2121 |
|
---|
2122 | /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */
|
---|
2123 | for (i = 0; i < R92C_TX_PAGE_COUNT; i++) {
|
---|
2124 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0)
|
---|
2125 | return (error);
|
---|
2126 | }
|
---|
2127 | /* NB: 0xff indicates end-of-list. */
|
---|
2128 | if ((error = urtwn_llt_write(sc, i, 0xff)) != 0)
|
---|
2129 | return (error);
|
---|
2130 | /*
|
---|
2131 | * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1]
|
---|
2132 | * as ring buffer.
|
---|
2133 | */
|
---|
2134 | for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) {
|
---|
2135 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0)
|
---|
2136 | return (error);
|
---|
2137 | }
|
---|
2138 | /* Make the last page point to the beginning of the ring buffer. */
|
---|
2139 | error = urtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1);
|
---|
2140 | return (error);
|
---|
2141 | }
|
---|
2142 |
|
---|
2143 | void
|
---|
2144 | urtwn_fw_reset(struct urtwn_softc *sc)
|
---|
2145 | {
|
---|
2146 | uint16_t reg;
|
---|
2147 | int ntries;
|
---|
2148 |
|
---|
2149 | /* Tell 8051 to reset itself. */
|
---|
2150 | urtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
|
---|
2151 |
|
---|
2152 | /* Wait until 8051 resets by itself. */
|
---|
2153 | for (ntries = 0; ntries < 100; ntries++) {
|
---|
2154 | reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN);
|
---|
2155 | if (!(reg & R92C_SYS_FUNC_EN_CPUEN))
|
---|
2156 | return;
|
---|
2157 | DELAY(50);
|
---|
2158 | }
|
---|
2159 | /* Force 8051 reset. */
|
---|
2160 | urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
|
---|
2161 | }
|
---|
2162 |
|
---|
2163 | int
|
---|
2164 | urtwn_fw_loadpage(struct urtwn_softc *sc, int page, uint8_t *buf, int len)
|
---|
2165 | {
|
---|
2166 | uint32_t reg;
|
---|
2167 | int off, mlen, error = 0;
|
---|
2168 |
|
---|
2169 | reg = urtwn_read_4(sc, R92C_MCUFWDL);
|
---|
2170 | reg = RW(reg, R92C_MCUFWDL_PAGE, page);
|
---|
2171 | urtwn_write_4(sc, R92C_MCUFWDL, reg);
|
---|
2172 |
|
---|
2173 | off = R92C_FW_START_ADDR;
|
---|
2174 | while (len > 0) {
|
---|
2175 | if (len > 196)
|
---|
2176 | mlen = 196;
|
---|
2177 | else if (len > 4)
|
---|
2178 | mlen = 4;
|
---|
2179 | else
|
---|
2180 | mlen = 1;
|
---|
2181 | error = urtwn_write_region_1(sc, off, buf, mlen);
|
---|
2182 | if (error != 0)
|
---|
2183 | break;
|
---|
2184 | off += mlen;
|
---|
2185 | buf += mlen;
|
---|
2186 | len -= mlen;
|
---|
2187 | }
|
---|
2188 | return (error);
|
---|
2189 | }
|
---|
2190 |
|
---|
2191 | int
|
---|
2192 | urtwn_load_firmware(struct urtwn_softc *sc)
|
---|
2193 | {
|
---|
2194 | const struct r92c_fw_hdr *hdr;
|
---|
2195 | const char *name;
|
---|
2196 | u_char *fw, *ptr;
|
---|
2197 | size_t len;
|
---|
2198 | uint32_t reg;
|
---|
2199 | int mlen, ntries, page, error;
|
---|
2200 |
|
---|
2201 | /* Read firmware image from the filesystem. */
|
---|
2202 | if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) ==
|
---|
2203 | URTWN_CHIP_UMC_A_CUT)
|
---|
2204 | name = "urtwn-rtl8192cfwU";
|
---|
2205 | else
|
---|
2206 | name = "urtwn-rtl8192cfwT";
|
---|
2207 | if ((error = loadfirmware(name, &fw, &len)) != 0) {
|
---|
2208 | printf("%s: failed loadfirmware of file %s (error %d)\n",
|
---|
2209 | sc->sc_dev.dv_xname, name, error);
|
---|
2210 | return (error);
|
---|
2211 | }
|
---|
2212 | if (len < sizeof(*hdr)) {
|
---|
2213 | printf("%s: firmware too short\n", sc->sc_dev.dv_xname);
|
---|
2214 | error = EINVAL;
|
---|
2215 | goto fail;
|
---|
2216 | }
|
---|
2217 | ptr = fw;
|
---|
2218 | hdr = (const struct r92c_fw_hdr *)ptr;
|
---|
2219 | /* Check if there is a valid FW header and skip it. */
|
---|
2220 | if ((letoh16(hdr->signature) >> 4) == 0x88c ||
|
---|
2221 | (letoh16(hdr->signature) >> 4) == 0x92c) {
|
---|
2222 | DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n",
|
---|
2223 | letoh16(hdr->version), letoh16(hdr->subversion),
|
---|
2224 | hdr->month, hdr->date, hdr->hour, hdr->minute));
|
---|
2225 | ptr += sizeof(*hdr);
|
---|
2226 | len -= sizeof(*hdr);
|
---|
2227 | }
|
---|
2228 |
|
---|
2229 | if (urtwn_read_1(sc, R92C_MCUFWDL) & 0x80) {
|
---|
2230 | urtwn_fw_reset(sc);
|
---|
2231 | urtwn_write_1(sc, R92C_MCUFWDL, 0);
|
---|
2232 | }
|
---|
2233 | urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
---|
2234 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) |
|
---|
2235 | R92C_SYS_FUNC_EN_CPUEN);
|
---|
2236 | urtwn_write_1(sc, R92C_MCUFWDL,
|
---|
2237 | urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
|
---|
2238 | urtwn_write_1(sc, R92C_MCUFWDL + 2,
|
---|
2239 | urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08);
|
---|
2240 |
|
---|
2241 | for (page = 0; len > 0; page++) {
|
---|
2242 | mlen = MIN(len, R92C_FW_PAGE_SIZE);
|
---|
2243 | error = urtwn_fw_loadpage(sc, page, ptr, mlen);
|
---|
2244 | if (error != 0) {
|
---|
2245 | printf("%s: could not load firmware page %d\n",
|
---|
2246 | sc->sc_dev.dv_xname, page);
|
---|
2247 | goto fail;
|
---|
2248 | }
|
---|
2249 | ptr += mlen;
|
---|
2250 | len -= mlen;
|
---|
2251 | }
|
---|
2252 | urtwn_write_1(sc, R92C_MCUFWDL,
|
---|
2253 | urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN);
|
---|
2254 | urtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
|
---|
2255 |
|
---|
2256 | /* Wait for checksum report. */
|
---|
2257 | for (ntries = 0; ntries < 1000; ntries++) {
|
---|
2258 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
|
---|
2259 | break;
|
---|
2260 | DELAY(5);
|
---|
2261 | }
|
---|
2262 | if (ntries == 1000) {
|
---|
2263 | printf("%s: timeout waiting for checksum report\n",
|
---|
2264 | sc->sc_dev.dv_xname);
|
---|
2265 | error = ETIMEDOUT;
|
---|
2266 | goto fail;
|
---|
2267 | }
|
---|
2268 |
|
---|
2269 | reg = urtwn_read_4(sc, R92C_MCUFWDL);
|
---|
2270 | reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
|
---|
2271 | urtwn_write_4(sc, R92C_MCUFWDL, reg);
|
---|
2272 | /* Wait for firmware readiness. */
|
---|
2273 | for (ntries = 0; ntries < 1000; ntries++) {
|
---|
2274 | if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
|
---|
2275 | break;
|
---|
2276 | DELAY(5);
|
---|
2277 | }
|
---|
2278 | if (ntries == 1000) {
|
---|
2279 | printf("%s: timeout waiting for firmware readiness\n",
|
---|
2280 | sc->sc_dev.dv_xname);
|
---|
2281 | error = ETIMEDOUT;
|
---|
2282 | goto fail;
|
---|
2283 | }
|
---|
2284 | fail:
|
---|
2285 | free(fw, M_DEVBUF);
|
---|
2286 | return (error);
|
---|
2287 | }
|
---|
2288 |
|
---|
2289 | int
|
---|
2290 | urtwn_dma_init(struct urtwn_softc *sc)
|
---|
2291 | {
|
---|
2292 | int hashq, hasnq, haslq, nqueues, nqpages, nrempages;
|
---|
2293 | uint32_t reg;
|
---|
2294 | int error;
|
---|
2295 |
|
---|
2296 | /* Initialize LLT table. */
|
---|
2297 | error = urtwn_llt_init(sc);
|
---|
2298 | if (error != 0)
|
---|
2299 | return (error);
|
---|
2300 |
|
---|
2301 | /* Get Tx queues to USB endpoints mapping. */
|
---|
2302 | hashq = hasnq = haslq = 0;
|
---|
2303 | reg = urtwn_read_2(sc, R92C_USB_EP + 1);
|
---|
2304 | DPRINTFN(2, ("USB endpoints mapping 0x%x\n", reg));
|
---|
2305 | if (MS(reg, R92C_USB_EP_HQ) != 0)
|
---|
2306 | hashq = 1;
|
---|
2307 | if (MS(reg, R92C_USB_EP_NQ) != 0)
|
---|
2308 | hasnq = 1;
|
---|
2309 | if (MS(reg, R92C_USB_EP_LQ) != 0)
|
---|
2310 | haslq = 1;
|
---|
2311 | nqueues = hashq + hasnq + haslq;
|
---|
2312 | if (nqueues == 0)
|
---|
2313 | return (EIO);
|
---|
2314 | /* Get the number of pages for each queue. */
|
---|
2315 | nqpages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) / nqueues;
|
---|
2316 | /* The remaining pages are assigned to the high priority queue. */
|
---|
2317 | nrempages = (R92C_TX_PAGE_COUNT - R92C_PUBQ_NPAGES) % nqueues;
|
---|
2318 |
|
---|
2319 | /* Set number of pages for normal priority queue. */
|
---|
2320 | urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0);
|
---|
2321 | urtwn_write_4(sc, R92C_RQPN,
|
---|
2322 | /* Set number of pages for public queue. */
|
---|
2323 | SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) |
|
---|
2324 | /* Set number of pages for high priority queue. */
|
---|
2325 | SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) |
|
---|
2326 | /* Set number of pages for low priority queue. */
|
---|
2327 | SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) |
|
---|
2328 | /* Load values. */
|
---|
2329 | R92C_RQPN_LD);
|
---|
2330 |
|
---|
2331 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY);
|
---|
2332 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY);
|
---|
2333 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY);
|
---|
2334 | urtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY);
|
---|
2335 | urtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY);
|
---|
2336 |
|
---|
2337 | /* Set queue to USB pipe mapping. */
|
---|
2338 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL);
|
---|
2339 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M;
|
---|
2340 | if (nqueues == 1) {
|
---|
2341 | if (hashq)
|
---|
2342 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ;
|
---|
2343 | else if (hasnq)
|
---|
2344 | reg |= R92C_TRXDMA_CTRL_QMAP_NQ;
|
---|
2345 | else
|
---|
2346 | reg |= R92C_TRXDMA_CTRL_QMAP_LQ;
|
---|
2347 | } else if (nqueues == 2) {
|
---|
2348 | /* All 2-endpoints configs have a high priority queue. */
|
---|
2349 | if (!hashq)
|
---|
2350 | return (EIO);
|
---|
2351 | if (hasnq)
|
---|
2352 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ;
|
---|
2353 | else
|
---|
2354 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_LQ;
|
---|
2355 | } else
|
---|
2356 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP;
|
---|
2357 | urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg);
|
---|
2358 |
|
---|
2359 | /* Set Tx/Rx transfer page boundary. */
|
---|
2360 | urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff);
|
---|
2361 |
|
---|
2362 | /* Set Tx/Rx transfer page size. */
|
---|
2363 | urtwn_write_1(sc, R92C_PBP,
|
---|
2364 | SM(R92C_PBP_PSRX, R92C_PBP_128) |
|
---|
2365 | SM(R92C_PBP_PSTX, R92C_PBP_128));
|
---|
2366 | return (0);
|
---|
2367 | }
|
---|
2368 |
|
---|
2369 | void
|
---|
2370 | urtwn_mac_init(struct urtwn_softc *sc)
|
---|
2371 | {
|
---|
2372 | int i;
|
---|
2373 |
|
---|
2374 | /* Write MAC initialization values. */
|
---|
2375 | for (i = 0; i < nitems(rtl8192cu_mac); i++)
|
---|
2376 | urtwn_write_1(sc, rtl8192cu_mac[i].reg, rtl8192cu_mac[i].val);
|
---|
2377 | }
|
---|
2378 |
|
---|
2379 | void
|
---|
2380 | urtwn_bb_init(struct urtwn_softc *sc)
|
---|
2381 | {
|
---|
2382 | const struct urtwn_bb_prog *prog;
|
---|
2383 | uint32_t reg;
|
---|
2384 | int i;
|
---|
2385 |
|
---|
2386 | /* Enable BB and RF. */
|
---|
2387 | urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
---|
2388 | urtwn_read_2(sc, R92C_SYS_FUNC_EN) |
|
---|
2389 | R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
|
---|
2390 | R92C_SYS_FUNC_EN_DIO_RF);
|
---|
2391 |
|
---|
2392 | urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
|
---|
2393 |
|
---|
2394 | urtwn_write_1(sc, R92C_RF_CTRL,
|
---|
2395 | R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
|
---|
2396 | urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
---|
2397 | R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD |
|
---|
2398 | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB);
|
---|
2399 |
|
---|
2400 | urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f);
|
---|
2401 | urtwn_write_1(sc, 0x15, 0xe9);
|
---|
2402 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
|
---|
2403 |
|
---|
2404 | /* Select BB programming based on board type. */
|
---|
2405 | if (!(sc->chip & URTWN_CHIP_92C)) {
|
---|
2406 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
---|
2407 | prog = &rtl8188ce_bb_prog;
|
---|
2408 | else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
---|
2409 | prog = &rtl8188ru_bb_prog;
|
---|
2410 | else
|
---|
2411 | prog = &rtl8188cu_bb_prog;
|
---|
2412 | } else {
|
---|
2413 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
---|
2414 | prog = &rtl8192ce_bb_prog;
|
---|
2415 | else
|
---|
2416 | prog = &rtl8192cu_bb_prog;
|
---|
2417 | }
|
---|
2418 | /* Write BB initialization values. */
|
---|
2419 | for (i = 0; i < prog->count; i++) {
|
---|
2420 | urtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
|
---|
2421 | DELAY(1);
|
---|
2422 | }
|
---|
2423 |
|
---|
2424 | if (sc->chip & URTWN_CHIP_92C_1T2R) {
|
---|
2425 | /* 8192C 1T only configuration. */
|
---|
2426 | reg = urtwn_bb_read(sc, R92C_FPGA0_TXINFO);
|
---|
2427 | reg = (reg & ~0x00000003) | 0x2;
|
---|
2428 | urtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
|
---|
2429 |
|
---|
2430 | reg = urtwn_bb_read(sc, R92C_FPGA1_TXINFO);
|
---|
2431 | reg = (reg & ~0x00300033) | 0x00200022;
|
---|
2432 | urtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
|
---|
2433 |
|
---|
2434 | reg = urtwn_bb_read(sc, R92C_CCK0_AFESETTING);
|
---|
2435 | reg = (reg & ~0xff000000) | 0x45 << 24;
|
---|
2436 | urtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
|
---|
2437 |
|
---|
2438 | reg = urtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
|
---|
2439 | reg = (reg & ~0x000000ff) | 0x23;
|
---|
2440 | urtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
|
---|
2441 |
|
---|
2442 | reg = urtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
|
---|
2443 | reg = (reg & ~0x00000030) | 1 << 4;
|
---|
2444 | urtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
|
---|
2445 |
|
---|
2446 | reg = urtwn_bb_read(sc, 0xe74);
|
---|
2447 | reg = (reg & ~0x0c000000) | 2 << 26;
|
---|
2448 | urtwn_bb_write(sc, 0xe74, reg);
|
---|
2449 | reg = urtwn_bb_read(sc, 0xe78);
|
---|
2450 | reg = (reg & ~0x0c000000) | 2 << 26;
|
---|
2451 | urtwn_bb_write(sc, 0xe78, reg);
|
---|
2452 | reg = urtwn_bb_read(sc, 0xe7c);
|
---|
2453 | reg = (reg & ~0x0c000000) | 2 << 26;
|
---|
2454 | urtwn_bb_write(sc, 0xe7c, reg);
|
---|
2455 | reg = urtwn_bb_read(sc, 0xe80);
|
---|
2456 | reg = (reg & ~0x0c000000) | 2 << 26;
|
---|
2457 | urtwn_bb_write(sc, 0xe80, reg);
|
---|
2458 | reg = urtwn_bb_read(sc, 0xe88);
|
---|
2459 | reg = (reg & ~0x0c000000) | 2 << 26;
|
---|
2460 | urtwn_bb_write(sc, 0xe88, reg);
|
---|
2461 | }
|
---|
2462 |
|
---|
2463 | /* Write AGC values. */
|
---|
2464 | for (i = 0; i < prog->agccount; i++) {
|
---|
2465 | urtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
|
---|
2466 | prog->agcvals[i]);
|
---|
2467 | DELAY(1);
|
---|
2468 | }
|
---|
2469 |
|
---|
2470 | if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
|
---|
2471 | R92C_HSSI_PARAM2_CCK_HIPWR)
|
---|
2472 | sc->sc_flags |= URTWN_FLAG_CCK_HIPWR;
|
---|
2473 | }
|
---|
2474 |
|
---|
2475 | void
|
---|
2476 | urtwn_rf_init(struct urtwn_softc *sc)
|
---|
2477 | {
|
---|
2478 | const struct urtwn_rf_prog *prog;
|
---|
2479 | uint32_t reg, type;
|
---|
2480 | int i, j, idx, off;
|
---|
2481 |
|
---|
2482 | /* Select RF programming based on board type. */
|
---|
2483 | if (!(sc->chip & URTWN_CHIP_92C)) {
|
---|
2484 | if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
---|
2485 | prog = rtl8188ce_rf_prog;
|
---|
2486 | else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
---|
2487 | prog = rtl8188ru_rf_prog;
|
---|
2488 | else
|
---|
2489 | prog = rtl8188cu_rf_prog;
|
---|
2490 | } else
|
---|
2491 | prog = rtl8192ce_rf_prog;
|
---|
2492 |
|
---|
2493 | for (i = 0; i < sc->nrxchains; i++) {
|
---|
2494 | /* Save RF_ENV control type. */
|
---|
2495 | idx = i / 2;
|
---|
2496 | off = (i % 2) * 16;
|
---|
2497 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
|
---|
2498 | type = (reg >> off) & 0x10;
|
---|
2499 |
|
---|
2500 | /* Set RF_ENV enable. */
|
---|
2501 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
|
---|
2502 | reg |= 0x100000;
|
---|
2503 | urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
|
---|
2504 | DELAY(1);
|
---|
2505 | /* Set RF_ENV output high. */
|
---|
2506 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
|
---|
2507 | reg |= 0x10;
|
---|
2508 | urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
|
---|
2509 | DELAY(1);
|
---|
2510 | /* Set address and data lengths of RF registers. */
|
---|
2511 | reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
|
---|
2512 | reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH;
|
---|
2513 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
|
---|
2514 | DELAY(1);
|
---|
2515 | reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
|
---|
2516 | reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH;
|
---|
2517 | urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
|
---|
2518 | DELAY(1);
|
---|
2519 |
|
---|
2520 | /* Write RF initialization values for this chain. */
|
---|
2521 | for (j = 0; j < prog[i].count; j++) {
|
---|
2522 | if (prog[i].regs[j] >= 0xf9 &&
|
---|
2523 | prog[i].regs[j] <= 0xfe) {
|
---|
2524 | /*
|
---|
2525 | * These are fake RF registers offsets that
|
---|
2526 | * indicate a delay is required.
|
---|
2527 | */
|
---|
2528 | usbd_delay_ms(sc->sc_udev, 50);
|
---|
2529 | continue;
|
---|
2530 | }
|
---|
2531 | urtwn_rf_write(sc, i, prog[i].regs[j],
|
---|
2532 | prog[i].vals[j]);
|
---|
2533 | DELAY(1);
|
---|
2534 | }
|
---|
2535 |
|
---|
2536 | /* Restore RF_ENV control type. */
|
---|
2537 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
|
---|
2538 | reg &= ~(0x10 << off) | (type << off);
|
---|
2539 | urtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg);
|
---|
2540 |
|
---|
2541 | /* Cache RF register CHNLBW. */
|
---|
2542 | sc->rf_chnlbw[i] = urtwn_rf_read(sc, i, R92C_RF_CHNLBW);
|
---|
2543 | }
|
---|
2544 |
|
---|
2545 | if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) ==
|
---|
2546 | URTWN_CHIP_UMC_A_CUT) {
|
---|
2547 | urtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
|
---|
2548 | urtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
|
---|
2549 | }
|
---|
2550 | }
|
---|
2551 |
|
---|
2552 | void
|
---|
2553 | urtwn_cam_init(struct urtwn_softc *sc)
|
---|
2554 | {
|
---|
2555 | /* Invalidate all CAM entries. */
|
---|
2556 | urtwn_write_4(sc, R92C_CAMCMD,
|
---|
2557 | R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
|
---|
2558 | }
|
---|
2559 |
|
---|
2560 | void
|
---|
2561 | urtwn_pa_bias_init(struct urtwn_softc *sc)
|
---|
2562 | {
|
---|
2563 | uint8_t reg;
|
---|
2564 | int i;
|
---|
2565 |
|
---|
2566 | for (i = 0; i < sc->nrxchains; i++) {
|
---|
2567 | if (sc->pa_setting & (1 << i))
|
---|
2568 | continue;
|
---|
2569 | urtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
|
---|
2570 | urtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
|
---|
2571 | urtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
|
---|
2572 | urtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
|
---|
2573 | }
|
---|
2574 | if (!(sc->pa_setting & 0x10)) {
|
---|
2575 | reg = urtwn_read_1(sc, 0x16);
|
---|
2576 | reg = (reg & ~0xf0) | 0x90;
|
---|
2577 | urtwn_write_1(sc, 0x16, reg);
|
---|
2578 | }
|
---|
2579 | }
|
---|
2580 |
|
---|
2581 | void
|
---|
2582 | urtwn_rxfilter_init(struct urtwn_softc *sc)
|
---|
2583 | {
|
---|
2584 | /* Initialize Rx filter. */
|
---|
2585 | /* TODO: use better filter for monitor mode. */
|
---|
2586 | urtwn_write_4(sc, R92C_RCR,
|
---|
2587 | R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB |
|
---|
2588 | R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL |
|
---|
2589 | R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS);
|
---|
2590 | /* Accept all multicast frames. */
|
---|
2591 | urtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
|
---|
2592 | urtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
|
---|
2593 | /* Accept all management frames. */
|
---|
2594 | urtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff);
|
---|
2595 | /* Reject all control frames. */
|
---|
2596 | urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
|
---|
2597 | /* Accept all data frames. */
|
---|
2598 | urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
|
---|
2599 | }
|
---|
2600 |
|
---|
2601 | void
|
---|
2602 | urtwn_edca_init(struct urtwn_softc *sc)
|
---|
2603 | {
|
---|
2604 | urtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a);
|
---|
2605 | urtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a);
|
---|
2606 | urtwn_write_2(sc, R92C_SIFS_CCK, 0x100a);
|
---|
2607 | urtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a);
|
---|
2608 | urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
|
---|
2609 | urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
|
---|
2610 | urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324);
|
---|
2611 | urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226);
|
---|
2612 | }
|
---|
2613 |
|
---|
2614 | void
|
---|
2615 | urtwn_write_txpower(struct urtwn_softc *sc, int chain,
|
---|
2616 | uint16_t power[URTWN_RIDX_COUNT])
|
---|
2617 | {
|
---|
2618 | uint32_t reg;
|
---|
2619 |
|
---|
2620 | /* Write per-CCK rate Tx power. */
|
---|
2621 | if (chain == 0) {
|
---|
2622 | reg = urtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
|
---|
2623 | reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]);
|
---|
2624 | urtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
|
---|
2625 | reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
|
---|
2626 | reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]);
|
---|
2627 | reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]);
|
---|
2628 | reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]);
|
---|
2629 | urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
|
---|
2630 | } else {
|
---|
2631 | reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
|
---|
2632 | reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]);
|
---|
2633 | reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]);
|
---|
2634 | reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]);
|
---|
2635 | urtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
|
---|
2636 | reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
|
---|
2637 | reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]);
|
---|
2638 | urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
|
---|
2639 | }
|
---|
2640 | /* Write per-OFDM rate Tx power. */
|
---|
2641 | urtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
|
---|
2642 | SM(R92C_TXAGC_RATE06, power[ 4]) |
|
---|
2643 | SM(R92C_TXAGC_RATE09, power[ 5]) |
|
---|
2644 | SM(R92C_TXAGC_RATE12, power[ 6]) |
|
---|
2645 | SM(R92C_TXAGC_RATE18, power[ 7]));
|
---|
2646 | urtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
|
---|
2647 | SM(R92C_TXAGC_RATE24, power[ 8]) |
|
---|
2648 | SM(R92C_TXAGC_RATE36, power[ 9]) |
|
---|
2649 | SM(R92C_TXAGC_RATE48, power[10]) |
|
---|
2650 | SM(R92C_TXAGC_RATE54, power[11]));
|
---|
2651 | /* Write per-MCS Tx power. */
|
---|
2652 | urtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
|
---|
2653 | SM(R92C_TXAGC_MCS00, power[12]) |
|
---|
2654 | SM(R92C_TXAGC_MCS01, power[13]) |
|
---|
2655 | SM(R92C_TXAGC_MCS02, power[14]) |
|
---|
2656 | SM(R92C_TXAGC_MCS03, power[15]));
|
---|
2657 | urtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
|
---|
2658 | SM(R92C_TXAGC_MCS04, power[16]) |
|
---|
2659 | SM(R92C_TXAGC_MCS05, power[17]) |
|
---|
2660 | SM(R92C_TXAGC_MCS06, power[18]) |
|
---|
2661 | SM(R92C_TXAGC_MCS07, power[19]));
|
---|
2662 | urtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
|
---|
2663 | SM(R92C_TXAGC_MCS08, power[20]) |
|
---|
2664 | SM(R92C_TXAGC_MCS08, power[21]) |
|
---|
2665 | SM(R92C_TXAGC_MCS10, power[22]) |
|
---|
2666 | SM(R92C_TXAGC_MCS11, power[23]));
|
---|
2667 | urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
|
---|
2668 | SM(R92C_TXAGC_MCS12, power[24]) |
|
---|
2669 | SM(R92C_TXAGC_MCS13, power[25]) |
|
---|
2670 | SM(R92C_TXAGC_MCS14, power[26]) |
|
---|
2671 | SM(R92C_TXAGC_MCS15, power[27]));
|
---|
2672 | }
|
---|
2673 |
|
---|
2674 | void
|
---|
2675 | urtwn_get_txpower(struct urtwn_softc *sc, int chain,
|
---|
2676 | struct ieee80211_channel *c, struct ieee80211_channel *extc,
|
---|
2677 | uint16_t power[URTWN_RIDX_COUNT])
|
---|
2678 | {
|
---|
2679 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
2680 | struct r92c_rom *rom = &sc->rom;
|
---|
2681 | uint16_t cckpow, ofdmpow, htpow, diff, max;
|
---|
2682 | const struct urtwn_txpwr *base;
|
---|
2683 | int ridx, chan, group;
|
---|
2684 |
|
---|
2685 | /* Determine channel group. */
|
---|
2686 | chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
|
---|
2687 | if (chan <= 3)
|
---|
2688 | group = 0;
|
---|
2689 | else if (chan <= 9)
|
---|
2690 | group = 1;
|
---|
2691 | else
|
---|
2692 | group = 2;
|
---|
2693 |
|
---|
2694 | /* Get original Tx power based on board type and RF chain. */
|
---|
2695 | if (!(sc->chip & URTWN_CHIP_92C)) {
|
---|
2696 | if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
---|
2697 | base = &rtl8188ru_txagc[chain];
|
---|
2698 | else
|
---|
2699 | base = &rtl8192cu_txagc[chain];
|
---|
2700 | } else
|
---|
2701 | base = &rtl8192cu_txagc[chain];
|
---|
2702 |
|
---|
2703 | memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0]));
|
---|
2704 | if (sc->regulatory == 0) {
|
---|
2705 | for (ridx = 0; ridx <= 3; ridx++)
|
---|
2706 | power[ridx] = base->pwr[0][ridx];
|
---|
2707 | }
|
---|
2708 | for (ridx = 4; ridx < URTWN_RIDX_COUNT; ridx++) {
|
---|
2709 | if (sc->regulatory == 3) {
|
---|
2710 | power[ridx] = base->pwr[0][ridx];
|
---|
2711 | /* Apply vendor limits. */
|
---|
2712 | if (extc != NULL)
|
---|
2713 | max = rom->ht40_max_pwr[group];
|
---|
2714 | else
|
---|
2715 | max = rom->ht20_max_pwr[group];
|
---|
2716 | max = (max >> (chain * 4)) & 0xf;
|
---|
2717 | if (power[ridx] > max)
|
---|
2718 | power[ridx] = max;
|
---|
2719 | } else if (sc->regulatory == 1) {
|
---|
2720 | if (extc == NULL)
|
---|
2721 | power[ridx] = base->pwr[group][ridx];
|
---|
2722 | } else if (sc->regulatory != 2)
|
---|
2723 | power[ridx] = base->pwr[0][ridx];
|
---|
2724 | }
|
---|
2725 |
|
---|
2726 | /* Compute per-CCK rate Tx power. */
|
---|
2727 | cckpow = rom->cck_tx_pwr[chain][group];
|
---|
2728 | for (ridx = 0; ridx <= 3; ridx++) {
|
---|
2729 | power[ridx] += cckpow;
|
---|
2730 | if (power[ridx] > R92C_MAX_TX_PWR)
|
---|
2731 | power[ridx] = R92C_MAX_TX_PWR;
|
---|
2732 | }
|
---|
2733 |
|
---|
2734 | htpow = rom->ht40_1s_tx_pwr[chain][group];
|
---|
2735 | if (sc->ntxchains > 1) {
|
---|
2736 | /* Apply reduction for 2 spatial streams. */
|
---|
2737 | diff = rom->ht40_2s_tx_pwr_diff[group];
|
---|
2738 | diff = (diff >> (chain * 4)) & 0xf;
|
---|
2739 | htpow = (htpow > diff) ? htpow - diff : 0;
|
---|
2740 | }
|
---|
2741 |
|
---|
2742 | /* Compute per-OFDM rate Tx power. */
|
---|
2743 | diff = rom->ofdm_tx_pwr_diff[group];
|
---|
2744 | diff = (diff >> (chain * 4)) & 0xf;
|
---|
2745 | ofdmpow = htpow + diff; /* HT->OFDM correction. */
|
---|
2746 | for (ridx = 4; ridx <= 11; ridx++) {
|
---|
2747 | power[ridx] += ofdmpow;
|
---|
2748 | if (power[ridx] > R92C_MAX_TX_PWR)
|
---|
2749 | power[ridx] = R92C_MAX_TX_PWR;
|
---|
2750 | }
|
---|
2751 |
|
---|
2752 | /* Compute per-MCS Tx power. */
|
---|
2753 | if (extc == NULL) {
|
---|
2754 | diff = rom->ht20_tx_pwr_diff[group];
|
---|
2755 | diff = (diff >> (chain * 4)) & 0xf;
|
---|
2756 | htpow += diff; /* HT40->HT20 correction. */
|
---|
2757 | }
|
---|
2758 | for (ridx = 12; ridx <= 27; ridx++) {
|
---|
2759 | power[ridx] += htpow;
|
---|
2760 | if (power[ridx] > R92C_MAX_TX_PWR)
|
---|
2761 | power[ridx] = R92C_MAX_TX_PWR;
|
---|
2762 | }
|
---|
2763 | #ifdef URTWN_DEBUG
|
---|
2764 | if (urtwn_debug >= 4) {
|
---|
2765 | /* Dump per-rate Tx power values. */
|
---|
2766 | printf("Tx power for chain %d:\n", chain);
|
---|
2767 | for (ridx = 0; ridx < URTWN_RIDX_COUNT; ridx++)
|
---|
2768 | printf("Rate %d = %u\n", ridx, power[ridx]);
|
---|
2769 | }
|
---|
2770 | #endif
|
---|
2771 | }
|
---|
2772 |
|
---|
2773 | void
|
---|
2774 | urtwn_set_txpower(struct urtwn_softc *sc, struct ieee80211_channel *c,
|
---|
2775 | struct ieee80211_channel *extc)
|
---|
2776 | {
|
---|
2777 | uint16_t power[URTWN_RIDX_COUNT];
|
---|
2778 | int i;
|
---|
2779 |
|
---|
2780 | for (i = 0; i < sc->ntxchains; i++) {
|
---|
2781 | /* Compute per-rate Tx power values. */
|
---|
2782 | urtwn_get_txpower(sc, i, c, extc, power);
|
---|
2783 | /* Write per-rate Tx power values to hardware. */
|
---|
2784 | urtwn_write_txpower(sc, i, power);
|
---|
2785 | }
|
---|
2786 | }
|
---|
2787 |
|
---|
2788 | void
|
---|
2789 | urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c,
|
---|
2790 | struct ieee80211_channel *extc)
|
---|
2791 | {
|
---|
2792 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
2793 | uint32_t reg;
|
---|
2794 | u_int chan;
|
---|
2795 | int i;
|
---|
2796 |
|
---|
2797 | chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
|
---|
2798 |
|
---|
2799 | /* Set Tx power for this new channel. */
|
---|
2800 | urtwn_set_txpower(sc, c, extc);
|
---|
2801 |
|
---|
2802 | for (i = 0; i < sc->nrxchains; i++) {
|
---|
2803 | urtwn_rf_write(sc, i, R92C_RF_CHNLBW,
|
---|
2804 | RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
|
---|
2805 | }
|
---|
2806 | #ifndef IEEE80211_NO_HT
|
---|
2807 | if (extc != NULL) {
|
---|
2808 | /* Is secondary channel below or above primary? */
|
---|
2809 | int prichlo = c->ic_freq < extc->ic_freq;
|
---|
2810 |
|
---|
2811 | urtwn_write_1(sc, R92C_BWOPMODE,
|
---|
2812 | urtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ);
|
---|
2813 |
|
---|
2814 | reg = urtwn_read_1(sc, R92C_RRSR + 2);
|
---|
2815 | reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5;
|
---|
2816 | urtwn_write_1(sc, R92C_RRSR + 2, reg);
|
---|
2817 |
|
---|
2818 | urtwn_bb_write(sc, R92C_FPGA0_RFMOD,
|
---|
2819 | urtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ);
|
---|
2820 | urtwn_bb_write(sc, R92C_FPGA1_RFMOD,
|
---|
2821 | urtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ);
|
---|
2822 |
|
---|
2823 | /* Set CCK side band. */
|
---|
2824 | reg = urtwn_bb_read(sc, R92C_CCK0_SYSTEM);
|
---|
2825 | reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4;
|
---|
2826 | urtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg);
|
---|
2827 |
|
---|
2828 | reg = urtwn_bb_read(sc, R92C_OFDM1_LSTF);
|
---|
2829 | reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10;
|
---|
2830 | urtwn_bb_write(sc, R92C_OFDM1_LSTF, reg);
|
---|
2831 |
|
---|
2832 | urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
|
---|
2833 | urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) &
|
---|
2834 | ~R92C_FPGA0_ANAPARAM2_CBW20);
|
---|
2835 |
|
---|
2836 | reg = urtwn_bb_read(sc, 0x818);
|
---|
2837 | reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26;
|
---|
2838 | urtwn_bb_write(sc, 0x818, reg);
|
---|
2839 |
|
---|
2840 | /* Select 40MHz bandwidth. */
|
---|
2841 | urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
---|
2842 | (sc->rf_chnlbw[0] & ~0xfff) | chan);
|
---|
2843 | } else
|
---|
2844 | #endif
|
---|
2845 | {
|
---|
2846 | urtwn_write_1(sc, R92C_BWOPMODE,
|
---|
2847 | urtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ);
|
---|
2848 |
|
---|
2849 | urtwn_bb_write(sc, R92C_FPGA0_RFMOD,
|
---|
2850 | urtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ);
|
---|
2851 | urtwn_bb_write(sc, R92C_FPGA1_RFMOD,
|
---|
2852 | urtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ);
|
---|
2853 |
|
---|
2854 | urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
|
---|
2855 | urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
|
---|
2856 | R92C_FPGA0_ANAPARAM2_CBW20);
|
---|
2857 |
|
---|
2858 | /* Select 20MHz bandwidth. */
|
---|
2859 | urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
---|
2860 | (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan);
|
---|
2861 | }
|
---|
2862 | }
|
---|
2863 |
|
---|
2864 | int
|
---|
2865 | urtwn_iq_calib_chain(struct urtwn_softc *sc, int chain, uint16_t tx[2],
|
---|
2866 | uint16_t rx[2])
|
---|
2867 | {
|
---|
2868 | uint32_t status;
|
---|
2869 | int offset = chain * 0x20;
|
---|
2870 |
|
---|
2871 | if (chain == 0) { /* IQ calibration for chain 0. */
|
---|
2872 | /* IQ calibration settings for chain 0. */
|
---|
2873 | urtwn_bb_write(sc, 0xe30, 0x10008c1f);
|
---|
2874 | urtwn_bb_write(sc, 0xe34, 0x10008c1f);
|
---|
2875 | urtwn_bb_write(sc, 0xe38, 0x82140102);
|
---|
2876 |
|
---|
2877 | if (sc->ntxchains > 1) {
|
---|
2878 | urtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */
|
---|
2879 | /* IQ calibration settings for chain 1. */
|
---|
2880 | urtwn_bb_write(sc, 0xe50, 0x10008c22);
|
---|
2881 | urtwn_bb_write(sc, 0xe54, 0x10008c22);
|
---|
2882 | urtwn_bb_write(sc, 0xe58, 0x82140102);
|
---|
2883 | urtwn_bb_write(sc, 0xe5c, 0x28160202);
|
---|
2884 | } else
|
---|
2885 | urtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */
|
---|
2886 |
|
---|
2887 | /* LO calibration settings. */
|
---|
2888 | urtwn_bb_write(sc, 0xe4c, 0x001028d1);
|
---|
2889 | /* We're doing LO and IQ calibration in one shot. */
|
---|
2890 | urtwn_bb_write(sc, 0xe48, 0xf9000000);
|
---|
2891 | urtwn_bb_write(sc, 0xe48, 0xf8000000);
|
---|
2892 |
|
---|
2893 | } else { /* IQ calibration for chain 1. */
|
---|
2894 | /* We're doing LO and IQ calibration in one shot. */
|
---|
2895 | urtwn_bb_write(sc, 0xe60, 0x00000002);
|
---|
2896 | urtwn_bb_write(sc, 0xe60, 0x00000000);
|
---|
2897 | }
|
---|
2898 |
|
---|
2899 | /* Give LO and IQ calibrations the time to complete. */
|
---|
2900 | usbd_delay_ms(sc->sc_udev, 1);
|
---|
2901 |
|
---|
2902 | /* Read IQ calibration status. */
|
---|
2903 | status = urtwn_bb_read(sc, 0xeac);
|
---|
2904 |
|
---|
2905 | if (status & (1 << (28 + chain * 3)))
|
---|
2906 | return (0); /* Tx failed. */
|
---|
2907 | /* Read Tx IQ calibration results. */
|
---|
2908 | tx[0] = (urtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff;
|
---|
2909 | tx[1] = (urtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff;
|
---|
2910 | if (tx[0] == 0x142 || tx[1] == 0x042)
|
---|
2911 | return (0); /* Tx failed. */
|
---|
2912 |
|
---|
2913 | if (status & (1 << (27 + chain * 3)))
|
---|
2914 | return (1); /* Rx failed. */
|
---|
2915 | /* Read Rx IQ calibration results. */
|
---|
2916 | rx[0] = (urtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff;
|
---|
2917 | rx[1] = (urtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff;
|
---|
2918 | if (rx[0] == 0x132 || rx[1] == 0x036)
|
---|
2919 | return (1); /* Rx failed. */
|
---|
2920 |
|
---|
2921 | return (3); /* Both Tx and Rx succeeded. */
|
---|
2922 | }
|
---|
2923 |
|
---|
2924 | void
|
---|
2925 | urtwn_iq_calib(struct urtwn_softc *sc)
|
---|
2926 | {
|
---|
2927 | /* TODO */
|
---|
2928 | }
|
---|
2929 |
|
---|
2930 | void
|
---|
2931 | urtwn_lc_calib(struct urtwn_softc *sc)
|
---|
2932 | {
|
---|
2933 | uint32_t rf_ac[2];
|
---|
2934 | uint8_t txmode;
|
---|
2935 | int i;
|
---|
2936 |
|
---|
2937 | txmode = urtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
|
---|
2938 | if ((txmode & 0x70) != 0) {
|
---|
2939 | /* Disable all continuous Tx. */
|
---|
2940 | urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
|
---|
2941 |
|
---|
2942 | /* Set RF mode to standby mode. */
|
---|
2943 | for (i = 0; i < sc->nrxchains; i++) {
|
---|
2944 | rf_ac[i] = urtwn_rf_read(sc, i, R92C_RF_AC);
|
---|
2945 | urtwn_rf_write(sc, i, R92C_RF_AC,
|
---|
2946 | RW(rf_ac[i], R92C_RF_AC_MODE,
|
---|
2947 | R92C_RF_AC_MODE_STANDBY));
|
---|
2948 | }
|
---|
2949 | } else {
|
---|
2950 | /* Block all Tx queues. */
|
---|
2951 | urtwn_write_1(sc, R92C_TXPAUSE, 0xff);
|
---|
2952 | }
|
---|
2953 | /* Start calibration. */
|
---|
2954 | urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
---|
2955 | urtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART);
|
---|
2956 |
|
---|
2957 | /* Give calibration the time to complete. */
|
---|
2958 | usbd_delay_ms(sc->sc_udev, 100);
|
---|
2959 |
|
---|
2960 | /* Restore configuration. */
|
---|
2961 | if ((txmode & 0x70) != 0) {
|
---|
2962 | /* Restore Tx mode. */
|
---|
2963 | urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
|
---|
2964 | /* Restore RF mode. */
|
---|
2965 | for (i = 0; i < sc->nrxchains; i++)
|
---|
2966 | urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
|
---|
2967 | } else {
|
---|
2968 | /* Unblock all Tx queues. */
|
---|
2969 | urtwn_write_1(sc, R92C_TXPAUSE, 0x00);
|
---|
2970 | }
|
---|
2971 | }
|
---|
2972 |
|
---|
2973 | void
|
---|
2974 | urtwn_temp_calib(struct urtwn_softc *sc)
|
---|
2975 | {
|
---|
2976 | int temp;
|
---|
2977 |
|
---|
2978 | if (sc->thcal_state == 0) {
|
---|
2979 | /* Start measuring temperature. */
|
---|
2980 | urtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60);
|
---|
2981 | sc->thcal_state = 1;
|
---|
2982 | return;
|
---|
2983 | }
|
---|
2984 | sc->thcal_state = 0;
|
---|
2985 |
|
---|
2986 | /* Read measured temperature. */
|
---|
2987 | temp = urtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f;
|
---|
2988 | if (temp == 0) /* Read failed, skip. */
|
---|
2989 | return;
|
---|
2990 | DPRINTFN(2, ("temperature=%d\n", temp));
|
---|
2991 |
|
---|
2992 | /*
|
---|
2993 | * Redo LC calibration if temperature changed significantly since
|
---|
2994 | * last calibration.
|
---|
2995 | */
|
---|
2996 | if (sc->thcal_lctemp == 0) {
|
---|
2997 | /* First LC calibration is performed in urtwn_init(). */
|
---|
2998 | sc->thcal_lctemp = temp;
|
---|
2999 | } else if (abs(temp - sc->thcal_lctemp) > 1) {
|
---|
3000 | DPRINTF(("LC calib triggered by temp: %d -> %d\n",
|
---|
3001 | sc->thcal_lctemp, temp));
|
---|
3002 | urtwn_lc_calib(sc);
|
---|
3003 | /* Record temperature of last LC calibration. */
|
---|
3004 | sc->thcal_lctemp = temp;
|
---|
3005 | }
|
---|
3006 | }
|
---|
3007 |
|
---|
3008 | int
|
---|
3009 | urtwn_init(struct ifnet *ifp)
|
---|
3010 | {
|
---|
3011 | struct urtwn_softc *sc = ifp->if_softc;
|
---|
3012 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
3013 | struct urtwn_rx_data *data;
|
---|
3014 | uint32_t reg;
|
---|
3015 | int i, error;
|
---|
3016 |
|
---|
3017 | /* Init host async commands ring. */
|
---|
3018 | sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
|
---|
3019 | /* Init firmware commands ring. */
|
---|
3020 | sc->fwcur = 0;
|
---|
3021 |
|
---|
3022 | /* Allocate Tx/Rx buffers. */
|
---|
3023 | error = urtwn_alloc_rx_list(sc);
|
---|
3024 | if (error != 0) {
|
---|
3025 | printf("%s: could not allocate Rx buffers\n",
|
---|
3026 | sc->sc_dev.dv_xname);
|
---|
3027 | goto fail;
|
---|
3028 | }
|
---|
3029 | error = urtwn_alloc_tx_list(sc);
|
---|
3030 | if (error != 0) {
|
---|
3031 | printf("%s: could not allocate Tx buffers\n",
|
---|
3032 | sc->sc_dev.dv_xname);
|
---|
3033 | goto fail;
|
---|
3034 | }
|
---|
3035 | /* Power on adapter. */
|
---|
3036 | error = urtwn_power_on(sc);
|
---|
3037 | if (error != 0)
|
---|
3038 | goto fail;
|
---|
3039 |
|
---|
3040 | /* Initialize DMA. */
|
---|
3041 | error = urtwn_dma_init(sc);
|
---|
3042 | if (error != 0)
|
---|
3043 | goto fail;
|
---|
3044 |
|
---|
3045 | /* Set info size in Rx descriptors (in 64-bit words). */
|
---|
3046 | urtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4);
|
---|
3047 |
|
---|
3048 | /* Init interrupts. */
|
---|
3049 | urtwn_write_4(sc, R92C_HISR, 0xffffffff);
|
---|
3050 | urtwn_write_4(sc, R92C_HIMR, 0xffffffff);
|
---|
3051 |
|
---|
3052 | /* Set MAC address. */
|
---|
3053 | IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
|
---|
3054 | urtwn_write_region_1(sc, R92C_MACID, ic->ic_myaddr,
|
---|
3055 | IEEE80211_ADDR_LEN);
|
---|
3056 |
|
---|
3057 | /* Set initial network type. */
|
---|
3058 | reg = urtwn_read_4(sc, R92C_CR);
|
---|
3059 | reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
|
---|
3060 | urtwn_write_4(sc, R92C_CR, reg);
|
---|
3061 |
|
---|
3062 | urtwn_rxfilter_init(sc);
|
---|
3063 |
|
---|
3064 | reg = urtwn_read_4(sc, R92C_RRSR);
|
---|
3065 | reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_CCK_ONLY_1M);
|
---|
3066 | urtwn_write_4(sc, R92C_RRSR, reg);
|
---|
3067 |
|
---|
3068 | /* Set short/long retry limits. */
|
---|
3069 | urtwn_write_2(sc, R92C_RL,
|
---|
3070 | SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30));
|
---|
3071 |
|
---|
3072 | /* Initialize EDCA parameters. */
|
---|
3073 | urtwn_edca_init(sc);
|
---|
3074 |
|
---|
3075 | /* Setup rate fallback. */
|
---|
3076 | urtwn_write_4(sc, R92C_DARFRC + 0, 0x00000000);
|
---|
3077 | urtwn_write_4(sc, R92C_DARFRC + 4, 0x10080404);
|
---|
3078 | urtwn_write_4(sc, R92C_RARFRC + 0, 0x04030201);
|
---|
3079 | urtwn_write_4(sc, R92C_RARFRC + 4, 0x08070605);
|
---|
3080 |
|
---|
3081 | urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL,
|
---|
3082 | urtwn_read_1(sc, R92C_FWHW_TXQ_CTRL) |
|
---|
3083 | R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW);
|
---|
3084 | /* Set ACK timeout. */
|
---|
3085 | urtwn_write_1(sc, R92C_ACKTO, 0x40);
|
---|
3086 |
|
---|
3087 | /* Setup USB aggregation. */
|
---|
3088 | reg = urtwn_read_4(sc, R92C_TDECTRL);
|
---|
3089 | reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, 6);
|
---|
3090 | urtwn_write_4(sc, R92C_TDECTRL, reg);
|
---|
3091 | urtwn_write_1(sc, R92C_TRXDMA_CTRL,
|
---|
3092 | urtwn_read_1(sc, R92C_TRXDMA_CTRL) |
|
---|
3093 | R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
|
---|
3094 | urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION,
|
---|
3095 | urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) |
|
---|
3096 | R92C_USB_SPECIAL_OPTION_AGG_EN);
|
---|
3097 | urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48);
|
---|
3098 | urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4);
|
---|
3099 | urtwn_write_1(sc, R92C_USB_AGG_TH, 8);
|
---|
3100 | urtwn_write_1(sc, R92C_USB_AGG_TO, 6);
|
---|
3101 |
|
---|
3102 | /* Initialize beacon parameters. */
|
---|
3103 | urtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
|
---|
3104 | urtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
|
---|
3105 | urtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
|
---|
3106 | urtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
|
---|
3107 |
|
---|
3108 | /* Setup AMPDU aggregation. */
|
---|
3109 | urtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */
|
---|
3110 | urtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
|
---|
3111 | urtwn_write_2(sc, 0x4ca, 0x0708);
|
---|
3112 |
|
---|
3113 | urtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
|
---|
3114 | urtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0);
|
---|
3115 |
|
---|
3116 | /* Load 8051 microcode. */
|
---|
3117 | error = urtwn_load_firmware(sc);
|
---|
3118 | if (error != 0)
|
---|
3119 | goto fail;
|
---|
3120 |
|
---|
3121 | /* Initialize MAC/BB/RF blocks. */
|
---|
3122 | urtwn_mac_init(sc);
|
---|
3123 | urtwn_bb_init(sc);
|
---|
3124 | urtwn_rf_init(sc);
|
---|
3125 |
|
---|
3126 | /* Turn CCK and OFDM blocks on. */
|
---|
3127 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD);
|
---|
3128 | reg |= R92C_RFMOD_CCK_EN;
|
---|
3129 | urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
|
---|
3130 | reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD);
|
---|
3131 | reg |= R92C_RFMOD_OFDM_EN;
|
---|
3132 | urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
|
---|
3133 |
|
---|
3134 | /* Clear per-station keys table. */
|
---|
3135 | urtwn_cam_init(sc);
|
---|
3136 |
|
---|
3137 | /* Enable hardware sequence numbering. */
|
---|
3138 | urtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff);
|
---|
3139 |
|
---|
3140 | /* Perform LO and IQ calibrations. */
|
---|
3141 | urtwn_iq_calib(sc);
|
---|
3142 | /* Perform LC calibration. */
|
---|
3143 | urtwn_lc_calib(sc);
|
---|
3144 |
|
---|
3145 | /* Fix USB interference issue. */
|
---|
3146 | urtwn_write_1(sc, 0xfe40, 0xe0);
|
---|
3147 | urtwn_write_1(sc, 0xfe41, 0x8d);
|
---|
3148 | urtwn_write_1(sc, 0xfe42, 0x80);
|
---|
3149 |
|
---|
3150 | urtwn_pa_bias_init(sc);
|
---|
3151 |
|
---|
3152 | /* Initialize GPIO setting. */
|
---|
3153 | urtwn_write_1(sc, R92C_GPIO_MUXCFG,
|
---|
3154 | urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT);
|
---|
3155 |
|
---|
3156 | /* Fix for lower temperature. */
|
---|
3157 | urtwn_write_1(sc, 0x15, 0xe9);
|
---|
3158 |
|
---|
3159 | /* Set default channel. */
|
---|
3160 | ic->ic_bss->ni_chan = ic->ic_ibss_chan;
|
---|
3161 | urtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
|
---|
3162 |
|
---|
3163 | /* Queue Rx xfers. */
|
---|
3164 | for (i = 0; i < URTWN_RX_LIST_COUNT; i++) {
|
---|
3165 | data = &sc->rx_data[i];
|
---|
3166 |
|
---|
3167 | usbd_setup_xfer(data->xfer, sc->rx_pipe, data, data->buf,
|
---|
3168 | URTWN_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
|
---|
3169 | USBD_NO_TIMEOUT, urtwn_rxeof);
|
---|
3170 | error = usbd_transfer(data->xfer);
|
---|
3171 | if (error != 0 && error != USBD_IN_PROGRESS)
|
---|
3172 | goto fail;
|
---|
3173 | }
|
---|
3174 |
|
---|
3175 | /* We're ready to go. */
|
---|
3176 | ifp->if_flags &= ~IFF_OACTIVE;
|
---|
3177 | ifp->if_flags |= IFF_RUNNING;
|
---|
3178 |
|
---|
3179 | #ifdef notyet
|
---|
3180 | if (ic->ic_flags & IEEE80211_F_WEPON) {
|
---|
3181 | /* Install WEP keys. */
|
---|
3182 | for (i = 0; i < IEEE80211_WEP_NKID; i++)
|
---|
3183 | urtwn_set_key(ic, NULL, &ic->ic_nw_keys[i]);
|
---|
3184 | urtwn_wait_async(sc);
|
---|
3185 | }
|
---|
3186 | #endif
|
---|
3187 | if (ic->ic_opmode == IEEE80211_M_MONITOR)
|
---|
3188 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
|
---|
3189 | else
|
---|
3190 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
|
---|
3191 | return (0);
|
---|
3192 | fail:
|
---|
3193 | urtwn_stop(ifp);
|
---|
3194 | return (error);
|
---|
3195 | }
|
---|
3196 |
|
---|
3197 | void
|
---|
3198 | urtwn_stop(struct ifnet *ifp)
|
---|
3199 | {
|
---|
3200 | struct urtwn_softc *sc = ifp->if_softc;
|
---|
3201 | struct ieee80211com *ic = &sc->sc_ic;
|
---|
3202 | int i, s;
|
---|
3203 |
|
---|
3204 | sc->sc_tx_timer = 0;
|
---|
3205 | ifp->if_timer = 0;
|
---|
3206 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
|
---|
3207 |
|
---|
3208 | s = splusb();
|
---|
3209 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
|
---|
3210 | /* Wait for all async commands to complete. */
|
---|
3211 | urtwn_wait_async(sc);
|
---|
3212 | splx(s);
|
---|
3213 |
|
---|
3214 | timeout_del(&sc->scan_to);
|
---|
3215 | timeout_del(&sc->calib_to);
|
---|
3216 |
|
---|
3217 | /* Abort Tx. */
|
---|
3218 | for (i = 0; i < R92C_MAX_EPOUT; i++) {
|
---|
3219 | if (sc->tx_pipe[i] != NULL)
|
---|
3220 | usbd_abort_pipe(sc->tx_pipe[i]);
|
---|
3221 | }
|
---|
3222 | /* Stop Rx pipe. */
|
---|
3223 | usbd_abort_pipe(sc->rx_pipe);
|
---|
3224 | /* Free Tx/Rx buffers. */
|
---|
3225 | urtwn_free_tx_list(sc);
|
---|
3226 | urtwn_free_rx_list(sc);
|
---|
3227 | }
|
---|