xref: /netbsd-src/sys/dev/usb/if_urtw.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: if_urtw.c,v 1.27 2024/07/05 04:31:52 rin Exp $	*/
2ac24a5a5Schristos /*	$OpenBSD: if_urtw.c,v 1.39 2011/07/03 15:47:17 matthew Exp $	*/
3ac24a5a5Schristos 
4ac24a5a5Schristos /*-
5ac24a5a5Schristos  * Copyright (c) 2009 Martynas Venckus <martynas@openbsd.org>
6ac24a5a5Schristos  * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
7ac24a5a5Schristos  *
8ac24a5a5Schristos  * Permission to use, copy, modify, and distribute this software for any
9ac24a5a5Schristos  * purpose with or without fee is hereby granted, provided that the above
10ac24a5a5Schristos  * copyright notice and this permission notice appear in all copies.
11ac24a5a5Schristos  *
12ac24a5a5Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13ac24a5a5Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14ac24a5a5Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15ac24a5a5Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16ac24a5a5Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17ac24a5a5Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18ac24a5a5Schristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19ac24a5a5Schristos  */
20ac24a5a5Schristos 
21ac24a5a5Schristos #include <sys/cdefs.h>
22*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: if_urtw.c,v 1.27 2024/07/05 04:31:52 rin Exp $");
23a7c71d30Sskrll 
24a7c71d30Sskrll #ifdef _KERNEL_OPT
25a7c71d30Sskrll #include "opt_usb.h"
26a7c71d30Sskrll #endif
27ac24a5a5Schristos 
28ac24a5a5Schristos #include <sys/param.h>
29ac24a5a5Schristos #include <sys/sockio.h>
30ac24a5a5Schristos #include <sys/proc.h>
31ac24a5a5Schristos #include <sys/mbuf.h>
32ac24a5a5Schristos #include <sys/kernel.h>
33ac24a5a5Schristos #include <sys/socket.h>
34ac24a5a5Schristos #include <sys/systm.h>
35ac24a5a5Schristos #include <sys/callout.h>
36ac24a5a5Schristos #include <sys/conf.h>
37ac24a5a5Schristos #include <sys/device.h>
38ac24a5a5Schristos #include <sys/module.h>
39ac24a5a5Schristos #include <sys/bus.h>
40ac24a5a5Schristos 
41ac24a5a5Schristos #include <machine/endian.h>
42ac24a5a5Schristos #include <net/bpf.h>
43ac24a5a5Schristos #include <net/if.h>
44ac24a5a5Schristos #include <net/if_arp.h>
45ac24a5a5Schristos #include <net/if_dl.h>
46ac24a5a5Schristos #include <net/if_ether.h>
47ac24a5a5Schristos #include <net/if_media.h>
48ac24a5a5Schristos #include <net/if_types.h>
49ac24a5a5Schristos 
50ac24a5a5Schristos #include <netinet/in.h>
51ac24a5a5Schristos #include <netinet/in_systm.h>
52ac24a5a5Schristos #include <netinet/in_var.h>
53ac24a5a5Schristos #include <netinet/if_inarp.h>
54ac24a5a5Schristos #include <netinet/ip.h>
55ac24a5a5Schristos 
56ac24a5a5Schristos #include <net80211/ieee80211_var.h>
57ac24a5a5Schristos #include <net80211/ieee80211_radiotap.h>
58ac24a5a5Schristos 
59ac24a5a5Schristos #include <dev/usb/usb.h>
60ac24a5a5Schristos #include <dev/usb/usbdi.h>
61ac24a5a5Schristos #include <dev/usb/usbdi_util.h>
62ac24a5a5Schristos #include <dev/usb/usbdivar.h>
63ac24a5a5Schristos #include <dev/usb/usbdevs.h>
64ac24a5a5Schristos 
65ac24a5a5Schristos #include "if_urtwreg.h"
66ac24a5a5Schristos 
67ac24a5a5Schristos #ifdef URTW_DEBUG
68ac24a5a5Schristos #define	DPRINTF(x)	do { if (urtw_debug) printf x; } while (0)
69ac24a5a5Schristos #define	DPRINTFN(n, x)	do { if (urtw_debug >= (n)) printf x; } while (0)
70ac24a5a5Schristos int urtw_debug = 0;
71ac24a5a5Schristos #else
72ac24a5a5Schristos #define	DPRINTF(x)
73ac24a5a5Schristos #define	DPRINTFN(n, x)
74ac24a5a5Schristos #endif
75ac24a5a5Schristos 
76ac24a5a5Schristos /*
77ac24a5a5Schristos  * Recognized device vendors/products.
78ac24a5a5Schristos  */
79ac24a5a5Schristos static const struct urtw_type {
80ac24a5a5Schristos 	struct usb_devno	dev;
81ac24a5a5Schristos 	uint8_t			rev;
82ac24a5a5Schristos } urtw_devs[] = {
83ac24a5a5Schristos #define	URTW_DEV_RTL8187(v, p)	\
84ac24a5a5Schristos 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187 }
85ac24a5a5Schristos #define	URTW_DEV_RTL8187B(v, p)	\
86ac24a5a5Schristos 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187B }
87ac24a5a5Schristos 	/* Realtek RTL8187 devices. */
88ac24a5a5Schristos 	URTW_DEV_RTL8187(ASUSTEK,	P5B_WIFI),
89ac24a5a5Schristos 	URTW_DEV_RTL8187(DICKSMITH,	RTL8187),
90ac24a5a5Schristos 	URTW_DEV_RTL8187(LINKSYS4,	WUSB54GC_2),
91ac24a5a5Schristos 	URTW_DEV_RTL8187(LOGITEC,	RTL8187),
92ac24a5a5Schristos 	URTW_DEV_RTL8187(NETGEAR,	WG111V2),
93ac24a5a5Schristos 	URTW_DEV_RTL8187(REALTEK,	RTL8187),
94ac24a5a5Schristos 	URTW_DEV_RTL8187(SITECOMEU,	WL168V1),
95ac24a5a5Schristos 	URTW_DEV_RTL8187(SPHAIRON,	RTL8187),
96ac24a5a5Schristos 	URTW_DEV_RTL8187(SURECOM,	EP9001G2A),
97ac24a5a5Schristos 	/* Realtek RTL8187B devices. */
98ac24a5a5Schristos 	URTW_DEV_RTL8187B(BELKIN,	F5D7050E),
99ac24a5a5Schristos 	URTW_DEV_RTL8187B(NETGEAR,	WG111V3),
100ac24a5a5Schristos 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_0),
101ac24a5a5Schristos 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_1),
102ac24a5a5Schristos 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_2),
103ac24a5a5Schristos 	URTW_DEV_RTL8187B(SITECOMEU,	WL168V4)
104ac24a5a5Schristos #undef	URTW_DEV_RTL8187
105ac24a5a5Schristos #undef	URTW_DEV_RTL8187B
106ac24a5a5Schristos };
107ac24a5a5Schristos #define	urtw_lookup(v, p)	\
108ac24a5a5Schristos 	    ((const struct urtw_type *)usb_lookup(urtw_devs, v, p))
109ac24a5a5Schristos 
110ac24a5a5Schristos /*
111ac24a5a5Schristos  * Helper read/write macros.
112ac24a5a5Schristos  */
113ac24a5a5Schristos #define urtw_read8_m(sc, val, data)	do {			\
114ac24a5a5Schristos 	error = urtw_read8_c(sc, val, data, 0);			\
115ac24a5a5Schristos 	if (error != 0)						\
116ac24a5a5Schristos 		goto fail;					\
117ac24a5a5Schristos } while (0)
118ac24a5a5Schristos #define urtw_read8_idx_m(sc, val, data, idx)	do {		\
119ac24a5a5Schristos 	error = urtw_read8_c(sc, val, data, idx);		\
120ac24a5a5Schristos 	if (error != 0)						\
121ac24a5a5Schristos 		goto fail;					\
122ac24a5a5Schristos } while (0)
123ac24a5a5Schristos #define urtw_write8_m(sc, val, data)	do {			\
124ac24a5a5Schristos 	error = urtw_write8_c(sc, val, data, 0);		\
125ac24a5a5Schristos 	if (error != 0)						\
126ac24a5a5Schristos 		goto fail;					\
127ac24a5a5Schristos } while (0)
128ac24a5a5Schristos #define urtw_write8_idx_m(sc, val, data, idx)	do {		\
129ac24a5a5Schristos 	error = urtw_write8_c(sc, val, data, idx);		\
130ac24a5a5Schristos 	if (error != 0)						\
131ac24a5a5Schristos 		goto fail;					\
132ac24a5a5Schristos } while (0)
133ac24a5a5Schristos #define urtw_read16_m(sc, val, data)	do {			\
134ac24a5a5Schristos 	error = urtw_read16_c(sc, val, data, 0);		\
135ac24a5a5Schristos 	if (error != 0)						\
136ac24a5a5Schristos 		goto fail;					\
137ac24a5a5Schristos } while (0)
138ac24a5a5Schristos #define urtw_read16_idx_m(sc, val, data, idx)	do {		\
139ac24a5a5Schristos 	error = urtw_read16_c(sc, val, data, idx);		\
140ac24a5a5Schristos 	if (error != 0)						\
141ac24a5a5Schristos 		goto fail;					\
142ac24a5a5Schristos } while (0)
143ac24a5a5Schristos #define urtw_write16_m(sc, val, data)	do {			\
144ac24a5a5Schristos 	error = urtw_write16_c(sc, val, data, 0);		\
145ac24a5a5Schristos 	if (error != 0)						\
146ac24a5a5Schristos 		goto fail;					\
147ac24a5a5Schristos } while (0)
148ac24a5a5Schristos #define urtw_write16_idx_m(sc, val, data, idx)	do {		\
149ac24a5a5Schristos 	error = urtw_write16_c(sc, val, data, idx);		\
150ac24a5a5Schristos 	if (error != 0)						\
151ac24a5a5Schristos 		goto fail;					\
152ac24a5a5Schristos } while (0)
153ac24a5a5Schristos #define urtw_read32_m(sc, val, data)	do {			\
154ac24a5a5Schristos 	error = urtw_read32_c(sc, val, data, 0);		\
155ac24a5a5Schristos 	if (error != 0)						\
156ac24a5a5Schristos 		goto fail;					\
157ac24a5a5Schristos } while (0)
158ac24a5a5Schristos #define urtw_read32_idx_m(sc, val, data, idx)	do {		\
159ac24a5a5Schristos 	error = urtw_read32_c(sc, val, data, idx);		\
160ac24a5a5Schristos 	if (error != 0)						\
161ac24a5a5Schristos 		goto fail;					\
162ac24a5a5Schristos } while (0)
163ac24a5a5Schristos #define urtw_write32_m(sc, val, data)	do {			\
164ac24a5a5Schristos 	error = urtw_write32_c(sc, val, data, 0);		\
165ac24a5a5Schristos 	if (error != 0)						\
166ac24a5a5Schristos 		goto fail;					\
167ac24a5a5Schristos } while (0)
168ac24a5a5Schristos #define urtw_write32_idx_m(sc, val, data, idx)	do {		\
169ac24a5a5Schristos 	error = urtw_write32_c(sc, val, data, idx);		\
170ac24a5a5Schristos 	if (error != 0)						\
171ac24a5a5Schristos 		goto fail;					\
172ac24a5a5Schristos } while (0)
173ac24a5a5Schristos #define urtw_8187_write_phy_ofdm(sc, val, data)	do {		\
174ac24a5a5Schristos 	error = urtw_8187_write_phy_ofdm_c(sc, val, data);	\
175ac24a5a5Schristos 	if (error != 0)						\
176ac24a5a5Schristos 		goto fail;					\
177ac24a5a5Schristos } while (0)
178ac24a5a5Schristos #define urtw_8187_write_phy_cck(sc, val, data)	do {		\
179ac24a5a5Schristos 	error = urtw_8187_write_phy_cck_c(sc, val, data);	\
180ac24a5a5Schristos 	if (error != 0)						\
181ac24a5a5Schristos 		goto fail;					\
182ac24a5a5Schristos } while (0)
183ac24a5a5Schristos #define urtw_8225_write(sc, val, data)	do {			\
184ac24a5a5Schristos 	error = urtw_8225_write_c(sc, val, data);		\
185ac24a5a5Schristos 	if (error != 0)						\
186ac24a5a5Schristos 		goto fail;					\
187ac24a5a5Schristos } while (0)
188ac24a5a5Schristos 
189ac24a5a5Schristos struct urtw_pair {
190ac24a5a5Schristos 	uint32_t	reg;
191ac24a5a5Schristos 	uint32_t	val;
192ac24a5a5Schristos };
193ac24a5a5Schristos 
194ac24a5a5Schristos struct urtw_pair_idx {
195ac24a5a5Schristos 	uint8_t		reg;
196ac24a5a5Schristos 	uint8_t		val;
197ac24a5a5Schristos 	uint8_t		idx;
198ac24a5a5Schristos };
199ac24a5a5Schristos 
200ac24a5a5Schristos static struct urtw_pair_idx urtw_8187b_regtbl[] = {
201ac24a5a5Schristos 	{ 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
202ac24a5a5Schristos 	{ 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
203ac24a5a5Schristos 	{ 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
204ac24a5a5Schristos 	{ 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
205ac24a5a5Schristos 	{ 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
206ac24a5a5Schristos 	{ 0xff, 0x00, 0 },
207ac24a5a5Schristos 
208ac24a5a5Schristos 	{ 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 }, { 0x5a, 0x4b, 1 },
209ac24a5a5Schristos 	{ 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 }, { 0x61, 0x09, 1 },
210ac24a5a5Schristos 	{ 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 }, { 0xce, 0x0f, 1 },
211ac24a5a5Schristos 	{ 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 }, { 0xe1, 0x0f, 1 },
212ac24a5a5Schristos 	{ 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 }, { 0xf1, 0x01, 1 },
213ac24a5a5Schristos 	{ 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 }, { 0xf4, 0x04, 1 },
214ac24a5a5Schristos 	{ 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 }, { 0xf7, 0x07, 1 },
215ac24a5a5Schristos 	{ 0xf8, 0x08, 1 },
216ac24a5a5Schristos 
217ac24a5a5Schristos 	{ 0x4e, 0x00, 2 }, { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 },
218ac24a5a5Schristos 	{ 0x22, 0x68, 2 }, { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 },
219ac24a5a5Schristos 	{ 0x25, 0x7d, 2 }, { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 },
220ac24a5a5Schristos 	{ 0x4d, 0x08, 2 }, { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 },
221ac24a5a5Schristos 	{ 0x52, 0x04, 2 }, { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 },
222ac24a5a5Schristos 	{ 0x55, 0x23, 2 }, { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 },
223ac24a5a5Schristos 	{ 0x58, 0x08, 2 }, { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 },
224ac24a5a5Schristos 	{ 0x5b, 0x08, 2 }, { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 },
225ac24a5a5Schristos 	{ 0x62, 0x08, 2 }, { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 },
226ac24a5a5Schristos 	{ 0x72, 0x56, 2 }, { 0x73, 0x9a, 2 },
227ac24a5a5Schristos 
228ac24a5a5Schristos 	{ 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 }, { 0x5b, 0x40, 0 },
229ac24a5a5Schristos 	{ 0x84, 0x88, 0 }, { 0x85, 0x24, 0 }, { 0x88, 0x54, 0 },
230ac24a5a5Schristos 	{ 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 }, { 0x8d, 0x00, 0 },
231ac24a5a5Schristos 	{ 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 }, { 0x96, 0x00, 0 },
232ac24a5a5Schristos 	{ 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 }, { 0x9f, 0x10, 0 },
233ac24a5a5Schristos 	{ 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 }, { 0xdb, 0x00, 0 },
234ac24a5a5Schristos 	{ 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
235ac24a5a5Schristos 
236ac24a5a5Schristos 	{ 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
237ac24a5a5Schristos 	{ 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
238ac24a5a5Schristos };
239ac24a5a5Schristos 
240ac24a5a5Schristos static uint8_t urtw_8225_agc[] = {
241ac24a5a5Schristos 	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
242ac24a5a5Schristos 	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
243ac24a5a5Schristos 	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
244ac24a5a5Schristos 	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
245ac24a5a5Schristos 	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
246ac24a5a5Schristos 	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
247ac24a5a5Schristos 	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
248ac24a5a5Schristos 	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
249ac24a5a5Schristos 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
250ac24a5a5Schristos 	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
251ac24a5a5Schristos 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
252ac24a5a5Schristos 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
253ac24a5a5Schristos };
254ac24a5a5Schristos 
255ac24a5a5Schristos static uint32_t urtw_8225_channel[] = {
256ac24a5a5Schristos 	0x0000,		/* dummy channel 0 */
257ac24a5a5Schristos 	0x085c,		/* 1 */
258ac24a5a5Schristos 	0x08dc,		/* 2 */
259ac24a5a5Schristos 	0x095c,		/* 3 */
260ac24a5a5Schristos 	0x09dc,		/* 4 */
261ac24a5a5Schristos 	0x0a5c,		/* 5 */
262ac24a5a5Schristos 	0x0adc,		/* 6 */
263ac24a5a5Schristos 	0x0b5c,		/* 7 */
264ac24a5a5Schristos 	0x0bdc,		/* 8 */
265ac24a5a5Schristos 	0x0c5c,		/* 9 */
266ac24a5a5Schristos 	0x0cdc,		/* 10 */
267ac24a5a5Schristos 	0x0d5c,		/* 11 */
268ac24a5a5Schristos 	0x0ddc,		/* 12 */
269ac24a5a5Schristos 	0x0e5c,		/* 13 */
270ac24a5a5Schristos 	0x0f72,		/* 14 */
271ac24a5a5Schristos };
272ac24a5a5Schristos 
273ac24a5a5Schristos static uint8_t urtw_8225_gain[] = {
274ac24a5a5Schristos 	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm */
275ac24a5a5Schristos 	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm */
276ac24a5a5Schristos 	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm */
277ac24a5a5Schristos 	0x33, 0x80, 0x79, 0xc5,		/* -78dbm */
278ac24a5a5Schristos 	0x43, 0x78, 0x76, 0xc5,		/* -74dbm */
279ac24a5a5Schristos 	0x53, 0x60, 0x73, 0xc5,		/* -70dbm */
280ac24a5a5Schristos 	0x63, 0x58, 0x70, 0xc5,		/* -66dbm */
281ac24a5a5Schristos };
282ac24a5a5Schristos 
283ac24a5a5Schristos static struct urtw_pair urtw_8225_rf_part1[] = {
284ac24a5a5Schristos 	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
285ac24a5a5Schristos 	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
286ac24a5a5Schristos 	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
287ac24a5a5Schristos 	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 }
288ac24a5a5Schristos };
289ac24a5a5Schristos 
290ac24a5a5Schristos static struct urtw_pair urtw_8225_rf_part2[] = {
291ac24a5a5Schristos 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
292ac24a5a5Schristos 	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
293ac24a5a5Schristos 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
294ac24a5a5Schristos 	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
295ac24a5a5Schristos 	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
296ac24a5a5Schristos 	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
297ac24a5a5Schristos 	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
298ac24a5a5Schristos 	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
299ac24a5a5Schristos 	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
300ac24a5a5Schristos 	{ 0x27, 0x88 }
301ac24a5a5Schristos };
302ac24a5a5Schristos 
303ac24a5a5Schristos static struct urtw_pair urtw_8225_rf_part3[] = {
304ac24a5a5Schristos 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
305ac24a5a5Schristos 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
306ac24a5a5Schristos 	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
307ac24a5a5Schristos 	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
308ac24a5a5Schristos 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
309ac24a5a5Schristos 	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
310ac24a5a5Schristos 	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
311ac24a5a5Schristos };
312ac24a5a5Schristos 
313ac24a5a5Schristos static uint16_t urtw_8225_rxgain[] = {
314ac24a5a5Schristos 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
315ac24a5a5Schristos 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
316ac24a5a5Schristos 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
317ac24a5a5Schristos 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
318ac24a5a5Schristos 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
319ac24a5a5Schristos 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
320ac24a5a5Schristos 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
321ac24a5a5Schristos 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
322ac24a5a5Schristos 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
323ac24a5a5Schristos 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
324ac24a5a5Schristos 	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
325ac24a5a5Schristos 	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
326ac24a5a5Schristos };
327ac24a5a5Schristos 
328ac24a5a5Schristos static uint8_t urtw_8225_threshold[] = {
329ac24a5a5Schristos 	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
330ac24a5a5Schristos };
331ac24a5a5Schristos 
332ac24a5a5Schristos static uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
333ac24a5a5Schristos 	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
334ac24a5a5Schristos };
335ac24a5a5Schristos 
336ac24a5a5Schristos static uint8_t urtw_8225_txpwr_cck[] = {
337ac24a5a5Schristos 	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
338ac24a5a5Schristos 	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
339ac24a5a5Schristos 	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
340ac24a5a5Schristos 	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
341ac24a5a5Schristos 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
342ac24a5a5Schristos 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
343ac24a5a5Schristos };
344ac24a5a5Schristos 
345ac24a5a5Schristos static uint8_t urtw_8225_txpwr_cck_ch14[] = {
346ac24a5a5Schristos 	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
347ac24a5a5Schristos 	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
348ac24a5a5Schristos 	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
349ac24a5a5Schristos 	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
350ac24a5a5Schristos 	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
351ac24a5a5Schristos 	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
352ac24a5a5Schristos };
353ac24a5a5Schristos 
354ac24a5a5Schristos static uint8_t urtw_8225_txpwr_ofdm[] = {
355ac24a5a5Schristos 	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
356ac24a5a5Schristos };
357ac24a5a5Schristos 
358ac24a5a5Schristos static uint8_t urtw_8225v2_agc[] = {
359ac24a5a5Schristos 	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57,
360ac24a5a5Schristos 	0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x47,
361ac24a5a5Schristos 	0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
362ac24a5a5Schristos 	0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27,
363ac24a5a5Schristos 	0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17,
364ac24a5a5Schristos 	0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
365ac24a5a5Schristos 	0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
366ac24a5a5Schristos 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
367ac24a5a5Schristos 	0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
368ac24a5a5Schristos 	0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
369ac24a5a5Schristos 	0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
370ac24a5a5Schristos 	0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
371ac24a5a5Schristos 	0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f,
372ac24a5a5Schristos 	0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
373ac24a5a5Schristos 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
374ac24a5a5Schristos 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
375ac24a5a5Schristos };
376ac24a5a5Schristos 
377ac24a5a5Schristos static uint8_t urtw_8225v2_ofdm[] = {
378ac24a5a5Schristos 	0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
379ac24a5a5Schristos 	0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
380ac24a5a5Schristos 	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
381ac24a5a5Schristos 	0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
382ac24a5a5Schristos 	0x0a, 0xe1, 0x2c, 0x8a, 0x86, 0x83, 0x34, 0x0f,
383ac24a5a5Schristos 	0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
384ac24a5a5Schristos 	0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
385ac24a5a5Schristos 	0x6d, 0x3c, 0xfb, 0x07
386ac24a5a5Schristos };
387ac24a5a5Schristos 
388ac24a5a5Schristos static uint8_t urtw_8225v2_gain_bg[] = {
389ac24a5a5Schristos 	0x23, 0x15, 0xa5,		/* -82-1dbm */
390ac24a5a5Schristos 	0x23, 0x15, 0xb5,		/* -82-2dbm */
391ac24a5a5Schristos 	0x23, 0x15, 0xc5,		/* -82-3dbm */
392ac24a5a5Schristos 	0x33, 0x15, 0xc5,		/* -78dbm */
393ac24a5a5Schristos 	0x43, 0x15, 0xc5,		/* -74dbm */
394ac24a5a5Schristos 	0x53, 0x15, 0xc5,		/* -70dbm */
395ac24a5a5Schristos 	0x63, 0x15, 0xc5,		/* -66dbm */
396ac24a5a5Schristos };
397ac24a5a5Schristos 
398ac24a5a5Schristos static struct urtw_pair urtw_8225v2_rf_part1[] = {
399ac24a5a5Schristos 	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
400ac24a5a5Schristos 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
401ac24a5a5Schristos 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
402ac24a5a5Schristos 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
403ac24a5a5Schristos };
404ac24a5a5Schristos 
405ac24a5a5Schristos static struct urtw_pair urtw_8225v2_rf_part2[] = {
406ac24a5a5Schristos 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
407ac24a5a5Schristos 	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
408ac24a5a5Schristos 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
409ac24a5a5Schristos 	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
410ac24a5a5Schristos 	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
411ac24a5a5Schristos 	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
412ac24a5a5Schristos 	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
413ac24a5a5Schristos 	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
414ac24a5a5Schristos 	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
415ac24a5a5Schristos 	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
416ac24a5a5Schristos };
417ac24a5a5Schristos 
418ac24a5a5Schristos static struct urtw_pair urtw_8225v2_rf_part3[] = {
419ac24a5a5Schristos 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
420ac24a5a5Schristos 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
421ac24a5a5Schristos 	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
422ac24a5a5Schristos 	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
423ac24a5a5Schristos 	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
424ac24a5a5Schristos 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
425ac24a5a5Schristos 	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
426ac24a5a5Schristos 	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
427ac24a5a5Schristos };
428ac24a5a5Schristos 
429ac24a5a5Schristos static uint16_t urtw_8225v2_rxgain[] = {
430ac24a5a5Schristos 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
431ac24a5a5Schristos 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
432ac24a5a5Schristos 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
433ac24a5a5Schristos 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
434ac24a5a5Schristos 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
435ac24a5a5Schristos 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
436ac24a5a5Schristos 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
437ac24a5a5Schristos 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
438ac24a5a5Schristos 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
439ac24a5a5Schristos 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
440ac24a5a5Schristos 	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
441ac24a5a5Schristos 	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
442ac24a5a5Schristos };
443ac24a5a5Schristos 
444ac24a5a5Schristos static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
445ac24a5a5Schristos 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
446ac24a5a5Schristos 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
447ac24a5a5Schristos 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
448ac24a5a5Schristos 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
449ac24a5a5Schristos 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
450ac24a5a5Schristos 	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
451ac24a5a5Schristos };
452ac24a5a5Schristos 
453ac24a5a5Schristos static uint8_t urtw_8225v2_txpwr_cck[] = {
454ac24a5a5Schristos 	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
455ac24a5a5Schristos 	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
456ac24a5a5Schristos 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
457ac24a5a5Schristos 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
458ac24a5a5Schristos };
459ac24a5a5Schristos 
460ac24a5a5Schristos static uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
461ac24a5a5Schristos 	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
462ac24a5a5Schristos 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
463ac24a5a5Schristos 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
464ac24a5a5Schristos 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
465ac24a5a5Schristos };
466ac24a5a5Schristos 
467ac24a5a5Schristos static struct urtw_pair urtw_8225v2_b_rf[] = {
468ac24a5a5Schristos 	{ 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
469ac24a5a5Schristos 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
470ac24a5a5Schristos 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
471ac24a5a5Schristos 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 },
472ac24a5a5Schristos 	{ 0x00, 0x01b7 }
473ac24a5a5Schristos };
474ac24a5a5Schristos 
475ac24a5a5Schristos static struct urtw_pair urtw_ratetable[] = {
476ac24a5a5Schristos 	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
477ac24a5a5Schristos 	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
478ac24a5a5Schristos 	{ 96, 10 }, { 108, 11 }
479ac24a5a5Schristos };
480ac24a5a5Schristos 
48128885f8eSmaxv static int		urtw_init(struct ifnet *);
48228885f8eSmaxv static void		urtw_stop(struct ifnet *, int);
48328885f8eSmaxv static int		urtw_ioctl(struct ifnet *, u_long, void *);
48428885f8eSmaxv static void		urtw_start(struct ifnet *);
48528885f8eSmaxv static int		urtw_alloc_rx_data_list(struct urtw_softc *);
48628885f8eSmaxv static void		urtw_free_rx_data_list(struct urtw_softc *);
48728885f8eSmaxv static int		urtw_alloc_tx_data_list(struct urtw_softc *);
48828885f8eSmaxv static void		urtw_free_tx_data_list(struct urtw_softc *);
48928885f8eSmaxv static void		urtw_rxeof(struct usbd_xfer *, void *,
490ac24a5a5Schristos 		    usbd_status);
49128885f8eSmaxv static int		urtw_tx_start(struct urtw_softc *,
492ac24a5a5Schristos 		    struct ieee80211_node *, struct mbuf *, int);
49328885f8eSmaxv static void		urtw_txeof_low(struct usbd_xfer *, void *,
494ac24a5a5Schristos 		    usbd_status);
49528885f8eSmaxv static void		urtw_txeof_normal(struct usbd_xfer *, void *,
496ac24a5a5Schristos 		    usbd_status);
49728885f8eSmaxv static void		urtw_next_scan(void *);
49828885f8eSmaxv static void		urtw_task(void *);
49928885f8eSmaxv static void		urtw_ledusbtask(void *);
50028885f8eSmaxv static void		urtw_ledtask(void *);
50128885f8eSmaxv static int		urtw_media_change(struct ifnet *);
50228885f8eSmaxv static int		urtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
50328885f8eSmaxv static void		urtw_watchdog(struct ifnet *);
50428885f8eSmaxv static void		urtw_set_chan(struct urtw_softc *, struct ieee80211_channel *);
50528885f8eSmaxv static int		urtw_isbmode(uint16_t);
50628885f8eSmaxv static uint16_t	urtw_rate2rtl(int);
50728885f8eSmaxv static uint16_t	urtw_rtl2rate(int);
50828885f8eSmaxv static usbd_status	urtw_set_rate(struct urtw_softc *);
50928885f8eSmaxv static usbd_status	urtw_update_msr(struct urtw_softc *);
51028885f8eSmaxv static usbd_status	urtw_read8_c(struct urtw_softc *, int, uint8_t *, uint8_t);
51128885f8eSmaxv static usbd_status	urtw_read16_c(struct urtw_softc *, int, uint16_t *, uint8_t);
51228885f8eSmaxv static usbd_status	urtw_read32_c(struct urtw_softc *, int, uint32_t *, uint8_t);
51328885f8eSmaxv static usbd_status	urtw_write8_c(struct urtw_softc *, int, uint8_t, uint8_t);
51428885f8eSmaxv static usbd_status	urtw_write16_c(struct urtw_softc *, int, uint16_t, uint8_t);
51528885f8eSmaxv static usbd_status	urtw_write32_c(struct urtw_softc *, int, uint32_t, uint8_t);
51628885f8eSmaxv static usbd_status	urtw_eprom_cs(struct urtw_softc *, int);
51728885f8eSmaxv static usbd_status	urtw_eprom_ck(struct urtw_softc *);
51828885f8eSmaxv static usbd_status	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
519ac24a5a5Schristos 		    int);
52028885f8eSmaxv static usbd_status	urtw_eprom_read32(struct urtw_softc *, uint32_t,
521ac24a5a5Schristos 		    uint32_t *);
52228885f8eSmaxv static usbd_status	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
52328885f8eSmaxv static usbd_status	urtw_eprom_writebit(struct urtw_softc *, int16_t);
52428885f8eSmaxv static usbd_status	urtw_get_macaddr(struct urtw_softc *);
52528885f8eSmaxv static usbd_status	urtw_get_txpwr(struct urtw_softc *);
52628885f8eSmaxv static usbd_status	urtw_get_rfchip(struct urtw_softc *);
52728885f8eSmaxv static usbd_status	urtw_led_init(struct urtw_softc *);
52828885f8eSmaxv static usbd_status	urtw_8185_rf_pins_enable(struct urtw_softc *);
52928885f8eSmaxv static usbd_status	urtw_8185_tx_antenna(struct urtw_softc *, uint8_t);
53028885f8eSmaxv static usbd_status	urtw_8187_write_phy(struct urtw_softc *, uint8_t, uint32_t);
53128885f8eSmaxv static usbd_status	urtw_8187_write_phy_ofdm_c(struct urtw_softc *, uint8_t,
532ac24a5a5Schristos 		    uint32_t);
53328885f8eSmaxv static usbd_status	urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t,
534ac24a5a5Schristos 		    uint32_t);
53528885f8eSmaxv static usbd_status	urtw_8225_setgain(struct urtw_softc *, int16_t);
53628885f8eSmaxv static usbd_status	urtw_8225_usb_init(struct urtw_softc *);
53728885f8eSmaxv static usbd_status	urtw_8225_write_c(struct urtw_softc *, uint8_t, uint16_t);
53828885f8eSmaxv static usbd_status	urtw_8225_write_s16(struct urtw_softc *, uint8_t, int,
539ac24a5a5Schristos 		    uint16_t);
54028885f8eSmaxv static usbd_status	urtw_8225_read(struct urtw_softc *, uint8_t, uint32_t *);
54128885f8eSmaxv static usbd_status	urtw_8225_rf_init(struct urtw_rf *);
54228885f8eSmaxv static usbd_status	urtw_8225_rf_set_chan(struct urtw_rf *, int);
54328885f8eSmaxv static usbd_status	urtw_8225_rf_set_sens(struct urtw_rf *);
54428885f8eSmaxv static usbd_status	urtw_8225_set_txpwrlvl(struct urtw_softc *, int);
54528885f8eSmaxv static usbd_status	urtw_8225v2_rf_init(struct urtw_rf *);
54628885f8eSmaxv static usbd_status	urtw_8225v2_rf_set_chan(struct urtw_rf *, int);
54728885f8eSmaxv static usbd_status	urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int);
54828885f8eSmaxv static usbd_status	urtw_8225v2_setgain(struct urtw_softc *, int16_t);
54928885f8eSmaxv static usbd_status	urtw_8225_isv2(struct urtw_softc *, int *);
55028885f8eSmaxv static usbd_status	urtw_read8e(struct urtw_softc *, int, uint8_t *);
55128885f8eSmaxv static usbd_status	urtw_write8e(struct urtw_softc *, int, uint8_t);
55228885f8eSmaxv static usbd_status	urtw_8180_set_anaparam(struct urtw_softc *, uint32_t);
55328885f8eSmaxv static usbd_status	urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t);
55428885f8eSmaxv static usbd_status	urtw_open_pipes(struct urtw_softc *);
55528885f8eSmaxv static usbd_status	urtw_close_pipes(struct urtw_softc *);
55628885f8eSmaxv static usbd_status	urtw_intr_enable(struct urtw_softc *);
55728885f8eSmaxv static usbd_status	urtw_intr_disable(struct urtw_softc *);
55828885f8eSmaxv static usbd_status	urtw_reset(struct urtw_softc *);
55928885f8eSmaxv static usbd_status	urtw_led_on(struct urtw_softc *, int);
56028885f8eSmaxv static usbd_status	urtw_led_ctl(struct urtw_softc *, int);
56128885f8eSmaxv static usbd_status	urtw_led_blink(struct urtw_softc *);
56228885f8eSmaxv static usbd_status	urtw_led_mode0(struct urtw_softc *, int);
56328885f8eSmaxv static usbd_status	urtw_led_mode1(struct urtw_softc *, int);
56428885f8eSmaxv static usbd_status	urtw_led_mode2(struct urtw_softc *, int);
56528885f8eSmaxv static usbd_status	urtw_led_mode3(struct urtw_softc *, int);
56628885f8eSmaxv static usbd_status	urtw_rx_setconf(struct urtw_softc *);
56728885f8eSmaxv static usbd_status	urtw_rx_enable(struct urtw_softc *);
56828885f8eSmaxv static usbd_status	urtw_tx_enable(struct urtw_softc *);
56928885f8eSmaxv static usbd_status	urtw_8187b_update_wmm(struct urtw_softc *);
57028885f8eSmaxv static usbd_status	urtw_8187b_reset(struct urtw_softc *);
57128885f8eSmaxv static int		urtw_8187b_init(struct ifnet *);
57228885f8eSmaxv static usbd_status	urtw_8225v2_b_config_mac(struct urtw_softc *);
57328885f8eSmaxv static usbd_status	urtw_8225v2_b_init_rfe(struct urtw_softc *);
57428885f8eSmaxv static usbd_status	urtw_8225v2_b_update_chan(struct urtw_softc *);
57528885f8eSmaxv static usbd_status	urtw_8225v2_b_rf_init(struct urtw_rf *);
57628885f8eSmaxv static usbd_status	urtw_8225v2_b_rf_set_chan(struct urtw_rf *, int);
57728885f8eSmaxv static usbd_status	urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *, int);
57828885f8eSmaxv static int		urtw_set_bssid(struct urtw_softc *, const uint8_t *);
57928885f8eSmaxv static int		urtw_set_macaddr(struct urtw_softc *, const uint8_t *);
580ac24a5a5Schristos 
58128885f8eSmaxv static int urtw_match(device_t, cfdata_t, void *);
58228885f8eSmaxv static void urtw_attach(device_t, device_t, void *);
58328885f8eSmaxv static int urtw_detach(device_t, int);
58428885f8eSmaxv static int urtw_activate(device_t, enum devact);
585ac24a5a5Schristos 
586ac24a5a5Schristos CFATTACH_DECL_NEW(urtw, sizeof(struct urtw_softc),
587ac24a5a5Schristos 	urtw_match,
588ac24a5a5Schristos 	urtw_attach,
589ac24a5a5Schristos 	urtw_detach,
590ac24a5a5Schristos 	urtw_activate
591ac24a5a5Schristos );
592ac24a5a5Schristos 
59328885f8eSmaxv static int
urtw_match(device_t parent,cfdata_t match,void * aux)594ac24a5a5Schristos urtw_match(device_t parent, cfdata_t match, void *aux)
595ac24a5a5Schristos {
596ac24a5a5Schristos 	struct usb_attach_arg *uaa = aux;
597ac24a5a5Schristos 
5984e8e6643Sskrll 	return urtw_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ?
5994e8e6643Sskrll 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
600ac24a5a5Schristos }
601ac24a5a5Schristos 
60228885f8eSmaxv static void
urtw_attach(device_t parent,device_t self,void * aux)603ac24a5a5Schristos urtw_attach(device_t parent, device_t self, void *aux)
604ac24a5a5Schristos {
605ac24a5a5Schristos 	struct urtw_softc *sc = device_private(self);
606ac24a5a5Schristos 	struct usb_attach_arg *uaa = aux;
607ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
608ac24a5a5Schristos 	struct ifnet *ifp = &sc->sc_if;
609ac24a5a5Schristos 	usbd_status error;
610ac24a5a5Schristos 	uint8_t data8;
611ac24a5a5Schristos 	uint32_t data;
612ac24a5a5Schristos 	int i;
613ac24a5a5Schristos 
614ac24a5a5Schristos 	sc->sc_dev = self;
6154e8e6643Sskrll 	sc->sc_udev = uaa->uaa_device;
6164e8e6643Sskrll 	sc->sc_hwrev = urtw_lookup(uaa->uaa_vendor, uaa->uaa_product)->rev;
617e11ff962Smaxv 	sc->sc_init_state = URTW_INIT_NONE;
618ac24a5a5Schristos 
619d21ffc75Smsaitoh 	aprint_naive("\n");
620d21ffc75Smsaitoh 	aprint_normal(": ");
621ac24a5a5Schristos 
622ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
623ac24a5a5Schristos 		urtw_read32_m(sc, URTW_TX_CONF, &data);
624ac24a5a5Schristos 		data &= URTW_TX_HWREV_MASK;
625ac24a5a5Schristos 		switch (data) {
626ac24a5a5Schristos 		case URTW_TX_HWREV_8187_D:
627ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187_D;
628d21ffc75Smsaitoh 			aprint_normal("RTL8187 rev D");
629ac24a5a5Schristos 			break;
630ac24a5a5Schristos 		case URTW_TX_HWREV_8187B_D:
631ac24a5a5Schristos 			/*
632ac24a5a5Schristos 			 * Detect Realtek RTL8187B devices that use
633ac24a5a5Schristos 			 * USB IDs of RTL8187.
634ac24a5a5Schristos 			 */
635ac24a5a5Schristos 			sc->sc_hwrev = URTW_HWREV_8187B | URTW_HWREV_8187B_B;
636d21ffc75Smsaitoh 			aprint_normal("RTL8187B rev B (early)");
637ac24a5a5Schristos 			break;
638ac24a5a5Schristos 		default:
639ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187_B;
640aa3d6ec1Schristos 			aprint_normal("RTL8187 rev 0x%02x", data >> 25);
641ac24a5a5Schristos 			break;
642ac24a5a5Schristos 		}
643ac24a5a5Schristos 	} else {
644ac24a5a5Schristos 		/* RTL8187B hwrev register. */
645ac24a5a5Schristos 		urtw_read8_m(sc, URTW_8187B_HWREV, &data8);
646ac24a5a5Schristos 		switch (data8) {
647ac24a5a5Schristos 		case URTW_8187B_HWREV_8187B_B:
648ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
649d21ffc75Smsaitoh 			aprint_normal("RTL8187B rev B");
650ac24a5a5Schristos 			break;
651ac24a5a5Schristos 		case URTW_8187B_HWREV_8187B_D:
652ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187B_D;
653d21ffc75Smsaitoh 			aprint_normal("RTL8187B rev D");
654ac24a5a5Schristos 			break;
655ac24a5a5Schristos 		case URTW_8187B_HWREV_8187B_E:
656ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187B_E;
657d21ffc75Smsaitoh 			aprint_normal("RTL8187B rev E");
658ac24a5a5Schristos 			break;
659ac24a5a5Schristos 		default:
660ac24a5a5Schristos 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
661aa3d6ec1Schristos 			aprint_normal("RTL8187B rev 0x%02x", data8);
662ac24a5a5Schristos 			break;
663ac24a5a5Schristos 		}
664ac24a5a5Schristos 	}
665ac24a5a5Schristos 
666ac24a5a5Schristos 	urtw_read32_m(sc, URTW_RX, &data);
667ac24a5a5Schristos 	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
668ac24a5a5Schristos 	    URTW_EEPROM_93C46;
669ac24a5a5Schristos 
670ac24a5a5Schristos 	error = urtw_get_rfchip(sc);
671ac24a5a5Schristos 	if (error != 0)
672ac24a5a5Schristos 		goto fail;
673ac24a5a5Schristos 	error = urtw_get_macaddr(sc);
674ac24a5a5Schristos 	if (error != 0)
675ac24a5a5Schristos 		goto fail;
676ac24a5a5Schristos 	error = urtw_get_txpwr(sc);
677ac24a5a5Schristos 	if (error != 0)
678ac24a5a5Schristos 		goto fail;
679ac24a5a5Schristos 	error = urtw_led_init(sc);		/* XXX incompleted */
680ac24a5a5Schristos 	if (error != 0)
681ac24a5a5Schristos 		goto fail;
682ac24a5a5Schristos 
683ac24a5a5Schristos 	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
684ac24a5a5Schristos 	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
685ac24a5a5Schristos 	sc->sc_currate = 3;
686ac24a5a5Schristos 	/* XXX for what? */
687ac24a5a5Schristos 	sc->sc_preamble_mode = 2;
688ac24a5a5Schristos 
6897c64a30eSjmcneill 	usb_init_task(&sc->sc_task, urtw_task, sc, 0);
6907c64a30eSjmcneill 	usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc, 0);
691ac24a5a5Schristos 	callout_init(&sc->scan_to, 0);
692ac24a5a5Schristos 	callout_setfunc(&sc->scan_to, urtw_next_scan, sc);
693ac24a5a5Schristos 	callout_init(&sc->sc_led_ch, 0);
694ac24a5a5Schristos 	callout_setfunc(&sc->sc_led_ch, urtw_ledtask, sc);
695ac24a5a5Schristos 
696ac24a5a5Schristos 	ic->ic_ifp = ifp;
697ac24a5a5Schristos 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
698ac24a5a5Schristos 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
699ac24a5a5Schristos 	ic->ic_state = IEEE80211_S_INIT;
700ac24a5a5Schristos 
701ac24a5a5Schristos 	/* set device capabilities */
702ac24a5a5Schristos 	ic->ic_caps =
703ac24a5a5Schristos 	    IEEE80211_C_MONITOR |	/* monitor mode supported */
704ac24a5a5Schristos 	    IEEE80211_C_TXPMGT |	/* tx power management */
705ac24a5a5Schristos 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
706ac24a5a5Schristos 	    IEEE80211_C_SHSLOT |	/* short slot time supported */
707ac24a5a5Schristos 	    IEEE80211_C_WEP |		/* s/w WEP */
708ac24a5a5Schristos 	    IEEE80211_C_WPA;		/* WPA/RSN */
709ac24a5a5Schristos 
710ac24a5a5Schristos 	/* set supported .11b and .11g rates */
711ac24a5a5Schristos 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
712ac24a5a5Schristos 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
713ac24a5a5Schristos 
714ac24a5a5Schristos 	/* set supported .11b and .11g channels (1 through 14) */
715ac24a5a5Schristos 	for (i = 1; i <= 14; i++) {
716ac24a5a5Schristos 		ic->ic_channels[i].ic_freq =
717ac24a5a5Schristos 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
718ac24a5a5Schristos 		ic->ic_channels[i].ic_flags =
719ac24a5a5Schristos 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
720ac24a5a5Schristos 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
721ac24a5a5Schristos 	}
722ac24a5a5Schristos 
723ac24a5a5Schristos 	ifp->if_softc = sc;
724ac24a5a5Schristos 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
725ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
726ac24a5a5Schristos 		ifp->if_init = urtw_init;
727ac24a5a5Schristos 	} else {
728ac24a5a5Schristos 		ifp->if_init = urtw_8187b_init;
729ac24a5a5Schristos 	}
730ac24a5a5Schristos 	ifp->if_ioctl = urtw_ioctl;
731ac24a5a5Schristos 	ifp->if_start = urtw_start;
732ac24a5a5Schristos 	ifp->if_watchdog = urtw_watchdog;
733ac24a5a5Schristos 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
734ac24a5a5Schristos 	IFQ_SET_READY(&ifp->if_snd);
735ac24a5a5Schristos 	memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
736ac24a5a5Schristos 
737ac24a5a5Schristos 	if_attach(ifp);
738ac24a5a5Schristos 	ieee80211_ifattach(ic);
739ac24a5a5Schristos 
740ac24a5a5Schristos 	/* override state transition machine */
741ac24a5a5Schristos 	sc->sc_newstate = ic->ic_newstate;
742ac24a5a5Schristos 	ic->ic_newstate = urtw_newstate;
7437a9a30c5Sthorpej 
7447a9a30c5Sthorpej 	/* XXX media locking needs revisiting */
7457a9a30c5Sthorpej 	mutex_init(&sc->sc_media_mtx, MUTEX_DEFAULT, IPL_SOFTUSB);
7467a9a30c5Sthorpej 	ieee80211_media_init_with_lock(ic,
7477a9a30c5Sthorpej 	    urtw_media_change, ieee80211_media_status, &sc->sc_media_mtx);
748ac24a5a5Schristos 
749ac24a5a5Schristos 	bpf_attach2(ifp, DLT_IEEE802_11_RADIO,
750ac24a5a5Schristos 	    sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
751ac24a5a5Schristos 	    &sc->sc_drvbpf);
752ac24a5a5Schristos 
7534e8e6643Sskrll 	sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
754ac24a5a5Schristos 	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
755ac24a5a5Schristos 	sc->sc_rxtap.wr_ihdr.it_present = htole32(URTW_RX_RADIOTAP_PRESENT);
756ac24a5a5Schristos 
7574e8e6643Sskrll 	sc->sc_txtap_len = sizeof(sc->sc_txtapu);
758ac24a5a5Schristos 	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
759ac24a5a5Schristos 	sc->sc_txtap.wt_ihdr.it_present = htole32(URTW_TX_RADIOTAP_PRESENT);
760ac24a5a5Schristos 
761d21ffc75Smsaitoh 	aprint_normal(", address %s\n", ether_sprintf(ic->ic_myaddr));
762ac24a5a5Schristos 
763ac24a5a5Schristos 	ieee80211_announce(ic);
764ac24a5a5Schristos 
765e11ff962Smaxv 	sc->sc_init_state = URTW_INIT_INITED;
766e11ff962Smaxv 
767ac24a5a5Schristos 	return;
768ac24a5a5Schristos fail:
769d21ffc75Smsaitoh 	aprint_error(": %s failed!\n", __func__);
770ac24a5a5Schristos 	sc->sc_dying = true;
771ac24a5a5Schristos }
772ac24a5a5Schristos 
77328885f8eSmaxv static int
urtw_detach(device_t self,int flags)774ac24a5a5Schristos urtw_detach(device_t self, int flags)
775ac24a5a5Schristos {
776ac24a5a5Schristos 	struct urtw_softc *sc = device_private(self);
777ac24a5a5Schristos 	struct ifnet *ifp = &sc->sc_if;
778ac24a5a5Schristos 	int s;
779ac24a5a5Schristos 
780ac24a5a5Schristos 	s = splusb();
781ac24a5a5Schristos 
782ac24a5a5Schristos 	sc->sc_dying = true;
783ac24a5a5Schristos 
784e11ff962Smaxv 	if (sc->sc_init_state < URTW_INIT_INITED)
785e11ff962Smaxv 		goto out;
786e11ff962Smaxv 
787300e2267Sriastradh 	callout_halt(&sc->scan_to, NULL);
788300e2267Sriastradh 	callout_halt(&sc->sc_led_ch, NULL);
789ac24a5a5Schristos 	callout_destroy(&sc->scan_to);
790ac24a5a5Schristos 	callout_destroy(&sc->sc_led_ch);
791ac24a5a5Schristos 
792a1de0147Sriastradh 	usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL);
793a1de0147Sriastradh 	usb_rem_task_wait(sc->sc_udev, &sc->sc_ledtask, USB_TASKQ_DRIVER,
794a1de0147Sriastradh 	    NULL);
795ac24a5a5Schristos 
796ac24a5a5Schristos 	if (ifp->if_softc != NULL) {
797ac24a5a5Schristos 		bpf_detach(ifp);
798ac24a5a5Schristos 		ieee80211_ifdetach(&sc->sc_ic);	/* free all nodes */
799ac24a5a5Schristos 		if_detach(ifp);
800ac24a5a5Schristos 	}
801ac24a5a5Schristos 
802ac24a5a5Schristos 	/* abort and free xfers */
803ac24a5a5Schristos 	urtw_free_tx_data_list(sc);
804ac24a5a5Schristos 	urtw_free_rx_data_list(sc);
805ac24a5a5Schristos 	urtw_close_pipes(sc);
806ac24a5a5Schristos 
807e11ff962Smaxv out:
808ac24a5a5Schristos 	splx(s);
8094e8e6643Sskrll 	return 0;
810ac24a5a5Schristos }
811ac24a5a5Schristos 
81228885f8eSmaxv static int
urtw_activate(device_t self,enum devact act)813ac24a5a5Schristos urtw_activate(device_t self, enum devact act)
814ac24a5a5Schristos {
815ac24a5a5Schristos 	struct urtw_softc *sc = device_private(self);
816ac24a5a5Schristos 
817ac24a5a5Schristos 	switch (act) {
818ac24a5a5Schristos 	case DVACT_DEACTIVATE:
819ac24a5a5Schristos 		sc->sc_dying = true;
820ac24a5a5Schristos 		break;
821ac24a5a5Schristos 	}
822ac24a5a5Schristos 
8234e8e6643Sskrll 	return 0;
824ac24a5a5Schristos }
825ac24a5a5Schristos 
82628885f8eSmaxv static usbd_status
urtw_close_pipes(struct urtw_softc * sc)827ac24a5a5Schristos urtw_close_pipes(struct urtw_softc *sc)
828ac24a5a5Schristos {
829ac24a5a5Schristos 	usbd_status error = 0;
830ac24a5a5Schristos 
831ac24a5a5Schristos 	if (sc->sc_rxpipe != NULL) {
83240e1019eSriastradh 		usbd_close_pipe(sc->sc_rxpipe);
833ac24a5a5Schristos 		sc->sc_rxpipe = NULL;
834ac24a5a5Schristos 	}
835ac24a5a5Schristos 	if (sc->sc_txpipe_low != NULL) {
83640e1019eSriastradh 		usbd_close_pipe(sc->sc_txpipe_low);
837ac24a5a5Schristos 		sc->sc_txpipe_low = NULL;
838ac24a5a5Schristos 	}
839ac24a5a5Schristos 	if (sc->sc_txpipe_normal != NULL) {
84040e1019eSriastradh 		usbd_close_pipe(sc->sc_txpipe_normal);
841ac24a5a5Schristos 		sc->sc_txpipe_normal = NULL;
842ac24a5a5Schristos 	}
8434e8e6643Sskrll 	return error;
844ac24a5a5Schristos }
845ac24a5a5Schristos 
84628885f8eSmaxv static usbd_status
urtw_open_pipes(struct urtw_softc * sc)847ac24a5a5Schristos urtw_open_pipes(struct urtw_softc *sc)
848ac24a5a5Schristos {
849ac24a5a5Schristos 	usbd_status error;
850ac24a5a5Schristos 
851ac24a5a5Schristos 	/*
852ac24a5a5Schristos 	 * NB: there is no way to distinguish each pipes so we need to hardcode
853ac24a5a5Schristos 	 * pipe numbers
854ac24a5a5Schristos 	 */
855ac24a5a5Schristos 
856ac24a5a5Schristos 	/* tx pipe - low priority packets */
857ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187)
858ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x2,
859ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_txpipe_low);
860ac24a5a5Schristos 	else
861ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x6,
862ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_txpipe_low);
863ac24a5a5Schristos 	if (error != 0) {
864ac24a5a5Schristos 		printf("%s: could not open Tx low pipe: %s\n",
865ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(error));
866ac24a5a5Schristos 		goto fail;
867ac24a5a5Schristos 	}
868ac24a5a5Schristos 	/* tx pipe - normal priority packets */
869ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187)
870ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x3,
871ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_txpipe_normal);
872ac24a5a5Schristos 	else
873ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x7,
874ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_txpipe_normal);
875ac24a5a5Schristos 	if (error != 0) {
876ac24a5a5Schristos 		printf("%s: could not open Tx normal pipe: %s\n",
877ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(error));
878ac24a5a5Schristos 		goto fail;
879ac24a5a5Schristos 	}
880ac24a5a5Schristos 	/* rx pipe */
881ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187)
882ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x81,
883ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_rxpipe);
884ac24a5a5Schristos 	else
885ac24a5a5Schristos 		error = usbd_open_pipe(sc->sc_iface, 0x83,
886ac24a5a5Schristos 		    USBD_EXCLUSIVE_USE, &sc->sc_rxpipe);
887ac24a5a5Schristos 	if (error != 0) {
888ac24a5a5Schristos 		printf("%s: could not open Rx pipe: %s\n",
889ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(error));
890ac24a5a5Schristos 		goto fail;
891ac24a5a5Schristos 	}
892ac24a5a5Schristos 
8934e8e6643Sskrll 	return 0;
894ac24a5a5Schristos fail:
895ac24a5a5Schristos 	(void)urtw_close_pipes(sc);
8964e8e6643Sskrll 	return error;
897ac24a5a5Schristos }
898ac24a5a5Schristos 
89928885f8eSmaxv static int
urtw_alloc_rx_data_list(struct urtw_softc * sc)900ac24a5a5Schristos urtw_alloc_rx_data_list(struct urtw_softc *sc)
901ac24a5a5Schristos {
902ac24a5a5Schristos 	int i, error;
903ac24a5a5Schristos 
904ac24a5a5Schristos 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
905ac24a5a5Schristos 		struct urtw_rx_data *data = &sc->sc_rx_data[i];
906ac24a5a5Schristos 
907ac24a5a5Schristos 		data->sc = sc;
908ac24a5a5Schristos 
9094e8e6643Sskrll 		error = usbd_create_xfer(sc->sc_rxpipe, MCLBYTES,
910b8421611Sskrll 		    0, 0, &data->xfer);
9114e8e6643Sskrll 		if (error) {
912ac24a5a5Schristos 
9134e8e6643Sskrll 			printf("%s: could not allocate rx xfer\n",
914ac24a5a5Schristos 			    device_xname(sc->sc_dev));
915ac24a5a5Schristos 			error = ENOMEM;
916ac24a5a5Schristos 			goto fail;
917ac24a5a5Schristos 		}
918ac24a5a5Schristos 
919ac24a5a5Schristos 		MGETHDR(data->m, M_DONTWAIT, MT_DATA);
920ac24a5a5Schristos 		if (data->m == NULL) {
921ac24a5a5Schristos 			printf("%s: could not allocate rx mbuf\n",
922ac24a5a5Schristos 			    device_xname(sc->sc_dev));
923ac24a5a5Schristos 			error = ENOMEM;
924ac24a5a5Schristos 			goto fail;
925ac24a5a5Schristos 		}
926ac24a5a5Schristos 		MCLGET(data->m, M_DONTWAIT);
927ac24a5a5Schristos 		if (!(data->m->m_flags & M_EXT)) {
928ac24a5a5Schristos 			printf("%s: could not allocate rx mbuf cluster\n",
929ac24a5a5Schristos 			    device_xname(sc->sc_dev));
930ac24a5a5Schristos 			error = ENOMEM;
931ac24a5a5Schristos 			goto fail;
932ac24a5a5Schristos 		}
933ac24a5a5Schristos 		data->buf = mtod(data->m, uint8_t *);
934ac24a5a5Schristos 	}
935ac24a5a5Schristos 
9364e8e6643Sskrll 	return 0;
937ac24a5a5Schristos 
938ac24a5a5Schristos fail:
939ac24a5a5Schristos 	urtw_free_rx_data_list(sc);
9404e8e6643Sskrll 	return error;
941ac24a5a5Schristos }
942ac24a5a5Schristos 
94328885f8eSmaxv static void
urtw_free_rx_data_list(struct urtw_softc * sc)944ac24a5a5Schristos urtw_free_rx_data_list(struct urtw_softc *sc)
945ac24a5a5Schristos {
946ac24a5a5Schristos 	int i;
947ac24a5a5Schristos 
948ac24a5a5Schristos 	/* Make sure no transfers are pending. */
949ac24a5a5Schristos 	if (sc->sc_rxpipe != NULL)
950ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_rxpipe);
951ac24a5a5Schristos 
952ac24a5a5Schristos 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
953ac24a5a5Schristos 		struct urtw_rx_data *data = &sc->sc_rx_data[i];
954ac24a5a5Schristos 
955ac24a5a5Schristos 		if (data->xfer != NULL) {
9564e8e6643Sskrll 			usbd_destroy_xfer(data->xfer);
957ac24a5a5Schristos 			data->xfer = NULL;
958ac24a5a5Schristos 		}
959ac24a5a5Schristos 		m_freem(data->m);
960ac24a5a5Schristos 		data->m = NULL;
961ac24a5a5Schristos 	}
962ac24a5a5Schristos }
963ac24a5a5Schristos 
96428885f8eSmaxv static int
urtw_alloc_tx_data_list(struct urtw_softc * sc)965ac24a5a5Schristos urtw_alloc_tx_data_list(struct urtw_softc *sc)
966ac24a5a5Schristos {
967ac24a5a5Schristos 	int i, error;
968ac24a5a5Schristos 
9694e8e6643Sskrll 	for (size_t j = 0; j < URTW_PRIORITY_MAX; j++) {
970ac24a5a5Schristos 		for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++) {
9714e8e6643Sskrll 			struct urtw_tx_data *data = &sc->sc_tx_data[j][i];
972ac24a5a5Schristos 
973ac24a5a5Schristos 			data->sc = sc;
974ac24a5a5Schristos 			data->ni = NULL;
975ac24a5a5Schristos 
9764e8e6643Sskrll 			error = usbd_create_xfer((j == URTW_PRIORITY_LOW) ?
9774e8e6643Sskrll 			    sc->sc_txpipe_low : sc->sc_txpipe_normal,
9784e8e6643Sskrll 			    URTW_TX_MAXSIZE, USBD_FORCE_SHORT_XFER, 0,
9794e8e6643Sskrll 			    &data->xfer);
9804e8e6643Sskrll 			if (error) {
981ac24a5a5Schristos 				printf("%s: could not allocate tx xfer\n",
982ac24a5a5Schristos 				    device_xname(sc->sc_dev));
983ac24a5a5Schristos 				goto fail;
984ac24a5a5Schristos 			}
985ac24a5a5Schristos 
9864e8e6643Sskrll 			data->buf = usbd_get_buffer(data->xfer);
987ac24a5a5Schristos 
988ac24a5a5Schristos 			if (((unsigned long)data->buf) % 4)
989ac24a5a5Schristos 				printf("%s: warn: unaligned buffer %p\n",
990ac24a5a5Schristos 				    device_xname(sc->sc_dev), data->buf);
991ac24a5a5Schristos 		}
9924e8e6643Sskrll 	}
993ac24a5a5Schristos 
9944e8e6643Sskrll 	return 0;
995ac24a5a5Schristos 
996ac24a5a5Schristos fail:
997ac24a5a5Schristos 	urtw_free_tx_data_list(sc);
9984e8e6643Sskrll 	return error;
999ac24a5a5Schristos }
1000ac24a5a5Schristos 
100128885f8eSmaxv static void
urtw_free_tx_data_list(struct urtw_softc * sc)1002ac24a5a5Schristos urtw_free_tx_data_list(struct urtw_softc *sc)
1003ac24a5a5Schristos {
1004ac24a5a5Schristos 	int i;
1005ac24a5a5Schristos 
1006ac24a5a5Schristos 	/* Make sure no transfers are pending. */
1007ac24a5a5Schristos 	if (sc->sc_txpipe_low != NULL)
1008ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_txpipe_low);
1009ac24a5a5Schristos 	if (sc->sc_txpipe_normal != NULL)
1010ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_txpipe_normal);
1011ac24a5a5Schristos 
10124e8e6643Sskrll 	for (size_t j = 0; j < URTW_PRIORITY_MAX; j++) {
1013ac24a5a5Schristos 		for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++) {
10144e8e6643Sskrll 			struct urtw_tx_data *data = &sc->sc_tx_data[j][i];
1015ac24a5a5Schristos 
1016ac24a5a5Schristos 			if (data->xfer != NULL) {
10174e8e6643Sskrll 				usbd_destroy_xfer(data->xfer);
1018ac24a5a5Schristos 				data->xfer = NULL;
1019ac24a5a5Schristos 			}
1020ac24a5a5Schristos 			if (data->ni != NULL) {
1021ac24a5a5Schristos 				ieee80211_free_node(data->ni);
1022ac24a5a5Schristos 				data->ni = NULL;
1023ac24a5a5Schristos 			}
1024ac24a5a5Schristos 		}
1025ac24a5a5Schristos 	}
10264e8e6643Sskrll }
1027ac24a5a5Schristos 
102828885f8eSmaxv static int
urtw_media_change(struct ifnet * ifp)1029ac24a5a5Schristos urtw_media_change(struct ifnet *ifp)
1030ac24a5a5Schristos {
1031ac24a5a5Schristos 	int error;
1032ac24a5a5Schristos 
1033ac24a5a5Schristos 	error = ieee80211_media_change(ifp);
1034ac24a5a5Schristos 	if (error != ENETRESET)
10354e8e6643Sskrll 		return error;
1036ac24a5a5Schristos 
1037ac24a5a5Schristos 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
1038ac24a5a5Schristos 	    (IFF_UP | IFF_RUNNING))
1039b4d088cbSriastradh 		if_init(ifp);
1040ac24a5a5Schristos 
10414e8e6643Sskrll 	return 0;
1042ac24a5a5Schristos }
1043ac24a5a5Schristos 
104428885f8eSmaxv static int
urtw_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)1045ac24a5a5Schristos urtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1046ac24a5a5Schristos {
1047ac24a5a5Schristos 	struct urtw_softc *sc = ic->ic_ifp->if_softc;
1048ac24a5a5Schristos 
1049300e2267Sriastradh 	/*
1050300e2267Sriastradh 	 * XXXSMP: This does not wait for the task, if it is in flight,
1051300e2267Sriastradh 	 * to complete.  If this code works at all, it must rely on the
1052300e2267Sriastradh 	 * kernel lock to serialize with the USB task thread.
1053300e2267Sriastradh 	 */
1054ac24a5a5Schristos 	usb_rem_task(sc->sc_udev, &sc->sc_task);
1055ac24a5a5Schristos 	callout_stop(&sc->scan_to);
1056ac24a5a5Schristos 
1057ac24a5a5Schristos 	/* do it in a process context */
1058ac24a5a5Schristos 	sc->sc_state = nstate;
1059ac24a5a5Schristos 	sc->sc_arg = arg;
1060ac24a5a5Schristos 	usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
1061ac24a5a5Schristos 
10624e8e6643Sskrll 	return 0;
1063ac24a5a5Schristos }
1064ac24a5a5Schristos 
106528885f8eSmaxv static usbd_status
urtw_led_init(struct urtw_softc * sc)1066ac24a5a5Schristos urtw_led_init(struct urtw_softc *sc)
1067ac24a5a5Schristos {
1068ac24a5a5Schristos 	uint32_t rev;
1069ac24a5a5Schristos 	usbd_status error;
1070ac24a5a5Schristos 
1071ac24a5a5Schristos 	urtw_read8_m(sc, URTW_PSR, &sc->sc_psr);
1072ac24a5a5Schristos 	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
1073ac24a5a5Schristos 	if (error != 0)
1074ac24a5a5Schristos 		goto fail;
1075ac24a5a5Schristos 
1076ac24a5a5Schristos 	switch (rev & URTW_EPROM_CID_MASK) {
1077ac24a5a5Schristos 	case URTW_EPROM_CID_ALPHA0:
1078ac24a5a5Schristos 		sc->sc_strategy = URTW_SW_LED_MODE1;
1079ac24a5a5Schristos 		break;
1080ac24a5a5Schristos 	case URTW_EPROM_CID_SERCOMM_PS:
1081ac24a5a5Schristos 		sc->sc_strategy = URTW_SW_LED_MODE3;
1082ac24a5a5Schristos 		break;
1083ac24a5a5Schristos 	case URTW_EPROM_CID_HW_LED:
1084ac24a5a5Schristos 		sc->sc_strategy = URTW_HW_LED;
1085ac24a5a5Schristos 		break;
1086ac24a5a5Schristos 	case URTW_EPROM_CID_RSVD0:
1087ac24a5a5Schristos 	case URTW_EPROM_CID_RSVD1:
1088ac24a5a5Schristos 	default:
1089ac24a5a5Schristos 		sc->sc_strategy = URTW_SW_LED_MODE0;
1090ac24a5a5Schristos 		break;
1091ac24a5a5Schristos 	}
1092ac24a5a5Schristos 
1093ac24a5a5Schristos 	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
1094ac24a5a5Schristos 
1095ac24a5a5Schristos fail:
10964e8e6643Sskrll 	return error;
1097ac24a5a5Schristos }
1098ac24a5a5Schristos 
109928885f8eSmaxv static usbd_status
urtw_8225_write_s16(struct urtw_softc * sc,uint8_t addr,int index,uint16_t data)1100ac24a5a5Schristos urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
1101ac24a5a5Schristos     uint16_t data)
1102ac24a5a5Schristos {
1103ac24a5a5Schristos 	usb_device_request_t req;
1104ac24a5a5Schristos 
1105ac24a5a5Schristos 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1106ac24a5a5Schristos 	req.bRequest = URTW_8187_SETREGS_REQ;
1107ac24a5a5Schristos 	USETW(req.wValue, addr);
1108ac24a5a5Schristos 	USETW(req.wIndex, index);
1109ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint16_t));
1110ac24a5a5Schristos 
11114e8e6643Sskrll 	return usbd_do_request(sc->sc_udev, &req, &data);
1112ac24a5a5Schristos }
1113ac24a5a5Schristos 
111428885f8eSmaxv static usbd_status
urtw_8225_read(struct urtw_softc * sc,uint8_t addr,uint32_t * data)1115ac24a5a5Schristos urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
1116ac24a5a5Schristos {
1117ac24a5a5Schristos 	int i;
1118ac24a5a5Schristos 	int16_t bit;
1119ac24a5a5Schristos 	uint8_t rlen = 12, wlen = 6;
1120ac24a5a5Schristos 	uint16_t o1, o2, o3, tmp;
1121ac24a5a5Schristos 	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
1122ac24a5a5Schristos 	uint32_t mask = 0x80000000, value = 0;
1123ac24a5a5Schristos 	usbd_status error;
1124ac24a5a5Schristos 
1125ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1);
1126ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2);
1127ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3);
1128ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | 0xf);
1129ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | 0xf);
1130ac24a5a5Schristos 	o1 &= ~0xf;
1131ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN);
1132ac24a5a5Schristos 	DELAY(5);
1133ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1);
1134ac24a5a5Schristos 	DELAY(5);
1135ac24a5a5Schristos 
1136ac24a5a5Schristos 	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
1137ac24a5a5Schristos 		bit = ((d2w & mask) != 0) ? 1 : 0;
1138ac24a5a5Schristos 
1139ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
1140ac24a5a5Schristos 		DELAY(2);
1141ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
1142ac24a5a5Schristos 		    URTW_BB_HOST_BANG_CLK);
1143ac24a5a5Schristos 		DELAY(2);
1144ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
1145ac24a5a5Schristos 		    URTW_BB_HOST_BANG_CLK);
1146ac24a5a5Schristos 		DELAY(2);
1147ac24a5a5Schristos 		mask = mask >> 1;
1148ac24a5a5Schristos 		if (i == 2)
1149ac24a5a5Schristos 			break;
1150ac24a5a5Schristos 		bit = ((d2w & mask) != 0) ? 1 : 0;
1151ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
1152ac24a5a5Schristos 		    URTW_BB_HOST_BANG_CLK);
1153ac24a5a5Schristos 		DELAY(2);
1154ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
1155ac24a5a5Schristos 		    URTW_BB_HOST_BANG_CLK);
1156ac24a5a5Schristos 		DELAY(2);
1157ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
1158ac24a5a5Schristos 		DELAY(1);
1159ac24a5a5Schristos 	}
1160ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW |
1161ac24a5a5Schristos 	    URTW_BB_HOST_BANG_CLK);
1162ac24a5a5Schristos 	DELAY(2);
1163ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW);
1164ac24a5a5Schristos 	DELAY(2);
1165ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW);
1166ac24a5a5Schristos 	DELAY(2);
1167ac24a5a5Schristos 
1168ac24a5a5Schristos 	mask = 0x800;
1169ac24a5a5Schristos 	for (i = 0; i < rlen; i++, mask = mask >> 1) {
1170ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
1171ac24a5a5Schristos 		    o1 | URTW_BB_HOST_BANG_RW);
1172ac24a5a5Schristos 		DELAY(2);
1173ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
1174ac24a5a5Schristos 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
1175ac24a5a5Schristos 		DELAY(2);
1176ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
1177ac24a5a5Schristos 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
1178ac24a5a5Schristos 		DELAY(2);
1179ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
1180ac24a5a5Schristos 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
1181ac24a5a5Schristos 		DELAY(2);
1182ac24a5a5Schristos 
1183ac24a5a5Schristos 		urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp);
1184ac24a5a5Schristos 		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
1185ac24a5a5Schristos 		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
1186ac24a5a5Schristos 		    o1 | URTW_BB_HOST_BANG_RW);
1187ac24a5a5Schristos 		DELAY(2);
1188ac24a5a5Schristos 	}
1189ac24a5a5Schristos 
1190ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN |
1191ac24a5a5Schristos 	    URTW_BB_HOST_BANG_RW);
1192ac24a5a5Schristos 	DELAY(2);
1193ac24a5a5Schristos 
1194ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2);
1195ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3);
1196ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x3a0);
1197ac24a5a5Schristos 
1198ac24a5a5Schristos 	if (data != NULL)
1199ac24a5a5Schristos 		*data = value;
1200ac24a5a5Schristos fail:
12014e8e6643Sskrll 	return error;
1202ac24a5a5Schristos }
1203ac24a5a5Schristos 
120428885f8eSmaxv static usbd_status
urtw_8225_write_c(struct urtw_softc * sc,uint8_t addr,uint16_t data)1205ac24a5a5Schristos urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
1206ac24a5a5Schristos {
1207ac24a5a5Schristos 	uint16_t d80, d82, d84;
1208ac24a5a5Schristos 	usbd_status error;
1209ac24a5a5Schristos 
1210ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80);
1211ac24a5a5Schristos 	d80 &= 0xfff3;
1212ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82);
1213ac24a5a5Schristos 	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84);
1214ac24a5a5Schristos 	d84 &= 0xfff0;
1215ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | 0x0007);
1216ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | 0x0007);
1217ac24a5a5Schristos 	DELAY(10);
1218ac24a5a5Schristos 
1219ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
1220ac24a5a5Schristos 	DELAY(2);
1221ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80);
1222ac24a5a5Schristos 	DELAY(10);
1223ac24a5a5Schristos 
1224ac24a5a5Schristos 	error = urtw_8225_write_s16(sc, addr, 0x8225, data);
1225ac24a5a5Schristos 	if (error != 0)
1226ac24a5a5Schristos 		goto fail;
1227ac24a5a5Schristos 
1228ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
1229ac24a5a5Schristos 	DELAY(10);
1230ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
1231ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84);
1232ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 2);
1233ac24a5a5Schristos fail:
12344e8e6643Sskrll 	return error;
1235ac24a5a5Schristos }
1236ac24a5a5Schristos 
123728885f8eSmaxv static usbd_status
urtw_8225_isv2(struct urtw_softc * sc,int * ret)1238ac24a5a5Schristos urtw_8225_isv2(struct urtw_softc *sc, int *ret)
1239ac24a5a5Schristos {
1240ac24a5a5Schristos 	uint32_t data;
1241ac24a5a5Schristos 	usbd_status error;
1242ac24a5a5Schristos 
1243ac24a5a5Schristos 	*ret = 1;
1244ac24a5a5Schristos 
1245ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0080);
1246ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x0080);
1247ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x0080);
1248ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 500);
1249ac24a5a5Schristos 
1250ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x1b7);
1251ac24a5a5Schristos 
1252ac24a5a5Schristos 	error = urtw_8225_read(sc, 0x8, &data);
1253ac24a5a5Schristos 	if (error != 0)
1254ac24a5a5Schristos 		goto fail;
1255ac24a5a5Schristos 	if (data != 0x588)
1256ac24a5a5Schristos 		*ret = 0;
1257ac24a5a5Schristos 	else {
1258ac24a5a5Schristos 		error = urtw_8225_read(sc, 0x9, &data);
1259ac24a5a5Schristos 		if (error != 0)
1260ac24a5a5Schristos 			goto fail;
1261ac24a5a5Schristos 		if (data != 0x700)
1262ac24a5a5Schristos 			*ret = 0;
1263ac24a5a5Schristos 	}
1264ac24a5a5Schristos 
1265ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0xb7);
1266ac24a5a5Schristos fail:
12674e8e6643Sskrll 	return error;
1268ac24a5a5Schristos }
1269ac24a5a5Schristos 
127028885f8eSmaxv static usbd_status
urtw_get_rfchip(struct urtw_softc * sc)1271ac24a5a5Schristos urtw_get_rfchip(struct urtw_softc *sc)
1272ac24a5a5Schristos {
1273ac24a5a5Schristos 	struct urtw_rf *rf = &sc->sc_rf;
1274ac24a5a5Schristos 	int ret;
1275ac24a5a5Schristos 	uint32_t data;
1276ac24a5a5Schristos 	usbd_status error;
1277ac24a5a5Schristos 
1278ac24a5a5Schristos 	rf->rf_sc = sc;
1279ac24a5a5Schristos 
1280ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
1281ac24a5a5Schristos 		error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
1282ac24a5a5Schristos 		if (error != 0)
1283e11ff962Smaxv 			return error;
1284ac24a5a5Schristos 		switch (data & 0xff) {
1285ac24a5a5Schristos 		case URTW_EPROM_RFCHIPID_RTL8225U:
1286ac24a5a5Schristos 			error = urtw_8225_isv2(sc, &ret);
1287ac24a5a5Schristos 			if (error != 0)
1288ac24a5a5Schristos 				goto fail;
1289ac24a5a5Schristos 			if (ret == 0) {
1290ac24a5a5Schristos 				rf->init = urtw_8225_rf_init;
1291ac24a5a5Schristos 				rf->set_chan = urtw_8225_rf_set_chan;
1292ac24a5a5Schristos 				rf->set_sens = urtw_8225_rf_set_sens;
1293ac24a5a5Schristos 				printf(", RFv1");
1294ac24a5a5Schristos 			} else {
1295ac24a5a5Schristos 				rf->init = urtw_8225v2_rf_init;
1296ac24a5a5Schristos 				rf->set_chan = urtw_8225v2_rf_set_chan;
1297ac24a5a5Schristos 				rf->set_sens = NULL;
1298ac24a5a5Schristos 				printf(", RFv2");
1299ac24a5a5Schristos 			}
1300ac24a5a5Schristos 			break;
1301ac24a5a5Schristos 		default:
1302ac24a5a5Schristos 			goto fail;
1303ac24a5a5Schristos 		}
1304ac24a5a5Schristos 	} else {
1305ac24a5a5Schristos 		rf->init = urtw_8225v2_b_rf_init;
1306ac24a5a5Schristos 		rf->set_chan = urtw_8225v2_b_rf_set_chan;
1307ac24a5a5Schristos 		rf->set_sens = NULL;
1308ac24a5a5Schristos 	}
1309ac24a5a5Schristos 
1310ac24a5a5Schristos 	rf->max_sens = URTW_8225_RF_MAX_SENS;
1311ac24a5a5Schristos 	rf->sens = URTW_8225_RF_DEF_SENS;
1312ac24a5a5Schristos 
13134e8e6643Sskrll 	return 0;
1314ac24a5a5Schristos 
1315ac24a5a5Schristos fail:
1316e11ff962Smaxv 	aprint_error(": unsupported RF chip %d", data & 0xff);
1317e11ff962Smaxv 	return USBD_INVAL;
1318ac24a5a5Schristos }
1319ac24a5a5Schristos 
132028885f8eSmaxv static usbd_status
urtw_get_txpwr(struct urtw_softc * sc)1321ac24a5a5Schristos urtw_get_txpwr(struct urtw_softc *sc)
1322ac24a5a5Schristos {
1323ac24a5a5Schristos 	int i, j;
1324ac24a5a5Schristos 	uint32_t data;
1325ac24a5a5Schristos 	usbd_status error;
1326ac24a5a5Schristos 
1327ac24a5a5Schristos 	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
1328ac24a5a5Schristos 	if (error != 0)
1329ac24a5a5Schristos 		goto fail;
1330ac24a5a5Schristos 	sc->sc_txpwr_cck_base = data & 0xf;
1331ac24a5a5Schristos 	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
1332ac24a5a5Schristos 
1333ac24a5a5Schristos 	for (i = 1, j = 0; i < 6; i += 2, j++) {
1334ac24a5a5Schristos 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
1335ac24a5a5Schristos 		if (error != 0)
1336ac24a5a5Schristos 			goto fail;
1337ac24a5a5Schristos 		sc->sc_txpwr_cck[i] = data & 0xf;
1338ac24a5a5Schristos 		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
1339ac24a5a5Schristos 		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
1340ac24a5a5Schristos 		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
1341ac24a5a5Schristos 	}
1342ac24a5a5Schristos 	for (i = 1, j = 0; i < 4; i += 2, j++) {
1343ac24a5a5Schristos 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
1344ac24a5a5Schristos 		if (error != 0)
1345ac24a5a5Schristos 			goto fail;
1346ac24a5a5Schristos 		sc->sc_txpwr_cck[i + 6] = data & 0xf;
1347ac24a5a5Schristos 		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
1348ac24a5a5Schristos 		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
1349ac24a5a5Schristos 		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
1350ac24a5a5Schristos 	}
1351ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
1352ac24a5a5Schristos 		for (i = 1, j = 0; i < 4; i += 2, j++) {
1353ac24a5a5Schristos 			error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
1354ac24a5a5Schristos 			    &data);
1355ac24a5a5Schristos 			if (error != 0)
1356ac24a5a5Schristos 				goto fail;
1357ac24a5a5Schristos 			sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
1358ac24a5a5Schristos 			sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
1359ac24a5a5Schristos 			sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
1360ac24a5a5Schristos 			sc->sc_txpwr_ofdm[i + 6 + 4 + 1] =
1361ac24a5a5Schristos 			    (data & 0xf000) >> 12;
1362ac24a5a5Schristos 		}
1363ac24a5a5Schristos 	} else {
1364ac24a5a5Schristos 		/* Channel 11. */
1365ac24a5a5Schristos 		error = urtw_eprom_read32(sc, 0x1b, &data);
1366ac24a5a5Schristos 		if (error != 0)
1367ac24a5a5Schristos 			goto fail;
1368ac24a5a5Schristos 		sc->sc_txpwr_cck[11] = data & 0xf;
1369ac24a5a5Schristos 		sc->sc_txpwr_ofdm[11] = (data & 0xf0) >> 4;
1370ac24a5a5Schristos 
1371ac24a5a5Schristos 		/* Channel 12. */
1372ac24a5a5Schristos 		error = urtw_eprom_read32(sc, 0xa, &data);
1373ac24a5a5Schristos 		if (error != 0)
1374ac24a5a5Schristos 			goto fail;
1375ac24a5a5Schristos 		sc->sc_txpwr_cck[12] = data & 0xf;
1376ac24a5a5Schristos 		sc->sc_txpwr_ofdm[12] = (data & 0xf0) >> 4;
1377ac24a5a5Schristos 
1378ac24a5a5Schristos 		/* Channel 13, 14. */
1379ac24a5a5Schristos 		error = urtw_eprom_read32(sc, 0x1c, &data);
1380ac24a5a5Schristos 		if (error != 0)
1381ac24a5a5Schristos 			goto fail;
1382ac24a5a5Schristos 		sc->sc_txpwr_cck[13] = data & 0xf;
1383ac24a5a5Schristos 		sc->sc_txpwr_ofdm[13] = (data & 0xf0) >> 4;
1384ac24a5a5Schristos 		sc->sc_txpwr_cck[14] = (data & 0xf00) >> 8;
1385ac24a5a5Schristos 		sc->sc_txpwr_ofdm[14] = (data & 0xf000) >> 12;
1386ac24a5a5Schristos 	}
1387ac24a5a5Schristos fail:
13884e8e6643Sskrll 	return error;
1389ac24a5a5Schristos }
1390ac24a5a5Schristos 
139128885f8eSmaxv static usbd_status
urtw_get_macaddr(struct urtw_softc * sc)1392ac24a5a5Schristos urtw_get_macaddr(struct urtw_softc *sc)
1393ac24a5a5Schristos {
1394ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
1395ac24a5a5Schristos 	usbd_status error;
1396ac24a5a5Schristos 	uint32_t data;
1397ac24a5a5Schristos 
1398ac24a5a5Schristos 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
1399ac24a5a5Schristos 	if (error != 0)
1400ac24a5a5Schristos 		goto fail;
1401ac24a5a5Schristos 	ic->ic_myaddr[0] = data & 0xff;
1402ac24a5a5Schristos 	ic->ic_myaddr[1] = (data & 0xff00) >> 8;
1403ac24a5a5Schristos 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
1404ac24a5a5Schristos 	if (error != 0)
1405ac24a5a5Schristos 		goto fail;
1406ac24a5a5Schristos 	ic->ic_myaddr[2] = data & 0xff;
1407ac24a5a5Schristos 	ic->ic_myaddr[3] = (data & 0xff00) >> 8;
1408ac24a5a5Schristos 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
1409ac24a5a5Schristos 	if (error != 0)
1410ac24a5a5Schristos 		goto fail;
1411ac24a5a5Schristos 	ic->ic_myaddr[4] = data & 0xff;
1412ac24a5a5Schristos 	ic->ic_myaddr[5] = (data & 0xff00) >> 8;
1413ac24a5a5Schristos fail:
14144e8e6643Sskrll 	return error;
1415ac24a5a5Schristos }
1416ac24a5a5Schristos 
141728885f8eSmaxv static usbd_status
urtw_eprom_read32(struct urtw_softc * sc,uint32_t addr,uint32_t * data)1418ac24a5a5Schristos urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
1419ac24a5a5Schristos {
1420ac24a5a5Schristos #define URTW_READCMD_LEN		3
1421ac24a5a5Schristos 	int addrlen, i;
1422ac24a5a5Schristos 	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
1423ac24a5a5Schristos 	usbd_status error;
1424ac24a5a5Schristos 
1425ac24a5a5Schristos 	/* NB: make sure the buffer is initialized */
1426ac24a5a5Schristos 	*data = 0;
1427ac24a5a5Schristos 
1428ac24a5a5Schristos 	/* enable EPROM programming */
1429ac24a5a5Schristos 	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE);
1430ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1431ac24a5a5Schristos 
1432ac24a5a5Schristos 	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
1433ac24a5a5Schristos 	if (error != 0)
1434ac24a5a5Schristos 		goto fail;
1435ac24a5a5Schristos 	error = urtw_eprom_ck(sc);
1436ac24a5a5Schristos 	if (error != 0)
1437ac24a5a5Schristos 		goto fail;
1438ac24a5a5Schristos 	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
1439ac24a5a5Schristos 	if (error != 0)
1440ac24a5a5Schristos 		goto fail;
1441ac24a5a5Schristos 	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
1442ac24a5a5Schristos 		addrlen = 8;
1443ac24a5a5Schristos 		addrstr[0] = addr & (1 << 7);
1444ac24a5a5Schristos 		addrstr[1] = addr & (1 << 6);
1445ac24a5a5Schristos 		addrstr[2] = addr & (1 << 5);
1446ac24a5a5Schristos 		addrstr[3] = addr & (1 << 4);
1447ac24a5a5Schristos 		addrstr[4] = addr & (1 << 3);
1448ac24a5a5Schristos 		addrstr[5] = addr & (1 << 2);
1449ac24a5a5Schristos 		addrstr[6] = addr & (1 << 1);
1450ac24a5a5Schristos 		addrstr[7] = addr & (1 << 0);
1451ac24a5a5Schristos 	} else {
1452ac24a5a5Schristos 		addrlen=6;
1453ac24a5a5Schristos 		addrstr[0] = addr & (1 << 5);
1454ac24a5a5Schristos 		addrstr[1] = addr & (1 << 4);
1455ac24a5a5Schristos 		addrstr[2] = addr & (1 << 3);
1456ac24a5a5Schristos 		addrstr[3] = addr & (1 << 2);
1457ac24a5a5Schristos 		addrstr[4] = addr & (1 << 1);
1458ac24a5a5Schristos 		addrstr[5] = addr & (1 << 0);
1459ac24a5a5Schristos 	}
1460ac24a5a5Schristos 	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
1461ac24a5a5Schristos 	if (error != 0)
1462ac24a5a5Schristos 		goto fail;
1463ac24a5a5Schristos 
1464ac24a5a5Schristos 	error = urtw_eprom_writebit(sc, 0);
1465ac24a5a5Schristos 	if (error != 0)
1466ac24a5a5Schristos 		goto fail;
1467ac24a5a5Schristos 
1468ac24a5a5Schristos 	for (i = 0; i < 16; i++) {
1469ac24a5a5Schristos 		error = urtw_eprom_ck(sc);
1470ac24a5a5Schristos 		if (error != 0)
1471ac24a5a5Schristos 			goto fail;
1472ac24a5a5Schristos 		error = urtw_eprom_readbit(sc, &data16);
1473ac24a5a5Schristos 		if (error != 0)
1474ac24a5a5Schristos 			goto fail;
1475ac24a5a5Schristos 
1476ac24a5a5Schristos 		(*data) |= (data16 << (15 - i));
1477ac24a5a5Schristos 	}
1478ac24a5a5Schristos 
1479ac24a5a5Schristos 	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
1480ac24a5a5Schristos 	if (error != 0)
1481ac24a5a5Schristos 		goto fail;
1482ac24a5a5Schristos 	error = urtw_eprom_ck(sc);
1483ac24a5a5Schristos 	if (error != 0)
1484ac24a5a5Schristos 		goto fail;
1485ac24a5a5Schristos 
1486ac24a5a5Schristos 	/* now disable EPROM programming */
1487ac24a5a5Schristos 	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE);
1488ac24a5a5Schristos fail:
14894e8e6643Sskrll 	return error;
1490ac24a5a5Schristos #undef URTW_READCMD_LEN
1491ac24a5a5Schristos }
1492ac24a5a5Schristos 
149328885f8eSmaxv static usbd_status
urtw_eprom_readbit(struct urtw_softc * sc,int16_t * data)1494ac24a5a5Schristos urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
1495ac24a5a5Schristos {
1496ac24a5a5Schristos 	uint8_t data8;
1497ac24a5a5Schristos 	usbd_status error;
1498ac24a5a5Schristos 
1499ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data8);
1500ac24a5a5Schristos 	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
1501ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1502ac24a5a5Schristos 
1503ac24a5a5Schristos fail:
15044e8e6643Sskrll 	return error;
1505ac24a5a5Schristos }
1506ac24a5a5Schristos 
150728885f8eSmaxv static usbd_status
urtw_eprom_sendbits(struct urtw_softc * sc,int16_t * buf,int buflen)1508ac24a5a5Schristos urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
1509ac24a5a5Schristos {
1510ac24a5a5Schristos 	int i = 0;
1511ac24a5a5Schristos 	usbd_status error = 0;
1512ac24a5a5Schristos 
1513ac24a5a5Schristos 	for (i = 0; i < buflen; i++) {
1514ac24a5a5Schristos 		error = urtw_eprom_writebit(sc, buf[i]);
1515ac24a5a5Schristos 		if (error != 0)
1516ac24a5a5Schristos 			goto fail;
1517ac24a5a5Schristos 		error = urtw_eprom_ck(sc);
1518ac24a5a5Schristos 		if (error != 0)
1519ac24a5a5Schristos 			goto fail;
1520ac24a5a5Schristos 	}
1521ac24a5a5Schristos fail:
15224e8e6643Sskrll 	return error;
1523ac24a5a5Schristos }
1524ac24a5a5Schristos 
152528885f8eSmaxv static usbd_status
urtw_eprom_writebit(struct urtw_softc * sc,int16_t bit)1526ac24a5a5Schristos urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
1527ac24a5a5Schristos {
1528ac24a5a5Schristos 	uint8_t data;
1529ac24a5a5Schristos 	usbd_status error;
1530ac24a5a5Schristos 
1531ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1532ac24a5a5Schristos 	if (bit != 0)
1533ac24a5a5Schristos 		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT);
1534ac24a5a5Schristos 	else
1535ac24a5a5Schristos 		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT);
1536ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1537ac24a5a5Schristos fail:
15384e8e6643Sskrll 	return error;
1539ac24a5a5Schristos }
1540ac24a5a5Schristos 
154128885f8eSmaxv static usbd_status
urtw_eprom_ck(struct urtw_softc * sc)1542ac24a5a5Schristos urtw_eprom_ck(struct urtw_softc *sc)
1543ac24a5a5Schristos {
1544ac24a5a5Schristos 	uint8_t data;
1545ac24a5a5Schristos 	usbd_status error;
1546ac24a5a5Schristos 
1547ac24a5a5Schristos 	/* masking */
1548ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1549ac24a5a5Schristos 	urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK);
1550ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1551ac24a5a5Schristos 	/* unmasking */
1552ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1553ac24a5a5Schristos 	urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK);
1554ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1555ac24a5a5Schristos fail:
15564e8e6643Sskrll 	return error;
1557ac24a5a5Schristos }
1558ac24a5a5Schristos 
155928885f8eSmaxv static usbd_status
urtw_eprom_cs(struct urtw_softc * sc,int able)1560ac24a5a5Schristos urtw_eprom_cs(struct urtw_softc *sc, int able)
1561ac24a5a5Schristos {
1562ac24a5a5Schristos 	uint8_t data;
1563ac24a5a5Schristos 	usbd_status error;
1564ac24a5a5Schristos 
1565ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1566ac24a5a5Schristos 	if (able == URTW_EPROM_ENABLE)
1567ac24a5a5Schristos 		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS);
1568ac24a5a5Schristos 	else
1569ac24a5a5Schristos 		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS);
1570ac24a5a5Schristos 	DELAY(URTW_EPROM_DELAY);
1571ac24a5a5Schristos fail:
15724e8e6643Sskrll 	return error;
1573ac24a5a5Schristos }
1574ac24a5a5Schristos 
157528885f8eSmaxv static usbd_status
urtw_read8_c(struct urtw_softc * sc,int val,uint8_t * data,uint8_t idx)1576ac24a5a5Schristos urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data, uint8_t idx)
1577ac24a5a5Schristos {
1578ac24a5a5Schristos 	usb_device_request_t req;
1579ac24a5a5Schristos 	usbd_status error;
1580ac24a5a5Schristos 
1581ac24a5a5Schristos 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1582ac24a5a5Schristos 	req.bRequest = URTW_8187_GETREGS_REQ;
1583ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1584ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1585ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint8_t));
1586ac24a5a5Schristos 
1587ac24a5a5Schristos 	error = usbd_do_request(sc->sc_udev, &req, data);
15884e8e6643Sskrll 	return error;
1589ac24a5a5Schristos }
1590ac24a5a5Schristos 
159128885f8eSmaxv static usbd_status
urtw_read8e(struct urtw_softc * sc,int val,uint8_t * data)1592ac24a5a5Schristos urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
1593ac24a5a5Schristos {
1594ac24a5a5Schristos 	usb_device_request_t req;
1595ac24a5a5Schristos 	usbd_status error;
1596ac24a5a5Schristos 
1597ac24a5a5Schristos 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1598ac24a5a5Schristos 	req.bRequest = URTW_8187_GETREGS_REQ;
1599ac24a5a5Schristos 	USETW(req.wValue, val | 0xfe00);
1600ac24a5a5Schristos 	USETW(req.wIndex, 0);
1601ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint8_t));
1602ac24a5a5Schristos 
1603ac24a5a5Schristos 	error = usbd_do_request(sc->sc_udev, &req, data);
16044e8e6643Sskrll 	return error;
1605ac24a5a5Schristos }
1606ac24a5a5Schristos 
160728885f8eSmaxv static usbd_status
urtw_read16_c(struct urtw_softc * sc,int val,uint16_t * data,uint8_t idx)1608ac24a5a5Schristos urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data, uint8_t idx)
1609ac24a5a5Schristos {
1610ac24a5a5Schristos 	usb_device_request_t req;
1611ac24a5a5Schristos 	usbd_status error;
1612ac24a5a5Schristos 
1613ac24a5a5Schristos 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1614ac24a5a5Schristos 	req.bRequest = URTW_8187_GETREGS_REQ;
1615ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1616ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1617ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint16_t));
1618ac24a5a5Schristos 
1619ac24a5a5Schristos 	error = usbd_do_request(sc->sc_udev, &req, data);
16204e8e6643Sskrll 	return error;
1621ac24a5a5Schristos }
1622ac24a5a5Schristos 
162328885f8eSmaxv static usbd_status
urtw_read32_c(struct urtw_softc * sc,int val,uint32_t * data,uint8_t idx)1624ac24a5a5Schristos urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data, uint8_t idx)
1625ac24a5a5Schristos {
1626ac24a5a5Schristos 	usb_device_request_t req;
1627ac24a5a5Schristos 	usbd_status error;
1628ac24a5a5Schristos 
1629ac24a5a5Schristos 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1630ac24a5a5Schristos 	req.bRequest = URTW_8187_GETREGS_REQ;
1631ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1632ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1633ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint32_t));
1634ac24a5a5Schristos 
1635ac24a5a5Schristos 	error = usbd_do_request(sc->sc_udev, &req, data);
16364e8e6643Sskrll 	return error;
1637ac24a5a5Schristos }
1638ac24a5a5Schristos 
163928885f8eSmaxv static usbd_status
urtw_write8_c(struct urtw_softc * sc,int val,uint8_t data,uint8_t idx)1640ac24a5a5Schristos urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data, uint8_t idx)
1641ac24a5a5Schristos {
1642ac24a5a5Schristos 	usb_device_request_t req;
1643ac24a5a5Schristos 
1644ac24a5a5Schristos 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1645ac24a5a5Schristos 	req.bRequest = URTW_8187_SETREGS_REQ;
1646ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1647ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1648ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint8_t));
1649ac24a5a5Schristos 
16504e8e6643Sskrll 	return usbd_do_request(sc->sc_udev, &req, &data);
1651ac24a5a5Schristos }
1652ac24a5a5Schristos 
165328885f8eSmaxv static usbd_status
urtw_write8e(struct urtw_softc * sc,int val,uint8_t data)1654ac24a5a5Schristos urtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
1655ac24a5a5Schristos {
1656ac24a5a5Schristos 	usb_device_request_t req;
1657ac24a5a5Schristos 
1658ac24a5a5Schristos 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1659ac24a5a5Schristos 	req.bRequest = URTW_8187_SETREGS_REQ;
1660ac24a5a5Schristos 	USETW(req.wValue, val | 0xfe00);
1661ac24a5a5Schristos 	USETW(req.wIndex, 0);
1662ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint8_t));
1663ac24a5a5Schristos 
16644e8e6643Sskrll 	return usbd_do_request(sc->sc_udev, &req, &data);
1665ac24a5a5Schristos }
1666ac24a5a5Schristos 
166728885f8eSmaxv static usbd_status
urtw_write16_c(struct urtw_softc * sc,int val,uint16_t data,uint8_t idx)1668ac24a5a5Schristos urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data, uint8_t idx)
1669ac24a5a5Schristos {
1670ac24a5a5Schristos 	usb_device_request_t req;
1671ac24a5a5Schristos 
1672ac24a5a5Schristos 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1673ac24a5a5Schristos 	req.bRequest = URTW_8187_SETREGS_REQ;
1674ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1675ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1676ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint16_t));
1677ac24a5a5Schristos 
16784e8e6643Sskrll 	return usbd_do_request(sc->sc_udev, &req, &data);
1679ac24a5a5Schristos }
1680ac24a5a5Schristos 
168128885f8eSmaxv static usbd_status
urtw_write32_c(struct urtw_softc * sc,int val,uint32_t data,uint8_t idx)1682ac24a5a5Schristos urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data, uint8_t idx)
1683ac24a5a5Schristos {
1684ac24a5a5Schristos 	usb_device_request_t req;
1685ac24a5a5Schristos 
1686ac24a5a5Schristos 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1687ac24a5a5Schristos 	req.bRequest = URTW_8187_SETREGS_REQ;
1688ac24a5a5Schristos 	USETW(req.wValue, val | 0xff00);
1689ac24a5a5Schristos 	USETW(req.wIndex, idx & 0x03);
1690ac24a5a5Schristos 	USETW(req.wLength, sizeof(uint32_t));
1691ac24a5a5Schristos 
16924e8e6643Sskrll 	return usbd_do_request(sc->sc_udev, &req, &data);
1693ac24a5a5Schristos }
1694ac24a5a5Schristos 
1695ac24a5a5Schristos static usbd_status
urtw_set_mode(struct urtw_softc * sc,uint32_t mode)1696ac24a5a5Schristos urtw_set_mode(struct urtw_softc *sc, uint32_t mode)
1697ac24a5a5Schristos {
1698ac24a5a5Schristos 	uint8_t data;
1699ac24a5a5Schristos 	usbd_status error;
1700ac24a5a5Schristos 
1701ac24a5a5Schristos 	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
1702ac24a5a5Schristos 	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
1703ac24a5a5Schristos 	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
1704ac24a5a5Schristos 	urtw_write8_m(sc, URTW_EPROM_CMD, data);
1705ac24a5a5Schristos fail:
17064e8e6643Sskrll 	return error;
1707ac24a5a5Schristos }
1708ac24a5a5Schristos 
170928885f8eSmaxv static usbd_status
urtw_8180_set_anaparam(struct urtw_softc * sc,uint32_t val)1710ac24a5a5Schristos urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
1711ac24a5a5Schristos {
1712ac24a5a5Schristos 	uint8_t data;
1713ac24a5a5Schristos 	usbd_status error;
1714ac24a5a5Schristos 
1715ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1716ac24a5a5Schristos 	if (error)
1717ac24a5a5Schristos 		goto fail;
1718ac24a5a5Schristos 
1719ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
1720ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
1721ac24a5a5Schristos 	urtw_write32_m(sc, URTW_ANAPARAM, val);
1722ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
1723ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
1724ac24a5a5Schristos 
1725ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1726ac24a5a5Schristos 	if (error)
1727ac24a5a5Schristos 		goto fail;
1728ac24a5a5Schristos fail:
17294e8e6643Sskrll 	return error;
1730ac24a5a5Schristos }
1731ac24a5a5Schristos 
173228885f8eSmaxv static usbd_status
urtw_8185_set_anaparam2(struct urtw_softc * sc,uint32_t val)1733ac24a5a5Schristos urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
1734ac24a5a5Schristos {
1735ac24a5a5Schristos 	uint8_t data;
1736ac24a5a5Schristos 	usbd_status error;
1737ac24a5a5Schristos 
1738ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1739ac24a5a5Schristos 	if (error)
1740ac24a5a5Schristos 		goto fail;
1741ac24a5a5Schristos 
1742ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
1743ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
1744ac24a5a5Schristos 	urtw_write32_m(sc, URTW_ANAPARAM2, val);
1745ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
1746ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
1747ac24a5a5Schristos 
1748ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1749ac24a5a5Schristos 	if (error)
1750ac24a5a5Schristos 		goto fail;
1751ac24a5a5Schristos fail:
17524e8e6643Sskrll 	return error;
1753ac24a5a5Schristos }
1754ac24a5a5Schristos 
175528885f8eSmaxv static usbd_status
urtw_intr_disable(struct urtw_softc * sc)1756ac24a5a5Schristos urtw_intr_disable(struct urtw_softc *sc)
1757ac24a5a5Schristos {
1758ac24a5a5Schristos 	usbd_status error;
1759ac24a5a5Schristos 
1760ac24a5a5Schristos 	urtw_write16_m(sc, URTW_INTR_MASK, 0);
1761ac24a5a5Schristos 
1762ac24a5a5Schristos fail:
17634e8e6643Sskrll 	return error;
1764ac24a5a5Schristos }
1765ac24a5a5Schristos 
176628885f8eSmaxv static usbd_status
urtw_reset(struct urtw_softc * sc)1767ac24a5a5Schristos urtw_reset(struct urtw_softc *sc)
1768ac24a5a5Schristos {
1769ac24a5a5Schristos 	uint8_t data;
1770ac24a5a5Schristos 	usbd_status error;
1771ac24a5a5Schristos 
1772ac24a5a5Schristos 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
1773ac24a5a5Schristos 	if (error)
1774ac24a5a5Schristos 		goto fail;
1775ac24a5a5Schristos 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
1776ac24a5a5Schristos 	if (error)
1777ac24a5a5Schristos 		goto fail;
1778ac24a5a5Schristos 
1779ac24a5a5Schristos 	error = urtw_intr_disable(sc);
1780ac24a5a5Schristos 	if (error)
1781ac24a5a5Schristos 		goto fail;
1782ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
1783ac24a5a5Schristos 
1784ac24a5a5Schristos 	error = urtw_write8e(sc, 0x18, 0x10);
1785ac24a5a5Schristos 	if (error != 0)
1786ac24a5a5Schristos 		goto fail;
1787ac24a5a5Schristos 	error = urtw_write8e(sc, 0x18, 0x11);
1788ac24a5a5Schristos 	if (error != 0)
1789ac24a5a5Schristos 		goto fail;
1790ac24a5a5Schristos 	error = urtw_write8e(sc, 0x18, 0x00);
1791ac24a5a5Schristos 	if (error != 0)
1792ac24a5a5Schristos 		goto fail;
1793ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
1794ac24a5a5Schristos 
1795ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
1796ac24a5a5Schristos 	data = (data & 2) | URTW_CMD_RST;
1797ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, data);
1798ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
1799ac24a5a5Schristos 
1800ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
1801ac24a5a5Schristos 	if (data & URTW_CMD_RST) {
1802ac24a5a5Schristos 		printf("%s: reset timeout\n", device_xname(sc->sc_dev));
1803ac24a5a5Schristos 		goto fail;
1804ac24a5a5Schristos 	}
1805ac24a5a5Schristos 
1806ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
1807ac24a5a5Schristos 	if (error)
1808ac24a5a5Schristos 		goto fail;
1809ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
1810ac24a5a5Schristos 
1811ac24a5a5Schristos 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
1812ac24a5a5Schristos 	if (error)
1813ac24a5a5Schristos 		goto fail;
1814ac24a5a5Schristos 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
1815ac24a5a5Schristos 	if (error)
1816ac24a5a5Schristos 		goto fail;
1817ac24a5a5Schristos fail:
18184e8e6643Sskrll 	return error;
1819ac24a5a5Schristos }
1820ac24a5a5Schristos 
182128885f8eSmaxv static usbd_status
urtw_led_on(struct urtw_softc * sc,int type)1822ac24a5a5Schristos urtw_led_on(struct urtw_softc *sc, int type)
1823ac24a5a5Schristos {
1824ac24a5a5Schristos 	usbd_status error;
1825ac24a5a5Schristos 
1826ac24a5a5Schristos 	if (type == URTW_LED_GPIO) {
1827ac24a5a5Schristos 		switch (sc->sc_gpio_ledpin) {
1828ac24a5a5Schristos 		case URTW_LED_PIN_GPIO0:
1829ac24a5a5Schristos 			urtw_write8_m(sc, URTW_GPIO, 0x01);
1830ac24a5a5Schristos 			urtw_write8_m(sc, URTW_GP_ENABLE, 0x00);
1831ac24a5a5Schristos 			break;
1832ac24a5a5Schristos 		default:
1833d3dde16cSchristos 			panic("unsupported LED PIN type %#x",
1834ac24a5a5Schristos 			    sc->sc_gpio_ledpin);
1835ac24a5a5Schristos 			/* NOTREACHED */
1836ac24a5a5Schristos 		}
1837ac24a5a5Schristos 	} else {
1838d3dde16cSchristos 		panic("unsupported LED type %#x", type);
1839ac24a5a5Schristos 		/* NOTREACHED */
1840ac24a5a5Schristos 	}
1841ac24a5a5Schristos 
1842ac24a5a5Schristos 	sc->sc_gpio_ledon = 1;
1843ac24a5a5Schristos fail:
18444e8e6643Sskrll 	return error;
1845ac24a5a5Schristos }
1846ac24a5a5Schristos 
1847ac24a5a5Schristos static usbd_status
urtw_led_off(struct urtw_softc * sc,int type)1848ac24a5a5Schristos urtw_led_off(struct urtw_softc *sc, int type)
1849ac24a5a5Schristos {
1850ac24a5a5Schristos 	usbd_status error;
1851ac24a5a5Schristos 
1852ac24a5a5Schristos 	if (type == URTW_LED_GPIO) {
1853ac24a5a5Schristos 		switch (sc->sc_gpio_ledpin) {
1854ac24a5a5Schristos 		case URTW_LED_PIN_GPIO0:
1855ac24a5a5Schristos 			urtw_write8_m(sc, URTW_GPIO, 0x01);
1856ac24a5a5Schristos 			urtw_write8_m(sc, URTW_GP_ENABLE, 0x01);
1857ac24a5a5Schristos 			break;
1858ac24a5a5Schristos 		default:
1859d3dde16cSchristos 			panic("unsupported LED PIN type %#x",
1860ac24a5a5Schristos 			    sc->sc_gpio_ledpin);
1861ac24a5a5Schristos 			/* NOTREACHED */
1862ac24a5a5Schristos 		}
1863ac24a5a5Schristos 	} else {
1864d3dde16cSchristos 		panic("unsupported LED type %#x", type);
1865ac24a5a5Schristos 		/* NOTREACHED */
1866ac24a5a5Schristos 	}
1867ac24a5a5Schristos 
1868ac24a5a5Schristos 	sc->sc_gpio_ledon = 0;
1869ac24a5a5Schristos 
1870ac24a5a5Schristos fail:
18714e8e6643Sskrll 	return error;
1872ac24a5a5Schristos }
1873ac24a5a5Schristos 
187428885f8eSmaxv static usbd_status
urtw_led_mode0(struct urtw_softc * sc,int mode)1875ac24a5a5Schristos urtw_led_mode0(struct urtw_softc *sc, int mode)
1876ac24a5a5Schristos {
1877ac24a5a5Schristos 	switch (mode) {
1878ac24a5a5Schristos 	case URTW_LED_CTL_POWER_ON:
1879ac24a5a5Schristos 		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
1880ac24a5a5Schristos 		break;
1881ac24a5a5Schristos 	case URTW_LED_CTL_TX:
1882ac24a5a5Schristos 		if (sc->sc_gpio_ledinprogress == 1)
18834e8e6643Sskrll 			return 0;
1884ac24a5a5Schristos 
1885ac24a5a5Schristos 		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
1886ac24a5a5Schristos 		sc->sc_gpio_blinktime = 2;
1887ac24a5a5Schristos 		break;
1888ac24a5a5Schristos 	case URTW_LED_CTL_LINK:
1889ac24a5a5Schristos 		sc->sc_gpio_ledstate = URTW_LED_ON;
1890ac24a5a5Schristos 		break;
1891ac24a5a5Schristos 	default:
1892d3dde16cSchristos 		panic("unsupported LED mode %#x", mode);
1893ac24a5a5Schristos 		/* NOTREACHED */
1894ac24a5a5Schristos 	}
1895ac24a5a5Schristos 
1896ac24a5a5Schristos 	switch (sc->sc_gpio_ledstate) {
1897ac24a5a5Schristos 	case URTW_LED_ON:
1898ac24a5a5Schristos 		if (sc->sc_gpio_ledinprogress != 0)
1899ac24a5a5Schristos 			break;
1900ac24a5a5Schristos 		urtw_led_on(sc, URTW_LED_GPIO);
1901ac24a5a5Schristos 		break;
1902ac24a5a5Schristos 	case URTW_LED_BLINK_NORMAL:
1903ac24a5a5Schristos 		if (sc->sc_gpio_ledinprogress != 0)
1904ac24a5a5Schristos 			break;
1905ac24a5a5Schristos 		sc->sc_gpio_ledinprogress = 1;
1906ac24a5a5Schristos 		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
1907ac24a5a5Schristos 			URTW_LED_OFF : URTW_LED_ON;
1908ac24a5a5Schristos 		if (!sc->sc_dying)
1909ac24a5a5Schristos 			callout_schedule(&sc->sc_led_ch, mstohz(100));
1910ac24a5a5Schristos 		break;
1911ac24a5a5Schristos 	case URTW_LED_POWER_ON_BLINK:
1912ac24a5a5Schristos 		urtw_led_on(sc, URTW_LED_GPIO);
1913ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 100);
1914ac24a5a5Schristos 		urtw_led_off(sc, URTW_LED_GPIO);
1915ac24a5a5Schristos 		break;
1916ac24a5a5Schristos 	default:
1917d3dde16cSchristos 		panic("unknown LED status %#x", sc->sc_gpio_ledstate);
1918ac24a5a5Schristos 		/* NOTREACHED */
1919ac24a5a5Schristos 	}
19204e8e6643Sskrll 	return 0;
1921ac24a5a5Schristos }
1922ac24a5a5Schristos 
192328885f8eSmaxv static usbd_status
urtw_led_mode1(struct urtw_softc * sc,int mode)1924ac24a5a5Schristos urtw_led_mode1(struct urtw_softc *sc, int mode)
1925ac24a5a5Schristos {
19264e8e6643Sskrll 	return USBD_INVAL;
1927ac24a5a5Schristos }
1928ac24a5a5Schristos 
192928885f8eSmaxv static usbd_status
urtw_led_mode2(struct urtw_softc * sc,int mode)1930ac24a5a5Schristos urtw_led_mode2(struct urtw_softc *sc, int mode)
1931ac24a5a5Schristos {
19324e8e6643Sskrll 	return USBD_INVAL;
1933ac24a5a5Schristos }
1934ac24a5a5Schristos 
193528885f8eSmaxv static usbd_status
urtw_led_mode3(struct urtw_softc * sc,int mode)1936ac24a5a5Schristos urtw_led_mode3(struct urtw_softc *sc, int mode)
1937ac24a5a5Schristos {
19384e8e6643Sskrll 	return USBD_INVAL;
1939ac24a5a5Schristos }
1940ac24a5a5Schristos 
194128885f8eSmaxv static void
urtw_ledusbtask(void * arg)1942ac24a5a5Schristos urtw_ledusbtask(void *arg)
1943ac24a5a5Schristos {
1944ac24a5a5Schristos 	struct urtw_softc *sc = arg;
1945ac24a5a5Schristos 
1946ac24a5a5Schristos 	if (sc->sc_strategy != URTW_SW_LED_MODE0)
1947d3dde16cSchristos 		panic("could not process a LED strategy %#x", sc->sc_strategy);
1948ac24a5a5Schristos 
1949ac24a5a5Schristos 	urtw_led_blink(sc);
1950ac24a5a5Schristos }
1951ac24a5a5Schristos 
195228885f8eSmaxv static void
urtw_ledtask(void * arg)1953ac24a5a5Schristos urtw_ledtask(void *arg)
1954ac24a5a5Schristos {
1955ac24a5a5Schristos 	struct urtw_softc *sc = arg;
1956ac24a5a5Schristos 
1957ac24a5a5Schristos 	/*
1958ac24a5a5Schristos 	 * NB: to change a status of the led we need at least a sleep so we
1959ac24a5a5Schristos 	 * can't do it here
1960ac24a5a5Schristos 	 */
1961ac24a5a5Schristos 	usb_add_task(sc->sc_udev, &sc->sc_ledtask, USB_TASKQ_DRIVER);
1962ac24a5a5Schristos }
1963ac24a5a5Schristos 
196428885f8eSmaxv static usbd_status
urtw_led_ctl(struct urtw_softc * sc,int mode)1965ac24a5a5Schristos urtw_led_ctl(struct urtw_softc *sc, int mode)
1966ac24a5a5Schristos {
1967ac24a5a5Schristos 	usbd_status error = 0;
1968ac24a5a5Schristos 
1969ac24a5a5Schristos 	switch (sc->sc_strategy) {
1970ac24a5a5Schristos 	case URTW_SW_LED_MODE0:
1971ac24a5a5Schristos 		error = urtw_led_mode0(sc, mode);
1972ac24a5a5Schristos 		break;
1973ac24a5a5Schristos 	case URTW_SW_LED_MODE1:
1974ac24a5a5Schristos 		error = urtw_led_mode1(sc, mode);
1975ac24a5a5Schristos 		break;
1976ac24a5a5Schristos 	case URTW_SW_LED_MODE2:
1977ac24a5a5Schristos 		error = urtw_led_mode2(sc, mode);
1978ac24a5a5Schristos 		break;
1979ac24a5a5Schristos 	case URTW_SW_LED_MODE3:
1980ac24a5a5Schristos 		error = urtw_led_mode3(sc, mode);
1981ac24a5a5Schristos 		break;
1982ac24a5a5Schristos 	default:
1983ac24a5a5Schristos 		panic("unsupported LED mode %d", sc->sc_strategy);
1984ac24a5a5Schristos 		/* NOTREACHED */
1985ac24a5a5Schristos 	}
1986ac24a5a5Schristos 
19874e8e6643Sskrll 	return error;
1988ac24a5a5Schristos }
1989ac24a5a5Schristos 
199028885f8eSmaxv static usbd_status
urtw_led_blink(struct urtw_softc * sc)1991ac24a5a5Schristos urtw_led_blink(struct urtw_softc *sc)
1992ac24a5a5Schristos {
1993ac24a5a5Schristos 	uint8_t ing = 0;
1994ac24a5a5Schristos 
1995ac24a5a5Schristos 	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
19966c759efcSchristos 		(void)urtw_led_on(sc, URTW_LED_GPIO);
1997ac24a5a5Schristos 	else
19986c759efcSchristos 		(void)urtw_led_off(sc, URTW_LED_GPIO);
1999ac24a5a5Schristos 	sc->sc_gpio_blinktime--;
2000ac24a5a5Schristos 	if (sc->sc_gpio_blinktime == 0)
2001ac24a5a5Schristos 		ing = 1;
2002ac24a5a5Schristos 	else {
2003ac24a5a5Schristos 		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
2004ac24a5a5Schristos 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
2005ac24a5a5Schristos 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
2006ac24a5a5Schristos 			ing = 1;
2007ac24a5a5Schristos 	}
2008ac24a5a5Schristos 	if (ing == 1) {
2009ac24a5a5Schristos 		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
2010ac24a5a5Schristos 		    sc->sc_gpio_ledon == 0)
20116c759efcSchristos 			(void)urtw_led_on(sc, URTW_LED_GPIO);
2012ac24a5a5Schristos 		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
2013ac24a5a5Schristos 		    sc->sc_gpio_ledon == 1)
20146c759efcSchristos 			(void)urtw_led_off(sc, URTW_LED_GPIO);
2015ac24a5a5Schristos 
2016ac24a5a5Schristos 		sc->sc_gpio_blinktime = 0;
2017ac24a5a5Schristos 		sc->sc_gpio_ledinprogress = 0;
20184e8e6643Sskrll 		return 0;
2019ac24a5a5Schristos 	}
2020ac24a5a5Schristos 
2021ac24a5a5Schristos 	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
2022ac24a5a5Schristos 	    URTW_LED_ON : URTW_LED_OFF;
2023ac24a5a5Schristos 
2024ac24a5a5Schristos 	switch (sc->sc_gpio_ledstate) {
2025ac24a5a5Schristos 	case URTW_LED_BLINK_NORMAL:
2026ac24a5a5Schristos 		if (!sc->sc_dying)
2027ac24a5a5Schristos 			callout_schedule(&sc->sc_led_ch, mstohz(100));
2028ac24a5a5Schristos 		break;
2029ac24a5a5Schristos 	default:
2030d3dde16cSchristos 		panic("unknown LED status %#x", sc->sc_gpio_ledstate);
2031ac24a5a5Schristos 		/* NOTREACHED */
2032ac24a5a5Schristos 	}
20334e8e6643Sskrll 	return 0;
2034ac24a5a5Schristos }
2035ac24a5a5Schristos 
203628885f8eSmaxv static usbd_status
urtw_update_msr(struct urtw_softc * sc)2037ac24a5a5Schristos urtw_update_msr(struct urtw_softc *sc)
2038ac24a5a5Schristos {
2039ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2040ac24a5a5Schristos 	uint8_t data;
2041ac24a5a5Schristos 	usbd_status error;
2042ac24a5a5Schristos 
2043ac24a5a5Schristos 	urtw_read8_m(sc, URTW_MSR, &data);
2044ac24a5a5Schristos 	data &= ~URTW_MSR_LINK_MASK;
2045ac24a5a5Schristos 
2046ac24a5a5Schristos 	/* Should always be set. */
2047ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187B)
2048ac24a5a5Schristos 		data |= URTW_MSR_LINK_ENEDCA;
2049ac24a5a5Schristos 
2050ac24a5a5Schristos 	if (sc->sc_state == IEEE80211_S_RUN) {
2051ac24a5a5Schristos 		switch (ic->ic_opmode) {
2052ac24a5a5Schristos 		case IEEE80211_M_STA:
2053ac24a5a5Schristos 		case IEEE80211_M_MONITOR:
2054ac24a5a5Schristos 			data |= URTW_MSR_LINK_STA;
2055ac24a5a5Schristos 			break;
2056ac24a5a5Schristos 		default:
2057d3dde16cSchristos 			panic("unsupported operation mode %#x",
2058ac24a5a5Schristos 			    ic->ic_opmode);
2059ac24a5a5Schristos 			/* NOTREACHED */
2060ac24a5a5Schristos 		}
2061ac24a5a5Schristos 	} else
2062ac24a5a5Schristos 		data |= URTW_MSR_LINK_NONE;
2063ac24a5a5Schristos 
2064ac24a5a5Schristos 	urtw_write8_m(sc, URTW_MSR, data);
2065ac24a5a5Schristos fail:
20664e8e6643Sskrll 	return error;
2067ac24a5a5Schristos }
2068ac24a5a5Schristos 
206928885f8eSmaxv static uint16_t
urtw_rate2rtl(int rate)2070ac24a5a5Schristos urtw_rate2rtl(int rate)
2071ac24a5a5Schristos {
2072ac24a5a5Schristos 	unsigned int i;
2073ac24a5a5Schristos 
2074ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_ratetable); i++) {
2075ac24a5a5Schristos 		if (rate == urtw_ratetable[i].reg)
20764e8e6643Sskrll 			return urtw_ratetable[i].val;
2077ac24a5a5Schristos 	}
2078ac24a5a5Schristos 
20794e8e6643Sskrll 	return 3;
2080ac24a5a5Schristos }
2081ac24a5a5Schristos 
208228885f8eSmaxv static uint16_t
urtw_rtl2rate(int rate)2083ac24a5a5Schristos urtw_rtl2rate(int rate)
2084ac24a5a5Schristos {
2085ac24a5a5Schristos 	unsigned int i;
2086ac24a5a5Schristos 
2087ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_ratetable); i++) {
2088ac24a5a5Schristos 		if (rate == urtw_ratetable[i].val)
20894e8e6643Sskrll 			return urtw_ratetable[i].reg;
2090ac24a5a5Schristos 	}
2091ac24a5a5Schristos 
20924e8e6643Sskrll 	return 0;
2093ac24a5a5Schristos }
2094ac24a5a5Schristos 
209528885f8eSmaxv static usbd_status
urtw_set_rate(struct urtw_softc * sc)2096ac24a5a5Schristos urtw_set_rate(struct urtw_softc *sc)
2097ac24a5a5Schristos {
2098ac24a5a5Schristos 	int i, basic_rate, min_rr_rate, max_rr_rate;
2099ac24a5a5Schristos 	uint16_t data;
2100ac24a5a5Schristos 	usbd_status error;
2101ac24a5a5Schristos 
2102ac24a5a5Schristos 	basic_rate = urtw_rate2rtl(48);
2103ac24a5a5Schristos 	min_rr_rate = urtw_rate2rtl(12);
2104ac24a5a5Schristos 	max_rr_rate = urtw_rate2rtl(48);
2105ac24a5a5Schristos 
2106ac24a5a5Schristos 	urtw_write8_m(sc, URTW_RESP_RATE,
2107ac24a5a5Schristos 	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
2108ac24a5a5Schristos 	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT);
2109ac24a5a5Schristos 
2110ac24a5a5Schristos 	urtw_read16_m(sc, URTW_8187_BRSR, &data);
2111ac24a5a5Schristos 	data &= ~URTW_BRSR_MBR_8185;
2112ac24a5a5Schristos 
2113ac24a5a5Schristos 	for (i = 0; i <= basic_rate; i++)
2114ac24a5a5Schristos 		data |= (1 << i);
2115ac24a5a5Schristos 
2116ac24a5a5Schristos 	urtw_write16_m(sc, URTW_8187_BRSR, data);
2117ac24a5a5Schristos fail:
21184e8e6643Sskrll 	return error;
2119ac24a5a5Schristos }
2120ac24a5a5Schristos 
212128885f8eSmaxv static usbd_status
urtw_intr_enable(struct urtw_softc * sc)2122ac24a5a5Schristos urtw_intr_enable(struct urtw_softc *sc)
2123ac24a5a5Schristos {
2124ac24a5a5Schristos 	usbd_status error;
2125ac24a5a5Schristos 
2126ac24a5a5Schristos 	urtw_write16_m(sc, URTW_INTR_MASK, 0xffff);
2127ac24a5a5Schristos fail:
21284e8e6643Sskrll 	return error;
2129ac24a5a5Schristos }
2130ac24a5a5Schristos 
213128885f8eSmaxv static usbd_status
urtw_rx_setconf(struct urtw_softc * sc)2132ac24a5a5Schristos urtw_rx_setconf(struct urtw_softc *sc)
2133ac24a5a5Schristos {
2134ac24a5a5Schristos 	struct ifnet *ifp = sc->sc_ic.ic_ifp;
2135ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2136ac24a5a5Schristos 	uint32_t data;
2137ac24a5a5Schristos 	usbd_status error;
2138ac24a5a5Schristos 
2139ac24a5a5Schristos 	urtw_read32_m(sc, URTW_RX, &data);
2140ac24a5a5Schristos 	data = data &~ URTW_RX_FILTER_MASK;
2141ac24a5a5Schristos #if 0
2142ac24a5a5Schristos 	data = data | URTW_RX_FILTER_CTL;
2143ac24a5a5Schristos #endif
2144ac24a5a5Schristos 	data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
2145ac24a5a5Schristos 	data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
2146ac24a5a5Schristos 
2147ac24a5a5Schristos 	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
2148ac24a5a5Schristos 		data = data | URTW_RX_FILTER_ICVERR;
2149ac24a5a5Schristos 		data = data | URTW_RX_FILTER_PWR;
2150ac24a5a5Schristos 	}
2151ac24a5a5Schristos 	if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
2152ac24a5a5Schristos 		data = data | URTW_RX_FILTER_CRCERR;
2153ac24a5a5Schristos 
2154ac24a5a5Schristos 	if (ic->ic_opmode == IEEE80211_M_MONITOR ||
2155ac24a5a5Schristos 	    (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) {
2156ac24a5a5Schristos 		data = data | URTW_RX_FILTER_ALLMAC;
2157ac24a5a5Schristos 	} else {
2158ac24a5a5Schristos 		data = data | URTW_RX_FILTER_NICMAC;
2159ac24a5a5Schristos 		data = data | URTW_RX_CHECK_BSSID;
2160ac24a5a5Schristos 	}
2161ac24a5a5Schristos 
2162ac24a5a5Schristos 	data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
2163ac24a5a5Schristos 	data = data | URTW_RX_FIFO_THRESHOLD_NONE | URTW_RX_AUTORESETPHY;
2164ac24a5a5Schristos 	data = data &~ URTW_MAX_RX_DMA_MASK;
2165ac24a5a5Schristos 	data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT;
2166ac24a5a5Schristos 
2167ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RX, data);
2168ac24a5a5Schristos fail:
21694e8e6643Sskrll 	return error;
2170ac24a5a5Schristos }
2171ac24a5a5Schristos 
217228885f8eSmaxv static usbd_status
urtw_rx_enable(struct urtw_softc * sc)2173ac24a5a5Schristos urtw_rx_enable(struct urtw_softc *sc)
2174ac24a5a5Schristos {
2175ac24a5a5Schristos 	int i;
2176ac24a5a5Schristos 	struct urtw_rx_data *rx_data;
2177ac24a5a5Schristos 	uint8_t data;
2178ac24a5a5Schristos 	usbd_status error;
2179ac24a5a5Schristos 
2180ac24a5a5Schristos 	/*
2181ac24a5a5Schristos 	 * Start up the receive pipe.
2182ac24a5a5Schristos 	 */
2183ac24a5a5Schristos 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
2184ac24a5a5Schristos 		rx_data = &sc->sc_rx_data[i];
2185ac24a5a5Schristos 
21864e8e6643Sskrll 		usbd_setup_xfer(rx_data->xfer, rx_data, rx_data->buf, MCLBYTES,
21874e8e6643Sskrll 		    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, urtw_rxeof);
2188ac24a5a5Schristos 		error = usbd_transfer(rx_data->xfer);
2189ac24a5a5Schristos 		if (error != USBD_IN_PROGRESS && error != 0) {
2190ac24a5a5Schristos 			printf("%s: could not queue Rx transfer\n",
2191ac24a5a5Schristos 			    device_xname(sc->sc_dev));
2192ac24a5a5Schristos 			goto fail;
2193ac24a5a5Schristos 		}
2194ac24a5a5Schristos 	}
2195ac24a5a5Schristos 
2196ac24a5a5Schristos 	error = urtw_rx_setconf(sc);
2197ac24a5a5Schristos 	if (error != 0)
2198ac24a5a5Schristos 		goto fail;
2199ac24a5a5Schristos 
2200ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
2201ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE);
2202ac24a5a5Schristos fail:
22034e8e6643Sskrll 	return error;
2204ac24a5a5Schristos }
2205ac24a5a5Schristos 
220628885f8eSmaxv static usbd_status
urtw_tx_enable(struct urtw_softc * sc)2207ac24a5a5Schristos urtw_tx_enable(struct urtw_softc *sc)
2208ac24a5a5Schristos {
2209ac24a5a5Schristos 	uint8_t data8;
2210ac24a5a5Schristos 	uint32_t data;
2211ac24a5a5Schristos 	usbd_status error;
2212ac24a5a5Schristos 
2213ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
2214ac24a5a5Schristos 		urtw_read8_m(sc, URTW_CW_CONF, &data8);
2215ac24a5a5Schristos 		data8 &= ~(URTW_CW_CONF_PERPACKET_CW |
2216ac24a5a5Schristos 		    URTW_CW_CONF_PERPACKET_RETRY);
2217ac24a5a5Schristos 		urtw_write8_m(sc, URTW_CW_CONF, data8);
2218ac24a5a5Schristos 
2219ac24a5a5Schristos 		urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
2220ac24a5a5Schristos 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
2221ac24a5a5Schristos 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
2222ac24a5a5Schristos 		data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
2223ac24a5a5Schristos 		urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
2224ac24a5a5Schristos 
2225ac24a5a5Schristos 		urtw_read32_m(sc, URTW_TX_CONF, &data);
2226ac24a5a5Schristos 		data &= ~URTW_TX_LOOPBACK_MASK;
2227ac24a5a5Schristos 		data |= URTW_TX_LOOPBACK_NONE;
2228ac24a5a5Schristos 		data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
2229ac24a5a5Schristos 		data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
2230ac24a5a5Schristos 		data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
2231ac24a5a5Schristos 		data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
2232ac24a5a5Schristos 		data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
2233ac24a5a5Schristos 		data &= ~URTW_TX_SWPLCPLEN;
2234ac24a5a5Schristos 		data |= URTW_TX_NOICV;
2235ac24a5a5Schristos 		urtw_write32_m(sc, URTW_TX_CONF, data);
2236ac24a5a5Schristos 	} else {
2237ac24a5a5Schristos 		data = URTW_TX_DURPROCMODE | URTW_TX_DISREQQSIZE |
2238ac24a5a5Schristos 		    URTW_TX_MXDMA_2048 | URTW_TX_SHORTRETRY |
2239ac24a5a5Schristos 		    URTW_TX_LONGRETRY;
2240ac24a5a5Schristos 		urtw_write32_m(sc, URTW_TX_CONF, data);
2241ac24a5a5Schristos 	}
2242ac24a5a5Schristos 
2243ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data8);
2244ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
2245ac24a5a5Schristos fail:
22464e8e6643Sskrll 	return error;
2247ac24a5a5Schristos }
2248ac24a5a5Schristos 
224928885f8eSmaxv static int
urtw_init(struct ifnet * ifp)2250ac24a5a5Schristos urtw_init(struct ifnet *ifp)
2251ac24a5a5Schristos {
2252ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
2253ac24a5a5Schristos 	struct urtw_rf *rf = &sc->sc_rf;
2254ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2255ac24a5a5Schristos 	usbd_status error;
2256ac24a5a5Schristos 
2257ac24a5a5Schristos 	urtw_stop(ifp, 0);
2258ac24a5a5Schristos 
2259ac24a5a5Schristos 	error = urtw_reset(sc);
2260ac24a5a5Schristos 	if (error)
2261ac24a5a5Schristos 		goto fail;
2262ac24a5a5Schristos 
2263ac24a5a5Schristos 	urtw_write8_m(sc, 0x85, 0);
2264ac24a5a5Schristos 	urtw_write8_m(sc, URTW_GPIO, 0);
2265ac24a5a5Schristos 
2266ac24a5a5Schristos 	/* for led */
2267ac24a5a5Schristos 	urtw_write8_m(sc, 0x85, 4);
2268ac24a5a5Schristos 	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
2269ac24a5a5Schristos 	if (error != 0)
2270ac24a5a5Schristos 		goto fail;
2271ac24a5a5Schristos 
2272ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2273ac24a5a5Schristos 	if (error)
2274ac24a5a5Schristos 		goto fail;
2275ac24a5a5Schristos 
2276ac24a5a5Schristos 	/* applying MAC address again. */
2277ac24a5a5Schristos 	IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
2278ac24a5a5Schristos 	error = urtw_set_macaddr(sc, ic->ic_myaddr);
2279ac24a5a5Schristos 	if (error)
2280ac24a5a5Schristos 		goto fail;
2281ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2282ac24a5a5Schristos 	if (error)
2283ac24a5a5Schristos 		goto fail;
2284ac24a5a5Schristos 
2285ac24a5a5Schristos 	error = urtw_update_msr(sc);
2286ac24a5a5Schristos 	if (error)
2287ac24a5a5Schristos 		goto fail;
2288ac24a5a5Schristos 
2289ac24a5a5Schristos 	urtw_write32_m(sc, URTW_INT_TIMEOUT, 0);
2290ac24a5a5Schristos 	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
2291ac24a5a5Schristos 	urtw_write8_m(sc, URTW_RATE_FALLBACK, 0x81);
2292ac24a5a5Schristos 	error = urtw_set_rate(sc);
2293ac24a5a5Schristos 	if (error != 0)
2294ac24a5a5Schristos 		goto fail;
2295ac24a5a5Schristos 
2296ac24a5a5Schristos 	error = rf->init(rf);
2297ac24a5a5Schristos 	if (error != 0)
2298ac24a5a5Schristos 		goto fail;
2299ac24a5a5Schristos 	if (rf->set_sens != NULL)
2300ac24a5a5Schristos 		rf->set_sens(rf);
2301ac24a5a5Schristos 
2302ac24a5a5Schristos 	urtw_write16_m(sc, 0x5e, 1);
2303ac24a5a5Schristos 	urtw_write16_m(sc, 0xfe, 0x10);
2304ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TALLY_SEL, 0x80);
2305ac24a5a5Schristos 	urtw_write8_m(sc, 0xff, 0x60);
2306ac24a5a5Schristos 	urtw_write16_m(sc, 0x5e, 0);
2307ac24a5a5Schristos 	urtw_write8_m(sc, 0x85, 4);
2308ac24a5a5Schristos 
2309ac24a5a5Schristos 	error = urtw_intr_enable(sc);
2310ac24a5a5Schristos 	if (error != 0)
2311ac24a5a5Schristos 		goto fail;
2312ac24a5a5Schristos 
2313ac24a5a5Schristos 	/* reset softc variables */
23144e8e6643Sskrll 	for (size_t j = 0; j < URTW_PRIORITY_MAX; j++) {
23154e8e6643Sskrll 		sc->sc_txidx[j] = sc->sc_tx_queued[j] = 0;
23164e8e6643Sskrll 	}
2317ac24a5a5Schristos 	sc->sc_txtimer = 0;
2318ac24a5a5Schristos 
2319ac24a5a5Schristos 	if (!(sc->sc_flags & URTW_INIT_ONCE)) {
2320ac24a5a5Schristos 		error = usbd_set_config_no(sc->sc_udev, URTW_CONFIG_NO, 0);
2321ac24a5a5Schristos 		if (error != 0) {
2322897388eaSskrll 			aprint_error_dev(sc->sc_dev, "failed to set configuration"
2323897388eaSskrll 			    ", err=%s\n", usbd_errstr(error));
2324ac24a5a5Schristos 			goto fail;
2325ac24a5a5Schristos 		}
2326ac24a5a5Schristos 		/* get the first interface handle */
2327ac24a5a5Schristos 		error = usbd_device2interface_handle(sc->sc_udev,
2328ac24a5a5Schristos 		    URTW_IFACE_INDEX, &sc->sc_iface);
2329ac24a5a5Schristos 		if (error != 0) {
2330ac24a5a5Schristos 			printf("%s: could not get interface handle\n",
2331ac24a5a5Schristos 			    device_xname(sc->sc_dev));
2332ac24a5a5Schristos 			goto fail;
2333ac24a5a5Schristos 		}
2334ac24a5a5Schristos 		error = urtw_open_pipes(sc);
2335ac24a5a5Schristos 		if (error != 0)
2336ac24a5a5Schristos 			goto fail;
23376c759efcSchristos 		error = urtw_alloc_rx_data_list(sc);
2338ac24a5a5Schristos 		if (error != 0)
2339ac24a5a5Schristos 			goto fail;
23406c759efcSchristos 		error = urtw_alloc_tx_data_list(sc);
2341ac24a5a5Schristos 		if (error != 0)
2342ac24a5a5Schristos 			goto fail;
2343ac24a5a5Schristos 		sc->sc_flags |= URTW_INIT_ONCE;
2344ac24a5a5Schristos 	}
2345ac24a5a5Schristos 
2346ac24a5a5Schristos 	error = urtw_rx_enable(sc);
2347ac24a5a5Schristos 	if (error != 0)
2348ac24a5a5Schristos 		goto fail;
2349ac24a5a5Schristos 	error = urtw_tx_enable(sc);
2350ac24a5a5Schristos 	if (error != 0)
2351ac24a5a5Schristos 		goto fail;
2352ac24a5a5Schristos 
2353ac24a5a5Schristos 	ifp->if_flags &= ~IFF_OACTIVE;
2354ac24a5a5Schristos 	ifp->if_flags |= IFF_RUNNING;
2355ac24a5a5Schristos 
2356ac24a5a5Schristos 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
2357ac24a5a5Schristos 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2358ac24a5a5Schristos 	else
2359ac24a5a5Schristos 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2360ac24a5a5Schristos 
23614e8e6643Sskrll 	return 0;
2362ac24a5a5Schristos fail:
23634e8e6643Sskrll 	return error;
2364ac24a5a5Schristos }
2365ac24a5a5Schristos 
236628885f8eSmaxv static int
urtw_ioctl(struct ifnet * ifp,u_long cmd,void * data)2367ac24a5a5Schristos urtw_ioctl(struct ifnet *ifp, u_long cmd, void *data)
2368ac24a5a5Schristos {
2369ac24a5a5Schristos #define IS_RUNNING(ifp) \
2370ac24a5a5Schristos 	(((ifp)->if_flags & IFF_UP) && ((ifp)->if_flags & IFF_RUNNING))
2371ac24a5a5Schristos 
2372ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
2373ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2374ac24a5a5Schristos 	int s, error = 0;
2375ac24a5a5Schristos 
2376ac24a5a5Schristos 	if (sc->sc_dying)
23774e8e6643Sskrll 		return ENXIO;
2378ac24a5a5Schristos 
2379ac24a5a5Schristos 	s = splnet();
2380ac24a5a5Schristos 
2381ac24a5a5Schristos 	switch (cmd) {
2382ac24a5a5Schristos 	case SIOCSIFFLAGS:
2383ac24a5a5Schristos 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
2384ac24a5a5Schristos 			break;
2385ac24a5a5Schristos 		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
2386ac24a5a5Schristos 		case IFF_UP|IFF_RUNNING:
2387ac24a5a5Schristos 			break;
2388ac24a5a5Schristos 		case IFF_UP:
2389b4d088cbSriastradh 			if_init(ifp);
2390ac24a5a5Schristos 			break;
2391ac24a5a5Schristos 		case IFF_RUNNING:
2392ac24a5a5Schristos 			urtw_stop(ifp, 1);
2393ac24a5a5Schristos 			break;
2394ac24a5a5Schristos 		case 0:
2395ac24a5a5Schristos 			break;
2396ac24a5a5Schristos 		}
2397ac24a5a5Schristos 		break;
2398ac24a5a5Schristos 
2399ac24a5a5Schristos 	case SIOCADDMULTI:
2400ac24a5a5Schristos 	case SIOCDELMULTI:
2401ac24a5a5Schristos 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET)
2402ac24a5a5Schristos 			error = 0;
2403ac24a5a5Schristos 		break;
2404ac24a5a5Schristos 
2405ac24a5a5Schristos 	default:
2406ac24a5a5Schristos 		error = ieee80211_ioctl(ic, cmd, data);
2407ac24a5a5Schristos 		break;
2408ac24a5a5Schristos 	}
2409ac24a5a5Schristos 
2410ac24a5a5Schristos 	if (error == ENETRESET) {
2411ac24a5a5Schristos 		if (IS_RUNNING(ifp) &&
2412ac24a5a5Schristos 		    (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
2413b4d088cbSriastradh 			if_init(ifp);
2414ac24a5a5Schristos 		error = 0;
2415ac24a5a5Schristos 	}
2416ac24a5a5Schristos 
2417ac24a5a5Schristos 	splx(s);
2418ac24a5a5Schristos 
24194e8e6643Sskrll 	return error;
2420ac24a5a5Schristos #undef IS_RUNNING
2421ac24a5a5Schristos }
2422ac24a5a5Schristos 
242328885f8eSmaxv static void
urtw_start(struct ifnet * ifp)2424ac24a5a5Schristos urtw_start(struct ifnet *ifp)
2425ac24a5a5Schristos {
2426ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
2427ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2428ac24a5a5Schristos 	struct ieee80211_node *ni;
2429ac24a5a5Schristos 	struct ether_header *eh;
2430ac24a5a5Schristos 	struct mbuf *m0;
2431ac24a5a5Schristos 
2432ac24a5a5Schristos 	/*
2433ac24a5a5Schristos 	 * net80211 may still try to send management frames even if the
2434ac24a5a5Schristos 	 * IFF_RUNNING flag is not set...
2435ac24a5a5Schristos 	 */
2436ac24a5a5Schristos 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
2437ac24a5a5Schristos 		return;
2438ac24a5a5Schristos 
2439ac24a5a5Schristos 	for (;;) {
2440ac24a5a5Schristos 		IF_POLL(&ic->ic_mgtq, m0);
2441ac24a5a5Schristos 		if (m0 != NULL) {
24424e8e6643Sskrll 
24434e8e6643Sskrll 			if (sc->sc_tx_queued[URTW_PRIORITY_NORMAL] >=
2444ac24a5a5Schristos 			    URTW_TX_DATA_LIST_COUNT) {
2445ac24a5a5Schristos 				ifp->if_flags |= IFF_OACTIVE;
2446ac24a5a5Schristos 				break;
2447ac24a5a5Schristos 			}
2448ac24a5a5Schristos 			IF_DEQUEUE(&ic->ic_mgtq, m0);
2449ea0349e7Sozaki-r 			ni = M_GETCTX(m0, struct ieee80211_node *);
24506bbd2477Sozaki-r 			M_CLEARCTX(m0);
24513cd62456Smsaitoh 			bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT);
2452ac24a5a5Schristos 			if (urtw_tx_start(sc, ni, m0, URTW_PRIORITY_NORMAL)
2453ac24a5a5Schristos 			    != 0)
2454ac24a5a5Schristos 				break;
2455ac24a5a5Schristos 		} else {
2456ac24a5a5Schristos 			if (ic->ic_state != IEEE80211_S_RUN)
2457ac24a5a5Schristos 				break;
2458ac24a5a5Schristos 			IFQ_POLL(&ifp->if_snd, m0);
2459ac24a5a5Schristos 			if (m0 == NULL)
2460ac24a5a5Schristos 				break;
24614e8e6643Sskrll 			if (sc->sc_tx_queued[URTW_PRIORITY_NORMAL] >=
2462ac24a5a5Schristos 			    URTW_TX_DATA_LIST_COUNT) {
2463ac24a5a5Schristos 				ifp->if_flags |= IFF_OACTIVE;
2464ac24a5a5Schristos 				break;
2465ac24a5a5Schristos 			}
2466ac24a5a5Schristos 			IFQ_DEQUEUE(&ifp->if_snd, m0);
2467ac24a5a5Schristos 			if (m0->m_len < sizeof(struct ether_header) &&
2468ac24a5a5Schristos 			    !(m0 = m_pullup(m0, sizeof(struct ether_header))))
2469ac24a5a5Schristos 				continue;
2470ac24a5a5Schristos 
2471ac24a5a5Schristos 			eh = mtod(m0, struct ether_header *);
2472ac24a5a5Schristos 			ni = ieee80211_find_txnode(ic, eh->ether_dhost);
2473ac24a5a5Schristos 			if (ni == NULL) {
2474ac24a5a5Schristos 				m_freem(m0);
2475ac24a5a5Schristos 				continue;
2476ac24a5a5Schristos 			}
24773cd62456Smsaitoh 			bpf_mtap(ifp, m0, BPF_D_OUT);
2478ac24a5a5Schristos 			m0 = ieee80211_encap(ic, m0, ni);
2479ac24a5a5Schristos 			if (m0 == NULL) {
2480ac24a5a5Schristos 				ieee80211_free_node(ni);
2481ac24a5a5Schristos 				continue;
2482ac24a5a5Schristos 			}
24833cd62456Smsaitoh 			bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT);
2484ac24a5a5Schristos 			if (urtw_tx_start(sc, ni, m0, URTW_PRIORITY_NORMAL)
2485ac24a5a5Schristos 			    != 0) {
2486ac24a5a5Schristos 				ieee80211_free_node(ni);
2487cdaa0e91Sthorpej 				if_statinc(ifp, if_oerrors);
2488ac24a5a5Schristos 				break;
2489ac24a5a5Schristos 			}
2490ac24a5a5Schristos 		}
2491ac24a5a5Schristos 		sc->sc_txtimer = 5;
2492ac24a5a5Schristos 		ifp->if_timer = 1;
2493ac24a5a5Schristos 	}
2494ac24a5a5Schristos }
2495ac24a5a5Schristos 
249628885f8eSmaxv static void
urtw_watchdog(struct ifnet * ifp)2497ac24a5a5Schristos urtw_watchdog(struct ifnet *ifp)
2498ac24a5a5Schristos {
2499ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
2500ac24a5a5Schristos 
2501ac24a5a5Schristos 	ifp->if_timer = 0;
2502ac24a5a5Schristos 
2503ac24a5a5Schristos 	if (sc->sc_txtimer > 0) {
2504ac24a5a5Schristos 		if (--sc->sc_txtimer == 0) {
2505ac24a5a5Schristos 			printf("%s: device timeout\n", device_xname(sc->sc_dev));
2506cdaa0e91Sthorpej 			if_statinc(ifp, if_oerrors);
2507ac24a5a5Schristos 			return;
2508ac24a5a5Schristos 		}
2509ac24a5a5Schristos 		ifp->if_timer = 1;
2510ac24a5a5Schristos 	}
2511ac24a5a5Schristos 
2512ac24a5a5Schristos 	ieee80211_watchdog(&sc->sc_ic);
2513ac24a5a5Schristos }
2514ac24a5a5Schristos 
251528885f8eSmaxv static void
urtw_txeof_low(struct usbd_xfer * xfer,void * priv,usbd_status status)25164e8e6643Sskrll urtw_txeof_low(struct usbd_xfer *xfer, void *priv,
2517ac24a5a5Schristos     usbd_status status)
2518ac24a5a5Schristos {
2519ac24a5a5Schristos 	struct urtw_tx_data *data = priv;
2520ac24a5a5Schristos 	struct urtw_softc *sc = data->sc;
2521ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2522ac24a5a5Schristos 	struct ifnet *ifp = ic->ic_ifp;
2523ac24a5a5Schristos 	int s;
2524ac24a5a5Schristos 
2525ac24a5a5Schristos 	if (status != USBD_NORMAL_COMPLETION) {
2526ac24a5a5Schristos 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
2527ac24a5a5Schristos 			return;
2528ac24a5a5Schristos 
2529ac24a5a5Schristos 		printf("%s: could not transmit buffer: %s\n",
2530ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(status));
2531ac24a5a5Schristos 
2532ac24a5a5Schristos 		if (status == USBD_STALLED)
2533ac24a5a5Schristos 			usbd_clear_endpoint_stall_async(sc->sc_txpipe_low);
2534ac24a5a5Schristos 
2535cdaa0e91Sthorpej 		if_statinc(ifp, if_oerrors);
2536ac24a5a5Schristos 		return;
2537ac24a5a5Schristos 	}
2538ac24a5a5Schristos 
2539ac24a5a5Schristos 	s = splnet();
2540ac24a5a5Schristos 
2541ac24a5a5Schristos 	ieee80211_free_node(data->ni);
2542ac24a5a5Schristos 	data->ni = NULL;
2543ac24a5a5Schristos 
2544ac24a5a5Schristos 	sc->sc_txtimer = 0;
2545cdaa0e91Sthorpej 	if_statinc(ifp, if_opackets);
2546ac24a5a5Schristos 
25474e8e6643Sskrll 	sc->sc_tx_queued[URTW_PRIORITY_LOW]--;
2548ac24a5a5Schristos 	ifp->if_flags &= ~IFF_OACTIVE;
2549ac24a5a5Schristos 	urtw_start(ifp);
2550ac24a5a5Schristos 
2551ac24a5a5Schristos 	splx(s);
2552ac24a5a5Schristos }
2553ac24a5a5Schristos 
255428885f8eSmaxv static void
urtw_txeof_normal(struct usbd_xfer * xfer,void * priv,usbd_status status)25554e8e6643Sskrll urtw_txeof_normal(struct usbd_xfer *xfer, void *priv,
2556ac24a5a5Schristos     usbd_status status)
2557ac24a5a5Schristos {
2558ac24a5a5Schristos 	struct urtw_tx_data *data = priv;
2559ac24a5a5Schristos 	struct urtw_softc *sc = data->sc;
2560ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2561ac24a5a5Schristos 	struct ifnet *ifp = ic->ic_ifp;
2562ac24a5a5Schristos 	int s;
2563ac24a5a5Schristos 
2564ac24a5a5Schristos 	if (status != USBD_NORMAL_COMPLETION) {
2565ac24a5a5Schristos 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
2566ac24a5a5Schristos 			return;
2567ac24a5a5Schristos 
2568ac24a5a5Schristos 		printf("%s: could not transmit buffer: %s\n",
2569ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(status));
2570ac24a5a5Schristos 
2571ac24a5a5Schristos 		if (status == USBD_STALLED)
2572ac24a5a5Schristos 			usbd_clear_endpoint_stall_async(sc->sc_txpipe_normal);
2573ac24a5a5Schristos 
2574cdaa0e91Sthorpej 		if_statinc(ifp, if_oerrors);
2575ac24a5a5Schristos 		return;
2576ac24a5a5Schristos 	}
2577ac24a5a5Schristos 
2578ac24a5a5Schristos 	s = splnet();
2579ac24a5a5Schristos 
2580ac24a5a5Schristos 	ieee80211_free_node(data->ni);
2581ac24a5a5Schristos 	data->ni = NULL;
2582ac24a5a5Schristos 
2583ac24a5a5Schristos 	sc->sc_txtimer = 0;
2584cdaa0e91Sthorpej 	if_statinc(ifp, if_opackets);
2585ac24a5a5Schristos 
25864e8e6643Sskrll 	sc->sc_tx_queued[URTW_PRIORITY_NORMAL]--;
2587ac24a5a5Schristos 	ifp->if_flags &= ~IFF_OACTIVE;
2588ac24a5a5Schristos 	urtw_start(ifp);
2589ac24a5a5Schristos 
2590ac24a5a5Schristos 	splx(s);
2591ac24a5a5Schristos }
2592ac24a5a5Schristos 
259328885f8eSmaxv static int
urtw_tx_start(struct urtw_softc * sc,struct ieee80211_node * ni,struct mbuf * m0,int prior)2594ac24a5a5Schristos urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0,
2595ac24a5a5Schristos     int prior)
2596ac24a5a5Schristos {
2597ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2598ac24a5a5Schristos 	struct urtw_tx_data *data;
2599ac24a5a5Schristos 	struct ieee80211_frame *wh;
2600ac24a5a5Schristos 	struct ieee80211_key *k;
2601ac24a5a5Schristos 	usbd_status error;
2602ac24a5a5Schristos 	int xferlen;
2603ac24a5a5Schristos 
2604ac24a5a5Schristos 	wh = mtod(m0, struct ieee80211_frame *);
2605ac24a5a5Schristos 
2606ac24a5a5Schristos 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2607ac24a5a5Schristos 		k = ieee80211_crypto_encap(ic, ni, m0);
2608ac24a5a5Schristos 		if (k == NULL) {
2609ac24a5a5Schristos 			m_freem(m0);
26104e8e6643Sskrll 			return ENOBUFS;
2611ac24a5a5Schristos 		}
2612ac24a5a5Schristos 		/* packet header may have moved, reset our local pointer */
2613ac24a5a5Schristos 		wh = mtod(m0, struct ieee80211_frame *);
2614ac24a5a5Schristos 	}
2615ac24a5a5Schristos 
2616ac24a5a5Schristos 	if (sc->sc_drvbpf != NULL) {
2617ac24a5a5Schristos 		struct urtw_tx_radiotap_header *tap = &sc->sc_txtap;
2618ac24a5a5Schristos 
2619ac24a5a5Schristos 		tap->wt_flags = 0;
2620ac24a5a5Schristos 		tap->wt_rate = 0;
2621ac24a5a5Schristos 		tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
2622ac24a5a5Schristos 		tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
2623ac24a5a5Schristos 
26243cd62456Smsaitoh 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0, BPF_D_OUT);
2625ac24a5a5Schristos 	}
2626ac24a5a5Schristos 
2627ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187)
2628ac24a5a5Schristos 		xferlen = m0->m_pkthdr.len + 4 * 3;
2629ac24a5a5Schristos 	else
2630ac24a5a5Schristos 		xferlen = m0->m_pkthdr.len + 4 * 8;
2631ac24a5a5Schristos 
2632ac24a5a5Schristos 	if ((0 == xferlen % 64) || (0 == xferlen % 512))
2633ac24a5a5Schristos 		xferlen += 1;
2634ac24a5a5Schristos 
26354e8e6643Sskrll 	data = &sc->sc_tx_data[prior][sc->sc_txidx[prior]];
26364e8e6643Sskrll 	sc->sc_txidx[prior] =
26374e8e6643Sskrll 	    (sc->sc_txidx[prior] + 1) % URTW_TX_DATA_LIST_COUNT;
2638ac24a5a5Schristos 
26394e8e6643Sskrll 	memset(data->buf, 0, URTW_TX_MAXSIZE);
2640ac24a5a5Schristos 	data->buf[0] = m0->m_pkthdr.len & 0xff;
2641ac24a5a5Schristos 	data->buf[1] = (m0->m_pkthdr.len & 0x0f00) >> 8;
2642ac24a5a5Schristos 	data->buf[1] |= (1 << 7);
2643ac24a5a5Schristos 
2644ac24a5a5Schristos 	/* XXX sc_preamble_mode is always 2. */
2645ac24a5a5Schristos 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
2646ac24a5a5Schristos 	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) &&
2647ac24a5a5Schristos 	    (sc->sc_preamble_mode == 1) && (sc->sc_currate != 0))
2648ac24a5a5Schristos 		data->buf[2] |= 1;
2649ac24a5a5Schristos 	if ((m0->m_pkthdr.len > ic->ic_rtsthreshold) &&
2650ac24a5a5Schristos 	    prior == URTW_PRIORITY_LOW)
2651ac24a5a5Schristos 		panic("TODO tx.");
2652ac24a5a5Schristos 	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
2653ac24a5a5Schristos 		data->buf[2] |= (1 << 1);
2654ac24a5a5Schristos 	/* RTS rate - 10 means we use a basic rate. */
2655ac24a5a5Schristos 	data->buf[2] |= (urtw_rate2rtl(2) << 3);
2656ac24a5a5Schristos 	/*
2657ac24a5a5Schristos 	 * XXX currently TX rate control depends on the rate value of
2658ac24a5a5Schristos 	 * RX descriptor because I don't know how to we can control TX rate
2659ac24a5a5Schristos 	 * in more smart way.  Please fix me you find a thing.
2660ac24a5a5Schristos 	 */
2661ac24a5a5Schristos 	data->buf[3] = sc->sc_currate;
2662ac24a5a5Schristos 	if (prior == URTW_PRIORITY_NORMAL) {
2663ac24a5a5Schristos 		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
2664ac24a5a5Schristos 			data->buf[3] = urtw_rate2rtl(ni->ni_rates.rs_rates[0]);
2665ac24a5a5Schristos 		else if (ic->ic_fixed_rate != -1)
2666ac24a5a5Schristos 			data->buf[3] = urtw_rate2rtl(ic->ic_fixed_rate);
2667ac24a5a5Schristos 	}
2668ac24a5a5Schristos 
2669ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
2670ac24a5a5Schristos 		data->buf[8] = 3;		/* CW minimum */
2671ac24a5a5Schristos 		data->buf[8] |= (7 << 4);	/* CW maximum */
2672ac24a5a5Schristos 		data->buf[9] |= 11;		/* retry limitation */
2673ac24a5a5Schristos 		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)&data->buf[12]);
2674ac24a5a5Schristos 	} else {
2675ac24a5a5Schristos 		data->buf[21] |= 11;		/* retry limitation */
2676ac24a5a5Schristos 		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)&data->buf[32]);
2677ac24a5a5Schristos 	}
2678ac24a5a5Schristos 
2679ac24a5a5Schristos 	data->ni = ni;
2680ac24a5a5Schristos 
2681ac24a5a5Schristos 	/* mbuf is no longer needed. */
2682ac24a5a5Schristos 	m_freem(m0);
2683ac24a5a5Schristos 
26844e8e6643Sskrll 	usbd_setup_xfer(data->xfer, data, data->buf, xferlen,
26854e8e6643Sskrll 	    USBD_FORCE_SHORT_XFER, URTW_DATA_TIMEOUT,
2686ac24a5a5Schristos 	    (prior == URTW_PRIORITY_LOW) ? urtw_txeof_low : urtw_txeof_normal);
2687ac24a5a5Schristos 	error = usbd_transfer(data->xfer);
2688ac24a5a5Schristos 	if (error != USBD_IN_PROGRESS && error != USBD_NORMAL_COMPLETION) {
2689ac24a5a5Schristos 		printf("%s: could not send frame: %s\n",
2690ac24a5a5Schristos 		    device_xname(sc->sc_dev), usbd_errstr(error));
26914e8e6643Sskrll 		return EIO;
2692ac24a5a5Schristos 	}
2693ac24a5a5Schristos 
2694ac24a5a5Schristos 	error = urtw_led_ctl(sc, URTW_LED_CTL_TX);
2695ac24a5a5Schristos 	if (error != 0)
2696ac24a5a5Schristos 		printf("%s: could not control LED (%d)\n",
2697ac24a5a5Schristos 		    device_xname(sc->sc_dev), error);
2698ac24a5a5Schristos 
26994e8e6643Sskrll 	sc->sc_tx_queued[prior]++;
2700ac24a5a5Schristos 
27014e8e6643Sskrll 	return 0;
2702ac24a5a5Schristos }
2703ac24a5a5Schristos 
270428885f8eSmaxv static usbd_status
urtw_8225_usb_init(struct urtw_softc * sc)2705ac24a5a5Schristos urtw_8225_usb_init(struct urtw_softc *sc)
2706ac24a5a5Schristos {
2707ac24a5a5Schristos 	uint8_t data;
2708ac24a5a5Schristos 	usbd_status error;
2709ac24a5a5Schristos 
2710ac24a5a5Schristos 	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0);
2711ac24a5a5Schristos 	urtw_write8_m(sc, URTW_GPIO, 0);
2712ac24a5a5Schristos 	error = urtw_read8e(sc, 0x53, &data);
2713ac24a5a5Schristos 	if (error)
2714ac24a5a5Schristos 		goto fail;
2715ac24a5a5Schristos 	error = urtw_write8e(sc, 0x53, data | (1 << 7));
2716ac24a5a5Schristos 	if (error)
2717ac24a5a5Schristos 		goto fail;
2718ac24a5a5Schristos 	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4);
2719ac24a5a5Schristos 	urtw_write8_m(sc, URTW_GPIO, 0x20);
2720ac24a5a5Schristos 	urtw_write8_m(sc, URTW_GP_ENABLE, 0);
2721ac24a5a5Schristos 
2722ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80);
2723ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80);
2724ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80);
2725ac24a5a5Schristos 
2726ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 500);
2727ac24a5a5Schristos fail:
27284e8e6643Sskrll 	return error;
2729ac24a5a5Schristos }
2730ac24a5a5Schristos 
273128885f8eSmaxv static usbd_status
urtw_8185_rf_pins_enable(struct urtw_softc * sc)2732ac24a5a5Schristos urtw_8185_rf_pins_enable(struct urtw_softc *sc)
2733ac24a5a5Schristos {
2734ac24a5a5Schristos 	usbd_status error = 0;
2735ac24a5a5Schristos 
2736ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7);
2737ac24a5a5Schristos fail:
27384e8e6643Sskrll 	return error;
2739ac24a5a5Schristos }
2740ac24a5a5Schristos 
274128885f8eSmaxv static usbd_status
urtw_8187_write_phy(struct urtw_softc * sc,uint8_t addr,uint32_t data)2742ac24a5a5Schristos urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2743ac24a5a5Schristos {
2744ac24a5a5Schristos 	uint32_t phyw;
2745ac24a5a5Schristos 	usbd_status error;
2746ac24a5a5Schristos 
2747ac24a5a5Schristos 	phyw = ((data << 8) | (addr | 0x80));
2748ac24a5a5Schristos 	urtw_write8_m(sc, 0x7f, ((phyw & 0xff000000) >> 24));
2749ac24a5a5Schristos 	urtw_write8_m(sc, 0x7e, ((phyw & 0x00ff0000) >> 16));
2750ac24a5a5Schristos 	urtw_write8_m(sc, 0x7d, ((phyw & 0x0000ff00) >> 8));
2751ac24a5a5Schristos 	urtw_write8_m(sc, 0x7c, ((phyw & 0x000000ff)));
2752ac24a5a5Schristos 	/*
2753ac24a5a5Schristos 	 * Delay removed from 8185 to 8187.
2754ac24a5a5Schristos 	 * usbd_delay_ms(sc->sc_udev, 1);
2755ac24a5a5Schristos 	 */
2756ac24a5a5Schristos fail:
27574e8e6643Sskrll 	return error;
2758ac24a5a5Schristos }
2759ac24a5a5Schristos 
276028885f8eSmaxv static usbd_status
urtw_8187_write_phy_ofdm_c(struct urtw_softc * sc,uint8_t addr,uint32_t data)2761ac24a5a5Schristos urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2762ac24a5a5Schristos {
2763ac24a5a5Schristos 	data = data & 0xff;
27644e8e6643Sskrll 	return urtw_8187_write_phy(sc, addr, data);
2765ac24a5a5Schristos }
2766ac24a5a5Schristos 
276728885f8eSmaxv static usbd_status
urtw_8187_write_phy_cck_c(struct urtw_softc * sc,uint8_t addr,uint32_t data)2768ac24a5a5Schristos urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2769ac24a5a5Schristos {
2770ac24a5a5Schristos 	data = data & 0xff;
27714e8e6643Sskrll 	return urtw_8187_write_phy(sc, addr, data | 0x10000);
2772ac24a5a5Schristos }
2773ac24a5a5Schristos 
277428885f8eSmaxv static usbd_status
urtw_8225_setgain(struct urtw_softc * sc,int16_t gain)2775ac24a5a5Schristos urtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
2776ac24a5a5Schristos {
2777ac24a5a5Schristos 	usbd_status error;
2778ac24a5a5Schristos 
2779ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]);
2780ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]);
2781ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]);
2782ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]);
2783ac24a5a5Schristos fail:
27844e8e6643Sskrll 	return error;
2785ac24a5a5Schristos }
2786ac24a5a5Schristos 
278728885f8eSmaxv static usbd_status
urtw_8225_set_txpwrlvl(struct urtw_softc * sc,int chan)2788ac24a5a5Schristos urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
2789ac24a5a5Schristos {
2790ac24a5a5Schristos 	int i, idx, set;
2791ac24a5a5Schristos 	uint8_t *cck_pwltable;
2792ac24a5a5Schristos 	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
2793ac24a5a5Schristos 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
2794ac24a5a5Schristos 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
2795ac24a5a5Schristos 	usbd_status error;
2796ac24a5a5Schristos 
2797ac24a5a5Schristos 	cck_pwrlvl_max = 11;
2798ac24a5a5Schristos 	ofdm_pwrlvl_max = 25;	/* 12 -> 25 */
2799ac24a5a5Schristos 	ofdm_pwrlvl_min = 10;
2800ac24a5a5Schristos 
2801ac24a5a5Schristos 	/* CCK power setting */
2802ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
2803ac24a5a5Schristos 	idx = cck_pwrlvl % 6;
2804ac24a5a5Schristos 	set = cck_pwrlvl / 6;
2805ac24a5a5Schristos 	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
2806ac24a5a5Schristos 	    urtw_8225_txpwr_cck;
2807ac24a5a5Schristos 
2808ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
2809ac24a5a5Schristos 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2810ac24a5a5Schristos 	for (i = 0; i < 8; i++) {
2811ac24a5a5Schristos 		urtw_8187_write_phy_cck(sc, 0x44 + i,
2812ac24a5a5Schristos 		    cck_pwltable[idx * 8 + i]);
2813ac24a5a5Schristos 	}
2814ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
2815ac24a5a5Schristos 
2816ac24a5a5Schristos 	/* OFDM power setting */
2817ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
2818ac24a5a5Schristos 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
2819ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
2820ac24a5a5Schristos 
2821ac24a5a5Schristos 	idx = ofdm_pwrlvl % 6;
2822ac24a5a5Schristos 	set = ofdm_pwrlvl / 6;
2823ac24a5a5Schristos 
2824ac24a5a5Schristos 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
2825ac24a5a5Schristos 	if (error)
2826ac24a5a5Schristos 		goto fail;
2827ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
2828ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 6, 0);
2829ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 8, 0);
2830ac24a5a5Schristos 
2831ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
2832ac24a5a5Schristos 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2833ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]);
2834ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]);
2835ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
2836ac24a5a5Schristos fail:
28374e8e6643Sskrll 	return error;
2838ac24a5a5Schristos }
2839ac24a5a5Schristos 
284028885f8eSmaxv static usbd_status
urtw_8185_tx_antenna(struct urtw_softc * sc,uint8_t ant)2841ac24a5a5Schristos urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
2842ac24a5a5Schristos {
2843ac24a5a5Schristos 	usbd_status error;
2844ac24a5a5Schristos 
2845ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_ANTENNA, ant);
2846ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
2847ac24a5a5Schristos fail:
28484e8e6643Sskrll 	return error;
2849ac24a5a5Schristos }
2850ac24a5a5Schristos 
285128885f8eSmaxv static usbd_status
urtw_8225_rf_init(struct urtw_rf * rf)2852ac24a5a5Schristos urtw_8225_rf_init(struct urtw_rf *rf)
2853ac24a5a5Schristos {
2854ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
2855ac24a5a5Schristos 	unsigned int i;
2856ac24a5a5Schristos 	uint16_t data;
2857ac24a5a5Schristos 	usbd_status error;
2858ac24a5a5Schristos 
2859ac24a5a5Schristos 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
2860ac24a5a5Schristos 	if (error)
2861ac24a5a5Schristos 		goto fail;
2862ac24a5a5Schristos 
2863ac24a5a5Schristos 	error = urtw_8225_usb_init(sc);
2864ac24a5a5Schristos 	if (error)
2865ac24a5a5Schristos 		goto fail;
2866ac24a5a5Schristos 
2867ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
2868ac24a5a5Schristos 	urtw_read16_m(sc, URTW_8187_BRSR, &data);	/* XXX ??? */
2869ac24a5a5Schristos 	urtw_write16_m(sc, URTW_8187_BRSR, 0xffff);
2870ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
2871ac24a5a5Schristos 
2872ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2873ac24a5a5Schristos 	if (error)
2874ac24a5a5Schristos 		goto fail;
2875ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
2876ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2877ac24a5a5Schristos 	if (error)
2878ac24a5a5Schristos 		goto fail;
2879ac24a5a5Schristos 
2880ac24a5a5Schristos 	error = urtw_8185_rf_pins_enable(sc);
2881ac24a5a5Schristos 	if (error)
2882ac24a5a5Schristos 		goto fail;
2883ac24a5a5Schristos 
2884ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 500);
2885ac24a5a5Schristos 
2886ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_rf_part1); i++) {
2887ac24a5a5Schristos 		urtw_8225_write(sc, urtw_8225_rf_part1[i].reg,
2888ac24a5a5Schristos 		    urtw_8225_rf_part1[i].val);
2889ac24a5a5Schristos 	}
2890ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 50);
2891ac24a5a5Schristos 	urtw_8225_write(sc, 0x2, 0xc4d);
2892ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 200);
2893ac24a5a5Schristos 	urtw_8225_write(sc, 0x2, 0x44d);
2894ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 200);
2895ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x127);
2896ac24a5a5Schristos 
2897ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_rxgain); i++) {
2898ac24a5a5Schristos 		urtw_8225_write(sc, 0x1, (uint8_t)(i + 1));
2899ac24a5a5Schristos 		urtw_8225_write(sc, 0x2, urtw_8225_rxgain[i]);
2900ac24a5a5Schristos 	}
2901ac24a5a5Schristos 
2902ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x27);
2903ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x22f);
2904ac24a5a5Schristos 
2905ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_agc); i++) {
2906ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
2907ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
2908ac24a5a5Schristos 	}
2909ac24a5a5Schristos 
2910ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_rf_part2); i++) {
2911ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg,
2912ac24a5a5Schristos 		    urtw_8225_rf_part2[i].val);
2913ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 1);
2914ac24a5a5Schristos 	}
2915ac24a5a5Schristos 
2916ac24a5a5Schristos 	error = urtw_8225_setgain(sc, 4);
2917ac24a5a5Schristos 	if (error)
2918ac24a5a5Schristos 		goto fail;
2919ac24a5a5Schristos 
2920ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_rf_part3); i++) {
2921ac24a5a5Schristos 		urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg,
2922ac24a5a5Schristos 		    urtw_8225_rf_part3[i].val);
2923ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 1);
2924ac24a5a5Schristos 	}
2925ac24a5a5Schristos 
2926ac24a5a5Schristos 	urtw_write8_m(sc, 0x5b, 0x0d);
2927ac24a5a5Schristos 
2928ac24a5a5Schristos 	error = urtw_8225_set_txpwrlvl(sc, 1);
2929ac24a5a5Schristos 	if (error)
2930ac24a5a5Schristos 		goto fail;
2931ac24a5a5Schristos 
2932ac24a5a5Schristos 	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
2933ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
2934ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
2935ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
2936ac24a5a5Schristos 
2937ac24a5a5Schristos 	/* TX ant A, 0x0 for B */
2938ac24a5a5Schristos 	error = urtw_8185_tx_antenna(sc, 0x3);
2939ac24a5a5Schristos 	if (error)
2940ac24a5a5Schristos 		goto fail;
2941ac24a5a5Schristos 	urtw_write32_m(sc, 0x94, 0x3dc00002);
2942ac24a5a5Schristos 
2943ac24a5a5Schristos 	error = urtw_8225_rf_set_chan(rf, 1);
2944ac24a5a5Schristos fail:
29454e8e6643Sskrll 	return error;
2946ac24a5a5Schristos }
2947ac24a5a5Schristos 
294828885f8eSmaxv static usbd_status
urtw_8225_rf_set_chan(struct urtw_rf * rf,int chan)2949ac24a5a5Schristos urtw_8225_rf_set_chan(struct urtw_rf *rf, int chan)
2950ac24a5a5Schristos {
2951ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
2952ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
2953ac24a5a5Schristos 	struct ieee80211_channel *c = ic->ic_ibss_chan;
2954ac24a5a5Schristos 	usbd_status error;
2955ac24a5a5Schristos 
2956ac24a5a5Schristos 	error = urtw_8225_set_txpwrlvl(sc, chan);
2957ac24a5a5Schristos 	if (error)
2958ac24a5a5Schristos 		goto fail;
2959ac24a5a5Schristos 	urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]);
2960ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 10);
2961ac24a5a5Schristos 
2962ac24a5a5Schristos 	urtw_write8_m(sc, URTW_SIFS, 0x22);
2963ac24a5a5Schristos 
2964ac24a5a5Schristos 	if (sc->sc_state == IEEE80211_S_ASSOC &&
2965ac24a5a5Schristos 	    ic->ic_flags & IEEE80211_F_SHSLOT)
2966ac24a5a5Schristos 		urtw_write8_m(sc, URTW_SLOT, 0x9);
2967ac24a5a5Schristos 	else
2968ac24a5a5Schristos 		urtw_write8_m(sc, URTW_SLOT, 0x14);
2969ac24a5a5Schristos 
2970ac24a5a5Schristos 	if (IEEE80211_IS_CHAN_G(c)) {
2971ac24a5a5Schristos 		urtw_write8_m(sc, URTW_DIFS, 0x14);
2972ac24a5a5Schristos 		urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x14);
2973ac24a5a5Schristos 		urtw_write8_m(sc, URTW_CW_VAL, 0x73);
2974ac24a5a5Schristos 	} else {
2975ac24a5a5Schristos 		urtw_write8_m(sc, URTW_DIFS, 0x24);
2976ac24a5a5Schristos 		urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x24);
2977ac24a5a5Schristos 		urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
2978ac24a5a5Schristos 	}
2979ac24a5a5Schristos 
2980ac24a5a5Schristos fail:
29814e8e6643Sskrll 	return error;
2982ac24a5a5Schristos }
2983ac24a5a5Schristos 
298428885f8eSmaxv static usbd_status
urtw_8225_rf_set_sens(struct urtw_rf * rf)2985ac24a5a5Schristos urtw_8225_rf_set_sens(struct urtw_rf *rf)
2986ac24a5a5Schristos {
2987ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
2988ac24a5a5Schristos 	usbd_status error;
2989ac24a5a5Schristos 
2990ac24a5a5Schristos 	if (rf->sens > 6)
29914e8e6643Sskrll 		return -1;
2992ac24a5a5Schristos 
2993ac24a5a5Schristos 	if (rf->sens > 4)
2994ac24a5a5Schristos 		urtw_8225_write(sc, 0x0c, 0x850);
2995ac24a5a5Schristos 	else
2996ac24a5a5Schristos 		urtw_8225_write(sc, 0x0c, 0x50);
2997ac24a5a5Schristos 
2998ac24a5a5Schristos 	rf->sens = 6 - rf->sens;
2999ac24a5a5Schristos 	error = urtw_8225_setgain(sc, rf->sens);
3000ac24a5a5Schristos 	if (error)
3001ac24a5a5Schristos 		goto fail;
3002ac24a5a5Schristos 
3003ac24a5a5Schristos 	urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[rf->sens]);
3004ac24a5a5Schristos 
3005ac24a5a5Schristos fail:
30064e8e6643Sskrll 	return error;
3007ac24a5a5Schristos }
3008ac24a5a5Schristos 
300928885f8eSmaxv static void
urtw_stop(struct ifnet * ifp,int disable)3010ac24a5a5Schristos urtw_stop(struct ifnet *ifp, int disable)
3011ac24a5a5Schristos {
3012ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
3013ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3014ac24a5a5Schristos 	uint8_t data;
3015ac24a5a5Schristos 	usbd_status error;
3016ac24a5a5Schristos 
3017ac24a5a5Schristos 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3018ac24a5a5Schristos 
3019ac24a5a5Schristos 	sc->sc_txtimer = 0;
3020ac24a5a5Schristos 	ifp->if_timer = 0;
3021ac24a5a5Schristos 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
3022ac24a5a5Schristos 
3023ac24a5a5Schristos 	callout_stop(&sc->scan_to);
3024ac24a5a5Schristos 	callout_stop(&sc->sc_led_ch);
3025ac24a5a5Schristos 
3026ac24a5a5Schristos 	urtw_intr_disable(sc);
3027ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
3028ac24a5a5Schristos 	data &= ~URTW_CMD_TX_ENABLE;
3029ac24a5a5Schristos 	data &= ~URTW_CMD_RX_ENABLE;
3030ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, data);
3031ac24a5a5Schristos 
3032ac24a5a5Schristos 	if (sc->sc_rxpipe != NULL)
3033ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_rxpipe);
3034ac24a5a5Schristos 	if (sc->sc_txpipe_low != NULL)
3035ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_txpipe_low);
3036ac24a5a5Schristos 	if (sc->sc_txpipe_normal != NULL)
3037ac24a5a5Schristos 		usbd_abort_pipe(sc->sc_txpipe_normal);
3038ac24a5a5Schristos 
3039ac24a5a5Schristos fail:
3040ac24a5a5Schristos 	return;
3041ac24a5a5Schristos }
3042ac24a5a5Schristos 
304328885f8eSmaxv static int
urtw_isbmode(uint16_t rate)3044ac24a5a5Schristos urtw_isbmode(uint16_t rate)
3045ac24a5a5Schristos {
3046ac24a5a5Schristos 	rate = urtw_rtl2rate(rate);
3047ac24a5a5Schristos 
30484e8e6643Sskrll 	return ((rate <= 22 && rate != 12 && rate != 18) ||
30494e8e6643Sskrll 	    rate == 44) ? 1 : 0;
3050ac24a5a5Schristos }
3051ac24a5a5Schristos 
305228885f8eSmaxv static void
urtw_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)30534e8e6643Sskrll urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
3054ac24a5a5Schristos {
3055ac24a5a5Schristos 	struct urtw_rx_data *data = priv;
3056ac24a5a5Schristos 	struct urtw_softc *sc = data->sc;
3057ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3058ac24a5a5Schristos 	struct ifnet *ifp = ic->ic_ifp;
3059ac24a5a5Schristos 	struct ieee80211_frame *wh;
3060ac24a5a5Schristos 	struct ieee80211_node *ni;
3061ac24a5a5Schristos 	struct mbuf *m, *mnew;
3062ac24a5a5Schristos 	uint8_t *desc, quality, rate;
30636c759efcSchristos 	int actlen, flen, len, rssi, s;
3064ac24a5a5Schristos 
3065ac24a5a5Schristos 	if (status != USBD_NORMAL_COMPLETION) {
3066ac24a5a5Schristos 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
3067ac24a5a5Schristos 			return;
3068ac24a5a5Schristos 
3069ac24a5a5Schristos 		if (status == USBD_STALLED)
3070ac24a5a5Schristos 			usbd_clear_endpoint_stall_async(sc->sc_rxpipe);
3071cdaa0e91Sthorpej 		if_statinc(ifp, if_ierrors);
3072ac24a5a5Schristos 		goto skip;
3073ac24a5a5Schristos 	}
3074ac24a5a5Schristos 
3075ac24a5a5Schristos 	usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
3076ac24a5a5Schristos 	if (actlen < URTW_MIN_RXBUFSZ) {
3077cdaa0e91Sthorpej 		if_statinc(ifp, if_ierrors);
3078ac24a5a5Schristos 		goto skip;
3079ac24a5a5Schristos 	}
3080ac24a5a5Schristos 
3081ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187)
3082ac24a5a5Schristos 		/* 4 dword and 4 byte CRC */
3083ac24a5a5Schristos 		len = actlen - (4 * 4);
3084ac24a5a5Schristos 	else
3085ac24a5a5Schristos 		/* 5 dword and 4 byte CRC */
3086ac24a5a5Schristos 		len = actlen - (4 * 5);
3087ac24a5a5Schristos 
3088ac24a5a5Schristos 	desc = data->buf + len;
3089ac24a5a5Schristos 	flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
3090ac24a5a5Schristos 	if (flen > actlen) {
3091cdaa0e91Sthorpej 		if_statinc(ifp, if_ierrors);
3092ac24a5a5Schristos 		goto skip;
3093ac24a5a5Schristos 	}
3094ac24a5a5Schristos 
3095ac24a5a5Schristos 	rate = (desc[2] & 0xf0) >> 4;
3096ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187) {
3097ac24a5a5Schristos 		quality = desc[4] & 0xff;
3098ac24a5a5Schristos 		rssi = (desc[6] & 0xfe) >> 1;
3099ac24a5a5Schristos 
3100ac24a5a5Schristos 		/* XXX correct? */
3101ac24a5a5Schristos 		if (!urtw_isbmode(rate)) {
3102ac24a5a5Schristos 			rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi);
3103ac24a5a5Schristos 			rssi = ((90 - rssi) * 100) / 65;
3104ac24a5a5Schristos 		} else {
3105ac24a5a5Schristos 			rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi);
3106ac24a5a5Schristos 			rssi = ((95 - rssi) * 100) / 65;
3107ac24a5a5Schristos 		}
3108ac24a5a5Schristos 	} else {
3109ac24a5a5Schristos 		quality = desc[12];
3110ac24a5a5Schristos 		rssi = 14 - desc[14] / 2;
3111ac24a5a5Schristos 	}
3112ac24a5a5Schristos 
3113ac24a5a5Schristos 	MGETHDR(mnew, M_DONTWAIT, MT_DATA);
3114ac24a5a5Schristos 	if (mnew == NULL) {
3115ac24a5a5Schristos 		printf("%s: could not allocate rx mbuf\n",
3116ac24a5a5Schristos 		    device_xname(sc->sc_dev));
3117cdaa0e91Sthorpej 		if_statinc(ifp, if_ierrors);
3118ac24a5a5Schristos 		goto skip;
3119ac24a5a5Schristos 	}
3120ac24a5a5Schristos 	MCLGET(mnew, M_DONTWAIT);
3121ac24a5a5Schristos 	if (!(mnew->m_flags & M_EXT)) {
3122ac24a5a5Schristos 		printf("%s: could not allocate rx mbuf cluster\n",
3123ac24a5a5Schristos 		    device_xname(sc->sc_dev));
3124ac24a5a5Schristos 		m_freem(mnew);
3125cdaa0e91Sthorpej 		if_statinc(ifp, if_ierrors);
3126ac24a5a5Schristos 		goto skip;
3127ac24a5a5Schristos 	}
3128ac24a5a5Schristos 
3129ac24a5a5Schristos 	m = data->m;
3130ac24a5a5Schristos 	data->m = mnew;
3131ac24a5a5Schristos 	data->buf = mtod(mnew, uint8_t *);
3132ac24a5a5Schristos 
3133ac24a5a5Schristos 	/* finalize mbuf */
3134d938d837Sozaki-r 	m_set_rcvif(m, ifp);
3135ac24a5a5Schristos 	m->m_pkthdr.len = m->m_len = flen - 4;
3136ac24a5a5Schristos 
3137ac24a5a5Schristos 	s = splnet();
3138ac24a5a5Schristos 
3139ac24a5a5Schristos 	if (sc->sc_drvbpf != NULL) {
3140ac24a5a5Schristos 		struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap;
3141ac24a5a5Schristos 
3142ac24a5a5Schristos 		/* XXX Are variables correct? */
3143ac24a5a5Schristos 		tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
3144ac24a5a5Schristos 		tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
3145ac24a5a5Schristos 		tap->wr_dbm_antsignal = (int8_t)rssi;
3146ac24a5a5Schristos 
31473cd62456Smsaitoh 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_D_IN);
3148ac24a5a5Schristos 	}
3149ac24a5a5Schristos 	wh = mtod(m, struct ieee80211_frame *);
3150ac24a5a5Schristos 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
3151ac24a5a5Schristos 		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
3152ac24a5a5Schristos 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
3153ac24a5a5Schristos 
3154ac24a5a5Schristos 	/* XXX correct? */
3155ac24a5a5Schristos 	if (!urtw_isbmode(rate)) {
3156ac24a5a5Schristos 		if (quality > 127)
3157ac24a5a5Schristos 			quality = 0;
3158ac24a5a5Schristos 		else if (quality < 27)
3159ac24a5a5Schristos 			quality = 100;
3160ac24a5a5Schristos 		else
3161ac24a5a5Schristos 			quality = 127 - quality;
3162ac24a5a5Schristos 	} else
3163ac24a5a5Schristos 		quality = (quality > 64) ? 0 : ((64 - quality) * 100) / 64;
3164ac24a5a5Schristos 
3165ac24a5a5Schristos 	/* send the frame to the 802.11 layer */
3166ac24a5a5Schristos 	ieee80211_input(ic, m, ni, rssi, 0);
3167ac24a5a5Schristos 
3168ac24a5a5Schristos 	/* node is no longer needed */
3169ac24a5a5Schristos 	ieee80211_free_node(ni);
3170ac24a5a5Schristos 
3171ac24a5a5Schristos 	splx(s);
3172ac24a5a5Schristos 
3173ac24a5a5Schristos skip:	/* setup a new transfer */
31744e8e6643Sskrll 	usbd_setup_xfer(xfer, data, data->buf, MCLBYTES,
3175ac24a5a5Schristos 	    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, urtw_rxeof);
3176ac24a5a5Schristos 	(void)usbd_transfer(xfer);
3177ac24a5a5Schristos }
3178ac24a5a5Schristos 
317928885f8eSmaxv static usbd_status
urtw_8225v2_setgain(struct urtw_softc * sc,int16_t gain)3180ac24a5a5Schristos urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
3181ac24a5a5Schristos {
3182ac24a5a5Schristos 	uint8_t *gainp;
3183ac24a5a5Schristos 	usbd_status error;
3184ac24a5a5Schristos 
3185ac24a5a5Schristos 	/* XXX for A? */
3186ac24a5a5Schristos 	gainp = urtw_8225v2_gain_bg;
3187ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]);
3188ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3189ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]);
3190ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3191ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]);
3192ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3193ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x21, 0x17);
3194ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3195ac24a5a5Schristos fail:
31964e8e6643Sskrll 	return error;
3197ac24a5a5Schristos }
3198ac24a5a5Schristos 
319928885f8eSmaxv static usbd_status
urtw_8225v2_set_txpwrlvl(struct urtw_softc * sc,int chan)3200ac24a5a5Schristos urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
3201ac24a5a5Schristos {
3202ac24a5a5Schristos 	int i;
3203ac24a5a5Schristos 	uint8_t *cck_pwrtable;
3204ac24a5a5Schristos 	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
3205ac24a5a5Schristos 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3206ac24a5a5Schristos 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3207ac24a5a5Schristos 	usbd_status error;
3208ac24a5a5Schristos 
3209ac24a5a5Schristos 	/* CCK power setting */
3210ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
3211ac24a5a5Schristos 	cck_pwrlvl += sc->sc_txpwr_cck_base;
3212ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3213ac24a5a5Schristos 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3214ac24a5a5Schristos 	    urtw_8225v2_txpwr_cck;
3215ac24a5a5Schristos 
3216ac24a5a5Schristos 	for (i = 0; i < 8; i++) {
3217ac24a5a5Schristos 		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3218ac24a5a5Schristos 	}
3219ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3220ac24a5a5Schristos 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]);
3221ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3222ac24a5a5Schristos 
3223ac24a5a5Schristos 	/* OFDM power setting */
3224ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3225ac24a5a5Schristos 		ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3226ac24a5a5Schristos 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3227ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3228ac24a5a5Schristos 
3229ac24a5a5Schristos 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
3230ac24a5a5Schristos 	if (error)
3231ac24a5a5Schristos 		goto fail;
3232ac24a5a5Schristos 
3233ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
3234ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 5, 0x0);
3235ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 6, 0x40);
3236ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 7, 0x0);
3237ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 8, 0x40);
3238ac24a5a5Schristos 
3239ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3240ac24a5a5Schristos 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]);
3241ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1);
3242ac24a5a5Schristos fail:
32434e8e6643Sskrll 	return error;
3244ac24a5a5Schristos }
3245ac24a5a5Schristos 
324628885f8eSmaxv static usbd_status
urtw_8225v2_rf_init(struct urtw_rf * rf)3247ac24a5a5Schristos urtw_8225v2_rf_init(struct urtw_rf *rf)
3248ac24a5a5Schristos {
3249ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
3250ac24a5a5Schristos 	int i;
3251ac24a5a5Schristos 	uint16_t data;
3252ac24a5a5Schristos 	uint32_t data32;
3253ac24a5a5Schristos 	usbd_status error;
3254ac24a5a5Schristos 
3255ac24a5a5Schristos 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
3256ac24a5a5Schristos 	if (error)
3257ac24a5a5Schristos 		goto fail;
3258ac24a5a5Schristos 
3259ac24a5a5Schristos 	error = urtw_8225_usb_init(sc);
3260ac24a5a5Schristos 	if (error)
3261ac24a5a5Schristos 		goto fail;
3262ac24a5a5Schristos 
3263ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
3264ac24a5a5Schristos 	urtw_read16_m(sc, URTW_8187_BRSR, &data);	/* XXX ??? */
3265ac24a5a5Schristos 	urtw_write16_m(sc, URTW_8187_BRSR, 0xffff);
3266ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
3267ac24a5a5Schristos 
3268ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3269ac24a5a5Schristos 	if (error)
3270ac24a5a5Schristos 		goto fail;
3271ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
3272ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3273ac24a5a5Schristos 	if (error)
3274ac24a5a5Schristos 		goto fail;
3275ac24a5a5Schristos 
3276ac24a5a5Schristos 	error = urtw_8185_rf_pins_enable(sc);
3277ac24a5a5Schristos 	if (error)
3278ac24a5a5Schristos 		goto fail;
3279ac24a5a5Schristos 
3280ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 1000);
3281ac24a5a5Schristos 
3282ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_rf_part1); i++) {
3283ac24a5a5Schristos 		urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg,
3284ac24a5a5Schristos 		    urtw_8225v2_rf_part1[i].val);
3285ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 1);
3286ac24a5a5Schristos 	}
3287ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 50);
3288ac24a5a5Schristos 
3289ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x1b7);
3290ac24a5a5Schristos 
3291ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_rxgain); i++) {
3292ac24a5a5Schristos 		urtw_8225_write(sc, 0x1, (uint8_t)(i + 1));
3293ac24a5a5Schristos 		urtw_8225_write(sc, 0x2, urtw_8225v2_rxgain[i]);
3294ac24a5a5Schristos 	}
3295ac24a5a5Schristos 
3296ac24a5a5Schristos 	urtw_8225_write(sc, 0x3, 0x2);
3297ac24a5a5Schristos 	urtw_8225_write(sc, 0x5, 0x4);
3298ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0xb7);
3299ac24a5a5Schristos 	urtw_8225_write(sc, 0x2, 0xc4d);
3300ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
3301ac24a5a5Schristos 	urtw_8225_write(sc, 0x2, 0x44d);
3302ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
3303ac24a5a5Schristos 
3304ac24a5a5Schristos 	error = urtw_8225_read(sc, 0x6, &data32);
3305ac24a5a5Schristos 	if (error != 0)
3306ac24a5a5Schristos 		goto fail;
3307ac24a5a5Schristos 	if (data32 != 0xe6)
3308d3dde16cSchristos 		printf("%s: expect 0xe6!! (%#x)\n", device_xname(sc->sc_dev),
3309ac24a5a5Schristos 		    data32);
3310ac24a5a5Schristos 	if (!(data32 & 0x80)) {
3311ac24a5a5Schristos 		urtw_8225_write(sc, 0x02, 0x0c4d);
3312ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 200);
3313ac24a5a5Schristos 		urtw_8225_write(sc, 0x02, 0x044d);
3314ac24a5a5Schristos 		usbd_delay_ms(sc->sc_udev, 100);
3315ac24a5a5Schristos 		error = urtw_8225_read(sc, 0x6, &data32);
3316ac24a5a5Schristos 		if (error != 0)
3317ac24a5a5Schristos 			goto fail;
3318ac24a5a5Schristos 		if (!(data32 & 0x80))
3319ac24a5a5Schristos 			printf("%s: RF calibration failed\n",
3320ac24a5a5Schristos 			    device_xname(sc->sc_dev));
3321ac24a5a5Schristos 	}
3322ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
3323ac24a5a5Schristos 
3324ac24a5a5Schristos 	urtw_8225_write(sc, 0x0, 0x2bf);
3325ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225_agc); i++) {
3326ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
3327ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
3328ac24a5a5Schristos 	}
3329ac24a5a5Schristos 
3330ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_rf_part2); i++) {
3331ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg,
3332ac24a5a5Schristos 		    urtw_8225v2_rf_part2[i].val);
3333ac24a5a5Schristos 	}
3334ac24a5a5Schristos 
3335ac24a5a5Schristos 	error = urtw_8225v2_setgain(sc, 4);
3336ac24a5a5Schristos 	if (error)
3337ac24a5a5Schristos 		goto fail;
3338ac24a5a5Schristos 
3339ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_rf_part3); i++) {
3340ac24a5a5Schristos 		urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg,
3341ac24a5a5Schristos 		    urtw_8225v2_rf_part3[i].val);
3342ac24a5a5Schristos 	}
3343ac24a5a5Schristos 
3344ac24a5a5Schristos 	urtw_write8_m(sc, 0x5b, 0x0d);
3345ac24a5a5Schristos 
3346ac24a5a5Schristos 	error = urtw_8225v2_set_txpwrlvl(sc, 1);
3347ac24a5a5Schristos 	if (error)
3348ac24a5a5Schristos 		goto fail;
3349ac24a5a5Schristos 
3350ac24a5a5Schristos 	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
3351ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
3352ac24a5a5Schristos 
3353ac24a5a5Schristos 	/* TX ant A, 0x0 for B */
3354ac24a5a5Schristos 	error = urtw_8185_tx_antenna(sc, 0x3);
3355ac24a5a5Schristos 	if (error)
3356ac24a5a5Schristos 		goto fail;
3357ac24a5a5Schristos 	urtw_write32_m(sc, 0x94, 0x3dc00002);
3358ac24a5a5Schristos 
3359ac24a5a5Schristos 	error = urtw_8225_rf_set_chan(rf, 1);
3360ac24a5a5Schristos fail:
33614e8e6643Sskrll 	return error;
3362ac24a5a5Schristos }
3363ac24a5a5Schristos 
336428885f8eSmaxv static usbd_status
urtw_8225v2_rf_set_chan(struct urtw_rf * rf,int chan)3365ac24a5a5Schristos urtw_8225v2_rf_set_chan(struct urtw_rf *rf, int chan)
3366ac24a5a5Schristos {
3367ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
3368ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3369ac24a5a5Schristos 	struct ieee80211_channel *c = ic->ic_ibss_chan;
3370ac24a5a5Schristos 	usbd_status error;
3371ac24a5a5Schristos 
3372ac24a5a5Schristos 	error = urtw_8225v2_set_txpwrlvl(sc, chan);
3373ac24a5a5Schristos 	if (error)
3374ac24a5a5Schristos 		goto fail;
3375ac24a5a5Schristos 
3376ac24a5a5Schristos 	urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]);
3377ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 10);
3378ac24a5a5Schristos 
3379ac24a5a5Schristos 	urtw_write8_m(sc, URTW_SIFS, 0x22);
3380ac24a5a5Schristos 
3381ac24a5a5Schristos 	if(sc->sc_state == IEEE80211_S_ASSOC &&
3382ac24a5a5Schristos 	    ic->ic_flags & IEEE80211_F_SHSLOT)
3383ac24a5a5Schristos 		urtw_write8_m(sc, URTW_SLOT, 0x9);
3384ac24a5a5Schristos 	else
3385ac24a5a5Schristos 		urtw_write8_m(sc, URTW_SLOT, 0x14);
3386ac24a5a5Schristos 
3387ac24a5a5Schristos 	if (IEEE80211_IS_CHAN_G(c)) {
3388ac24a5a5Schristos 		urtw_write8_m(sc, URTW_DIFS, 0x14);
3389ac24a5a5Schristos 		urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x14);
3390ac24a5a5Schristos 		urtw_write8_m(sc, URTW_CW_VAL, 0x73);
3391ac24a5a5Schristos 	} else {
3392ac24a5a5Schristos 		urtw_write8_m(sc, URTW_DIFS, 0x24);
3393ac24a5a5Schristos 		urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x24);
3394ac24a5a5Schristos 		urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
3395ac24a5a5Schristos 	}
3396ac24a5a5Schristos 
3397ac24a5a5Schristos fail:
33984e8e6643Sskrll 	return error;
3399ac24a5a5Schristos }
3400ac24a5a5Schristos 
340128885f8eSmaxv static void
urtw_set_chan(struct urtw_softc * sc,struct ieee80211_channel * c)3402ac24a5a5Schristos urtw_set_chan(struct urtw_softc *sc, struct ieee80211_channel *c)
3403ac24a5a5Schristos {
3404ac24a5a5Schristos 	struct urtw_rf *rf = &sc->sc_rf;
3405ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3406ac24a5a5Schristos 	usbd_status error = 0;
3407ac24a5a5Schristos 	uint32_t data;
3408ac24a5a5Schristos 	u_int chan;
3409ac24a5a5Schristos 
3410ac24a5a5Schristos 	chan = ieee80211_chan2ieee(ic, c);
3411ac24a5a5Schristos 	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
3412ac24a5a5Schristos 		return;
3413ac24a5a5Schristos 	/*
3414ac24a5a5Schristos 	 * During changing the channel we need to temporary disable
3415ac24a5a5Schristos 	 * TX.
3416ac24a5a5Schristos 	 */
3417ac24a5a5Schristos 	urtw_read32_m(sc, URTW_TX_CONF, &data);
3418ac24a5a5Schristos 	data &= ~URTW_TX_LOOPBACK_MASK;
3419ac24a5a5Schristos 	urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC);
3420ac24a5a5Schristos 	error = rf->set_chan(rf, chan);
3421ac24a5a5Schristos 	if (error != 0) {
3422ac24a5a5Schristos 		printf("%s could not change the channel\n",
3423ac24a5a5Schristos 		    device_xname(sc->sc_dev));
3424ac24a5a5Schristos 		return;
3425ac24a5a5Schristos 	}
3426ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 10);
3427ac24a5a5Schristos 	urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_NONE);
3428ac24a5a5Schristos 
3429ac24a5a5Schristos fail:	return;
3430ac24a5a5Schristos 
3431ac24a5a5Schristos }
3432ac24a5a5Schristos 
343328885f8eSmaxv static void
urtw_next_scan(void * arg)3434ac24a5a5Schristos urtw_next_scan(void *arg)
3435ac24a5a5Schristos {
3436ac24a5a5Schristos 	struct urtw_softc *sc = arg;
3437ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3438ac24a5a5Schristos 	int s;
3439ac24a5a5Schristos 
3440ac24a5a5Schristos 	if (sc->sc_dying)
3441ac24a5a5Schristos 		return;
3442ac24a5a5Schristos 
3443ac24a5a5Schristos 	s = splnet();
3444ac24a5a5Schristos 	if (ic->ic_state == IEEE80211_S_SCAN)
3445ac24a5a5Schristos 		ieee80211_next_scan(ic);
3446ac24a5a5Schristos 	splx(s);
3447ac24a5a5Schristos }
3448ac24a5a5Schristos 
344928885f8eSmaxv static void
urtw_task(void * arg)3450ac24a5a5Schristos urtw_task(void *arg)
3451ac24a5a5Schristos {
3452ac24a5a5Schristos 	struct urtw_softc *sc = arg;
3453ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3454ac24a5a5Schristos 	struct ieee80211_node *ni;
3455ac24a5a5Schristos 	enum ieee80211_state ostate;
3456ac24a5a5Schristos 	usbd_status error = 0;
3457ac24a5a5Schristos 
3458ac24a5a5Schristos 	if (sc->sc_dying)
3459ac24a5a5Schristos 		return;
3460ac24a5a5Schristos 
3461ac24a5a5Schristos 	ostate = ic->ic_state;
3462ac24a5a5Schristos 
3463ac24a5a5Schristos 	switch (sc->sc_state) {
3464ac24a5a5Schristos 	case IEEE80211_S_INIT:
3465ac24a5a5Schristos 		if (ostate == IEEE80211_S_RUN) {
3466ac24a5a5Schristos 			/* turn link LED off */
3467ac24a5a5Schristos 			(void)urtw_led_off(sc, URTW_LED_GPIO);
3468ac24a5a5Schristos 		}
3469ac24a5a5Schristos 		break;
3470ac24a5a5Schristos 
3471ac24a5a5Schristos 	case IEEE80211_S_SCAN:
3472ac24a5a5Schristos 		urtw_set_chan(sc, ic->ic_curchan);
3473ac24a5a5Schristos 		if (!sc->sc_dying)
3474ac24a5a5Schristos 			callout_schedule(&sc->scan_to, mstohz(200));
3475ac24a5a5Schristos 		break;
3476ac24a5a5Schristos 
3477ac24a5a5Schristos 	case IEEE80211_S_AUTH:
3478ac24a5a5Schristos 	case IEEE80211_S_ASSOC:
3479ac24a5a5Schristos 		urtw_set_chan(sc, ic->ic_curchan);
3480ac24a5a5Schristos 		break;
3481ac24a5a5Schristos 
3482ac24a5a5Schristos 	case IEEE80211_S_RUN:
3483ac24a5a5Schristos 		ni = ic->ic_bss;
3484ac24a5a5Schristos 
3485ac24a5a5Schristos 		urtw_set_chan(sc, ic->ic_curchan);
3486ac24a5a5Schristos 
3487ac24a5a5Schristos 		/* setting bssid. */
3488ac24a5a5Schristos 		error = urtw_set_bssid(sc, ni->ni_bssid);
3489ac24a5a5Schristos 		if (error != 0)
3490ac24a5a5Schristos 			goto fail;
3491ac24a5a5Schristos 		urtw_update_msr(sc);
3492ac24a5a5Schristos 		/* XXX maybe the below would be incorrect. */
3493ac24a5a5Schristos 		urtw_write16_m(sc, URTW_ATIM_WND, 2);
3494ac24a5a5Schristos 		urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
3495ac24a5a5Schristos 		urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64);
3496ac24a5a5Schristos 		urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 0x3ff);
3497ac24a5a5Schristos 		error = urtw_led_ctl(sc, URTW_LED_CTL_LINK);
3498ac24a5a5Schristos 		if (error != 0)
3499ac24a5a5Schristos 			printf("%s: could not control LED (%d)\n",
3500ac24a5a5Schristos 			    device_xname(sc->sc_dev), error);
3501ac24a5a5Schristos 		break;
3502ac24a5a5Schristos 	}
3503ac24a5a5Schristos 
3504ac24a5a5Schristos 	sc->sc_newstate(ic, sc->sc_state, sc->sc_arg);
3505ac24a5a5Schristos 
3506ac24a5a5Schristos fail:
3507ac24a5a5Schristos 	if (error != 0) {
3508ac24a5a5Schristos 		DPRINTF(("%s: error duing processing RUN state.",
3509ac24a5a5Schristos 		    device_xname(sc->sc_dev)));
3510ac24a5a5Schristos 	}
3511ac24a5a5Schristos }
3512ac24a5a5Schristos 
351328885f8eSmaxv static usbd_status
urtw_8187b_update_wmm(struct urtw_softc * sc)3514ac24a5a5Schristos urtw_8187b_update_wmm(struct urtw_softc *sc)
3515ac24a5a5Schristos {
3516ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3517ac24a5a5Schristos 	struct ieee80211_channel *c = ic->ic_ibss_chan;
3518ac24a5a5Schristos 	uint32_t data;
3519ac24a5a5Schristos 	uint8_t aifs, sifs, slot, ecwmin, ecwmax;
3520ac24a5a5Schristos 	usbd_status error;
3521ac24a5a5Schristos 
3522ac24a5a5Schristos 	sifs = 0xa;
3523ac24a5a5Schristos 	if (IEEE80211_IS_CHAN_G(c))
3524ac24a5a5Schristos 		slot = 0x9;
3525ac24a5a5Schristos 	else
3526ac24a5a5Schristos 		slot = 0x14;
3527ac24a5a5Schristos 
3528ac24a5a5Schristos 	aifs = (2 * slot) + sifs;
3529ac24a5a5Schristos 	ecwmin = 3;
3530ac24a5a5Schristos 	ecwmax = 7;
3531ac24a5a5Schristos 
3532ac24a5a5Schristos 	data = ((uint32_t)aifs << 0) |		/* AIFS, offset 0 */
3533ac24a5a5Schristos 	    ((uint32_t)ecwmin << 8) |		/* ECW minimum, offset 8 */
3534ac24a5a5Schristos 	    ((uint32_t)ecwmax << 12);		/* ECW maximum, offset 16 */
3535ac24a5a5Schristos 
3536ac24a5a5Schristos 	urtw_write32_m(sc, URTW_AC_VO, data);
3537ac24a5a5Schristos 	urtw_write32_m(sc, URTW_AC_VI, data);
3538ac24a5a5Schristos 	urtw_write32_m(sc, URTW_AC_BE, data);
3539ac24a5a5Schristos 	urtw_write32_m(sc, URTW_AC_BK, data);
3540ac24a5a5Schristos 
3541ac24a5a5Schristos fail:
35424e8e6643Sskrll 	return error;
3543ac24a5a5Schristos }
3544ac24a5a5Schristos 
354528885f8eSmaxv static usbd_status
urtw_8187b_reset(struct urtw_softc * sc)3546ac24a5a5Schristos urtw_8187b_reset(struct urtw_softc *sc)
3547ac24a5a5Schristos {
3548ac24a5a5Schristos 	uint8_t data;
3549ac24a5a5Schristos 	usbd_status error;
3550ac24a5a5Schristos 
3551ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3552ac24a5a5Schristos 	if (error)
3553ac24a5a5Schristos 		goto fail;
3554ac24a5a5Schristos 
3555ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
3556ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE |
3557ac24a5a5Schristos 		URTW_CONFIG3_GNT_SELECT);
3558ac24a5a5Schristos 
3559ac24a5a5Schristos 	urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON);
3560ac24a5a5Schristos 	urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON);
3561ac24a5a5Schristos 	urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON);
3562ac24a5a5Schristos 
3563ac24a5a5Schristos 	urtw_write8_m(sc, 0x61, 0x10);
3564ac24a5a5Schristos 	urtw_read8_m(sc, 0x62, &data);
3565ac24a5a5Schristos 	urtw_write8_m(sc, 0x62, data & ~(1 << 5));
3566ac24a5a5Schristos 	urtw_write8_m(sc, 0x62, data | (1 << 5));
3567ac24a5a5Schristos 
3568ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
3569ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
3570ac24a5a5Schristos 
3571ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3572ac24a5a5Schristos 	if (error)
3573ac24a5a5Schristos 		goto fail;
3574ac24a5a5Schristos 
3575ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
3576ac24a5a5Schristos 	data = (data & 2) | URTW_CMD_RST;
3577ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, data);
3578ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
3579ac24a5a5Schristos 
3580ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CMD, &data);
3581ac24a5a5Schristos 	if (data & URTW_CMD_RST) {
3582ac24a5a5Schristos 		printf("%s: reset timeout\n", device_xname(sc->sc_dev));
3583ac24a5a5Schristos 		goto fail;
3584ac24a5a5Schristos 	}
3585ac24a5a5Schristos 
3586ac24a5a5Schristos fail:
35874e8e6643Sskrll 	return error;
3588ac24a5a5Schristos }
3589ac24a5a5Schristos 
359028885f8eSmaxv static int
urtw_8187b_init(struct ifnet * ifp)3591ac24a5a5Schristos urtw_8187b_init(struct ifnet *ifp)
3592ac24a5a5Schristos {
3593ac24a5a5Schristos 	struct urtw_softc *sc = ifp->if_softc;
3594ac24a5a5Schristos 	struct urtw_rf *rf = &sc->sc_rf;
3595ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3596ac24a5a5Schristos 	uint8_t data;
3597ac24a5a5Schristos 	usbd_status error;
3598ac24a5a5Schristos 
3599ac24a5a5Schristos 	urtw_stop(ifp, 0);
3600ac24a5a5Schristos 
3601ac24a5a5Schristos 	error = urtw_8187b_update_wmm(sc);
3602ac24a5a5Schristos 	if (error != 0)
3603ac24a5a5Schristos 		goto fail;
3604ac24a5a5Schristos 	error = urtw_8187b_reset(sc);
3605ac24a5a5Schristos 	if (error)
3606ac24a5a5Schristos 		goto fail;
3607ac24a5a5Schristos 
3608ac24a5a5Schristos 	/* Applying MAC address again. */
3609ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3610ac24a5a5Schristos 	if (error)
3611ac24a5a5Schristos 		goto fail;
3612ac24a5a5Schristos 	IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
3613ac24a5a5Schristos 	error = urtw_set_macaddr(sc, ic->ic_myaddr);
3614ac24a5a5Schristos 	if (error)
3615ac24a5a5Schristos 		goto fail;
3616ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3617ac24a5a5Schristos 	if (error)
3618ac24a5a5Schristos 		goto fail;
3619ac24a5a5Schristos 
3620ac24a5a5Schristos 	error = urtw_update_msr(sc);
3621ac24a5a5Schristos 	if (error)
3622ac24a5a5Schristos 		goto fail;
3623ac24a5a5Schristos 
3624ac24a5a5Schristos 	error = rf->init(rf);
3625ac24a5a5Schristos 	if (error != 0)
3626ac24a5a5Schristos 		goto fail;
3627ac24a5a5Schristos 
3628ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CMD, URTW_CMD_TX_ENABLE |
3629ac24a5a5Schristos 		URTW_CMD_RX_ENABLE);
3630ac24a5a5Schristos 	error = urtw_intr_enable(sc);
3631ac24a5a5Schristos 	if (error != 0)
3632ac24a5a5Schristos 		goto fail;
3633ac24a5a5Schristos 
3634ac24a5a5Schristos 	error = urtw_write8e(sc, 0x41, 0xf4);
3635ac24a5a5Schristos 	if (error != 0)
3636ac24a5a5Schristos 		goto fail;
3637ac24a5a5Schristos 	error = urtw_write8e(sc, 0x40, 0x00);
3638ac24a5a5Schristos 	if (error != 0)
3639ac24a5a5Schristos 		goto fail;
3640ac24a5a5Schristos 	error = urtw_write8e(sc, 0x42, 0x00);
3641ac24a5a5Schristos 	if (error != 0)
3642ac24a5a5Schristos 		goto fail;
3643ac24a5a5Schristos 	error = urtw_write8e(sc, 0x42, 0x01);
3644ac24a5a5Schristos 	if (error != 0)
3645ac24a5a5Schristos 		goto fail;
3646ac24a5a5Schristos 	error = urtw_write8e(sc, 0x40, 0x0f);
3647ac24a5a5Schristos 	if (error != 0)
3648ac24a5a5Schristos 		goto fail;
3649ac24a5a5Schristos 	error = urtw_write8e(sc, 0x42, 0x00);
3650ac24a5a5Schristos 	if (error != 0)
3651ac24a5a5Schristos 		goto fail;
3652ac24a5a5Schristos 	error = urtw_write8e(sc, 0x42, 0x01);
3653ac24a5a5Schristos 	if (error != 0)
3654ac24a5a5Schristos 		goto fail;
3655ac24a5a5Schristos 
3656ac24a5a5Schristos 	urtw_read8_m(sc, 0xdb, &data);
3657ac24a5a5Schristos 	urtw_write8_m(sc, 0xdb, data | (1 << 2));
3658ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x72, 0x59fa, 3);
3659ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x74, 0x59d2, 3);
3660ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x76, 0x59d2, 3);
3661ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x78, 0x19fa, 3);
3662ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x7a, 0x19fa, 3);
3663ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0x7c, 0x00d0, 3);
3664ac24a5a5Schristos 	urtw_write8_m(sc, 0x61, 0);
3665ac24a5a5Schristos 	urtw_write8_idx_m(sc, 0x80, 0x0f, 1);
3666ac24a5a5Schristos 	urtw_write8_idx_m(sc, 0x83, 0x03, 1);
3667ac24a5a5Schristos 	urtw_write8_m(sc, 0xda, 0x10);
3668ac24a5a5Schristos 	urtw_write8_idx_m(sc, 0x4d, 0x08, 2);
3669ac24a5a5Schristos 
3670ac24a5a5Schristos 	urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321b);
3671ac24a5a5Schristos 
3672ac24a5a5Schristos 	urtw_write16_idx_m(sc, 0xec, 0x0800, 1);
3673ac24a5a5Schristos 
3674ac24a5a5Schristos 	urtw_write8_m(sc, URTW_ACM_CONTROL, 0);
3675ac24a5a5Schristos 
3676ac24a5a5Schristos 	/* Reset softc variables. */
36774e8e6643Sskrll 	for (size_t j = 0; j < URTW_PRIORITY_MAX; j++) {
36784e8e6643Sskrll 		sc->sc_txidx[j] = sc->sc_tx_queued[j] = 0;
36794e8e6643Sskrll 	}
3680ac24a5a5Schristos 	sc->sc_txtimer = 0;
3681ac24a5a5Schristos 
3682ac24a5a5Schristos 	if (!(sc->sc_flags & URTW_INIT_ONCE)) {
3683ac24a5a5Schristos 		error = usbd_set_config_no(sc->sc_udev, URTW_CONFIG_NO, 0);
3684ac24a5a5Schristos 		if (error != 0) {
3685897388eaSskrll 			aprint_error_dev(sc->sc_dev, "failed to set configuration"
3686897388eaSskrll 			    ", err=%s\n", usbd_errstr(error));
3687897388eaSskrll 
3688ac24a5a5Schristos 			goto fail;
3689ac24a5a5Schristos 		}
3690ac24a5a5Schristos 		/* Get the first interface handle. */
3691ac24a5a5Schristos 		error = usbd_device2interface_handle(sc->sc_udev,
3692ac24a5a5Schristos 		    URTW_IFACE_INDEX, &sc->sc_iface);
3693ac24a5a5Schristos 		if (error != 0) {
3694ac24a5a5Schristos 			printf("%s: could not get interface handle\n",
3695ac24a5a5Schristos 			    device_xname(sc->sc_dev));
3696ac24a5a5Schristos 			goto fail;
3697ac24a5a5Schristos 		}
3698ac24a5a5Schristos 		error = urtw_open_pipes(sc);
3699ac24a5a5Schristos 		if (error != 0)
3700ac24a5a5Schristos 			goto fail;
37016c759efcSchristos 		error = urtw_alloc_rx_data_list(sc);
3702ac24a5a5Schristos 		if (error != 0)
3703ac24a5a5Schristos 			goto fail;
37046c759efcSchristos 		error = urtw_alloc_tx_data_list(sc);
3705ac24a5a5Schristos 		if (error != 0)
3706ac24a5a5Schristos 			goto fail;
3707ac24a5a5Schristos 		sc->sc_flags |= URTW_INIT_ONCE;
3708ac24a5a5Schristos 	}
3709ac24a5a5Schristos 
3710ac24a5a5Schristos 	error = urtw_rx_enable(sc);
3711ac24a5a5Schristos 	if (error != 0)
3712ac24a5a5Schristos 		goto fail;
3713ac24a5a5Schristos 	error = urtw_tx_enable(sc);
3714ac24a5a5Schristos 	if (error != 0)
3715ac24a5a5Schristos 		goto fail;
3716ac24a5a5Schristos 
3717ac24a5a5Schristos 	ifp->if_flags &= ~IFF_OACTIVE;
3718ac24a5a5Schristos 	ifp->if_flags |= IFF_RUNNING;
3719ac24a5a5Schristos 
3720ac24a5a5Schristos 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
3721ac24a5a5Schristos 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
3722ac24a5a5Schristos 	else
3723ac24a5a5Schristos 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
3724ac24a5a5Schristos 
3725ac24a5a5Schristos fail:
37264e8e6643Sskrll 	return error;
3727ac24a5a5Schristos }
3728ac24a5a5Schristos 
372928885f8eSmaxv static usbd_status
urtw_8225v2_b_config_mac(struct urtw_softc * sc)3730ac24a5a5Schristos urtw_8225v2_b_config_mac(struct urtw_softc *sc)
3731ac24a5a5Schristos {
3732ac24a5a5Schristos 	int i;
3733ac24a5a5Schristos 	usbd_status error;
3734ac24a5a5Schristos 
3735ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8187b_regtbl); i++) {
3736ac24a5a5Schristos 		urtw_write8_idx_m(sc, urtw_8187b_regtbl[i].reg,
3737ac24a5a5Schristos 		    urtw_8187b_regtbl[i].val, urtw_8187b_regtbl[i].idx);
3738ac24a5a5Schristos 	}
3739ac24a5a5Schristos 
3740ac24a5a5Schristos 	urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50);
3741ac24a5a5Schristos 	urtw_write16_m(sc, URTW_INT_MIG, 0);
3742ac24a5a5Schristos 
3743ac24a5a5Schristos 	urtw_write32_idx_m(sc, 0xf0, 0, 1);
3744ac24a5a5Schristos 	urtw_write32_idx_m(sc, 0xf4, 0, 1);
3745ac24a5a5Schristos 	urtw_write8_idx_m(sc, 0xf8, 0, 1);
3746ac24a5a5Schristos 
3747ac24a5a5Schristos 	urtw_write32_m(sc, URTW_RF_TIMING, 0x00004001);
3748ac24a5a5Schristos 
3749ac24a5a5Schristos fail:
37504e8e6643Sskrll 	return error;
3751ac24a5a5Schristos }
3752ac24a5a5Schristos 
375328885f8eSmaxv static usbd_status
urtw_8225v2_b_init_rfe(struct urtw_softc * sc)3754ac24a5a5Schristos urtw_8225v2_b_init_rfe(struct urtw_softc *sc)
3755ac24a5a5Schristos {
3756ac24a5a5Schristos 	usbd_status error;
3757ac24a5a5Schristos 
3758ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480);
3759ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488);
3760ac24a5a5Schristos 	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff);
3761ac24a5a5Schristos 	usbd_delay_ms(sc->sc_udev, 100);
3762ac24a5a5Schristos 
3763ac24a5a5Schristos fail:
37644e8e6643Sskrll 	return error;
3765ac24a5a5Schristos }
3766ac24a5a5Schristos 
376728885f8eSmaxv static usbd_status
urtw_8225v2_b_update_chan(struct urtw_softc * sc)3768ac24a5a5Schristos urtw_8225v2_b_update_chan(struct urtw_softc *sc)
3769ac24a5a5Schristos {
3770ac24a5a5Schristos 	struct ieee80211com *ic = &sc->sc_ic;
3771ac24a5a5Schristos 	struct ieee80211_channel *c = ic->ic_ibss_chan;
3772ac24a5a5Schristos 	uint8_t aifs, difs, eifs, sifs, slot;
3773ac24a5a5Schristos 	usbd_status error;
3774ac24a5a5Schristos 
3775ac24a5a5Schristos 	urtw_write8_m(sc, URTW_SIFS, 0x22);
3776ac24a5a5Schristos 
3777ac24a5a5Schristos 	sifs = 0xa;
3778ac24a5a5Schristos 	if (IEEE80211_IS_CHAN_G(c)) {
3779ac24a5a5Schristos 		slot = 0x9;
3780ac24a5a5Schristos 		difs = 0x1c;
3781ac24a5a5Schristos 		eifs = 0x5b;
3782ac24a5a5Schristos 	} else {
3783ac24a5a5Schristos 		slot = 0x14;
3784ac24a5a5Schristos 		difs = 0x32;
3785ac24a5a5Schristos 		eifs = 0x5b;
3786ac24a5a5Schristos 	}
3787ac24a5a5Schristos 	aifs = (2 * slot) + sifs;
3788ac24a5a5Schristos 
3789ac24a5a5Schristos 	urtw_write8_m(sc, URTW_SLOT, slot);
3790ac24a5a5Schristos 
3791ac24a5a5Schristos 	urtw_write8_m(sc, URTW_AC_VO, aifs);
3792ac24a5a5Schristos 	urtw_write8_m(sc, URTW_AC_VI, aifs);
3793ac24a5a5Schristos 	urtw_write8_m(sc, URTW_AC_BE, aifs);
3794ac24a5a5Schristos 	urtw_write8_m(sc, URTW_AC_BK, aifs);
3795ac24a5a5Schristos 
3796ac24a5a5Schristos 	urtw_write8_m(sc, URTW_DIFS, difs);
3797ac24a5a5Schristos 	urtw_write8_m(sc, URTW_8187B_EIFS, eifs);
3798ac24a5a5Schristos 
3799ac24a5a5Schristos fail:
38004e8e6643Sskrll 	return error;
3801ac24a5a5Schristos }
3802ac24a5a5Schristos 
380328885f8eSmaxv static usbd_status
urtw_8225v2_b_rf_init(struct urtw_rf * rf)3804ac24a5a5Schristos urtw_8225v2_b_rf_init(struct urtw_rf *rf)
3805ac24a5a5Schristos {
3806ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
3807ac24a5a5Schristos 	unsigned int i;
3808ac24a5a5Schristos 	uint8_t data;
3809ac24a5a5Schristos 	usbd_status error;
3810ac24a5a5Schristos 
3811ac24a5a5Schristos 	/* Set up ACK rate, retry limit, TX AGC, TX antenna. */
3812ac24a5a5Schristos 	urtw_write16_m(sc, URTW_8187B_BRSR, 0x0fff);
3813ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CW_CONF, &data);
3814ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CW_CONF, data |
3815ac24a5a5Schristos 		URTW_CW_CONF_PERPACKET_RETRY);
3816ac24a5a5Schristos 	urtw_read8_m(sc, URTW_TX_AGC_CTL, &data);
3817ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_AGC_CTL, data |
3818ac24a5a5Schristos 		URTW_TX_AGC_CTL_PERPACKET_GAIN |
3819ac24a5a5Schristos 		URTW_TX_AGC_CTL_PERPACKET_ANTSEL);
3820ac24a5a5Schristos 
3821ac24a5a5Schristos 	/* Auto rate fallback control. */
3822ac24a5a5Schristos 	urtw_write16_idx_m(sc, URTW_ARFR, 0x0fff, 1);	/* 1M ~ 54M */
3823ac24a5a5Schristos 	urtw_read8_m(sc, URTW_RATE_FALLBACK, &data);
3824ac24a5a5Schristos 	urtw_write8_m(sc, URTW_RATE_FALLBACK, data |
3825ac24a5a5Schristos 		URTW_RATE_FALLBACK_ENABLE);
3826ac24a5a5Schristos 
3827ac24a5a5Schristos 	urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
3828ac24a5a5Schristos 	urtw_write16_m(sc, URTW_ATIM_WND, 2);
3829ac24a5a5Schristos 	urtw_write16_idx_m(sc, URTW_FEMR, 0xffff, 1);
3830ac24a5a5Schristos 
3831ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3832ac24a5a5Schristos 	if (error)
3833ac24a5a5Schristos 		goto fail;
3834ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG1, &data);
3835ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG1, (data & 0x3f) | 0x80);
3836ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3837ac24a5a5Schristos 	if (error)
3838ac24a5a5Schristos 		goto fail;
3839ac24a5a5Schristos 
3840ac24a5a5Schristos 	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
3841ac24a5a5Schristos 	urtw_8225v2_b_config_mac(sc);
3842ac24a5a5Schristos 	urtw_write16_idx_m(sc, URTW_RFSW_CTRL, 0x569a, 2);
3843ac24a5a5Schristos 
3844ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3845ac24a5a5Schristos 	if (error)
3846ac24a5a5Schristos 		goto fail;
3847ac24a5a5Schristos 	urtw_read8_m(sc, URTW_CONFIG3, &data);
3848ac24a5a5Schristos 	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
3849ac24a5a5Schristos 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3850ac24a5a5Schristos 	if (error)
3851ac24a5a5Schristos 		goto fail;
3852ac24a5a5Schristos 
3853ac24a5a5Schristos 	urtw_8225v2_b_init_rfe(sc);
3854ac24a5a5Schristos 
3855ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_b_rf); i++) {
3856ac24a5a5Schristos 		urtw_8225_write(sc, urtw_8225v2_b_rf[i].reg,
3857ac24a5a5Schristos 		    urtw_8225v2_b_rf[i].val);
3858ac24a5a5Schristos 	}
3859ac24a5a5Schristos 
3860ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_rxgain); i++) {
3861ac24a5a5Schristos 		urtw_8225_write(sc, 0x1, (uint8_t)(i + 1));
3862ac24a5a5Schristos 		urtw_8225_write(sc, 0x2, urtw_8225v2_rxgain[i]);
3863ac24a5a5Schristos 	}
3864ac24a5a5Schristos 
3865ac24a5a5Schristos 	urtw_8225_write(sc, 0x03, 0x080);
3866ac24a5a5Schristos 	urtw_8225_write(sc, 0x05, 0x004);
3867ac24a5a5Schristos 	urtw_8225_write(sc, 0x00, 0x0b7);
3868ac24a5a5Schristos 	urtw_8225_write(sc, 0x02, 0xc4d);
3869ac24a5a5Schristos 	urtw_8225_write(sc, 0x02, 0x44d);
3870ac24a5a5Schristos 	urtw_8225_write(sc, 0x00, 0x2bf);
3871ac24a5a5Schristos 
3872ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03);
3873ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07);
3874ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03);
3875ac24a5a5Schristos 
3876ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x80, 0x12);
3877ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_agc); i++) {
3878ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0x0f, urtw_8225v2_agc[i]);
3879ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0x0e, (uint8_t)i + 0x80);
3880ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, 0x0e, 0);
3881ac24a5a5Schristos 	}
3882ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x80, 0x10);
3883ac24a5a5Schristos 
3884ac24a5a5Schristos 	for (i = 0; i < __arraycount(urtw_8225v2_ofdm); i++)
3885ac24a5a5Schristos 		urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2_ofdm[i]);
3886ac24a5a5Schristos 
3887ac24a5a5Schristos 	urtw_8225v2_b_update_chan(sc);
3888ac24a5a5Schristos 
3889ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x97, 0x46);
3890ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6);
3891ac24a5a5Schristos 	urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc);
3892ac24a5a5Schristos 	urtw_8187_write_phy_cck(sc, 0xc1, 0x88);
3893ac24a5a5Schristos 
3894ac24a5a5Schristos 	error = urtw_8225v2_b_rf_set_chan(rf, 1);
3895ac24a5a5Schristos fail:
38964e8e6643Sskrll 	return error;
3897ac24a5a5Schristos }
3898ac24a5a5Schristos 
389928885f8eSmaxv static usbd_status
urtw_8225v2_b_rf_set_chan(struct urtw_rf * rf,int chan)3900ac24a5a5Schristos urtw_8225v2_b_rf_set_chan(struct urtw_rf *rf, int chan)
3901ac24a5a5Schristos {
3902ac24a5a5Schristos 	struct urtw_softc *sc = rf->rf_sc;
3903ac24a5a5Schristos 	usbd_status error;
3904ac24a5a5Schristos 
3905ac24a5a5Schristos 	error = urtw_8225v2_b_set_txpwrlvl(sc, chan);
3906ac24a5a5Schristos 	if (error)
3907ac24a5a5Schristos 		goto fail;
3908ac24a5a5Schristos 
3909ac24a5a5Schristos 	urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]);
3910ac24a5a5Schristos 	/*
3911ac24a5a5Schristos 	 * Delay removed from 8185 to 8187.
3912ac24a5a5Schristos 	 * usbd_delay_ms(sc->sc_udev, 10);
3913ac24a5a5Schristos 	 */
3914ac24a5a5Schristos 
3915ac24a5a5Schristos 	urtw_write16_m(sc, URTW_AC_VO, 0x5114);
3916ac24a5a5Schristos 	urtw_write16_m(sc, URTW_AC_VI, 0x5114);
3917ac24a5a5Schristos 	urtw_write16_m(sc, URTW_AC_BE, 0x5114);
3918ac24a5a5Schristos 	urtw_write16_m(sc, URTW_AC_BK, 0x5114);
3919ac24a5a5Schristos 
3920ac24a5a5Schristos fail:
39214e8e6643Sskrll 	return error;
3922ac24a5a5Schristos }
3923ac24a5a5Schristos 
392428885f8eSmaxv static usbd_status
urtw_8225v2_b_set_txpwrlvl(struct urtw_softc * sc,int chan)3925ac24a5a5Schristos urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *sc, int chan)
3926ac24a5a5Schristos {
3927ac24a5a5Schristos 	int i;
3928ac24a5a5Schristos 	uint8_t *cck_pwrtable;
3929ac24a5a5Schristos 	uint8_t cck_pwrlvl_min, cck_pwrlvl_max, ofdm_pwrlvl_min,
3930ac24a5a5Schristos 	    ofdm_pwrlvl_max;
3931ac24a5a5Schristos 	int8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3932ac24a5a5Schristos 	int8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3933ac24a5a5Schristos 	usbd_status error;
3934ac24a5a5Schristos 
3935ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3936ac24a5a5Schristos 		cck_pwrlvl_min = 0;
3937ac24a5a5Schristos 		cck_pwrlvl_max = 15;
3938ac24a5a5Schristos 		ofdm_pwrlvl_min = 2;
3939ac24a5a5Schristos 		ofdm_pwrlvl_max = 17;
3940ac24a5a5Schristos 	} else {
3941ac24a5a5Schristos 		cck_pwrlvl_min = 7;
3942ac24a5a5Schristos 		cck_pwrlvl_max = 22;
3943ac24a5a5Schristos 		ofdm_pwrlvl_min = 10;
3944ac24a5a5Schristos 		ofdm_pwrlvl_max = 25;
3945ac24a5a5Schristos 	}
3946ac24a5a5Schristos 
3947ac24a5a5Schristos 	/* CCK power setting */
3948ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl > (cck_pwrlvl_max - cck_pwrlvl_min)) ?
3949ac24a5a5Schristos 	    cck_pwrlvl_max : (cck_pwrlvl + cck_pwrlvl_min);
3950ac24a5a5Schristos 
3951ac24a5a5Schristos 	cck_pwrlvl += sc->sc_txpwr_cck_base;
3952ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3953ac24a5a5Schristos 	cck_pwrlvl = (cck_pwrlvl < 0) ? 0 : cck_pwrlvl;
3954ac24a5a5Schristos 
3955ac24a5a5Schristos 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3956ac24a5a5Schristos 	    urtw_8225v2_txpwr_cck;
3957ac24a5a5Schristos 
3958ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3959ac24a5a5Schristos 		if (cck_pwrlvl <= 6)
3960ac24a5a5Schristos 			; /* do nothing */
3961ac24a5a5Schristos 		else if (cck_pwrlvl <= 11)
3962ac24a5a5Schristos 			cck_pwrtable += 8;
3963ac24a5a5Schristos 		else
3964ac24a5a5Schristos 			cck_pwrtable += 16;
3965ac24a5a5Schristos 	} else {
3966ac24a5a5Schristos 		if (cck_pwrlvl <= 5)
3967ac24a5a5Schristos 			; /* do nothing */
3968ac24a5a5Schristos 		else if (cck_pwrlvl <= 11)
3969ac24a5a5Schristos 			cck_pwrtable += 8;
3970ac24a5a5Schristos 		else if (cck_pwrlvl <= 17)
3971ac24a5a5Schristos 			cck_pwrtable += 16;
3972ac24a5a5Schristos 		else
3973ac24a5a5Schristos 			cck_pwrtable += 24;
3974ac24a5a5Schristos 	}
3975ac24a5a5Schristos 
3976ac24a5a5Schristos 	for (i = 0; i < 8; i++) {
3977ac24a5a5Schristos 		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3978ac24a5a5Schristos 	}
3979ac24a5a5Schristos 
3980ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3981ac24a5a5Schristos 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1);
3982ac24a5a5Schristos 	/*
3983ac24a5a5Schristos 	 * Delay removed from 8185 to 8187.
3984ac24a5a5Schristos 	 * usbd_delay_ms(sc->sc_udev, 1);
3985ac24a5a5Schristos 	 */
3986ac24a5a5Schristos 
3987ac24a5a5Schristos 	/* OFDM power setting */
3988ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3989ac24a5a5Schristos 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3990ac24a5a5Schristos 
3991ac24a5a5Schristos 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3992ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3993ac24a5a5Schristos 	ofdm_pwrlvl = (ofdm_pwrlvl < 0) ? 0 : ofdm_pwrlvl;
3994ac24a5a5Schristos 
3995ac24a5a5Schristos 	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3996ac24a5a5Schristos 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1);
3997ac24a5a5Schristos 
3998ac24a5a5Schristos 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3999ac24a5a5Schristos 		if (ofdm_pwrlvl <= 11) {
4000ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x87, 0x60);
4001ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x89, 0x60);
4002ac24a5a5Schristos 		} else {
4003ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
4004ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
4005ac24a5a5Schristos 		}
4006ac24a5a5Schristos 	} else {
4007ac24a5a5Schristos 		if (ofdm_pwrlvl <= 11) {
4008ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
4009ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
4010ac24a5a5Schristos 		} else if (ofdm_pwrlvl <= 17) {
4011ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x87, 0x54);
4012ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x89, 0x54);
4013ac24a5a5Schristos 		} else {
4014ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x87, 0x50);
4015ac24a5a5Schristos 			urtw_8187_write_phy_ofdm(sc, 0x89, 0x50);
4016ac24a5a5Schristos 		}
4017ac24a5a5Schristos 	}
4018ac24a5a5Schristos 
4019ac24a5a5Schristos 	/*
4020ac24a5a5Schristos 	 * Delay removed from 8185 to 8187.
4021ac24a5a5Schristos 	 * usbd_delay_ms(sc->sc_udev, 1);
4022ac24a5a5Schristos 	 */
4023ac24a5a5Schristos fail:
40244e8e6643Sskrll 	return error;
4025ac24a5a5Schristos }
4026ac24a5a5Schristos 
402728885f8eSmaxv static int
urtw_set_bssid(struct urtw_softc * sc,const uint8_t * bssid)4028ac24a5a5Schristos urtw_set_bssid(struct urtw_softc *sc, const uint8_t *bssid)
4029ac24a5a5Schristos {
4030ac24a5a5Schristos 	int error;
4031ac24a5a5Schristos 
4032ac24a5a5Schristos 	urtw_write32_m(sc, URTW_BSSID,
4033ac24a5a5Schristos 	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
4034ac24a5a5Schristos 	urtw_write16_m(sc, URTW_BSSID + 4,
4035ac24a5a5Schristos 	    bssid[4] | bssid[5] << 8);
4036ac24a5a5Schristos 
4037ac24a5a5Schristos 	return 0;
4038ac24a5a5Schristos 
4039ac24a5a5Schristos fail:
4040ac24a5a5Schristos 	return error;
4041ac24a5a5Schristos }
4042ac24a5a5Schristos 
404328885f8eSmaxv static int
urtw_set_macaddr(struct urtw_softc * sc,const uint8_t * addr)4044ac24a5a5Schristos urtw_set_macaddr(struct urtw_softc *sc, const uint8_t *addr)
4045ac24a5a5Schristos {
4046ac24a5a5Schristos 	int error;
4047ac24a5a5Schristos 
4048ac24a5a5Schristos 	urtw_write32_m(sc, URTW_MAC0,
4049ac24a5a5Schristos 	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
4050ac24a5a5Schristos 	urtw_write16_m(sc, URTW_MAC4,
4051ac24a5a5Schristos 	    addr[4] | addr[5] << 8);
4052ac24a5a5Schristos 
4053ac24a5a5Schristos 	return 0;
4054ac24a5a5Schristos 
4055ac24a5a5Schristos fail:
4056ac24a5a5Schristos 	return error;
4057ac24a5a5Schristos }
4058ac24a5a5Schristos 
405960d3fae6Schristos MODULE(MODULE_CLASS_DRIVER, if_urtw, NULL);
4060ac24a5a5Schristos 
4061ac24a5a5Schristos #ifdef _MODULE
4062ac24a5a5Schristos #include "ioconf.c"
4063ac24a5a5Schristos #endif
4064ac24a5a5Schristos 
4065ac24a5a5Schristos static int
if_urtw_modcmd(modcmd_t cmd,void * aux)4066ac24a5a5Schristos if_urtw_modcmd(modcmd_t cmd, void *aux)
4067ac24a5a5Schristos {
4068ac24a5a5Schristos 	int error = 0;
4069ac24a5a5Schristos 
4070ac24a5a5Schristos 	switch (cmd) {
4071ac24a5a5Schristos 	case MODULE_CMD_INIT:
4072ac24a5a5Schristos #ifdef _MODULE
4073ac24a5a5Schristos 		error = config_init_component(cfdriver_ioconf_urtw,
4074ac24a5a5Schristos 		    cfattach_ioconf_urtw, cfdata_ioconf_urtw);
4075ac24a5a5Schristos #endif
4076ac24a5a5Schristos 		return error;
4077ac24a5a5Schristos 	case MODULE_CMD_FINI:
4078ac24a5a5Schristos #ifdef _MODULE
4079ac24a5a5Schristos 		error = config_fini_component(cfdriver_ioconf_urtw,
4080ac24a5a5Schristos 		    cfattach_ioconf_urtw, cfdata_ioconf_urtw);
4081ac24a5a5Schristos #endif
4082ac24a5a5Schristos 		return error;
4083ac24a5a5Schristos 	default:
4084ac24a5a5Schristos 		return ENOTTY;
4085ac24a5a5Schristos 	}
4086ac24a5a5Schristos }
4087