1192873Sweongyo/*-
2192873Sweongyo * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
3192873Sweongyo *
4192873Sweongyo * Permission to use, copy, modify, and distribute this software for any
5192873Sweongyo * purpose with or without fee is hereby granted, provided that the above
6192873Sweongyo * copyright notice and this permission notice appear in all copies.
7192873Sweongyo *
8192873Sweongyo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9192873Sweongyo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10192873Sweongyo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11192873Sweongyo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12192873Sweongyo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13192873Sweongyo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14192873Sweongyo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15192873Sweongyo */
16192873Sweongyo
17192873Sweongyo#include <sys/cdefs.h>
18192873Sweongyo__FBSDID("$FreeBSD$");
19192873Sweongyo#include <sys/param.h>
20192873Sweongyo#include <sys/sockio.h>
21192873Sweongyo#include <sys/sysctl.h>
22192873Sweongyo#include <sys/lock.h>
23192873Sweongyo#include <sys/mutex.h>
24192873Sweongyo#include <sys/mbuf.h>
25192873Sweongyo#include <sys/kernel.h>
26192873Sweongyo#include <sys/socket.h>
27192873Sweongyo#include <sys/systm.h>
28192873Sweongyo#include <sys/malloc.h>
29192873Sweongyo#include <sys/module.h>
30192873Sweongyo#include <sys/bus.h>
31192873Sweongyo#include <sys/endian.h>
32192873Sweongyo#include <sys/kdb.h>
33192873Sweongyo
34192873Sweongyo#include <machine/bus.h>
35192873Sweongyo#include <machine/resource.h>
36192873Sweongyo#include <sys/rman.h>
37192873Sweongyo
38192873Sweongyo#include <net/if.h>
39192873Sweongyo#include <net/if_arp.h>
40192873Sweongyo#include <net/ethernet.h>
41192873Sweongyo#include <net/if_dl.h>
42192873Sweongyo#include <net/if_media.h>
43192873Sweongyo#include <net/if_types.h>
44192873Sweongyo
45192873Sweongyo#ifdef INET
46192873Sweongyo#include <netinet/in.h>
47192873Sweongyo#include <netinet/in_systm.h>
48192873Sweongyo#include <netinet/in_var.h>
49192873Sweongyo#include <netinet/if_ether.h>
50192873Sweongyo#include <netinet/ip.h>
51192873Sweongyo#endif
52192873Sweongyo
53192873Sweongyo#include <net80211/ieee80211_var.h>
54192873Sweongyo#include <net80211/ieee80211_regdomain.h>
55192873Sweongyo#include <net80211/ieee80211_radiotap.h>
56192873Sweongyo
57192873Sweongyo#include <dev/usb/usb.h>
58194677Sthompsa#include <dev/usb/usbdi.h>
59192873Sweongyo#include "usbdevs.h"
60192873Sweongyo
61192873Sweongyo#include <dev/usb/wlan/if_urtwreg.h>
62192873Sweongyo#include <dev/usb/wlan/if_urtwvar.h>
63192873Sweongyo
64248085Smariusstatic SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L");
65192873Sweongyo#ifdef URTW_DEBUG
66192873Sweongyoint urtw_debug = 0;
67242775ShselaskySYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &urtw_debug, 0,
68192873Sweongyo    "control debugging printfs");
69192873SweongyoTUNABLE_INT("hw.usb.urtw.debug", &urtw_debug);
70192873Sweongyoenum {
71192873Sweongyo	URTW_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
72192873Sweongyo	URTW_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
73192873Sweongyo	URTW_DEBUG_RESET	= 0x00000004,	/* reset processing */
74192873Sweongyo	URTW_DEBUG_TX_PROC	= 0x00000008,	/* tx ISR proc */
75192873Sweongyo	URTW_DEBUG_RX_PROC	= 0x00000010,	/* rx ISR proc */
76192873Sweongyo	URTW_DEBUG_STATE	= 0x00000020,	/* 802.11 state transitions */
77192873Sweongyo	URTW_DEBUG_STAT		= 0x00000040,	/* statistic */
78192873Sweongyo	URTW_DEBUG_INIT		= 0x00000080,	/* initialization of dev */
79198194Sweongyo	URTW_DEBUG_TXSTATUS	= 0x00000100,	/* tx status */
80192873Sweongyo	URTW_DEBUG_ANY		= 0xffffffff
81192873Sweongyo};
82192873Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {				\
83192873Sweongyo	if (sc->sc_debug & (m))					\
84192873Sweongyo		printf(fmt, __VA_ARGS__);			\
85192873Sweongyo} while (0)
86192873Sweongyo#else
87192873Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {				\
88192873Sweongyo	(void) sc;						\
89192873Sweongyo} while (0)
90192873Sweongyo#endif
91194099Sthompsastatic int urtw_preamble_mode = URTW_PREAMBLE_MODE_LONG;
92242775ShselaskySYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW | CTLFLAG_TUN,
93192873Sweongyo    &urtw_preamble_mode, 0, "set the preable mode (long or short)");
94192873SweongyoTUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode);
95192873Sweongyo
96192873Sweongyo/* recognized device vendors/products */
97192873Sweongyo#define urtw_lookup(v, p)						\
98192873Sweongyo	((const struct urtw_type *)usb_lookup(urtw_devs, v, p))
99192873Sweongyo#define	URTW_DEV_B(v,p)							\
100192873Sweongyo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187B) }
101192873Sweongyo#define	URTW_DEV_L(v,p)							\
102192873Sweongyo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) }
103192873Sweongyo#define	URTW_REV_RTL8187B	0
104192873Sweongyo#define	URTW_REV_RTL8187L	1
105223486Shselaskystatic const STRUCT_USB_HOST_ID urtw_devs[] = {
106197761Sweongyo	URTW_DEV_B(NETGEAR, WG111V3),
107197761Sweongyo	URTW_DEV_B(REALTEK, RTL8187B_0),
108197761Sweongyo	URTW_DEV_B(REALTEK, RTL8187B_1),
109197761Sweongyo	URTW_DEV_B(REALTEK, RTL8187B_2),
110197761Sweongyo	URTW_DEV_B(SITECOMEU, WL168V4),
111197761Sweongyo	URTW_DEV_L(ASUS, P5B_WIFI),
112197761Sweongyo	URTW_DEV_L(BELKIN, F5D7050E),
113197761Sweongyo	URTW_DEV_L(LINKSYS4, WUSB54GCV2),
114197761Sweongyo	URTW_DEV_L(NETGEAR, WG111V2),
115197761Sweongyo	URTW_DEV_L(REALTEK, RTL8187),
116197761Sweongyo	URTW_DEV_L(SITECOMEU, WL168V1),
117197761Sweongyo	URTW_DEV_L(SURECOM, EP9001G2A),
118223446Sgavin	{ USB_VPI(USB_VENDOR_OVISLINK, 0x8187, URTW_REV_RTL8187L) },
119192873Sweongyo	{ USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) },
120192873Sweongyo	{ USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) },
121192873Sweongyo	{ USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) },
122192873Sweongyo	{ USB_VPI(USB_VENDOR_NETGEAR, 0x6100, URTW_REV_RTL8187L) },
123192873Sweongyo	{ USB_VPI(USB_VENDOR_SPHAIRON, 0x0150, URTW_REV_RTL8187L) },
124192873Sweongyo	{ USB_VPI(USB_VENDOR_QCOM, 0x6232, URTW_REV_RTL8187L) },
125192873Sweongyo#undef URTW_DEV_L
126192873Sweongyo#undef URTW_DEV_B
127192873Sweongyo};
128192873Sweongyo
129192873Sweongyo#define urtw_read8_m(sc, val, data)	do {			\
130192873Sweongyo	error = urtw_read8_c(sc, val, data);			\
131192873Sweongyo	if (error != 0)						\
132192873Sweongyo		goto fail;					\
133192873Sweongyo} while (0)
134192873Sweongyo#define urtw_write8_m(sc, val, data)	do {			\
135192873Sweongyo	error = urtw_write8_c(sc, val, data);			\
136192873Sweongyo	if (error != 0)						\
137192873Sweongyo		goto fail;					\
138192873Sweongyo} while (0)
139192873Sweongyo#define urtw_read16_m(sc, val, data)	do {			\
140192873Sweongyo	error = urtw_read16_c(sc, val, data);			\
141192873Sweongyo	if (error != 0)						\
142192873Sweongyo		goto fail;					\
143192873Sweongyo} while (0)
144192873Sweongyo#define urtw_write16_m(sc, val, data)	do {			\
145192873Sweongyo	error = urtw_write16_c(sc, val, data);			\
146192873Sweongyo	if (error != 0)						\
147192873Sweongyo		goto fail;					\
148192873Sweongyo} while (0)
149192873Sweongyo#define urtw_read32_m(sc, val, data)	do {			\
150192873Sweongyo	error = urtw_read32_c(sc, val, data);			\
151192873Sweongyo	if (error != 0)						\
152192873Sweongyo		goto fail;					\
153192873Sweongyo} while (0)
154192873Sweongyo#define urtw_write32_m(sc, val, data)	do {			\
155192873Sweongyo	error = urtw_write32_c(sc, val, data);			\
156192873Sweongyo	if (error != 0)						\
157192873Sweongyo		goto fail;					\
158192873Sweongyo} while (0)
159192873Sweongyo#define urtw_8187_write_phy_ofdm(sc, val, data)	do {		\
160192873Sweongyo	error = urtw_8187_write_phy_ofdm_c(sc, val, data);	\
161192873Sweongyo	if (error != 0)						\
162192873Sweongyo		goto fail;					\
163192873Sweongyo} while (0)
164192873Sweongyo#define urtw_8187_write_phy_cck(sc, val, data)	do {		\
165192873Sweongyo	error = urtw_8187_write_phy_cck_c(sc, val, data);	\
166192873Sweongyo	if (error != 0)						\
167192873Sweongyo		goto fail;					\
168192873Sweongyo} while (0)
169192873Sweongyo#define urtw_8225_write(sc, val, data)	do {			\
170192873Sweongyo	error = urtw_8225_write_c(sc, val, data);		\
171192873Sweongyo	if (error != 0)						\
172192873Sweongyo		goto fail;					\
173192873Sweongyo} while (0)
174192873Sweongyo
175192873Sweongyostruct urtw_pair {
176192873Sweongyo	uint32_t	reg;
177192873Sweongyo	uint32_t	val;
178192873Sweongyo};
179192873Sweongyo
180192873Sweongyostatic uint8_t urtw_8225_agc[] = {
181192873Sweongyo	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
182192873Sweongyo	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
183192873Sweongyo	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
184192873Sweongyo	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
185192873Sweongyo	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
186192873Sweongyo	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
187192873Sweongyo	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
188192873Sweongyo	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
189192873Sweongyo	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
190192873Sweongyo	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
191192873Sweongyo	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
192192873Sweongyo	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
193192873Sweongyo};
194192873Sweongyo
195196970Sphkstatic uint8_t urtw_8225z2_agc[] = {
196196970Sphk	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51,
197196970Sphk	0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b,
198196970Sphk	0x39, 0x37, 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25,
199196970Sphk	0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f,
200196970Sphk	0x0d, 0x0b, 0x09, 0x07, 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
201196970Sphk	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x19,
202196970Sphk	0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x20, 0x21, 0x22, 0x23,
203196970Sphk	0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
204196970Sphk	0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
205196970Sphk	0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31,
206196970Sphk	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
207196970Sphk	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
208196970Sphk};
209196970Sphk
210192873Sweongyostatic uint32_t urtw_8225_channel[] = {
211192873Sweongyo	0x0000,		/* dummy channel 0  */
212192873Sweongyo	0x085c,		/* 1  */
213192873Sweongyo	0x08dc,		/* 2  */
214192873Sweongyo	0x095c,		/* 3  */
215192873Sweongyo	0x09dc,		/* 4  */
216192873Sweongyo	0x0a5c,		/* 5  */
217192873Sweongyo	0x0adc,		/* 6  */
218192873Sweongyo	0x0b5c,		/* 7  */
219192873Sweongyo	0x0bdc,		/* 8  */
220192873Sweongyo	0x0c5c,		/* 9  */
221192873Sweongyo	0x0cdc,		/* 10  */
222192873Sweongyo	0x0d5c,		/* 11  */
223192873Sweongyo	0x0ddc,		/* 12  */
224192873Sweongyo	0x0e5c,		/* 13  */
225192873Sweongyo	0x0f72,		/* 14  */
226192873Sweongyo};
227192873Sweongyo
228192873Sweongyostatic uint8_t urtw_8225_gain[] = {
229192873Sweongyo	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm  */
230192873Sweongyo	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm  */
231192873Sweongyo	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm  */
232192873Sweongyo	0x33, 0x80, 0x79, 0xc5,		/* -78dbm  */
233192873Sweongyo	0x43, 0x78, 0x76, 0xc5,		/* -74dbm  */
234192873Sweongyo	0x53, 0x60, 0x73, 0xc5,		/* -70dbm  */
235192873Sweongyo	0x63, 0x58, 0x70, 0xc5,		/* -66dbm  */
236192873Sweongyo};
237192873Sweongyo
238192873Sweongyostatic struct urtw_pair urtw_8225_rf_part1[] = {
239192873Sweongyo	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
240192873Sweongyo	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
241192873Sweongyo	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
242196970Sphk	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
243192873Sweongyo};
244192873Sweongyo
245192873Sweongyostatic struct urtw_pair urtw_8225_rf_part2[] = {
246192873Sweongyo	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
247192873Sweongyo	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
248192873Sweongyo	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
249192873Sweongyo	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
250192873Sweongyo	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
251192873Sweongyo	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
252192873Sweongyo	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
253192873Sweongyo	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
254192873Sweongyo	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
255192873Sweongyo	{ 0x27, 0x88 }
256192873Sweongyo};
257192873Sweongyo
258192873Sweongyostatic struct urtw_pair urtw_8225_rf_part3[] = {
259192873Sweongyo	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
260192873Sweongyo	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
261192873Sweongyo	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
262192873Sweongyo	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
263192873Sweongyo	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
264192873Sweongyo	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
265192873Sweongyo	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
266192873Sweongyo};
267192873Sweongyo
268192873Sweongyostatic uint16_t urtw_8225_rxgain[] = {
269192873Sweongyo	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
270192873Sweongyo	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
271192873Sweongyo	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
272192873Sweongyo	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
273192873Sweongyo	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
274192873Sweongyo	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
275192873Sweongyo	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
276192873Sweongyo	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
277192873Sweongyo	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
278192873Sweongyo	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
279192873Sweongyo	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
280192873Sweongyo	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
281192873Sweongyo};
282192873Sweongyo
283192873Sweongyostatic uint8_t urtw_8225_threshold[] = {
284196970Sphk	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
285192873Sweongyo};
286192873Sweongyo
287192873Sweongyostatic uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
288192873Sweongyo	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
289192873Sweongyo};
290192873Sweongyo
291192873Sweongyostatic uint8_t urtw_8225_txpwr_cck[] = {
292192873Sweongyo	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
293192873Sweongyo	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
294192873Sweongyo	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
295192873Sweongyo	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
296192873Sweongyo	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
297192873Sweongyo	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
298192873Sweongyo};
299192873Sweongyo
300192873Sweongyostatic uint8_t urtw_8225_txpwr_cck_ch14[] = {
301192873Sweongyo	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
302192873Sweongyo	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
303192873Sweongyo	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
304192873Sweongyo	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
305192873Sweongyo	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
306192873Sweongyo	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
307192873Sweongyo};
308192873Sweongyo
309196970Sphkstatic uint8_t urtw_8225_txpwr_ofdm[]={
310192873Sweongyo	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
311192873Sweongyo};
312192873Sweongyo
313192873Sweongyostatic uint8_t urtw_8225v2_gain_bg[]={
314192873Sweongyo	0x23, 0x15, 0xa5,		/* -82-1dbm  */
315192873Sweongyo	0x23, 0x15, 0xb5,		/* -82-2dbm  */
316192873Sweongyo	0x23, 0x15, 0xc5,		/* -82-3dbm  */
317192873Sweongyo	0x33, 0x15, 0xc5,		/* -78dbm  */
318192873Sweongyo	0x43, 0x15, 0xc5,		/* -74dbm  */
319192873Sweongyo	0x53, 0x15, 0xc5,		/* -70dbm  */
320192873Sweongyo	0x63, 0x15, 0xc5,		/* -66dbm  */
321192873Sweongyo};
322192873Sweongyo
323192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part1[] = {
324192873Sweongyo	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
325192873Sweongyo	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
326192873Sweongyo	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
327192873Sweongyo	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
328192873Sweongyo};
329192873Sweongyo
330198194Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part0[] = {
331192873Sweongyo	{ 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
332192873Sweongyo	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
333192873Sweongyo	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
334192873Sweongyo	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
335192873Sweongyo};
336192873Sweongyo
337198194Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part1[] = {
338198194Sweongyo	{0x0f0, 0x32}, {0x0f1, 0x32}, {0x0f2, 0x00},
339198194Sweongyo	{0x0f3, 0x00}, {0x0f4, 0x32}, {0x0f5, 0x43},
340198194Sweongyo	{0x0f6, 0x00}, {0x0f7, 0x00}, {0x0f8, 0x46},
341198194Sweongyo	{0x0f9, 0xa4}, {0x0fa, 0x00}, {0x0fb, 0x00},
342198194Sweongyo	{0x0fc, 0x96}, {0x0fd, 0xa4}, {0x0fe, 0x00},
343198194Sweongyo	{0x0ff, 0x00}, {0x158, 0x4b}, {0x159, 0x00},
344198194Sweongyo	{0x15a, 0x4b}, {0x15b, 0x00}, {0x160, 0x4b},
345198194Sweongyo	{0x161, 0x09}, {0x162, 0x4b}, {0x163, 0x09},
346198194Sweongyo	{0x1ce, 0x0f}, {0x1cf, 0x00}, {0x1e0, 0xff},
347198194Sweongyo	{0x1e1, 0x0f}, {0x1e2, 0x00}, {0x1f0, 0x4e},
348198194Sweongyo	{0x1f1, 0x01}, {0x1f2, 0x02}, {0x1f3, 0x03},
349198194Sweongyo	{0x1f4, 0x04}, {0x1f5, 0x05}, {0x1f6, 0x06},
350198194Sweongyo	{0x1f7, 0x07}, {0x1f8, 0x08}, {0x24e, 0x00},
351198194Sweongyo	{0x20c, 0x04}, {0x221, 0x61}, {0x222, 0x68},
352198194Sweongyo	{0x223, 0x6f}, {0x224, 0x76}, {0x225, 0x7d},
353198194Sweongyo	{0x226, 0x84}, {0x227, 0x8d}, {0x24d, 0x08},
354198194Sweongyo	{0x250, 0x05}, {0x251, 0xf5}, {0x252, 0x04},
355198194Sweongyo	{0x253, 0xa0}, {0x254, 0x1f}, {0x255, 0x23},
356198194Sweongyo	{0x256, 0x45}, {0x257, 0x67}, {0x258, 0x08},
357198194Sweongyo	{0x259, 0x08}, {0x25a, 0x08}, {0x25b, 0x08},
358198194Sweongyo	{0x260, 0x08}, {0x261, 0x08}, {0x262, 0x08},
359198194Sweongyo	{0x263, 0x08}, {0x264, 0xcf}, {0x272, 0x56},
360198194Sweongyo	{0x273, 0x9a}, {0x034, 0xf0}, {0x035, 0x0f},
361198194Sweongyo	{0x05b, 0x40}, {0x084, 0x88}, {0x085, 0x24},
362198194Sweongyo	{0x088, 0x54}, {0x08b, 0xb8}, {0x08c, 0x07},
363198194Sweongyo	{0x08d, 0x00}, {0x094, 0x1b}, {0x095, 0x12},
364198194Sweongyo	{0x096, 0x00}, {0x097, 0x06}, {0x09d, 0x1a},
365198194Sweongyo	{0x09f, 0x10}, {0x0b4, 0x22}, {0x0be, 0x80},
366198194Sweongyo	{0x0db, 0x00}, {0x0ee, 0x00}, {0x091, 0x03},
367198194Sweongyo	{0x24c, 0x00}, {0x39f, 0x00}, {0x08c, 0x01},
368198194Sweongyo	{0x08d, 0x10}, {0x08e, 0x08}, {0x08f, 0x00}
369198194Sweongyo};
370198194Sweongyo
371192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part2[] = {
372192873Sweongyo	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
373192873Sweongyo	{ 0x04, 0x00 },	{ 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
374192873Sweongyo	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
375192873Sweongyo	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
376192873Sweongyo	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
377192873Sweongyo	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
378192873Sweongyo	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
379192873Sweongyo	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
380192873Sweongyo	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
381192873Sweongyo	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
382192873Sweongyo};
383192873Sweongyo
384192873Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part2[] = {
385192873Sweongyo	{ 0x00, 0x10 }, { 0x01, 0x0d }, { 0x02, 0x01 }, { 0x03, 0x00 },
386192873Sweongyo	{ 0x04, 0x14 }, { 0x05, 0xfb }, { 0x06, 0xfb }, { 0x07, 0x60 },
387192873Sweongyo	{ 0x08, 0x00 }, { 0x09, 0x60 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
388192873Sweongyo	{ 0x0c, 0x00 }, { 0x0d, 0x5c }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
389192873Sweongyo	{ 0x10, 0x40 }, { 0x11, 0x00 }, { 0x12, 0x40 }, { 0x13, 0x00 },
390192873Sweongyo	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0xa8 }, { 0x17, 0x26 },
391192873Sweongyo	{ 0x18, 0x32 }, { 0x19, 0x33 }, { 0x1a, 0x07 }, { 0x1b, 0xa5 },
392192873Sweongyo	{ 0x1c, 0x6f }, { 0x1d, 0x55 }, { 0x1e, 0xc8 }, { 0x1f, 0xb3 },
393192873Sweongyo	{ 0x20, 0x0a }, { 0x21, 0xe1 }, { 0x22, 0x2C }, { 0x23, 0x8a },
394192873Sweongyo	{ 0x24, 0x86 }, { 0x25, 0x83 }, { 0x26, 0x34 }, { 0x27, 0x0f },
395192873Sweongyo	{ 0x28, 0x4f }, { 0x29, 0x24 }, { 0x2a, 0x6f }, { 0x2b, 0xc2 },
396192873Sweongyo	{ 0x2c, 0x6b }, { 0x2d, 0x40 }, { 0x2e, 0x80 }, { 0x2f, 0x00 },
397192873Sweongyo	{ 0x30, 0xc0 }, { 0x31, 0xc1 }, { 0x32, 0x58 }, { 0x33, 0xf1 },
398192873Sweongyo	{ 0x34, 0x00 }, { 0x35, 0xe4 }, { 0x36, 0x90 }, { 0x37, 0x3e },
399192873Sweongyo	{ 0x38, 0x6d }, { 0x39, 0x3c }, { 0x3a, 0xfb }, { 0x3b, 0x07 }
400192873Sweongyo};
401192873Sweongyo
402192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part3[] = {
403192873Sweongyo	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
404192873Sweongyo	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
405192873Sweongyo	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
406192873Sweongyo	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
407192873Sweongyo	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
408192873Sweongyo	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
409192873Sweongyo	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
410192873Sweongyo	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
411192873Sweongyo};
412192873Sweongyo
413192873Sweongyostatic uint16_t urtw_8225v2_rxgain[] = {
414192873Sweongyo	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
415192873Sweongyo	0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
416192873Sweongyo	0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
417192873Sweongyo	0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
418192873Sweongyo	0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
419192873Sweongyo	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
420192873Sweongyo	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
421192873Sweongyo	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
422192873Sweongyo	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
423192873Sweongyo	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
424192873Sweongyo	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
425192873Sweongyo	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
426192873Sweongyo};
427192873Sweongyo
428192873Sweongyostatic uint16_t urtw_8225v2b_rxgain[] = {
429192873Sweongyo	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
430192873Sweongyo	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
431192873Sweongyo	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
432192873Sweongyo	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
433192873Sweongyo	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
434192873Sweongyo	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
435192873Sweongyo	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
436192873Sweongyo	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
437192873Sweongyo	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
438192873Sweongyo	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
439192873Sweongyo	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
440192873Sweongyo	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
441192873Sweongyo};
442192873Sweongyo
443192873Sweongyostatic uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
444192873Sweongyo	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
445192873Sweongyo	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
446192873Sweongyo	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
447192873Sweongyo	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
448192873Sweongyo	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
449196970Sphk	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
450192873Sweongyo};
451192873Sweongyo
452196970Sphkstatic uint8_t urtw_8225v2_txpwr_cck[] = {
453196970Sphk	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
454196970Sphk};
455196970Sphk
456192873Sweongyostatic uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
457192873Sweongyo	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
458192873Sweongyo};
459192873Sweongyo
460192873Sweongyostatic uint8_t urtw_8225v2b_txpwr_cck[] = {
461192873Sweongyo	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
462192873Sweongyo	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
463192873Sweongyo	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
464192873Sweongyo	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
465192873Sweongyo};
466192873Sweongyo
467192873Sweongyostatic uint8_t urtw_8225v2b_txpwr_cck_ch14[] = {
468192873Sweongyo	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
469192873Sweongyo	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
470192873Sweongyo	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
471192873Sweongyo	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
472192873Sweongyo};
473192873Sweongyo
474192873Sweongyostatic struct urtw_pair urtw_ratetable[] = {
475192873Sweongyo	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
476192873Sweongyo	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
477192873Sweongyo	{ 96, 10 }, { 108, 11 }
478192873Sweongyo};
479192873Sweongyo
480260284Sdim#if 0
481196970Sphkstatic const uint8_t urtw_8187b_reg_table[][3] = {
482196970Sphk	{ 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
483196970Sphk	{ 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
484196970Sphk	{ 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
485196970Sphk	{ 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
486196970Sphk	{ 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
487196970Sphk	{ 0xff, 0x00, 0 }, { 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 },
488196970Sphk	{ 0x5a, 0x4b, 1 }, { 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 },
489196970Sphk	{ 0x61, 0x09, 1 }, { 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 },
490196970Sphk	{ 0xce, 0x0f, 1 }, { 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 },
491196970Sphk	{ 0xe1, 0x0f, 1 }, { 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 },
492196970Sphk	{ 0xf1, 0x01, 1 }, { 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 },
493196970Sphk	{ 0xf4, 0x04, 1 }, { 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 },
494196970Sphk	{ 0xf7, 0x07, 1 }, { 0xf8, 0x08, 1 }, { 0x4e, 0x00, 2 },
495196970Sphk	{ 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 }, { 0x22, 0x68, 2 },
496196970Sphk	{ 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 }, { 0x25, 0x7d, 2 },
497196970Sphk	{ 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 }, { 0x4d, 0x08, 2 },
498196970Sphk	{ 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 }, { 0x52, 0x04, 2 },
499196970Sphk	{ 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 }, { 0x55, 0x23, 2 },
500196970Sphk	{ 0x56, 0x45, 2 }, { 0x57, 0x67, 2 }, { 0x58, 0x08, 2 },
501196970Sphk	{ 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 }, { 0x5b, 0x08, 2 },
502196970Sphk	{ 0x60, 0x08, 2 }, { 0x61, 0x08, 2 }, { 0x62, 0x08, 2 },
503196970Sphk	{ 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 }, { 0x72, 0x56, 2 },
504196970Sphk	{ 0x73, 0x9a, 2 }, { 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 },
505196970Sphk	{ 0x5b, 0x40, 0 }, { 0x84, 0x88, 0 }, { 0x85, 0x24, 0 },
506196970Sphk	{ 0x88, 0x54, 0 }, { 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 },
507196970Sphk	{ 0x8d, 0x00, 0 }, { 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 },
508196970Sphk	{ 0x96, 0x00, 0 }, { 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 },
509196970Sphk	{ 0x9f, 0x10, 0 }, { 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 },
510196970Sphk	{ 0xdb, 0x00, 0 }, { 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
511196970Sphk	{ 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
512196970Sphk	{ 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
513196970Sphk};
514260284Sdim#endif
515196970Sphk
516193045Sthompsastatic usb_callback_t urtw_bulk_rx_callback;
517193045Sthompsastatic usb_callback_t urtw_bulk_tx_callback;
518198194Sweongyostatic usb_callback_t urtw_bulk_tx_status_callback;
519192873Sweongyo
520192984Sthompsastatic const struct usb_config urtw_8187b_usbconfig[URTW_8187B_N_XFERS] = {
521192873Sweongyo	[URTW_8187B_BULK_RX] = {
522192873Sweongyo		.type = UE_BULK,
523192873Sweongyo		.endpoint = 0x83,
524192873Sweongyo		.direction = UE_DIR_IN,
525192873Sweongyo		.bufsize = MCLBYTES,
526192873Sweongyo		.flags = {
527192873Sweongyo			.ext_buffer = 1,
528192873Sweongyo			.pipe_bof = 1,
529192873Sweongyo			.short_xfer_ok = 1
530192873Sweongyo		},
531192873Sweongyo		.callback = urtw_bulk_rx_callback
532192873Sweongyo	},
533198194Sweongyo	[URTW_8187B_BULK_TX_STATUS] = {
534198194Sweongyo		.type = UE_BULK,
535198194Sweongyo		.endpoint = 0x89,
536198194Sweongyo		.direction = UE_DIR_IN,
537259454Shselasky		.bufsize = sizeof(uint64_t),
538198194Sweongyo		.flags = {
539198194Sweongyo			.pipe_bof = 1,
540198194Sweongyo			.short_xfer_ok = 1
541198194Sweongyo		},
542198194Sweongyo		.callback = urtw_bulk_tx_status_callback
543198194Sweongyo	},
544192873Sweongyo	[URTW_8187B_BULK_TX_BE] = {
545192873Sweongyo		.type = UE_BULK,
546192873Sweongyo		.endpoint = URTW_8187B_TXPIPE_BE,
547192873Sweongyo		.direction = UE_DIR_OUT,
548259454Shselasky		.bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT,
549192873Sweongyo		.flags = {
550192873Sweongyo			.force_short_xfer = 1,
551192873Sweongyo			.pipe_bof = 1,
552192873Sweongyo		},
553192873Sweongyo		.callback = urtw_bulk_tx_callback,
554192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
555192873Sweongyo	},
556192873Sweongyo	[URTW_8187B_BULK_TX_BK] = {
557192873Sweongyo		.type = UE_BULK,
558192873Sweongyo		.endpoint = URTW_8187B_TXPIPE_BK,
559192873Sweongyo		.direction = UE_DIR_OUT,
560192873Sweongyo		.bufsize = URTW_TX_MAXSIZE,
561192873Sweongyo		.flags = {
562192873Sweongyo			.ext_buffer = 1,
563192873Sweongyo			.force_short_xfer = 1,
564192873Sweongyo			.pipe_bof = 1,
565192873Sweongyo		},
566192873Sweongyo		.callback = urtw_bulk_tx_callback,
567192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
568192873Sweongyo	},
569192873Sweongyo	[URTW_8187B_BULK_TX_VI] = {
570192873Sweongyo		.type = UE_BULK,
571192873Sweongyo		.endpoint = URTW_8187B_TXPIPE_VI,
572192873Sweongyo		.direction = UE_DIR_OUT,
573192873Sweongyo		.bufsize = URTW_TX_MAXSIZE,
574192873Sweongyo		.flags = {
575192873Sweongyo			.ext_buffer = 1,
576192873Sweongyo			.force_short_xfer = 1,
577192873Sweongyo			.pipe_bof = 1,
578192873Sweongyo		},
579192873Sweongyo		.callback = urtw_bulk_tx_callback,
580192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
581192873Sweongyo	},
582192873Sweongyo	[URTW_8187B_BULK_TX_VO] = {
583192873Sweongyo		.type = UE_BULK,
584192873Sweongyo		.endpoint = URTW_8187B_TXPIPE_VO,
585192873Sweongyo		.direction = UE_DIR_OUT,
586192873Sweongyo		.bufsize = URTW_TX_MAXSIZE,
587192873Sweongyo		.flags = {
588192873Sweongyo			.ext_buffer = 1,
589192873Sweongyo			.force_short_xfer = 1,
590192873Sweongyo			.pipe_bof = 1,
591192873Sweongyo		},
592192873Sweongyo		.callback = urtw_bulk_tx_callback,
593192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
594192873Sweongyo	},
595192873Sweongyo	[URTW_8187B_BULK_TX_EP12] = {
596192873Sweongyo		.type = UE_BULK,
597192873Sweongyo		.endpoint = 0xc,
598192873Sweongyo		.direction = UE_DIR_OUT,
599192873Sweongyo		.bufsize = URTW_TX_MAXSIZE,
600192873Sweongyo		.flags = {
601192873Sweongyo			.ext_buffer = 1,
602192873Sweongyo			.force_short_xfer = 1,
603192873Sweongyo			.pipe_bof = 1,
604192873Sweongyo		},
605192873Sweongyo		.callback = urtw_bulk_tx_callback,
606192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
607192873Sweongyo	}
608192873Sweongyo};
609192873Sweongyo
610192984Sthompsastatic const struct usb_config urtw_8187l_usbconfig[URTW_8187L_N_XFERS] = {
611192873Sweongyo	[URTW_8187L_BULK_RX] = {
612192873Sweongyo		.type = UE_BULK,
613192873Sweongyo		.endpoint = 0x81,
614192873Sweongyo		.direction = UE_DIR_IN,
615192873Sweongyo		.bufsize = MCLBYTES,
616192873Sweongyo		.flags = {
617192873Sweongyo			.ext_buffer = 1,
618192873Sweongyo			.pipe_bof = 1,
619192873Sweongyo			.short_xfer_ok = 1
620192873Sweongyo		},
621192873Sweongyo		.callback = urtw_bulk_rx_callback
622192873Sweongyo	},
623192873Sweongyo	[URTW_8187L_BULK_TX_LOW] = {
624192873Sweongyo		.type = UE_BULK,
625192873Sweongyo		.endpoint = 0x2,
626192873Sweongyo		.direction = UE_DIR_OUT,
627259454Shselasky		.bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT,
628192873Sweongyo		.flags = {
629192873Sweongyo			.force_short_xfer = 1,
630192873Sweongyo			.pipe_bof = 1,
631192873Sweongyo		},
632192873Sweongyo		.callback = urtw_bulk_tx_callback,
633192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
634192873Sweongyo	},
635192873Sweongyo	[URTW_8187L_BULK_TX_NORMAL] = {
636192873Sweongyo		.type = UE_BULK,
637192873Sweongyo		.endpoint = 0x3,
638192873Sweongyo		.direction = UE_DIR_OUT,
639192873Sweongyo		.bufsize = URTW_TX_MAXSIZE,
640192873Sweongyo		.flags = {
641192873Sweongyo			.ext_buffer = 1,
642192873Sweongyo			.force_short_xfer = 1,
643192873Sweongyo			.pipe_bof = 1,
644192873Sweongyo		},
645192873Sweongyo		.callback = urtw_bulk_tx_callback,
646192873Sweongyo		.timeout = URTW_DATA_TIMEOUT
647192873Sweongyo	},
648192873Sweongyo};
649192873Sweongyo
650192873Sweongyostatic struct ieee80211vap *urtw_vap_create(struct ieee80211com *,
651234753Sdim			    const char [IFNAMSIZ], int, enum ieee80211_opmode,
652234753Sdim			    int, const uint8_t [IEEE80211_ADDR_LEN],
653234753Sdim			    const uint8_t [IEEE80211_ADDR_LEN]);
654192873Sweongyostatic void		urtw_vap_delete(struct ieee80211vap *);
655192873Sweongyostatic void		urtw_init(void *);
656259456Shselaskystatic void		urtw_stop(struct ifnet *);
657259456Shselaskystatic void		urtw_stop_locked(struct ifnet *);
658192873Sweongyostatic int		urtw_ioctl(struct ifnet *, u_long, caddr_t);
659192873Sweongyostatic void		urtw_start(struct ifnet *);
660192873Sweongyostatic int		urtw_alloc_rx_data_list(struct urtw_softc *);
661192873Sweongyostatic int		urtw_alloc_tx_data_list(struct urtw_softc *);
662192873Sweongyostatic int		urtw_raw_xmit(struct ieee80211_node *, struct mbuf *,
663192873Sweongyo			    const struct ieee80211_bpf_params *);
664192873Sweongyostatic void		urtw_scan_start(struct ieee80211com *);
665192873Sweongyostatic void		urtw_scan_end(struct ieee80211com *);
666192873Sweongyostatic void		urtw_set_channel(struct ieee80211com *);
667192873Sweongyostatic void		urtw_update_mcast(struct ifnet *);
668192873Sweongyostatic int		urtw_tx_start(struct urtw_softc *,
669192873Sweongyo			    struct ieee80211_node *, struct mbuf *,
670192873Sweongyo			    struct urtw_data *, int);
671192873Sweongyostatic int		urtw_newstate(struct ieee80211vap *,
672192873Sweongyo			    enum ieee80211_state, int);
673192873Sweongyostatic void		urtw_led_ch(void *);
674192873Sweongyostatic void		urtw_ledtask(void *, int);
675192873Sweongyostatic void		urtw_watchdog(void *);
676192873Sweongyostatic void		urtw_set_multi(void *);
677192873Sweongyostatic int		urtw_isbmode(uint16_t);
678235000Shselaskystatic uint16_t		urtw_rate2rtl(uint32_t);
679235000Shselaskystatic uint16_t		urtw_rtl2rate(uint32_t);
680193045Sthompsastatic usb_error_t	urtw_set_rate(struct urtw_softc *);
681193045Sthompsastatic usb_error_t	urtw_update_msr(struct urtw_softc *);
682193045Sthompsastatic usb_error_t	urtw_read8_c(struct urtw_softc *, int, uint8_t *);
683193045Sthompsastatic usb_error_t	urtw_read16_c(struct urtw_softc *, int, uint16_t *);
684193045Sthompsastatic usb_error_t	urtw_read32_c(struct urtw_softc *, int, uint32_t *);
685193045Sthompsastatic usb_error_t	urtw_write8_c(struct urtw_softc *, int, uint8_t);
686193045Sthompsastatic usb_error_t	urtw_write16_c(struct urtw_softc *, int, uint16_t);
687193045Sthompsastatic usb_error_t	urtw_write32_c(struct urtw_softc *, int, uint32_t);
688193045Sthompsastatic usb_error_t	urtw_eprom_cs(struct urtw_softc *, int);
689193045Sthompsastatic usb_error_t	urtw_eprom_ck(struct urtw_softc *);
690193045Sthompsastatic usb_error_t	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
691192873Sweongyo			    int);
692193045Sthompsastatic usb_error_t	urtw_eprom_read32(struct urtw_softc *, uint32_t,
693192873Sweongyo			    uint32_t *);
694193045Sthompsastatic usb_error_t	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
695193045Sthompsastatic usb_error_t	urtw_eprom_writebit(struct urtw_softc *, int16_t);
696193045Sthompsastatic usb_error_t	urtw_get_macaddr(struct urtw_softc *);
697193045Sthompsastatic usb_error_t	urtw_get_txpwr(struct urtw_softc *);
698193045Sthompsastatic usb_error_t	urtw_get_rfchip(struct urtw_softc *);
699193045Sthompsastatic usb_error_t	urtw_led_init(struct urtw_softc *);
700193045Sthompsastatic usb_error_t	urtw_8185_rf_pins_enable(struct urtw_softc *);
701193045Sthompsastatic usb_error_t	urtw_8185_tx_antenna(struct urtw_softc *, uint8_t);
702193045Sthompsastatic usb_error_t	urtw_8187_write_phy(struct urtw_softc *, uint8_t,
703192873Sweongyo			    uint32_t);
704193045Sthompsastatic usb_error_t	urtw_8187_write_phy_ofdm_c(struct urtw_softc *,
705192873Sweongyo			    uint8_t, uint32_t);
706193045Sthompsastatic usb_error_t	urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t,
707192873Sweongyo			    uint32_t);
708193045Sthompsastatic usb_error_t	urtw_8225_setgain(struct urtw_softc *, int16_t);
709193045Sthompsastatic usb_error_t	urtw_8225_usb_init(struct urtw_softc *);
710193045Sthompsastatic usb_error_t	urtw_8225_write_c(struct urtw_softc *, uint8_t,
711192873Sweongyo			    uint16_t);
712193045Sthompsastatic usb_error_t	urtw_8225_write_s16(struct urtw_softc *, uint8_t, int,
713192873Sweongyo			    uint16_t *);
714193045Sthompsastatic usb_error_t	urtw_8225_read(struct urtw_softc *, uint8_t,
715192873Sweongyo			    uint32_t *);
716193045Sthompsastatic usb_error_t	urtw_8225_rf_init(struct urtw_softc *);
717193045Sthompsastatic usb_error_t	urtw_8225_rf_set_chan(struct urtw_softc *, int);
718193045Sthompsastatic usb_error_t	urtw_8225_rf_set_sens(struct urtw_softc *, int);
719193045Sthompsastatic usb_error_t	urtw_8225_set_txpwrlvl(struct urtw_softc *, int);
720193045Sthompsastatic usb_error_t	urtw_8225_rf_stop(struct urtw_softc *);
721193045Sthompsastatic usb_error_t	urtw_8225v2_rf_init(struct urtw_softc *);
722193045Sthompsastatic usb_error_t	urtw_8225v2_rf_set_chan(struct urtw_softc *, int);
723193045Sthompsastatic usb_error_t	urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int);
724193045Sthompsastatic usb_error_t	urtw_8225v2_setgain(struct urtw_softc *, int16_t);
725193045Sthompsastatic usb_error_t	urtw_8225_isv2(struct urtw_softc *, int *);
726193045Sthompsastatic usb_error_t	urtw_8225v2b_rf_init(struct urtw_softc *);
727193045Sthompsastatic usb_error_t	urtw_8225v2b_rf_set_chan(struct urtw_softc *, int);
728193045Sthompsastatic usb_error_t	urtw_read8e(struct urtw_softc *, int, uint8_t *);
729193045Sthompsastatic usb_error_t	urtw_write8e(struct urtw_softc *, int, uint8_t);
730193045Sthompsastatic usb_error_t	urtw_8180_set_anaparam(struct urtw_softc *, uint32_t);
731193045Sthompsastatic usb_error_t	urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t);
732193045Sthompsastatic usb_error_t	urtw_intr_enable(struct urtw_softc *);
733193045Sthompsastatic usb_error_t	urtw_intr_disable(struct urtw_softc *);
734193045Sthompsastatic usb_error_t	urtw_reset(struct urtw_softc *);
735193045Sthompsastatic usb_error_t	urtw_led_on(struct urtw_softc *, int);
736193045Sthompsastatic usb_error_t	urtw_led_ctl(struct urtw_softc *, int);
737193045Sthompsastatic usb_error_t	urtw_led_blink(struct urtw_softc *);
738193045Sthompsastatic usb_error_t	urtw_led_mode0(struct urtw_softc *, int);
739193045Sthompsastatic usb_error_t	urtw_led_mode1(struct urtw_softc *, int);
740193045Sthompsastatic usb_error_t	urtw_led_mode2(struct urtw_softc *, int);
741193045Sthompsastatic usb_error_t	urtw_led_mode3(struct urtw_softc *, int);
742193045Sthompsastatic usb_error_t	urtw_rx_setconf(struct urtw_softc *);
743193045Sthompsastatic usb_error_t	urtw_rx_enable(struct urtw_softc *);
744193045Sthompsastatic usb_error_t	urtw_tx_enable(struct urtw_softc *sc);
745192873Sweongyostatic void		urtw_free_tx_data_list(struct urtw_softc *);
746192873Sweongyostatic void		urtw_free_rx_data_list(struct urtw_softc *);
747192873Sweongyostatic void		urtw_free_data_list(struct urtw_softc *,
748192873Sweongyo			    struct urtw_data data[], int, int);
749193045Sthompsastatic usb_error_t	urtw_adapter_start(struct urtw_softc *);
750193045Sthompsastatic usb_error_t	urtw_adapter_start_b(struct urtw_softc *);
751193045Sthompsastatic usb_error_t	urtw_set_mode(struct urtw_softc *, uint32_t);
752193045Sthompsastatic usb_error_t	urtw_8187b_cmd_reset(struct urtw_softc *);
753193045Sthompsastatic usb_error_t	urtw_do_request(struct urtw_softc *,
754192984Sthompsa			    struct usb_device_request *, void *);
755193045Sthompsastatic usb_error_t	urtw_8225v2b_set_txpwrlvl(struct urtw_softc *, int);
756193045Sthompsastatic usb_error_t	urtw_led_off(struct urtw_softc *, int);
757192873Sweongyostatic void		urtw_abort_xfers(struct urtw_softc *);
758192873Sweongyostatic struct urtw_data *
759192873Sweongyo			urtw_getbuf(struct urtw_softc *sc);
760198194Sweongyostatic int		urtw_compute_txtime(uint16_t, uint16_t, uint8_t,
761198194Sweongyo			    uint8_t);
762198194Sweongyostatic void		urtw_updateslot(struct ifnet *);
763198194Sweongyostatic void		urtw_updateslottask(void *, int);
764203087Sweongyostatic void		urtw_sysctl_node(struct urtw_softc *);
765192873Sweongyo
766192873Sweongyostatic int
767192873Sweongyourtw_match(device_t dev)
768192873Sweongyo{
769192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
770192873Sweongyo
771192873Sweongyo	if (uaa->usb_mode != USB_MODE_HOST)
772192873Sweongyo		return (ENXIO);
773192873Sweongyo	if (uaa->info.bConfigIndex != URTW_CONFIG_INDEX)
774192873Sweongyo		return (ENXIO);
775192873Sweongyo	if (uaa->info.bIfaceIndex != URTW_IFACE_INDEX)
776192873Sweongyo		return (ENXIO);
777192873Sweongyo
778194228Sthompsa	return (usbd_lookup_id_by_uaa(urtw_devs, sizeof(urtw_devs), uaa));
779192873Sweongyo}
780192873Sweongyo
781192873Sweongyostatic int
782192873Sweongyourtw_attach(device_t dev)
783192873Sweongyo{
784192984Sthompsa	const struct usb_config *setup_start;
785192873Sweongyo	int ret = ENXIO;
786192873Sweongyo	struct urtw_softc *sc = device_get_softc(dev);
787192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
788192873Sweongyo	struct ieee80211com *ic;
789192873Sweongyo	struct ifnet *ifp;
790192873Sweongyo	uint8_t bands, iface_index = URTW_IFACE_INDEX;		/* XXX */
791192873Sweongyo	uint16_t n_setup;
792192873Sweongyo	uint32_t data;
793193045Sthompsa	usb_error_t error;
794192873Sweongyo
795194228Sthompsa	device_set_usb_desc(dev);
796192873Sweongyo
797192873Sweongyo	sc->sc_dev = dev;
798192873Sweongyo	sc->sc_udev = uaa->device;
799192873Sweongyo	if (USB_GET_DRIVER_INFO(uaa) == URTW_REV_RTL8187B)
800192873Sweongyo		sc->sc_flags |= URTW_RTL8187B;
801192873Sweongyo#ifdef URTW_DEBUG
802192873Sweongyo	sc->sc_debug = urtw_debug;
803192873Sweongyo#endif
804192873Sweongyo
805192873Sweongyo	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK,
806192873Sweongyo	    MTX_DEF);
807194228Sthompsa	usb_callout_init_mtx(&sc->sc_led_ch, &sc->sc_mtx, 0);
808192873Sweongyo	TASK_INIT(&sc->sc_led_task, 0, urtw_ledtask, sc);
809198194Sweongyo	TASK_INIT(&sc->sc_updateslot_task, 0, urtw_updateslottask, sc);
810192873Sweongyo	callout_init(&sc->sc_watchdog_ch, 0);
811192873Sweongyo
812192873Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
813192873Sweongyo		setup_start = urtw_8187b_usbconfig;
814192873Sweongyo		n_setup = URTW_8187B_N_XFERS;
815192873Sweongyo	} else {
816192873Sweongyo		setup_start = urtw_8187l_usbconfig;
817192873Sweongyo		n_setup = URTW_8187L_N_XFERS;
818192873Sweongyo	}
819192873Sweongyo
820194228Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
821192873Sweongyo	    setup_start, n_setup, sc, &sc->sc_mtx);
822192873Sweongyo	if (error) {
823192873Sweongyo		device_printf(dev, "could not allocate USB transfers, "
824194228Sthompsa		    "err=%s\n", usbd_errstr(error));
825192873Sweongyo		ret = ENXIO;
826192873Sweongyo		goto fail0;
827192873Sweongyo	}
828192873Sweongyo
829259454Shselasky	if (sc->sc_flags & URTW_RTL8187B) {
830259454Shselasky		sc->sc_tx_dma_buf =
831259454Shselasky		    usbd_xfer_get_frame_buffer(sc->sc_xfer[
832259454Shselasky		    URTW_8187B_BULK_TX_BE], 0);
833259454Shselasky	} else {
834259454Shselasky		sc->sc_tx_dma_buf =
835259454Shselasky		    usbd_xfer_get_frame_buffer(sc->sc_xfer[
836259454Shselasky		    URTW_8187L_BULK_TX_LOW], 0);
837259454Shselasky	}
838259454Shselasky
839192873Sweongyo	URTW_LOCK(sc);
840192873Sweongyo
841192873Sweongyo	urtw_read32_m(sc, URTW_RX, &data);
842192873Sweongyo	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
843192873Sweongyo	    URTW_EEPROM_93C46;
844192873Sweongyo
845192873Sweongyo	error = urtw_get_rfchip(sc);
846192873Sweongyo	if (error != 0)
847192873Sweongyo		goto fail;
848192873Sweongyo	error = urtw_get_macaddr(sc);
849192873Sweongyo	if (error != 0)
850192873Sweongyo		goto fail;
851192873Sweongyo	error = urtw_get_txpwr(sc);
852192873Sweongyo	if (error != 0)
853192873Sweongyo		goto fail;
854192873Sweongyo	error = urtw_led_init(sc);
855192873Sweongyo	if (error != 0)
856192873Sweongyo		goto fail;
857192873Sweongyo
858192873Sweongyo	URTW_UNLOCK(sc);
859192873Sweongyo
860192873Sweongyo	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
861192873Sweongyo	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
862192873Sweongyo	sc->sc_currate = 3;
863192873Sweongyo	sc->sc_preamble_mode = urtw_preamble_mode;
864192873Sweongyo
865192873Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
866192873Sweongyo	if (ifp == NULL) {
867192873Sweongyo		device_printf(sc->sc_dev, "can not allocate ifnet\n");
868192873Sweongyo		ret = ENOMEM;
869192873Sweongyo		goto fail1;
870192873Sweongyo	}
871192873Sweongyo
872192873Sweongyo	ifp->if_softc = sc;
873192873Sweongyo	if_initname(ifp, "urtw", device_get_unit(sc->sc_dev));
874192873Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
875192873Sweongyo	ifp->if_init = urtw_init;
876192873Sweongyo	ifp->if_ioctl = urtw_ioctl;
877192873Sweongyo	ifp->if_start = urtw_start;
878192873Sweongyo	/* XXX URTW_TX_DATA_LIST_COUNT */
879207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
880207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
881192873Sweongyo	IFQ_SET_READY(&ifp->if_snd);
882192873Sweongyo
883192873Sweongyo	ic = ifp->if_l2com;
884192873Sweongyo	ic->ic_ifp = ifp;
885192873Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
886192873Sweongyo	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
887192873Sweongyo
888192873Sweongyo	/* set device capabilities */
889192873Sweongyo	ic->ic_caps =
890192873Sweongyo	    IEEE80211_C_STA |		/* station mode */
891192873Sweongyo	    IEEE80211_C_MONITOR |	/* monitor mode supported */
892192873Sweongyo	    IEEE80211_C_TXPMGT |	/* tx power management */
893192873Sweongyo	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
894192873Sweongyo	    IEEE80211_C_SHSLOT |	/* short slot time supported */
895192873Sweongyo	    IEEE80211_C_BGSCAN |	/* capable of bg scanning */
896192873Sweongyo	    IEEE80211_C_WPA;		/* 802.11i */
897192873Sweongyo
898192873Sweongyo	bands = 0;
899192873Sweongyo	setbit(&bands, IEEE80211_MODE_11B);
900192873Sweongyo	setbit(&bands, IEEE80211_MODE_11G);
901192873Sweongyo	ieee80211_init_channels(ic, NULL, &bands);
902192873Sweongyo
903192873Sweongyo	ieee80211_ifattach(ic, sc->sc_bssid);
904192873Sweongyo	ic->ic_raw_xmit = urtw_raw_xmit;
905192873Sweongyo	ic->ic_scan_start = urtw_scan_start;
906192873Sweongyo	ic->ic_scan_end = urtw_scan_end;
907192873Sweongyo	ic->ic_set_channel = urtw_set_channel;
908198194Sweongyo	ic->ic_updateslot = urtw_updateslot;
909192873Sweongyo	ic->ic_vap_create = urtw_vap_create;
910192873Sweongyo	ic->ic_vap_delete = urtw_vap_delete;
911192873Sweongyo	ic->ic_update_mcast = urtw_update_mcast;
912192873Sweongyo
913192873Sweongyo	ieee80211_radiotap_attach(ic,
914192873Sweongyo	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
915192873Sweongyo	    URTW_TX_RADIOTAP_PRESENT,
916192873Sweongyo	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
917192873Sweongyo	    URTW_RX_RADIOTAP_PRESENT);
918192873Sweongyo
919203087Sweongyo	urtw_sysctl_node(sc);
920203087Sweongyo
921192873Sweongyo	if (bootverbose)
922192873Sweongyo		ieee80211_announce(ic);
923192873Sweongyo	return (0);
924192873Sweongyo
925192873Sweongyofail:	URTW_UNLOCK(sc);
926194228Sthompsafail1:	usbd_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ?
927192873Sweongyo	    URTW_8187B_N_XFERS : URTW_8187L_N_XFERS);
928192873Sweongyofail0:
929192873Sweongyo	return (ret);
930192873Sweongyo}
931192873Sweongyo
932192873Sweongyostatic int
933192873Sweongyourtw_detach(device_t dev)
934192873Sweongyo{
935192873Sweongyo	struct urtw_softc *sc = device_get_softc(dev);
936192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
937192873Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
938259456Shselasky	unsigned int x;
939259456Shselasky	unsigned int n_xfers;
940192873Sweongyo
941259456Shselasky	/* Prevent further ioctls */
942259456Shselasky	URTW_LOCK(sc);
943259456Shselasky	sc->sc_flags |= URTW_DETACHED;
944259456Shselasky	URTW_UNLOCK(sc);
945192873Sweongyo
946259456Shselasky	urtw_stop(ifp);
947259456Shselasky
948198194Sweongyo	ieee80211_draintask(ic, &sc->sc_updateslot_task);
949192873Sweongyo	ieee80211_draintask(ic, &sc->sc_led_task);
950192873Sweongyo
951194228Sthompsa	usb_callout_drain(&sc->sc_led_ch);
952192873Sweongyo	callout_drain(&sc->sc_watchdog_ch);
953192873Sweongyo
954259456Shselasky	n_xfers = (sc->sc_flags & URTW_RTL8187B) ?
955259456Shselasky	    URTW_8187B_N_XFERS : URTW_8187L_N_XFERS;
956259454Shselasky
957259456Shselasky	/* prevent further allocations from RX/TX data lists */
958259456Shselasky	URTW_LOCK(sc);
959259456Shselasky	STAILQ_INIT(&sc->sc_tx_active);
960259456Shselasky	STAILQ_INIT(&sc->sc_tx_inactive);
961259456Shselasky	STAILQ_INIT(&sc->sc_tx_pending);
962192873Sweongyo
963259456Shselasky	STAILQ_INIT(&sc->sc_rx_active);
964259456Shselasky	STAILQ_INIT(&sc->sc_rx_inactive);
965259456Shselasky	URTW_UNLOCK(sc);
966259456Shselasky
967259456Shselasky	/* drain USB transfers */
968259456Shselasky	for (x = 0; x != n_xfers; x++)
969259456Shselasky		usbd_transfer_drain(sc->sc_xfer[x]);
970259456Shselasky
971259456Shselasky	/* free data buffers */
972259456Shselasky	URTW_LOCK(sc);
973192873Sweongyo	urtw_free_tx_data_list(sc);
974192873Sweongyo	urtw_free_rx_data_list(sc);
975259456Shselasky	URTW_UNLOCK(sc);
976192873Sweongyo
977259456Shselasky	/* free USB transfers and some data buffers */
978259456Shselasky	usbd_transfer_unsetup(sc->sc_xfer, n_xfers);
979259456Shselasky
980259456Shselasky	ieee80211_ifdetach(ic);
981192873Sweongyo	if_free(ifp);
982192873Sweongyo	mtx_destroy(&sc->sc_mtx);
983192873Sweongyo	return (0);
984192873Sweongyo}
985192873Sweongyo
986192873Sweongyostatic void
987192873Sweongyourtw_free_tx_data_list(struct urtw_softc *sc)
988192873Sweongyo{
989192873Sweongyo	urtw_free_data_list(sc, sc->sc_tx, URTW_TX_DATA_LIST_COUNT, 0);
990192873Sweongyo}
991192873Sweongyo
992192873Sweongyostatic void
993192873Sweongyourtw_free_rx_data_list(struct urtw_softc *sc)
994192873Sweongyo{
995192873Sweongyo	urtw_free_data_list(sc, sc->sc_rx, URTW_RX_DATA_LIST_COUNT, 1);
996192873Sweongyo}
997192873Sweongyo
998192873Sweongyostatic void
999192873Sweongyourtw_free_data_list(struct urtw_softc *sc, struct urtw_data data[], int ndata,
1000192873Sweongyo    int fillmbuf)
1001192873Sweongyo{
1002192873Sweongyo	int i;
1003192873Sweongyo
1004192873Sweongyo	for (i = 0; i < ndata; i++) {
1005192873Sweongyo		struct urtw_data *dp = &data[i];
1006192873Sweongyo
1007192873Sweongyo		if (fillmbuf == 1) {
1008192873Sweongyo			if (dp->m != NULL) {
1009192873Sweongyo				m_freem(dp->m);
1010192873Sweongyo				dp->m = NULL;
1011192873Sweongyo				dp->buf = NULL;
1012192873Sweongyo			}
1013192873Sweongyo		} else {
1014259454Shselasky			dp->buf = NULL;
1015192873Sweongyo		}
1016192873Sweongyo		if (dp->ni != NULL) {
1017192873Sweongyo			ieee80211_free_node(dp->ni);
1018192873Sweongyo			dp->ni = NULL;
1019192873Sweongyo		}
1020192873Sweongyo	}
1021192873Sweongyo}
1022192873Sweongyo
1023192873Sweongyostatic struct ieee80211vap *
1024234753Sdimurtw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
1025234753Sdim    enum ieee80211_opmode opmode, int flags,
1026234753Sdim    const uint8_t bssid[IEEE80211_ADDR_LEN],
1027234753Sdim    const uint8_t mac[IEEE80211_ADDR_LEN])
1028192873Sweongyo{
1029192873Sweongyo	struct urtw_vap *uvp;
1030192873Sweongyo	struct ieee80211vap *vap;
1031192873Sweongyo
1032192873Sweongyo	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
1033192873Sweongyo		return (NULL);
1034192873Sweongyo	uvp = (struct urtw_vap *) malloc(sizeof(struct urtw_vap),
1035192873Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
1036192873Sweongyo	if (uvp == NULL)
1037192873Sweongyo		return (NULL);
1038192873Sweongyo	vap = &uvp->vap;
1039192873Sweongyo	/* enable s/w bmiss handling for sta mode */
1040192873Sweongyo
1041259457Shselasky	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
1042259457Shselasky	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) {
1043259457Shselasky		/* out of memory */
1044259457Shselasky		free(uvp, M_80211_VAP);
1045259457Shselasky		return (NULL);
1046259457Shselasky	}
1047259457Shselasky
1048192873Sweongyo	/* override state transition machine */
1049192873Sweongyo	uvp->newstate = vap->iv_newstate;
1050192873Sweongyo	vap->iv_newstate = urtw_newstate;
1051192873Sweongyo
1052192873Sweongyo	/* complete setup */
1053192873Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
1054192873Sweongyo	    ieee80211_media_status);
1055192873Sweongyo	ic->ic_opmode = opmode;
1056192873Sweongyo	return (vap);
1057192873Sweongyo}
1058192873Sweongyo
1059192873Sweongyostatic void
1060192873Sweongyourtw_vap_delete(struct ieee80211vap *vap)
1061192873Sweongyo{
1062192873Sweongyo	struct urtw_vap *uvp = URTW_VAP(vap);
1063192873Sweongyo
1064192873Sweongyo	ieee80211_vap_detach(vap);
1065192873Sweongyo	free(uvp, M_80211_VAP);
1066192873Sweongyo}
1067192873Sweongyo
1068192873Sweongyostatic void
1069192873Sweongyourtw_init_locked(void *arg)
1070192873Sweongyo{
1071192873Sweongyo	int ret;
1072192873Sweongyo	struct urtw_softc *sc = arg;
1073192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1074193045Sthompsa	usb_error_t error;
1075192873Sweongyo
1076192873Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1077259456Shselasky		urtw_stop_locked(ifp);
1078192873Sweongyo
1079192873Sweongyo	error = (sc->sc_flags & URTW_RTL8187B) ? urtw_adapter_start_b(sc) :
1080192873Sweongyo	    urtw_adapter_start(sc);
1081192873Sweongyo	if (error != 0)
1082192873Sweongyo		goto fail;
1083192873Sweongyo
1084192873Sweongyo	/* reset softc variables  */
1085192873Sweongyo	sc->sc_txtimer = 0;
1086192873Sweongyo
1087192873Sweongyo	if (!(sc->sc_flags & URTW_INIT_ONCE)) {
1088192873Sweongyo		ret = urtw_alloc_rx_data_list(sc);
1089229121Shselasky		if (ret != 0)
1090192873Sweongyo			goto fail;
1091192873Sweongyo		ret = urtw_alloc_tx_data_list(sc);
1092229121Shselasky		if (ret != 0)
1093192873Sweongyo			goto fail;
1094192873Sweongyo		sc->sc_flags |= URTW_INIT_ONCE;
1095192873Sweongyo	}
1096192873Sweongyo
1097192873Sweongyo	error = urtw_rx_enable(sc);
1098192873Sweongyo	if (error != 0)
1099192873Sweongyo		goto fail;
1100192873Sweongyo	error = urtw_tx_enable(sc);
1101192873Sweongyo	if (error != 0)
1102192873Sweongyo		goto fail;
1103192873Sweongyo
1104198194Sweongyo	if (sc->sc_flags & URTW_RTL8187B)
1105198194Sweongyo		usbd_transfer_start(sc->sc_xfer[URTW_8187B_BULK_TX_STATUS]);
1106198194Sweongyo
1107192873Sweongyo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1108192873Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1109192873Sweongyo
1110192873Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
1111192873Sweongyofail:
1112192873Sweongyo	return;
1113192873Sweongyo}
1114192873Sweongyo
1115192873Sweongyostatic void
1116192873Sweongyourtw_init(void *arg)
1117192873Sweongyo{
1118192873Sweongyo	struct urtw_softc *sc = arg;
1119192873Sweongyo
1120192873Sweongyo	URTW_LOCK(sc);
1121192873Sweongyo	urtw_init_locked(arg);
1122192873Sweongyo	URTW_UNLOCK(sc);
1123192873Sweongyo}
1124192873Sweongyo
1125193045Sthompsastatic usb_error_t
1126192873Sweongyourtw_adapter_start_b(struct urtw_softc *sc)
1127192873Sweongyo{
1128235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
1129192873Sweongyo	uint8_t data8;
1130193045Sthompsa	usb_error_t error;
1131192873Sweongyo
1132192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1133192873Sweongyo	if (error)
1134192873Sweongyo		goto fail;
1135192873Sweongyo
1136192873Sweongyo	urtw_read8_m(sc, URTW_CONFIG3, &data8);
1137192873Sweongyo	urtw_write8_m(sc, URTW_CONFIG3,
1138192873Sweongyo	    data8 | URTW_CONFIG3_ANAPARAM_WRITE | URTW_CONFIG3_GNT_SELECT);
1139192873Sweongyo	urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON);
1140192873Sweongyo	urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON);
1141192873Sweongyo	urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON);
1142192873Sweongyo
1143192873Sweongyo	urtw_write8_m(sc, 0x61, 0x10);
1144192873Sweongyo	urtw_read8_m(sc, 0x62, &data8);
1145192873Sweongyo	urtw_write8_m(sc, 0x62, data8 & ~(1 << 5));
1146192873Sweongyo	urtw_write8_m(sc, 0x62, data8 | (1 << 5));
1147192873Sweongyo
1148192873Sweongyo	urtw_read8_m(sc, URTW_CONFIG3, &data8);
1149192873Sweongyo	data8 &= ~URTW_CONFIG3_ANAPARAM_WRITE;
1150192873Sweongyo	urtw_write8_m(sc, URTW_CONFIG3, data8);
1151192873Sweongyo
1152192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1153192873Sweongyo	if (error)
1154192873Sweongyo		goto fail;
1155192873Sweongyo
1156192873Sweongyo	error = urtw_8187b_cmd_reset(sc);
1157192873Sweongyo	if (error)
1158192873Sweongyo		goto fail;
1159192873Sweongyo
1160192873Sweongyo	error = sc->sc_rf_init(sc);
1161192873Sweongyo	if (error != 0)
1162192873Sweongyo		goto fail;
1163198194Sweongyo	urtw_write8_m(sc, URTW_CMD, URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE);
1164192873Sweongyo
1165198194Sweongyo	/* fix RTL8187B RX stall */
1166192873Sweongyo	error = urtw_intr_enable(sc);
1167192873Sweongyo	if (error)
1168192873Sweongyo		goto fail;
1169192873Sweongyo
1170192873Sweongyo	error = urtw_write8e(sc, 0x41, 0xf4);
1171192873Sweongyo	if (error)
1172192873Sweongyo		goto fail;
1173192873Sweongyo	error = urtw_write8e(sc, 0x40, 0x00);
1174192873Sweongyo	if (error)
1175192873Sweongyo		goto fail;
1176192873Sweongyo	error = urtw_write8e(sc, 0x42, 0x00);
1177192873Sweongyo	if (error)
1178192873Sweongyo		goto fail;
1179192873Sweongyo	error = urtw_write8e(sc, 0x42, 0x01);
1180192873Sweongyo	if (error)
1181192873Sweongyo		goto fail;
1182192873Sweongyo	error = urtw_write8e(sc, 0x40, 0x0f);
1183192873Sweongyo	if (error)
1184192873Sweongyo		goto fail;
1185192873Sweongyo	error = urtw_write8e(sc, 0x42, 0x00);
1186192873Sweongyo	if (error)
1187192873Sweongyo		goto fail;
1188192873Sweongyo	error = urtw_write8e(sc, 0x42, 0x01);
1189192873Sweongyo	if (error)
1190192873Sweongyo		goto fail;
1191192873Sweongyo
1192192873Sweongyo	urtw_read8_m(sc, 0xdb, &data8);
1193192873Sweongyo	urtw_write8_m(sc, 0xdb, data8 | (1 << 2));
1194198194Sweongyo	urtw_write16_m(sc, 0x372, 0x59fa);
1195198194Sweongyo	urtw_write16_m(sc, 0x374, 0x59d2);
1196198194Sweongyo	urtw_write16_m(sc, 0x376, 0x59d2);
1197198194Sweongyo	urtw_write16_m(sc, 0x378, 0x19fa);
1198198194Sweongyo	urtw_write16_m(sc, 0x37a, 0x19fa);
1199198194Sweongyo	urtw_write16_m(sc, 0x37c, 0x00d0);
1200192873Sweongyo	urtw_write8_m(sc, 0x61, 0);
1201198194Sweongyo
1202198194Sweongyo	urtw_write8_m(sc, 0x180, 0x0f);
1203198194Sweongyo	urtw_write8_m(sc, 0x183, 0x03);
1204192873Sweongyo	urtw_write8_m(sc, 0xda, 0x10);
1205198194Sweongyo	urtw_write8_m(sc, 0x24d, 0x08);
1206198194Sweongyo	urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321b);
1207192873Sweongyo
1208198194Sweongyo	urtw_write16_m(sc, 0x1ec, 0x800);	/* RX MAX SIZE */
1209192873Sweongyofail:
1210192873Sweongyo	return (error);
1211196970Sphk#undef N
1212192873Sweongyo}
1213192873Sweongyo
1214193045Sthompsastatic usb_error_t
1215192873Sweongyourtw_adapter_start(struct urtw_softc *sc)
1216192873Sweongyo{
1217193045Sthompsa	usb_error_t error;
1218192873Sweongyo
1219192873Sweongyo	error = urtw_reset(sc);
1220192873Sweongyo	if (error)
1221192873Sweongyo		goto fail;
1222192873Sweongyo
1223192873Sweongyo	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 0);
1224192873Sweongyo	urtw_write8_m(sc, URTW_GPIO, 0);
1225192873Sweongyo
1226192873Sweongyo	/* for led  */
1227192873Sweongyo	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
1228192873Sweongyo	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
1229192873Sweongyo	if (error != 0)
1230192873Sweongyo		goto fail;
1231192873Sweongyo
1232192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1233192873Sweongyo	if (error)
1234192873Sweongyo		goto fail;
1235192873Sweongyo	/* applying MAC address again.  */
1236192873Sweongyo	urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]);
1237192873Sweongyo	urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff);
1238192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1239192873Sweongyo	if (error)
1240192873Sweongyo		goto fail;
1241192873Sweongyo
1242192873Sweongyo	error = urtw_update_msr(sc);
1243192873Sweongyo	if (error)
1244192873Sweongyo		goto fail;
1245192873Sweongyo
1246192873Sweongyo	urtw_write32_m(sc, URTW_INT_TIMEOUT, 0);
1247192873Sweongyo	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
1248192873Sweongyo	urtw_write8_m(sc, URTW_RATE_FALLBACK, URTW_RATE_FALLBACK_ENABLE | 0x1);
1249192873Sweongyo	error = urtw_set_rate(sc);
1250192873Sweongyo	if (error != 0)
1251192873Sweongyo		goto fail;
1252192873Sweongyo
1253192873Sweongyo	error = sc->sc_rf_init(sc);
1254192873Sweongyo	if (error != 0)
1255192873Sweongyo		goto fail;
1256192873Sweongyo	if (sc->sc_rf_set_sens != NULL)
1257192873Sweongyo		sc->sc_rf_set_sens(sc, sc->sc_sens);
1258192873Sweongyo
1259192873Sweongyo	/* XXX correct? to call write16  */
1260192873Sweongyo	urtw_write16_m(sc, URTW_PSR, 1);
1261192873Sweongyo	urtw_write16_m(sc, URTW_ADDR_MAGIC2, 0x10);
1262192873Sweongyo	urtw_write8_m(sc, URTW_TALLY_SEL, 0x80);
1263192873Sweongyo	urtw_write8_m(sc, URTW_ADDR_MAGIC3, 0x60);
1264192873Sweongyo	/* XXX correct? to call write16  */
1265192873Sweongyo	urtw_write16_m(sc, URTW_PSR, 0);
1266192873Sweongyo	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
1267192873Sweongyo
1268192873Sweongyo	error = urtw_intr_enable(sc);
1269192873Sweongyo	if (error != 0)
1270192873Sweongyo		goto fail;
1271192873Sweongyo
1272192873Sweongyofail:
1273192873Sweongyo	return (error);
1274192873Sweongyo}
1275192873Sweongyo
1276196970Sphkstatic usb_error_t
1277196970Sphkurtw_set_mode(struct urtw_softc *sc, uint32_t mode)
1278196970Sphk{
1279196970Sphk	uint8_t data;
1280196970Sphk	usb_error_t error;
1281192873Sweongyo
1282196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1283196970Sphk	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
1284196970Sphk	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
1285196970Sphk	urtw_write8_m(sc, URTW_EPROM_CMD, data);
1286196970Sphkfail:
1287196970Sphk	return (error);
1288196970Sphk}
1289196970Sphk
1290193045Sthompsastatic usb_error_t
1291192873Sweongyourtw_8187b_cmd_reset(struct urtw_softc *sc)
1292192873Sweongyo{
1293192873Sweongyo	int i;
1294192873Sweongyo	uint8_t data8;
1295193045Sthompsa	usb_error_t error;
1296192873Sweongyo
1297192873Sweongyo	/* XXX the code can be duplicate with urtw_reset().  */
1298192873Sweongyo	urtw_read8_m(sc, URTW_CMD, &data8);
1299192873Sweongyo	data8 = (data8 & 0x2) | URTW_CMD_RST;
1300192873Sweongyo	urtw_write8_m(sc, URTW_CMD, data8);
1301192873Sweongyo
1302192873Sweongyo	for (i = 0; i < 20; i++) {
1303194228Sthompsa		usb_pause_mtx(&sc->sc_mtx, 2);
1304192873Sweongyo		urtw_read8_m(sc, URTW_CMD, &data8);
1305192873Sweongyo		if (!(data8 & URTW_CMD_RST))
1306192873Sweongyo			break;
1307192873Sweongyo	}
1308192873Sweongyo	if (i >= 20) {
1309192873Sweongyo		device_printf(sc->sc_dev, "reset timeout\n");
1310192873Sweongyo		goto fail;
1311192873Sweongyo	}
1312192873Sweongyofail:
1313192873Sweongyo	return (error);
1314192873Sweongyo}
1315192873Sweongyo
1316193045Sthompsastatic usb_error_t
1317192873Sweongyourtw_do_request(struct urtw_softc *sc,
1318192984Sthompsa    struct usb_device_request *req, void *data)
1319192873Sweongyo{
1320193045Sthompsa	usb_error_t err;
1321192873Sweongyo	int ntries = 10;
1322192873Sweongyo
1323192873Sweongyo	URTW_ASSERT_LOCKED(sc);
1324192873Sweongyo
1325192873Sweongyo	while (ntries--) {
1326194228Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1327192873Sweongyo		    req, data, 0, NULL, 250 /* ms */);
1328192873Sweongyo		if (err == 0)
1329192873Sweongyo			break;
1330192873Sweongyo
1331192873Sweongyo		DPRINTF(sc, URTW_DEBUG_INIT,
1332192873Sweongyo		    "Control request failed, %s (retrying)\n",
1333194228Sthompsa		    usbd_errstr(err));
1334194228Sthompsa		usb_pause_mtx(&sc->sc_mtx, hz / 100);
1335192873Sweongyo	}
1336192873Sweongyo	return (err);
1337192873Sweongyo}
1338192873Sweongyo
1339192873Sweongyostatic void
1340259456Shselaskyurtw_stop_locked(struct ifnet *ifp)
1341196970Sphk{
1342196970Sphk	struct urtw_softc *sc = ifp->if_softc;
1343196970Sphk	uint8_t data8;
1344196970Sphk	usb_error_t error;
1345196970Sphk
1346196970Sphk	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1347196970Sphk
1348196970Sphk	error = urtw_intr_disable(sc);
1349196970Sphk	if (error)
1350196970Sphk		goto fail;
1351196970Sphk	urtw_read8_m(sc, URTW_CMD, &data8);
1352196970Sphk	data8 &= ~(URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE);
1353196970Sphk	urtw_write8_m(sc, URTW_CMD, data8);
1354196970Sphk
1355196970Sphk	error = sc->sc_rf_stop(sc);
1356196970Sphk	if (error != 0)
1357196970Sphk		goto fail;
1358196970Sphk
1359196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1360196970Sphk	if (error)
1361196970Sphk		goto fail;
1362196970Sphk	urtw_read8_m(sc, URTW_CONFIG4, &data8);
1363196970Sphk	urtw_write8_m(sc, URTW_CONFIG4, data8 | URTW_CONFIG4_VCOOFF);
1364196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1365196970Sphk	if (error)
1366196970Sphk		goto fail;
1367196970Sphkfail:
1368196970Sphk	if (error)
1369196970Sphk		device_printf(sc->sc_dev, "failed to stop (%s)\n",
1370196970Sphk		    usbd_errstr(error));
1371196970Sphk
1372196970Sphk	usb_callout_stop(&sc->sc_led_ch);
1373196970Sphk	callout_stop(&sc->sc_watchdog_ch);
1374196970Sphk
1375196970Sphk	urtw_abort_xfers(sc);
1376196970Sphk}
1377196970Sphk
1378196970Sphkstatic void
1379259456Shselaskyurtw_stop(struct ifnet *ifp)
1380196970Sphk{
1381196970Sphk	struct urtw_softc *sc = ifp->if_softc;
1382196970Sphk
1383196970Sphk	URTW_LOCK(sc);
1384259456Shselasky	urtw_stop_locked(ifp);
1385196970Sphk	URTW_UNLOCK(sc);
1386196970Sphk}
1387196970Sphk
1388196970Sphkstatic void
1389192873Sweongyourtw_abort_xfers(struct urtw_softc *sc)
1390192873Sweongyo{
1391192873Sweongyo	int i, max;
1392192873Sweongyo
1393192873Sweongyo	URTW_ASSERT_LOCKED(sc);
1394192873Sweongyo
1395192873Sweongyo	max = (sc->sc_flags & URTW_RTL8187B) ? URTW_8187B_N_XFERS :
1396192873Sweongyo	    URTW_8187L_N_XFERS;
1397192873Sweongyo
1398192873Sweongyo	/* abort any pending transfers */
1399192873Sweongyo	for (i = 0; i < max; i++)
1400194228Sthompsa		usbd_transfer_stop(sc->sc_xfer[i]);
1401192873Sweongyo}
1402192873Sweongyo
1403192873Sweongyostatic int
1404192873Sweongyourtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1405192873Sweongyo{
1406192873Sweongyo	struct urtw_softc *sc = ifp->if_softc;
1407192873Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1408192873Sweongyo	struct ifreq *ifr = (struct ifreq *) data;
1409259456Shselasky	int error;
1410259456Shselasky	int startall = 0;
1411192873Sweongyo
1412259456Shselasky	URTW_LOCK(sc);
1413259456Shselasky	error = (sc->sc_flags & URTW_DETACHED) ? ENXIO : 0;
1414259456Shselasky	URTW_UNLOCK(sc);
1415259456Shselasky	if (error)
1416259456Shselasky		return (error);
1417259456Shselasky
1418192873Sweongyo	switch (cmd) {
1419192873Sweongyo	case SIOCSIFFLAGS:
1420192873Sweongyo		if (ifp->if_flags & IFF_UP) {
1421192873Sweongyo			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1422192873Sweongyo				if ((ifp->if_flags ^ sc->sc_if_flags) &
1423192873Sweongyo				    (IFF_ALLMULTI | IFF_PROMISC))
1424192873Sweongyo					urtw_set_multi(sc);
1425192873Sweongyo			} else {
1426192873Sweongyo				urtw_init(ifp->if_softc);
1427192873Sweongyo				startall = 1;
1428192873Sweongyo			}
1429192873Sweongyo		} else {
1430192873Sweongyo			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1431259456Shselasky				urtw_stop(ifp);
1432192873Sweongyo		}
1433192873Sweongyo		sc->sc_if_flags = ifp->if_flags;
1434192873Sweongyo		if (startall)
1435192873Sweongyo			ieee80211_start_all(ic);
1436192873Sweongyo		break;
1437192873Sweongyo	case SIOCGIFMEDIA:
1438192873Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1439192873Sweongyo		break;
1440192873Sweongyo	case SIOCGIFADDR:
1441192873Sweongyo		error = ether_ioctl(ifp, cmd, data);
1442192873Sweongyo		break;
1443192873Sweongyo	default:
1444192873Sweongyo		error = EINVAL;
1445192873Sweongyo		break;
1446192873Sweongyo	}
1447192873Sweongyo	return (error);
1448192873Sweongyo}
1449192873Sweongyo
1450192873Sweongyostatic void
1451192873Sweongyourtw_start(struct ifnet *ifp)
1452192873Sweongyo{
1453192873Sweongyo	struct urtw_data *bf;
1454192873Sweongyo	struct urtw_softc *sc = ifp->if_softc;
1455192873Sweongyo	struct ieee80211_node *ni;
1456192873Sweongyo	struct mbuf *m;
1457192873Sweongyo
1458192873Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1459192873Sweongyo		return;
1460192873Sweongyo
1461192873Sweongyo	URTW_LOCK(sc);
1462192873Sweongyo	for (;;) {
1463192873Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1464192873Sweongyo		if (m == NULL)
1465192873Sweongyo			break;
1466192873Sweongyo		bf = urtw_getbuf(sc);
1467192873Sweongyo		if (bf == NULL) {
1468192873Sweongyo			IFQ_DRV_PREPEND(&ifp->if_snd, m);
1469192873Sweongyo			break;
1470192873Sweongyo		}
1471192873Sweongyo
1472192873Sweongyo		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
1473192873Sweongyo		m->m_pkthdr.rcvif = NULL;
1474192873Sweongyo
1475192873Sweongyo		if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_NORMAL) != 0) {
1476192873Sweongyo			ifp->if_oerrors++;
1477192873Sweongyo			STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
1478192873Sweongyo			ieee80211_free_node(ni);
1479192873Sweongyo			break;
1480192873Sweongyo		}
1481192873Sweongyo
1482192873Sweongyo		sc->sc_txtimer = 5;
1483198194Sweongyo		callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
1484192873Sweongyo	}
1485192873Sweongyo	URTW_UNLOCK(sc);
1486192873Sweongyo}
1487192873Sweongyo
1488192873Sweongyostatic int
1489192873Sweongyourtw_alloc_data_list(struct urtw_softc *sc, struct urtw_data data[],
1490259454Shselasky    int ndata, int maxsz, void *dma_buf)
1491192873Sweongyo{
1492192873Sweongyo	int i, error;
1493192873Sweongyo
1494192873Sweongyo	for (i = 0; i < ndata; i++) {
1495192873Sweongyo		struct urtw_data *dp = &data[i];
1496192873Sweongyo
1497192873Sweongyo		dp->sc = sc;
1498259454Shselasky		if (dma_buf == NULL) {
1499248078Smarius			dp->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1500192873Sweongyo			if (dp->m == NULL) {
1501192873Sweongyo				device_printf(sc->sc_dev,
1502192873Sweongyo				    "could not allocate rx mbuf\n");
1503192873Sweongyo				error = ENOMEM;
1504192873Sweongyo				goto fail;
1505192873Sweongyo			}
1506192873Sweongyo			dp->buf = mtod(dp->m, uint8_t *);
1507192873Sweongyo		} else {
1508192873Sweongyo			dp->m = NULL;
1509259454Shselasky			dp->buf = ((uint8_t *)dma_buf) +
1510259454Shselasky			    (i * maxsz);
1511192873Sweongyo		}
1512192873Sweongyo		dp->ni = NULL;
1513192873Sweongyo	}
1514259454Shselasky	return (0);
1515192873Sweongyo
1516259454Shselaskyfail:	urtw_free_data_list(sc, data, ndata, 1);
1517259454Shselasky	return (error);
1518192873Sweongyo}
1519192873Sweongyo
1520192873Sweongyostatic int
1521192873Sweongyourtw_alloc_rx_data_list(struct urtw_softc *sc)
1522192873Sweongyo{
1523192873Sweongyo	int error, i;
1524192873Sweongyo
1525192873Sweongyo	error = urtw_alloc_data_list(sc,
1526259454Shselasky	    sc->sc_rx, URTW_RX_DATA_LIST_COUNT,
1527259454Shselasky	    MCLBYTES, NULL /* mbufs */);
1528192873Sweongyo	if (error != 0)
1529192873Sweongyo		return (error);
1530192873Sweongyo
1531192873Sweongyo	STAILQ_INIT(&sc->sc_rx_active);
1532192873Sweongyo	STAILQ_INIT(&sc->sc_rx_inactive);
1533192873Sweongyo
1534192873Sweongyo	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++)
1535192873Sweongyo		STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next);
1536192873Sweongyo
1537192873Sweongyo	return (0);
1538192873Sweongyo}
1539192873Sweongyo
1540192873Sweongyostatic int
1541192873Sweongyourtw_alloc_tx_data_list(struct urtw_softc *sc)
1542192873Sweongyo{
1543192873Sweongyo	int error, i;
1544192873Sweongyo
1545192873Sweongyo	error = urtw_alloc_data_list(sc,
1546192873Sweongyo	    sc->sc_tx, URTW_TX_DATA_LIST_COUNT, URTW_TX_MAXSIZE,
1547259454Shselasky	    sc->sc_tx_dma_buf /* no mbufs */);
1548192873Sweongyo	if (error != 0)
1549192873Sweongyo		return (error);
1550192873Sweongyo
1551192873Sweongyo	STAILQ_INIT(&sc->sc_tx_active);
1552192873Sweongyo	STAILQ_INIT(&sc->sc_tx_inactive);
1553192873Sweongyo	STAILQ_INIT(&sc->sc_tx_pending);
1554192873Sweongyo
1555192873Sweongyo	for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++)
1556192873Sweongyo		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i],
1557192873Sweongyo		    next);
1558192873Sweongyo
1559192873Sweongyo	return (0);
1560192873Sweongyo}
1561192873Sweongyo
1562192873Sweongyostatic int
1563192873Sweongyourtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1564192873Sweongyo    const struct ieee80211_bpf_params *params)
1565192873Sweongyo{
1566192873Sweongyo	struct ieee80211com *ic = ni->ni_ic;
1567192873Sweongyo	struct ifnet *ifp = ic->ic_ifp;
1568192873Sweongyo	struct urtw_data *bf;
1569192873Sweongyo	struct urtw_softc *sc = ifp->if_softc;
1570192873Sweongyo
1571192873Sweongyo	/* prevent management frames from being sent if we're not ready */
1572192873Sweongyo	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1573192873Sweongyo		m_freem(m);
1574192873Sweongyo		ieee80211_free_node(ni);
1575192873Sweongyo		return ENETDOWN;
1576192873Sweongyo	}
1577192873Sweongyo	URTW_LOCK(sc);
1578192873Sweongyo	bf = urtw_getbuf(sc);
1579192873Sweongyo	if (bf == NULL) {
1580192873Sweongyo		ieee80211_free_node(ni);
1581192873Sweongyo		m_freem(m);
1582192873Sweongyo		URTW_UNLOCK(sc);
1583192873Sweongyo		return (ENOBUFS);		/* XXX */
1584192873Sweongyo	}
1585192873Sweongyo
1586192873Sweongyo	ifp->if_opackets++;
1587192873Sweongyo	if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_LOW) != 0) {
1588192873Sweongyo		ieee80211_free_node(ni);
1589192873Sweongyo		ifp->if_oerrors++;
1590192873Sweongyo		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
1591192873Sweongyo		URTW_UNLOCK(sc);
1592192873Sweongyo		return (EIO);
1593192873Sweongyo	}
1594192873Sweongyo	URTW_UNLOCK(sc);
1595192873Sweongyo
1596192873Sweongyo	sc->sc_txtimer = 5;
1597192873Sweongyo	return (0);
1598192873Sweongyo}
1599192873Sweongyo
1600192873Sweongyostatic void
1601192873Sweongyourtw_scan_start(struct ieee80211com *ic)
1602192873Sweongyo{
1603192873Sweongyo
1604192873Sweongyo	/* XXX do nothing?  */
1605192873Sweongyo}
1606192873Sweongyo
1607192873Sweongyostatic void
1608192873Sweongyourtw_scan_end(struct ieee80211com *ic)
1609192873Sweongyo{
1610192873Sweongyo
1611192873Sweongyo	/* XXX do nothing?  */
1612192873Sweongyo}
1613192873Sweongyo
1614192873Sweongyostatic void
1615192873Sweongyourtw_set_channel(struct ieee80211com *ic)
1616192873Sweongyo{
1617192873Sweongyo	struct urtw_softc *sc  = ic->ic_ifp->if_softc;
1618192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1619192873Sweongyo	uint32_t data, orig;
1620193045Sthompsa	usb_error_t error;
1621192873Sweongyo
1622192873Sweongyo	/*
1623192873Sweongyo	 * if the user set a channel explicitly using ifconfig(8) this function
1624192873Sweongyo	 * can be called earlier than we're expected that in some cases the
1625192873Sweongyo	 * initialization would be failed if setting a channel is called before
1626192873Sweongyo	 * the init have done.
1627192873Sweongyo	 */
1628192873Sweongyo	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1629192873Sweongyo		return;
1630192873Sweongyo
1631192873Sweongyo	if (sc->sc_curchan != NULL && sc->sc_curchan == ic->ic_curchan)
1632192873Sweongyo		return;
1633192873Sweongyo
1634192873Sweongyo	URTW_LOCK(sc);
1635192873Sweongyo
1636192873Sweongyo	/*
1637192873Sweongyo	 * during changing th channel we need to temporarily be disable
1638192873Sweongyo	 * TX.
1639192873Sweongyo	 */
1640192873Sweongyo	urtw_read32_m(sc, URTW_TX_CONF, &orig);
1641192873Sweongyo	data = orig & ~URTW_TX_LOOPBACK_MASK;
1642192873Sweongyo	urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC);
1643192873Sweongyo
1644192873Sweongyo	error = sc->sc_rf_set_chan(sc, ieee80211_chan2ieee(ic, ic->ic_curchan));
1645192873Sweongyo	if (error != 0)
1646192873Sweongyo		goto fail;
1647194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 10);
1648192873Sweongyo	urtw_write32_m(sc, URTW_TX_CONF, orig);
1649192873Sweongyo
1650192873Sweongyo	urtw_write16_m(sc, URTW_ATIM_WND, 2);
1651192873Sweongyo	urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
1652192873Sweongyo	urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
1653192873Sweongyo	urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
1654192873Sweongyo
1655192873Sweongyofail:
1656192873Sweongyo	URTW_UNLOCK(sc);
1657192873Sweongyo
1658192873Sweongyo	sc->sc_curchan = ic->ic_curchan;
1659192873Sweongyo
1660192873Sweongyo	if (error != 0)
1661192873Sweongyo		device_printf(sc->sc_dev, "could not change the channel\n");
1662192873Sweongyo}
1663192873Sweongyo
1664192873Sweongyostatic void
1665192873Sweongyourtw_update_mcast(struct ifnet *ifp)
1666192873Sweongyo{
1667192873Sweongyo
1668192873Sweongyo	/* XXX do nothing?  */
1669192873Sweongyo}
1670192873Sweongyo
1671192873Sweongyostatic int
1672192873Sweongyourtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0,
1673192873Sweongyo    struct urtw_data *data, int prior)
1674192873Sweongyo{
1675192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1676192873Sweongyo	struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
1677192873Sweongyo	struct ieee80211_key *k;
1678192873Sweongyo	const struct ieee80211_txparam *tp;
1679192873Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1680192873Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
1681192984Sthompsa	struct usb_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = {
1682192873Sweongyo		sc->sc_xfer[URTW_8187B_BULK_TX_BE],
1683192873Sweongyo		sc->sc_xfer[URTW_8187B_BULK_TX_BK],
1684192873Sweongyo		sc->sc_xfer[URTW_8187B_BULK_TX_VI],
1685192873Sweongyo		sc->sc_xfer[URTW_8187B_BULK_TX_VO]
1686192873Sweongyo	};
1687192984Sthompsa	struct usb_xfer *xfer;
1688198194Sweongyo	int dur = 0, rtsdur = 0, rtsenable = 0, ctsenable = 0, rate,
1689198194Sweongyo	    pkttime = 0, txdur = 0, isshort = 0, xferlen;
1690198194Sweongyo	uint16_t acktime, rtstime, ctstime;
1691198194Sweongyo	uint32_t flags;
1692193045Sthompsa	usb_error_t error;
1693192873Sweongyo
1694192873Sweongyo	URTW_ASSERT_LOCKED(sc);
1695192873Sweongyo
1696192873Sweongyo	/*
1697192873Sweongyo	 * Software crypto.
1698192873Sweongyo	 */
1699192873Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1700192873Sweongyo		k = ieee80211_crypto_encap(ni, m0);
1701192873Sweongyo		if (k == NULL) {
1702192873Sweongyo			device_printf(sc->sc_dev,
1703192873Sweongyo			    "ieee80211_crypto_encap returns NULL.\n");
1704192873Sweongyo			/* XXX we don't expect the fragmented frames  */
1705192873Sweongyo			m_freem(m0);
1706192873Sweongyo			return (ENOBUFS);
1707192873Sweongyo		}
1708192873Sweongyo
1709192873Sweongyo		/* in case packet header moved, reset pointer */
1710192873Sweongyo		wh = mtod(m0, struct ieee80211_frame *);
1711192873Sweongyo	}
1712192873Sweongyo
1713192873Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
1714192873Sweongyo		struct urtw_tx_radiotap_header *tap = &sc->sc_txtap;
1715192873Sweongyo
1716192873Sweongyo		/* XXX Are variables correct?  */
1717192873Sweongyo		tap->wt_flags = 0;
1718192873Sweongyo		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1719192873Sweongyo		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1720192873Sweongyo
1721192873Sweongyo		ieee80211_radiotap_tx(vap, m0);
1722192873Sweongyo	}
1723192873Sweongyo
1724198862Sweongyo	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT ||
1725198194Sweongyo	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) {
1726198194Sweongyo		tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1727198194Sweongyo		rate = tp->mgmtrate;
1728198194Sweongyo	} else {
1729198194Sweongyo		tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
1730198194Sweongyo		/* for data frames */
1731198194Sweongyo		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1732198194Sweongyo			rate = tp->mcastrate;
1733198194Sweongyo		else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
1734198194Sweongyo			rate = tp->ucastrate;
1735198194Sweongyo		else
1736198194Sweongyo			rate = urtw_rtl2rate(sc->sc_currate);
1737198194Sweongyo	}
1738198194Sweongyo
1739203087Sweongyo	sc->sc_stats.txrates[sc->sc_currate]++;
1740203087Sweongyo
1741198194Sweongyo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1742198194Sweongyo		txdur = pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
1743198194Sweongyo		    IEEE80211_CRC_LEN, rate, 0, 0);
1744198194Sweongyo	else {
1745198194Sweongyo		acktime = urtw_compute_txtime(14, 2,0, 0);
1746198194Sweongyo		if ((m0->m_pkthdr.len + 4) > vap->iv_rtsthreshold) {
1747198194Sweongyo			rtsenable = 1;
1748198194Sweongyo			ctsenable = 0;
1749198194Sweongyo			rtstime = urtw_compute_txtime(URTW_ACKCTS_LEN, 2, 0, 0);
1750198194Sweongyo			ctstime = urtw_compute_txtime(14, 2, 0, 0);
1751198194Sweongyo			pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
1752198194Sweongyo			    IEEE80211_CRC_LEN, rate, 0, isshort);
1753198194Sweongyo			rtsdur = ctstime + pkttime + acktime +
1754198194Sweongyo			    3 * URTW_ASIFS_TIME;
1755198194Sweongyo			txdur = rtstime + rtsdur;
1756198194Sweongyo		} else {
1757198194Sweongyo			rtsenable = ctsenable = rtsdur = 0;
1758198194Sweongyo			pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
1759198194Sweongyo			    IEEE80211_CRC_LEN, rate, 0, isshort);
1760198194Sweongyo			txdur = pkttime + URTW_ASIFS_TIME + acktime;
1761198194Sweongyo		}
1762198194Sweongyo
1763198194Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
1764198194Sweongyo			dur = urtw_compute_txtime(m0->m_pkthdr.len +
1765198194Sweongyo			    IEEE80211_CRC_LEN, rate, 0, isshort) +
1766198194Sweongyo			    3 * URTW_ASIFS_TIME +
1767198194Sweongyo			    2 * acktime;
1768198194Sweongyo		else
1769198194Sweongyo			dur = URTW_ASIFS_TIME + acktime;
1770198194Sweongyo	}
1771259457Shselasky	USETW(wh->i_dur, dur);
1772198194Sweongyo
1773192873Sweongyo	xferlen = m0->m_pkthdr.len;
1774192873Sweongyo	xferlen += (sc->sc_flags & URTW_RTL8187B) ? (4 * 8) : (4 * 3);
1775192873Sweongyo	if ((0 == xferlen % 64) || (0 == xferlen % 512))
1776192873Sweongyo		xferlen += 1;
1777192873Sweongyo
1778229080Shselasky	memset(data->buf, 0, URTW_TX_MAXSIZE);
1779198194Sweongyo	flags = m0->m_pkthdr.len & 0xfff;
1780198194Sweongyo	flags |= URTW_TX_FLAG_NO_ENC;
1781192873Sweongyo	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
1782192873Sweongyo	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) &&
1783192873Sweongyo	    (sc->sc_preamble_mode == URTW_PREAMBLE_MODE_SHORT) &&
1784192873Sweongyo	    (sc->sc_currate != 0))
1785198194Sweongyo		flags |= URTW_TX_FLAG_SPLCP;
1786192873Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
1787198194Sweongyo		flags |= URTW_TX_FLAG_MOREFRAG;
1788192873Sweongyo
1789198194Sweongyo	flags |= (sc->sc_currate & 0xf) << URTW_TX_FLAG_TXRATE_SHIFT;
1790198194Sweongyo
1791192873Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
1792198194Sweongyo		struct urtw_8187b_txhdr *tx;
1793198194Sweongyo
1794198194Sweongyo		tx = (struct urtw_8187b_txhdr *)data->buf;
1795198194Sweongyo		if (ctsenable)
1796198194Sweongyo			flags |= URTW_TX_FLAG_CTS;
1797198194Sweongyo		if (rtsenable) {
1798198194Sweongyo			flags |= URTW_TX_FLAG_RTS;
1799198194Sweongyo			flags |= (urtw_rate2rtl(11) & 0xf) <<
1800198194Sweongyo			    URTW_TX_FLAG_RTSRATE_SHIFT;
1801198194Sweongyo			tx->rtsdur = rtsdur;
1802198194Sweongyo		}
1803198194Sweongyo		tx->flag = htole32(flags);
1804198194Sweongyo		tx->txdur = txdur;
1805198194Sweongyo		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
1806198194Sweongyo		    IEEE80211_FC0_TYPE_MGT &&
1807198194Sweongyo		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
1808198194Sweongyo		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
1809198194Sweongyo			tx->retry = 1;
1810198194Sweongyo		else
1811198194Sweongyo			tx->retry = URTW_TX_MAXRETRY;
1812198194Sweongyo		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1));
1813192873Sweongyo	} else {
1814198194Sweongyo		struct urtw_8187l_txhdr *tx;
1815198194Sweongyo
1816198194Sweongyo		tx = (struct urtw_8187l_txhdr *)data->buf;
1817198194Sweongyo		if (rtsenable) {
1818198194Sweongyo			flags |= URTW_TX_FLAG_RTS;
1819198194Sweongyo			tx->rtsdur = rtsdur;
1820198194Sweongyo		}
1821198194Sweongyo		flags |= (urtw_rate2rtl(11) & 0xf) << URTW_TX_FLAG_RTSRATE_SHIFT;
1822198194Sweongyo		tx->flag = htole32(flags);
1823198194Sweongyo		tx->retry = 3;		/* CW minimum  */
1824198194Sweongyo		tx->retry = 7 << 4;	/* CW maximum  */
1825198194Sweongyo		tx->retry = URTW_TX_MAXRETRY << 8;	/* retry limitation  */
1826198194Sweongyo		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1));
1827192873Sweongyo	}
1828192873Sweongyo
1829192873Sweongyo	data->buflen = xferlen;
1830192873Sweongyo	data->ni = ni;
1831192873Sweongyo	data->m = m0;
1832192873Sweongyo
1833192873Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
1834192873Sweongyo		switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
1835192873Sweongyo		case IEEE80211_FC0_TYPE_CTL:
1836192873Sweongyo		case IEEE80211_FC0_TYPE_MGT:
1837192873Sweongyo			xfer = sc->sc_xfer[URTW_8187B_BULK_TX_EP12];
1838192873Sweongyo			break;
1839192873Sweongyo		default:
1840192873Sweongyo			KASSERT(M_WME_GETAC(m0) < URTW_8187B_TXPIPE_MAX,
1841192873Sweongyo			    ("unsupported WME pipe %d", M_WME_GETAC(m0)));
1842192873Sweongyo			xfer = rtl8187b_pipes[M_WME_GETAC(m0)];
1843192873Sweongyo			break;
1844192873Sweongyo		}
1845192873Sweongyo	} else
1846192873Sweongyo		xfer = (prior == URTW_PRIORITY_LOW) ?
1847192873Sweongyo		    sc->sc_xfer[URTW_8187L_BULK_TX_LOW] :
1848192873Sweongyo		    sc->sc_xfer[URTW_8187L_BULK_TX_NORMAL];
1849192873Sweongyo
1850192873Sweongyo	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
1851194228Sthompsa	usbd_transfer_start(xfer);
1852192873Sweongyo
1853192873Sweongyo	error = urtw_led_ctl(sc, URTW_LED_CTL_TX);
1854192873Sweongyo	if (error != 0)
1855192873Sweongyo		device_printf(sc->sc_dev, "could not control LED (%d)\n",
1856192873Sweongyo		    error);
1857192873Sweongyo	return (0);
1858192873Sweongyo}
1859192873Sweongyo
1860192873Sweongyostatic int
1861192873Sweongyourtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
1862192873Sweongyo{
1863192873Sweongyo	struct ieee80211com *ic = vap->iv_ic;
1864192873Sweongyo	struct urtw_softc *sc = ic->ic_ifp->if_softc;
1865192873Sweongyo	struct urtw_vap *uvp = URTW_VAP(vap);
1866212131Sthompsa	struct ieee80211_node *ni;
1867193045Sthompsa	usb_error_t error = 0;
1868192873Sweongyo
1869192873Sweongyo	DPRINTF(sc, URTW_DEBUG_STATE, "%s: %s -> %s\n", __func__,
1870192873Sweongyo	    ieee80211_state_name[vap->iv_state],
1871192873Sweongyo	    ieee80211_state_name[nstate]);
1872192873Sweongyo
1873192873Sweongyo	sc->sc_state = nstate;
1874192873Sweongyo
1875192873Sweongyo	IEEE80211_UNLOCK(ic);
1876192873Sweongyo	URTW_LOCK(sc);
1877194228Sthompsa	usb_callout_stop(&sc->sc_led_ch);
1878192873Sweongyo	callout_stop(&sc->sc_watchdog_ch);
1879192873Sweongyo
1880192873Sweongyo	switch (nstate) {
1881192873Sweongyo	case IEEE80211_S_INIT:
1882192873Sweongyo	case IEEE80211_S_SCAN:
1883192873Sweongyo	case IEEE80211_S_AUTH:
1884192873Sweongyo	case IEEE80211_S_ASSOC:
1885192873Sweongyo		break;
1886192873Sweongyo	case IEEE80211_S_RUN:
1887212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
1888192873Sweongyo		/* setting bssid.  */
1889192873Sweongyo		urtw_write32_m(sc, URTW_BSSID, ((uint32_t *)ni->ni_bssid)[0]);
1890192873Sweongyo		urtw_write16_m(sc, URTW_BSSID + 4,
1891192873Sweongyo		    ((uint16_t *)ni->ni_bssid)[2]);
1892192873Sweongyo		urtw_update_msr(sc);
1893192873Sweongyo		/* XXX maybe the below would be incorrect.  */
1894192873Sweongyo		urtw_write16_m(sc, URTW_ATIM_WND, 2);
1895192873Sweongyo		urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
1896192873Sweongyo		urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64);
1897192873Sweongyo		urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
1898192873Sweongyo		error = urtw_led_ctl(sc, URTW_LED_CTL_LINK);
1899192873Sweongyo		if (error != 0)
1900192873Sweongyo			device_printf(sc->sc_dev,
1901192873Sweongyo			    "could not control LED (%d)\n", error);
1902212127Sthompsa		ieee80211_free_node(ni);
1903192873Sweongyo		break;
1904192873Sweongyo	default:
1905192873Sweongyo		break;
1906192873Sweongyo	}
1907192873Sweongyofail:
1908192873Sweongyo	URTW_UNLOCK(sc);
1909192873Sweongyo	IEEE80211_LOCK(ic);
1910192873Sweongyo	return (uvp->newstate(vap, nstate, arg));
1911192873Sweongyo}
1912192873Sweongyo
1913192873Sweongyostatic void
1914192873Sweongyourtw_watchdog(void *arg)
1915192873Sweongyo{
1916192873Sweongyo	struct urtw_softc *sc = arg;
1917192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1918192873Sweongyo
1919192873Sweongyo	if (sc->sc_txtimer > 0) {
1920192873Sweongyo		if (--sc->sc_txtimer == 0) {
1921192873Sweongyo			device_printf(sc->sc_dev, "device timeout\n");
1922192873Sweongyo			ifp->if_oerrors++;
1923192873Sweongyo			return;
1924192873Sweongyo		}
1925192873Sweongyo		callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
1926192873Sweongyo	}
1927192873Sweongyo}
1928192873Sweongyo
1929192873Sweongyostatic void
1930192873Sweongyourtw_set_multi(void *arg)
1931192873Sweongyo{
1932192873Sweongyo	struct urtw_softc *sc = arg;
1933192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1934192873Sweongyo
1935192873Sweongyo	if (!(ifp->if_flags & IFF_UP))
1936192873Sweongyo		return;
1937192873Sweongyo
1938192873Sweongyo	/*
1939192873Sweongyo	 * XXX don't know how to set a device.  Lack of docs.  Just try to set
1940192873Sweongyo	 * IFF_ALLMULTI flag here.
1941192873Sweongyo	 */
1942192873Sweongyo	ifp->if_flags |= IFF_ALLMULTI;
1943192873Sweongyo}
1944192873Sweongyo
1945193045Sthompsastatic usb_error_t
1946196970Sphkurtw_set_rate(struct urtw_softc *sc)
1947192873Sweongyo{
1948196970Sphk	int i, basic_rate, min_rr_rate, max_rr_rate;
1949196970Sphk	uint16_t data;
1950193045Sthompsa	usb_error_t error;
1951192873Sweongyo
1952196970Sphk	basic_rate = urtw_rate2rtl(48);
1953196970Sphk	min_rr_rate = urtw_rate2rtl(12);
1954196970Sphk	max_rr_rate = urtw_rate2rtl(48);
1955192873Sweongyo
1956196970Sphk	urtw_write8_m(sc, URTW_RESP_RATE,
1957196970Sphk	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
1958196970Sphk	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT);
1959192873Sweongyo
1960196970Sphk	urtw_read16_m(sc, URTW_BRSR, &data);
1961196970Sphk	data &= ~URTW_BRSR_MBR_8185;
1962192873Sweongyo
1963196970Sphk	for (i = 0; i <= basic_rate; i++)
1964196970Sphk		data |= (1 << i);
1965192873Sweongyo
1966196970Sphk	urtw_write16_m(sc, URTW_BRSR, data);
1967192873Sweongyofail:
1968192873Sweongyo	return (error);
1969192873Sweongyo}
1970192873Sweongyo
1971196970Sphkstatic uint16_t
1972235000Shselaskyurtw_rate2rtl(uint32_t rate)
1973192873Sweongyo{
1974235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
1975196970Sphk	int i;
1976192873Sweongyo
1977196970Sphk	for (i = 0; i < N(urtw_ratetable); i++) {
1978196970Sphk		if (rate == urtw_ratetable[i].reg)
1979196970Sphk			return urtw_ratetable[i].val;
1980196970Sphk	}
1981192873Sweongyo
1982196970Sphk	return (3);
1983196970Sphk#undef N
1984192873Sweongyo}
1985192873Sweongyo
1986196970Sphkstatic uint16_t
1987235000Shselaskyurtw_rtl2rate(uint32_t rate)
1988192873Sweongyo{
1989235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
1990196970Sphk	int i;
1991192873Sweongyo
1992196970Sphk	for (i = 0; i < N(urtw_ratetable); i++) {
1993196970Sphk		if (rate == urtw_ratetable[i].val)
1994196970Sphk			return urtw_ratetable[i].reg;
1995192873Sweongyo	}
1996192873Sweongyo
1997196970Sphk	return (0);
1998196970Sphk#undef N
1999192873Sweongyo}
2000192873Sweongyo
2001193045Sthompsastatic usb_error_t
2002196970Sphkurtw_update_msr(struct urtw_softc *sc)
2003192873Sweongyo{
2004196970Sphk	struct ifnet *ifp = sc->sc_ifp;
2005196970Sphk	struct ieee80211com *ic = ifp->if_l2com;
2006192873Sweongyo	uint8_t data;
2007193045Sthompsa	usb_error_t error;
2008192873Sweongyo
2009196970Sphk	urtw_read8_m(sc, URTW_MSR, &data);
2010196970Sphk	data &= ~URTW_MSR_LINK_MASK;
2011192873Sweongyo
2012196970Sphk	if (sc->sc_state == IEEE80211_S_RUN) {
2013196970Sphk		switch (ic->ic_opmode) {
2014196970Sphk		case IEEE80211_M_STA:
2015196970Sphk		case IEEE80211_M_MONITOR:
2016196970Sphk			data |= URTW_MSR_LINK_STA;
2017196970Sphk			if (sc->sc_flags & URTW_RTL8187B)
2018196970Sphk				data |= URTW_MSR_LINK_ENEDCA;
2019196970Sphk			break;
2020196970Sphk		case IEEE80211_M_IBSS:
2021196970Sphk			data |= URTW_MSR_LINK_ADHOC;
2022196970Sphk			break;
2023196970Sphk		case IEEE80211_M_HOSTAP:
2024196970Sphk			data |= URTW_MSR_LINK_HOSTAP;
2025196970Sphk			break;
2026196970Sphk		default:
2027259456Shselasky			DPRINTF(sc, URTW_DEBUG_STATE,
2028259456Shselasky			    "unsupported operation mode 0x%x\n",
2029196970Sphk			    ic->ic_opmode);
2030259456Shselasky			error = USB_ERR_INVAL;
2031259456Shselasky			goto fail;
2032196970Sphk		}
2033196970Sphk	} else
2034196970Sphk		data |= URTW_MSR_LINK_NONE;
2035192873Sweongyo
2036196970Sphk	urtw_write8_m(sc, URTW_MSR, data);
2037192873Sweongyofail:
2038192873Sweongyo	return (error);
2039192873Sweongyo}
2040192873Sweongyo
2041193045Sthompsastatic usb_error_t
2042192873Sweongyourtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data)
2043192873Sweongyo{
2044192984Sthompsa	struct usb_device_request req;
2045193045Sthompsa	usb_error_t error;
2046192873Sweongyo
2047192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2048192873Sweongyo
2049192873Sweongyo	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2050192873Sweongyo	req.bRequest = URTW_8187_GETREGS_REQ;
2051198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2052198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2053192873Sweongyo	USETW(req.wLength, sizeof(uint8_t));
2054192873Sweongyo
2055192873Sweongyo	error = urtw_do_request(sc, &req, data);
2056192873Sweongyo	return (error);
2057192873Sweongyo}
2058192873Sweongyo
2059193045Sthompsastatic usb_error_t
2060192873Sweongyourtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data)
2061192873Sweongyo{
2062192984Sthompsa	struct usb_device_request req;
2063193045Sthompsa	usb_error_t error;
2064192873Sweongyo
2065192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2066192873Sweongyo
2067192873Sweongyo	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2068192873Sweongyo	req.bRequest = URTW_8187_GETREGS_REQ;
2069198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2070198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2071192873Sweongyo	USETW(req.wLength, sizeof(uint16_t));
2072192873Sweongyo
2073192873Sweongyo	error = urtw_do_request(sc, &req, data);
2074192873Sweongyo	return (error);
2075192873Sweongyo}
2076192873Sweongyo
2077193045Sthompsastatic usb_error_t
2078192873Sweongyourtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data)
2079192873Sweongyo{
2080192984Sthompsa	struct usb_device_request req;
2081193045Sthompsa	usb_error_t error;
2082192873Sweongyo
2083192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2084192873Sweongyo
2085192873Sweongyo	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2086192873Sweongyo	req.bRequest = URTW_8187_GETREGS_REQ;
2087198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2088198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2089192873Sweongyo	USETW(req.wLength, sizeof(uint32_t));
2090192873Sweongyo
2091192873Sweongyo	error = urtw_do_request(sc, &req, data);
2092192873Sweongyo	return (error);
2093192873Sweongyo}
2094192873Sweongyo
2095193045Sthompsastatic usb_error_t
2096192873Sweongyourtw_write8_c(struct urtw_softc *sc, int val, uint8_t data)
2097192873Sweongyo{
2098192984Sthompsa	struct usb_device_request req;
2099192873Sweongyo
2100192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2101192873Sweongyo
2102192873Sweongyo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2103192873Sweongyo	req.bRequest = URTW_8187_SETREGS_REQ;
2104198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2105198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2106192873Sweongyo	USETW(req.wLength, sizeof(uint8_t));
2107192873Sweongyo
2108192873Sweongyo	return (urtw_do_request(sc, &req, &data));
2109192873Sweongyo}
2110192873Sweongyo
2111193045Sthompsastatic usb_error_t
2112192873Sweongyourtw_write16_c(struct urtw_softc *sc, int val, uint16_t data)
2113192873Sweongyo{
2114192984Sthompsa	struct usb_device_request req;
2115192873Sweongyo
2116192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2117192873Sweongyo
2118192873Sweongyo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2119192873Sweongyo	req.bRequest = URTW_8187_SETREGS_REQ;
2120198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2121198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2122192873Sweongyo	USETW(req.wLength, sizeof(uint16_t));
2123192873Sweongyo
2124192873Sweongyo	return (urtw_do_request(sc, &req, &data));
2125192873Sweongyo}
2126192873Sweongyo
2127193045Sthompsastatic usb_error_t
2128192873Sweongyourtw_write32_c(struct urtw_softc *sc, int val, uint32_t data)
2129192873Sweongyo{
2130192984Sthompsa	struct usb_device_request req;
2131192873Sweongyo
2132192873Sweongyo	URTW_ASSERT_LOCKED(sc);
2133192873Sweongyo
2134192873Sweongyo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2135192873Sweongyo	req.bRequest = URTW_8187_SETREGS_REQ;
2136198194Sweongyo	USETW(req.wValue, (val & 0xff) | 0xff00);
2137198194Sweongyo	USETW(req.wIndex, (val >> 8) & 0x3);
2138192873Sweongyo	USETW(req.wLength, sizeof(uint32_t));
2139192873Sweongyo
2140192873Sweongyo	return (urtw_do_request(sc, &req, &data));
2141192873Sweongyo}
2142192873Sweongyo
2143193045Sthompsastatic usb_error_t
2144196970Sphkurtw_get_macaddr(struct urtw_softc *sc)
2145192873Sweongyo{
2146196970Sphk	uint32_t data;
2147193045Sthompsa	usb_error_t error;
2148192873Sweongyo
2149196970Sphk	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
2150196970Sphk	if (error != 0)
2151192873Sweongyo		goto fail;
2152196970Sphk	sc->sc_bssid[0] = data & 0xff;
2153196970Sphk	sc->sc_bssid[1] = (data & 0xff00) >> 8;
2154196970Sphk	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
2155196970Sphk	if (error != 0)
2156192873Sweongyo		goto fail;
2157196970Sphk	sc->sc_bssid[2] = data & 0xff;
2158196970Sphk	sc->sc_bssid[3] = (data & 0xff00) >> 8;
2159196970Sphk	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
2160196970Sphk	if (error != 0)
2161192873Sweongyo		goto fail;
2162196970Sphk	sc->sc_bssid[4] = data & 0xff;
2163196970Sphk	sc->sc_bssid[5] = (data & 0xff00) >> 8;
2164192873Sweongyofail:
2165192873Sweongyo	return (error);
2166192873Sweongyo}
2167192873Sweongyo
2168193045Sthompsastatic usb_error_t
2169196970Sphkurtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
2170192873Sweongyo{
2171196970Sphk#define URTW_READCMD_LEN		3
2172196970Sphk	int addrlen, i;
2173196970Sphk	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
2174193045Sthompsa	usb_error_t error;
2175192873Sweongyo
2176196970Sphk	/* NB: make sure the buffer is initialized  */
2177196970Sphk	*data = 0;
2178192873Sweongyo
2179196970Sphk	/* enable EPROM programming */
2180196970Sphk	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE);
2181196970Sphk	DELAY(URTW_EPROM_DELAY);
2182192873Sweongyo
2183196970Sphk	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
2184196970Sphk	if (error != 0)
2185192873Sweongyo		goto fail;
2186196970Sphk	error = urtw_eprom_ck(sc);
2187196970Sphk	if (error != 0)
2188192873Sweongyo		goto fail;
2189196970Sphk	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
2190192873Sweongyo	if (error != 0)
2191192873Sweongyo		goto fail;
2192196970Sphk	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
2193196970Sphk		addrlen = 8;
2194196970Sphk		addrstr[0] = addr & (1 << 7);
2195196970Sphk		addrstr[1] = addr & (1 << 6);
2196196970Sphk		addrstr[2] = addr & (1 << 5);
2197196970Sphk		addrstr[3] = addr & (1 << 4);
2198196970Sphk		addrstr[4] = addr & (1 << 3);
2199196970Sphk		addrstr[5] = addr & (1 << 2);
2200196970Sphk		addrstr[6] = addr & (1 << 1);
2201196970Sphk		addrstr[7] = addr & (1 << 0);
2202196970Sphk	} else {
2203196970Sphk		addrlen=6;
2204196970Sphk		addrstr[0] = addr & (1 << 5);
2205196970Sphk		addrstr[1] = addr & (1 << 4);
2206196970Sphk		addrstr[2] = addr & (1 << 3);
2207196970Sphk		addrstr[3] = addr & (1 << 2);
2208196970Sphk		addrstr[4] = addr & (1 << 1);
2209196970Sphk		addrstr[5] = addr & (1 << 0);
2210196970Sphk	}
2211196970Sphk	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
2212192873Sweongyo	if (error != 0)
2213192873Sweongyo		goto fail;
2214196970Sphk
2215196970Sphk	error = urtw_eprom_writebit(sc, 0);
2216192873Sweongyo	if (error != 0)
2217192873Sweongyo		goto fail;
2218192873Sweongyo
2219196970Sphk	for (i = 0; i < 16; i++) {
2220196970Sphk		error = urtw_eprom_ck(sc);
2221196970Sphk		if (error != 0)
2222196970Sphk			goto fail;
2223196970Sphk		error = urtw_eprom_readbit(sc, &data16);
2224196970Sphk		if (error != 0)
2225196970Sphk			goto fail;
2226192873Sweongyo
2227196970Sphk		(*data) |= (data16 << (15 - i));
2228192873Sweongyo	}
2229192873Sweongyo
2230196970Sphk	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
2231196970Sphk	if (error != 0)
2232192873Sweongyo		goto fail;
2233196970Sphk	error = urtw_eprom_ck(sc);
2234196970Sphk	if (error != 0)
2235192873Sweongyo		goto fail;
2236192873Sweongyo
2237196970Sphk	/* now disable EPROM programming */
2238196970Sphk	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE);
2239192873Sweongyofail:
2240192873Sweongyo	return (error);
2241196970Sphk#undef URTW_READCMD_LEN
2242192873Sweongyo}
2243192873Sweongyo
2244193045Sthompsastatic usb_error_t
2245196970Sphkurtw_eprom_cs(struct urtw_softc *sc, int able)
2246192873Sweongyo{
2247196970Sphk	uint8_t data;
2248193045Sthompsa	usb_error_t error;
2249192873Sweongyo
2250196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2251196970Sphk	if (able == URTW_EPROM_ENABLE)
2252196970Sphk		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS);
2253196970Sphk	else
2254196970Sphk		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS);
2255196970Sphk	DELAY(URTW_EPROM_DELAY);
2256192873Sweongyofail:
2257192873Sweongyo	return (error);
2258192873Sweongyo}
2259192873Sweongyo
2260193045Sthompsastatic usb_error_t
2261196970Sphkurtw_eprom_ck(struct urtw_softc *sc)
2262192873Sweongyo{
2263192873Sweongyo	uint8_t data;
2264193045Sthompsa	usb_error_t error;
2265192873Sweongyo
2266196970Sphk	/* masking  */
2267196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2268196970Sphk	urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK);
2269196970Sphk	DELAY(URTW_EPROM_DELAY);
2270196970Sphk	/* unmasking  */
2271196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2272196970Sphk	urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK);
2273196970Sphk	DELAY(URTW_EPROM_DELAY);
2274192873Sweongyofail:
2275192873Sweongyo	return (error);
2276192873Sweongyo}
2277192873Sweongyo
2278193045Sthompsastatic usb_error_t
2279196970Sphkurtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
2280192873Sweongyo{
2281196970Sphk	uint8_t data8;
2282193045Sthompsa	usb_error_t error;
2283192873Sweongyo
2284196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data8);
2285196970Sphk	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
2286196970Sphk	DELAY(URTW_EPROM_DELAY);
2287192873Sweongyo
2288192873Sweongyofail:
2289192873Sweongyo	return (error);
2290192873Sweongyo}
2291192873Sweongyo
2292193045Sthompsastatic usb_error_t
2293196970Sphkurtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
2294192873Sweongyo{
2295192873Sweongyo	uint8_t data;
2296193045Sthompsa	usb_error_t error;
2297192873Sweongyo
2298196970Sphk	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2299196970Sphk	if (bit != 0)
2300196970Sphk		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT);
2301196970Sphk	else
2302196970Sphk		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT);
2303196970Sphk	DELAY(URTW_EPROM_DELAY);
2304192873Sweongyofail:
2305192873Sweongyo	return (error);
2306192873Sweongyo}
2307192873Sweongyo
2308193045Sthompsastatic usb_error_t
2309196970Sphkurtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
2310192873Sweongyo{
2311196970Sphk	int i = 0;
2312196970Sphk	usb_error_t error = 0;
2313192873Sweongyo
2314196970Sphk	for (i = 0; i < buflen; i++) {
2315196970Sphk		error = urtw_eprom_writebit(sc, buf[i]);
2316196970Sphk		if (error != 0)
2317196970Sphk			goto fail;
2318196970Sphk		error = urtw_eprom_ck(sc);
2319196970Sphk		if (error != 0)
2320196970Sphk			goto fail;
2321192873Sweongyo	}
2322192873Sweongyofail:
2323192873Sweongyo	return (error);
2324192873Sweongyo}
2325192873Sweongyo
2326192873Sweongyo
2327193045Sthompsastatic usb_error_t
2328192873Sweongyourtw_get_txpwr(struct urtw_softc *sc)
2329192873Sweongyo{
2330192873Sweongyo	int i, j;
2331192873Sweongyo	uint32_t data;
2332193045Sthompsa	usb_error_t error;
2333192873Sweongyo
2334192873Sweongyo	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
2335192873Sweongyo	if (error != 0)
2336192873Sweongyo		goto fail;
2337192873Sweongyo	sc->sc_txpwr_cck_base = data & 0xf;
2338192873Sweongyo	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
2339192873Sweongyo
2340192873Sweongyo	for (i = 1, j = 0; i < 6; i += 2, j++) {
2341192873Sweongyo		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
2342192873Sweongyo		if (error != 0)
2343192873Sweongyo			goto fail;
2344192873Sweongyo		sc->sc_txpwr_cck[i] = data & 0xf;
2345192873Sweongyo		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
2346192873Sweongyo		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
2347192873Sweongyo		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
2348192873Sweongyo	}
2349192873Sweongyo	for (i = 1, j = 0; i < 4; i += 2, j++) {
2350192873Sweongyo		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
2351192873Sweongyo		if (error != 0)
2352192873Sweongyo			goto fail;
2353192873Sweongyo		sc->sc_txpwr_cck[i + 6] = data & 0xf;
2354192873Sweongyo		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
2355192873Sweongyo		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
2356192873Sweongyo		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
2357192873Sweongyo	}
2358192873Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
2359192873Sweongyo		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2, &data);
2360192873Sweongyo		if (error != 0)
2361192873Sweongyo			goto fail;
2362192873Sweongyo		sc->sc_txpwr_cck[1 + 6 + 4] = data & 0xf;
2363192873Sweongyo		sc->sc_txpwr_ofdm[1 + 6 + 4] = (data & 0xf0) >> 4;
2364192873Sweongyo		error = urtw_eprom_read32(sc, 0x0a, &data);
2365192873Sweongyo		if (error != 0)
2366192873Sweongyo			goto fail;
2367192873Sweongyo		sc->sc_txpwr_cck[2 + 6 + 4] = data & 0xf;
2368192873Sweongyo		sc->sc_txpwr_ofdm[2 + 6 + 4] = (data & 0xf0) >> 4;
2369192873Sweongyo		error = urtw_eprom_read32(sc, 0x1c, &data);
2370192873Sweongyo		if (error != 0)
2371192873Sweongyo			goto fail;
2372192873Sweongyo		sc->sc_txpwr_cck[3 + 6 + 4] = data & 0xf;
2373192873Sweongyo		sc->sc_txpwr_cck[3 + 6 + 4 + 1] = (data & 0xf00) >> 8;
2374192873Sweongyo		sc->sc_txpwr_ofdm[3 + 6 + 4] = (data & 0xf0) >> 4;
2375192873Sweongyo		sc->sc_txpwr_ofdm[3 + 6 + 4 + 1] = (data & 0xf000) >> 12;
2376192873Sweongyo	} else {
2377192873Sweongyo		for (i = 1, j = 0; i < 4; i += 2, j++) {
2378192873Sweongyo			error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
2379192873Sweongyo			    &data);
2380192873Sweongyo			if (error != 0)
2381192873Sweongyo				goto fail;
2382192873Sweongyo			sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
2383192873Sweongyo			sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
2384192873Sweongyo			sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
2385192873Sweongyo			sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = (data & 0xf000) >> 12;
2386192873Sweongyo		}
2387192873Sweongyo	}
2388192873Sweongyofail:
2389192873Sweongyo	return (error);
2390192873Sweongyo}
2391192873Sweongyo
2392192873Sweongyo
2393193045Sthompsastatic usb_error_t
2394192873Sweongyourtw_get_rfchip(struct urtw_softc *sc)
2395192873Sweongyo{
2396192873Sweongyo	int ret;
2397192873Sweongyo	uint8_t data8;
2398192873Sweongyo	uint32_t data;
2399193045Sthompsa	usb_error_t error;
2400192873Sweongyo
2401198194Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
2402198194Sweongyo		urtw_read8_m(sc, 0xe1, &data8);
2403198194Sweongyo		switch (data8) {
2404198194Sweongyo		case 0:
2405198194Sweongyo			sc->sc_flags |= URTW_RTL8187B_REV_B;
2406198194Sweongyo			break;
2407198194Sweongyo		case 1:
2408198194Sweongyo			sc->sc_flags |= URTW_RTL8187B_REV_D;
2409198194Sweongyo			break;
2410198194Sweongyo		case 2:
2411198194Sweongyo			sc->sc_flags |= URTW_RTL8187B_REV_E;
2412198194Sweongyo			break;
2413198194Sweongyo		default:
2414198194Sweongyo			device_printf(sc->sc_dev, "unknown type: %#x\n", data8);
2415198194Sweongyo			sc->sc_flags |= URTW_RTL8187B_REV_B;
2416198194Sweongyo			break;
2417198194Sweongyo		}
2418198194Sweongyo	} else {
2419198194Sweongyo		urtw_read32_m(sc, URTW_TX_CONF, &data);
2420198194Sweongyo		switch (data & URTW_TX_HWMASK) {
2421198194Sweongyo		case URTW_TX_R8187vD_B:
2422198194Sweongyo			sc->sc_flags |= URTW_RTL8187B;
2423198194Sweongyo			break;
2424198194Sweongyo		case URTW_TX_R8187vD:
2425198194Sweongyo			break;
2426198194Sweongyo		default:
2427198194Sweongyo			device_printf(sc->sc_dev, "unknown RTL8187L type: %#x\n",
2428198194Sweongyo			    data & URTW_TX_HWMASK);
2429198194Sweongyo			break;
2430198194Sweongyo		}
2431198194Sweongyo	}
2432198194Sweongyo
2433192873Sweongyo	error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
2434192873Sweongyo	if (error != 0)
2435192873Sweongyo		goto fail;
2436192873Sweongyo	switch (data & 0xff) {
2437192873Sweongyo	case URTW_EPROM_RFCHIPID_RTL8225U:
2438192873Sweongyo		error = urtw_8225_isv2(sc, &ret);
2439192873Sweongyo		if (error != 0)
2440192873Sweongyo			goto fail;
2441192873Sweongyo		if (ret == 0) {
2442192873Sweongyo			sc->sc_rf_init = urtw_8225_rf_init;
2443192873Sweongyo			sc->sc_rf_set_sens = urtw_8225_rf_set_sens;
2444192873Sweongyo			sc->sc_rf_set_chan = urtw_8225_rf_set_chan;
2445192873Sweongyo			sc->sc_rf_stop = urtw_8225_rf_stop;
2446192873Sweongyo		} else {
2447192873Sweongyo			sc->sc_rf_init = urtw_8225v2_rf_init;
2448192873Sweongyo			sc->sc_rf_set_chan = urtw_8225v2_rf_set_chan;
2449192873Sweongyo			sc->sc_rf_stop = urtw_8225_rf_stop;
2450192873Sweongyo		}
2451192873Sweongyo		sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
2452192873Sweongyo		sc->sc_sens = URTW_8225_RF_DEF_SENS;
2453192873Sweongyo		break;
2454192873Sweongyo	case URTW_EPROM_RFCHIPID_RTL8225Z2:
2455192873Sweongyo		sc->sc_rf_init = urtw_8225v2b_rf_init;
2456192873Sweongyo		sc->sc_rf_set_chan = urtw_8225v2b_rf_set_chan;
2457192873Sweongyo		sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
2458192873Sweongyo		sc->sc_sens = URTW_8225_RF_DEF_SENS;
2459192873Sweongyo		sc->sc_rf_stop = urtw_8225_rf_stop;
2460192873Sweongyo		break;
2461192873Sweongyo	default:
2462259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
2463259456Shselasky		    "unsupported RF chip %d\n", data & 0xff);
2464259456Shselasky		error = USB_ERR_INVAL;
2465259456Shselasky		goto fail;
2466192873Sweongyo	}
2467192873Sweongyo
2468192873Sweongyo	device_printf(sc->sc_dev, "%s rf %s hwrev %s\n",
2469192873Sweongyo	    (sc->sc_flags & URTW_RTL8187B) ? "rtl8187b" : "rtl8187l",
2470192873Sweongyo	    ((data & 0xff) == URTW_EPROM_RFCHIPID_RTL8225U) ? "rtl8225u" :
2471192873Sweongyo	    "rtl8225z2",
2472192873Sweongyo	    (sc->sc_flags & URTW_RTL8187B) ? ((data8 == 0) ? "b" :
2473192873Sweongyo		(data8 == 1) ? "d" : "e") : "none");
2474192873Sweongyo
2475192873Sweongyofail:
2476192873Sweongyo	return (error);
2477192873Sweongyo}
2478192873Sweongyo
2479192873Sweongyo
2480193045Sthompsastatic usb_error_t
2481192873Sweongyourtw_led_init(struct urtw_softc *sc)
2482192873Sweongyo{
2483192873Sweongyo	uint32_t rev;
2484193045Sthompsa	usb_error_t error;
2485192873Sweongyo
2486192873Sweongyo	urtw_read8_m(sc, URTW_PSR, &sc->sc_psr);
2487192873Sweongyo	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
2488192873Sweongyo	if (error != 0)
2489192873Sweongyo		goto fail;
2490192873Sweongyo
2491192873Sweongyo	switch (rev & URTW_EPROM_CID_MASK) {
2492192873Sweongyo	case URTW_EPROM_CID_ALPHA0:
2493192873Sweongyo		sc->sc_strategy = URTW_SW_LED_MODE1;
2494192873Sweongyo		break;
2495192873Sweongyo	case URTW_EPROM_CID_SERCOMM_PS:
2496192873Sweongyo		sc->sc_strategy = URTW_SW_LED_MODE3;
2497192873Sweongyo		break;
2498192873Sweongyo	case URTW_EPROM_CID_HW_LED:
2499192873Sweongyo		sc->sc_strategy = URTW_HW_LED;
2500192873Sweongyo		break;
2501192873Sweongyo	case URTW_EPROM_CID_RSVD0:
2502192873Sweongyo	case URTW_EPROM_CID_RSVD1:
2503192873Sweongyo	default:
2504192873Sweongyo		sc->sc_strategy = URTW_SW_LED_MODE0;
2505192873Sweongyo		break;
2506192873Sweongyo	}
2507192873Sweongyo
2508192873Sweongyo	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
2509192873Sweongyo
2510192873Sweongyofail:
2511192873Sweongyo	return (error);
2512192873Sweongyo}
2513192873Sweongyo
2514196970Sphk
2515193045Sthompsastatic usb_error_t
2516196970Sphkurtw_8225_rf_init(struct urtw_softc *sc)
2517196970Sphk{
2518235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
2519196970Sphk	int i;
2520196970Sphk	uint16_t data;
2521196970Sphk	usb_error_t error;
2522196970Sphk
2523196970Sphk	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
2524196970Sphk	if (error)
2525196970Sphk		goto fail;
2526196970Sphk
2527196970Sphk	error = urtw_8225_usb_init(sc);
2528196970Sphk	if (error)
2529196970Sphk		goto fail;
2530196970Sphk
2531196970Sphk	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
2532196970Sphk	urtw_read16_m(sc, URTW_BRSR, &data);		/* XXX ??? */
2533196970Sphk	urtw_write16_m(sc, URTW_BRSR, 0xffff);
2534196970Sphk	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
2535196970Sphk
2536196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2537196970Sphk	if (error)
2538196970Sphk		goto fail;
2539196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
2540196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2541196970Sphk	if (error)
2542196970Sphk		goto fail;
2543196970Sphk
2544196970Sphk	error = urtw_8185_rf_pins_enable(sc);
2545196970Sphk	if (error)
2546196970Sphk		goto fail;
2547196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1000);
2548196970Sphk
2549196970Sphk	for (i = 0; i < N(urtw_8225_rf_part1); i++) {
2550196970Sphk		urtw_8225_write(sc, urtw_8225_rf_part1[i].reg,
2551196970Sphk		    urtw_8225_rf_part1[i].val);
2552196970Sphk		usb_pause_mtx(&sc->sc_mtx, 1);
2553196970Sphk	}
2554196970Sphk	usb_pause_mtx(&sc->sc_mtx, 100);
2555196970Sphk	urtw_8225_write(sc,
2556196970Sphk	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2557196970Sphk	usb_pause_mtx(&sc->sc_mtx, 200);
2558196970Sphk	urtw_8225_write(sc,
2559196970Sphk	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2560196970Sphk	usb_pause_mtx(&sc->sc_mtx, 200);
2561196970Sphk	urtw_8225_write(sc,
2562196970Sphk	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC3);
2563196970Sphk
2564196970Sphk	for (i = 0; i < 95; i++) {
2565196970Sphk		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
2566196970Sphk		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, urtw_8225_rxgain[i]);
2567196970Sphk	}
2568196970Sphk
2569196970Sphk	urtw_8225_write(sc,
2570196970Sphk	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC4);
2571196970Sphk	urtw_8225_write(sc,
2572196970Sphk	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC5);
2573196970Sphk
2574196970Sphk	for (i = 0; i < 128; i++) {
2575196970Sphk		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
2576196970Sphk		usb_pause_mtx(&sc->sc_mtx, 1);
2577196970Sphk		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
2578196970Sphk		usb_pause_mtx(&sc->sc_mtx, 1);
2579196970Sphk	}
2580196970Sphk
2581196970Sphk	for (i = 0; i < N(urtw_8225_rf_part2); i++) {
2582196970Sphk		urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg,
2583196970Sphk		    urtw_8225_rf_part2[i].val);
2584196970Sphk		usb_pause_mtx(&sc->sc_mtx, 1);
2585196970Sphk	}
2586196970Sphk
2587196970Sphk	error = urtw_8225_setgain(sc, 4);
2588196970Sphk	if (error)
2589196970Sphk		goto fail;
2590196970Sphk
2591196970Sphk	for (i = 0; i < N(urtw_8225_rf_part3); i++) {
2592196970Sphk		urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg,
2593196970Sphk		    urtw_8225_rf_part3[i].val);
2594196970Sphk		usb_pause_mtx(&sc->sc_mtx, 1);
2595196970Sphk	}
2596196970Sphk
2597196970Sphk	urtw_write8_m(sc, URTW_TESTR, 0x0d);
2598196970Sphk
2599196970Sphk	error = urtw_8225_set_txpwrlvl(sc, 1);
2600196970Sphk	if (error)
2601196970Sphk		goto fail;
2602196970Sphk
2603196970Sphk	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
2604196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
2605196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
2606196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
2607196970Sphk
2608196970Sphk	/* TX ant A, 0x0 for B */
2609196970Sphk	error = urtw_8185_tx_antenna(sc, 0x3);
2610196970Sphk	if (error)
2611196970Sphk		goto fail;
2612196970Sphk	urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
2613196970Sphk
2614196970Sphk	error = urtw_8225_rf_set_chan(sc, 1);
2615196970Sphkfail:
2616196970Sphk	return (error);
2617196970Sphk#undef N
2618196970Sphk}
2619196970Sphk
2620196970Sphkstatic usb_error_t
2621192873Sweongyourtw_8185_rf_pins_enable(struct urtw_softc *sc)
2622192873Sweongyo{
2623193045Sthompsa	usb_error_t error = 0;
2624192873Sweongyo
2625192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7);
2626192873Sweongyofail:
2627192873Sweongyo	return (error);
2628192873Sweongyo}
2629192873Sweongyo
2630193045Sthompsastatic usb_error_t
2631192873Sweongyourtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
2632192873Sweongyo{
2633193045Sthompsa	usb_error_t error;
2634192873Sweongyo
2635192873Sweongyo	urtw_write8_m(sc, URTW_TX_ANTENNA, ant);
2636194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 1);
2637192873Sweongyofail:
2638192873Sweongyo	return (error);
2639192873Sweongyo}
2640192873Sweongyo
2641193045Sthompsastatic usb_error_t
2642192873Sweongyourtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2643192873Sweongyo{
2644192873Sweongyo
2645192873Sweongyo	data = data & 0xff;
2646192873Sweongyo	return urtw_8187_write_phy(sc, addr, data);
2647192873Sweongyo}
2648192873Sweongyo
2649193045Sthompsastatic usb_error_t
2650192873Sweongyourtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2651192873Sweongyo{
2652192873Sweongyo
2653192873Sweongyo	data = data & 0xff;
2654192873Sweongyo	return urtw_8187_write_phy(sc, addr, data | 0x10000);
2655192873Sweongyo}
2656192873Sweongyo
2657193045Sthompsastatic usb_error_t
2658192873Sweongyourtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2659192873Sweongyo{
2660192873Sweongyo	uint32_t phyw;
2661193045Sthompsa	usb_error_t error;
2662192873Sweongyo
2663192873Sweongyo	phyw = ((data << 8) | (addr | 0x80));
2664192873Sweongyo	urtw_write8_m(sc, URTW_PHY_MAGIC4, ((phyw & 0xff000000) >> 24));
2665192873Sweongyo	urtw_write8_m(sc, URTW_PHY_MAGIC3, ((phyw & 0x00ff0000) >> 16));
2666192873Sweongyo	urtw_write8_m(sc, URTW_PHY_MAGIC2, ((phyw & 0x0000ff00) >> 8));
2667192873Sweongyo	urtw_write8_m(sc, URTW_PHY_MAGIC1, ((phyw & 0x000000ff)));
2668194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 1);
2669192873Sweongyofail:
2670192873Sweongyo	return (error);
2671192873Sweongyo}
2672192873Sweongyo
2673193045Sthompsastatic usb_error_t
2674192873Sweongyourtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
2675192873Sweongyo{
2676193045Sthompsa	usb_error_t error;
2677192873Sweongyo
2678192873Sweongyo	urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]);
2679192873Sweongyo	urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]);
2680192873Sweongyo	urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]);
2681192873Sweongyo	urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]);
2682192873Sweongyofail:
2683192873Sweongyo	return (error);
2684192873Sweongyo}
2685192873Sweongyo
2686193045Sthompsastatic usb_error_t
2687192873Sweongyourtw_8225_usb_init(struct urtw_softc *sc)
2688192873Sweongyo{
2689192873Sweongyo	uint8_t data;
2690193045Sthompsa	usb_error_t error;
2691192873Sweongyo
2692192873Sweongyo	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0);
2693192873Sweongyo	urtw_write8_m(sc, URTW_GPIO, 0);
2694192873Sweongyo	error = urtw_read8e(sc, 0x53, &data);
2695192873Sweongyo	if (error)
2696192873Sweongyo		goto fail;
2697192873Sweongyo	error = urtw_write8e(sc, 0x53, data | (1 << 7));
2698192873Sweongyo	if (error)
2699192873Sweongyo		goto fail;
2700192873Sweongyo	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4);
2701192873Sweongyo	urtw_write8_m(sc, URTW_GPIO, 0x20);
2702192873Sweongyo	urtw_write8_m(sc, URTW_GP_ENABLE, 0);
2703192873Sweongyo
2704192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80);
2705192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80);
2706192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80);
2707192873Sweongyo
2708194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 500);
2709192873Sweongyofail:
2710192873Sweongyo	return (error);
2711192873Sweongyo}
2712192873Sweongyo
2713193045Sthompsastatic usb_error_t
2714192873Sweongyourtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
2715192873Sweongyo{
2716192873Sweongyo	uint16_t d80, d82, d84;
2717193045Sthompsa	usb_error_t error;
2718192873Sweongyo
2719192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80);
2720192873Sweongyo	d80 &= URTW_RF_PINS_MAGIC1;
2721192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82);
2722192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84);
2723192873Sweongyo	d84 &= URTW_RF_PINS_MAGIC2;
2724192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | URTW_RF_PINS_MAGIC3);
2725192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | URTW_RF_PINS_MAGIC3);
2726192873Sweongyo	DELAY(10);
2727192873Sweongyo
2728192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2729192873Sweongyo	DELAY(2);
2730192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80);
2731192873Sweongyo	DELAY(10);
2732192873Sweongyo
2733192873Sweongyo	error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
2734192873Sweongyo	if (error != 0)
2735192873Sweongyo		goto fail;
2736192873Sweongyo
2737192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2738192873Sweongyo	DELAY(10);
2739192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2740192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84);
2741194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 2);
2742192873Sweongyofail:
2743192873Sweongyo	return (error);
2744192873Sweongyo}
2745192873Sweongyo
2746193045Sthompsastatic usb_error_t
2747192873Sweongyourtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
2748192873Sweongyo    uint16_t *data)
2749192873Sweongyo{
2750259454Shselasky	uint8_t buf[2];
2751192873Sweongyo	uint16_t data16;
2752259454Shselasky	struct usb_device_request req;
2753193045Sthompsa	usb_error_t error = 0;
2754192873Sweongyo
2755192873Sweongyo	data16 = *data;
2756192873Sweongyo
2757259454Shselasky	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2758259454Shselasky	req.bRequest = URTW_8187_SETREGS_REQ;
2759259454Shselasky	USETW(req.wValue, addr);
2760259454Shselasky	USETW(req.wIndex, index);
2761259454Shselasky	USETW(req.wLength, sizeof(uint16_t));
2762192873Sweongyo	buf[0] = (data16 & 0x00ff);
2763192873Sweongyo	buf[1] = (data16 & 0xff00) >> 8;
2764192873Sweongyo
2765259454Shselasky	error = urtw_do_request(sc, &req, buf);
2766192873Sweongyo
2767259454Shselasky	return (error);
2768192873Sweongyo}
2769192873Sweongyo
2770193045Sthompsastatic usb_error_t
2771192873Sweongyourtw_8225_rf_set_chan(struct urtw_softc *sc, int chan)
2772192873Sweongyo{
2773193045Sthompsa	usb_error_t error;
2774192873Sweongyo
2775192873Sweongyo	error = urtw_8225_set_txpwrlvl(sc, chan);
2776192873Sweongyo	if (error)
2777192873Sweongyo		goto fail;
2778192873Sweongyo	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
2779194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 10);
2780192873Sweongyofail:
2781192873Sweongyo	return (error);
2782192873Sweongyo}
2783192873Sweongyo
2784193045Sthompsastatic usb_error_t
2785192873Sweongyourtw_8225_rf_set_sens(struct urtw_softc *sc, int sens)
2786192873Sweongyo{
2787193045Sthompsa	usb_error_t error;
2788192873Sweongyo
2789192873Sweongyo	if (sens < 0 || sens > 6)
2790192873Sweongyo		return -1;
2791192873Sweongyo
2792192873Sweongyo	if (sens > 4)
2793192873Sweongyo		urtw_8225_write(sc,
2794192873Sweongyo		    URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC1);
2795192873Sweongyo	else
2796192873Sweongyo		urtw_8225_write(sc,
2797192873Sweongyo		    URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC2);
2798192873Sweongyo
2799192873Sweongyo	sens = 6 - sens;
2800192873Sweongyo	error = urtw_8225_setgain(sc, sens);
2801192873Sweongyo	if (error)
2802192873Sweongyo		goto fail;
2803192873Sweongyo
2804192873Sweongyo	urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[sens]);
2805192873Sweongyo
2806192873Sweongyofail:
2807192873Sweongyo	return (error);
2808192873Sweongyo}
2809192873Sweongyo
2810196970Sphkstatic usb_error_t
2811196970Sphkurtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
2812192873Sweongyo{
2813196970Sphk	int i, idx, set;
2814196970Sphk	uint8_t *cck_pwltable;
2815196970Sphk	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
2816196970Sphk	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
2817196970Sphk	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
2818193045Sthompsa	usb_error_t error;
2819192873Sweongyo
2820196970Sphk	cck_pwrlvl_max = 11;
2821196970Sphk	ofdm_pwrlvl_max = 25;	/* 12 -> 25  */
2822196970Sphk	ofdm_pwrlvl_min = 10;
2823192873Sweongyo
2824196970Sphk	/* CCK power setting */
2825196970Sphk	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
2826196970Sphk	idx = cck_pwrlvl % 6;
2827196970Sphk	set = cck_pwrlvl / 6;
2828196970Sphk	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
2829196970Sphk	    urtw_8225_txpwr_cck;
2830192873Sweongyo
2831196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
2832196970Sphk	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2833196970Sphk	for (i = 0; i < 8; i++) {
2834196970Sphk		urtw_8187_write_phy_cck(sc, 0x44 + i,
2835196970Sphk		    cck_pwltable[idx * 8 + i]);
2836192873Sweongyo	}
2837196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
2838192873Sweongyo
2839196970Sphk	/* OFDM power setting */
2840196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
2841196970Sphk	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
2842196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
2843192873Sweongyo
2844196970Sphk	idx = ofdm_pwrlvl % 6;
2845196970Sphk	set = ofdm_pwrlvl / 6;
2846192873Sweongyo
2847196970Sphk	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
2848196970Sphk	if (error)
2849196970Sphk		goto fail;
2850196970Sphk	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
2851196970Sphk	urtw_8187_write_phy_ofdm(sc, 6, 0);
2852196970Sphk	urtw_8187_write_phy_ofdm(sc, 8, 0);
2853192873Sweongyo
2854196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
2855196970Sphk	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2856196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]);
2857196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]);
2858194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 1);
2859192873Sweongyofail:
2860192873Sweongyo	return (error);
2861192873Sweongyo}
2862192873Sweongyo
2863196970Sphk
2864193045Sthompsastatic usb_error_t
2865196970Sphkurtw_8225_rf_stop(struct urtw_softc *sc)
2866192873Sweongyo{
2867196970Sphk	uint8_t data;
2868193045Sthompsa	usb_error_t error;
2869192873Sweongyo
2870196970Sphk	urtw_8225_write(sc, 0x4, 0x1f);
2871192873Sweongyo
2872196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2873196970Sphk	if (error)
2874196970Sphk		goto fail;
2875192873Sweongyo
2876196970Sphk	urtw_read8_m(sc, URTW_CONFIG3, &data);
2877196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
2878196970Sphk	if (sc->sc_flags & URTW_RTL8187B) {
2879196970Sphk		urtw_write32_m(sc, URTW_ANAPARAM2,
2880196970Sphk		    URTW_8187B_8225_ANAPARAM2_OFF);
2881196970Sphk		urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_OFF);
2882196970Sphk		urtw_write32_m(sc, URTW_ANAPARAM3,
2883196970Sphk		    URTW_8187B_8225_ANAPARAM3_OFF);
2884196970Sphk	} else {
2885196970Sphk		urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8225_ANAPARAM2_OFF);
2886196970Sphk		urtw_write32_m(sc, URTW_ANAPARAM, URTW_8225_ANAPARAM_OFF);
2887196970Sphk	}
2888192873Sweongyo
2889196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
2890196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2891192873Sweongyo	if (error)
2892192873Sweongyo		goto fail;
2893192873Sweongyo
2894192873Sweongyofail:
2895192873Sweongyo	return (error);
2896192873Sweongyo}
2897192873Sweongyo
2898193045Sthompsastatic usb_error_t
2899192873Sweongyourtw_8225v2_rf_init(struct urtw_softc *sc)
2900192873Sweongyo{
2901235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
2902192873Sweongyo	int i;
2903192873Sweongyo	uint16_t data;
2904192873Sweongyo	uint32_t data32;
2905193045Sthompsa	usb_error_t error;
2906192873Sweongyo
2907192873Sweongyo	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
2908192873Sweongyo	if (error)
2909192873Sweongyo		goto fail;
2910192873Sweongyo
2911192873Sweongyo	error = urtw_8225_usb_init(sc);
2912192873Sweongyo	if (error)
2913192873Sweongyo		goto fail;
2914192873Sweongyo
2915192873Sweongyo	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
2916192873Sweongyo	urtw_read16_m(sc, URTW_BRSR, &data);		/* XXX ??? */
2917192873Sweongyo	urtw_write16_m(sc, URTW_BRSR, 0xffff);
2918192873Sweongyo	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
2919192873Sweongyo
2920192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2921192873Sweongyo	if (error)
2922192873Sweongyo		goto fail;
2923192873Sweongyo	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
2924192873Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2925192873Sweongyo	if (error)
2926192873Sweongyo		goto fail;
2927192873Sweongyo
2928192873Sweongyo	error = urtw_8185_rf_pins_enable(sc);
2929192873Sweongyo	if (error)
2930192873Sweongyo		goto fail;
2931192873Sweongyo
2932194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 500);
2933192873Sweongyo
2934196970Sphk	for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
2935192873Sweongyo		urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg,
2936192873Sweongyo		    urtw_8225v2_rf_part1[i].val);
2937192873Sweongyo	}
2938194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 50);
2939192873Sweongyo
2940192873Sweongyo	urtw_8225_write(sc,
2941192873Sweongyo	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC1);
2942192873Sweongyo
2943192873Sweongyo	for (i = 0; i < 95; i++) {
2944192873Sweongyo		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
2945192873Sweongyo		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
2946192873Sweongyo		    urtw_8225v2_rxgain[i]);
2947192873Sweongyo	}
2948192873Sweongyo
2949192873Sweongyo	urtw_8225_write(sc,
2950192873Sweongyo	    URTW_8225_ADDR_3_MAGIC, URTW_8225_ADDR_3_DATA_MAGIC1);
2951192873Sweongyo	urtw_8225_write(sc,
2952192873Sweongyo	    URTW_8225_ADDR_5_MAGIC, URTW_8225_ADDR_5_DATA_MAGIC1);
2953192873Sweongyo	urtw_8225_write(sc,
2954192873Sweongyo	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC2);
2955192873Sweongyo	urtw_8225_write(sc,
2956192873Sweongyo	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2957194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 100);
2958192873Sweongyo	urtw_8225_write(sc,
2959192873Sweongyo	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2960194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 100);
2961192873Sweongyo
2962192873Sweongyo	error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
2963192873Sweongyo	if (error != 0)
2964192873Sweongyo		goto fail;
2965192873Sweongyo	if (data32 != URTW_8225_ADDR_6_DATA_MAGIC1)
2966192873Sweongyo		device_printf(sc->sc_dev, "expect 0xe6!! (0x%x)\n", data32);
2967192873Sweongyo	if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2)) {
2968192873Sweongyo		urtw_8225_write(sc,
2969192873Sweongyo		    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2970194228Sthompsa		usb_pause_mtx(&sc->sc_mtx, 100);
2971192873Sweongyo		urtw_8225_write(sc,
2972192873Sweongyo		    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2973194228Sthompsa		usb_pause_mtx(&sc->sc_mtx, 50);
2974192873Sweongyo		error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
2975192873Sweongyo		if (error != 0)
2976192873Sweongyo			goto fail;
2977192873Sweongyo		if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2))
2978192873Sweongyo			device_printf(sc->sc_dev, "RF calibration failed\n");
2979192873Sweongyo	}
2980194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 100);
2981192873Sweongyo
2982192873Sweongyo	urtw_8225_write(sc,
2983192873Sweongyo	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC6);
2984192873Sweongyo	for (i = 0; i < 128; i++) {
2985192873Sweongyo		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
2986192873Sweongyo		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
2987192873Sweongyo	}
2988192873Sweongyo
2989196970Sphk	for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
2990192873Sweongyo		urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg,
2991192873Sweongyo		    urtw_8225v2_rf_part2[i].val);
2992192873Sweongyo	}
2993192873Sweongyo
2994192873Sweongyo	error = urtw_8225v2_setgain(sc, 4);
2995192873Sweongyo	if (error)
2996192873Sweongyo		goto fail;
2997192873Sweongyo
2998196970Sphk	for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
2999192873Sweongyo		urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg,
3000192873Sweongyo		    urtw_8225v2_rf_part3[i].val);
3001192873Sweongyo	}
3002192873Sweongyo
3003192873Sweongyo	urtw_write8_m(sc, URTW_TESTR, 0x0d);
3004192873Sweongyo
3005192873Sweongyo	error = urtw_8225v2_set_txpwrlvl(sc, 1);
3006192873Sweongyo	if (error)
3007192873Sweongyo		goto fail;
3008192873Sweongyo
3009192873Sweongyo	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
3010192873Sweongyo	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
3011192873Sweongyo
3012192873Sweongyo	/* TX ant A, 0x0 for B */
3013192873Sweongyo	error = urtw_8185_tx_antenna(sc, 0x3);
3014192873Sweongyo	if (error)
3015192873Sweongyo		goto fail;
3016192873Sweongyo	urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
3017192873Sweongyo
3018192873Sweongyo	error = urtw_8225_rf_set_chan(sc, 1);
3019192873Sweongyofail:
3020192873Sweongyo	return (error);
3021196970Sphk#undef N
3022192873Sweongyo}
3023192873Sweongyo
3024193045Sthompsastatic usb_error_t
3025192873Sweongyourtw_8225v2_rf_set_chan(struct urtw_softc *sc, int chan)
3026192873Sweongyo{
3027193045Sthompsa	usb_error_t error;
3028192873Sweongyo
3029192873Sweongyo	error = urtw_8225v2_set_txpwrlvl(sc, chan);
3030192873Sweongyo	if (error)
3031192873Sweongyo		goto fail;
3032192873Sweongyo
3033192873Sweongyo	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
3034194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 10);
3035192873Sweongyofail:
3036192873Sweongyo	return (error);
3037192873Sweongyo}
3038192873Sweongyo
3039193045Sthompsastatic usb_error_t
3040192873Sweongyourtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
3041192873Sweongyo{
3042192873Sweongyo	int i;
3043192873Sweongyo	int16_t bit;
3044192873Sweongyo	uint8_t rlen = 12, wlen = 6;
3045192873Sweongyo	uint16_t o1, o2, o3, tmp;
3046192873Sweongyo	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
3047192873Sweongyo	uint32_t mask = 0x80000000, value = 0;
3048193045Sthompsa	usb_error_t error;
3049192873Sweongyo
3050192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1);
3051192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2);
3052192873Sweongyo	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3);
3053192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | URTW_RF_PINS_MAGIC4);
3054192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | URTW_RF_PINS_MAGIC4);
3055192873Sweongyo	o1 &= ~URTW_RF_PINS_MAGIC4;
3056192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN);
3057192873Sweongyo	DELAY(5);
3058192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1);
3059192873Sweongyo	DELAY(5);
3060192873Sweongyo
3061192873Sweongyo	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
3062192873Sweongyo		bit = ((d2w & mask) != 0) ? 1 : 0;
3063192873Sweongyo
3064192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
3065192873Sweongyo		DELAY(2);
3066192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3067192873Sweongyo		    URTW_BB_HOST_BANG_CLK);
3068192873Sweongyo		DELAY(2);
3069192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3070192873Sweongyo		    URTW_BB_HOST_BANG_CLK);
3071192873Sweongyo		DELAY(2);
3072192873Sweongyo		mask = mask >> 1;
3073192873Sweongyo		if (i == 2)
3074192873Sweongyo			break;
3075192873Sweongyo		bit = ((d2w & mask) != 0) ? 1 : 0;
3076192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3077192873Sweongyo		    URTW_BB_HOST_BANG_CLK);
3078192873Sweongyo		DELAY(2);
3079192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3080192873Sweongyo		    URTW_BB_HOST_BANG_CLK);
3081192873Sweongyo		DELAY(2);
3082192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
3083192873Sweongyo		DELAY(1);
3084192873Sweongyo	}
3085192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW |
3086192873Sweongyo	    URTW_BB_HOST_BANG_CLK);
3087192873Sweongyo	DELAY(2);
3088192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW);
3089192873Sweongyo	DELAY(2);
3090192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW);
3091192873Sweongyo	DELAY(2);
3092192873Sweongyo
3093192873Sweongyo	mask = 0x800;
3094192873Sweongyo	for (i = 0; i < rlen; i++, mask = mask >> 1) {
3095192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3096192873Sweongyo		    o1 | URTW_BB_HOST_BANG_RW);
3097192873Sweongyo		DELAY(2);
3098192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3099192873Sweongyo		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3100192873Sweongyo		DELAY(2);
3101192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3102192873Sweongyo		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3103192873Sweongyo		DELAY(2);
3104192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3105192873Sweongyo		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3106192873Sweongyo		DELAY(2);
3107192873Sweongyo
3108192873Sweongyo		urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp);
3109192873Sweongyo		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
3110192873Sweongyo		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3111192873Sweongyo		    o1 | URTW_BB_HOST_BANG_RW);
3112192873Sweongyo		DELAY(2);
3113192873Sweongyo	}
3114192873Sweongyo
3115192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN |
3116192873Sweongyo	    URTW_BB_HOST_BANG_RW);
3117192873Sweongyo	DELAY(2);
3118192873Sweongyo
3119192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2);
3120192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3);
3121192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_OUTPUT_MAGIC1);
3122192873Sweongyo
3123192873Sweongyo	if (data != NULL)
3124192873Sweongyo		*data = value;
3125192873Sweongyofail:
3126192873Sweongyo	return (error);
3127192873Sweongyo}
3128192873Sweongyo
3129192873Sweongyo
3130193045Sthompsastatic usb_error_t
3131196970Sphkurtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
3132196970Sphk{
3133196970Sphk	int i;
3134196970Sphk	uint8_t *cck_pwrtable;
3135196970Sphk	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
3136196970Sphk	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3137196970Sphk	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3138196970Sphk	usb_error_t error;
3139196970Sphk
3140196970Sphk	/* CCK power setting */
3141196970Sphk	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
3142196970Sphk	cck_pwrlvl += sc->sc_txpwr_cck_base;
3143196970Sphk	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3144196970Sphk	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3145196970Sphk	    urtw_8225v2_txpwr_cck;
3146196970Sphk
3147196970Sphk	for (i = 0; i < 8; i++)
3148196970Sphk		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3149196970Sphk
3150196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3151196970Sphk	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]);
3152196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3153196970Sphk
3154196970Sphk	/* OFDM power setting */
3155196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3156196970Sphk		ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3157196970Sphk	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3158196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3159196970Sphk
3160196970Sphk	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3161196970Sphk	if (error)
3162196970Sphk		goto fail;
3163196970Sphk
3164196970Sphk	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
3165196970Sphk	urtw_8187_write_phy_ofdm(sc, 5, 0x0);
3166196970Sphk	urtw_8187_write_phy_ofdm(sc, 6, 0x40);
3167196970Sphk	urtw_8187_write_phy_ofdm(sc, 7, 0x0);
3168196970Sphk	urtw_8187_write_phy_ofdm(sc, 8, 0x40);
3169196970Sphk
3170196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3171196970Sphk	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]);
3172196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3173196970Sphkfail:
3174196970Sphk	return (error);
3175196970Sphk}
3176196970Sphk
3177196970Sphkstatic usb_error_t
3178196970Sphkurtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
3179196970Sphk{
3180196970Sphk	uint8_t *gainp;
3181196970Sphk	usb_error_t error;
3182196970Sphk
3183196970Sphk	/* XXX for A?  */
3184196970Sphk	gainp = urtw_8225v2_gain_bg;
3185196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]);
3186196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3187196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]);
3188196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3189196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]);
3190196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3191196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x21, 0x17);
3192196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3193196970Sphkfail:
3194196970Sphk	return (error);
3195196970Sphk}
3196196970Sphk
3197196970Sphkstatic usb_error_t
3198192873Sweongyourtw_8225_isv2(struct urtw_softc *sc, int *ret)
3199192873Sweongyo{
3200192873Sweongyo	uint32_t data;
3201193045Sthompsa	usb_error_t error;
3202192873Sweongyo
3203192873Sweongyo	*ret = 1;
3204192873Sweongyo
3205192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_MAGIC5);
3206192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, URTW_RF_PINS_MAGIC5);
3207192873Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, URTW_RF_PINS_MAGIC5);
3208194228Sthompsa	usb_pause_mtx(&sc->sc_mtx, 500);
3209192873Sweongyo
3210192873Sweongyo	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
3211192873Sweongyo	    URTW_8225_ADDR_0_DATA_MAGIC1);
3212192873Sweongyo
3213192873Sweongyo	error = urtw_8225_read(sc, URTW_8225_ADDR_8_MAGIC, &data);
3214192873Sweongyo	if (error != 0)
3215192873Sweongyo		goto fail;
3216192873Sweongyo	if (data != URTW_8225_ADDR_8_DATA_MAGIC1)
3217192873Sweongyo		*ret = 0;
3218192873Sweongyo	else {
3219192873Sweongyo		error = urtw_8225_read(sc, URTW_8225_ADDR_9_MAGIC, &data);
3220192873Sweongyo		if (error != 0)
3221192873Sweongyo			goto fail;
3222192873Sweongyo		if (data != URTW_8225_ADDR_9_DATA_MAGIC1)
3223192873Sweongyo			*ret = 0;
3224192873Sweongyo	}
3225192873Sweongyo
3226192873Sweongyo	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
3227192873Sweongyo	    URTW_8225_ADDR_0_DATA_MAGIC2);
3228192873Sweongyofail:
3229192873Sweongyo	return (error);
3230192873Sweongyo}
3231196970Sphk
3232196970Sphkstatic usb_error_t
3233196970Sphkurtw_8225v2b_rf_init(struct urtw_softc *sc)
3234196970Sphk{
3235235000Shselasky#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
3236196970Sphk	int i;
3237198194Sweongyo	uint8_t data8;
3238196970Sphk	usb_error_t error;
3239196970Sphk
3240198194Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3241198194Sweongyo	if (error)
3242198194Sweongyo		goto fail;
3243198194Sweongyo
3244198194Sweongyo	/*
3245198194Sweongyo	 * initialize extra registers on 8187
3246198194Sweongyo	 */
3247198194Sweongyo	urtw_write16_m(sc, URTW_BRSR_8187B, 0xfff);
3248198194Sweongyo
3249198194Sweongyo	/* retry limit */
3250198194Sweongyo	urtw_read8_m(sc, URTW_CW_CONF, &data8);
3251198194Sweongyo	data8 |= URTW_CW_CONF_PERPACKET_RETRY;
3252198194Sweongyo	urtw_write8_m(sc, URTW_CW_CONF, data8);
3253198194Sweongyo
3254198194Sweongyo	/* TX AGC */
3255198194Sweongyo	urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
3256198194Sweongyo	data8 |= URTW_TX_AGC_CTL_PERPACKET_GAIN;
3257198194Sweongyo	urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
3258198194Sweongyo
3259198194Sweongyo	/* Auto Rate Fallback Control */
3260198194Sweongyo#define	URTW_ARFR	0x1e0
3261198194Sweongyo	urtw_write16_m(sc, URTW_ARFR, 0xfff);
3262198194Sweongyo	urtw_read8_m(sc, URTW_RATE_FALLBACK, &data8);
3263198194Sweongyo	urtw_write8_m(sc, URTW_RATE_FALLBACK,
3264198194Sweongyo	    data8 | URTW_RATE_FALLBACK_ENABLE);
3265198194Sweongyo
3266198194Sweongyo	urtw_read8_m(sc, URTW_MSR, &data8);
3267198194Sweongyo	urtw_write8_m(sc, URTW_MSR, data8 & 0xf3);
3268198194Sweongyo	urtw_read8_m(sc, URTW_MSR, &data8);
3269198194Sweongyo	urtw_write8_m(sc, URTW_MSR, data8 | URTW_MSR_LINK_ENEDCA);
3270198194Sweongyo	urtw_write8_m(sc, URTW_ACM_CONTROL, sc->sc_acmctl);
3271198194Sweongyo
3272198194Sweongyo	urtw_write16_m(sc, URTW_ATIM_WND, 2);
3273198194Sweongyo	urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
3274198194Sweongyo#define	URTW_FEMR_FOR_8187B	0x1d4
3275198194Sweongyo	urtw_write16_m(sc, URTW_FEMR_FOR_8187B, 0xffff);
3276198194Sweongyo
3277198194Sweongyo	/* led type */
3278198194Sweongyo	urtw_read8_m(sc, URTW_CONFIG1, &data8);
3279198194Sweongyo	data8 = (data8 & 0x3f) | 0x80;
3280198194Sweongyo	urtw_write8_m(sc, URTW_CONFIG1, data8);
3281198194Sweongyo
3282198194Sweongyo	/* applying MAC address again.  */
3283198194Sweongyo	urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]);
3284198194Sweongyo	urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff);
3285198194Sweongyo
3286198194Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3287198194Sweongyo	if (error)
3288198194Sweongyo		goto fail;
3289198194Sweongyo
3290198194Sweongyo	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
3291198194Sweongyo
3292198194Sweongyo	/*
3293198194Sweongyo	 * MAC configuration
3294198194Sweongyo	 */
3295196970Sphk	for (i = 0; i < N(urtw_8225v2b_rf_part1); i++)
3296198194Sweongyo		urtw_write8_m(sc, urtw_8225v2b_rf_part1[i].reg,
3297196970Sphk		    urtw_8225v2b_rf_part1[i].val);
3298198194Sweongyo	urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50);
3299198194Sweongyo	urtw_write16_m(sc, URTW_INT_MIG, 0x0000);
3300198194Sweongyo	urtw_write32_m(sc, 0x1f0, 0);
3301198194Sweongyo	urtw_write32_m(sc, 0x1f4, 0);
3302198194Sweongyo	urtw_write8_m(sc, 0x1f8, 0);
3303198194Sweongyo	urtw_write32_m(sc, URTW_RF_TIMING, 0x4001);
3304196970Sphk
3305198194Sweongyo#define	URTW_RFSW_CTRL	0x272
3306198194Sweongyo	urtw_write16_m(sc, URTW_RFSW_CTRL, 0x569a);
3307196970Sphk
3308198194Sweongyo	/*
3309198194Sweongyo	 * initialize PHY
3310198194Sweongyo	 */
3311198194Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3312198194Sweongyo	if (error)
3313198194Sweongyo		goto fail;
3314198194Sweongyo	urtw_read8_m(sc, URTW_CONFIG3, &data8);
3315198194Sweongyo	urtw_write8_m(sc, URTW_CONFIG3,
3316198194Sweongyo	    data8 | URTW_CONFIG3_ANAPARAM_WRITE);
3317198194Sweongyo
3318198194Sweongyo	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3319198194Sweongyo	if (error)
3320198194Sweongyo		goto fail;
3321198194Sweongyo
3322198194Sweongyo	/* setup RFE initial timing */
3323198194Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480);
3324198194Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488);
3325198194Sweongyo	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff);
3326198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1100);
3327198194Sweongyo
3328198194Sweongyo	for (i = 0; i < N(urtw_8225v2b_rf_part0); i++) {
3329198194Sweongyo		urtw_8225_write(sc, urtw_8225v2b_rf_part0[i].reg,
3330198194Sweongyo		    urtw_8225v2b_rf_part0[i].val);
3331198194Sweongyo		usb_pause_mtx(&sc->sc_mtx, 1);
3332198194Sweongyo	}
3333198194Sweongyo	urtw_8225_write(sc, 0x00, 0x01b7);
3334198194Sweongyo
3335198194Sweongyo	for (i = 0; i < 95; i++) {
3336196970Sphk		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
3337198194Sweongyo		usb_pause_mtx(&sc->sc_mtx, 1);
3338196970Sphk		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
3339196970Sphk		    urtw_8225v2b_rxgain[i]);
3340198194Sweongyo		usb_pause_mtx(&sc->sc_mtx, 1);
3341196970Sphk	}
3342196970Sphk
3343196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_3_MAGIC, 0x080);
3344198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1);
3345196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_5_MAGIC, 0x004);
3346198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1);
3347196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x0b7);
3348198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1);
3349198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 3000);
3350196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0xc4d);
3351198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 2000);
3352196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0x44d);
3353198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1);
3354196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x2bf);
3355198194Sweongyo	usb_pause_mtx(&sc->sc_mtx, 1);
3356196970Sphk
3357196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03);
3358196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07);
3359196970Sphk	urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03);
3360196970Sphk
3361196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x80, 0x12);
3362198194Sweongyo	for (i = 0; i < 128; i++) {
3363198194Sweongyo		uint32_t addr, data;
3364198194Sweongyo
3365198194Sweongyo		data = (urtw_8225z2_agc[i] << 8) | 0x0000008f;
3366198194Sweongyo		addr = ((i + 0x80) << 8) | 0x0000008e;
3367198194Sweongyo
3368198194Sweongyo		urtw_8187_write_phy_ofdm(sc, data & 0x7f, (data >> 8) & 0xff);
3369198194Sweongyo		urtw_8187_write_phy_ofdm(sc, addr & 0x7f, (addr >> 8) & 0xff);
3370198194Sweongyo		urtw_8187_write_phy_ofdm(sc, 0x0e, 0x00);
3371196970Sphk	}
3372196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x80, 0x10);
3373196970Sphk
3374196970Sphk	for (i = 0; i < N(urtw_8225v2b_rf_part2); i++)
3375196970Sphk		urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2b_rf_part2[i].val);
3376196970Sphk
3377198194Sweongyo	urtw_write32_m(sc, URTW_8187B_AC_VO, (7 << 12) | (3 << 8) | 0x1c);
3378198194Sweongyo	urtw_write32_m(sc, URTW_8187B_AC_VI, (7 << 12) | (3 << 8) | 0x1c);
3379198194Sweongyo	urtw_write32_m(sc, URTW_8187B_AC_BE, (7 << 12) | (3 << 8) | 0x1c);
3380198194Sweongyo	urtw_write32_m(sc, URTW_8187B_AC_BK, (7 << 12) | (3 << 8) | 0x1c);
3381196970Sphk
3382196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x97, 0x46);
3383196970Sphk	urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6);
3384196970Sphk	urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc);
3385196970Sphk	urtw_8187_write_phy_cck(sc, 0xc1, 0x88);
3386198194Sweongyo
3387196970Sphkfail:
3388196970Sphk	return (error);
3389196970Sphk#undef N
3390196970Sphk}
3391196970Sphk
3392196970Sphkstatic usb_error_t
3393196970Sphkurtw_8225v2b_rf_set_chan(struct urtw_softc *sc, int chan)
3394196970Sphk{
3395196970Sphk	usb_error_t error;
3396196970Sphk
3397196970Sphk	error = urtw_8225v2b_set_txpwrlvl(sc, chan);
3398196970Sphk	if (error)
3399196970Sphk		goto fail;
3400196970Sphk
3401196970Sphk	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
3402196970Sphk	usb_pause_mtx(&sc->sc_mtx, 10);
3403196970Sphkfail:
3404196970Sphk	return (error);
3405196970Sphk}
3406196970Sphk
3407196970Sphkstatic usb_error_t
3408196970Sphkurtw_8225v2b_set_txpwrlvl(struct urtw_softc *sc, int chan)
3409196970Sphk{
3410196970Sphk	int i;
3411196970Sphk	uint8_t *cck_pwrtable;
3412196970Sphk	uint8_t cck_pwrlvl_max = 15;
3413196970Sphk	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3414196970Sphk	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3415196970Sphk	usb_error_t error;
3416196970Sphk
3417196970Sphk	/* CCK power setting */
3418196970Sphk	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
3419196970Sphk	    ((sc->sc_flags & URTW_RTL8187B_REV_B) ? cck_pwrlvl_max : 22) :
3420196970Sphk	    (cck_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 0 : 7));
3421196970Sphk	cck_pwrlvl += sc->sc_txpwr_cck_base;
3422196970Sphk	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3423196970Sphk	cck_pwrtable = (chan == 14) ? urtw_8225v2b_txpwr_cck_ch14 :
3424196970Sphk	    urtw_8225v2b_txpwr_cck;
3425196970Sphk
3426196970Sphk	if (sc->sc_flags & URTW_RTL8187B_REV_B)
3427196970Sphk		cck_pwrtable += (cck_pwrlvl <= 6) ? 0 :
3428196970Sphk		    ((cck_pwrlvl <= 11) ? 8 : 16);
3429196970Sphk	else
3430196970Sphk		cck_pwrtable += (cck_pwrlvl <= 5) ? 0 :
3431196970Sphk		    ((cck_pwrlvl <= 11) ? 8 : ((cck_pwrlvl <= 17) ? 16 : 24));
3432196970Sphk
3433196970Sphk	for (i = 0; i < 8; i++)
3434196970Sphk		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3435196970Sphk
3436196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3437196970Sphk	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1);
3438196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3439196970Sphk
3440196970Sphk	/* OFDM power setting */
3441196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > 15) ?
3442196970Sphk	    ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 17 : 25) :
3443196970Sphk	    (ofdm_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 2 : 10));
3444196970Sphk	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3445196970Sphk	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3446196970Sphk
3447196970Sphk	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3448196970Sphk	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1);
3449196970Sphk
3450196970Sphk	if (sc->sc_flags & URTW_RTL8187B_REV_B) {
3451196970Sphk		if (ofdm_pwrlvl <= 11) {
3452196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x87, 0x60);
3453196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x89, 0x60);
3454196970Sphk		} else {
3455196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
3456196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
3457196970Sphk		}
3458196970Sphk	} else {
3459196970Sphk		if (ofdm_pwrlvl <= 11) {
3460196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
3461196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
3462196970Sphk		} else if (ofdm_pwrlvl <= 17) {
3463196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x87, 0x54);
3464196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x89, 0x54);
3465196970Sphk		} else {
3466196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x87, 0x50);
3467196970Sphk			urtw_8187_write_phy_ofdm(sc, 0x89, 0x50);
3468196970Sphk		}
3469196970Sphk	}
3470196970Sphk	usb_pause_mtx(&sc->sc_mtx, 1);
3471196970Sphkfail:
3472196970Sphk	return (error);
3473196970Sphk}
3474196970Sphk
3475196970Sphkstatic usb_error_t
3476196970Sphkurtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
3477196970Sphk{
3478196970Sphk	struct usb_device_request req;
3479196970Sphk	usb_error_t error;
3480196970Sphk
3481196970Sphk	req.bmRequestType = UT_READ_VENDOR_DEVICE;
3482196970Sphk	req.bRequest = URTW_8187_GETREGS_REQ;
3483196970Sphk	USETW(req.wValue, val | 0xfe00);
3484196970Sphk	USETW(req.wIndex, 0);
3485196970Sphk	USETW(req.wLength, sizeof(uint8_t));
3486196970Sphk
3487196970Sphk	error = urtw_do_request(sc, &req, data);
3488196970Sphk	return (error);
3489196970Sphk}
3490196970Sphk
3491196970Sphkstatic usb_error_t
3492196970Sphkurtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
3493196970Sphk{
3494196970Sphk	struct usb_device_request req;
3495196970Sphk
3496196970Sphk	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
3497196970Sphk	req.bRequest = URTW_8187_SETREGS_REQ;
3498196970Sphk	USETW(req.wValue, val | 0xfe00);
3499196970Sphk	USETW(req.wIndex, 0);
3500196970Sphk	USETW(req.wLength, sizeof(uint8_t));
3501196970Sphk
3502196970Sphk	return (urtw_do_request(sc, &req, &data));
3503196970Sphk}
3504196970Sphk
3505196970Sphkstatic usb_error_t
3506196970Sphkurtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
3507196970Sphk{
3508196970Sphk	uint8_t data;
3509196970Sphk	usb_error_t error;
3510196970Sphk
3511196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3512196970Sphk	if (error)
3513196970Sphk		goto fail;
3514196970Sphk
3515196970Sphk	urtw_read8_m(sc, URTW_CONFIG3, &data);
3516196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
3517196970Sphk	urtw_write32_m(sc, URTW_ANAPARAM, val);
3518196970Sphk	urtw_read8_m(sc, URTW_CONFIG3, &data);
3519196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
3520196970Sphk
3521196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3522196970Sphk	if (error)
3523196970Sphk		goto fail;
3524196970Sphkfail:
3525196970Sphk	return (error);
3526196970Sphk}
3527196970Sphk
3528196970Sphkstatic usb_error_t
3529196970Sphkurtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
3530196970Sphk{
3531196970Sphk	uint8_t data;
3532196970Sphk	usb_error_t error;
3533196970Sphk
3534196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3535196970Sphk	if (error)
3536196970Sphk		goto fail;
3537196970Sphk
3538196970Sphk	urtw_read8_m(sc, URTW_CONFIG3, &data);
3539196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
3540196970Sphk	urtw_write32_m(sc, URTW_ANAPARAM2, val);
3541196970Sphk	urtw_read8_m(sc, URTW_CONFIG3, &data);
3542196970Sphk	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
3543196970Sphk
3544196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3545196970Sphk	if (error)
3546196970Sphk		goto fail;
3547196970Sphkfail:
3548196970Sphk	return (error);
3549196970Sphk}
3550196970Sphk
3551196970Sphkstatic usb_error_t
3552196970Sphkurtw_intr_enable(struct urtw_softc *sc)
3553196970Sphk{
3554196970Sphk	usb_error_t error;
3555196970Sphk
3556196970Sphk	urtw_write16_m(sc, URTW_INTR_MASK, 0xffff);
3557196970Sphkfail:
3558196970Sphk	return (error);
3559196970Sphk}
3560196970Sphk
3561196970Sphkstatic usb_error_t
3562196970Sphkurtw_intr_disable(struct urtw_softc *sc)
3563196970Sphk{
3564196970Sphk	usb_error_t error;
3565196970Sphk
3566196970Sphk	urtw_write16_m(sc, URTW_INTR_MASK, 0);
3567196970Sphkfail:
3568196970Sphk	return (error);
3569196970Sphk}
3570196970Sphk
3571196970Sphkstatic usb_error_t
3572196970Sphkurtw_reset(struct urtw_softc *sc)
3573196970Sphk{
3574196970Sphk	uint8_t data;
3575196970Sphk	usb_error_t error;
3576196970Sphk
3577196970Sphk	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
3578196970Sphk	if (error)
3579196970Sphk		goto fail;
3580196970Sphk	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3581196970Sphk	if (error)
3582196970Sphk		goto fail;
3583196970Sphk
3584196970Sphk	error = urtw_intr_disable(sc);
3585196970Sphk	if (error)
3586196970Sphk		goto fail;
3587196970Sphk	usb_pause_mtx(&sc->sc_mtx, 100);
3588196970Sphk
3589196970Sphk	error = urtw_write8e(sc, 0x18, 0x10);
3590196970Sphk	if (error != 0)
3591196970Sphk		goto fail;
3592196970Sphk	error = urtw_write8e(sc, 0x18, 0x11);
3593196970Sphk	if (error != 0)
3594196970Sphk		goto fail;
3595196970Sphk	error = urtw_write8e(sc, 0x18, 0x00);
3596196970Sphk	if (error != 0)
3597196970Sphk		goto fail;
3598196970Sphk	usb_pause_mtx(&sc->sc_mtx, 100);
3599196970Sphk
3600196970Sphk	urtw_read8_m(sc, URTW_CMD, &data);
3601196970Sphk	data = (data & 0x2) | URTW_CMD_RST;
3602196970Sphk	urtw_write8_m(sc, URTW_CMD, data);
3603196970Sphk	usb_pause_mtx(&sc->sc_mtx, 100);
3604196970Sphk
3605196970Sphk	urtw_read8_m(sc, URTW_CMD, &data);
3606196970Sphk	if (data & URTW_CMD_RST) {
3607196970Sphk		device_printf(sc->sc_dev, "reset timeout\n");
3608196970Sphk		goto fail;
3609196970Sphk	}
3610196970Sphk
3611196970Sphk	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
3612196970Sphk	if (error)
3613196970Sphk		goto fail;
3614196970Sphk	usb_pause_mtx(&sc->sc_mtx, 100);
3615196970Sphk
3616196970Sphk	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
3617196970Sphk	if (error)
3618196970Sphk		goto fail;
3619196970Sphk	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3620196970Sphk	if (error)
3621196970Sphk		goto fail;
3622196970Sphkfail:
3623196970Sphk	return (error);
3624196970Sphk}
3625196970Sphk
3626196970Sphkstatic usb_error_t
3627196970Sphkurtw_led_ctl(struct urtw_softc *sc, int mode)
3628196970Sphk{
3629196970Sphk	usb_error_t error = 0;
3630196970Sphk
3631196970Sphk	switch (sc->sc_strategy) {
3632196970Sphk	case URTW_SW_LED_MODE0:
3633196970Sphk		error = urtw_led_mode0(sc, mode);
3634196970Sphk		break;
3635196970Sphk	case URTW_SW_LED_MODE1:
3636196970Sphk		error = urtw_led_mode1(sc, mode);
3637196970Sphk		break;
3638196970Sphk	case URTW_SW_LED_MODE2:
3639196970Sphk		error = urtw_led_mode2(sc, mode);
3640196970Sphk		break;
3641196970Sphk	case URTW_SW_LED_MODE3:
3642196970Sphk		error = urtw_led_mode3(sc, mode);
3643196970Sphk		break;
3644196970Sphk	default:
3645259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3646259456Shselasky		    "unsupported LED mode %d\n", sc->sc_strategy);
3647259456Shselasky		error = USB_ERR_INVAL;
3648259456Shselasky		break;
3649196970Sphk	}
3650196970Sphk
3651196970Sphk	return (error);
3652196970Sphk}
3653196970Sphk
3654196970Sphkstatic usb_error_t
3655196970Sphkurtw_led_mode0(struct urtw_softc *sc, int mode)
3656196970Sphk{
3657196970Sphk
3658196970Sphk	switch (mode) {
3659196970Sphk	case URTW_LED_CTL_POWER_ON:
3660196970Sphk		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
3661196970Sphk		break;
3662196970Sphk	case URTW_LED_CTL_TX:
3663196970Sphk		if (sc->sc_gpio_ledinprogress == 1)
3664196970Sphk			return (0);
3665196970Sphk
3666196970Sphk		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
3667196970Sphk		sc->sc_gpio_blinktime = 2;
3668196970Sphk		break;
3669196970Sphk	case URTW_LED_CTL_LINK:
3670196970Sphk		sc->sc_gpio_ledstate = URTW_LED_ON;
3671196970Sphk		break;
3672196970Sphk	default:
3673259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3674259456Shselasky		    "unsupported LED mode 0x%x", mode);
3675259456Shselasky		return (USB_ERR_INVAL);
3676196970Sphk	}
3677196970Sphk
3678196970Sphk	switch (sc->sc_gpio_ledstate) {
3679196970Sphk	case URTW_LED_ON:
3680196970Sphk		if (sc->sc_gpio_ledinprogress != 0)
3681196970Sphk			break;
3682196970Sphk		urtw_led_on(sc, URTW_LED_GPIO);
3683196970Sphk		break;
3684196970Sphk	case URTW_LED_BLINK_NORMAL:
3685196970Sphk		if (sc->sc_gpio_ledinprogress != 0)
3686196970Sphk			break;
3687196970Sphk		sc->sc_gpio_ledinprogress = 1;
3688196970Sphk		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
3689196970Sphk			URTW_LED_OFF : URTW_LED_ON;
3690196970Sphk		usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
3691196970Sphk		break;
3692196970Sphk	case URTW_LED_POWER_ON_BLINK:
3693196970Sphk		urtw_led_on(sc, URTW_LED_GPIO);
3694196970Sphk		usb_pause_mtx(&sc->sc_mtx, 100);
3695196970Sphk		urtw_led_off(sc, URTW_LED_GPIO);
3696196970Sphk		break;
3697196970Sphk	default:
3698259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3699259456Shselasky		    "unknown LED status 0x%x", sc->sc_gpio_ledstate);
3700259456Shselasky		return (USB_ERR_INVAL);
3701196970Sphk	}
3702196970Sphk	return (0);
3703196970Sphk}
3704196970Sphk
3705196970Sphkstatic usb_error_t
3706196970Sphkurtw_led_mode1(struct urtw_softc *sc, int mode)
3707196970Sphk{
3708196970Sphk	return (USB_ERR_INVAL);
3709196970Sphk}
3710196970Sphk
3711196970Sphkstatic usb_error_t
3712196970Sphkurtw_led_mode2(struct urtw_softc *sc, int mode)
3713196970Sphk{
3714196970Sphk	return (USB_ERR_INVAL);
3715196970Sphk}
3716196970Sphk
3717196970Sphkstatic usb_error_t
3718196970Sphkurtw_led_mode3(struct urtw_softc *sc, int mode)
3719196970Sphk{
3720196970Sphk	return (USB_ERR_INVAL);
3721196970Sphk}
3722196970Sphk
3723196970Sphkstatic usb_error_t
3724196970Sphkurtw_led_on(struct urtw_softc *sc, int type)
3725196970Sphk{
3726196970Sphk	usb_error_t error;
3727196970Sphk
3728196970Sphk	if (type == URTW_LED_GPIO) {
3729196970Sphk		switch (sc->sc_gpio_ledpin) {
3730196970Sphk		case URTW_LED_PIN_GPIO0:
3731196970Sphk			urtw_write8_m(sc, URTW_GPIO, 0x01);
3732196970Sphk			urtw_write8_m(sc, URTW_GP_ENABLE, 0x00);
3733196970Sphk			break;
3734196970Sphk		default:
3735259456Shselasky			DPRINTF(sc, URTW_DEBUG_STATE,
3736259456Shselasky			    "unsupported LED PIN type 0x%x",
3737196970Sphk			    sc->sc_gpio_ledpin);
3738259456Shselasky			error = USB_ERR_INVAL;
3739259456Shselasky			goto fail;
3740196970Sphk		}
3741196970Sphk	} else {
3742259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3743259456Shselasky		    "unsupported LED type 0x%x", type);
3744259456Shselasky		error = USB_ERR_INVAL;
3745259456Shselasky		goto fail;
3746196970Sphk	}
3747196970Sphk
3748196970Sphk	sc->sc_gpio_ledon = 1;
3749196970Sphkfail:
3750196970Sphk	return (error);
3751196970Sphk}
3752196970Sphk
3753196970Sphkstatic usb_error_t
3754196970Sphkurtw_led_off(struct urtw_softc *sc, int type)
3755196970Sphk{
3756196970Sphk	usb_error_t error;
3757196970Sphk
3758196970Sphk	if (type == URTW_LED_GPIO) {
3759196970Sphk		switch (sc->sc_gpio_ledpin) {
3760196970Sphk		case URTW_LED_PIN_GPIO0:
3761196970Sphk			urtw_write8_m(sc, URTW_GPIO, URTW_GPIO_DATA_MAGIC1);
3762196970Sphk			urtw_write8_m(sc,
3763196970Sphk			    URTW_GP_ENABLE, URTW_GP_ENABLE_DATA_MAGIC1);
3764196970Sphk			break;
3765196970Sphk		default:
3766259456Shselasky			DPRINTF(sc, URTW_DEBUG_STATE,
3767259456Shselasky			    "unsupported LED PIN type 0x%x",
3768196970Sphk			    sc->sc_gpio_ledpin);
3769259456Shselasky			error = USB_ERR_INVAL;
3770259456Shselasky			goto fail;
3771196970Sphk		}
3772196970Sphk	} else {
3773259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3774259456Shselasky		    "unsupported LED type 0x%x", type);
3775259456Shselasky		error = USB_ERR_INVAL;
3776259456Shselasky		goto fail;
3777196970Sphk	}
3778196970Sphk
3779196970Sphk	sc->sc_gpio_ledon = 0;
3780196970Sphk
3781196970Sphkfail:
3782196970Sphk	return (error);
3783196970Sphk}
3784196970Sphk
3785192873Sweongyostatic void
3786192873Sweongyourtw_led_ch(void *arg)
3787192873Sweongyo{
3788192873Sweongyo	struct urtw_softc *sc = arg;
3789192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3790192873Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
3791192873Sweongyo
3792192873Sweongyo	ieee80211_runtask(ic, &sc->sc_led_task);
3793192873Sweongyo}
3794196970Sphk
3795192873Sweongyostatic void
3796196970Sphkurtw_ledtask(void *arg, int pending)
3797196970Sphk{
3798196970Sphk	struct urtw_softc *sc = arg;
3799196970Sphk
3800259456Shselasky	if (sc->sc_strategy != URTW_SW_LED_MODE0) {
3801259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3802259456Shselasky		    "could not process a LED strategy 0x%x",
3803259456Shselasky		    sc->sc_strategy);
3804259456Shselasky		return;
3805259456Shselasky	}
3806196970Sphk
3807196970Sphk	URTW_LOCK(sc);
3808196970Sphk	urtw_led_blink(sc);
3809196970Sphk	URTW_UNLOCK(sc);
3810196970Sphk}
3811196970Sphk
3812196970Sphkstatic usb_error_t
3813196970Sphkurtw_led_blink(struct urtw_softc *sc)
3814196970Sphk{
3815196970Sphk	uint8_t ing = 0;
3816196970Sphk	usb_error_t error;
3817196970Sphk
3818196970Sphk	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
3819196970Sphk		error = urtw_led_on(sc, URTW_LED_GPIO);
3820196970Sphk	else
3821196970Sphk		error = urtw_led_off(sc, URTW_LED_GPIO);
3822196970Sphk	sc->sc_gpio_blinktime--;
3823196970Sphk	if (sc->sc_gpio_blinktime == 0)
3824196970Sphk		ing = 1;
3825196970Sphk	else {
3826196970Sphk		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
3827196970Sphk		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
3828196970Sphk		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
3829196970Sphk			ing = 1;
3830196970Sphk	}
3831196970Sphk	if (ing == 1) {
3832196970Sphk		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
3833196970Sphk		    sc->sc_gpio_ledon == 0)
3834196970Sphk			error = urtw_led_on(sc, URTW_LED_GPIO);
3835196970Sphk		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
3836196970Sphk		    sc->sc_gpio_ledon == 1)
3837196970Sphk			error = urtw_led_off(sc, URTW_LED_GPIO);
3838196970Sphk
3839196970Sphk		sc->sc_gpio_blinktime = 0;
3840196970Sphk		sc->sc_gpio_ledinprogress = 0;
3841196970Sphk		return (0);
3842196970Sphk	}
3843196970Sphk
3844196970Sphk	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
3845196970Sphk	    URTW_LED_ON : URTW_LED_OFF;
3846196970Sphk
3847196970Sphk	switch (sc->sc_gpio_ledstate) {
3848196970Sphk	case URTW_LED_BLINK_NORMAL:
3849196970Sphk		usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
3850196970Sphk		break;
3851196970Sphk	default:
3852259456Shselasky		DPRINTF(sc, URTW_DEBUG_STATE,
3853259456Shselasky		    "unknown LED status 0x%x",
3854259456Shselasky		    sc->sc_gpio_ledstate);
3855259456Shselasky		return (USB_ERR_INVAL);
3856196970Sphk	}
3857196970Sphk	return (0);
3858196970Sphk}
3859196970Sphk
3860196970Sphkstatic usb_error_t
3861196970Sphkurtw_rx_enable(struct urtw_softc *sc)
3862196970Sphk{
3863196970Sphk	uint8_t data;
3864196970Sphk	usb_error_t error;
3865196970Sphk
3866196970Sphk	usbd_transfer_start((sc->sc_flags & URTW_RTL8187B) ?
3867196970Sphk	    sc->sc_xfer[URTW_8187B_BULK_RX] : sc->sc_xfer[URTW_8187L_BULK_RX]);
3868196970Sphk
3869196970Sphk	error = urtw_rx_setconf(sc);
3870196970Sphk	if (error != 0)
3871196970Sphk		goto fail;
3872196970Sphk
3873198194Sweongyo	if ((sc->sc_flags & URTW_RTL8187B) == 0) {
3874198194Sweongyo		urtw_read8_m(sc, URTW_CMD, &data);
3875198194Sweongyo		urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE);
3876198194Sweongyo	}
3877196970Sphkfail:
3878196970Sphk	return (error);
3879196970Sphk}
3880196970Sphk
3881196970Sphkstatic usb_error_t
3882196970Sphkurtw_tx_enable(struct urtw_softc *sc)
3883196970Sphk{
3884196970Sphk	uint8_t data8;
3885196970Sphk	uint32_t data;
3886196970Sphk	usb_error_t error;
3887196970Sphk
3888196970Sphk	if (sc->sc_flags & URTW_RTL8187B) {
3889196970Sphk		urtw_read32_m(sc, URTW_TX_CONF, &data);
3890196970Sphk		data &= ~URTW_TX_LOOPBACK_MASK;
3891196970Sphk		data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
3892196970Sphk		data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
3893196970Sphk		data &= ~URTW_TX_SWPLCPLEN;
3894196970Sphk		data |= URTW_TX_HW_SEQNUM | URTW_TX_DISREQQSIZE |
3895196970Sphk		    (7 << 8) |	/* short retry limit */
3896196970Sphk		    (7 << 0) |	/* long retry limit */
3897196970Sphk		    (7 << 21);	/* MAX TX DMA */
3898196970Sphk		urtw_write32_m(sc, URTW_TX_CONF, data);
3899196970Sphk
3900198194Sweongyo		urtw_read8_m(sc, URTW_MSR, &data8);
3901198194Sweongyo		data8 |= URTW_MSR_LINK_ENEDCA;
3902198194Sweongyo		urtw_write8_m(sc, URTW_MSR, data8);
3903196970Sphk		return (error);
3904196970Sphk	}
3905196970Sphk
3906196970Sphk	urtw_read8_m(sc, URTW_CW_CONF, &data8);
3907196970Sphk	data8 &= ~(URTW_CW_CONF_PERPACKET_CW | URTW_CW_CONF_PERPACKET_RETRY);
3908196970Sphk	urtw_write8_m(sc, URTW_CW_CONF, data8);
3909196970Sphk
3910196970Sphk	urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
3911196970Sphk	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
3912196970Sphk	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
3913196970Sphk	data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
3914196970Sphk	urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
3915196970Sphk
3916196970Sphk	urtw_read32_m(sc, URTW_TX_CONF, &data);
3917196970Sphk	data &= ~URTW_TX_LOOPBACK_MASK;
3918196970Sphk	data |= URTW_TX_LOOPBACK_NONE;
3919196970Sphk	data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
3920196970Sphk	data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
3921196970Sphk	data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
3922196970Sphk	data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
3923196970Sphk	data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
3924196970Sphk	data &= ~URTW_TX_SWPLCPLEN;
3925196970Sphk	data |= URTW_TX_NOICV;
3926196970Sphk	urtw_write32_m(sc, URTW_TX_CONF, data);
3927196970Sphk
3928196970Sphk	urtw_read8_m(sc, URTW_CMD, &data8);
3929196970Sphk	urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
3930196970Sphkfail:
3931196970Sphk	return (error);
3932196970Sphk}
3933196970Sphk
3934196970Sphkstatic usb_error_t
3935196970Sphkurtw_rx_setconf(struct urtw_softc *sc)
3936196970Sphk{
3937196970Sphk	struct ifnet *ifp = sc->sc_ifp;
3938196970Sphk	struct ieee80211com *ic = ifp->if_l2com;
3939196970Sphk	uint32_t data;
3940196970Sphk	usb_error_t error;
3941196970Sphk
3942196970Sphk	urtw_read32_m(sc, URTW_RX, &data);
3943196970Sphk	data = data &~ URTW_RX_FILTER_MASK;
3944196970Sphk	if (sc->sc_flags & URTW_RTL8187B) {
3945196970Sphk		data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA |
3946196970Sphk		    URTW_RX_FILTER_MCAST | URTW_RX_FILTER_BCAST |
3947196970Sphk		    URTW_RX_FILTER_NICMAC | URTW_RX_CHECK_BSSID |
3948196970Sphk		    URTW_RX_FIFO_THRESHOLD_NONE |
3949196970Sphk		    URTW_MAX_RX_DMA_2048 |
3950196970Sphk		    URTW_RX_AUTORESETPHY | URTW_RCR_ONLYERLPKT;
3951196970Sphk	} else {
3952196970Sphk		data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
3953196970Sphk		data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
3954196970Sphk
3955196970Sphk		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
3956196970Sphk			data = data | URTW_RX_FILTER_ICVERR;
3957196970Sphk			data = data | URTW_RX_FILTER_PWR;
3958196970Sphk		}
3959196970Sphk		if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
3960196970Sphk			data = data | URTW_RX_FILTER_CRCERR;
3961196970Sphk
3962196970Sphk		if (ic->ic_opmode == IEEE80211_M_MONITOR ||
3963196970Sphk		    (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) {
3964196970Sphk			data = data | URTW_RX_FILTER_ALLMAC;
3965196970Sphk		} else {
3966196970Sphk			data = data | URTW_RX_FILTER_NICMAC;
3967196970Sphk			data = data | URTW_RX_CHECK_BSSID;
3968196970Sphk		}
3969196970Sphk
3970196970Sphk		data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
3971196970Sphk		data = data | URTW_RX_FIFO_THRESHOLD_NONE |
3972196970Sphk		    URTW_RX_AUTORESETPHY;
3973196970Sphk		data = data &~ URTW_MAX_RX_DMA_MASK;
3974196970Sphk		data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT;
3975196970Sphk	}
3976196970Sphk
3977196970Sphk	urtw_write32_m(sc, URTW_RX, data);
3978196970Sphkfail:
3979196970Sphk	return (error);
3980196970Sphk}
3981196970Sphk
3982196970Sphkstatic struct mbuf *
3983196970Sphkurtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
3984196970Sphk    int8_t *nf_p)
3985196970Sphk{
3986198194Sweongyo	int actlen, flen, rssi;
3987196970Sphk	struct ieee80211_frame *wh;
3988196970Sphk	struct mbuf *m, *mnew;
3989196970Sphk	struct urtw_softc *sc = data->sc;
3990196970Sphk	struct ifnet *ifp = sc->sc_ifp;
3991196970Sphk	struct ieee80211com *ic = ifp->if_l2com;
3992198194Sweongyo	uint8_t noise = 0, rate;
3993196970Sphk
3994196970Sphk	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
3995196970Sphk
3996235000Shselasky	if (actlen < (int)URTW_MIN_RXBUFSZ) {
3997196970Sphk		ifp->if_ierrors++;
3998196970Sphk		return (NULL);
3999196970Sphk	}
4000196970Sphk
4001196970Sphk	if (sc->sc_flags & URTW_RTL8187B) {
4002198194Sweongyo		struct urtw_8187b_rxhdr *rx;
4003198194Sweongyo
4004198194Sweongyo		rx = (struct urtw_8187b_rxhdr *)(data->buf +
4005198194Sweongyo		    (actlen - (sizeof(struct urtw_8187b_rxhdr))));
4006198194Sweongyo		flen = le32toh(rx->flag) & 0xfff;
4007196970Sphk		if (flen > actlen) {
4008196970Sphk			ifp->if_ierrors++;
4009196970Sphk			return (NULL);
4010196970Sphk		}
4011198194Sweongyo		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
4012198194Sweongyo		/* XXX correct? */
4013198194Sweongyo		rssi = rx->rssi & URTW_RX_RSSI_MASK;
4014198194Sweongyo		noise = rx->noise;
4015196970Sphk	} else {
4016198194Sweongyo		struct urtw_8187l_rxhdr *rx;
4017198194Sweongyo
4018198194Sweongyo		rx = (struct urtw_8187l_rxhdr *)(data->buf +
4019198194Sweongyo		    (actlen - (sizeof(struct urtw_8187l_rxhdr))));
4020198194Sweongyo		flen = le32toh(rx->flag) & 0xfff;
4021196970Sphk		if (flen > actlen) {
4022196970Sphk			ifp->if_ierrors++;
4023196970Sphk			return (NULL);
4024196970Sphk		}
4025196970Sphk
4026198194Sweongyo		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
4027198194Sweongyo		/* XXX correct? */
4028198194Sweongyo		rssi = rx->rssi & URTW_RX_8187L_RSSI_MASK;
4029198194Sweongyo		noise = rx->noise;
4030196970Sphk	}
4031196970Sphk
4032248078Smarius	mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
4033196970Sphk	if (mnew == NULL) {
4034196970Sphk		ifp->if_ierrors++;
4035196970Sphk		return (NULL);
4036196970Sphk	}
4037196970Sphk
4038196970Sphk	m = data->m;
4039196970Sphk	data->m = mnew;
4040196970Sphk	data->buf = mtod(mnew, uint8_t *);
4041196970Sphk
4042196970Sphk	/* finalize mbuf */
4043196970Sphk	m->m_pkthdr.rcvif = ifp;
4044198194Sweongyo	m->m_pkthdr.len = m->m_len = flen - IEEE80211_CRC_LEN;
4045196970Sphk
4046196970Sphk	if (ieee80211_radiotap_active(ic)) {
4047196970Sphk		struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap;
4048196970Sphk
4049196970Sphk		/* XXX Are variables correct?  */
4050196970Sphk		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
4051196970Sphk		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
4052196970Sphk		tap->wr_dbm_antsignal = (int8_t)rssi;
4053196970Sphk	}
4054196970Sphk
4055196970Sphk	wh = mtod(m, struct ieee80211_frame *);
4056196970Sphk	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
4057196970Sphk		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
4058196970Sphk
4059196970Sphk	*rssi_p = rssi;
4060198194Sweongyo	*nf_p = noise;		/* XXX correct? */
4061196970Sphk
4062196970Sphk	return (m);
4063196970Sphk}
4064196970Sphk
4065196970Sphkstatic void
4066194677Sthompsaurtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
4067192873Sweongyo{
4068194677Sthompsa	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4069192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4070192873Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4071192873Sweongyo	struct ieee80211_frame *wh;
4072192873Sweongyo	struct ieee80211_node *ni;
4073192873Sweongyo	struct mbuf *m = NULL;
4074192873Sweongyo	struct urtw_data *data;
4075192873Sweongyo	int8_t nf = -95;
4076192873Sweongyo	int rssi = 1;
4077192873Sweongyo
4078192873Sweongyo	URTW_ASSERT_LOCKED(sc);
4079192873Sweongyo
4080192873Sweongyo	switch (USB_GET_STATE(xfer)) {
4081192873Sweongyo	case USB_ST_TRANSFERRED:
4082192873Sweongyo		data = STAILQ_FIRST(&sc->sc_rx_active);
4083192873Sweongyo		if (data == NULL)
4084192873Sweongyo			goto setup;
4085192873Sweongyo		STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
4086192873Sweongyo		m = urtw_rxeof(xfer, data, &rssi, &nf);
4087192873Sweongyo		STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
4088192873Sweongyo		/* FALLTHROUGH */
4089192873Sweongyo	case USB_ST_SETUP:
4090192873Sweongyosetup:
4091192873Sweongyo		data = STAILQ_FIRST(&sc->sc_rx_inactive);
4092192873Sweongyo		if (data == NULL) {
4093192873Sweongyo			KASSERT(m == NULL, ("mbuf isn't NULL"));
4094192873Sweongyo			return;
4095192873Sweongyo		}
4096192873Sweongyo		STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next);
4097192873Sweongyo		STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next);
4098194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, data->buf,
4099194677Sthompsa		    usbd_xfer_max_len(xfer));
4100194228Sthompsa		usbd_transfer_submit(xfer);
4101192873Sweongyo
4102192873Sweongyo		/*
4103192873Sweongyo		 * To avoid LOR we should unlock our private mutex here to call
4104192873Sweongyo		 * ieee80211_input() because here is at the end of a USB
4105192873Sweongyo		 * callback and safe to unlock.
4106192873Sweongyo		 */
4107192873Sweongyo		URTW_UNLOCK(sc);
4108192873Sweongyo		if (m != NULL) {
4109192873Sweongyo			wh = mtod(m, struct ieee80211_frame *);
4110192873Sweongyo			ni = ieee80211_find_rxnode(ic,
4111192873Sweongyo			    (struct ieee80211_frame_min *)wh);
4112192873Sweongyo			if (ni != NULL) {
4113192873Sweongyo				(void) ieee80211_input(ni, m, rssi, nf);
4114192873Sweongyo				/* node is no longer needed */
4115192873Sweongyo				ieee80211_free_node(ni);
4116192873Sweongyo			} else
4117192873Sweongyo				(void) ieee80211_input_all(ic, m, rssi, nf);
4118192873Sweongyo			m = NULL;
4119192873Sweongyo		}
4120192873Sweongyo		URTW_LOCK(sc);
4121192873Sweongyo		break;
4122192873Sweongyo	default:
4123192873Sweongyo		/* needs it to the inactive queue due to a error.  */
4124192873Sweongyo		data = STAILQ_FIRST(&sc->sc_rx_active);
4125192873Sweongyo		if (data != NULL) {
4126192873Sweongyo			STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
4127192873Sweongyo			STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
4128192873Sweongyo		}
4129194677Sthompsa		if (error != USB_ERR_CANCELLED) {
4130194677Sthompsa			usbd_xfer_set_stall(xfer);
4131192873Sweongyo			ifp->if_ierrors++;
4132192873Sweongyo			goto setup;
4133192873Sweongyo		}
4134192873Sweongyo		break;
4135192873Sweongyo	}
4136192873Sweongyo}
4137192873Sweongyo
4138198194Sweongyo#define	URTW_STATUS_TYPE_TXCLOSE	1
4139198194Sweongyo#define	URTW_STATUS_TYPE_BEACON_INTR	0
4140198194Sweongyo
4141192873Sweongyostatic void
4142198194Sweongyourtw_txstatus_eof(struct usb_xfer *xfer)
4143198194Sweongyo{
4144198194Sweongyo	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4145198194Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4146198194Sweongyo	int actlen, type, pktretry, seq;
4147198194Sweongyo	uint64_t val;
4148198194Sweongyo
4149198194Sweongyo	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
4150198194Sweongyo
4151198194Sweongyo	if (actlen != sizeof(uint64_t))
4152198194Sweongyo		return;
4153198194Sweongyo
4154198194Sweongyo	val = le64toh(sc->sc_txstatus);
4155198194Sweongyo	type = (val >> 30) & 0x3;
4156198194Sweongyo	if (type == URTW_STATUS_TYPE_TXCLOSE) {
4157198194Sweongyo		pktretry = val & 0xff;
4158198194Sweongyo		seq = (val >> 16) & 0xff;
4159198194Sweongyo		if (pktretry == URTW_TX_MAXRETRY)
4160198194Sweongyo			ifp->if_oerrors++;
4161198194Sweongyo		DPRINTF(sc, URTW_DEBUG_TXSTATUS, "pktretry %d seq %#x\n",
4162198194Sweongyo		    pktretry, seq);
4163198194Sweongyo	}
4164198194Sweongyo}
4165198194Sweongyo
4166198194Sweongyostatic void
4167198194Sweongyourtw_bulk_tx_status_callback(struct usb_xfer *xfer, usb_error_t error)
4168198194Sweongyo{
4169198194Sweongyo	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4170198194Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4171259454Shselasky	void *dma_buf = usbd_xfer_get_frame_buffer(xfer, 0);
4172198194Sweongyo
4173198194Sweongyo	URTW_ASSERT_LOCKED(sc);
4174198194Sweongyo
4175198194Sweongyo	switch (USB_GET_STATE(xfer)) {
4176198194Sweongyo	case USB_ST_TRANSFERRED:
4177198194Sweongyo		urtw_txstatus_eof(xfer);
4178198194Sweongyo		/* FALLTHROUGH */
4179198194Sweongyo	case USB_ST_SETUP:
4180198194Sweongyosetup:
4181259454Shselasky		memcpy(dma_buf, &sc->sc_txstatus, sizeof(uint64_t));
4182260575Shselasky		usbd_xfer_set_frame_len(xfer, 0, sizeof(uint64_t));
4183198194Sweongyo		usbd_transfer_submit(xfer);
4184198194Sweongyo		break;
4185198194Sweongyo	default:
4186198194Sweongyo		if (error != USB_ERR_CANCELLED) {
4187198194Sweongyo			usbd_xfer_set_stall(xfer);
4188198194Sweongyo			ifp->if_ierrors++;
4189198194Sweongyo			goto setup;
4190198194Sweongyo		}
4191198194Sweongyo		break;
4192198194Sweongyo	}
4193198194Sweongyo}
4194198194Sweongyo
4195198194Sweongyostatic void
4196192984Sthompsaurtw_txeof(struct usb_xfer *xfer, struct urtw_data *data)
4197192873Sweongyo{
4198194677Sthompsa	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4199192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4200192873Sweongyo	struct mbuf *m;
4201192873Sweongyo
4202192873Sweongyo	URTW_ASSERT_LOCKED(sc);
4203192873Sweongyo
4204192873Sweongyo	/*
4205192873Sweongyo	 * Do any tx complete callback.  Note this must be done before releasing
4206192873Sweongyo	 * the node reference.
4207192873Sweongyo	 */
4208192873Sweongyo	if (data->m) {
4209192873Sweongyo		m = data->m;
4210192873Sweongyo		if (m->m_flags & M_TXCB) {
4211192873Sweongyo			/* XXX status? */
4212192873Sweongyo			ieee80211_process_callback(data->ni, m, 0);
4213192873Sweongyo		}
4214192873Sweongyo		m_freem(m);
4215192873Sweongyo		data->m = NULL;
4216192873Sweongyo	}
4217192873Sweongyo	if (data->ni) {
4218192873Sweongyo		ieee80211_free_node(data->ni);
4219192873Sweongyo		data->ni = NULL;
4220192873Sweongyo	}
4221192873Sweongyo	sc->sc_txtimer = 0;
4222192873Sweongyo	ifp->if_opackets++;
4223192873Sweongyo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
4224192873Sweongyo}
4225192873Sweongyo
4226192873Sweongyostatic void
4227194677Sthompsaurtw_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
4228192873Sweongyo{
4229194677Sthompsa	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4230192873Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4231192873Sweongyo	struct urtw_data *data;
4232192873Sweongyo
4233192873Sweongyo	URTW_ASSERT_LOCKED(sc);
4234192873Sweongyo
4235192873Sweongyo	switch (USB_GET_STATE(xfer)) {
4236192873Sweongyo	case USB_ST_TRANSFERRED:
4237192873Sweongyo		data = STAILQ_FIRST(&sc->sc_tx_active);
4238192873Sweongyo		if (data == NULL)
4239192873Sweongyo			goto setup;
4240192873Sweongyo		STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
4241192873Sweongyo		urtw_txeof(xfer, data);
4242192873Sweongyo		STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
4243192873Sweongyo		/* FALLTHROUGH */
4244192873Sweongyo	case USB_ST_SETUP:
4245192873Sweongyosetup:
4246192873Sweongyo		data = STAILQ_FIRST(&sc->sc_tx_pending);
4247192873Sweongyo		if (data == NULL) {
4248192873Sweongyo			DPRINTF(sc, URTW_DEBUG_XMIT,
4249192873Sweongyo			    "%s: empty pending queue\n", __func__);
4250192873Sweongyo			return;
4251192873Sweongyo		}
4252192873Sweongyo		STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
4253192873Sweongyo		STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
4254192873Sweongyo
4255194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
4256194228Sthompsa		usbd_transfer_submit(xfer);
4257192873Sweongyo
4258192873Sweongyo		URTW_UNLOCK(sc);
4259192873Sweongyo		urtw_start(ifp);
4260192873Sweongyo		URTW_LOCK(sc);
4261192873Sweongyo		break;
4262192873Sweongyo	default:
4263192873Sweongyo		data = STAILQ_FIRST(&sc->sc_tx_active);
4264192873Sweongyo		if (data == NULL)
4265192873Sweongyo			goto setup;
4266192873Sweongyo		if (data->ni != NULL) {
4267192873Sweongyo			ieee80211_free_node(data->ni);
4268192873Sweongyo			data->ni = NULL;
4269192873Sweongyo			ifp->if_oerrors++;
4270192873Sweongyo		}
4271194677Sthompsa		if (error != USB_ERR_CANCELLED) {
4272194677Sthompsa			usbd_xfer_set_stall(xfer);
4273192873Sweongyo			goto setup;
4274192873Sweongyo		}
4275192873Sweongyo		break;
4276192873Sweongyo	}
4277192873Sweongyo}
4278192873Sweongyo
4279192873Sweongyostatic struct urtw_data *
4280192873Sweongyo_urtw_getbuf(struct urtw_softc *sc)
4281192873Sweongyo{
4282192873Sweongyo	struct urtw_data *bf;
4283192873Sweongyo
4284192873Sweongyo	bf = STAILQ_FIRST(&sc->sc_tx_inactive);
4285192873Sweongyo	if (bf != NULL)
4286192873Sweongyo		STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
4287192873Sweongyo	else
4288192873Sweongyo		bf = NULL;
4289192873Sweongyo	if (bf == NULL)
4290192873Sweongyo		DPRINTF(sc, URTW_DEBUG_XMIT, "%s: %s\n", __func__,
4291192873Sweongyo		    "out of xmit buffers");
4292192873Sweongyo	return (bf);
4293192873Sweongyo}
4294192873Sweongyo
4295192873Sweongyostatic struct urtw_data *
4296192873Sweongyourtw_getbuf(struct urtw_softc *sc)
4297192873Sweongyo{
4298192873Sweongyo	struct urtw_data *bf;
4299192873Sweongyo
4300192873Sweongyo	URTW_ASSERT_LOCKED(sc);
4301192873Sweongyo
4302192873Sweongyo	bf = _urtw_getbuf(sc);
4303192873Sweongyo	if (bf == NULL) {
4304192873Sweongyo		struct ifnet *ifp = sc->sc_ifp;
4305192873Sweongyo
4306192873Sweongyo		DPRINTF(sc, URTW_DEBUG_XMIT, "%s: stop queue\n", __func__);
4307192873Sweongyo		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4308192873Sweongyo	}
4309192873Sweongyo	return (bf);
4310192873Sweongyo}
4311192873Sweongyo
4312196970Sphkstatic int
4313196970Sphkurtw_isbmode(uint16_t rate)
4314192873Sweongyo{
4315192873Sweongyo
4316196970Sphk	return ((rate <= 22 && rate != 12 && rate != 18) ||
4317196970Sphk	    rate == 44) ? (1) : (0);
4318192873Sweongyo}
4319192873Sweongyo
4320198194Sweongyostatic uint16_t
4321198194Sweongyourtw_rate2dbps(uint16_t rate)
4322198194Sweongyo{
4323198194Sweongyo
4324198194Sweongyo	switch(rate) {
4325198194Sweongyo	case 12:
4326198194Sweongyo	case 18:
4327198194Sweongyo	case 24:
4328198194Sweongyo	case 36:
4329198194Sweongyo	case 48:
4330198194Sweongyo	case 72:
4331198194Sweongyo	case 96:
4332198194Sweongyo	case 108:
4333198194Sweongyo		return (rate * 2);
4334198194Sweongyo	default:
4335198194Sweongyo		break;
4336198194Sweongyo	}
4337198194Sweongyo	return (24);
4338198194Sweongyo}
4339198194Sweongyo
4340198194Sweongyostatic int
4341198194Sweongyourtw_compute_txtime(uint16_t framelen, uint16_t rate,
4342198194Sweongyo    uint8_t ismgt, uint8_t isshort)
4343198194Sweongyo{
4344198194Sweongyo	uint16_t     ceiling, frametime, n_dbps;
4345198194Sweongyo
4346198194Sweongyo	if (urtw_isbmode(rate)) {
4347198194Sweongyo		if (ismgt || !isshort || rate == 2)
4348198194Sweongyo			frametime = (uint16_t)(144 + 48 +
4349198194Sweongyo			    (framelen * 8 / (rate / 2)));
4350198194Sweongyo		else
4351198194Sweongyo			frametime = (uint16_t)(72 + 24 +
4352198194Sweongyo			    (framelen * 8 / (rate / 2)));
4353198194Sweongyo		if ((framelen * 8 % (rate / 2)) != 0)
4354198194Sweongyo			frametime++;
4355198194Sweongyo	} else {
4356198194Sweongyo		n_dbps = urtw_rate2dbps(rate);
4357198194Sweongyo		ceiling = (16 + 8 * framelen + 6) / n_dbps
4358198194Sweongyo		    + (((16 + 8 * framelen + 6) % n_dbps) ? 1 : 0);
4359198194Sweongyo		frametime = (uint16_t)(16 + 4 + 4 * ceiling + 6);
4360198194Sweongyo	}
4361198194Sweongyo	return (frametime);
4362198194Sweongyo}
4363198194Sweongyo
4364198194Sweongyo/*
4365198194Sweongyo * Callback from the 802.11 layer to update the
4366198194Sweongyo * slot time based on the current setting.
4367198194Sweongyo */
4368198194Sweongyostatic void
4369198194Sweongyourtw_updateslot(struct ifnet *ifp)
4370198194Sweongyo{
4371198194Sweongyo	struct urtw_softc *sc = ifp->if_softc;
4372198194Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4373198194Sweongyo
4374198194Sweongyo	ieee80211_runtask(ic, &sc->sc_updateslot_task);
4375198194Sweongyo}
4376198194Sweongyo
4377198194Sweongyostatic void
4378198194Sweongyourtw_updateslottask(void *arg, int pending)
4379198194Sweongyo{
4380198194Sweongyo	struct urtw_softc *sc = arg;
4381198194Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4382198194Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4383198194Sweongyo	int error;
4384198194Sweongyo
4385198194Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
4386198194Sweongyo		return;
4387198194Sweongyo
4388198194Sweongyo	URTW_LOCK(sc);
4389198194Sweongyo	if (sc->sc_flags & URTW_RTL8187B) {
4390198194Sweongyo		urtw_write8_m(sc, URTW_SIFS, 0x22);
4391198194Sweongyo		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
4392198194Sweongyo			urtw_write8_m(sc, URTW_SLOT, 0x9);
4393198194Sweongyo		else
4394198194Sweongyo			urtw_write8_m(sc, URTW_SLOT, 0x14);
4395198194Sweongyo		urtw_write8_m(sc, URTW_8187B_EIFS, 0x5b);
4396198194Sweongyo		urtw_write8_m(sc, URTW_CARRIER_SCOUNT, 0x5b);
4397198194Sweongyo	} else {
4398198194Sweongyo		urtw_write8_m(sc, URTW_SIFS, 0x22);
4399198194Sweongyo		if (sc->sc_state == IEEE80211_S_ASSOC &&
4400198194Sweongyo		    ic->ic_flags & IEEE80211_F_SHSLOT)
4401198194Sweongyo			urtw_write8_m(sc, URTW_SLOT, 0x9);
4402198194Sweongyo		else
4403198194Sweongyo			urtw_write8_m(sc, URTW_SLOT, 0x14);
4404198194Sweongyo		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
4405198194Sweongyo			urtw_write8_m(sc, URTW_DIFS, 0x14);
4406198194Sweongyo			urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x14);
4407198194Sweongyo			urtw_write8_m(sc, URTW_CW_VAL, 0x73);
4408198194Sweongyo		} else {
4409198194Sweongyo			urtw_write8_m(sc, URTW_DIFS, 0x24);
4410198194Sweongyo			urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x24);
4411198194Sweongyo			urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
4412198194Sweongyo		}
4413198194Sweongyo	}
4414198194Sweongyofail:
4415198194Sweongyo	URTW_UNLOCK(sc);
4416198194Sweongyo}
4417198194Sweongyo
4418203087Sweongyostatic void
4419203087Sweongyourtw_sysctl_node(struct urtw_softc *sc)
4420203087Sweongyo{
4421203087Sweongyo#define	URTW_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
4422203087Sweongyo	SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
4423203087Sweongyo	struct sysctl_ctx_list *ctx;
4424203087Sweongyo	struct sysctl_oid_list *child, *parent;
4425203087Sweongyo	struct sysctl_oid *tree;
4426203087Sweongyo	struct urtw_stats *stats = &sc->sc_stats;
4427203087Sweongyo
4428203087Sweongyo	ctx = device_get_sysctl_ctx(sc->sc_dev);
4429203087Sweongyo	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev));
4430203087Sweongyo
4431203087Sweongyo	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
4432203087Sweongyo	    NULL, "URTW statistics");
4433203087Sweongyo	parent = SYSCTL_CHILDREN(tree);
4434203087Sweongyo
4435203087Sweongyo	/* Tx statistics. */
4436203087Sweongyo	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
4437203087Sweongyo	    NULL, "Tx MAC statistics");
4438203087Sweongyo	child = SYSCTL_CHILDREN(tree);
4439203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "1m", &stats->txrates[0],
4440203087Sweongyo	    "1 Mbit/s");
4441203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "2m", &stats->txrates[1],
4442203087Sweongyo	    "2 Mbit/s");
4443203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "5.5m", &stats->txrates[2],
4444203087Sweongyo	    "5.5 Mbit/s");
4445203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "6m", &stats->txrates[4],
4446203087Sweongyo	    "6 Mbit/s");
4447203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "9m", &stats->txrates[5],
4448203087Sweongyo	    "9 Mbit/s");
4449203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "11m", &stats->txrates[3],
4450203087Sweongyo	    "11 Mbit/s");
4451203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "12m", &stats->txrates[6],
4452203087Sweongyo	    "12 Mbit/s");
4453203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "18m", &stats->txrates[7],
4454203087Sweongyo	    "18 Mbit/s");
4455203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "24m", &stats->txrates[8],
4456203087Sweongyo	    "24 Mbit/s");
4457203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "36m", &stats->txrates[9],
4458203087Sweongyo	    "36 Mbit/s");
4459203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "48m", &stats->txrates[10],
4460203087Sweongyo	    "48 Mbit/s");
4461203087Sweongyo	URTW_SYSCTL_STAT_ADD32(ctx, child, "54m", &stats->txrates[11],
4462203087Sweongyo	    "54 Mbit/s");
4463203087Sweongyo#undef URTW_SYSCTL_STAT_ADD32
4464203087Sweongyo}
4465203087Sweongyo
4466192873Sweongyostatic device_method_t urtw_methods[] = {
4467192873Sweongyo	DEVMETHOD(device_probe, urtw_match),
4468192873Sweongyo	DEVMETHOD(device_attach, urtw_attach),
4469192873Sweongyo	DEVMETHOD(device_detach, urtw_detach),
4470259454Shselasky	DEVMETHOD_END
4471192873Sweongyo};
4472192873Sweongyostatic driver_t urtw_driver = {
4473235000Shselasky	.name = "urtw",
4474235000Shselasky	.methods = urtw_methods,
4475235000Shselasky	.size = sizeof(struct urtw_softc)
4476192873Sweongyo};
4477192873Sweongyostatic devclass_t urtw_devclass;
4478192873Sweongyo
4479192873SweongyoDRIVER_MODULE(urtw, uhub, urtw_driver, urtw_devclass, NULL, 0);
4480192873SweongyoMODULE_DEPEND(urtw, wlan, 1, 1, 1);
4481192873SweongyoMODULE_DEPEND(urtw, usb, 1, 1, 1);
4482212122SthompsaMODULE_VERSION(urtw, 1);
4483