1203134Sthompsa/*-
2205042Sthompsa * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr>
3205042Sthompsa * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
4205042Sthompsa * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org>
5261868Skevlo * Copyright (c) 2013-2014 Kevin Lo
6203134Sthompsa *
7203134Sthompsa * Permission to use, copy, modify, and distribute this software for any
8203134Sthompsa * purpose with or without fee is hereby granted, provided that the above
9203134Sthompsa * copyright notice and this permission notice appear in all copies.
10203134Sthompsa *
11203134Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12203134Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13203134Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14203134Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15203134Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16203134Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17203134Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18203134Sthompsa */
19203134Sthompsa
20203134Sthompsa#include <sys/cdefs.h>
21203134Sthompsa__FBSDID("$FreeBSD: stable/10/sys/dev/usb/wlan/if_run.c 343821 2019-02-06 02:18:11Z avos $");
22203134Sthompsa
23203134Sthompsa/*-
24259453Shselasky * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
25203134Sthompsa * http://www.ralinktech.com/
26203134Sthompsa */
27203134Sthompsa
28203134Sthompsa#include <sys/param.h>
29203134Sthompsa#include <sys/sockio.h>
30203134Sthompsa#include <sys/sysctl.h>
31203134Sthompsa#include <sys/lock.h>
32203134Sthompsa#include <sys/mutex.h>
33203134Sthompsa#include <sys/mbuf.h>
34203134Sthompsa#include <sys/kernel.h>
35203134Sthompsa#include <sys/socket.h>
36203134Sthompsa#include <sys/systm.h>
37203134Sthompsa#include <sys/malloc.h>
38203134Sthompsa#include <sys/module.h>
39203134Sthompsa#include <sys/bus.h>
40203134Sthompsa#include <sys/endian.h>
41203134Sthompsa#include <sys/linker.h>
42203134Sthompsa#include <sys/firmware.h>
43203134Sthompsa#include <sys/kdb.h>
44203134Sthompsa
45203134Sthompsa#include <net/bpf.h>
46203134Sthompsa#include <net/if.h>
47203134Sthompsa#include <net/if_arp.h>
48203134Sthompsa#include <net/ethernet.h>
49203134Sthompsa#include <net/if_dl.h>
50203134Sthompsa#include <net/if_media.h>
51203134Sthompsa#include <net/if_types.h>
52203134Sthompsa
53203134Sthompsa#include <netinet/in.h>
54203134Sthompsa#include <netinet/in_systm.h>
55203134Sthompsa#include <netinet/in_var.h>
56203134Sthompsa#include <netinet/if_ether.h>
57203134Sthompsa#include <netinet/ip.h>
58203134Sthompsa
59203134Sthompsa#include <net80211/ieee80211_var.h>
60203134Sthompsa#include <net80211/ieee80211_regdomain.h>
61203134Sthompsa#include <net80211/ieee80211_radiotap.h>
62206358Srpaulo#include <net80211/ieee80211_ratectl.h>
63203134Sthompsa
64203134Sthompsa#include <dev/usb/usb.h>
65203134Sthompsa#include <dev/usb/usbdi.h>
66203134Sthompsa#include "usbdevs.h"
67203134Sthompsa
68261868Skevlo#define	USB_DEBUG_VAR	run_debug
69203134Sthompsa#include <dev/usb/usb_debug.h>
70261868Skevlo#include <dev/usb/usb_msctest.h>
71203134Sthompsa
72220235Skevlo#include <dev/usb/wlan/if_runreg.h>
73220235Skevlo#include <dev/usb/wlan/if_runvar.h>
74203134Sthompsa
75207077Sthompsa#ifdef	USB_DEBUG
76261868Skevlo#define	RUN_DEBUG
77203134Sthompsa#endif
78203134Sthompsa
79203134Sthompsa#ifdef	RUN_DEBUG
80203134Sthompsaint run_debug = 0;
81227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
82203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
83203134Sthompsa    "run debug level");
84203134Sthompsa#endif
85203134Sthompsa
86261868Skevlo#define	IEEE80211_HAS_ADDR4(wh)	\
87203134Sthompsa	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
88203134Sthompsa
89208019Sthompsa/*
90208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
91208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
92208019Sthompsa */
93261868Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
94208019Sthompsa
95223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
96261868Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
97261868Skevlo#define	RUN_DEV_EJECT(v,p)	\
98262604Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
99262604Skevlo#define	RUN_EJECT	1
100209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
101209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
102209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
103209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
104209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
105209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
106209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
107209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
108209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
109209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
110209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
112209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
113209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
114209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
115209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
116209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
118209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
119209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
120209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
121209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
122209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
123209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
126209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
127209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
128209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
129209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
130209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
131209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
132209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
133209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
134209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
135209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
136209918Sthompsa    RUN_DEV(ASUS,		USBN13),
137209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
138261868Skevlo    RUN_DEV(ASUS,		USBN66),
139239358Shselasky    RUN_DEV(ASUS,		USB_N53),
140209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
141209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
142209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
143209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
144209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
145209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
146261868Skevlo    RUN_DEV(BELKIN,		F9L1103),
147209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
148209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
149226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
150209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
151257044Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
152209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
153209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
154226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
155209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
156209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
157209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
158209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
159209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
160209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
161209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
168209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
169209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
170209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
171209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
172209918Sthompsa    RUN_DEV(COREGA,		RT3070),
173209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
174209918Sthompsa    RUN_DEV(DLINK,		RT2870),
175209918Sthompsa    RUN_DEV(DLINK,		RT3072),
176255238Sbr    RUN_DEV(DLINK,		DWA127),
177259453Shselasky    RUN_DEV(DLINK,		DWA140B3),
178259453Shselasky    RUN_DEV(DLINK,		DWA160B2),
179267263Skevlo    RUN_DEV(DLINK,		DWA140D1),
180261868Skevlo    RUN_DEV(DLINK,		DWA162),
181209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
182209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
183209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
184209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
185209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
186209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
187209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
188209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
191209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
192209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
193261868Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
194209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
195209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
196209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
197209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
198209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
199209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
200209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
201209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
202209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
203209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
204209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
205209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
206209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
207209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
208209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
209209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
210209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
211209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
212209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
213209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
214209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
215209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
216209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
217209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
218209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
219209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
220230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
221238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
222248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
223281878Skevlo    RUN_DEV(MELCO,		WLIUCG300HP),
224209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
225209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
226209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
227219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
228209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
229227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
230281878Skevlo    RUN_DEV(MELCO,		WLIUCG300HPV1),
231238274Shrs    RUN_DEV(MELCO,		WLIUCGNM2),
232209918Sthompsa    RUN_DEV(MOTOROLA4,		RT2770),
233209918Sthompsa    RUN_DEV(MOTOROLA4,		RT3070),
234209918Sthompsa    RUN_DEV(MSI,		RT3070_1),
235209918Sthompsa    RUN_DEV(MSI,		RT3070_2),
236209918Sthompsa    RUN_DEV(MSI,		RT3070_3),
237209918Sthompsa    RUN_DEV(MSI,		RT3070_4),
238209918Sthompsa    RUN_DEV(MSI,		RT3070_5),
239209918Sthompsa    RUN_DEV(MSI,		RT3070_6),
240209918Sthompsa    RUN_DEV(MSI,		RT3070_7),
241209918Sthompsa    RUN_DEV(MSI,		RT3070_8),
242209918Sthompsa    RUN_DEV(MSI,		RT3070_9),
243209918Sthompsa    RUN_DEV(MSI,		RT3070_10),
244209918Sthompsa    RUN_DEV(MSI,		RT3070_11),
245292183Shselasky    RUN_DEV(NETGEAR,		WNDA4100),
246209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
247209918Sthompsa    RUN_DEV(PARA,		RT3070),
248209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
249209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
250209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
251209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
252209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
253209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
254209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
255209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
256209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
257209918Sthompsa    RUN_DEV(QCOM,		RT2870),
258209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
259209918Sthompsa    RUN_DEV(RALINK,		RT2070),
260209918Sthompsa    RUN_DEV(RALINK,		RT2770),
261209918Sthompsa    RUN_DEV(RALINK,		RT2870),
262209918Sthompsa    RUN_DEV(RALINK,		RT3070),
263209918Sthompsa    RUN_DEV(RALINK,		RT3071),
264209918Sthompsa    RUN_DEV(RALINK,		RT3072),
265209918Sthompsa    RUN_DEV(RALINK,		RT3370),
266209918Sthompsa    RUN_DEV(RALINK,		RT3572),
267261868Skevlo    RUN_DEV(RALINK,		RT3573),
268259453Shselasky    RUN_DEV(RALINK,		RT5370),
269259453Shselasky    RUN_DEV(RALINK,		RT5572),
270209918Sthompsa    RUN_DEV(RALINK,		RT8070),
271226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
272209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
273209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
274209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
275209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
276209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
277209918Sthompsa    RUN_DEV(SENAO,		RT3070),
278209918Sthompsa    RUN_DEV(SENAO,		RT3071),
279209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
280209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
281209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
282209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
284209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
285209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
286209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
287209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
300209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
301209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
302209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
303209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
304209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
305209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
306209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
307209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
308209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
309209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
310209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
311209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
312209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
313209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
315209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
316209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
317292183Shselasky    RUN_DEV(ZYXEL,		RT3070),
318262604Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
319261868Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
320261868Skevlo#undef RUN_DEV_EJECT
321209918Sthompsa#undef RUN_DEV
322203134Sthompsa};
323203134Sthompsa
324203134Sthompsastatic device_probe_t	run_match;
325203134Sthompsastatic device_attach_t	run_attach;
326203134Sthompsastatic device_detach_t	run_detach;
327203134Sthompsa
328203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
329203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
330203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
331203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
332203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
335203134Sthompsa
336261868Skevlostatic void	run_autoinst(void *, struct usb_device *,
337261868Skevlo		    struct usb_attach_arg *);
338261868Skevlostatic int	run_driver_loaded(struct module *, int, void *);
339203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
340259453Shselasky		    usb_error_t error, u_int index);
341203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
342228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
343228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
344228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
345203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
346208019Sthompsastatic void	run_cmdq_cb(void *, int);
347203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
348203134Sthompsa		    struct run_endpoint_queue *);
349203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
350203134Sthompsa		    struct run_endpoint_queue *);
351203134Sthompsastatic int	run_load_microcode(struct run_softc *);
352203134Sthompsastatic int	run_reset(struct run_softc *);
353203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
354203134Sthompsa		    struct usb_device_request *, void *);
355203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
356203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
357203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
358203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
359203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
360203134Sthompsa		    const uint8_t *, int);
361203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
362261868Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
363203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
364203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
365259453Shselaskystatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
366203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
367203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
368203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
369203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
370203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
371259453Shselaskystatic const char *run_get_rf(uint16_t);
372261868Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
373261868Skevlostatic void	run_get_txpower(struct run_softc *);
374203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
375203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
376203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
377203134Sthompsastatic int	run_media_change(struct ifnet *);
378203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
379203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
380208019Sthompsastatic void	run_wme_update_cb(void *);
381203134Sthompsastatic void	run_key_update_begin(struct ieee80211vap *);
382203134Sthompsastatic void	run_key_update_end(struct ieee80211vap *);
383208019Sthompsastatic void	run_key_set_cb(void *);
384208019Sthompsastatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
385259453Shselasky		    const uint8_t mac[IEEE80211_ADDR_LEN]);
386208019Sthompsastatic void	run_key_delete_cb(void *);
387208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
388206358Srpaulostatic void	run_ratectl_to(void *);
389206358Srpaulostatic void	run_ratectl_cb(void *, int);
390208019Sthompsastatic void	run_drain_fifo(void *);
391203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
392208019Sthompsastatic void	run_newassoc_cb(void *);
393203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
394203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
395203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
396203134Sthompsa		    struct run_tx_data *, int);
397208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
398203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
399203134Sthompsa		    struct ieee80211_node *);
400203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
401203134Sthompsa		    struct ieee80211_node *);
402203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *, int, int);
404203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
405203134Sthompsa		    struct ieee80211_node *,
406203134Sthompsa		    const struct ieee80211_bpf_params *);
407203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
408203134Sthompsa		    const struct ieee80211_bpf_params *);
409203134Sthompsastatic void	run_start(struct ifnet *);
410203134Sthompsastatic int	run_ioctl(struct ifnet *, u_long, caddr_t);
411261868Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
412205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
413203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
414203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
415203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
416203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
417205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
418261868Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
419259453Shselaskystatic void	run_rt5390_set_chan(struct run_softc *, u_int);
420259453Shselaskystatic void	run_rt5592_set_chan(struct run_softc *, u_int);
421203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
422203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
423203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
424203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
425203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
426208019Sthompsastatic void	run_update_beacon_cb(void *);
427203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
428218492Sbschmidtstatic void	run_updateprot_cb(void *);
429208019Sthompsastatic void	run_usb_timeout_cb(void *);
430203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
431203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
432203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
433203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
434203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
435203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
436203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
437203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
438203134Sthompsastatic void	run_updateslot(struct ifnet *);
439218492Sbschmidtstatic void	run_updateslot_cb(void *);
440208019Sthompsastatic void	run_update_mcast(struct ifnet *);
441203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
442203134Sthompsastatic void	run_update_promisc_locked(struct ifnet *);
443203134Sthompsastatic void	run_update_promisc(struct ifnet *);
444259453Shselaskystatic void	run_rt5390_bbp_init(struct run_softc *);
445203134Sthompsastatic int	run_bbp_init(struct run_softc *);
446203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
447261868Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
448259453Shselaskystatic void	run_rt5390_rf_init(struct run_softc *);
449203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
450203134Sthompsa		    uint8_t *);
451205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
452261868Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
453261868Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
454203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
455259453Shselaskystatic void	run_adjust_freq_offset(struct run_softc *);
456203134Sthompsastatic void	run_init(void *);
457203134Sthompsastatic void	run_init_locked(struct run_softc *);
458203134Sthompsastatic void	run_stop(void *);
459259453Shselaskystatic void	run_delay(struct run_softc *, u_int);
460203134Sthompsa
461261868Skevlostatic eventhandler_tag run_etag;
462261868Skevlo
463261868Skevlostatic const struct rt2860_rate {
464261868Skevlo	uint8_t		rate;
465261868Skevlo	uint8_t		mcs;
466261868Skevlo	enum		ieee80211_phytype phy;
467261868Skevlo	uint8_t		ctl_ridx;
468261868Skevlo	uint16_t	sp_ack_dur;
469261868Skevlo	uint16_t	lp_ack_dur;
470261868Skevlo} rt2860_rates[] = {
471261868Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
472261868Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
473261868Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
474261868Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
475261868Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
476261868Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
477261868Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
478261868Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
479261868Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
480261868Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
481261868Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
482261868Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
483261868Skevlo};
484261868Skevlo
485203134Sthompsastatic const struct {
486208019Sthompsa	uint16_t	reg;
487203134Sthompsa	uint32_t	val;
488203134Sthompsa} rt2870_def_mac[] = {
489203134Sthompsa	RT2870_DEF_MAC
490203134Sthompsa};
491203134Sthompsa
492203134Sthompsastatic const struct {
493203134Sthompsa	uint8_t	reg;
494203134Sthompsa	uint8_t	val;
495203134Sthompsa} rt2860_def_bbp[] = {
496203134Sthompsa	RT2860_DEF_BBP
497259453Shselasky},rt5390_def_bbp[] = {
498259453Shselasky	RT5390_DEF_BBP
499259453Shselasky},rt5592_def_bbp[] = {
500259453Shselasky	RT5592_DEF_BBP
501203134Sthompsa};
502203134Sthompsa
503259453Shselasky/*
504259453Shselasky * Default values for BBP register R196 for RT5592.
505259453Shselasky */
506259453Shselaskystatic const uint8_t rt5592_bbp_r196[] = {
507259453Shselasky	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
508259453Shselasky	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
509259453Shselasky	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
510259453Shselasky	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
511259453Shselasky	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
512259453Shselasky	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
513259453Shselasky	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514259453Shselasky	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
515259453Shselasky	0x2e, 0x36, 0x30, 0x6e
516259453Shselasky};
517259453Shselasky
518203134Sthompsastatic const struct rfprog {
519203134Sthompsa	uint8_t		chan;
520203134Sthompsa	uint32_t	r1, r2, r3, r4;
521203134Sthompsa} rt2860_rf2850[] = {
522203134Sthompsa	RT2860_RF2850
523203134Sthompsa};
524203134Sthompsa
525203134Sthompsastruct {
526203134Sthompsa	uint8_t	n, r, k;
527205042Sthompsa} rt3070_freqs[] = {
528205042Sthompsa	RT3070_RF3052
529203134Sthompsa};
530203134Sthompsa
531259453Shselaskystatic const struct rt5592_freqs {
532259453Shselasky	uint16_t	n;
533259453Shselasky	uint8_t		k, m, r;
534259453Shselasky} rt5592_freqs_20mhz[] = {
535259453Shselasky	RT5592_RF5592_20MHZ
536259453Shselasky},rt5592_freqs_40mhz[] = {
537259453Shselasky	RT5592_RF5592_40MHZ
538259453Shselasky};
539259453Shselasky
540203134Sthompsastatic const struct {
541203134Sthompsa	uint8_t	reg;
542203134Sthompsa	uint8_t	val;
543203134Sthompsa} rt3070_def_rf[] = {
544203134Sthompsa	RT3070_DEF_RF
545205042Sthompsa},rt3572_def_rf[] = {
546205042Sthompsa	RT3572_DEF_RF
547261868Skevlo},rt3593_def_rf[] = {
548261868Skevlo	RT3593_DEF_RF
549259453Shselasky},rt5390_def_rf[] = {
550259453Shselasky	RT5390_DEF_RF
551259453Shselasky},rt5392_def_rf[] = {
552259453Shselasky	RT5392_DEF_RF
553259453Shselasky},rt5592_def_rf[] = {
554259453Shselasky	RT5592_DEF_RF
555259453Shselasky},rt5592_2ghz_def_rf[] = {
556259453Shselasky	RT5592_2GHZ_DEF_RF
557259453Shselasky},rt5592_5ghz_def_rf[] = {
558259453Shselasky	RT5592_5GHZ_DEF_RF
559203134Sthompsa};
560203134Sthompsa
561259453Shselaskystatic const struct {
562259453Shselasky	u_int	firstchan;
563259453Shselasky	u_int	lastchan;
564259453Shselasky	uint8_t	reg;
565259453Shselasky	uint8_t	val;
566259453Shselasky} rt5592_chan_5ghz[] = {
567259453Shselasky	RT5592_CHAN_5GHZ
568259453Shselasky};
569259453Shselasky
570203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
571203134Sthompsa    [RUN_BULK_TX_BE] = {
572203134Sthompsa	.type = UE_BULK,
573203134Sthompsa	.endpoint = UE_ADDR_ANY,
574203134Sthompsa	.ep_index = 0,
575203134Sthompsa	.direction = UE_DIR_OUT,
576203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
577203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
578203134Sthompsa	.callback = run_bulk_tx_callback0,
579203134Sthompsa	.timeout = 5000,	/* ms */
580203134Sthompsa    },
581203134Sthompsa    [RUN_BULK_TX_BK] = {
582203134Sthompsa	.type = UE_BULK,
583203134Sthompsa	.endpoint = UE_ADDR_ANY,
584203134Sthompsa	.direction = UE_DIR_OUT,
585203134Sthompsa	.ep_index = 1,
586203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
587203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
588203134Sthompsa	.callback = run_bulk_tx_callback1,
589203134Sthompsa	.timeout = 5000,	/* ms */
590203134Sthompsa    },
591203134Sthompsa    [RUN_BULK_TX_VI] = {
592203134Sthompsa	.type = UE_BULK,
593203134Sthompsa	.endpoint = UE_ADDR_ANY,
594203134Sthompsa	.direction = UE_DIR_OUT,
595203134Sthompsa	.ep_index = 2,
596203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
597203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
598203134Sthompsa	.callback = run_bulk_tx_callback2,
599203134Sthompsa	.timeout = 5000,	/* ms */
600203134Sthompsa    },
601203134Sthompsa    [RUN_BULK_TX_VO] = {
602203134Sthompsa	.type = UE_BULK,
603203134Sthompsa	.endpoint = UE_ADDR_ANY,
604203134Sthompsa	.direction = UE_DIR_OUT,
605203134Sthompsa	.ep_index = 3,
606203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
607203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
608203134Sthompsa	.callback = run_bulk_tx_callback3,
609203134Sthompsa	.timeout = 5000,	/* ms */
610203134Sthompsa    },
611203134Sthompsa    [RUN_BULK_TX_HCCA] = {
612203134Sthompsa	.type = UE_BULK,
613203134Sthompsa	.endpoint = UE_ADDR_ANY,
614203134Sthompsa	.direction = UE_DIR_OUT,
615203134Sthompsa	.ep_index = 4,
616203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
617203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
618203134Sthompsa	.callback = run_bulk_tx_callback4,
619203134Sthompsa	.timeout = 5000,	/* ms */
620203134Sthompsa    },
621203134Sthompsa    [RUN_BULK_TX_PRIO] = {
622203134Sthompsa	.type = UE_BULK,
623203134Sthompsa	.endpoint = UE_ADDR_ANY,
624203134Sthompsa	.direction = UE_DIR_OUT,
625203134Sthompsa	.ep_index = 5,
626203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
627203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
628203134Sthompsa	.callback = run_bulk_tx_callback5,
629203134Sthompsa	.timeout = 5000,	/* ms */
630203134Sthompsa    },
631203134Sthompsa    [RUN_BULK_RX] = {
632203134Sthompsa	.type = UE_BULK,
633203134Sthompsa	.endpoint = UE_ADDR_ANY,
634203134Sthompsa	.direction = UE_DIR_IN,
635203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
636203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
637203134Sthompsa	.callback = run_bulk_rx_callback,
638203134Sthompsa    }
639203134Sthompsa};
640203134Sthompsa
641261868Skevlostatic void
642261868Skevlorun_autoinst(void *arg, struct usb_device *udev,
643261868Skevlo    struct usb_attach_arg *uaa)
644261868Skevlo{
645261868Skevlo	struct usb_interface *iface;
646261868Skevlo	struct usb_interface_descriptor *id;
647261868Skevlo
648261868Skevlo	if (uaa->dev_state != UAA_DEV_READY)
649261868Skevlo		return;
650261868Skevlo
651261868Skevlo	iface = usbd_get_iface(udev, 0);
652261868Skevlo	if (iface == NULL)
653261868Skevlo		return;
654261868Skevlo	id = iface->idesc;
655261868Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
656261868Skevlo		return;
657261868Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
658261868Skevlo		return;
659261868Skevlo
660261868Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
661261868Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
662261868Skevlo}
663261868Skevlo
664220235Skevlostatic int
665261868Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
666261868Skevlo{
667261868Skevlo	switch (what) {
668261868Skevlo	case MOD_LOAD:
669261868Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
670261868Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
671261868Skevlo		break;
672261868Skevlo	case MOD_UNLOAD:
673261868Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
674261868Skevlo		break;
675261868Skevlo	default:
676261868Skevlo		return (EOPNOTSUPP);
677261868Skevlo	}
678261868Skevlo	return (0);
679261868Skevlo}
680261868Skevlo
681261868Skevlostatic int
682203134Sthompsarun_match(device_t self)
683203134Sthompsa{
684203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
685203134Sthompsa
686203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
687203134Sthompsa		return (ENXIO);
688203134Sthompsa	if (uaa->info.bConfigIndex != 0)
689203134Sthompsa		return (ENXIO);
690203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
691203134Sthompsa		return (ENXIO);
692203134Sthompsa
693203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
694203134Sthompsa}
695203134Sthompsa
696203134Sthompsastatic int
697203134Sthompsarun_attach(device_t self)
698203134Sthompsa{
699203134Sthompsa	struct run_softc *sc = device_get_softc(self);
700203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
701203134Sthompsa	struct ieee80211com *ic;
702203134Sthompsa	struct ifnet *ifp;
703205042Sthompsa	uint32_t ver;
704259453Shselasky	int ntries, error;
705203134Sthompsa	uint8_t iface_index, bands;
706203134Sthompsa
707203134Sthompsa	device_set_usb_desc(self);
708203134Sthompsa	sc->sc_udev = uaa->device;
709203134Sthompsa	sc->sc_dev = self;
710262604Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
711262604Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
712203134Sthompsa
713203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
714203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
715203134Sthompsa
716203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
717208019Sthompsa
718203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
719203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
720203134Sthompsa	if (error) {
721205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
722203134Sthompsa		    "err=%s\n", usbd_errstr(error));
723203134Sthompsa		goto detach;
724203134Sthompsa	}
725203134Sthompsa
726203134Sthompsa	RUN_LOCK(sc);
727203134Sthompsa
728203134Sthompsa	/* wait for the chip to settle */
729203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
730209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
731203134Sthompsa			RUN_UNLOCK(sc);
732203134Sthompsa			goto detach;
733203134Sthompsa		}
734205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
735203134Sthompsa			break;
736203134Sthompsa		run_delay(sc, 10);
737203134Sthompsa	}
738203134Sthompsa	if (ntries == 100) {
739203138Sthompsa		device_printf(sc->sc_dev,
740203138Sthompsa		    "timeout waiting for NIC to initialize\n");
741203134Sthompsa		RUN_UNLOCK(sc);
742203134Sthompsa		goto detach;
743203134Sthompsa	}
744205042Sthompsa	sc->mac_ver = ver >> 16;
745205042Sthompsa	sc->mac_rev = ver & 0xffff;
746203134Sthompsa
747203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
748203134Sthompsa	run_read_eeprom(sc);
749203134Sthompsa
750203138Sthompsa	device_printf(sc->sc_dev,
751203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
752205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
753203138Sthompsa	    sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid));
754203134Sthompsa
755203134Sthompsa	RUN_UNLOCK(sc);
756203134Sthompsa
757203134Sthompsa	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
758220235Skevlo	if (ifp == NULL) {
759203138Sthompsa		device_printf(sc->sc_dev, "can not if_alloc()\n");
760203134Sthompsa		goto detach;
761203134Sthompsa	}
762203134Sthompsa	ic = ifp->if_l2com;
763203134Sthompsa
764203134Sthompsa	ifp->if_softc = sc;
765203134Sthompsa	if_initname(ifp, "run", device_get_unit(sc->sc_dev));
766203134Sthompsa	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
767203134Sthompsa	ifp->if_init = run_init;
768203134Sthompsa	ifp->if_ioctl = run_ioctl;
769203134Sthompsa	ifp->if_start = run_start;
770207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
771207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
772203134Sthompsa	IFQ_SET_READY(&ifp->if_snd);
773203134Sthompsa
774203134Sthompsa	ic->ic_ifp = ifp;
775203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
776203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
777208019Sthompsa
778203134Sthompsa	/* set device capabilities */
779203134Sthompsa	ic->ic_caps =
780203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
781203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
782203134Sthompsa	    IEEE80211_C_IBSS |
783203134Sthompsa	    IEEE80211_C_HOSTAP |
784208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
785208019Sthompsa	    IEEE80211_C_MBSS |
786203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
787203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
788203134Sthompsa	    IEEE80211_C_WME |		/* WME */
789214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
790203134Sthompsa
791203134Sthompsa	ic->ic_cryptocaps =
792203134Sthompsa	    IEEE80211_CRYPTO_WEP |
793203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
794203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
795203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
796203134Sthompsa
797203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
798203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
799203134Sthompsa
800203134Sthompsa	bands = 0;
801203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
802203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
803259453Shselasky	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
804261868Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
805261868Skevlo	    sc->rf_rev == RT5592_RF_5592)
806259453Shselasky		setbit(&bands, IEEE80211_MODE_11A);
807203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
808203134Sthompsa
809203134Sthompsa	ieee80211_ifattach(ic, sc->sc_bssid);
810203134Sthompsa
811203134Sthompsa	ic->ic_scan_start = run_scan_start;
812203134Sthompsa	ic->ic_scan_end = run_scan_end;
813203134Sthompsa	ic->ic_set_channel = run_set_channel;
814203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
815203134Sthompsa	ic->ic_newassoc = run_newassoc;
816218492Sbschmidt	ic->ic_updateslot = run_updateslot;
817208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
818203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
819203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
820203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
821203134Sthompsa
822203134Sthompsa	ic->ic_vap_create = run_vap_create;
823203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
824203134Sthompsa
825203134Sthompsa	ieee80211_radiotap_attach(ic,
826203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
827203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
828203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
829203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
830203134Sthompsa
831208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
832208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
833259453Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
834208019Sthompsa
835203134Sthompsa	if (bootverbose)
836203134Sthompsa		ieee80211_announce(ic);
837203134Sthompsa
838209917Sthompsa	return (0);
839203134Sthompsa
840203134Sthompsadetach:
841203134Sthompsa	run_detach(self);
842209917Sthompsa	return (ENXIO);
843203134Sthompsa}
844203134Sthompsa
845203134Sthompsastatic int
846203134Sthompsarun_detach(device_t self)
847203134Sthompsa{
848203134Sthompsa	struct run_softc *sc = device_get_softc(self);
849203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
850203134Sthompsa	struct ieee80211com *ic;
851203134Sthompsa	int i;
852203134Sthompsa
853246614Shselasky	RUN_LOCK(sc);
854246614Shselasky	sc->sc_detached = 1;
855246614Shselasky	RUN_UNLOCK(sc);
856246614Shselasky
857203134Sthompsa	/* stop all USB transfers */
858203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
859203134Sthompsa
860203134Sthompsa	RUN_LOCK(sc);
861209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
862209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
863209144Sthompsa
864203134Sthompsa	/* free TX list, if any */
865203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
866203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
867203134Sthompsa	RUN_UNLOCK(sc);
868203134Sthompsa
869203134Sthompsa	if (ifp) {
870203134Sthompsa		ic = ifp->if_l2com;
871208019Sthompsa		/* drain tasks */
872208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
873208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
874208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
875203134Sthompsa		ieee80211_ifdetach(ic);
876203134Sthompsa		if_free(ifp);
877203134Sthompsa	}
878203134Sthompsa
879203134Sthompsa	mtx_destroy(&sc->sc_mtx);
880203134Sthompsa
881203134Sthompsa	return (0);
882203134Sthompsa}
883203134Sthompsa
884203134Sthompsastatic struct ieee80211vap *
885228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
886228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
887203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
888203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
889203134Sthompsa{
890208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
891208019Sthompsa	struct run_softc *sc = ifp->if_softc;
892203134Sthompsa	struct run_vap *rvp;
893203134Sthompsa	struct ieee80211vap *vap;
894208019Sthompsa	int i;
895203134Sthompsa
896209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
897208019Sthompsa		if_printf(ifp, "number of VAPs maxed out\n");
898209917Sthompsa		return (NULL);
899208019Sthompsa	}
900208019Sthompsa
901208019Sthompsa	switch (opmode) {
902208019Sthompsa	case IEEE80211_M_STA:
903208019Sthompsa		/* enable s/w bmiss handling for sta mode */
904208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
905208019Sthompsa		/* fall though */
906208019Sthompsa	case IEEE80211_M_IBSS:
907208019Sthompsa	case IEEE80211_M_MONITOR:
908208019Sthompsa	case IEEE80211_M_HOSTAP:
909208019Sthompsa	case IEEE80211_M_MBSS:
910208019Sthompsa		/* other than WDS vaps, only one at a time */
911208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
912209917Sthompsa			return (NULL);
913208019Sthompsa		break;
914208019Sthompsa	case IEEE80211_M_WDS:
915208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
916208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
917208019Sthompsa				continue;
918208019Sthompsa			/* WDS vap's always share the local mac address. */
919208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
920208019Sthompsa			break;
921208019Sthompsa		}
922209917Sthompsa		if (vap == NULL) {
923208019Sthompsa			if_printf(ifp, "wds only supported in ap mode\n");
924209917Sthompsa			return (NULL);
925208019Sthompsa		}
926208019Sthompsa		break;
927208019Sthompsa	default:
928208019Sthompsa		if_printf(ifp, "unknown opmode %d\n", opmode);
929209917Sthompsa		return (NULL);
930208019Sthompsa	}
931208019Sthompsa
932208019Sthompsa	rvp = (struct run_vap *) malloc(sizeof(struct run_vap),
933203134Sthompsa	    M_80211_VAP, M_NOWAIT | M_ZERO);
934203134Sthompsa	if (rvp == NULL)
935209917Sthompsa		return (NULL);
936203134Sthompsa	vap = &rvp->vap;
937203134Sthompsa
938259453Shselasky	if (ieee80211_vap_setup(ic, vap, name, unit,
939259453Shselasky	    opmode, flags, bssid, mac) != 0) {
940259453Shselasky		/* out of memory */
941259453Shselasky		free(rvp, M_80211_VAP);
942259453Shselasky		return (NULL);
943259453Shselasky	}
944259453Shselasky
945203134Sthompsa	vap->iv_key_update_begin = run_key_update_begin;
946203134Sthompsa	vap->iv_key_update_end = run_key_update_end;
947203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
948208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
949208019Sthompsa	/*
950208019Sthompsa	 * To delete the right key from h/w, we need wcid.
951208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
952208019Sthompsa	 * and matching wcid will be written into there. So, cast
953208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
954208019Sthompsa	 */
955208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
956208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
957203134Sthompsa
958203134Sthompsa	/* override state transition machine */
959203134Sthompsa	rvp->newstate = vap->iv_newstate;
960203134Sthompsa	vap->iv_newstate = run_newstate;
961203134Sthompsa
962206358Srpaulo	ieee80211_ratectl_init(vap);
963206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
964203134Sthompsa
965203134Sthompsa	/* complete setup */
966203134Sthompsa	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status);
967208019Sthompsa
968208019Sthompsa	/* make sure id is always unique */
969209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
970208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
971208019Sthompsa			sc->rvp_bmap |= 1 << i;
972208019Sthompsa			rvp->rvp_id = i;
973208019Sthompsa			break;
974208019Sthompsa		}
975208019Sthompsa	}
976209917Sthompsa	if (sc->rvp_cnt++ == 0)
977208019Sthompsa		ic->ic_opmode = opmode;
978208019Sthompsa
979209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
980209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
981209144Sthompsa
982208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
983208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
984208019Sthompsa
985209917Sthompsa	return (vap);
986203134Sthompsa}
987203134Sthompsa
988203134Sthompsastatic void
989203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
990203134Sthompsa{
991203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
992203134Sthompsa	struct ifnet *ifp;
993203134Sthompsa	struct ieee80211com *ic;
994203134Sthompsa	struct run_softc *sc;
995208019Sthompsa	uint8_t rvp_id;
996203134Sthompsa
997209917Sthompsa	if (vap == NULL)
998203134Sthompsa		return;
999203134Sthompsa
1000203134Sthompsa	ic = vap->iv_ic;
1001203134Sthompsa	ifp = ic->ic_ifp;
1002203134Sthompsa
1003203134Sthompsa	sc = ifp->if_softc;
1004203134Sthompsa
1005205042Sthompsa	RUN_LOCK(sc);
1006208019Sthompsa
1007218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1008218492Sbschmidt	rvp->beacon_mbuf = NULL;
1009218492Sbschmidt
1010208019Sthompsa	rvp_id = rvp->rvp_id;
1011208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1012208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1013208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1014208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1015208019Sthompsa	--sc->rvp_cnt;
1016208019Sthompsa
1017208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1018208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1019208019Sthompsa
1020205042Sthompsa	RUN_UNLOCK(sc);
1021203134Sthompsa
1022206358Srpaulo	ieee80211_ratectl_deinit(vap);
1023203134Sthompsa	ieee80211_vap_detach(vap);
1024203134Sthompsa	free(rvp, M_80211_VAP);
1025203134Sthompsa}
1026203134Sthompsa
1027208019Sthompsa/*
1028208019Sthompsa * There are numbers of functions need to be called in context thread.
1029208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1030208019Sthompsa * here is all-for-one taskqueue callback function. This function
1031208019Sthompsa * gurantees deferred functions are executed in the same order they
1032208019Sthompsa * were enqueued.
1033208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1034208019Sthompsa */
1035203134Sthompsastatic void
1036208019Sthompsarun_cmdq_cb(void *arg, int pending)
1037208019Sthompsa{
1038208019Sthompsa	struct run_softc *sc = arg;
1039208019Sthompsa	uint8_t i;
1040208019Sthompsa
1041208019Sthompsa	/* call cmdq[].func locked */
1042208019Sthompsa	RUN_LOCK(sc);
1043209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1044209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1045208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1046209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1047208019Sthompsa			/*
1048208019Sthompsa			 * If arg0 is NULL, callback func needs more
1049208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1050208019Sthompsa			 */
1051209917Sthompsa			if (sc->cmdq[i].arg0)
1052208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1053208019Sthompsa			else
1054208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1055208019Sthompsa		}
1056208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1057208019Sthompsa		sc->cmdq[i].func = NULL;
1058208019Sthompsa		sc->cmdq_exec++;
1059208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1060208019Sthompsa	}
1061208019Sthompsa	RUN_UNLOCK(sc);
1062208019Sthompsa}
1063208019Sthompsa
1064208019Sthompsastatic void
1065203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1066203134Sthompsa{
1067203134Sthompsa	struct run_tx_data *data;
1068203134Sthompsa
1069203134Sthompsa	memset(pq, 0, sizeof(*pq));
1070203134Sthompsa
1071203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1072203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1073203134Sthompsa
1074203134Sthompsa	for (data = &pq->tx_data[0];
1075203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1076203134Sthompsa		data->sc = sc;
1077203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1078203134Sthompsa	}
1079203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1080203134Sthompsa}
1081203134Sthompsa
1082203134Sthompsastatic void
1083203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1084203134Sthompsa{
1085203134Sthompsa	struct run_tx_data *data;
1086203134Sthompsa
1087203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1088203134Sthompsa	pq->tx_nfree = 0;
1089203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1090203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1091203134Sthompsa
1092203134Sthompsa	/* free up all node references and mbufs */
1093203134Sthompsa	for (data = &pq->tx_data[0];
1094209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1095203134Sthompsa		if (data->m != NULL) {
1096203134Sthompsa			m_freem(data->m);
1097203134Sthompsa			data->m = NULL;
1098203134Sthompsa		}
1099203134Sthompsa		if (data->ni != NULL) {
1100203134Sthompsa			ieee80211_free_node(data->ni);
1101203134Sthompsa			data->ni = NULL;
1102203134Sthompsa		}
1103203134Sthompsa	}
1104203134Sthompsa}
1105203134Sthompsa
1106220235Skevlostatic int
1107203134Sthompsarun_load_microcode(struct run_softc *sc)
1108203134Sthompsa{
1109203134Sthompsa	usb_device_request_t req;
1110203137Sthompsa	const struct firmware *fw;
1111203134Sthompsa	const u_char *base;
1112203134Sthompsa	uint32_t tmp;
1113203134Sthompsa	int ntries, error;
1114203134Sthompsa	const uint64_t *temp;
1115203134Sthompsa	uint64_t bytes;
1116203134Sthompsa
1117205042Sthompsa	RUN_UNLOCK(sc);
1118203137Sthompsa	fw = firmware_get("runfw");
1119205042Sthompsa	RUN_LOCK(sc);
1120209917Sthompsa	if (fw == NULL) {
1121203138Sthompsa		device_printf(sc->sc_dev,
1122203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1123203134Sthompsa		return ENOENT;
1124203134Sthompsa	}
1125203134Sthompsa
1126203137Sthompsa	if (fw->datasize != 8192) {
1127203138Sthompsa		device_printf(sc->sc_dev,
1128203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1129203137Sthompsa		error = EINVAL;
1130203137Sthompsa		goto fail;
1131203134Sthompsa	}
1132203134Sthompsa
1133203134Sthompsa	/*
1134203134Sthompsa	 * RT3071/RT3072 use a different firmware
1135203134Sthompsa	 * run-rt2870 (8KB) contains both,
1136203134Sthompsa	 * first half (4KB) is for rt2870,
1137203134Sthompsa	 * last half is for rt3071.
1138203134Sthompsa	 */
1139203137Sthompsa	base = fw->data;
1140205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1141205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1142209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1143203134Sthompsa		base += 4096;
1144205042Sthompsa	}
1145203134Sthompsa
1146203134Sthompsa	/* cheap sanity check */
1147203137Sthompsa	temp = fw->data;
1148203134Sthompsa	bytes = *temp;
1149259453Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1150203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1151203137Sthompsa		error = EINVAL;
1152203137Sthompsa		goto fail;
1153203137Sthompsa	}
1154203134Sthompsa
1155203134Sthompsa	/* write microcode image */
1156262604Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1157261868Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1158261868Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1159261868Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1160261868Skevlo	}
1161203134Sthompsa
1162203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1163203134Sthompsa	req.bRequest = RT2870_RESET;
1164203134Sthompsa	USETW(req.wValue, 8);
1165203134Sthompsa	USETW(req.wIndex, 0);
1166203134Sthompsa	USETW(req.wLength, 0);
1167220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1168220235Skevlo	    != 0) {
1169203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1170203137Sthompsa		goto fail;
1171203137Sthompsa	}
1172203134Sthompsa
1173203134Sthompsa	run_delay(sc, 10);
1174203134Sthompsa
1175261868Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1176203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1177261868Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1178205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1179203137Sthompsa		goto fail;
1180203134Sthompsa
1181203134Sthompsa	/* wait until microcontroller is ready */
1182203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1183261868Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1184203137Sthompsa			goto fail;
1185203134Sthompsa		if (tmp & RT2860_MCU_READY)
1186203134Sthompsa			break;
1187203134Sthompsa		run_delay(sc, 10);
1188203134Sthompsa	}
1189203134Sthompsa	if (ntries == 1000) {
1190203138Sthompsa		device_printf(sc->sc_dev,
1191203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1192203137Sthompsa		error = ETIMEDOUT;
1193203137Sthompsa		goto fail;
1194203134Sthompsa	}
1195233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1196233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1197233283Sbschmidt	    *(base + 4092), *(base + 4093));
1198203134Sthompsa
1199203137Sthompsafail:
1200203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1201203137Sthompsa	return (error);
1202203134Sthompsa}
1203203134Sthompsa
1204259453Shselaskystatic int
1205203134Sthompsarun_reset(struct run_softc *sc)
1206203134Sthompsa{
1207203134Sthompsa	usb_device_request_t req;
1208203134Sthompsa
1209203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1210203134Sthompsa	req.bRequest = RT2870_RESET;
1211203134Sthompsa	USETW(req.wValue, 1);
1212203134Sthompsa	USETW(req.wIndex, 0);
1213203134Sthompsa	USETW(req.wLength, 0);
1214209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1215203134Sthompsa}
1216203134Sthompsa
1217203134Sthompsastatic usb_error_t
1218203134Sthompsarun_do_request(struct run_softc *sc,
1219203134Sthompsa    struct usb_device_request *req, void *data)
1220203134Sthompsa{
1221203134Sthompsa	usb_error_t err;
1222203134Sthompsa	int ntries = 10;
1223203134Sthompsa
1224203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1225203134Sthompsa
1226203134Sthompsa	while (ntries--) {
1227203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1228203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1229203134Sthompsa		if (err == 0)
1230203134Sthompsa			break;
1231203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1232203134Sthompsa		    usbd_errstr(err));
1233203134Sthompsa		run_delay(sc, 10);
1234203134Sthompsa	}
1235203134Sthompsa	return (err);
1236203134Sthompsa}
1237203134Sthompsa
1238203134Sthompsastatic int
1239203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1240203134Sthompsa{
1241203134Sthompsa	uint32_t tmp;
1242203134Sthompsa	int error;
1243203134Sthompsa
1244203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1245203134Sthompsa	if (error == 0)
1246203134Sthompsa		*val = le32toh(tmp);
1247203134Sthompsa	else
1248203134Sthompsa		*val = 0xffffffff;
1249209917Sthompsa	return (error);
1250203134Sthompsa}
1251203134Sthompsa
1252203134Sthompsastatic int
1253203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1254203134Sthompsa{
1255203134Sthompsa	usb_device_request_t req;
1256203134Sthompsa
1257203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1258203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1259203134Sthompsa	USETW(req.wValue, 0);
1260203134Sthompsa	USETW(req.wIndex, reg);
1261203134Sthompsa	USETW(req.wLength, len);
1262203134Sthompsa
1263209917Sthompsa	return (run_do_request(sc, &req, buf));
1264203134Sthompsa}
1265203134Sthompsa
1266203134Sthompsastatic int
1267203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1268203134Sthompsa{
1269203134Sthompsa	usb_device_request_t req;
1270203134Sthompsa
1271203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1272203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1273203134Sthompsa	USETW(req.wValue, val);
1274203134Sthompsa	USETW(req.wIndex, reg);
1275203134Sthompsa	USETW(req.wLength, 0);
1276203134Sthompsa
1277209917Sthompsa	return (run_do_request(sc, &req, NULL));
1278203134Sthompsa}
1279203134Sthompsa
1280203134Sthompsastatic int
1281203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1282203134Sthompsa{
1283203134Sthompsa	int error;
1284203134Sthompsa
1285203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1286203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1287209917Sthompsa	return (error);
1288203134Sthompsa}
1289203134Sthompsa
1290203134Sthompsastatic int
1291203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1292203134Sthompsa    int len)
1293203134Sthompsa{
1294203134Sthompsa#if 1
1295203134Sthompsa	int i, error = 0;
1296203134Sthompsa	/*
1297203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1298203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1299203134Sthompsa	 */
1300203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1301203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1302203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1303209917Sthompsa	return (error);
1304203134Sthompsa#else
1305203134Sthompsa	usb_device_request_t req;
1306259453Shselasky	int error = 0;
1307203134Sthompsa
1308259453Shselasky	/*
1309259453Shselasky	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1310259453Shselasky	 * passed a huge amount of data, which will crash the
1311259453Shselasky	 * firmware. Limit amount of data passed to 64-bytes at a
1312259453Shselasky	 * time.
1313259453Shselasky	 */
1314259453Shselasky	while (len > 0) {
1315259453Shselasky		int delta = 64;
1316259453Shselasky		if (delta > len)
1317259453Shselasky			delta = len;
1318259453Shselasky
1319259453Shselasky		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1320259453Shselasky		req.bRequest = RT2870_WRITE_REGION_1;
1321259453Shselasky		USETW(req.wValue, 0);
1322259453Shselasky		USETW(req.wIndex, reg);
1323259453Shselasky		USETW(req.wLength, delta);
1324259453Shselasky		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1325259453Shselasky		if (error != 0)
1326259453Shselasky			break;
1327259453Shselasky		reg += delta;
1328259453Shselasky		buf += delta;
1329259453Shselasky		len -= delta;
1330259453Shselasky	}
1331259453Shselasky	return (error);
1332203134Sthompsa#endif
1333203134Sthompsa}
1334203134Sthompsa
1335203134Sthompsastatic int
1336203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1337203134Sthompsa{
1338203134Sthompsa	int i, error = 0;
1339203134Sthompsa
1340203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1341203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1342203134Sthompsa		error = run_write(sc, reg + i, val);
1343209917Sthompsa	return (error);
1344203134Sthompsa}
1345203134Sthompsa
1346203134Sthompsastatic int
1347261868Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1348203134Sthompsa{
1349203134Sthompsa	uint32_t tmp;
1350203134Sthompsa	uint16_t reg;
1351203134Sthompsa	int error, ntries;
1352203134Sthompsa
1353203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1354209917Sthompsa		return (error);
1355203134Sthompsa
1356261868Skevlo	if (count == 2)
1357261868Skevlo		addr *= 2;
1358203134Sthompsa	/*-
1359203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1360203134Sthompsa	 * DATA0: F E D C
1361203134Sthompsa	 * DATA1: B A 9 8
1362203134Sthompsa	 * DATA2: 7 6 5 4
1363203134Sthompsa	 * DATA3: 3 2 1 0
1364203134Sthompsa	 */
1365203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1366203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1367203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1368203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1369203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1370209917Sthompsa			return (error);
1371203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1372203134Sthompsa			break;
1373203134Sthompsa		run_delay(sc, 2);
1374203134Sthompsa	}
1375203134Sthompsa	if (ntries == 100)
1376209917Sthompsa		return (ETIMEDOUT);
1377203134Sthompsa
1378203134Sthompsa	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1379203134Sthompsa		*val = 0xffff;	/* address not found */
1380209917Sthompsa		return (0);
1381203134Sthompsa	}
1382203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1383203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1384203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1385209917Sthompsa		return (error);
1386203134Sthompsa
1387261868Skevlo	tmp >>= (8 * (addr & 0x3));
1388261868Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1389261868Skevlo
1390209917Sthompsa	return (0);
1391203134Sthompsa}
1392203134Sthompsa
1393261868Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1394203134Sthompsastatic int
1395261868Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1396261868Skevlo{
1397261868Skevlo	return (run_efuse_read(sc, addr, val, 2));
1398261868Skevlo}
1399261868Skevlo
1400261868Skevlostatic int
1401203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1402203134Sthompsa{
1403203134Sthompsa	usb_device_request_t req;
1404203134Sthompsa	uint16_t tmp;
1405203134Sthompsa	int error;
1406203134Sthompsa
1407203134Sthompsa	addr *= 2;
1408203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1409203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1410203134Sthompsa	USETW(req.wValue, 0);
1411203134Sthompsa	USETW(req.wIndex, addr);
1412261868Skevlo	USETW(req.wLength, sizeof(tmp));
1413203134Sthompsa
1414203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1415203134Sthompsa	if (error == 0)
1416203134Sthompsa		*val = le16toh(tmp);
1417203134Sthompsa	else
1418203134Sthompsa		*val = 0xffff;
1419209917Sthompsa	return (error);
1420203134Sthompsa}
1421203134Sthompsa
1422203134Sthompsastatic __inline int
1423203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1424203134Sthompsa{
1425203134Sthompsa	/* either eFUSE ROM or EEPROM */
1426203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1427203134Sthompsa}
1428203134Sthompsa
1429203134Sthompsastatic int
1430259453Shselaskyrun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1431203134Sthompsa{
1432203134Sthompsa	uint32_t tmp;
1433203134Sthompsa	int error, ntries;
1434203134Sthompsa
1435203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1436203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1437209917Sthompsa			return (error);
1438203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1439203134Sthompsa			break;
1440203134Sthompsa	}
1441203134Sthompsa	if (ntries == 10)
1442209917Sthompsa		return (ETIMEDOUT);
1443203134Sthompsa
1444259453Shselasky	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1445203134Sthompsa}
1446203134Sthompsa
1447203134Sthompsastatic int
1448203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1449203134Sthompsa{
1450203134Sthompsa	uint32_t tmp;
1451203134Sthompsa	int error, ntries;
1452203134Sthompsa
1453203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1454203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1455209917Sthompsa			return (error);
1456203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1457203134Sthompsa			break;
1458203134Sthompsa	}
1459203134Sthompsa	if (ntries == 100)
1460209917Sthompsa		return (ETIMEDOUT);
1461203134Sthompsa
1462203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1463203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1464209917Sthompsa		return (error);
1465203134Sthompsa
1466203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1467203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1468209917Sthompsa			return (error);
1469203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1470203134Sthompsa			break;
1471203134Sthompsa	}
1472203134Sthompsa	if (ntries == 100)
1473209917Sthompsa		return (ETIMEDOUT);
1474203134Sthompsa
1475203134Sthompsa	*val = tmp & 0xff;
1476209917Sthompsa	return (0);
1477203134Sthompsa}
1478203134Sthompsa
1479203134Sthompsastatic int
1480203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1481203134Sthompsa{
1482203134Sthompsa	uint32_t tmp;
1483203134Sthompsa	int error, ntries;
1484203134Sthompsa
1485203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1486203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1487209917Sthompsa			return (error);
1488203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1489203134Sthompsa			break;
1490203134Sthompsa	}
1491203134Sthompsa	if (ntries == 10)
1492209917Sthompsa		return (ETIMEDOUT);
1493203134Sthompsa
1494203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1495209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1496203134Sthompsa}
1497203134Sthompsa
1498203134Sthompsastatic int
1499203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1500203134Sthompsa{
1501203134Sthompsa	uint32_t tmp;
1502203134Sthompsa	int ntries, error;
1503203134Sthompsa
1504203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1505203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1506209917Sthompsa			return (error);
1507203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1508203134Sthompsa			break;
1509203134Sthompsa	}
1510203134Sthompsa	if (ntries == 10)
1511209917Sthompsa		return (ETIMEDOUT);
1512203134Sthompsa
1513203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1514203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1515209917Sthompsa		return (error);
1516203134Sthompsa
1517203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1518203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1519209917Sthompsa			return (error);
1520203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1521203134Sthompsa			break;
1522203134Sthompsa	}
1523203134Sthompsa	if (ntries == 10)
1524209917Sthompsa		return (ETIMEDOUT);
1525203134Sthompsa
1526203134Sthompsa	*val = tmp & 0xff;
1527209917Sthompsa	return (0);
1528203134Sthompsa}
1529203134Sthompsa
1530203134Sthompsastatic int
1531203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1532203134Sthompsa{
1533203134Sthompsa	uint32_t tmp;
1534203134Sthompsa	int ntries, error;
1535203134Sthompsa
1536203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1537203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1538209917Sthompsa			return (error);
1539203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1540203134Sthompsa			break;
1541203134Sthompsa	}
1542203134Sthompsa	if (ntries == 10)
1543209917Sthompsa		return (ETIMEDOUT);
1544203134Sthompsa
1545203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1546209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1547203134Sthompsa}
1548203134Sthompsa
1549203134Sthompsa/*
1550203134Sthompsa * Send a command to the 8051 microcontroller unit.
1551203134Sthompsa */
1552203134Sthompsastatic int
1553203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1554203134Sthompsa{
1555203134Sthompsa	uint32_t tmp;
1556203134Sthompsa	int error, ntries;
1557203134Sthompsa
1558203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1559203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1560203134Sthompsa			return error;
1561203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1562203134Sthompsa			break;
1563203134Sthompsa	}
1564203134Sthompsa	if (ntries == 100)
1565203134Sthompsa		return ETIMEDOUT;
1566203134Sthompsa
1567203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1568203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1569203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1570209917Sthompsa	return (error);
1571203134Sthompsa}
1572203134Sthompsa
1573203134Sthompsa/*
1574203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1575203134Sthompsa * Used to adjust per-rate Tx power registers.
1576203134Sthompsa */
1577203134Sthompsastatic __inline uint32_t
1578203134Sthompsab4inc(uint32_t b32, int8_t delta)
1579203134Sthompsa{
1580203134Sthompsa	int8_t i, b4;
1581203134Sthompsa
1582203134Sthompsa	for (i = 0; i < 8; i++) {
1583203134Sthompsa		b4 = b32 & 0xf;
1584203134Sthompsa		b4 += delta;
1585203134Sthompsa		if (b4 < 0)
1586203134Sthompsa			b4 = 0;
1587203134Sthompsa		else if (b4 > 0xf)
1588203134Sthompsa			b4 = 0xf;
1589203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1590203134Sthompsa	}
1591209917Sthompsa	return (b32);
1592203134Sthompsa}
1593203134Sthompsa
1594203134Sthompsastatic const char *
1595259453Shselaskyrun_get_rf(uint16_t rev)
1596203134Sthompsa{
1597203134Sthompsa	switch (rev) {
1598203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1599203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1600203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1601203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1602203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1603203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1604203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1605203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1606203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1607261868Skevlo	case RT3593_RF_3053:	return "RT3053";
1608259453Shselasky	case RT5592_RF_5592:	return "RT5592";
1609259453Shselasky	case RT5390_RF_5370:	return "RT5370";
1610259453Shselasky	case RT5390_RF_5372:	return "RT5372";
1611203134Sthompsa	}
1612209917Sthompsa	return ("unknown");
1613203134Sthompsa}
1614203134Sthompsa
1615261868Skevlostatic void
1616261868Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1617261868Skevlo{
1618261868Skevlo	uint16_t addr, val;
1619261868Skevlo	int i;
1620261868Skevlo
1621261868Skevlo	/* Read power settings for 2GHz channels. */
1622261868Skevlo	for (i = 0; i < 14; i += 2) {
1623261868Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1624261868Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1625261868Skevlo		run_srom_read(sc, addr + i / 2, &val);
1626261868Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1627261868Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1628261868Skevlo
1629261868Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1630261868Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1631261868Skevlo		run_srom_read(sc, addr + i / 2, &val);
1632261868Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1633261868Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1634261868Skevlo
1635261868Skevlo		if (sc->ntxchains == 3) {
1636261868Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1637261868Skevlo			    &val);
1638261868Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1639261868Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1640261868Skevlo		}
1641261868Skevlo	}
1642261868Skevlo	/* Fix broken Tx power entries. */
1643261868Skevlo	for (i = 0; i < 14; i++) {
1644261868Skevlo		if (sc->txpow1[i] > 31)
1645261868Skevlo			sc->txpow1[i] = 5;
1646261868Skevlo		if (sc->txpow2[i] > 31)
1647261868Skevlo			sc->txpow2[i] = 5;
1648261868Skevlo		if (sc->ntxchains == 3) {
1649261868Skevlo			if (sc->txpow3[i] > 31)
1650261868Skevlo				sc->txpow3[i] = 5;
1651261868Skevlo		}
1652261868Skevlo	}
1653261868Skevlo	/* Read power settings for 5GHz channels. */
1654261868Skevlo	for (i = 0; i < 40; i += 2) {
1655261868Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1656261868Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1657261868Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1658261868Skevlo
1659261868Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1660261868Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1661261868Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1662261868Skevlo
1663261868Skevlo		if (sc->ntxchains == 3) {
1664261868Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1665261868Skevlo			    &val);
1666261868Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1667261868Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1668261868Skevlo		}
1669261868Skevlo	}
1670261868Skevlo}
1671261868Skevlo
1672261868Skevlostatic void
1673261868Skevlorun_get_txpower(struct run_softc *sc)
1674261868Skevlo{
1675261868Skevlo	uint16_t val;
1676261868Skevlo	int i;
1677261868Skevlo
1678261868Skevlo	/* Read power settings for 2GHz channels. */
1679261868Skevlo	for (i = 0; i < 14; i += 2) {
1680261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1681261868Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1682261868Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1683261868Skevlo
1684261868Skevlo		if (sc->mac_ver != 0x5390) {
1685261868Skevlo			run_srom_read(sc,
1686261868Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1687261868Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1688261868Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1689261868Skevlo		}
1690261868Skevlo	}
1691261868Skevlo	/* Fix broken Tx power entries. */
1692261868Skevlo	for (i = 0; i < 14; i++) {
1693261868Skevlo		if (sc->mac_ver >= 0x5390) {
1694261868Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1695261868Skevlo				sc->txpow1[i] = 5;
1696261868Skevlo		} else {
1697261868Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1698261868Skevlo				sc->txpow1[i] = 5;
1699261868Skevlo		}
1700261868Skevlo		if (sc->mac_ver > 0x5390) {
1701261868Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1702261868Skevlo				sc->txpow2[i] = 5;
1703261868Skevlo		} else if (sc->mac_ver < 0x5390) {
1704261868Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1705261868Skevlo				sc->txpow2[i] = 5;
1706261868Skevlo		}
1707261868Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1708261868Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1709261868Skevlo	}
1710261868Skevlo	/* Read power settings for 5GHz channels. */
1711261868Skevlo	for (i = 0; i < 40; i += 2) {
1712261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1713261868Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1714261868Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1715261868Skevlo
1716261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1717261868Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1718261868Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1719261868Skevlo	}
1720261868Skevlo	/* Fix broken Tx power entries. */
1721261868Skevlo	for (i = 0; i < 40; i++ ) {
1722261868Skevlo		if (sc->mac_ver != 0x5592) {
1723261868Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1724261868Skevlo				sc->txpow1[14 + i] = 5;
1725261868Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1726261868Skevlo				sc->txpow2[14 + i] = 5;
1727261868Skevlo		}
1728261868Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1729261868Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1730261868Skevlo		    sc->txpow2[14 + i]);
1731261868Skevlo	}
1732261868Skevlo}
1733261868Skevlo
1734259453Shselaskystatic int
1735203134Sthompsarun_read_eeprom(struct run_softc *sc)
1736203134Sthompsa{
1737203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1738203134Sthompsa	uint32_t tmp;
1739203134Sthompsa	uint16_t val;
1740203134Sthompsa	int ridx, ant, i;
1741203134Sthompsa
1742203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1743203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1744205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1745203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1746203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1747261868Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1748203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1749203134Sthompsa	}
1750203134Sthompsa
1751203134Sthompsa	/* read ROM version */
1752203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1753203134Sthompsa	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1754203134Sthompsa
1755203134Sthompsa	/* read MAC address */
1756203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1757203134Sthompsa	sc->sc_bssid[0] = val & 0xff;
1758203134Sthompsa	sc->sc_bssid[1] = val >> 8;
1759203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1760203134Sthompsa	sc->sc_bssid[2] = val & 0xff;
1761203134Sthompsa	sc->sc_bssid[3] = val >> 8;
1762203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1763203134Sthompsa	sc->sc_bssid[4] = val & 0xff;
1764203134Sthompsa	sc->sc_bssid[5] = val >> 8;
1765203134Sthompsa
1766261868Skevlo	if (sc->mac_ver < 0x3593) {
1767259453Shselasky		/* read vender BBP settings */
1768205042Sthompsa		for (i = 0; i < 10; i++) {
1769259453Shselasky			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1770259453Shselasky			sc->bbp[i].val = val & 0xff;
1771259453Shselasky			sc->bbp[i].reg = val >> 8;
1772259453Shselasky			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1773259453Shselasky			    sc->bbp[i].val);
1774205042Sthompsa		}
1775259453Shselasky		if (sc->mac_ver >= 0x3071) {
1776259453Shselasky			/* read vendor RF settings */
1777259453Shselasky			for (i = 0; i < 10; i++) {
1778259453Shselasky				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1779259453Shselasky				   &val);
1780259453Shselasky				sc->rf[i].val = val & 0xff;
1781259453Shselasky				sc->rf[i].reg = val >> 8;
1782259453Shselasky				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1783259453Shselasky				    sc->rf[i].val);
1784259453Shselasky			}
1785259453Shselasky		}
1786205042Sthompsa	}
1787203134Sthompsa
1788203134Sthompsa	/* read RF frequency offset from EEPROM */
1789261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1790261868Skevlo	    RT3593_EEPROM_FREQ, &val);
1791203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1792203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1793203134Sthompsa
1794261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1795261868Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1796205042Sthompsa	if (val >> 8 != 0xff) {
1797203134Sthompsa		/* read LEDs operating mode */
1798205042Sthompsa		sc->leds = val >> 8;
1799261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1800261868Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1801261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1802261868Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1803261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1804261868Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1805203134Sthompsa	} else {
1806203134Sthompsa		/* broken EEPROM, use default settings */
1807203134Sthompsa		sc->leds = 0x01;
1808203134Sthompsa		sc->led[0] = 0x5555;
1809203134Sthompsa		sc->led[1] = 0x2221;
1810203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1811203134Sthompsa	}
1812203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1813203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1814203134Sthompsa
1815203134Sthompsa	/* read RF information */
1816259453Shselasky	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1817259453Shselasky		run_srom_read(sc, 0x00, &val);
1818259453Shselasky	else
1819259453Shselasky		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1820259453Shselasky
1821203134Sthompsa	if (val == 0xffff) {
1822261868Skevlo		device_printf(sc->sc_dev,
1823261868Skevlo		    "invalid EEPROM antenna info, using default\n");
1824203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1825205042Sthompsa		if (sc->mac_ver == 0x3572) {
1826205042Sthompsa			/* default to RF3052 2T2R */
1827205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1828205042Sthompsa			sc->ntxchains = 2;
1829205042Sthompsa			sc->nrxchains = 2;
1830205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1831203134Sthompsa			/* default to RF3020 1T1R */
1832203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1833203134Sthompsa			sc->ntxchains = 1;
1834203134Sthompsa			sc->nrxchains = 1;
1835203134Sthompsa		} else {
1836203134Sthompsa			/* default to RF2820 1T2R */
1837203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1838203134Sthompsa			sc->ntxchains = 1;
1839203134Sthompsa			sc->nrxchains = 2;
1840203134Sthompsa		}
1841203134Sthompsa	} else {
1842259453Shselasky		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1843259453Shselasky			sc->rf_rev = val;
1844259453Shselasky			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1845259453Shselasky		} else
1846259453Shselasky			sc->rf_rev = (val >> 8) & 0xf;
1847203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1848203134Sthompsa		sc->nrxchains = val & 0xf;
1849203134Sthompsa	}
1850259453Shselasky	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1851203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1852203134Sthompsa
1853208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1854203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1855203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1856205042Sthompsa	/* check if driver should patch the DAC issue */
1857205042Sthompsa	if ((val >> 8) != 0xff)
1858205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1859203134Sthompsa	if ((val & 0xff) != 0xff) {
1860203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1861203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1862205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1863203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1864205042Sthompsa		/* check if we have a hardware radio switch */
1865205042Sthompsa		sc->rfswitch = val & 1;
1866203134Sthompsa	}
1867203134Sthompsa
1868261868Skevlo	/* Read Tx power settings. */
1869261868Skevlo	if (sc->mac_ver == 0x3593)
1870261868Skevlo		run_rt3593_get_txpower(sc);
1871261868Skevlo	else
1872261868Skevlo		run_get_txpower(sc);
1873203134Sthompsa
1874203134Sthompsa	/* read Tx power compensation for each Tx rate */
1875203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1876203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1877203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1878203134Sthompsa		delta_2ghz = val & 0xf;
1879203134Sthompsa		if (!(val & 0x40))	/* negative number */
1880203134Sthompsa			delta_2ghz = -delta_2ghz;
1881203134Sthompsa	}
1882203134Sthompsa	val >>= 8;
1883203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1884203134Sthompsa		delta_5ghz = val & 0xf;
1885203134Sthompsa		if (!(val & 0x40))	/* negative number */
1886203134Sthompsa			delta_5ghz = -delta_5ghz;
1887203134Sthompsa	}
1888203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1889203134Sthompsa	    delta_2ghz, delta_5ghz);
1890203134Sthompsa
1891203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1892203134Sthompsa		uint32_t reg;
1893203134Sthompsa
1894208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1895208019Sthompsa		reg = val;
1896208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1897208019Sthompsa		reg |= (uint32_t)val << 16;
1898203134Sthompsa
1899203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1900203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1901203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1902203134Sthompsa
1903203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1904203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1905203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1906203134Sthompsa	}
1907203134Sthompsa
1908261868Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1909261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1910261868Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1911203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1912203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1913261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1914261868Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1915205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1916261868Skevlo		if (sc->mac_ver == 0x3593) {
1917261868Skevlo			sc->txmixgain_2ghz = 0;
1918261868Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1919261868Skevlo		} else {
1920261868Skevlo			/*
1921261868Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1922261868Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1923261868Skevlo			 */
1924261868Skevlo			if ((val & 0xff) != 0xff)
1925261868Skevlo				sc->txmixgain_2ghz = val & 0x7;
1926261868Skevlo		}
1927205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1928205042Sthompsa	} else
1929205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1930261868Skevlo	if (sc->mac_ver == 0x3593)
1931261868Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1932203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1933203134Sthompsa
1934261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1935261868Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1936203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1937203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1938261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1939261868Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1940205042Sthompsa	if (sc->mac_ver == 0x3572) {
1941205042Sthompsa		/*
1942205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1943205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1944205042Sthompsa		 */
1945205042Sthompsa		if ((val & 0xff) != 0xff)
1946205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1947205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1948205042Sthompsa	} else
1949205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1950261868Skevlo	if (sc->mac_ver == 0x3593) {
1951261868Skevlo		sc->txmixgain_5ghz = 0;
1952261868Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1953261868Skevlo	}
1954203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1955203134Sthompsa
1956261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1957261868Skevlo	    RT3593_EEPROM_LNA, &val);
1958203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1959203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1960203134Sthompsa
1961203134Sthompsa	/* fix broken 5GHz LNA entries */
1962203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1963203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1964203134Sthompsa		sc->lna[2] = sc->lna[1];
1965203134Sthompsa	}
1966203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1967203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1968203134Sthompsa		sc->lna[3] = sc->lna[1];
1969203134Sthompsa	}
1970203134Sthompsa
1971203134Sthompsa	/* fix broken RSSI offset entries */
1972203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1973203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1974203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1975203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1976203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1977203134Sthompsa		}
1978203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1979203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1980203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1981203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1982203134Sthompsa		}
1983203134Sthompsa	}
1984209917Sthompsa	return (0);
1985203134Sthompsa}
1986203134Sthompsa
1987218676Shselaskystatic struct ieee80211_node *
1988203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1989203134Sthompsa{
1990343821Savos	return malloc(sizeof (struct run_node), M_80211_NODE,
1991343821Savos	    M_NOWAIT | M_ZERO);
1992203134Sthompsa}
1993203134Sthompsa
1994203134Sthompsastatic int
1995203134Sthompsarun_media_change(struct ifnet *ifp)
1996203134Sthompsa{
1997208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1998208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1999203134Sthompsa	const struct ieee80211_txparam *tp;
2000208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2001203134Sthompsa	uint8_t rate, ridx;
2002203134Sthompsa	int error;
2003203134Sthompsa
2004203134Sthompsa	RUN_LOCK(sc);
2005203134Sthompsa
2006203134Sthompsa	error = ieee80211_media_change(ifp);
2007209917Sthompsa	if (error != ENETRESET) {
2008203134Sthompsa		RUN_UNLOCK(sc);
2009209917Sthompsa		return (error);
2010208019Sthompsa	}
2011203134Sthompsa
2012203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2013203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2014212127Sthompsa		struct ieee80211_node *ni;
2015212127Sthompsa		struct run_node	*rn;
2016212127Sthompsa
2017203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2018203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2019203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2020203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2021203134Sthompsa				break;
2022212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2023212127Sthompsa		rn = (struct run_node *)ni;
2024208019Sthompsa		rn->fix_ridx = ridx;
2025208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2026212127Sthompsa		ieee80211_free_node(ni);
2027203134Sthompsa	}
2028203134Sthompsa
2029208019Sthompsa#if 0
2030203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2031203134Sthompsa	    (ifp->if_drv_flags &  IFF_DRV_RUNNING)){
2032203134Sthompsa		run_init_locked(sc);
2033203134Sthompsa	}
2034208019Sthompsa#endif
2035203134Sthompsa
2036203134Sthompsa	RUN_UNLOCK(sc);
2037203134Sthompsa
2038209917Sthompsa	return (0);
2039203134Sthompsa}
2040203134Sthompsa
2041203134Sthompsastatic int
2042203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2043203134Sthompsa{
2044203134Sthompsa	const struct ieee80211_txparam *tp;
2045203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2046203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2047203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2048203134Sthompsa	enum ieee80211_state ostate;
2049208019Sthompsa	uint32_t sta[3];
2050203134Sthompsa	uint32_t tmp;
2051208019Sthompsa	uint8_t ratectl;
2052208019Sthompsa	uint8_t restart_ratectl = 0;
2053208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2054203134Sthompsa
2055203134Sthompsa	ostate = vap->iv_state;
2056203134Sthompsa	DPRINTF("%s -> %s\n",
2057203134Sthompsa		ieee80211_state_name[ostate],
2058203134Sthompsa		ieee80211_state_name[nstate]);
2059203134Sthompsa
2060203134Sthompsa	IEEE80211_UNLOCK(ic);
2061203134Sthompsa	RUN_LOCK(sc);
2062203134Sthompsa
2063208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2064208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2065208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2066203134Sthompsa
2067203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2068203134Sthompsa		/* turn link LED off */
2069203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2070203134Sthompsa	}
2071203134Sthompsa
2072203134Sthompsa	switch (nstate) {
2073203134Sthompsa	case IEEE80211_S_INIT:
2074208019Sthompsa		restart_ratectl = 1;
2075208019Sthompsa
2076208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2077208019Sthompsa			break;
2078208019Sthompsa
2079208019Sthompsa		ratectl &= ~bid;
2080208019Sthompsa		sc->runbmap &= ~bid;
2081208019Sthompsa
2082208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2083209917Sthompsa		if (--sc->running == 0) {
2084203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2085203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2086203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2087203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2088203134Sthompsa		}
2089203134Sthompsa		break;
2090203134Sthompsa
2091203134Sthompsa	case IEEE80211_S_RUN:
2092209917Sthompsa		if (!(sc->runbmap & bid)) {
2093208019Sthompsa			if(sc->running++)
2094208019Sthompsa				restart_ratectl = 1;
2095208019Sthompsa			sc->runbmap |= bid;
2096208019Sthompsa		}
2097203134Sthompsa
2098218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2099218492Sbschmidt		rvp->beacon_mbuf = NULL;
2100218492Sbschmidt
2101209917Sthompsa		switch (vap->iv_opmode) {
2102208019Sthompsa		case IEEE80211_M_HOSTAP:
2103208019Sthompsa		case IEEE80211_M_MBSS:
2104208019Sthompsa			sc->ap_running |= bid;
2105208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2106208019Sthompsa			run_update_beacon_cb(vap);
2107208019Sthompsa			break;
2108208019Sthompsa		case IEEE80211_M_IBSS:
2109208019Sthompsa			sc->adhoc_running |= bid;
2110209917Sthompsa			if (!sc->ap_running)
2111208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2112208019Sthompsa			run_update_beacon_cb(vap);
2113208019Sthompsa			break;
2114208019Sthompsa		case IEEE80211_M_STA:
2115208019Sthompsa			sc->sta_running |= bid;
2116209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2117208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2118208019Sthompsa
2119208019Sthompsa			/* read statistic counters (clear on read) */
2120208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2121208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2122208019Sthompsa
2123208019Sthompsa			break;
2124208019Sthompsa		default:
2125208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2126208019Sthompsa			break;
2127208019Sthompsa		}
2128208019Sthompsa
2129203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2130212127Sthompsa			struct ieee80211_node *ni;
2131212127Sthompsa
2132236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2133236439Shselasky				RUN_UNLOCK(sc);
2134236439Shselasky				IEEE80211_LOCK(ic);
2135236439Shselasky				return (-1);
2136236439Shselasky			}
2137203134Sthompsa			run_updateslot(ic->ic_ifp);
2138203134Sthompsa			run_enable_mrr(sc);
2139203134Sthompsa			run_set_txpreamble(sc);
2140203134Sthompsa			run_set_basicrates(sc);
2141212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2142203134Sthompsa			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
2143203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2144212127Sthompsa			ieee80211_free_node(ni);
2145208019Sthompsa			run_enable_tsf_sync(sc);
2146203134Sthompsa
2147208019Sthompsa			/* enable automatic rate adaptation */
2148208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2149208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2150208019Sthompsa				ratectl |= bid;
2151203134Sthompsa		}
2152203134Sthompsa
2153203134Sthompsa		/* turn link LED on */
2154203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2155208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2156203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2157203134Sthompsa
2158203134Sthompsa		break;
2159203134Sthompsa	default:
2160203134Sthompsa		DPRINTFN(6, "undefined case\n");
2161203134Sthompsa		break;
2162203134Sthompsa	}
2163203134Sthompsa
2164208019Sthompsa	/* restart amrr for running VAPs */
2165209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2166208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2167208019Sthompsa
2168203134Sthompsa	RUN_UNLOCK(sc);
2169203134Sthompsa	IEEE80211_LOCK(ic);
2170203134Sthompsa
2171203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2172203134Sthompsa}
2173203134Sthompsa
2174203134Sthompsa/* ARGSUSED */
2175203134Sthompsastatic void
2176208019Sthompsarun_wme_update_cb(void *arg)
2177203134Sthompsa{
2178203134Sthompsa	struct ieee80211com *ic = arg;
2179203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2180203134Sthompsa	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
2181203134Sthompsa	int aci, error = 0;
2182203134Sthompsa
2183208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2184203134Sthompsa
2185203134Sthompsa	/* update MAC TX configuration registers */
2186203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2187203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2188203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
2189203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
2190203134Sthompsa		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
2191203134Sthompsa		    wmesp->wme_params[aci].wmep_txopLimit);
2192209917Sthompsa		if (error) goto err;
2193203134Sthompsa	}
2194203134Sthompsa
2195203134Sthompsa	/* update SCH/DMA registers too */
2196203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2197203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
2198203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
2199203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
2200203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
2201209917Sthompsa	if (error) goto err;
2202203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2203203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
2204203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
2205203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
2206203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
2207209917Sthompsa	if (error) goto err;
2208203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2209203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
2210203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
2211203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
2212203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
2213209917Sthompsa	if (error) goto err;
2214203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2215203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
2216203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
2217209917Sthompsa	if (error) goto err;
2218203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2219203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
2220203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
2221203134Sthompsa
2222203134Sthompsaerr:
2223209917Sthompsa	if (error)
2224203134Sthompsa		DPRINTF("WME update failed\n");
2225203134Sthompsa
2226203134Sthompsa	return;
2227203134Sthompsa}
2228203134Sthompsa
2229208019Sthompsastatic int
2230208019Sthompsarun_wme_update(struct ieee80211com *ic)
2231208019Sthompsa{
2232208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2233208019Sthompsa
2234208019Sthompsa	/* sometime called wothout lock */
2235209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2236208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2237208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2238208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2239208019Sthompsa		sc->cmdq[i].arg0 = ic;
2240208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2241209918Sthompsa		return (0);
2242208019Sthompsa	}
2243208019Sthompsa
2244208019Sthompsa	RUN_LOCK(sc);
2245208019Sthompsa	run_wme_update_cb(ic);
2246208019Sthompsa	RUN_UNLOCK(sc);
2247208019Sthompsa
2248208019Sthompsa	/* return whatever, upper layer desn't care anyway */
2249208019Sthompsa	return (0);
2250208019Sthompsa}
2251208019Sthompsa
2252203134Sthompsastatic void
2253203134Sthompsarun_key_update_begin(struct ieee80211vap *vap)
2254203134Sthompsa{
2255203134Sthompsa	/*
2256208019Sthompsa	 * To avoid out-of-order events, both run_key_set() and
2257208019Sthompsa	 * _delete() are deferred and handled by run_cmdq_cb().
2258208019Sthompsa	 * So, there is nothing we need to do here.
2259203134Sthompsa	 */
2260203134Sthompsa}
2261203134Sthompsa
2262203134Sthompsastatic void
2263203134Sthompsarun_key_update_end(struct ieee80211vap *vap)
2264203134Sthompsa{
2265203134Sthompsa	/* null */
2266203134Sthompsa}
2267203134Sthompsa
2268208019Sthompsastatic void
2269208019Sthompsarun_key_set_cb(void *arg)
2270203134Sthompsa{
2271208019Sthompsa	struct run_cmdq *cmdq = arg;
2272208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2273208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2274203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2275208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2276203134Sthompsa	struct ieee80211_node *ni;
2277203134Sthompsa	uint32_t attr;
2278203134Sthompsa	uint16_t base, associd;
2279209144Sthompsa	uint8_t mode, wcid, iv[8];
2280203134Sthompsa
2281208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2282203134Sthompsa
2283209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2284208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2285209144Sthompsa	else
2286203134Sthompsa		ni = vap->iv_bss;
2287208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2288203134Sthompsa
2289203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2290203134Sthompsa	switch (k->wk_cipher->ic_cipher) {
2291203134Sthompsa	case IEEE80211_CIPHER_WEP:
2292203134Sthompsa		if(k->wk_keylen < 8)
2293203134Sthompsa			mode = RT2860_MODE_WEP40;
2294203134Sthompsa		else
2295203134Sthompsa			mode = RT2860_MODE_WEP104;
2296203134Sthompsa		break;
2297203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2298203134Sthompsa		mode = RT2860_MODE_TKIP;
2299203134Sthompsa		break;
2300203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2301203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2302203134Sthompsa		break;
2303203134Sthompsa	default:
2304203134Sthompsa		DPRINTF("undefined case\n");
2305208019Sthompsa		return;
2306203134Sthompsa	}
2307203134Sthompsa
2308208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2309203134Sthompsa	    associd, k->wk_keyix, mode,
2310208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2311208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2312208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2313203134Sthompsa
2314203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2315203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2316208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2317203134Sthompsa	} else {
2318245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2319245047Shselasky		    1 : RUN_AID2WCID(associd);
2320203134Sthompsa		base = RT2860_PKEY(wcid);
2321203134Sthompsa	}
2322203134Sthompsa
2323203134Sthompsa	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2324203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2325208019Sthompsa			return;
2326209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2327208019Sthompsa			return;
2328209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2329208019Sthompsa			return;
2330203134Sthompsa	} else {
2331203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2332203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2333208019Sthompsa			return;
2334203134Sthompsa	}
2335203134Sthompsa
2336203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2337203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2338203134Sthompsa		/* set initial packet number in IV+EIV */
2339209917Sthompsa		if (k->wk_cipher == IEEE80211_CIPHER_WEP) {
2340203134Sthompsa			memset(iv, 0, sizeof iv);
2341208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2342203134Sthompsa		} else {
2343203134Sthompsa			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2344203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2345203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2346203134Sthompsa				iv[2] = k->wk_keytsc;
2347203134Sthompsa			} else /* CCMP */ {
2348203134Sthompsa				iv[0] = k->wk_keytsc;
2349203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2350203134Sthompsa				iv[2] = 0;
2351203134Sthompsa			}
2352203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2353203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2354203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2355203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2356203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2357203134Sthompsa		}
2358209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2359208019Sthompsa			return;
2360203134Sthompsa	}
2361203134Sthompsa
2362203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2363203134Sthompsa		/* install group key */
2364209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2365208019Sthompsa			return;
2366203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2367203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2368209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2369208019Sthompsa			return;
2370203134Sthompsa	} else {
2371203134Sthompsa		/* install pairwise key */
2372209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2373208019Sthompsa			return;
2374203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2375209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2376208019Sthompsa			return;
2377203134Sthompsa	}
2378203134Sthompsa
2379203134Sthompsa	/* TODO create a pass-thru key entry? */
2380203134Sthompsa
2381208019Sthompsa	/* need wcid to delete the right key later */
2382208019Sthompsa	k->wk_pad = wcid;
2383203134Sthompsa}
2384203134Sthompsa
2385203134Sthompsa/*
2386208019Sthompsa * Don't have to be deferred, but in order to keep order of
2387208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2388208019Sthompsa * run_cmdq_cb() maintain the order.
2389208019Sthompsa *
2390203134Sthompsa * return 0 on error
2391203134Sthompsa */
2392203134Sthompsastatic int
2393208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2394208019Sthompsa		const uint8_t mac[IEEE80211_ADDR_LEN])
2395203134Sthompsa{
2396203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2397203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2398208019Sthompsa	uint32_t i;
2399208019Sthompsa
2400208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2401208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2402208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2403208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2404208019Sthompsa	sc->cmdq[i].arg1 = vap;
2405208019Sthompsa	sc->cmdq[i].k = k;
2406208019Sthompsa	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2407208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2408208019Sthompsa
2409209144Sthompsa	/*
2410209144Sthompsa	 * To make sure key will be set when hostapd
2411209144Sthompsa	 * calls iv_key_set() before if_init().
2412209144Sthompsa	 */
2413209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2414209144Sthompsa		RUN_LOCK(sc);
2415209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2416209144Sthompsa		RUN_UNLOCK(sc);
2417209144Sthompsa	}
2418209144Sthompsa
2419209917Sthompsa	return (1);
2420208019Sthompsa}
2421208019Sthompsa
2422208019Sthompsa/*
2423208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2424208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2425208019Sthompsa * vap is gone. Don't refer it.
2426208019Sthompsa */
2427208019Sthompsastatic void
2428208019Sthompsarun_key_delete_cb(void *arg)
2429208019Sthompsa{
2430208019Sthompsa	struct run_cmdq *cmdq = arg;
2431208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2432208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2433203134Sthompsa	uint32_t attr;
2434203134Sthompsa	uint8_t wcid;
2435203134Sthompsa
2436208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2437203134Sthompsa
2438203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2439203134Sthompsa		/* remove group key */
2440208019Sthompsa		DPRINTF("removing group key\n");
2441208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2442203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2443208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2444203134Sthompsa	} else {
2445203134Sthompsa		/* remove pairwise key */
2446208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2447208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2448208019Sthompsa		wcid = k->wk_pad;
2449208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2450203134Sthompsa		attr &= ~0xf;
2451208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2452208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2453203134Sthompsa	}
2454203134Sthompsa
2455208019Sthompsa	k->wk_pad = 0;
2456203134Sthompsa}
2457203134Sthompsa
2458208019Sthompsa/*
2459208019Sthompsa * return 0 on error
2460208019Sthompsa */
2461208019Sthompsastatic int
2462208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2463203134Sthompsa{
2464208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2465208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2466208019Sthompsa	struct ieee80211_key *k0;
2467208019Sthompsa	uint32_t i;
2468203134Sthompsa
2469208019Sthompsa	/*
2470208019Sthompsa	 * When called back, key might be gone. So, make a copy
2471208019Sthompsa	 * of some values need to delete keys before deferring.
2472208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2473208019Sthompsa	 * So, use atomic instead.
2474208019Sthompsa	 */
2475208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2476208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2477208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2478208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2479208019Sthompsa	sc->cmdq[i].arg1 = sc;
2480208019Sthompsa	k0 = &sc->cmdq[i].key;
2481208019Sthompsa	k0->wk_flags = k->wk_flags;
2482208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2483208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2484208019Sthompsa	k0->wk_pad = k->wk_pad;
2485208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2486208019Sthompsa	return (1);	/* return fake success */
2487203134Sthompsa
2488203134Sthompsa}
2489203134Sthompsa
2490203134Sthompsastatic void
2491206358Srpaulorun_ratectl_to(void *arg)
2492203134Sthompsa{
2493208019Sthompsa	struct run_softc *sc = arg;
2494203134Sthompsa
2495203134Sthompsa	/* do it in a process context, so it can go sleep */
2496208019Sthompsa	ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task);
2497203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2498203134Sthompsa}
2499203134Sthompsa
2500203134Sthompsa/* ARGSUSED */
2501203134Sthompsastatic void
2502206358Srpaulorun_ratectl_cb(void *arg, int pending)
2503203134Sthompsa{
2504208019Sthompsa	struct run_softc *sc = arg;
2505208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2506208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2507203134Sthompsa
2508209917Sthompsa	if (vap == NULL)
2509208019Sthompsa		return;
2510208019Sthompsa
2511263073Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2512203134Sthompsa		/*
2513203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2514203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2515203134Sthompsa		 * piggyback here rather than creating another callout.
2516203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2517203134Sthompsa		 * (when h/w is sending beacons).
2518203134Sthompsa		 */
2519203134Sthompsa		RUN_LOCK(sc);
2520203134Sthompsa		run_reset_livelock(sc);
2521208019Sthompsa		/* just in case, there are some stats to drain */
2522208019Sthompsa		run_drain_fifo(sc);
2523203134Sthompsa		RUN_UNLOCK(sc);
2524203134Sthompsa	}
2525203134Sthompsa
2526263073Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2527263073Shselasky
2528259453Shselasky	RUN_LOCK(sc);
2529208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2530208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2531259453Shselasky	RUN_UNLOCK(sc);
2532203134Sthompsa}
2533203134Sthompsa
2534203134Sthompsastatic void
2535208019Sthompsarun_drain_fifo(void *arg)
2536203134Sthompsa{
2537208019Sthompsa	struct run_softc *sc = arg;
2538208019Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2539208019Sthompsa	uint32_t stat;
2540218676Shselasky	uint16_t (*wstat)[3];
2541203134Sthompsa	uint8_t wcid, mcs, pid;
2542218676Shselasky	int8_t retry;
2543203134Sthompsa
2544208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2545203134Sthompsa
2546208019Sthompsa	for (;;) {
2547203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2548203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2549208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2550209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2551208019Sthompsa			break;
2552203134Sthompsa
2553208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2554203134Sthompsa
2555208019Sthompsa		/* if no ACK was requested, no feedback is available */
2556208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2557208019Sthompsa		    wcid == 0)
2558208019Sthompsa			continue;
2559203134Sthompsa
2560218676Shselasky		/*
2561218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2562218676Shselasky		 * the device can poll stats. Because there is no guarantee
2563218676Shselasky		 * that the referring node is still around when read the stats.
2564218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2565218676Shselasky		 * have hard time not to refer already freed node.
2566218676Shselasky		 *
2567218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2568218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2569218676Shselasky		 */
2570218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2571218676Shselasky		(*wstat)[RUN_TXCNT]++;
2572218676Shselasky		if (stat & RT2860_TXQ_OK)
2573218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2574218676Shselasky		else
2575208019Sthompsa			ifp->if_oerrors++;
2576218676Shselasky		/*
2577218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2578218676Shselasky		 * different from the requested rate. Note that it works only
2579218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2580218676Shselasky		 */
2581218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2582218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2583218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2584218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2585218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2586203134Sthompsa		}
2587208019Sthompsa	}
2588208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2589208019Sthompsa
2590208019Sthompsa	sc->fifo_cnt = 0;
2591208019Sthompsa}
2592208019Sthompsa
2593208019Sthompsastatic void
2594208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2595208019Sthompsa{
2596208019Sthompsa	struct run_softc *sc = arg;
2597208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2598208019Sthompsa	struct ieee80211com *ic = ni->ni_ic;
2599208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
2600208019Sthompsa	struct run_node *rn = (void *)ni;
2601218676Shselasky	union run_stats sta[2];
2602218676Shselasky	uint16_t (*wstat)[3];
2603218676Shselasky	int txcnt, success, retrycnt, error;
2604208019Sthompsa
2605218676Shselasky	RUN_LOCK(sc);
2606218676Shselasky
2607263073Shselasky	/* Check for special case */
2608263073Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2609263073Shselasky	    ni != vap->iv_bss)
2610263073Shselasky		goto fail;
2611263073Shselasky
2612209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2613209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2614203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2615203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2616203134Sthompsa		    sizeof sta);
2617203134Sthompsa		if (error != 0)
2618218676Shselasky			goto fail;
2619203134Sthompsa
2620203134Sthompsa		/* count failed TX as errors */
2621218676Shselasky		ifp->if_oerrors += le16toh(sta[0].error.fail);
2622203134Sthompsa
2623218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2624218676Shselasky		success = le16toh(sta[1].tx.success);
2625218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2626203134Sthompsa
2627218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2628218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2629218676Shselasky	} else {
2630218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2631203134Sthompsa
2632218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2633218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2634218676Shselasky			goto fail;
2635208019Sthompsa
2636218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2637218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2638218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2639218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2640218676Shselasky		    retrycnt, txcnt, success);
2641208019Sthompsa
2642218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2643203134Sthompsa	}
2644203134Sthompsa
2645218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2646208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2647218676Shselasky
2648218676Shselaskyfail:
2649218676Shselasky	RUN_UNLOCK(sc);
2650218676Shselasky
2651208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2652208019Sthompsa}
2653203134Sthompsa
2654208019Sthompsastatic void
2655208019Sthompsarun_newassoc_cb(void *arg)
2656208019Sthompsa{
2657208019Sthompsa	struct run_cmdq *cmdq = arg;
2658208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2659208019Sthompsa	struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc;
2660208019Sthompsa	uint8_t wcid = cmdq->wcid;
2661203134Sthompsa
2662208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2663208019Sthompsa
2664208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2665208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2666218676Shselasky
2667218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2668203134Sthompsa}
2669203134Sthompsa
2670203134Sthompsastatic void
2671203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2672203134Sthompsa{
2673203134Sthompsa	struct run_node *rn = (void *)ni;
2674203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2675208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2676208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2677208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2678203134Sthompsa	uint8_t rate;
2679208019Sthompsa	uint8_t ridx;
2680245047Shselasky	uint8_t wcid;
2681208019Sthompsa	int i, j;
2682203134Sthompsa
2683245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2684245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2685245047Shselasky
2686209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2687208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2688208019Sthompsa		return;
2689208019Sthompsa	}
2690203134Sthompsa
2691208019Sthompsa	/* only interested in true associations */
2692209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2693208019Sthompsa
2694208019Sthompsa		/*
2695208019Sthompsa		 * This function could is called though timeout function.
2696208019Sthompsa		 * Need to defer.
2697208019Sthompsa		 */
2698208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2699208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2700208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2701208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2702208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2703208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2704208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2705208019Sthompsa	}
2706208019Sthompsa
2707208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2708208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2709208019Sthompsa
2710203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2711203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2712203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2713203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2714203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2715203134Sthompsa				break;
2716203134Sthompsa		rn->ridx[i] = ridx;
2717203134Sthompsa		/* determine rate of control response frames */
2718203134Sthompsa		for (j = i; j >= 0; j--) {
2719203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2720203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2721203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2722203134Sthompsa				break;
2723203134Sthompsa		}
2724203134Sthompsa		if (j >= 0) {
2725203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2726203134Sthompsa		} else {
2727203134Sthompsa			/* no basic rate found, use mandatory one */
2728203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2729203134Sthompsa		}
2730203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2731203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2732203134Sthompsa	}
2733208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2734208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2735208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2736208019Sthompsa			break;
2737208019Sthompsa	rn->mgt_ridx = ridx;
2738208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2739208019Sthompsa
2740263073Shselasky	RUN_LOCK(sc);
2741263073Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2742263073Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2743263073Shselasky	RUN_UNLOCK(sc);
2744203134Sthompsa}
2745203134Sthompsa
2746203134Sthompsa/*
2747203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2748203134Sthompsa */
2749203134Sthompsastatic __inline uint8_t
2750203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2751203134Sthompsa{
2752203134Sthompsa	uint8_t rxchain = 0;
2753203134Sthompsa
2754203134Sthompsa	if (sc->nrxchains > 1) {
2755203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2756203134Sthompsa			rxchain = 1;
2757203134Sthompsa		if (sc->nrxchains > 2)
2758203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2759203134Sthompsa				rxchain = 2;
2760203134Sthompsa	}
2761209917Sthompsa	return (rxchain);
2762203134Sthompsa}
2763203134Sthompsa
2764203134Sthompsastatic void
2765203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2766203134Sthompsa{
2767203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2768203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
2769203134Sthompsa	struct ieee80211_frame *wh;
2770203134Sthompsa	struct ieee80211_node *ni;
2771203134Sthompsa	struct rt2870_rxd *rxd;
2772203134Sthompsa	struct rt2860_rxwi *rxwi;
2773203134Sthompsa	uint32_t flags;
2774259453Shselasky	uint16_t len, rxwisize;
2775203134Sthompsa	uint8_t ant, rssi;
2776203134Sthompsa	int8_t nf;
2777203134Sthompsa
2778203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2779203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2780261868Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2781261868Skevlo	if (sc->mac_ver == 0x5592)
2782261868Skevlo		rxwisize += sizeof(uint64_t);
2783261868Skevlo	else if (sc->mac_ver == 0x3593)
2784261868Skevlo		rxwisize += sizeof(uint32_t);
2785203134Sthompsa	if (__predict_false(len > dmalen)) {
2786203134Sthompsa		m_freem(m);
2787203134Sthompsa		ifp->if_ierrors++;
2788203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2789203134Sthompsa		return;
2790203134Sthompsa	}
2791203134Sthompsa	/* Rx descriptor is located at the end */
2792203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2793203134Sthompsa	flags = le32toh(rxd->flags);
2794203134Sthompsa
2795203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2796203134Sthompsa		m_freem(m);
2797203134Sthompsa		ifp->if_ierrors++;
2798203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2799203134Sthompsa		return;
2800203134Sthompsa	}
2801203134Sthompsa
2802259453Shselasky	m->m_data += rxwisize;
2803259453Shselasky	m->m_pkthdr.len = m->m_len -= rxwisize;
2804203134Sthompsa
2805203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2806203134Sthompsa
2807262007Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2808262007Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2809203134Sthompsa		m->m_flags |= M_WEP;
2810203134Sthompsa	}
2811203134Sthompsa
2812209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2813203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2814203134Sthompsa		len += 2;
2815203134Sthompsa	}
2816203134Sthompsa
2817208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2818208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2819208019Sthompsa
2820203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2821203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2822209917Sthompsa		if (ni != NULL)
2823259453Shselasky			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2824259453Shselasky			    rxwi->keyidx);
2825203134Sthompsa		m_freem(m);
2826203134Sthompsa		ifp->if_ierrors++;
2827203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2828203134Sthompsa		return;
2829203134Sthompsa	}
2830203134Sthompsa
2831203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2832203134Sthompsa	rssi = rxwi->rssi[ant];
2833203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2834203134Sthompsa
2835203134Sthompsa	m->m_pkthdr.rcvif = ifp;
2836203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2837203134Sthompsa
2838203134Sthompsa	if (ni != NULL) {
2839203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2840203134Sthompsa		ieee80211_free_node(ni);
2841203134Sthompsa	} else {
2842203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2843203134Sthompsa	}
2844203134Sthompsa
2845209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2846203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2847259453Shselasky		uint16_t phy;
2848203134Sthompsa
2849203134Sthompsa		tap->wr_flags = 0;
2850236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2851236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2852203134Sthompsa		tap->wr_antsignal = rssi;
2853203134Sthompsa		tap->wr_antenna = ant;
2854203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2855203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2856203134Sthompsa		phy = le16toh(rxwi->phy);
2857203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2858203134Sthompsa		case RT2860_PHY_CCK:
2859203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2860203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2861203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2862203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2863203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2864203134Sthompsa			}
2865203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2866203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2867203134Sthompsa			break;
2868203134Sthompsa		case RT2860_PHY_OFDM:
2869203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2870203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2871203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2872203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2873203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2874203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2875203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2876203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2877203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2878203134Sthompsa			}
2879203134Sthompsa			break;
2880203134Sthompsa		}
2881203134Sthompsa	}
2882203134Sthompsa}
2883203134Sthompsa
2884203134Sthompsastatic void
2885203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2886203134Sthompsa{
2887203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2888203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2889203134Sthompsa	struct mbuf *m = NULL;
2890203134Sthompsa	struct mbuf *m0;
2891203134Sthompsa	uint32_t dmalen;
2892259453Shselasky	uint16_t rxwisize;
2893203134Sthompsa	int xferlen;
2894203134Sthompsa
2895261868Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2896261868Skevlo	if (sc->mac_ver == 0x5592)
2897261868Skevlo		rxwisize += sizeof(uint64_t);
2898261868Skevlo	else if (sc->mac_ver == 0x3593)
2899261868Skevlo		rxwisize += sizeof(uint32_t);
2900259453Shselasky
2901203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2902203134Sthompsa
2903203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2904203134Sthompsa	case USB_ST_TRANSFERRED:
2905203134Sthompsa
2906203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2907203134Sthompsa
2908259453Shselasky		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2909259453Shselasky		    sizeof(struct rt2870_rxd))) {
2910203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2911203134Sthompsa			goto tr_setup;
2912203134Sthompsa		}
2913203134Sthompsa
2914203134Sthompsa		m = sc->rx_m;
2915203134Sthompsa		sc->rx_m = NULL;
2916203134Sthompsa
2917203134Sthompsa		/* FALLTHROUGH */
2918203134Sthompsa	case USB_ST_SETUP:
2919203134Sthompsatr_setup:
2920203134Sthompsa		if (sc->rx_m == NULL) {
2921243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2922203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2923203134Sthompsa		}
2924203134Sthompsa		if (sc->rx_m == NULL) {
2925203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2926203134Sthompsa			ifp->if_ierrors++;
2927203134Sthompsa			usbd_xfer_set_stall(xfer);
2928203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2929203134Sthompsa		} else {
2930203134Sthompsa			/*
2931203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2932203134Sthompsa			 * save some data copying. This works because
2933203134Sthompsa			 * there is only one cluster.
2934203134Sthompsa			 */
2935203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2936203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2937203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2938203134Sthompsa		}
2939203134Sthompsa		usbd_transfer_submit(xfer);
2940203134Sthompsa		break;
2941203134Sthompsa
2942203134Sthompsa	default:	/* Error */
2943203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2944203134Sthompsa			/* try to clear stall first */
2945203134Sthompsa			usbd_xfer_set_stall(xfer);
2946203134Sthompsa
2947203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2948203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2949203134Sthompsa
2950203134Sthompsa			ifp->if_ierrors++;
2951203134Sthompsa
2952203134Sthompsa			goto tr_setup;
2953203134Sthompsa		}
2954209917Sthompsa		if (sc->rx_m != NULL) {
2955203134Sthompsa			m_freem(sc->rx_m);
2956203134Sthompsa			sc->rx_m = NULL;
2957203134Sthompsa		}
2958203134Sthompsa		break;
2959203134Sthompsa	}
2960203134Sthompsa
2961203134Sthompsa	if (m == NULL)
2962203134Sthompsa		return;
2963203134Sthompsa
2964203134Sthompsa	/* inputting all the frames must be last */
2965203134Sthompsa
2966203134Sthompsa	RUN_UNLOCK(sc);
2967203134Sthompsa
2968203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2969203134Sthompsa
2970203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2971203134Sthompsa	for(;;) {
2972203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2973203134Sthompsa
2974233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2975233774Shselasky		    ((dmalen & 3) != 0)) {
2976203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2977203134Sthompsa			break;
2978203134Sthompsa		}
2979233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2980203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2981203134Sthompsa			dmalen + 8, xferlen);
2982203134Sthompsa			break;
2983203134Sthompsa		}
2984203134Sthompsa
2985203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2986209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2987203134Sthompsa			/* trim 32-bit DMA-len header */
2988203134Sthompsa			m->m_data += 4;
2989203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2990203134Sthompsa			run_rx_frame(sc, m, dmalen);
2991259453Shselasky			m = NULL;	/* don't free source buffer */
2992203134Sthompsa			break;
2993203134Sthompsa		}
2994203134Sthompsa
2995203134Sthompsa		/* copy aggregated frames to another mbuf */
2996243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2997203134Sthompsa		if (__predict_false(m0 == NULL)) {
2998203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2999203134Sthompsa			ifp->if_ierrors++;
3000203134Sthompsa			break;
3001203134Sthompsa		}
3002203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
3003203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
3004203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
3005203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
3006203134Sthompsa		run_rx_frame(sc, m0, dmalen);
3007203134Sthompsa
3008203134Sthompsa		/* update data ptr */
3009203134Sthompsa		m->m_data += dmalen + 8;
3010203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
3011203134Sthompsa	}
3012203134Sthompsa
3013259453Shselasky	/* make sure we free the source buffer, if any */
3014259453Shselasky	m_freem(m);
3015259453Shselasky
3016203134Sthompsa	RUN_LOCK(sc);
3017203134Sthompsa}
3018203134Sthompsa
3019203134Sthompsastatic void
3020203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3021203134Sthompsa    struct run_tx_data *data, int txerr)
3022203134Sthompsa{
3023203134Sthompsa	if (data->m != NULL) {
3024203134Sthompsa		if (data->m->m_flags & M_TXCB)
3025203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
3026203134Sthompsa			    txerr ? ETIMEDOUT : 0);
3027203134Sthompsa		m_freem(data->m);
3028203134Sthompsa		data->m = NULL;
3029203134Sthompsa
3030209917Sthompsa		if (data->ni == NULL) {
3031203134Sthompsa			DPRINTF("no node\n");
3032203134Sthompsa		} else {
3033203134Sthompsa			ieee80211_free_node(data->ni);
3034203134Sthompsa			data->ni = NULL;
3035203134Sthompsa		}
3036203134Sthompsa	}
3037203134Sthompsa
3038203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3039203134Sthompsa	pq->tx_nfree++;
3040203134Sthompsa}
3041203134Sthompsa
3042203134Sthompsastatic void
3043259453Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3044203134Sthompsa{
3045203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3046203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3047208019Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3048203134Sthompsa	struct run_tx_data *data;
3049203134Sthompsa	struct ieee80211vap *vap = NULL;
3050203134Sthompsa	struct usb_page_cache *pc;
3051203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3052203134Sthompsa	struct mbuf *m;
3053203134Sthompsa	usb_frlength_t size;
3054203134Sthompsa	int actlen;
3055203134Sthompsa	int sumlen;
3056203134Sthompsa
3057203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3058203134Sthompsa
3059209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3060203134Sthompsa	case USB_ST_TRANSFERRED:
3061203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3062203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3063203134Sthompsa
3064203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3065203134Sthompsa
3066203134Sthompsa		run_tx_free(pq, data, 0);
3067203134Sthompsa		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3068203134Sthompsa
3069203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3070203134Sthompsa
3071203134Sthompsa		ifp->if_opackets++;
3072203134Sthompsa
3073203134Sthompsa		/* FALLTHROUGH */
3074203134Sthompsa	case USB_ST_SETUP:
3075203134Sthompsatr_setup:
3076203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3077209917Sthompsa		if (data == NULL)
3078203134Sthompsa			break;
3079203134Sthompsa
3080203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3081203134Sthompsa
3082203134Sthompsa		m = data->m;
3083261868Skevlo		size = (sc->mac_ver == 0x5592) ?
3084261868Skevlo		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3085228508Shselasky		if ((m->m_pkthdr.len +
3086261868Skevlo		    size + 3 + 8) > RUN_MAX_TXSZ) {
3087203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3088203134Sthompsa			    m->m_pkthdr.len);
3089203134Sthompsa
3090203134Sthompsa			ifp->if_oerrors++;
3091203134Sthompsa
3092203134Sthompsa			run_tx_free(pq, data, 1);
3093203134Sthompsa
3094203134Sthompsa			goto tr_setup;
3095203134Sthompsa		}
3096203134Sthompsa
3097203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3098203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3099203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3100228508Shselasky		size += m->m_pkthdr.len;
3101228508Shselasky		/*
3102228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3103228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3104228508Shselasky		 * bytes:
3105228508Shselasky		 */
3106228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3107228508Shselasky		size += ((-size) & 3) + 8;
3108203134Sthompsa
3109203134Sthompsa		vap = data->ni->ni_vap;
3110203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3111203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3112259453Shselasky			struct rt2860_txwi *txwi =
3113208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3114203134Sthompsa			tap->wt_flags = 0;
3115203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3116236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3117236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3118203134Sthompsa			tap->wt_hwqueue = index;
3119208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3120203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3121203134Sthompsa
3122203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3123203134Sthompsa		}
3124203134Sthompsa
3125228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3126228508Shselasky		    m->m_pkthdr.len, size, index);
3127203134Sthompsa
3128228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3129203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3130203134Sthompsa
3131203134Sthompsa		usbd_transfer_submit(xfer);
3132203134Sthompsa
3133203134Sthompsa		RUN_UNLOCK(sc);
3134203134Sthompsa		run_start(ifp);
3135203134Sthompsa		RUN_LOCK(sc);
3136203134Sthompsa
3137203134Sthompsa		break;
3138203134Sthompsa
3139203134Sthompsa	default:
3140203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3141203134Sthompsa		    usbd_errstr(error));
3142203134Sthompsa
3143203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3144203134Sthompsa
3145203134Sthompsa		ifp->if_oerrors++;
3146203134Sthompsa
3147203134Sthompsa		if (data != NULL) {
3148208019Sthompsa			if(data->ni != NULL)
3149208019Sthompsa				vap = data->ni->ni_vap;
3150203134Sthompsa			run_tx_free(pq, data, error);
3151203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3152203134Sthompsa		}
3153209917Sthompsa		if (vap == NULL)
3154208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3155203134Sthompsa
3156203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3157203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3158203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3159208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3160208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3161208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3162208019Sthompsa				sc->cmdq[i].arg0 = vap;
3163208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3164203134Sthompsa			}
3165203134Sthompsa
3166203134Sthompsa			/*
3167203134Sthompsa			 * Try to clear stall first, also if other
3168203134Sthompsa			 * errors occur, hence clearing stall
3169203134Sthompsa			 * introduces a 50 ms delay:
3170203134Sthompsa			 */
3171203134Sthompsa			usbd_xfer_set_stall(xfer);
3172203134Sthompsa			goto tr_setup;
3173203134Sthompsa		}
3174203134Sthompsa		break;
3175203134Sthompsa	}
3176203134Sthompsa}
3177203134Sthompsa
3178203134Sthompsastatic void
3179203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3180203134Sthompsa{
3181203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3182203134Sthompsa}
3183203134Sthompsa
3184203134Sthompsastatic void
3185203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3186203134Sthompsa{
3187203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3188203134Sthompsa}
3189203134Sthompsa
3190203134Sthompsastatic void
3191203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3192203134Sthompsa{
3193203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3194203134Sthompsa}
3195203134Sthompsa
3196203134Sthompsastatic void
3197203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3198203134Sthompsa{
3199203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3200203134Sthompsa}
3201203134Sthompsa
3202203134Sthompsastatic void
3203203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3204203134Sthompsa{
3205203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3206203134Sthompsa}
3207203134Sthompsa
3208203134Sthompsastatic void
3209203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3210203134Sthompsa{
3211203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3212203134Sthompsa}
3213203134Sthompsa
3214203134Sthompsastatic void
3215208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3216203134Sthompsa{
3217203134Sthompsa	struct mbuf *m = data->m;
3218203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3219208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3220203134Sthompsa	struct ieee80211_frame *wh;
3221203134Sthompsa	struct rt2870_txd *txd;
3222203134Sthompsa	struct rt2860_txwi *txwi;
3223259453Shselasky	uint16_t xferlen, txwisize;
3224208019Sthompsa	uint16_t mcs;
3225203134Sthompsa	uint8_t ridx = data->ridx;
3226208019Sthompsa	uint8_t pad;
3227203134Sthompsa
3228203134Sthompsa	/* get MCS code from rate index */
3229208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3230203134Sthompsa
3231259453Shselasky	txwisize = (sc->mac_ver == 0x5592) ?
3232259453Shselasky	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3233259453Shselasky	xferlen = txwisize + m->m_pkthdr.len;
3234203134Sthompsa
3235203134Sthompsa	/* roundup to 32-bit alignment */
3236203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3237203134Sthompsa
3238203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3239203134Sthompsa	txd->len = htole16(xferlen);
3240203134Sthompsa
3241208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3242208019Sthompsa
3243208019Sthompsa	/*
3244208019Sthompsa	 * Ether both are true or both are false, the header
3245208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3246208019Sthompsa	 */
3247208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3248208019Sthompsa		pad = 0;
3249208019Sthompsa	else
3250208019Sthompsa		pad = 2;
3251208019Sthompsa
3252203134Sthompsa	/* setup TX Wireless Information */
3253203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3254203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3255203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3256270515Skevlo		mcs |= RT2860_PHY_CCK;
3257203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3258203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3259203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3260203134Sthompsa	} else
3261270515Skevlo		mcs |= RT2860_PHY_OFDM;
3262270515Skevlo	txwi->phy = htole16(mcs);
3263203134Sthompsa
3264203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3265203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3266203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3267203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3268203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3269208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3270203134Sthompsa	else
3271208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3272209144Sthompsa
3273209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3274209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3275203134Sthompsa}
3276203134Sthompsa
3277203134Sthompsa/* This function must be called locked */
3278203134Sthompsastatic int
3279203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3280203134Sthompsa{
3281203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3282208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3283203134Sthompsa	struct ieee80211_frame *wh;
3284208019Sthompsa	struct ieee80211_channel *chan;
3285203134Sthompsa	const struct ieee80211_txparam *tp;
3286208019Sthompsa	struct run_node *rn = (void *)ni;
3287203134Sthompsa	struct run_tx_data *data;
3288208019Sthompsa	struct rt2870_txd *txd;
3289208019Sthompsa	struct rt2860_txwi *txwi;
3290203134Sthompsa	uint16_t qos;
3291203134Sthompsa	uint16_t dur;
3292208019Sthompsa	uint16_t qid;
3293203134Sthompsa	uint8_t type;
3294203134Sthompsa	uint8_t tid;
3295208019Sthompsa	uint8_t ridx;
3296208019Sthompsa	uint8_t ctl_ridx;
3297203134Sthompsa	uint8_t qflags;
3298203134Sthompsa	uint8_t xflags = 0;
3299203134Sthompsa	int hasqos;
3300203134Sthompsa
3301203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3302203134Sthompsa
3303203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3304203134Sthompsa
3305203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3306203134Sthompsa
3307203134Sthompsa	/*
3308203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3309203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3310203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3311203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3312203134Sthompsa	 */
3313203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3314203134Sthompsa		uint8_t *frm;
3315203134Sthompsa
3316203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3317203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3318203134Sthompsa		else
3319203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3320203134Sthompsa
3321203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3322203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3323203134Sthompsa		qid = TID_TO_WME_AC(tid);
3324203134Sthompsa	} else {
3325203134Sthompsa		qos = 0;
3326203134Sthompsa		tid = 0;
3327203134Sthompsa		qid = WME_AC_BE;
3328203134Sthompsa	}
3329203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3330203134Sthompsa
3331203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3332203134Sthompsa	    qos, qid, tid, qflags);
3333203134Sthompsa
3334208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3335208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3336203134Sthompsa
3337203134Sthompsa	/* pickup a rate index */
3338203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3339270515Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3340203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3341203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3342203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3343203134Sthompsa	} else {
3344208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3345208019Sthompsa			ridx = rn->fix_ridx;
3346208019Sthompsa		else
3347208019Sthompsa			ridx = rn->amrr_ridx;
3348203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3349203134Sthompsa	}
3350203134Sthompsa
3351203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3352203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3353203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3354209144Sthompsa		xflags |= RT2860_TX_ACK;
3355203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3356208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3357203134Sthompsa		else
3358208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3359259453Shselasky		USETW(wh->i_dur, dur);
3360203134Sthompsa	}
3361203134Sthompsa
3362203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3363203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3364203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3365203134Sthompsa		return (-1);
3366203134Sthompsa	}
3367203134Sthompsa
3368203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3369203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3370203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3371203134Sthompsa
3372208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3373208019Sthompsa	txd->flags = qflags;
3374208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3375208019Sthompsa	txwi->xflags = xflags;
3376259453Shselasky	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3377245047Shselasky		txwi->wcid = 0;
3378259453Shselasky	else
3379245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3380245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3381259453Shselasky
3382208019Sthompsa	/* clear leftover garbage bits */
3383208019Sthompsa	txwi->flags = 0;
3384208019Sthompsa	txwi->txop = 0;
3385208019Sthompsa
3386203134Sthompsa	data->m = m;
3387203134Sthompsa	data->ni = ni;
3388203134Sthompsa	data->ridx = ridx;
3389203134Sthompsa
3390208019Sthompsa	run_set_tx_desc(sc, data);
3391203134Sthompsa
3392208019Sthompsa	/*
3393208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3394208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3395208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3396208019Sthompsa	 *
3397208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3398208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3399208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3400208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3401208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3402208019Sthompsa 	 *
3403208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3404208019Sthompsa 	 */
3405209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3406209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3407208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3408208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3409208019Sthompsa
3410208019Sthompsa		/*
3411208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3412208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3413208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3414208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3415208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3416208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3417208019Sthompsa		 * are used only in those modes.
3418208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3419208019Sthompsa		 * run_ratectl_cb() via callout.
3420208019Sthompsa		 * Call it early. Otherwise overflow.
3421208019Sthompsa		 */
3422209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3423208019Sthompsa			/*
3424208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3425208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3426208019Sthompsa			 */
3427208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3428208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3429208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3430208019Sthompsa			sc->cmdq[i].arg0 = sc;
3431208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3432208019Sthompsa		}
3433208019Sthompsa	}
3434208019Sthompsa
3435203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3436203134Sthompsa
3437203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3438203134Sthompsa
3439259453Shselasky	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3440259453Shselasky	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3441259453Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3442203134Sthompsa
3443203134Sthompsa	return (0);
3444203134Sthompsa}
3445203134Sthompsa
3446203134Sthompsastatic int
3447203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3448203134Sthompsa{
3449203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3450203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3451208019Sthompsa	struct run_node *rn = (void *)ni;
3452203134Sthompsa	struct run_tx_data *data;
3453203134Sthompsa	struct ieee80211_frame *wh;
3454208019Sthompsa	struct rt2870_txd *txd;
3455208019Sthompsa	struct rt2860_txwi *txwi;
3456203134Sthompsa	uint16_t dur;
3457208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3458203134Sthompsa	uint8_t type;
3459203134Sthompsa	uint8_t xflags = 0;
3460208019Sthompsa	uint8_t wflags = 0;
3461203134Sthompsa
3462203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3463203134Sthompsa
3464203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3465203134Sthompsa
3466203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3467203134Sthompsa
3468208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3469208019Sthompsa	if ((wh->i_fc[0] &
3470208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3471208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3472208019Sthompsa		wflags |= RT2860_TX_TS;
3473208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3474203134Sthompsa		xflags |= RT2860_TX_ACK;
3475203134Sthompsa
3476208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3477203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3478259453Shselasky		USETW(wh->i_dur, dur);
3479203134Sthompsa	}
3480203134Sthompsa
3481203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3482203134Sthompsa		/* let caller free mbuf */
3483203134Sthompsa		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3484203134Sthompsa		return (EIO);
3485203134Sthompsa	}
3486203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3487203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3488203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3489203134Sthompsa
3490208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3491208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3492208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3493208019Sthompsa	txwi->wcid = 0xff;
3494208019Sthompsa	txwi->flags = wflags;
3495208019Sthompsa	txwi->xflags = xflags;
3496208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3497208019Sthompsa
3498203134Sthompsa	data->m = m;
3499203134Sthompsa	data->ni = ni;
3500203134Sthompsa	data->ridx = ridx;
3501203134Sthompsa
3502208019Sthompsa	run_set_tx_desc(sc, data);
3503203134Sthompsa
3504203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3505259453Shselasky	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3506208019Sthompsa	    rt2860_rates[ridx].rate);
3507203134Sthompsa
3508203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3509203134Sthompsa
3510203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3511203134Sthompsa
3512203134Sthompsa	return (0);
3513203134Sthompsa}
3514203134Sthompsa
3515203134Sthompsastatic int
3516203134Sthompsarun_sendprot(struct run_softc *sc,
3517203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3518203134Sthompsa{
3519203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3520203134Sthompsa	struct ieee80211_frame *wh;
3521203134Sthompsa	struct run_tx_data *data;
3522208019Sthompsa	struct rt2870_txd *txd;
3523208019Sthompsa	struct rt2860_txwi *txwi;
3524203134Sthompsa	struct mbuf *mprot;
3525203134Sthompsa	int ridx;
3526203134Sthompsa	int protrate;
3527203134Sthompsa	int ackrate;
3528203134Sthompsa	int pktlen;
3529203134Sthompsa	int isshort;
3530203134Sthompsa	uint16_t dur;
3531203134Sthompsa	uint8_t type;
3532208019Sthompsa	uint8_t wflags = 0;
3533208019Sthompsa	uint8_t xflags = 0;
3534203134Sthompsa
3535203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3536203134Sthompsa
3537203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3538203134Sthompsa	    ("protection %d", prot));
3539203134Sthompsa
3540203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3541203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3542203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3543203134Sthompsa
3544203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3545203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3546203134Sthompsa
3547203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3548209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3549203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3550203134Sthompsa	wflags = RT2860_TX_FRAG;
3551203134Sthompsa
3552203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3553203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3554203134Sthompsa		/* let caller free mbuf */
3555203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3556203134Sthompsa		return (ENOBUFS);
3557203134Sthompsa	}
3558203134Sthompsa
3559203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3560203134Sthompsa		/* NB: CTS is the same size as an ACK */
3561203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3562208019Sthompsa		xflags |= RT2860_TX_ACK;
3563203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3564203134Sthompsa	} else {
3565203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3566203134Sthompsa	}
3567203134Sthompsa	if (mprot == NULL) {
3568203134Sthompsa		sc->sc_ifp->if_oerrors++;
3569203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3570203134Sthompsa		return (ENOBUFS);
3571203134Sthompsa	}
3572203134Sthompsa
3573203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3574203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3575203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3576203134Sthompsa
3577208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3578208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3579208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3580208019Sthompsa	txwi->wcid = 0xff;
3581208019Sthompsa	txwi->flags = wflags;
3582208019Sthompsa	txwi->xflags = xflags;
3583208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3584208019Sthompsa
3585203134Sthompsa	data->m = mprot;
3586203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3587203134Sthompsa
3588203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3589203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3590203134Sthompsa			break;
3591203134Sthompsa	data->ridx = ridx;
3592203134Sthompsa
3593208019Sthompsa	run_set_tx_desc(sc, data);
3594203134Sthompsa
3595203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3596203134Sthompsa            m->m_pkthdr.len, rate);
3597203134Sthompsa
3598203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3599203134Sthompsa
3600203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3601203134Sthompsa
3602203134Sthompsa	return (0);
3603203134Sthompsa}
3604203134Sthompsa
3605203134Sthompsastatic int
3606203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3607203134Sthompsa    const struct ieee80211_bpf_params *params)
3608203134Sthompsa{
3609203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3610203134Sthompsa	struct ieee80211_frame *wh;
3611203134Sthompsa	struct run_tx_data *data;
3612208019Sthompsa	struct rt2870_txd *txd;
3613208019Sthompsa	struct rt2860_txwi *txwi;
3614203134Sthompsa	uint8_t type;
3615208019Sthompsa	uint8_t ridx;
3616208019Sthompsa	uint8_t rate;
3617208019Sthompsa	uint8_t opflags = 0;
3618208019Sthompsa	uint8_t xflags = 0;
3619203134Sthompsa	int error;
3620203134Sthompsa
3621203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3622203134Sthompsa
3623203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3624203134Sthompsa
3625203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3626203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3627203134Sthompsa
3628203134Sthompsa	rate = params->ibp_rate0;
3629203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3630203134Sthompsa		/* let caller free mbuf */
3631203134Sthompsa		return (EINVAL);
3632203134Sthompsa	}
3633203134Sthompsa
3634203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3635208019Sthompsa		xflags |= RT2860_TX_ACK;
3636203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3637203134Sthompsa		error = run_sendprot(sc, m, ni,
3638203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3639203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3640203134Sthompsa		    rate);
3641203134Sthompsa		if (error) {
3642203134Sthompsa			/* let caller free mbuf */
3643209917Sthompsa			return error;
3644203134Sthompsa		}
3645203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3646203134Sthompsa	}
3647203134Sthompsa
3648203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3649203134Sthompsa		/* let caller free mbuf */
3650203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3651203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3652203134Sthompsa		return (EIO);
3653203134Sthompsa	}
3654203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3655203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3656203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3657203134Sthompsa
3658208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3659208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3660208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3661208019Sthompsa	txwi->wcid = 0xff;
3662208019Sthompsa	txwi->xflags = xflags;
3663208019Sthompsa	txwi->txop = opflags;
3664208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3665208019Sthompsa
3666203134Sthompsa        data->m = m;
3667203134Sthompsa        data->ni = ni;
3668203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3669203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3670203134Sthompsa			break;
3671203134Sthompsa	data->ridx = ridx;
3672203134Sthompsa
3673208019Sthompsa        run_set_tx_desc(sc, data);
3674203134Sthompsa
3675203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3676203134Sthompsa            m->m_pkthdr.len, rate);
3677203134Sthompsa
3678203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3679203134Sthompsa
3680203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3681203134Sthompsa
3682209917Sthompsa        return (0);
3683203134Sthompsa}
3684203134Sthompsa
3685203134Sthompsastatic int
3686203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3687203134Sthompsa    const struct ieee80211_bpf_params *params)
3688203134Sthompsa{
3689203134Sthompsa	struct ifnet *ifp = ni->ni_ic->ic_ifp;
3690203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3691208019Sthompsa	int error = 0;
3692208019Sthompsa
3693203134Sthompsa	RUN_LOCK(sc);
3694203134Sthompsa
3695203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3696203134Sthompsa	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3697203134Sthompsa		error =  ENETDOWN;
3698208019Sthompsa		goto done;
3699203134Sthompsa	}
3700203134Sthompsa
3701203134Sthompsa	if (params == NULL) {
3702203134Sthompsa		/* tx mgt packet */
3703209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3704203134Sthompsa			ifp->if_oerrors++;
3705203134Sthompsa			DPRINTF("mgt tx failed\n");
3706208019Sthompsa			goto done;
3707203134Sthompsa		}
3708203134Sthompsa	} else {
3709203134Sthompsa		/* tx raw packet with param */
3710209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3711203134Sthompsa			ifp->if_oerrors++;
3712203134Sthompsa			DPRINTF("tx with param failed\n");
3713208019Sthompsa			goto done;
3714203134Sthompsa		}
3715203134Sthompsa	}
3716203134Sthompsa
3717203134Sthompsa	ifp->if_opackets++;
3718203134Sthompsa
3719208019Sthompsadone:
3720203134Sthompsa	RUN_UNLOCK(sc);
3721203134Sthompsa
3722209917Sthompsa	if (error != 0) {
3723208019Sthompsa		if(m != NULL)
3724208019Sthompsa			m_freem(m);
3725208019Sthompsa		ieee80211_free_node(ni);
3726208019Sthompsa	}
3727203134Sthompsa
3728203134Sthompsa	return (error);
3729203134Sthompsa}
3730203134Sthompsa
3731203134Sthompsastatic void
3732203134Sthompsarun_start(struct ifnet *ifp)
3733203134Sthompsa{
3734203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3735203134Sthompsa	struct ieee80211_node *ni;
3736203134Sthompsa	struct mbuf *m;
3737203134Sthompsa
3738203134Sthompsa	RUN_LOCK(sc);
3739203134Sthompsa
3740203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3741203134Sthompsa		RUN_UNLOCK(sc);
3742203134Sthompsa		return;
3743203134Sthompsa	}
3744203134Sthompsa
3745203134Sthompsa	for (;;) {
3746203134Sthompsa		/* send data frames */
3747203134Sthompsa		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
3748203134Sthompsa		if (m == NULL)
3749203134Sthompsa			break;
3750203134Sthompsa
3751203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3752203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3753203134Sthompsa			IFQ_DRV_PREPEND(&ifp->if_snd, m);
3754203134Sthompsa			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3755203134Sthompsa			break;
3756203134Sthompsa		}
3757203134Sthompsa	}
3758203134Sthompsa
3759203134Sthompsa	RUN_UNLOCK(sc);
3760203134Sthompsa}
3761203134Sthompsa
3762203134Sthompsastatic int
3763203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3764203134Sthompsa{
3765203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3766203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3767203134Sthompsa	struct ifreq *ifr = (struct ifreq *) data;
3768208019Sthompsa	int startall = 0;
3769246614Shselasky	int error;
3770203134Sthompsa
3771246614Shselasky	RUN_LOCK(sc);
3772246614Shselasky	error = sc->sc_detached ? ENXIO : 0;
3773246614Shselasky	RUN_UNLOCK(sc);
3774246614Shselasky	if (error)
3775246614Shselasky		return (error);
3776246614Shselasky
3777203134Sthompsa	switch (cmd) {
3778203134Sthompsa	case SIOCSIFFLAGS:
3779203134Sthompsa		RUN_LOCK(sc);
3780203134Sthompsa		if (ifp->if_flags & IFF_UP) {
3781203134Sthompsa			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){
3782208019Sthompsa				startall = 1;
3783203134Sthompsa				run_init_locked(sc);
3784203134Sthompsa			} else
3785203134Sthompsa				run_update_promisc_locked(ifp);
3786203134Sthompsa		} else {
3787209917Sthompsa			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
3788209917Sthompsa			    (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) {
3789208019Sthompsa					run_stop(sc);
3790208019Sthompsa			}
3791203134Sthompsa		}
3792203134Sthompsa		RUN_UNLOCK(sc);
3793209917Sthompsa		if (startall)
3794208019Sthompsa			ieee80211_start_all(ic);
3795203134Sthompsa		break;
3796203134Sthompsa	case SIOCGIFMEDIA:
3797203134Sthompsa		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
3798203134Sthompsa		break;
3799203134Sthompsa	case SIOCGIFADDR:
3800203134Sthompsa		error = ether_ioctl(ifp, cmd, data);
3801203134Sthompsa		break;
3802203134Sthompsa	default:
3803203134Sthompsa		error = EINVAL;
3804203134Sthompsa		break;
3805203134Sthompsa	}
3806203134Sthompsa
3807203134Sthompsa	return (error);
3808203134Sthompsa}
3809203134Sthompsa
3810203134Sthompsastatic void
3811261868Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3812261868Skevlo{
3813261868Skevlo	uint16_t val;
3814261868Skevlo
3815261868Skevlo	/* Tx0 IQ gain. */
3816261868Skevlo	run_bbp_write(sc, 158, 0x2c);
3817261868Skevlo	if (chan <= 14)
3818261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3819261868Skevlo	else if (chan <= 64) {
3820261868Skevlo		run_efuse_read(sc,
3821261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3822261868Skevlo		    &val, 1);
3823261868Skevlo	} else if (chan <= 138) {
3824261868Skevlo		run_efuse_read(sc,
3825261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3826261868Skevlo		    &val, 1);
3827261868Skevlo	} else if (chan <= 165) {
3828261868Skevlo		run_efuse_read(sc,
3829261868Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3830261868Skevlo		    &val, 1);
3831261868Skevlo	} else
3832261868Skevlo		val = 0;
3833261868Skevlo	run_bbp_write(sc, 159, val);
3834261868Skevlo
3835261868Skevlo	/* Tx0 IQ phase. */
3836261868Skevlo	run_bbp_write(sc, 158, 0x2d);
3837261868Skevlo	if (chan <= 14) {
3838261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3839261868Skevlo		    &val, 1);
3840261868Skevlo	} else if (chan <= 64) {
3841261868Skevlo		run_efuse_read(sc,
3842261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3843261868Skevlo		    &val, 1);
3844261868Skevlo	} else if (chan <= 138) {
3845261868Skevlo		run_efuse_read(sc,
3846261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3847261868Skevlo		    &val, 1);
3848261868Skevlo	} else if (chan <= 165) {
3849261868Skevlo		run_efuse_read(sc,
3850261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3851261868Skevlo		    &val, 1);
3852261868Skevlo	} else
3853261868Skevlo		val = 0;
3854261868Skevlo	run_bbp_write(sc, 159, val);
3855261868Skevlo
3856261868Skevlo	/* Tx1 IQ gain. */
3857261868Skevlo	run_bbp_write(sc, 158, 0x4a);
3858261868Skevlo	if (chan <= 14) {
3859261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3860261868Skevlo		    &val, 1);
3861261868Skevlo	} else if (chan <= 64) {
3862261868Skevlo		run_efuse_read(sc,
3863261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3864261868Skevlo		    &val, 1);
3865261868Skevlo	} else if (chan <= 138) {
3866261868Skevlo		run_efuse_read(sc,
3867261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3868261868Skevlo		    &val, 1);
3869261868Skevlo	} else if (chan <= 165) {
3870261868Skevlo		run_efuse_read(sc,
3871261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3872261868Skevlo		    &val, 1);
3873261868Skevlo	} else
3874261868Skevlo		val = 0;
3875261868Skevlo	run_bbp_write(sc, 159, val);
3876261868Skevlo
3877261868Skevlo	/* Tx1 IQ phase. */
3878261868Skevlo	run_bbp_write(sc, 158, 0x4b);
3879261868Skevlo	if (chan <= 14) {
3880261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3881261868Skevlo		    &val, 1);
3882261868Skevlo	} else if (chan <= 64) {
3883261868Skevlo		run_efuse_read(sc,
3884261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3885261868Skevlo		    &val, 1);
3886261868Skevlo	} else if (chan <= 138) {
3887261868Skevlo		run_efuse_read(sc,
3888261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3889261868Skevlo		    &val, 1);
3890261868Skevlo	} else if (chan <= 165) {
3891261868Skevlo		run_efuse_read(sc,
3892261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3893261868Skevlo		    &val, 1);
3894261868Skevlo	} else
3895261868Skevlo		val = 0;
3896261868Skevlo	run_bbp_write(sc, 159, val);
3897261868Skevlo
3898261868Skevlo	/* RF IQ compensation control. */
3899261868Skevlo	run_bbp_write(sc, 158, 0x04);
3900261868Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3901261868Skevlo	    &val, 1);
3902261868Skevlo	run_bbp_write(sc, 159, val);
3903261868Skevlo
3904261868Skevlo	/* RF IQ imbalance compensation control. */
3905261868Skevlo	run_bbp_write(sc, 158, 0x03);
3906261868Skevlo	run_efuse_read(sc,
3907261868Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3908261868Skevlo	run_bbp_write(sc, 159, val);
3909261868Skevlo}
3910261868Skevlo
3911261868Skevlostatic void
3912205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3913205042Sthompsa{
3914205042Sthompsa	uint8_t bbp;
3915205042Sthompsa
3916205042Sthompsa	if (sc->mac_ver == 0x3572) {
3917205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3918205042Sthompsa		bbp &= ~(0x3 << 5);
3919205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3920205042Sthompsa		run_bbp_write(sc, 66, agc);
3921205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3922205042Sthompsa		run_bbp_write(sc, 66, agc);
3923205042Sthompsa	} else
3924205042Sthompsa		run_bbp_write(sc, 66, agc);
3925205042Sthompsa}
3926205042Sthompsa
3927205042Sthompsastatic void
3928203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3929203134Sthompsa{
3930203134Sthompsa	uint32_t tmp;
3931205042Sthompsa	uint8_t agc;
3932203134Sthompsa
3933203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3934203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3935203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3936259453Shselasky	if (sc->mac_ver < 0x3572)
3937259453Shselasky		run_bbp_write(sc, 86, 0x00);
3938203134Sthompsa
3939261868Skevlo	if (sc->mac_ver == 0x3593) {
3940261868Skevlo		run_bbp_write(sc, 77, 0x98);
3941261868Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3942261868Skevlo	}
3943261868Skevlo
3944203134Sthompsa	if (group == 0) {
3945203134Sthompsa		if (sc->ext_2ghz_lna) {
3946259453Shselasky			if (sc->mac_ver >= 0x5390)
3947259453Shselasky				run_bbp_write(sc, 75, 0x52);
3948259453Shselasky			else {
3949259453Shselasky				run_bbp_write(sc, 82, 0x62);
3950259453Shselasky				run_bbp_write(sc, 75, 0x46);
3951259453Shselasky			}
3952203134Sthompsa		} else {
3953259453Shselasky			if (sc->mac_ver == 0x5592) {
3954259453Shselasky				run_bbp_write(sc, 79, 0x1c);
3955259453Shselasky				run_bbp_write(sc, 80, 0x0e);
3956259453Shselasky				run_bbp_write(sc, 81, 0x3a);
3957259453Shselasky				run_bbp_write(sc, 82, 0x62);
3958259453Shselasky
3959259453Shselasky				run_bbp_write(sc, 195, 0x80);
3960259453Shselasky				run_bbp_write(sc, 196, 0xe0);
3961259453Shselasky				run_bbp_write(sc, 195, 0x81);
3962259453Shselasky				run_bbp_write(sc, 196, 0x1f);
3963259453Shselasky				run_bbp_write(sc, 195, 0x82);
3964259453Shselasky				run_bbp_write(sc, 196, 0x38);
3965259453Shselasky				run_bbp_write(sc, 195, 0x83);
3966259453Shselasky				run_bbp_write(sc, 196, 0x32);
3967259453Shselasky				run_bbp_write(sc, 195, 0x85);
3968259453Shselasky				run_bbp_write(sc, 196, 0x28);
3969259453Shselasky				run_bbp_write(sc, 195, 0x86);
3970259453Shselasky				run_bbp_write(sc, 196, 0x19);
3971259453Shselasky			} else if (sc->mac_ver >= 0x5390)
3972259453Shselasky				run_bbp_write(sc, 75, 0x50);
3973259453Shselasky			else {
3974261868Skevlo				run_bbp_write(sc, 82,
3975261868Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3976259453Shselasky				run_bbp_write(sc, 75, 0x50);
3977259453Shselasky			}
3978203134Sthompsa		}
3979203134Sthompsa	} else {
3980259453Shselasky		if (sc->mac_ver == 0x5592) {
3981259453Shselasky			run_bbp_write(sc, 79, 0x18);
3982259453Shselasky			run_bbp_write(sc, 80, 0x08);
3983259453Shselasky			run_bbp_write(sc, 81, 0x38);
3984259453Shselasky			run_bbp_write(sc, 82, 0x92);
3985259453Shselasky
3986259453Shselasky			run_bbp_write(sc, 195, 0x80);
3987259453Shselasky			run_bbp_write(sc, 196, 0xf0);
3988259453Shselasky			run_bbp_write(sc, 195, 0x81);
3989259453Shselasky			run_bbp_write(sc, 196, 0x1e);
3990259453Shselasky			run_bbp_write(sc, 195, 0x82);
3991259453Shselasky			run_bbp_write(sc, 196, 0x28);
3992259453Shselasky			run_bbp_write(sc, 195, 0x83);
3993259453Shselasky			run_bbp_write(sc, 196, 0x20);
3994259453Shselasky			run_bbp_write(sc, 195, 0x85);
3995259453Shselasky			run_bbp_write(sc, 196, 0x7f);
3996259453Shselasky			run_bbp_write(sc, 195, 0x86);
3997259453Shselasky			run_bbp_write(sc, 196, 0x7f);
3998259453Shselasky		} else if (sc->mac_ver == 0x3572)
3999205042Sthompsa			run_bbp_write(sc, 82, 0x94);
4000205042Sthompsa		else
4001261868Skevlo			run_bbp_write(sc, 82,
4002261868Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
4003205042Sthompsa		if (sc->ext_5ghz_lna)
4004203134Sthompsa			run_bbp_write(sc, 75, 0x46);
4005205042Sthompsa		else
4006203134Sthompsa			run_bbp_write(sc, 75, 0x50);
4007203134Sthompsa	}
4008203134Sthompsa
4009203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
4010203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
4011203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
4012203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
4013203134Sthompsa
4014203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
4015208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
4016261868Skevlo	if (sc->mac_ver == 0x3593)
4017261868Skevlo		tmp |= 1 << 29 | 1 << 28;
4018208019Sthompsa	if (sc->nrxchains > 1)
4019208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
4020203134Sthompsa	if (group == 0) {	/* 2GHz */
4021208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
4022203134Sthompsa		if (sc->ntxchains > 1)
4023203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
4024261868Skevlo		if (sc->mac_ver == 0x3593) {
4025261868Skevlo			if (sc->ntxchains > 2)
4026261868Skevlo				tmp |= 1 << 25;
4027261868Skevlo		}
4028203134Sthompsa	} else {		/* 5GHz */
4029208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
4030203134Sthompsa		if (sc->ntxchains > 1)
4031203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
4032203134Sthompsa	}
4033205042Sthompsa	if (sc->mac_ver == 0x3572) {
4034205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
4035205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4036205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
4037205042Sthompsa	} else
4038205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4039203134Sthompsa
4040259453Shselasky	if (sc->mac_ver == 0x5592) {
4041259453Shselasky		run_bbp_write(sc, 195, 0x8d);
4042259453Shselasky		run_bbp_write(sc, 196, 0x1a);
4043259453Shselasky	}
4044259453Shselasky
4045261868Skevlo	if (sc->mac_ver == 0x3593) {
4046261868Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
4047261868Skevlo		tmp &= ~0x01010000;
4048261868Skevlo		if (group == 0)
4049261868Skevlo			tmp |= 0x00010000;
4050261868Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
4051261868Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
4052261868Skevlo	}
4053261868Skevlo
4054203134Sthompsa	/* set initial AGC value */
4055205042Sthompsa	if (group == 0) {	/* 2GHz band */
4056205042Sthompsa		if (sc->mac_ver >= 0x3070)
4057205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
4058205042Sthompsa		else
4059205042Sthompsa			agc = 0x2e + sc->lna[0];
4060205042Sthompsa	} else {		/* 5GHz band */
4061259453Shselasky		if (sc->mac_ver == 0x5592)
4062259453Shselasky			agc = 0x24 + sc->lna[group] * 2;
4063261868Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4064205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4065205042Sthompsa		else
4066205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4067205042Sthompsa	}
4068205042Sthompsa	run_set_agc(sc, agc);
4069203134Sthompsa}
4070203134Sthompsa
4071203134Sthompsastatic void
4072259453Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4073203134Sthompsa{
4074203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4075203134Sthompsa	uint32_t r2, r3, r4;
4076203134Sthompsa	int8_t txpow1, txpow2;
4077203134Sthompsa	int i;
4078203134Sthompsa
4079203134Sthompsa	/* find the settings for this channel (we know it exists) */
4080203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4081203134Sthompsa
4082203134Sthompsa	r2 = rfprog[i].r2;
4083203134Sthompsa	if (sc->ntxchains == 1)
4084259453Shselasky		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4085203134Sthompsa	if (sc->nrxchains == 1)
4086259453Shselasky		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4087203134Sthompsa	else if (sc->nrxchains == 2)
4088259453Shselasky		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4089203134Sthompsa
4090203134Sthompsa	/* use Tx power values from EEPROM */
4091203134Sthompsa	txpow1 = sc->txpow1[i];
4092203134Sthompsa	txpow2 = sc->txpow2[i];
4093259453Shselasky
4094259453Shselasky	/* Initialize RF R3 and R4. */
4095259453Shselasky	r3 = rfprog[i].r3 & 0xffffc1ff;
4096259453Shselasky	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4097203134Sthompsa	if (chan > 14) {
4098259453Shselasky		if (txpow1 >= 0) {
4099259453Shselasky			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4100259453Shselasky			r3 |= (txpow1 << 10) | (1 << 9);
4101259453Shselasky		} else {
4102259453Shselasky			txpow1 += 7;
4103259453Shselasky
4104259453Shselasky			/* txpow1 is not possible larger than 15. */
4105259453Shselasky			r3 |= (txpow1 << 10);
4106259453Shselasky		}
4107259453Shselasky		if (txpow2 >= 0) {
4108259453Shselasky			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4109259453Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4110259453Shselasky		} else {
4111259453Shselasky			txpow2 += 7;
4112259453Shselasky			r4 |= (txpow2 << 7);
4113259453Shselasky		}
4114259453Shselasky	} else {
4115259453Shselasky		/* Set Tx0 power. */
4116259453Shselasky		r3 |= (txpow1 << 9);
4117259453Shselasky
4118259453Shselasky		/* Set frequency offset and Tx1 power. */
4119259453Shselasky		r4 |= (txpow2 << 6);
4120203134Sthompsa	}
4121203134Sthompsa
4122259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4123259453Shselasky	run_rt2870_rf_write(sc, r2);
4124259453Shselasky	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4125259453Shselasky	run_rt2870_rf_write(sc, r4);
4126203134Sthompsa
4127203134Sthompsa	run_delay(sc, 10);
4128203134Sthompsa
4129259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4130259453Shselasky	run_rt2870_rf_write(sc, r2);
4131259453Shselasky	run_rt2870_rf_write(sc, r3 | (1 << 2));
4132259453Shselasky	run_rt2870_rf_write(sc, r4);
4133203134Sthompsa
4134203134Sthompsa	run_delay(sc, 10);
4135203134Sthompsa
4136259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4137259453Shselasky	run_rt2870_rf_write(sc, r2);
4138259453Shselasky	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4139259453Shselasky	run_rt2870_rf_write(sc, r4);
4140203134Sthompsa}
4141203134Sthompsa
4142203134Sthompsastatic void
4143259453Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4144203134Sthompsa{
4145203134Sthompsa	int8_t txpow1, txpow2;
4146203134Sthompsa	uint8_t rf;
4147205042Sthompsa	int i;
4148203134Sthompsa
4149205042Sthompsa	/* find the settings for this channel (we know it exists) */
4150205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4151205042Sthompsa
4152203134Sthompsa	/* use Tx power values from EEPROM */
4153205042Sthompsa	txpow1 = sc->txpow1[i];
4154205042Sthompsa	txpow2 = sc->txpow2[i];
4155203134Sthompsa
4156205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4157259453Shselasky
4158259453Shselasky	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4159259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4160259453Shselasky	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4161259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4162259453Shselasky
4163203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4164205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4165203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4166203134Sthompsa
4167203134Sthompsa	/* set Tx0 power */
4168203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4169203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4170203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4171203134Sthompsa
4172203134Sthompsa	/* set Tx1 power */
4173203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4174203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4175203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4176203134Sthompsa
4177203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4178203134Sthompsa	rf &= ~0xfc;
4179203134Sthompsa	if (sc->ntxchains == 1)
4180203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4181203134Sthompsa	else if (sc->ntxchains == 2)
4182203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4183203134Sthompsa	if (sc->nrxchains == 1)
4184203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4185203134Sthompsa	else if (sc->nrxchains == 2)
4186203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4187203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4188203134Sthompsa
4189203134Sthompsa	/* set RF offset */
4190203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4191203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4192203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4193203134Sthompsa
4194203134Sthompsa	/* program RF filter */
4195205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4196205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4197205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4198205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4199205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4200205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4201203134Sthompsa
4202203134Sthompsa	/* enable RF tuning */
4203203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4204203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4205203134Sthompsa}
4206203134Sthompsa
4207203134Sthompsastatic void
4208205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4209205042Sthompsa{
4210205042Sthompsa	int8_t txpow1, txpow2;
4211205042Sthompsa	uint32_t tmp;
4212205042Sthompsa	uint8_t rf;
4213205042Sthompsa	int i;
4214205042Sthompsa
4215205042Sthompsa	/* find the settings for this channel (we know it exists) */
4216205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4217205042Sthompsa
4218205042Sthompsa	/* use Tx power values from EEPROM */
4219205042Sthompsa	txpow1 = sc->txpow1[i];
4220205042Sthompsa	txpow2 = sc->txpow2[i];
4221205042Sthompsa
4222205042Sthompsa	if (chan <= 14) {
4223205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4224205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4225205042Sthompsa	} else {
4226205042Sthompsa		/* enable IQ phase correction */
4227205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4228205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4229205042Sthompsa	}
4230205042Sthompsa
4231205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4232205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4233205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4234205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4235205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4236205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4237205042Sthompsa
4238205042Sthompsa	/* set PLL mode */
4239205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4240205042Sthompsa	rf &= ~(0x08 | 0x04);
4241205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4242205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4243205042Sthompsa
4244205042Sthompsa	/* set Tx power for chain 0 */
4245205042Sthompsa	if (chan <= 14)
4246205042Sthompsa		rf = 0x60 | txpow1;
4247205042Sthompsa	else
4248205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4249205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4250205042Sthompsa
4251205042Sthompsa	/* set Tx power for chain 1 */
4252205042Sthompsa	if (chan <= 14)
4253205042Sthompsa		rf = 0x60 | txpow2;
4254205042Sthompsa	else
4255205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4256205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4257205042Sthompsa
4258205042Sthompsa	/* set Tx/Rx streams */
4259205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4260205042Sthompsa	rf &= ~0xfc;
4261205042Sthompsa	if (sc->ntxchains == 1)
4262205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4263205042Sthompsa	else if (sc->ntxchains == 2)
4264205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4265205042Sthompsa	if (sc->nrxchains == 1)
4266205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4267205042Sthompsa	else if (sc->nrxchains == 2)
4268205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4269205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4270205042Sthompsa
4271205042Sthompsa	/* set RF offset */
4272205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4273205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4274205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4275205042Sthompsa
4276205042Sthompsa	/* program RF filter */
4277205042Sthompsa	rf = sc->rf24_20mhz;
4278205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4279205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4280205042Sthompsa
4281205042Sthompsa	/* enable RF tuning */
4282205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4283205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4284205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4285205042Sthompsa
4286205042Sthompsa	/* TSSI */
4287205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4288205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4289205042Sthompsa
4290205042Sthompsa	/* set loop filter 1 */
4291205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4292205042Sthompsa	/* set loop filter 2 */
4293205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4294205042Sthompsa
4295205042Sthompsa	/* set tx_mx2_ic */
4296205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4297205042Sthompsa	/* set tx_mx1_ic */
4298205042Sthompsa	if (chan <= 14)
4299205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4300205042Sthompsa	else
4301205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4302205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4303205042Sthompsa
4304205042Sthompsa	/* set tx_lo1 */
4305205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4306205042Sthompsa	/* set tx_lo2 */
4307205042Sthompsa	if (chan <= 14)
4308205042Sthompsa		rf = 0x93;
4309205042Sthompsa	else if (chan <= 64)
4310205042Sthompsa		rf = 0xb7;
4311205042Sthompsa	else if (chan <= 128)
4312205042Sthompsa		rf = 0x74;
4313205042Sthompsa	else
4314205042Sthompsa		rf = 0x72;
4315205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4316205042Sthompsa
4317205042Sthompsa	/* set rx_lo1 */
4318205042Sthompsa	if (chan <= 14)
4319205042Sthompsa		rf = 0xb3;
4320205042Sthompsa	else if (chan <= 64)
4321205042Sthompsa		rf = 0xf6;
4322205042Sthompsa	else if (chan <= 128)
4323205042Sthompsa		rf = 0xf4;
4324205042Sthompsa	else
4325205042Sthompsa		rf = 0xf3;
4326205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4327205042Sthompsa
4328205042Sthompsa	/* set pfd_delay */
4329205042Sthompsa	if (chan <= 14)
4330205042Sthompsa		rf = 0x15;
4331205042Sthompsa	else if (chan <= 64)
4332205042Sthompsa		rf = 0x3d;
4333205042Sthompsa	else
4334205042Sthompsa		rf = 0x01;
4335205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4336205042Sthompsa
4337205042Sthompsa	/* set rx_lo2 */
4338205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4339205042Sthompsa	/* set ldo_rf_vc */
4340205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4341205042Sthompsa	/* set drv_cc */
4342205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4343205042Sthompsa
4344205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4345205042Sthompsa	tmp &= ~0x8080;
4346205042Sthompsa	if (chan <= 14)
4347205042Sthompsa		tmp |= 0x80;
4348205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4349205042Sthompsa
4350205042Sthompsa	/* enable RF tuning */
4351205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4352205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4353205042Sthompsa
4354205042Sthompsa	run_delay(sc, 2);
4355205042Sthompsa}
4356205042Sthompsa
4357205042Sthompsastatic void
4358261868Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4359261868Skevlo{
4360261868Skevlo	int8_t txpow1, txpow2, txpow3;
4361261868Skevlo	uint8_t h20mhz, rf;
4362261868Skevlo	int i;
4363261868Skevlo
4364261868Skevlo	/* find the settings for this channel (we know it exists) */
4365261868Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4366261868Skevlo
4367261868Skevlo	/* use Tx power values from EEPROM */
4368261868Skevlo	txpow1 = sc->txpow1[i];
4369261868Skevlo	txpow2 = sc->txpow2[i];
4370261868Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4371261868Skevlo
4372261868Skevlo	if (chan <= 14) {
4373261868Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4374261868Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4375261868Skevlo	} else {
4376261868Skevlo		/* Enable IQ phase correction. */
4377261868Skevlo		run_bbp_write(sc, 25, 0x09);
4378261868Skevlo		run_bbp_write(sc, 26, 0xff);
4379261868Skevlo	}
4380261868Skevlo
4381261868Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4382261868Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4383261868Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4384261868Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4385261868Skevlo	run_rt3070_rf_write(sc, 11, rf);
4386261868Skevlo
4387261868Skevlo	/* Set pll_idoh. */
4388261868Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4389261868Skevlo	rf &= ~0x4c;
4390261868Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4391261868Skevlo	run_rt3070_rf_write(sc, 11, rf);
4392261868Skevlo
4393261868Skevlo	if (chan <= 14)
4394261868Skevlo		rf = txpow1 & 0x1f;
4395261868Skevlo	else
4396261868Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4397261868Skevlo	run_rt3070_rf_write(sc, 53, rf);
4398261868Skevlo
4399261868Skevlo	if (chan <= 14)
4400261868Skevlo		rf = txpow2 & 0x1f;
4401261868Skevlo	else
4402261868Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4403261868Skevlo	run_rt3070_rf_write(sc, 55, rf);
4404261868Skevlo
4405261868Skevlo	if (chan <= 14)
4406261868Skevlo		rf = txpow3 & 0x1f;
4407261868Skevlo	else
4408261868Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4409261868Skevlo	run_rt3070_rf_write(sc, 54, rf);
4410261868Skevlo
4411261868Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4412261868Skevlo	if (sc->ntxchains == 3)
4413261868Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4414261868Skevlo	else
4415261868Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4416261868Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4417261868Skevlo	run_rt3070_rf_write(sc, 1, rf);
4418261868Skevlo
4419261868Skevlo	run_adjust_freq_offset(sc);
4420261868Skevlo
4421261868Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4422261868Skevlo
4423261868Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4424261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4425261868Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4426261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
4427261868Skevlo
4428261868Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4429261868Skevlo	if (chan <= 14)
4430261868Skevlo		rf |= 0x80;
4431261868Skevlo	else
4432261868Skevlo		rf &= ~0x80;
4433261868Skevlo	run_rt3070_rf_write(sc, 36, rf);
4434261868Skevlo
4435261868Skevlo	/* Set vcolo_bs. */
4436261868Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4437261868Skevlo	/* Set pfd_delay. */
4438261868Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4439261868Skevlo
4440261868Skevlo	/* Set vco bias current control. */
4441261868Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4442261868Skevlo	rf &= ~0xc0;
4443261868Skevlo	if (chan <= 14)
4444261868Skevlo		rf |= 0x40;
4445261868Skevlo	else if (chan <= 128)
4446261868Skevlo		rf |= 0x80;
4447261868Skevlo	else
4448261868Skevlo		rf |= 0x40;
4449261868Skevlo	run_rt3070_rf_write(sc, 6, rf);
4450261868Skevlo
4451261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4452261868Skevlo	rf = (rf & ~0x18) | 0x10;
4453261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
4454261868Skevlo
4455261868Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4456261868Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4457261868Skevlo
4458261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4459261868Skevlo	rf = (rf & ~0x03) | 0x01;
4460261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4461261868Skevlo	/* Set tx_mx1_cc. */
4462261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4463261868Skevlo	rf &= ~0x1c;
4464261868Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4465261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4466261868Skevlo	/* Set tx_mx1_ic. */
4467261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4468261868Skevlo	rf &= ~0xe0;
4469261868Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4470261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4471261868Skevlo	/* Set tx_lo1_ic. */
4472261868Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4473261868Skevlo	rf &= ~0x1c;
4474261868Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4475261868Skevlo	run_rt3070_rf_write(sc, 49, rf);
4476261868Skevlo	/* Set tx_lo1_en. */
4477261868Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4478261868Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4479261868Skevlo	/* Set drv_cc. */
4480261868Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4481261868Skevlo	rf &= ~0xfc;
4482261868Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4483261868Skevlo	run_rt3070_rf_write(sc, 57, rf);
4484261868Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4485261868Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4486261868Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4487261868Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4488261868Skevlo	/* Enable VCO calibration. */
4489261868Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4490261868Skevlo	rf &= ~RT5390_VCOCAL;
4491261868Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4492261868Skevlo	run_rt3070_rf_write(sc, 3, rf);
4493261868Skevlo
4494261868Skevlo	if (chan <= 14)
4495261868Skevlo		rf = 0x23;
4496261868Skevlo	else if (chan <= 64)
4497261868Skevlo		rf = 0x36;
4498261868Skevlo	else if (chan <= 128)
4499261868Skevlo		rf = 0x32;
4500261868Skevlo	else
4501261868Skevlo		rf = 0x30;
4502261868Skevlo	run_rt3070_rf_write(sc, 39, rf);
4503261868Skevlo	if (chan <= 14)
4504261868Skevlo		rf = 0xbb;
4505261868Skevlo	else if (chan <= 64)
4506261868Skevlo		rf = 0xeb;
4507261868Skevlo	else if (chan <= 128)
4508261868Skevlo		rf = 0xb3;
4509261868Skevlo	else
4510261868Skevlo		rf = 0x9b;
4511261868Skevlo	run_rt3070_rf_write(sc, 45, rf);
4512261868Skevlo
4513261868Skevlo	/* Set FEQ/AEQ control. */
4514261868Skevlo	run_bbp_write(sc, 105, 0x34);
4515261868Skevlo}
4516261868Skevlo
4517261868Skevlostatic void
4518259453Shselaskyrun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4519259453Shselasky{
4520259453Shselasky	int8_t txpow1, txpow2;
4521259453Shselasky	uint8_t rf;
4522259453Shselasky	int i;
4523259453Shselasky
4524259453Shselasky	/* find the settings for this channel (we know it exists) */
4525259453Shselasky	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4526259453Shselasky
4527259453Shselasky	/* use Tx power values from EEPROM */
4528259453Shselasky	txpow1 = sc->txpow1[i];
4529259453Shselasky	txpow2 = sc->txpow2[i];
4530259453Shselasky
4531259453Shselasky	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4532259453Shselasky	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4533259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4534259453Shselasky	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4535259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4536259453Shselasky
4537259453Shselasky	run_rt3070_rf_read(sc, 49, &rf);
4538259453Shselasky	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4539259453Shselasky	/* The valid range of the RF R49 is 0x00 to 0x27. */
4540259453Shselasky	if ((rf & 0x3f) > 0x27)
4541259453Shselasky		rf = (rf & ~0x3f) | 0x27;
4542259453Shselasky	run_rt3070_rf_write(sc, 49, rf);
4543259453Shselasky
4544259453Shselasky	if (sc->mac_ver == 0x5392) {
4545259453Shselasky		run_rt3070_rf_read(sc, 50, &rf);
4546259453Shselasky		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4547259453Shselasky		/* The valid range of the RF R50 is 0x00 to 0x27. */
4548259453Shselasky		if ((rf & 0x3f) > 0x27)
4549259453Shselasky			rf = (rf & ~0x3f) | 0x27;
4550259453Shselasky		run_rt3070_rf_write(sc, 50, rf);
4551259453Shselasky	}
4552259453Shselasky
4553259453Shselasky	run_rt3070_rf_read(sc, 1, &rf);
4554259453Shselasky	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4555259453Shselasky	if (sc->mac_ver == 0x5392)
4556259453Shselasky		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4557259453Shselasky	run_rt3070_rf_write(sc, 1, rf);
4558259453Shselasky
4559259453Shselasky	if (sc->mac_ver != 0x5392) {
4560259453Shselasky		run_rt3070_rf_read(sc, 2, &rf);
4561259453Shselasky		rf |= 0x80;
4562259453Shselasky		run_rt3070_rf_write(sc, 2, rf);
4563259453Shselasky		run_delay(sc, 10);
4564259453Shselasky		rf &= 0x7f;
4565259453Shselasky		run_rt3070_rf_write(sc, 2, rf);
4566259453Shselasky	}
4567259453Shselasky
4568259453Shselasky	run_adjust_freq_offset(sc);
4569259453Shselasky
4570259453Shselasky	if (sc->mac_ver == 0x5392) {
4571259453Shselasky		/* Fix for RT5392C. */
4572259453Shselasky		if (sc->mac_rev >= 0x0223) {
4573259453Shselasky			if (chan <= 4)
4574259453Shselasky				rf = 0x0f;
4575259453Shselasky			else if (chan >= 5 && chan <= 7)
4576259453Shselasky				rf = 0x0e;
4577259453Shselasky			else
4578259453Shselasky				rf = 0x0d;
4579259453Shselasky			run_rt3070_rf_write(sc, 23, rf);
4580259453Shselasky
4581259453Shselasky			if (chan <= 4)
4582259453Shselasky				rf = 0x0c;
4583259453Shselasky			else if (chan == 5)
4584259453Shselasky				rf = 0x0b;
4585259453Shselasky			else if (chan >= 6 && chan <= 7)
4586259453Shselasky				rf = 0x0a;
4587259453Shselasky			else if (chan >= 8 && chan <= 10)
4588259453Shselasky				rf = 0x09;
4589259453Shselasky			else
4590259453Shselasky				rf = 0x08;
4591259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4592259453Shselasky		} else {
4593259453Shselasky			if (chan <= 11)
4594259453Shselasky				rf = 0x0f;
4595259453Shselasky			else
4596259453Shselasky				rf = 0x0b;
4597259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4598259453Shselasky		}
4599259453Shselasky	} else {
4600259453Shselasky		/* Fix for RT5390F. */
4601259453Shselasky		if (sc->mac_rev >= 0x0502) {
4602259453Shselasky			if (chan <= 11)
4603259453Shselasky				rf = 0x43;
4604259453Shselasky			else
4605259453Shselasky				rf = 0x23;
4606259453Shselasky			run_rt3070_rf_write(sc, 55, rf);
4607259453Shselasky
4608259453Shselasky			if (chan <= 11)
4609259453Shselasky				rf = 0x0f;
4610259453Shselasky			else if (chan == 12)
4611259453Shselasky				rf = 0x0d;
4612259453Shselasky			else
4613259453Shselasky				rf = 0x0b;
4614259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4615259453Shselasky		} else {
4616259453Shselasky			run_rt3070_rf_write(sc, 55, 0x44);
4617259453Shselasky			run_rt3070_rf_write(sc, 59, 0x8f);
4618259453Shselasky		}
4619259453Shselasky	}
4620259453Shselasky
4621259453Shselasky	/* Enable VCO calibration. */
4622259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4623259453Shselasky	rf |= RT5390_VCOCAL;
4624259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4625259453Shselasky}
4626259453Shselasky
4627259453Shselaskystatic void
4628259453Shselaskyrun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4629259453Shselasky{
4630259453Shselasky	const struct rt5592_freqs *freqs;
4631259453Shselasky	uint32_t tmp;
4632259453Shselasky	uint8_t reg, rf, txpow_bound;
4633259453Shselasky	int8_t txpow1, txpow2;
4634259453Shselasky	int i;
4635259453Shselasky
4636259453Shselasky	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4637259453Shselasky	freqs = (tmp & RT5592_SEL_XTAL) ?
4638259453Shselasky	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4639259453Shselasky
4640259453Shselasky	/* find the settings for this channel (we know it exists) */
4641259453Shselasky	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4642259453Shselasky
4643259453Shselasky	/* use Tx power values from EEPROM */
4644259453Shselasky	txpow1 = sc->txpow1[i];
4645259453Shselasky	txpow2 = sc->txpow2[i];
4646259453Shselasky
4647259453Shselasky	run_read(sc, RT3070_LDO_CFG0, &tmp);
4648259453Shselasky	tmp &= ~0x1c000000;
4649259453Shselasky	if (chan > 14)
4650259453Shselasky		tmp |= 0x14000000;
4651259453Shselasky	run_write(sc, RT3070_LDO_CFG0, tmp);
4652259453Shselasky
4653259453Shselasky	/* N setting. */
4654259453Shselasky	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4655259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4656259453Shselasky	rf &= ~(1 << 4);
4657259453Shselasky	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4658259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4659259453Shselasky
4660259453Shselasky	/* K setting. */
4661259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4662259453Shselasky	rf &= ~0x0f;
4663259453Shselasky	rf |= (freqs->k & 0x0f);
4664259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4665259453Shselasky
4666259453Shselasky	/* Mode setting. */
4667259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4668259453Shselasky	rf &= ~0x0c;
4669259453Shselasky	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4670259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4671259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4672259453Shselasky	rf &= ~(1 << 7);
4673259453Shselasky	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4674259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4675259453Shselasky
4676259453Shselasky	/* R setting. */
4677259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4678259453Shselasky	rf &= ~0x03;
4679259453Shselasky	rf |= (freqs->r - 0x1);
4680259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4681259453Shselasky
4682259453Shselasky	if (chan <= 14) {
4683259453Shselasky		/* Initialize RF registers for 2GHZ. */
4684259453Shselasky		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4685259453Shselasky			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4686259453Shselasky			    rt5592_2ghz_def_rf[i].val);
4687259453Shselasky		}
4688259453Shselasky
4689259453Shselasky		rf = (chan <= 10) ? 0x07 : 0x06;
4690259453Shselasky		run_rt3070_rf_write(sc, 23, rf);
4691259453Shselasky		run_rt3070_rf_write(sc, 59, rf);
4692259453Shselasky
4693259453Shselasky		run_rt3070_rf_write(sc, 55, 0x43);
4694259453Shselasky
4695259453Shselasky		/*
4696259453Shselasky		 * RF R49/R50 Tx power ALC code.
4697259453Shselasky		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4698259453Shselasky		 */
4699259453Shselasky		reg = 2;
4700259453Shselasky		txpow_bound = 0x27;
4701259453Shselasky	} else {
4702259453Shselasky		/* Initialize RF registers for 5GHZ. */
4703259453Shselasky		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4704259453Shselasky			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4705259453Shselasky			    rt5592_5ghz_def_rf[i].val);
4706259453Shselasky		}
4707259453Shselasky		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4708259453Shselasky			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4709259453Shselasky			    chan <= rt5592_chan_5ghz[i].lastchan) {
4710259453Shselasky				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4711259453Shselasky				    rt5592_chan_5ghz[i].val);
4712259453Shselasky			}
4713259453Shselasky		}
4714259453Shselasky
4715259453Shselasky		/*
4716259453Shselasky		 * RF R49/R50 Tx power ALC code.
4717259453Shselasky		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4718259453Shselasky		 */
4719259453Shselasky		reg = 3;
4720259453Shselasky		txpow_bound = 0x2b;
4721259453Shselasky	}
4722259453Shselasky
4723259453Shselasky	/* RF R49 ch0 Tx power ALC code. */
4724259453Shselasky	run_rt3070_rf_read(sc, 49, &rf);
4725259453Shselasky	rf &= ~0xc0;
4726259453Shselasky	rf |= (reg << 6);
4727259453Shselasky	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4728259453Shselasky	if ((rf & 0x3f) > txpow_bound)
4729259453Shselasky		rf = (rf & ~0x3f) | txpow_bound;
4730259453Shselasky	run_rt3070_rf_write(sc, 49, rf);
4731259453Shselasky
4732259453Shselasky	/* RF R50 ch1 Tx power ALC code. */
4733259453Shselasky	run_rt3070_rf_read(sc, 50, &rf);
4734259453Shselasky	rf &= ~(1 << 7 | 1 << 6);
4735259453Shselasky	rf |= (reg << 6);
4736259453Shselasky	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4737259453Shselasky	if ((rf & 0x3f) > txpow_bound)
4738259453Shselasky		rf = (rf & ~0x3f) | txpow_bound;
4739259453Shselasky	run_rt3070_rf_write(sc, 50, rf);
4740259453Shselasky
4741259453Shselasky	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4742259453Shselasky	run_rt3070_rf_read(sc, 1, &rf);
4743259453Shselasky	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4744259453Shselasky	if (sc->ntxchains > 1)
4745259453Shselasky		rf |= RT3070_TX1_PD;
4746259453Shselasky	if (sc->nrxchains > 1)
4747259453Shselasky		rf |= RT3070_RX1_PD;
4748259453Shselasky	run_rt3070_rf_write(sc, 1, rf);
4749259453Shselasky
4750259453Shselasky	run_rt3070_rf_write(sc, 6, 0xe4);
4751259453Shselasky
4752259453Shselasky	run_rt3070_rf_write(sc, 30, 0x10);
4753259453Shselasky	run_rt3070_rf_write(sc, 31, 0x80);
4754259453Shselasky	run_rt3070_rf_write(sc, 32, 0x80);
4755259453Shselasky
4756259453Shselasky	run_adjust_freq_offset(sc);
4757259453Shselasky
4758259453Shselasky	/* Enable VCO calibration. */
4759259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4760259453Shselasky	rf |= RT5390_VCOCAL;
4761259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4762259453Shselasky}
4763259453Shselasky
4764259453Shselaskystatic void
4765203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4766203134Sthompsa{
4767203134Sthompsa	uint32_t tmp;
4768259453Shselasky	uint8_t bbp152;
4769203134Sthompsa
4770203134Sthompsa	if (aux) {
4771259453Shselasky		if (sc->rf_rev == RT5390_RF_5370) {
4772259453Shselasky			run_bbp_read(sc, 152, &bbp152);
4773259453Shselasky			run_bbp_write(sc, 152, bbp152 & ~0x80);
4774259453Shselasky		} else {
4775259453Shselasky			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4776259453Shselasky			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4777259453Shselasky			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4778259453Shselasky		}
4779203134Sthompsa	} else {
4780259453Shselasky		if (sc->rf_rev == RT5390_RF_5370) {
4781259453Shselasky			run_bbp_read(sc, 152, &bbp152);
4782259453Shselasky			run_bbp_write(sc, 152, bbp152 | 0x80);
4783259453Shselasky		} else {
4784259453Shselasky			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4785259453Shselasky			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4786259453Shselasky			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4787259453Shselasky		}
4788203134Sthompsa	}
4789203134Sthompsa}
4790203134Sthompsa
4791203134Sthompsastatic int
4792203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4793203134Sthompsa{
4794203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4795259453Shselasky	u_int chan, group;
4796203134Sthompsa
4797203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4798203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4799209917Sthompsa		return (EINVAL);
4800203134Sthompsa
4801259453Shselasky	if (sc->mac_ver == 0x5592)
4802259453Shselasky		run_rt5592_set_chan(sc, chan);
4803259453Shselasky	else if (sc->mac_ver >= 0x5390)
4804259453Shselasky		run_rt5390_set_chan(sc, chan);
4805261868Skevlo	else if (sc->mac_ver == 0x3593)
4806261868Skevlo		run_rt3593_set_chan(sc, chan);
4807259453Shselasky	else if (sc->mac_ver == 0x3572)
4808205042Sthompsa		run_rt3572_set_chan(sc, chan);
4809205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4810203134Sthompsa		run_rt3070_set_chan(sc, chan);
4811203134Sthompsa	else
4812203134Sthompsa		run_rt2870_set_chan(sc, chan);
4813203134Sthompsa
4814203134Sthompsa	/* determine channel group */
4815203134Sthompsa	if (chan <= 14)
4816203134Sthompsa		group = 0;
4817203134Sthompsa	else if (chan <= 64)
4818203134Sthompsa		group = 1;
4819203134Sthompsa	else if (chan <= 128)
4820203134Sthompsa		group = 2;
4821203134Sthompsa	else
4822203134Sthompsa		group = 3;
4823203134Sthompsa
4824203134Sthompsa	/* XXX necessary only when group has changed! */
4825203134Sthompsa	run_select_chan_group(sc, group);
4826203134Sthompsa
4827203134Sthompsa	run_delay(sc, 10);
4828203134Sthompsa
4829261868Skevlo	/* Perform IQ calibration. */
4830261868Skevlo	if (sc->mac_ver >= 0x5392)
4831261868Skevlo		run_iq_calib(sc, chan);
4832261868Skevlo
4833209917Sthompsa	return (0);
4834203134Sthompsa}
4835203134Sthompsa
4836203134Sthompsastatic void
4837203134Sthompsarun_set_channel(struct ieee80211com *ic)
4838203134Sthompsa{
4839203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4840203134Sthompsa
4841203134Sthompsa	RUN_LOCK(sc);
4842203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4843203134Sthompsa	RUN_UNLOCK(sc);
4844203134Sthompsa
4845203134Sthompsa	return;
4846203134Sthompsa}
4847203134Sthompsa
4848203134Sthompsastatic void
4849203134Sthompsarun_scan_start(struct ieee80211com *ic)
4850203134Sthompsa{
4851203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4852203134Sthompsa	uint32_t tmp;
4853203134Sthompsa
4854203134Sthompsa	RUN_LOCK(sc);
4855203134Sthompsa
4856203134Sthompsa	/* abort TSF synchronization */
4857203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4858203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4859203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4860203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4861203134Sthompsa	run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr);
4862203134Sthompsa
4863203134Sthompsa	RUN_UNLOCK(sc);
4864203134Sthompsa
4865203134Sthompsa	return;
4866203134Sthompsa}
4867203134Sthompsa
4868203134Sthompsastatic void
4869203134Sthompsarun_scan_end(struct ieee80211com *ic)
4870203134Sthompsa{
4871203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4872203134Sthompsa
4873203134Sthompsa	RUN_LOCK(sc);
4874203134Sthompsa
4875203134Sthompsa	run_enable_tsf_sync(sc);
4876203134Sthompsa	/* XXX keep local copy */
4877203134Sthompsa	run_set_bssid(sc, sc->sc_bssid);
4878203134Sthompsa
4879203134Sthompsa	RUN_UNLOCK(sc);
4880203134Sthompsa
4881203134Sthompsa	return;
4882203134Sthompsa}
4883203134Sthompsa
4884208019Sthompsa/*
4885208019Sthompsa * Could be called from ieee80211_node_timeout()
4886208019Sthompsa * (non-sleepable thread)
4887208019Sthompsa */
4888208019Sthompsastatic void
4889208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4890203134Sthompsa{
4891208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4892208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4893218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4894218492Sbschmidt	int mcast = 0;
4895208019Sthompsa	uint32_t i;
4896208019Sthompsa
4897218492Sbschmidt	KASSERT(vap != NULL, ("no beacon"));
4898218492Sbschmidt
4899218492Sbschmidt	switch (item) {
4900218492Sbschmidt	case IEEE80211_BEACON_ERP:
4901218492Sbschmidt		run_updateslot(ic->ic_ifp);
4902218492Sbschmidt		break;
4903218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4904218492Sbschmidt		run_updateprot(ic);
4905218492Sbschmidt		break;
4906218492Sbschmidt	case IEEE80211_BEACON_TIM:
4907218492Sbschmidt		mcast = 1;	/*TODO*/
4908218492Sbschmidt		break;
4909218492Sbschmidt	default:
4910218492Sbschmidt		break;
4911218492Sbschmidt	}
4912218492Sbschmidt
4913218492Sbschmidt	setbit(rvp->bo.bo_flags, item);
4914273636Skevlo	if (rvp->beacon_mbuf == NULL) {
4915273636Skevlo		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4916273636Skevlo		    &rvp->bo);
4917273636Skevlo		if (rvp->beacon_mbuf == NULL)
4918273636Skevlo			return;
4919273636Skevlo	}
4920218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4921218492Sbschmidt
4922208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4923208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4924208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4925208019Sthompsa	sc->cmdq[i].arg0 = vap;
4926208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4927208019Sthompsa
4928208019Sthompsa	return;
4929203134Sthompsa}
4930203134Sthompsa
4931203134Sthompsastatic void
4932208019Sthompsarun_update_beacon_cb(void *arg)
4933203134Sthompsa{
4934208019Sthompsa	struct ieee80211vap *vap = arg;
4935218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4936203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4937203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4938203134Sthompsa	struct rt2860_txwi txwi;
4939203134Sthompsa	struct mbuf *m;
4940259453Shselasky	uint16_t txwisize;
4941208019Sthompsa	uint8_t ridx;
4942203134Sthompsa
4943209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4944208019Sthompsa		return;
4945236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4946236439Shselasky		return;
4947208019Sthompsa
4948218492Sbschmidt	/*
4949218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4950218492Sbschmidt	 * is taking care of apropriate calls.
4951218492Sbschmidt	 */
4952218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4953218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4954218492Sbschmidt		    &rvp->bo);
4955218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4956218492Sbschmidt			return;
4957218492Sbschmidt	}
4958218492Sbschmidt	m = rvp->beacon_mbuf;
4959203134Sthompsa
4960259453Shselasky	memset(&txwi, 0, sizeof(txwi));
4961203134Sthompsa	txwi.wcid = 0xff;
4962203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4963259453Shselasky
4964203134Sthompsa	/* send beacons at the lowest available rate */
4965208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4966208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4967208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4968208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4969259453Shselasky		txwi.phy |= htole16(RT2860_PHY_OFDM);
4970203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4971203134Sthompsa	txwi.flags = RT2860_TX_TS;
4972209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4973203134Sthompsa
4974259453Shselasky	txwisize = (sc->mac_ver == 0x5592) ?
4975259453Shselasky	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4976259453Shselasky	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4977259453Shselasky	    txwisize);
4978259453Shselasky	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4979259453Shselasky	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4980203134Sthompsa}
4981203134Sthompsa
4982203134Sthompsastatic void
4983203134Sthompsarun_updateprot(struct ieee80211com *ic)
4984203134Sthompsa{
4985203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4986218492Sbschmidt	uint32_t i;
4987218492Sbschmidt
4988218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4989218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4990218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4991218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4992218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4993218492Sbschmidt}
4994218492Sbschmidt
4995218492Sbschmidtstatic void
4996218492Sbschmidtrun_updateprot_cb(void *arg)
4997218492Sbschmidt{
4998218492Sbschmidt	struct ieee80211com *ic = arg;
4999218492Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
5000203134Sthompsa	uint32_t tmp;
5001203134Sthompsa
5002203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
5003203134Sthompsa	/* setup protection frame rate (MCS code) */
5004203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
5005270515Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
5006203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
5007203134Sthompsa
5008203134Sthompsa	/* CCK frames don't require protection */
5009203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
5010203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
5011203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
5012203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
5013203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
5014203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
5015203134Sthompsa	}
5016203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
5017203134Sthompsa}
5018203134Sthompsa
5019203134Sthompsastatic void
5020208019Sthompsarun_usb_timeout_cb(void *arg)
5021203134Sthompsa{
5022208019Sthompsa	struct ieee80211vap *vap = arg;
5023208019Sthompsa	struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc;
5024203134Sthompsa
5025208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5026203134Sthompsa
5027203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
5028203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
5029203134Sthompsa		run_reset_livelock(sc);
5030209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
5031203134Sthompsa		DPRINTF("timeout caused by scan\n");
5032203134Sthompsa		/* cancel bgscan */
5033203134Sthompsa		ieee80211_cancel_scan(vap);
5034203134Sthompsa	} else
5035203134Sthompsa		DPRINTF("timeout by unknown cause\n");
5036203134Sthompsa}
5037203134Sthompsa
5038203134Sthompsastatic void
5039203134Sthompsarun_reset_livelock(struct run_softc *sc)
5040203134Sthompsa{
5041203134Sthompsa	uint32_t tmp;
5042203134Sthompsa
5043208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5044208019Sthompsa
5045203134Sthompsa	/*
5046203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5047203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5048203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5049203134Sthompsa	 */
5050203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5051208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5052209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5053203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5054203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5055203134Sthompsa		run_delay(sc, 1);
5056203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5057203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5058203134Sthompsa	}
5059203134Sthompsa}
5060203134Sthompsa
5061203134Sthompsastatic void
5062203134Sthompsarun_update_promisc_locked(struct ifnet *ifp)
5063203134Sthompsa{
5064203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5065203134Sthompsa        uint32_t tmp;
5066203134Sthompsa
5067203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5068203134Sthompsa
5069203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5070203134Sthompsa        if (ifp->if_flags & IFF_PROMISC)
5071203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5072203134Sthompsa
5073203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5074203134Sthompsa
5075203134Sthompsa        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
5076203134Sthompsa            "entering" : "leaving");
5077203134Sthompsa}
5078203134Sthompsa
5079203134Sthompsastatic void
5080203134Sthompsarun_update_promisc(struct ifnet *ifp)
5081203134Sthompsa{
5082203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5083203134Sthompsa
5084203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
5085203134Sthompsa		return;
5086203134Sthompsa
5087203134Sthompsa	RUN_LOCK(sc);
5088203134Sthompsa	run_update_promisc_locked(ifp);
5089203134Sthompsa	RUN_UNLOCK(sc);
5090203134Sthompsa}
5091203134Sthompsa
5092203134Sthompsastatic void
5093203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5094203134Sthompsa{
5095208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5096203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5097203134Sthompsa	uint32_t tmp;
5098203134Sthompsa
5099259453Shselasky	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5100259453Shselasky	    ic->ic_opmode);
5101208019Sthompsa
5102203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5103203134Sthompsa	tmp &= ~0x1fffff;
5104203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5105203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5106203134Sthompsa
5107208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5108203134Sthompsa		/*
5109203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5110203134Sthompsa		 * reception.
5111203134Sthompsa		 */
5112203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5113208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5114203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5115203134Sthompsa	        /*
5116203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5117203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5118203134Sthompsa	         */
5119203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5120208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5121208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5122203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5123203134Sthompsa	        /* SYNC with nobody */
5124203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5125208019Sthompsa	} else {
5126203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5127208019Sthompsa		return;
5128208019Sthompsa	}
5129203134Sthompsa
5130203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5131203134Sthompsa}
5132203134Sthompsa
5133203134Sthompsastatic void
5134203134Sthompsarun_enable_mrr(struct run_softc *sc)
5135203134Sthompsa{
5136261868Skevlo#define	CCK(mcs)	(mcs)
5137261868Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5138203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5139203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5140203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5141203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5142203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5143203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5144203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5145203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5146203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5147203134Sthompsa
5148203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5149203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5150203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5151203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5152203134Sthompsa	    CCK(0));		/*   1-> 1 */
5153203134Sthompsa#undef OFDM
5154203134Sthompsa#undef CCK
5155203134Sthompsa}
5156203134Sthompsa
5157203134Sthompsastatic void
5158203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5159203134Sthompsa{
5160203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5161203134Sthompsa	uint32_t tmp;
5162203134Sthompsa
5163203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5164203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5165203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5166203134Sthompsa	else
5167203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5168203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5169203134Sthompsa}
5170203134Sthompsa
5171203134Sthompsastatic void
5172203134Sthompsarun_set_basicrates(struct run_softc *sc)
5173203134Sthompsa{
5174203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5175203134Sthompsa
5176203134Sthompsa	/* set basic rates mask */
5177203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5178203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5179203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5180203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5181203134Sthompsa	else	/* 11g */
5182203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5183203134Sthompsa}
5184203134Sthompsa
5185203134Sthompsastatic void
5186203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5187203134Sthompsa{
5188203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5189203134Sthompsa	    which | (sc->leds & 0x7f));
5190203134Sthompsa}
5191203134Sthompsa
5192203134Sthompsastatic void
5193203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5194203134Sthompsa{
5195203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5196203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5197203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5198203134Sthompsa	    bssid[4] | bssid[5] << 8);
5199203134Sthompsa}
5200203134Sthompsa
5201203134Sthompsastatic void
5202203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5203203134Sthompsa{
5204203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5205203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5206203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5207203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5208203134Sthompsa}
5209203134Sthompsa
5210203134Sthompsastatic void
5211203134Sthompsarun_updateslot(struct ifnet *ifp)
5212203134Sthompsa{
5213203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5214203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5215218492Sbschmidt	uint32_t i;
5216218492Sbschmidt
5217218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5218218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5219218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5220218492Sbschmidt	sc->cmdq[i].arg0 = ifp;
5221218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5222218492Sbschmidt
5223218492Sbschmidt	return;
5224218492Sbschmidt}
5225218492Sbschmidt
5226218492Sbschmidt/* ARGSUSED */
5227218492Sbschmidtstatic void
5228218492Sbschmidtrun_updateslot_cb(void *arg)
5229218492Sbschmidt{
5230218492Sbschmidt	struct ifnet *ifp = arg;
5231218492Sbschmidt	struct run_softc *sc = ifp->if_softc;
5232218492Sbschmidt	struct ieee80211com *ic = ifp->if_l2com;
5233203134Sthompsa	uint32_t tmp;
5234203134Sthompsa
5235203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5236203134Sthompsa	tmp &= ~0xff;
5237203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5238203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5239203134Sthompsa}
5240203134Sthompsa
5241208019Sthompsastatic void
5242208019Sthompsarun_update_mcast(struct ifnet *ifp)
5243208019Sthompsa{
5244208019Sthompsa	/* h/w filter supports getting everything or nothing */
5245208019Sthompsa	ifp->if_flags |= IFF_ALLMULTI;
5246208019Sthompsa}
5247208019Sthompsa
5248203134Sthompsastatic int8_t
5249203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5250203134Sthompsa{
5251203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5252203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5253203134Sthompsa	int delta;
5254203134Sthompsa
5255203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5256259453Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5257203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5258203134Sthompsa
5259203134Sthompsa		/* determine channel group */
5260203134Sthompsa		if (chan <= 64)
5261203134Sthompsa			delta -= sc->lna[1];
5262203134Sthompsa		else if (chan <= 128)
5263203134Sthompsa			delta -= sc->lna[2];
5264203134Sthompsa		else
5265203134Sthompsa			delta -= sc->lna[3];
5266203134Sthompsa	} else
5267203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5268203134Sthompsa
5269209917Sthompsa	return (-12 - delta - rssi);
5270203134Sthompsa}
5271203134Sthompsa
5272259453Shselaskystatic void
5273259453Shselaskyrun_rt5390_bbp_init(struct run_softc *sc)
5274259453Shselasky{
5275259453Shselasky	int i;
5276259453Shselasky	uint8_t bbp;
5277259453Shselasky
5278259453Shselasky	/* Apply maximum likelihood detection for 2 stream case. */
5279259453Shselasky	run_bbp_read(sc, 105, &bbp);
5280259453Shselasky	if (sc->nrxchains > 1)
5281259453Shselasky		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5282259453Shselasky
5283259453Shselasky	/* Avoid data lost and CRC error. */
5284259453Shselasky	run_bbp_read(sc, 4, &bbp);
5285259453Shselasky	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5286259453Shselasky
5287259453Shselasky	if (sc->mac_ver == 0x5592) {
5288259453Shselasky		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5289259453Shselasky			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5290259453Shselasky			    rt5592_def_bbp[i].val);
5291259453Shselasky		}
5292259453Shselasky		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5293259453Shselasky			run_bbp_write(sc, 195, i + 0x80);
5294259453Shselasky			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5295259453Shselasky		}
5296259453Shselasky	} else {
5297259453Shselasky		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5298259453Shselasky			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5299259453Shselasky			    rt5390_def_bbp[i].val);
5300259453Shselasky		}
5301259453Shselasky	}
5302259453Shselasky	if (sc->mac_ver == 0x5392) {
5303259453Shselasky		run_bbp_write(sc, 88, 0x90);
5304259453Shselasky		run_bbp_write(sc, 95, 0x9a);
5305259453Shselasky		run_bbp_write(sc, 98, 0x12);
5306259453Shselasky		run_bbp_write(sc, 106, 0x12);
5307259453Shselasky		run_bbp_write(sc, 134, 0xd0);
5308259453Shselasky		run_bbp_write(sc, 135, 0xf6);
5309259453Shselasky		run_bbp_write(sc, 148, 0x84);
5310259453Shselasky	}
5311259453Shselasky
5312259453Shselasky	run_bbp_read(sc, 152, &bbp);
5313259453Shselasky	run_bbp_write(sc, 152, bbp | 0x80);
5314259453Shselasky
5315259453Shselasky	/* Fix BBP254 for RT5592C. */
5316259453Shselasky	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5317259453Shselasky		run_bbp_read(sc, 254, &bbp);
5318259453Shselasky		run_bbp_write(sc, 254, bbp | 0x80);
5319259453Shselasky	}
5320259453Shselasky
5321259453Shselasky	/* Disable hardware antenna diversity. */
5322259453Shselasky	if (sc->mac_ver == 0x5390)
5323259453Shselasky		run_bbp_write(sc, 154, 0);
5324259453Shselasky
5325259453Shselasky	/* Initialize Rx CCK/OFDM frequency offset report. */
5326259453Shselasky	run_bbp_write(sc, 142, 1);
5327259453Shselasky	run_bbp_write(sc, 143, 57);
5328259453Shselasky}
5329259453Shselasky
5330203134Sthompsastatic int
5331203134Sthompsarun_bbp_init(struct run_softc *sc)
5332203134Sthompsa{
5333203134Sthompsa	int i, error, ntries;
5334203134Sthompsa	uint8_t bbp0;
5335203134Sthompsa
5336203134Sthompsa	/* wait for BBP to wake up */
5337203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5338203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5339203134Sthompsa			return error;
5340203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5341203134Sthompsa			break;
5342203134Sthompsa	}
5343203134Sthompsa	if (ntries == 20)
5344209917Sthompsa		return (ETIMEDOUT);
5345203134Sthompsa
5346203134Sthompsa	/* initialize BBP registers to default values */
5347259453Shselasky	if (sc->mac_ver >= 0x5390)
5348259453Shselasky		run_rt5390_bbp_init(sc);
5349259453Shselasky	else {
5350259453Shselasky		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5351259453Shselasky			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5352259453Shselasky			    rt2860_def_bbp[i].val);
5353259453Shselasky		}
5354203134Sthompsa	}
5355203134Sthompsa
5356261868Skevlo	if (sc->mac_ver == 0x3593) {
5357261868Skevlo		run_bbp_write(sc, 79, 0x13);
5358261868Skevlo		run_bbp_write(sc, 80, 0x05);
5359261868Skevlo		run_bbp_write(sc, 81, 0x33);
5360261868Skevlo		run_bbp_write(sc, 86, 0x46);
5361261868Skevlo		run_bbp_write(sc, 137, 0x0f);
5362261868Skevlo	}
5363261868Skevlo
5364203134Sthompsa	/* fix BBP84 for RT2860E */
5365205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5366205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5367203134Sthompsa
5368261868Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5369261868Skevlo	    sc->mac_ver != 0x5592)) {
5370203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5371203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5372203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5373205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5374203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5375203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5376203134Sthompsa	}
5377209917Sthompsa	return (0);
5378203134Sthompsa}
5379203134Sthompsa
5380203134Sthompsastatic int
5381203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5382203134Sthompsa{
5383203134Sthompsa	uint32_t tmp;
5384259453Shselasky	uint8_t bbp4, mingain, rf, target;
5385203134Sthompsa	int i;
5386203134Sthompsa
5387203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5388203134Sthompsa	/* toggle RF R30 bit 7 */
5389203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5390203134Sthompsa	run_delay(sc, 10);
5391203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5392203134Sthompsa
5393203134Sthompsa	/* initialize RF registers to default value */
5394205042Sthompsa	if (sc->mac_ver == 0x3572) {
5395259453Shselasky		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5396205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5397205042Sthompsa			    rt3572_def_rf[i].val);
5398205042Sthompsa		}
5399205042Sthompsa	} else {
5400259453Shselasky		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5401205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5402205042Sthompsa			    rt3070_def_rf[i].val);
5403205042Sthompsa		}
5404203134Sthompsa	}
5405205042Sthompsa
5406259453Shselasky	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5407259453Shselasky		/*
5408259453Shselasky		 * Change voltage from 1.2V to 1.35V for RT3070.
5409259453Shselasky		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5410259453Shselasky		 * in RT3070(F).
5411259453Shselasky		 */
5412203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5413203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5414203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5415203134Sthompsa
5416205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5417203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5418203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5419203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5420203134Sthompsa
5421203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5422203134Sthompsa		tmp &= ~0x1f000000;
5423205042Sthompsa		if (sc->mac_rev < 0x0211)
5424205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5425203134Sthompsa		else
5426205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5427203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5428203134Sthompsa
5429203134Sthompsa		/* patch LNA_PE_G1 */
5430203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5431203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5432208019Sthompsa
5433209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5434205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5435205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5436205042Sthompsa
5437208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5438208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5439208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5440208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5441203134Sthompsa
5442209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5443203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5444205042Sthompsa			/* decrease voltage back to 1.2V */
5445203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5446203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5447203134Sthompsa		}
5448203134Sthompsa	}
5449203134Sthompsa
5450203134Sthompsa	/* select 20MHz bandwidth */
5451203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5452203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5453203134Sthompsa
5454203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5455203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5456205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5457205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5458203134Sthompsa
5459203134Sthompsa	/* select 40MHz bandwidth */
5460203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5461259453Shselasky	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5462205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5463205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5464203134Sthompsa
5465203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5466203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5467205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5468205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5469203134Sthompsa
5470203134Sthompsa	/* go back to 20MHz bandwidth */
5471203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5472203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5473203134Sthompsa
5474205042Sthompsa	if (sc->mac_ver == 0x3572) {
5475205042Sthompsa		/* save default BBP registers 25 and 26 values */
5476205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5477205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5478259453Shselasky	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5479203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5480203134Sthompsa
5481203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5482203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5483203134Sthompsa
5484205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5485205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5486205042Sthompsa		rf &= ~RT3070_TX_LO1;
5487205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5488205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5489205042Sthompsa		    !sc->ext_2ghz_lna)
5490205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5491259453Shselasky		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5492259453Shselasky		if (sc->txmixgain_2ghz >= mingain)
5493205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5494205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5495205042Sthompsa	}
5496205042Sthompsa
5497270843Skevlo	if (sc->mac_ver == 0x3071) {
5498203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5499203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5500203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5501203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5502203134Sthompsa
5503203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5504203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5505203134Sthompsa
5506203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5507203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5508203134Sthompsa
5509203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5510203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5511205042Sthompsa	}
5512203134Sthompsa
5513205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5514205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5515203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5516203134Sthompsa		rf &= ~0x77;
5517205042Sthompsa		if (sc->mac_rev < 0x0211)
5518203134Sthompsa			rf |= 0x03;
5519203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5520203134Sthompsa	}
5521209917Sthompsa	return (0);
5522203134Sthompsa}
5523203134Sthompsa
5524259453Shselaskystatic void
5525261868Skevlorun_rt3593_rf_init(struct run_softc *sc)
5526261868Skevlo{
5527261868Skevlo	uint32_t tmp;
5528261868Skevlo	uint8_t rf;
5529261868Skevlo	int i;
5530261868Skevlo
5531261868Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5532261868Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5533261868Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5534261868Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5535261868Skevlo
5536261868Skevlo	/* Initialize RF registers to default value. */
5537261868Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5538261868Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5539261868Skevlo		    rt3593_def_rf[i].val);
5540261868Skevlo	}
5541261868Skevlo
5542261868Skevlo	/* Toggle RF R2 to initiate calibration. */
5543261868Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5544261868Skevlo
5545261868Skevlo	/* Initialize RF frequency offset. */
5546261868Skevlo	run_adjust_freq_offset(sc);
5547261868Skevlo
5548261868Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5549261868Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5550261868Skevlo
5551261868Skevlo	/*
5552261868Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5553261868Skevlo	 * decrease voltage back to 1.2V.
5554261868Skevlo	 */
5555261868Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5556261868Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5557261868Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5558261868Skevlo	run_delay(sc, 1);
5559261868Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5560261868Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5561261868Skevlo
5562261868Skevlo	sc->rf24_20mhz = 0x1f;
5563261868Skevlo	sc->rf24_40mhz = 0x2f;
5564261868Skevlo
5565261868Skevlo	/* Save default BBP registers 25 and 26 values. */
5566261868Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5567261868Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5568261868Skevlo
5569261868Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5570261868Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5571261868Skevlo}
5572261868Skevlo
5573261868Skevlostatic void
5574259453Shselaskyrun_rt5390_rf_init(struct run_softc *sc)
5575259453Shselasky{
5576259453Shselasky	uint32_t tmp;
5577259453Shselasky	uint8_t rf;
5578259453Shselasky	int i;
5579259453Shselasky
5580259453Shselasky	/* Toggle RF R2 to initiate calibration. */
5581259453Shselasky	if (sc->mac_ver == 0x5390) {
5582259453Shselasky		run_rt3070_rf_read(sc, 2, &rf);
5583259453Shselasky		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5584259453Shselasky		run_delay(sc, 10);
5585259453Shselasky		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5586259453Shselasky	} else {
5587259453Shselasky		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5588259453Shselasky		run_delay(sc, 10);
5589259453Shselasky	}
5590259453Shselasky
5591259453Shselasky	/* Initialize RF registers to default value. */
5592259453Shselasky	if (sc->mac_ver == 0x5592) {
5593259453Shselasky		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5594259453Shselasky			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5595259453Shselasky			    rt5592_def_rf[i].val);
5596259453Shselasky		}
5597259453Shselasky		/* Initialize RF frequency offset. */
5598259453Shselasky		run_adjust_freq_offset(sc);
5599259453Shselasky	} else if (sc->mac_ver == 0x5392) {
5600259453Shselasky		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5601259453Shselasky			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5602259453Shselasky			    rt5392_def_rf[i].val);
5603259453Shselasky		}
5604259453Shselasky		if (sc->mac_rev >= 0x0223) {
5605259453Shselasky			run_rt3070_rf_write(sc, 23, 0x0f);
5606259453Shselasky			run_rt3070_rf_write(sc, 24, 0x3e);
5607259453Shselasky			run_rt3070_rf_write(sc, 51, 0x32);
5608259453Shselasky			run_rt3070_rf_write(sc, 53, 0x22);
5609259453Shselasky			run_rt3070_rf_write(sc, 56, 0xc1);
5610259453Shselasky			run_rt3070_rf_write(sc, 59, 0x0f);
5611259453Shselasky		}
5612259453Shselasky	} else {
5613259453Shselasky		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5614259453Shselasky			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5615259453Shselasky			    rt5390_def_rf[i].val);
5616259453Shselasky		}
5617259453Shselasky		if (sc->mac_rev >= 0x0502) {
5618259453Shselasky			run_rt3070_rf_write(sc, 6, 0xe0);
5619259453Shselasky			run_rt3070_rf_write(sc, 25, 0x80);
5620259453Shselasky			run_rt3070_rf_write(sc, 46, 0x73);
5621259453Shselasky			run_rt3070_rf_write(sc, 53, 0x00);
5622259453Shselasky			run_rt3070_rf_write(sc, 56, 0x42);
5623259453Shselasky			run_rt3070_rf_write(sc, 61, 0xd1);
5624259453Shselasky		}
5625259453Shselasky	}
5626259453Shselasky
5627259453Shselasky	sc->rf24_20mhz = 0x1f;	/* default value */
5628259453Shselasky	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5629259453Shselasky
5630259453Shselasky	if (sc->mac_rev < 0x0211)
5631259453Shselasky		run_rt3070_rf_write(sc, 27, 0x3);
5632259453Shselasky
5633259453Shselasky	run_read(sc, RT3070_OPT_14, &tmp);
5634259453Shselasky	run_write(sc, RT3070_OPT_14, tmp | 1);
5635259453Shselasky}
5636259453Shselasky
5637203134Sthompsastatic int
5638203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5639203134Sthompsa    uint8_t *val)
5640203134Sthompsa{
5641203134Sthompsa	uint8_t rf22, rf24;
5642203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5643203134Sthompsa	int ntries;
5644203134Sthompsa
5645203134Sthompsa	/* program filter */
5646205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5647205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5648203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5649203134Sthompsa
5650203134Sthompsa	/* enable baseband loopback mode */
5651203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5652203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5653203134Sthompsa
5654203134Sthompsa	/* set power and frequency of passband test tone */
5655203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5656203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5657203134Sthompsa		/* transmit test tone */
5658203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5659203134Sthompsa		run_delay(sc, 10);
5660203134Sthompsa		/* read received power */
5661203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5662203134Sthompsa		if (bbp55_pb != 0)
5663203134Sthompsa			break;
5664203134Sthompsa	}
5665203134Sthompsa	if (ntries == 100)
5666259453Shselasky		return (ETIMEDOUT);
5667203134Sthompsa
5668203134Sthompsa	/* set power and frequency of stopband test tone */
5669203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5670203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5671203134Sthompsa		/* transmit test tone */
5672203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5673203134Sthompsa		run_delay(sc, 10);
5674203134Sthompsa		/* read received power */
5675203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5676203134Sthompsa
5677203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5678203134Sthompsa		if (delta > target)
5679203134Sthompsa			break;
5680203134Sthompsa
5681203134Sthompsa		/* reprogram filter */
5682203134Sthompsa		rf24++;
5683203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5684203134Sthompsa	}
5685203134Sthompsa	if (ntries < 100) {
5686203134Sthompsa		if (rf24 != init)
5687203134Sthompsa			rf24--;	/* backtrack */
5688203134Sthompsa		*val = rf24;
5689203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5690203134Sthompsa	}
5691203134Sthompsa
5692203134Sthompsa	/* restore initial state */
5693203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5694203134Sthompsa
5695203134Sthompsa	/* disable baseband loopback mode */
5696203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5697203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5698203134Sthompsa
5699209917Sthompsa	return (0);
5700203134Sthompsa}
5701203134Sthompsa
5702205042Sthompsastatic void
5703205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5704205042Sthompsa{
5705205042Sthompsa	uint8_t bbp, rf;
5706205042Sthompsa	int i;
5707205042Sthompsa
5708261868Skevlo	if (sc->mac_ver == 0x3572) {
5709205042Sthompsa		/* enable DC filter */
5710205042Sthompsa		if (sc->mac_rev >= 0x0201)
5711205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5712205042Sthompsa
5713205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5714205042Sthompsa		if (sc->ntxchains == 1)
5715205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5716205042Sthompsa		if (sc->nrxchains == 1)
5717205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5718205042Sthompsa		run_bbp_write(sc, 138, bbp);
5719205042Sthompsa
5720205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5721205042Sthompsa			/* improve power consumption */
5722205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5723205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5724205042Sthompsa		}
5725205042Sthompsa
5726205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5727205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5728205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5729205042Sthompsa
5730205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5731259453Shselasky		if (sc->mac_rev >= 0x0211) {
5732259453Shselasky			/* enable DC filter */
5733205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5734205042Sthompsa
5735259453Shselasky			/* improve power consumption */
5736259453Shselasky			run_bbp_read(sc, 31, &bbp);
5737259453Shselasky			run_bbp_write(sc, 31, bbp & ~0x03);
5738259453Shselasky		}
5739259453Shselasky
5740205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5741205042Sthompsa		if (sc->ntxchains == 1)
5742205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5743205042Sthompsa		if (sc->nrxchains == 1)
5744205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5745205042Sthompsa		run_bbp_write(sc, 138, bbp);
5746205042Sthompsa
5747205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5748205042Sthompsa		if (sc->mac_rev < 0x0211) {
5749205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5750205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5751205042Sthompsa		} else
5752205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5753205042Sthompsa
5754205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5755205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5756205042Sthompsa			/* enable DC filter */
5757205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5758205042Sthompsa
5759205042Sthompsa			/* improve power consumption */
5760205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5761205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5762205042Sthompsa		}
5763205042Sthompsa
5764259453Shselasky		if (sc->mac_rev < 0x0201) {
5765205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5766205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5767205042Sthompsa		} else
5768205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5769205042Sthompsa	}
5770205042Sthompsa
5771205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5772261868Skevlo	if (sc->mac_ver >= 0x3071) {
5773205042Sthompsa		for (i = 0; i < 10; i++) {
5774205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5775205042Sthompsa				continue;
5776205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5777205042Sthompsa		}
5778205042Sthompsa	}
5779205042Sthompsa}
5780205042Sthompsa
5781261868Skevlostatic void
5782261868Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5783261868Skevlo{
5784261868Skevlo	uint8_t bbp, rf;
5785261868Skevlo
5786261868Skevlo	if (sc->mac_rev >= 0x0211) {
5787261868Skevlo		/* Enable DC filter. */
5788261868Skevlo		run_bbp_write(sc, 103, 0xc0);
5789261868Skevlo	}
5790261868Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5791261868Skevlo	if (sc->mac_rev < 0x0211) {
5792261868Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5793261868Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5794261868Skevlo	} else
5795261868Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5796261868Skevlo
5797261868Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5798261868Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5799261868Skevlo
5800261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5801261868Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5802261868Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5803261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
5804261868Skevlo
5805261868Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5806261868Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5807261868Skevlo
5808261868Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5809261868Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5810261868Skevlo
5811261868Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5812261868Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5813261868Skevlo
5814261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5815261868Skevlo	rf = (rf & ~0x18) | 0x10;
5816261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
5817261868Skevlo
5818261868Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5819261868Skevlo	run_bbp_read(sc, 105, &bbp);
5820261868Skevlo	if (sc->nrxchains > 1)
5821261868Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5822261868Skevlo
5823261868Skevlo	/* Avoid data lost and CRC error. */
5824261868Skevlo	run_bbp_read(sc, 4, &bbp);
5825261868Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5826261868Skevlo
5827261868Skevlo	run_bbp_write(sc, 92, 0x02);
5828261868Skevlo	run_bbp_write(sc, 82, 0x82);
5829261868Skevlo	run_bbp_write(sc, 106, 0x05);
5830261868Skevlo	run_bbp_write(sc, 104, 0x92);
5831261868Skevlo	run_bbp_write(sc, 88, 0x90);
5832261868Skevlo	run_bbp_write(sc, 148, 0xc8);
5833261868Skevlo	run_bbp_write(sc, 47, 0x48);
5834261868Skevlo	run_bbp_write(sc, 120, 0x50);
5835261868Skevlo
5836261868Skevlo	run_bbp_write(sc, 163, 0x9d);
5837261868Skevlo
5838261868Skevlo	/* SNR mapping. */
5839261868Skevlo	run_bbp_write(sc, 142, 0x06);
5840261868Skevlo	run_bbp_write(sc, 143, 0xa0);
5841261868Skevlo	run_bbp_write(sc, 142, 0x07);
5842261868Skevlo	run_bbp_write(sc, 143, 0xa1);
5843261868Skevlo	run_bbp_write(sc, 142, 0x08);
5844261868Skevlo	run_bbp_write(sc, 143, 0xa2);
5845261868Skevlo
5846261868Skevlo	run_bbp_write(sc, 31, 0x08);
5847261868Skevlo	run_bbp_write(sc, 68, 0x0b);
5848261868Skevlo	run_bbp_write(sc, 105, 0x04);
5849261868Skevlo}
5850261868Skevlo
5851261868Skevlostatic void
5852261868Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5853261868Skevlo{
5854261868Skevlo	uint8_t bbp, rf;
5855261868Skevlo
5856261868Skevlo	if (sc->mac_rev >= 0x0211) {
5857261868Skevlo		/* Enable DC filter. */
5858261868Skevlo		run_bbp_write(sc, 103, 0xc0);
5859261868Skevlo
5860261868Skevlo		if (sc->mac_ver != 0x5592) {
5861261868Skevlo			/* Improve power consumption. */
5862261868Skevlo			run_bbp_read(sc, 31, &bbp);
5863261868Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5864261868Skevlo		}
5865261868Skevlo	}
5866261868Skevlo
5867261868Skevlo	run_bbp_read(sc, 138, &bbp);
5868261868Skevlo	if (sc->ntxchains == 1)
5869261868Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5870261868Skevlo	if (sc->nrxchains == 1)
5871261868Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5872261868Skevlo	run_bbp_write(sc, 138, bbp);
5873261868Skevlo
5874261868Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5875261868Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5876261868Skevlo
5877261868Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5878261868Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5879261868Skevlo
5880261868Skevlo	/* Avoid data lost and CRC error. */
5881261868Skevlo	run_bbp_read(sc, 4, &bbp);
5882261868Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5883261868Skevlo
5884261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5885261868Skevlo	rf = (rf & ~0x18) | 0x10;
5886261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
5887261868Skevlo
5888261868Skevlo	if (sc->mac_ver != 0x5592) {
5889261868Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5890261868Skevlo		if (sc->mac_rev < 0x0211) {
5891261868Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5892261868Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5893261868Skevlo		} else
5894261868Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5895261868Skevlo	}
5896261868Skevlo}
5897261868Skevlo
5898203134Sthompsastatic int
5899203134Sthompsarun_txrx_enable(struct run_softc *sc)
5900203134Sthompsa{
5901203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5902203134Sthompsa	uint32_t tmp;
5903203134Sthompsa	int error, ntries;
5904203134Sthompsa
5905203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5906203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5907203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5908259453Shselasky			return (error);
5909203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5910203134Sthompsa			break;
5911203134Sthompsa		run_delay(sc, 50);
5912203134Sthompsa	}
5913203134Sthompsa	if (ntries == 200)
5914259453Shselasky		return (ETIMEDOUT);
5915203134Sthompsa
5916203134Sthompsa	run_delay(sc, 50);
5917203134Sthompsa
5918203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5919203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5920203134Sthompsa
5921203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5922203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5923203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5924203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5925203134Sthompsa
5926203134Sthompsa	/* set Rx filter */
5927203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5928203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5929203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5930203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5931203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5932203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5933203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5934203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5935203134Sthompsa	}
5936203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5937203134Sthompsa
5938203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5939203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5940203134Sthompsa
5941209917Sthompsa	return (0);
5942203134Sthompsa}
5943203134Sthompsa
5944203134Sthompsastatic void
5945259453Shselaskyrun_adjust_freq_offset(struct run_softc *sc)
5946259453Shselasky{
5947259453Shselasky	uint8_t rf, tmp;
5948259453Shselasky
5949259453Shselasky	run_rt3070_rf_read(sc, 17, &rf);
5950259453Shselasky	tmp = rf;
5951259453Shselasky	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5952259453Shselasky	rf = MIN(rf, 0x5f);
5953259453Shselasky
5954259453Shselasky	if (tmp != rf)
5955259453Shselasky		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5956259453Shselasky}
5957259453Shselasky
5958259453Shselaskystatic void
5959203134Sthompsarun_init_locked(struct run_softc *sc)
5960203134Sthompsa{
5961203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
5962203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5963203134Sthompsa	uint32_t tmp;
5964203134Sthompsa	uint8_t bbp1, bbp3;
5965203134Sthompsa	int i;
5966203134Sthompsa	int ridx;
5967203134Sthompsa	int ntries;
5968203134Sthompsa
5969209917Sthompsa	if (ic->ic_nrunning > 1)
5970208019Sthompsa		return;
5971208019Sthompsa
5972203134Sthompsa	run_stop(sc);
5973203134Sthompsa
5974233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5975233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5976233283Sbschmidt		goto fail;
5977233283Sbschmidt	}
5978233283Sbschmidt
5979203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5980203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5981203134Sthompsa			goto fail;
5982203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5983203134Sthompsa			break;
5984203134Sthompsa		run_delay(sc, 10);
5985203134Sthompsa	}
5986203134Sthompsa	if (ntries == 100)
5987203134Sthompsa		goto fail;
5988203134Sthompsa
5989203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5990203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5991203134Sthompsa
5992203134Sthompsa	run_set_macaddr(sc, IF_LLADDR(ifp));
5993203134Sthompsa
5994203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5995203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5996203134Sthompsa			goto fail;
5997203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5998203134Sthompsa			break;
5999203134Sthompsa		run_delay(sc, 10);
6000203134Sthompsa	}
6001203134Sthompsa	if (ntries == 100) {
6002203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6003203134Sthompsa		goto fail;
6004203134Sthompsa	}
6005203134Sthompsa	tmp &= 0xff0;
6006203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
6007203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6008203134Sthompsa
6009203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
6010203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
6011203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
6012203134Sthompsa
6013203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
6014203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
6015203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6016203134Sthompsa
6017203134Sthompsa	if (run_reset(sc) != 0) {
6018203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
6019203134Sthompsa		goto fail;
6020203134Sthompsa	}
6021203134Sthompsa
6022203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6023203134Sthompsa
6024203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
6025203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
6026203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
6027203134Sthompsa			continue;
6028203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
6029203134Sthompsa	}
6030203134Sthompsa
6031259453Shselasky	for (i = 0; i < nitems(rt2870_def_mac); i++)
6032203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6033203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6034203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6035203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6036203134Sthompsa
6037259453Shselasky	if (sc->mac_ver >= 0x5390) {
6038259453Shselasky		run_write(sc, RT2860_TX_SW_CFG0,
6039259453Shselasky		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6040259453Shselasky		if (sc->mac_ver >= 0x5392) {
6041259453Shselasky			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6042259453Shselasky			if (sc->mac_ver == 0x5592) {
6043259453Shselasky				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6044259453Shselasky				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6045259453Shselasky			} else {
6046259453Shselasky				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6047259453Shselasky				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6048259453Shselasky			}
6049259453Shselasky		}
6050261868Skevlo	} else if (sc->mac_ver == 0x3593) {
6051261868Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6052261868Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6053259453Shselasky	} else if (sc->mac_ver >= 0x3070) {
6054203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6055203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6056203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6057203134Sthompsa	}
6058203134Sthompsa
6059203134Sthompsa	/* wait while MAC is busy */
6060203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6061203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6062203134Sthompsa			goto fail;
6063203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6064203134Sthompsa			break;
6065203134Sthompsa		run_delay(sc, 10);
6066203134Sthompsa	}
6067203134Sthompsa	if (ntries == 100)
6068203134Sthompsa		goto fail;
6069203134Sthompsa
6070203134Sthompsa	/* clear Host to MCU mailbox */
6071203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6072203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6073203134Sthompsa	run_delay(sc, 10);
6074203134Sthompsa
6075203134Sthompsa	if (run_bbp_init(sc) != 0) {
6076203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6077203134Sthompsa		goto fail;
6078203134Sthompsa	}
6079203134Sthompsa
6080203134Sthompsa	/* abort TSF synchronization */
6081203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6082203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6083203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6084203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6085203134Sthompsa
6086203134Sthompsa	/* clear RX WCID search table */
6087203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6088203134Sthompsa	/* clear WCID attribute table */
6089203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6090203134Sthompsa
6091209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6092209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6093209144Sthompsa		/* clear shared key table */
6094209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6095209144Sthompsa		/* clear shared key mode */
6096209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6097209144Sthompsa	}
6098209144Sthompsa
6099203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6100203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6101203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6102203134Sthompsa
6103205042Sthompsa	if (sc->mac_rev != 0x0101)
6104203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6105203134Sthompsa
6106203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6107203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6108203134Sthompsa
6109203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6110261868Skevlo	if (sc->mac_ver < 0x3593) {
6111259453Shselasky		for (i = 0; i < 10; i++) {
6112259453Shselasky			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6113259453Shselasky				continue;
6114259453Shselasky			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6115259453Shselasky		}
6116203134Sthompsa	}
6117203134Sthompsa
6118203134Sthompsa	/* select Main antenna for 1T1R devices */
6119259453Shselasky	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6120203134Sthompsa		run_set_rx_antenna(sc, 0);
6121203134Sthompsa
6122203134Sthompsa	/* send LEDs operating mode to microcontroller */
6123203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6124203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6125203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6126203134Sthompsa
6127259453Shselasky	if (sc->mac_ver >= 0x5390)
6128259453Shselasky		run_rt5390_rf_init(sc);
6129261868Skevlo	else if (sc->mac_ver == 0x3593)
6130261868Skevlo		run_rt3593_rf_init(sc);
6131259453Shselasky	else if (sc->mac_ver >= 0x3070)
6132205042Sthompsa		run_rt3070_rf_init(sc);
6133205042Sthompsa
6134203134Sthompsa	/* disable non-existing Rx chains */
6135203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6136203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6137203134Sthompsa	if (sc->nrxchains == 2)
6138203134Sthompsa		bbp3 |= 1 << 3;
6139203134Sthompsa	else if (sc->nrxchains == 3)
6140203134Sthompsa		bbp3 |= 1 << 4;
6141203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6142203134Sthompsa
6143203134Sthompsa	/* disable non-existing Tx chains */
6144203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6145203134Sthompsa	if (sc->ntxchains == 1)
6146203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6147203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6148203134Sthompsa
6149261868Skevlo	if (sc->mac_ver >= 0x5390)
6150261868Skevlo		run_rt5390_rf_setup(sc);
6151261868Skevlo	else if (sc->mac_ver == 0x3593)
6152261868Skevlo		run_rt3593_rf_setup(sc);
6153261868Skevlo	else if (sc->mac_ver >= 0x3070)
6154205042Sthompsa		run_rt3070_rf_setup(sc);
6155203134Sthompsa
6156203134Sthompsa	/* select default channel */
6157203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6158203134Sthompsa
6159203134Sthompsa	/* setup initial protection mode */
6160218492Sbschmidt	run_updateprot_cb(ic);
6161203134Sthompsa
6162203134Sthompsa	/* turn radio LED on */
6163203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6164203134Sthompsa
6165203134Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6166203134Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
6167208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6168203134Sthompsa
6169209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6170203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6171203134Sthompsa
6172203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6173203134Sthompsa
6174203134Sthompsa	if (run_txrx_enable(sc) != 0)
6175203134Sthompsa		goto fail;
6176203134Sthompsa
6177203134Sthompsa	return;
6178203134Sthompsa
6179203134Sthompsafail:
6180203134Sthompsa	run_stop(sc);
6181203134Sthompsa}
6182203134Sthompsa
6183203134Sthompsastatic void
6184203134Sthompsarun_init(void *arg)
6185203134Sthompsa{
6186203134Sthompsa	struct run_softc *sc = arg;
6187203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6188203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
6189203134Sthompsa
6190203134Sthompsa	RUN_LOCK(sc);
6191203134Sthompsa	run_init_locked(sc);
6192203134Sthompsa	RUN_UNLOCK(sc);
6193203134Sthompsa
6194203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6195208019Sthompsa		ieee80211_start_all(ic);
6196203134Sthompsa}
6197203134Sthompsa
6198203134Sthompsastatic void
6199203134Sthompsarun_stop(void *arg)
6200203134Sthompsa{
6201203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6202203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6203203134Sthompsa	uint32_t tmp;
6204203134Sthompsa	int i;
6205203134Sthompsa	int ntries;
6206203134Sthompsa
6207203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6208203134Sthompsa
6209203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6210203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6211203134Sthompsa
6212203134Sthompsa	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
6213203134Sthompsa
6214208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6215209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6216208019Sthompsa
6217203134Sthompsa	RUN_UNLOCK(sc);
6218203134Sthompsa
6219203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6220203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6221203134Sthompsa
6222203134Sthompsa	RUN_LOCK(sc);
6223203134Sthompsa
6224209917Sthompsa	if (sc->rx_m != NULL) {
6225203134Sthompsa		m_free(sc->rx_m);
6226203134Sthompsa		sc->rx_m = NULL;
6227203134Sthompsa	}
6228203134Sthompsa
6229259453Shselasky	/* Disable Tx/Rx DMA. */
6230259453Shselasky	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6231259453Shselasky		return;
6232259453Shselasky	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6233259453Shselasky	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6234259453Shselasky
6235259453Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6236259453Shselasky		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6237259453Shselasky			return;
6238259453Shselasky		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6239259453Shselasky				break;
6240259453Shselasky		run_delay(sc, 10);
6241259453Shselasky	}
6242259453Shselasky	if (ntries == 100) {
6243259453Shselasky		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6244259453Shselasky		return;
6245259453Shselasky	}
6246259453Shselasky
6247203134Sthompsa	/* disable Tx/Rx */
6248203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6249203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6250203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6251203134Sthompsa
6252203134Sthompsa	/* wait for pending Tx to complete */
6253203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6254209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6255203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6256203134Sthompsa			break;
6257203134Sthompsa		}
6258209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6259203134Sthompsa			DPRINTF("All Tx cleared\n");
6260203134Sthompsa			break;
6261203134Sthompsa		}
6262203134Sthompsa		run_delay(sc, 10);
6263203134Sthompsa	}
6264209917Sthompsa	if (ntries >= 100)
6265203134Sthompsa		DPRINTF("There are still pending Tx\n");
6266203134Sthompsa	run_delay(sc, 10);
6267203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6268203134Sthompsa
6269203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6270203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6271203134Sthompsa
6272203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6273203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6274203134Sthompsa}
6275203134Sthompsa
6276203134Sthompsastatic void
6277259453Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6278203134Sthompsa{
6279203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6280203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6281203134Sthompsa}
6282203134Sthompsa
6283203134Sthompsastatic device_method_t run_methods[] = {
6284203134Sthompsa	/* Device interface */
6285203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6286203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6287203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6288246614Shselasky	DEVMETHOD_END
6289203134Sthompsa};
6290203134Sthompsa
6291203134Sthompsastatic driver_t run_driver = {
6292233774Shselasky	.name = "run",
6293233774Shselasky	.methods = run_methods,
6294233774Shselasky	.size = sizeof(struct run_softc)
6295203134Sthompsa};
6296203134Sthompsa
6297203134Sthompsastatic devclass_t run_devclass;
6298203134Sthompsa
6299261868SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6300212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6301212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6302212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6303212122SthompsaMODULE_VERSION(run, 1);
6304