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