xref: /titanic_41/usr/src/uts/common/io/urtw/urtw.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
126594249SQin Michael Li /*
2*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
326594249SQin Michael Li  * Use is subject to license terms.
426594249SQin Michael Li  */
526594249SQin Michael Li 
626594249SQin Michael Li /*
726594249SQin Michael Li  * Copyright (c) 2008 Weongyo Jeong
826594249SQin Michael Li  * All rights reserved.
926594249SQin Michael Li  *
1026594249SQin Michael Li  * Redistribution and use in source and binary forms, with or without
1126594249SQin Michael Li  * modification, are permitted provided that the following conditions
1226594249SQin Michael Li  * are met:
1326594249SQin Michael Li  * 1. Redistributions of source code must retain the above copyright
1426594249SQin Michael Li  *    notice, this list of conditions and the following disclaimer,
1526594249SQin Michael Li  *    without modification.
1626594249SQin Michael Li  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1726594249SQin Michael Li  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1826594249SQin Michael Li  *    redistribution must be conditioned upon including a substantially
1926594249SQin Michael Li  *    similar Disclaimer requirement for further binary redistribution.
2026594249SQin Michael Li  *
2126594249SQin Michael Li  * NO WARRANTY
2226594249SQin Michael Li  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2326594249SQin Michael Li  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2426594249SQin Michael Li  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2526594249SQin Michael Li  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2626594249SQin Michael Li  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2726594249SQin Michael Li  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2826594249SQin Michael Li  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2926594249SQin Michael Li  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
3026594249SQin Michael Li  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3126594249SQin Michael Li  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3226594249SQin Michael Li  * THE POSSIBILITY OF SUCH DAMAGES.
3326594249SQin Michael Li  */
3426594249SQin Michael Li #include <sys/sysmacros.h>
3526594249SQin Michael Li #include <sys/strsubr.h>
3626594249SQin Michael Li #include <sys/strsun.h>
3726594249SQin Michael Li #include <sys/mac_provider.h>
3826594249SQin Michael Li #include <sys/mac_wifi.h>
3926594249SQin Michael Li #include <sys/net80211.h>
4026594249SQin Michael Li #define	USBDRV_MAJOR_VER	2
4126594249SQin Michael Li #define	USBDRV_MINOR_VER	0
4226594249SQin Michael Li #include <sys/usb/usba.h>
4326594249SQin Michael Li #include <sys/usb/usba/usba_types.h>
4426594249SQin Michael Li 
4526594249SQin Michael Li #include "urtw_reg.h"
4626594249SQin Michael Li #include "urtw_var.h"
4726594249SQin Michael Li 
4826594249SQin Michael Li static void *urtw_soft_state_p = NULL;
4926594249SQin Michael Li 
5026594249SQin Michael Li #define	URTW_TXBUF_SIZE  	(IEEE80211_MAX_LEN)
5126594249SQin Michael Li #define	URTW_RXBUF_SIZE  	(URTW_TXBUF_SIZE)
5226594249SQin Michael Li /*
5326594249SQin Michael Li  * device operations
5426594249SQin Michael Li  */
5526594249SQin Michael Li static int urtw_attach(dev_info_t *, ddi_attach_cmd_t);
5626594249SQin Michael Li static int urtw_detach(dev_info_t *, ddi_detach_cmd_t);
5726594249SQin Michael Li 
5826594249SQin Michael Li /*
5926594249SQin Michael Li  * Module Loading Data & Entry Points
6026594249SQin Michael Li  */
6126594249SQin Michael Li DDI_DEFINE_STREAM_OPS(urtw_dev_ops, nulldev, nulldev, urtw_attach,
6226594249SQin Michael Li     urtw_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
6326594249SQin Michael Li 
6426594249SQin Michael Li static struct modldrv urtw_modldrv = {
6526594249SQin Michael Li 	&mod_driverops,		/* Type of module.  This one is a driver */
66dfa03ef6SQin Michael Li 	"RTL8187L/B driver v1.2",	/* short description */
6726594249SQin Michael Li 	&urtw_dev_ops		/* driver specific ops */
6826594249SQin Michael Li };
6926594249SQin Michael Li 
7026594249SQin Michael Li static struct modlinkage modlinkage = {
7126594249SQin Michael Li 	MODREV_1,
7226594249SQin Michael Li 	(void *)&urtw_modldrv,
7326594249SQin Michael Li 	NULL
7426594249SQin Michael Li };
7526594249SQin Michael Li 
7626594249SQin Michael Li static int	urtw_m_stat(void *,  uint_t, uint64_t *);
7726594249SQin Michael Li static int	urtw_m_start(void *);
7826594249SQin Michael Li static void	urtw_m_stop(void *);
7926594249SQin Michael Li static int	urtw_m_promisc(void *, boolean_t);
8026594249SQin Michael Li static int	urtw_m_multicst(void *, boolean_t, const uint8_t *);
8126594249SQin Michael Li static int	urtw_m_unicst(void *, const uint8_t *);
8226594249SQin Michael Li static mblk_t	*urtw_m_tx(void *, mblk_t *);
8326594249SQin Michael Li static void	urtw_m_ioctl(void *, queue_t *, mblk_t *);
8426594249SQin Michael Li static int	urtw_m_setprop(void *, const char *, mac_prop_id_t,
8526594249SQin Michael Li     uint_t, const void *);
86dfa03ef6SQin Michael Li static int	urtw_m_getprop(void *, const char *, mac_prop_id_t,
87*0dc2366fSVenugopal Iyer     uint_t, void *);
88*0dc2366fSVenugopal Iyer static void	urtw_m_propinfo(void *, const char *, mac_prop_id_t,
89*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
9026594249SQin Michael Li 
9126594249SQin Michael Li static mac_callbacks_t urtw_m_callbacks = {
92*0dc2366fSVenugopal Iyer 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
9326594249SQin Michael Li 	urtw_m_stat,
9426594249SQin Michael Li 	urtw_m_start,
9526594249SQin Michael Li 	urtw_m_stop,
9626594249SQin Michael Li 	urtw_m_promisc,
9726594249SQin Michael Li 	urtw_m_multicst,
9826594249SQin Michael Li 	urtw_m_unicst,
9926594249SQin Michael Li 	urtw_m_tx,
100*0dc2366fSVenugopal Iyer 	NULL,
10126594249SQin Michael Li 	urtw_m_ioctl,
10226594249SQin Michael Li 	NULL,
10326594249SQin Michael Li 	NULL,
10426594249SQin Michael Li 	NULL,
10526594249SQin Michael Li 	urtw_m_setprop,
106*0dc2366fSVenugopal Iyer 	urtw_m_getprop,
107*0dc2366fSVenugopal Iyer 	urtw_m_propinfo
10826594249SQin Michael Li };
10926594249SQin Michael Li 
11026594249SQin Michael Li static int  urtw_tx_start(struct urtw_softc *, mblk_t *, int);
11126594249SQin Michael Li static int  urtw_rx_start(struct urtw_softc *);
11226594249SQin Michael Li 
11326594249SQin Michael Li 
11426594249SQin Michael Li /*
115dfa03ef6SQin Michael Li  * Supported rates for 802.11b/g modes (in 500Kbps unit).
11626594249SQin Michael Li  */
11726594249SQin Michael Li static const struct ieee80211_rateset urtw_rateset_11b =
11826594249SQin Michael Li 	{ 4, { 2, 4, 11, 22 } };
11926594249SQin Michael Li 
12026594249SQin Michael Li static const struct ieee80211_rateset urtw_rateset_11g =
12126594249SQin Michael Li 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
12226594249SQin Michael Li 
123dfa03ef6SQin Michael Li #define	USB_VENDOR_DICKSMITH	0x1371		/* Dick Smith Electronics */
124dfa03ef6SQin Michael Li #define	USB_VENDOR_LOGITEC	0x0789		/* Logitec */
125dfa03ef6SQin Michael Li #define	USB_VENDOR_NETGEAR	0x0846		/* BayNETGEAR */
126dfa03ef6SQin Michael Li #define	USB_VENDOR_REALTEK	0x0bda		/* Realtek */
127dfa03ef6SQin Michael Li #define	USB_VENDOR_SPHAIRON	0x114b		/* Sphairon Access Systems */
128dfa03ef6SQin Michael Li #define	USB_VENDOR_SURECOM	0x0769		/* Surecom Technology */
129dfa03ef6SQin Michael Li #define	USB_VENDOR_BELKIN	0x050d		/* Belkin Components */
130dfa03ef6SQin Michael Li #define	USB_VENDOR_SITECOMEU	0x0df6		/* Sitecom Europe */
131dfa03ef6SQin Michael Li 
132dfa03ef6SQin Michael Li #define	USB_PRODUCT_SPHAIRON_RTL8187	0x0150		/* RTL8187 */
133dfa03ef6SQin Michael Li #define	USB_PRODUCT_DICKSMITH_RTL8187	0x9401		/* RTL8187 */
134dfa03ef6SQin Michael Li #define	USB_PRODUCT_LOGITEC_RTL8187	0x010c		/* RTL8187 */
135dfa03ef6SQin Michael Li #define	USB_PRODUCT_REALTEK_RTL8187	0x8187		/* RTL8187 */
136dfa03ef6SQin Michael Li #define	USB_PRODUCT_NETGEAR_WG111V2	0x6a00		/* WG111v2 */
137dfa03ef6SQin Michael Li #define	USB_PRODUCT_SURECOM_EP9001G2A	0x11f2		/* EP-9001-G rev 2A */
138dfa03ef6SQin Michael Li #define	USB_PRODUCT_BELKIN_F5D7050E	0x705e		/* F5D705E 54g */
139dfa03ef6SQin Michael Li #define	USB_PRODUCT_NETGEAR_WG111V3	0x4260		/* WG111v3 */
140dfa03ef6SQin Michael Li #define	USB_PRODUCT_REALTEK_RTL8187B_0	0x8189		/* RTL8187B */
141dfa03ef6SQin Michael Li #define	USB_PRODUCT_REALTEK_RTL8187B_1	0x8197		/* RTL8187B */
142dfa03ef6SQin Michael Li #define	USB_PRODUCT_REALTEK_RTL8187B_2	0x8198		/* RTL8187B */
143dfa03ef6SQin Michael Li #define	USB_PRODUCT_SITECOMEU_WL168	0x0028		/* WL-168 */
144dfa03ef6SQin Michael Li 
145dfa03ef6SQin Michael Li #define	USB_PRODUCT_ANY	0xffff
146dfa03ef6SQin Michael Li 
147dfa03ef6SQin Michael Li struct usb_devno {
148dfa03ef6SQin Michael Li 	uint16_t v;
149dfa03ef6SQin Michael Li 	uint16_t p;
150dfa03ef6SQin Michael Li };
151dfa03ef6SQin Michael Li 
152dfa03ef6SQin Michael Li /*
153dfa03ef6SQin Michael Li  * Recognized device vendors/products.
154dfa03ef6SQin Michael Li  */
155dfa03ef6SQin Michael Li static struct urtw_type {
156dfa03ef6SQin Michael Li 	struct usb_devno	dev;
157dfa03ef6SQin Michael Li 	uint8_t			rev;
158dfa03ef6SQin Michael Li } urtw_devs[] = {
159dfa03ef6SQin Michael Li #define	URTW_DEV_RTL8187(v, p)	\
160dfa03ef6SQin Michael Li 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187 }
161dfa03ef6SQin Michael Li #define	URTW_DEV_RTL8187B(v, p)	\
162dfa03ef6SQin Michael Li 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187B }
163dfa03ef6SQin Michael Li 	/* Realtek RTL8187 devices. */
164dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(DICKSMITH,	RTL8187),
165dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(LOGITEC,	RTL8187),
166dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(NETGEAR,	WG111V2),
167dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(REALTEK,	RTL8187),
168dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(SPHAIRON,	RTL8187),
169dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187(SURECOM,	EP9001G2A),
170dfa03ef6SQin Michael Li 	/* Realtek RTL8187B devices. */
171dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(BELKIN,	F5D7050E),
172dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(NETGEAR,	WG111V3),
173dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_0),
174dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_1),
175dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_2),
176dfa03ef6SQin Michael Li 	URTW_DEV_RTL8187B(SITECOMEU,	WL168)
177dfa03ef6SQin Michael Li #undef	URTW_DEV_RTL8187
178dfa03ef6SQin Michael Li #undef	URTW_DEV_RTL8187B
179dfa03ef6SQin Michael Li };
180dfa03ef6SQin Michael Li 
181dfa03ef6SQin Michael Li /*
182dfa03ef6SQin Michael Li  * Search for a vendor/product pair in an array.  The item size is
183dfa03ef6SQin Michael Li  * given as an argument.
184dfa03ef6SQin Michael Li  */
185dfa03ef6SQin Michael Li struct urtw_type *
usb_match_device(struct urtw_type * tbl,uint32_t nentries,uint16_t vendor,uint16_t product)186dfa03ef6SQin Michael Li usb_match_device(struct urtw_type *tbl, uint32_t nentries,
187dfa03ef6SQin Michael Li 	uint16_t vendor, uint16_t product)
188dfa03ef6SQin Michael Li {
189dfa03ef6SQin Michael Li 	while (nentries-- > 0) {
190dfa03ef6SQin Michael Li 		uint16_t tproduct = tbl[nentries].dev.p;
191dfa03ef6SQin Michael Li 		if (tbl[nentries].dev.v == vendor &&
192dfa03ef6SQin Michael Li 		    (tproduct == product || tproduct == USB_PRODUCT_ANY))
193dfa03ef6SQin Michael Li 		return (&tbl[nentries]);
194dfa03ef6SQin Michael Li 	}
195dfa03ef6SQin Michael Li 	return (NULL);
196dfa03ef6SQin Michael Li }
197dfa03ef6SQin Michael Li 
198dfa03ef6SQin Michael Li #define	usb_lookup(tbl, vendor, product) \
199dfa03ef6SQin Michael Li 	usb_match_device(tbl, sizeof (tbl) / sizeof ((tbl)[0]), \
200dfa03ef6SQin Michael Li 		(vendor), (product))
201dfa03ef6SQin Michael Li 
202dfa03ef6SQin Michael Li #define	urtw_lookup(v, p)	(usb_lookup(urtw_devs, v, p))
20326594249SQin Michael Li 
20426594249SQin Michael Li struct urtw_pair {
20526594249SQin Michael Li 	uint32_t	reg;
20626594249SQin Michael Li 	uint32_t	val;
20726594249SQin Michael Li };
20826594249SQin Michael Li 
209dfa03ef6SQin Michael Li struct urtw_pair_idx {
210dfa03ef6SQin Michael Li 	uint8_t		reg;
211dfa03ef6SQin Michael Li 	uint8_t		val;
212dfa03ef6SQin Michael Li 	uint8_t		idx;
213dfa03ef6SQin Michael Li };
214dfa03ef6SQin Michael Li 
215dfa03ef6SQin Michael Li static struct urtw_pair_idx urtw_8187b_regtbl[] = {
216dfa03ef6SQin Michael Li 	{ 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
217dfa03ef6SQin Michael Li 	{ 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
218dfa03ef6SQin Michael Li 	{ 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
219dfa03ef6SQin Michael Li 	{ 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
220dfa03ef6SQin Michael Li 	{ 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
221dfa03ef6SQin Michael Li 	{ 0xff, 0x00, 0 },
222dfa03ef6SQin Michael Li 
223dfa03ef6SQin Michael Li 	{ 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 }, { 0x5a, 0x4b, 1 },
224dfa03ef6SQin Michael Li 	{ 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 }, { 0x61, 0x09, 1 },
225dfa03ef6SQin Michael Li 	{ 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 }, { 0xce, 0x0f, 1 },
226dfa03ef6SQin Michael Li 	{ 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 }, { 0xe1, 0x0f, 1 },
227dfa03ef6SQin Michael Li 	{ 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 }, { 0xf1, 0x01, 1 },
228dfa03ef6SQin Michael Li 	{ 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 }, { 0xf4, 0x04, 1 },
229dfa03ef6SQin Michael Li 	{ 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 }, { 0xf7, 0x07, 1 },
230dfa03ef6SQin Michael Li 	{ 0xf8, 0x08, 1 },
231dfa03ef6SQin Michael Li 
232dfa03ef6SQin Michael Li 	{ 0x4e, 0x00, 2 }, { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 },
233dfa03ef6SQin Michael Li 	{ 0x22, 0x68, 2 }, { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 },
234dfa03ef6SQin Michael Li 	{ 0x25, 0x7d, 2 }, { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 },
235dfa03ef6SQin Michael Li 	{ 0x4d, 0x08, 2 }, { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 },
236dfa03ef6SQin Michael Li 	{ 0x52, 0x04, 2 }, { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 },
237dfa03ef6SQin Michael Li 	{ 0x55, 0x23, 2 }, { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 },
238dfa03ef6SQin Michael Li 	{ 0x58, 0x08, 2 }, { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 },
239dfa03ef6SQin Michael Li 	{ 0x5b, 0x08, 2 }, { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 },
240dfa03ef6SQin Michael Li 	{ 0x62, 0x08, 2 }, { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 },
241dfa03ef6SQin Michael Li 	{ 0x72, 0x56, 2 }, { 0x73, 0x9a, 2 },
242dfa03ef6SQin Michael Li 
243dfa03ef6SQin Michael Li 	{ 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 }, { 0x5b, 0x40, 0 },
244dfa03ef6SQin Michael Li 	{ 0x84, 0x88, 0 }, { 0x85, 0x24, 0 }, { 0x88, 0x54, 0 },
245dfa03ef6SQin Michael Li 	{ 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 }, { 0x8d, 0x00, 0 },
246dfa03ef6SQin Michael Li 	{ 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 }, { 0x96, 0x00, 0 },
247dfa03ef6SQin Michael Li 	{ 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 }, { 0x9f, 0x10, 0 },
248dfa03ef6SQin Michael Li 	{ 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 }, { 0xdb, 0x00, 0 },
249dfa03ef6SQin Michael Li 	{ 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
250dfa03ef6SQin Michael Li 
251dfa03ef6SQin Michael Li 	{ 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
252dfa03ef6SQin Michael Li 	{ 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
253dfa03ef6SQin Michael Li };
254dfa03ef6SQin Michael Li 
25526594249SQin Michael Li static uint8_t urtw_8225_agc[] = {
25626594249SQin Michael Li 	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
25726594249SQin Michael Li 	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
25826594249SQin Michael Li 	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
25926594249SQin Michael Li 	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
26026594249SQin Michael Li 	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
26126594249SQin Michael Li 	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
26226594249SQin Michael Li 	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
26326594249SQin Michael Li 	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
26426594249SQin Michael Li 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
26526594249SQin Michael Li 	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
26626594249SQin Michael Li 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
26726594249SQin Michael Li 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
26826594249SQin Michael Li };
26926594249SQin Michael Li 
270dfa03ef6SQin Michael Li static uint8_t urtw_8225v2_agc[] = {
271dfa03ef6SQin Michael Li 	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57,
272dfa03ef6SQin Michael Li 	0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x47,
273dfa03ef6SQin Michael Li 	0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
274dfa03ef6SQin Michael Li 	0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27,
275dfa03ef6SQin Michael Li 	0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17,
276dfa03ef6SQin Michael Li 	0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
277dfa03ef6SQin Michael Li 	0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
278dfa03ef6SQin Michael Li 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
279dfa03ef6SQin Michael Li 	0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
280dfa03ef6SQin Michael Li 	0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
281dfa03ef6SQin Michael Li 	0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
282dfa03ef6SQin Michael Li 	0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
283dfa03ef6SQin Michael Li 	0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f,
284dfa03ef6SQin Michael Li 	0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
285dfa03ef6SQin Michael Li 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
286dfa03ef6SQin Michael Li 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
287dfa03ef6SQin Michael Li };
288dfa03ef6SQin Michael Li 
289dfa03ef6SQin Michael Li static uint8_t urtw_8225v2_ofdm[] = {
290dfa03ef6SQin Michael Li 	0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
291dfa03ef6SQin Michael Li 	0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
292dfa03ef6SQin Michael Li 	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
293dfa03ef6SQin Michael Li 	0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
294dfa03ef6SQin Michael Li 	0x0a, 0xe1, 0x2c, 0x8a, 0x86, 0x83, 0x34, 0x0f,
295dfa03ef6SQin Michael Li 	0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
296dfa03ef6SQin Michael Li 	0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
297dfa03ef6SQin Michael Li 	0x6d, 0x3c, 0xfb, 0x07
298dfa03ef6SQin Michael Li };
299dfa03ef6SQin Michael Li 
30026594249SQin Michael Li static uint32_t urtw_8225_channel[] = {
30126594249SQin Michael Li 	0x0000,		/* dummy channel 0  */
30226594249SQin Michael Li 	0x085c,		/* 1  */
30326594249SQin Michael Li 	0x08dc,		/* 2  */
30426594249SQin Michael Li 	0x095c,		/* 3  */
30526594249SQin Michael Li 	0x09dc,		/* 4  */
30626594249SQin Michael Li 	0x0a5c,		/* 5  */
30726594249SQin Michael Li 	0x0adc,		/* 6  */
30826594249SQin Michael Li 	0x0b5c,		/* 7  */
30926594249SQin Michael Li 	0x0bdc,		/* 8  */
31026594249SQin Michael Li 	0x0c5c,		/* 9  */
31126594249SQin Michael Li 	0x0cdc,		/* 10  */
31226594249SQin Michael Li 	0x0d5c,		/* 11  */
31326594249SQin Michael Li 	0x0ddc,		/* 12  */
31426594249SQin Michael Li 	0x0e5c,		/* 13  */
31526594249SQin Michael Li 	0x0f72,		/* 14  */
31626594249SQin Michael Li };
31726594249SQin Michael Li 
31826594249SQin Michael Li static uint8_t urtw_8225_gain[] = {
31926594249SQin Michael Li 	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm  */
32026594249SQin Michael Li 	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm  */
32126594249SQin Michael Li 	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm  */
32226594249SQin Michael Li 	0x33, 0x80, 0x79, 0xc5,		/* -78dbm  */
32326594249SQin Michael Li 	0x43, 0x78, 0x76, 0xc5,		/* -74dbm  */
32426594249SQin Michael Li 	0x53, 0x60, 0x73, 0xc5,		/* -70dbm  */
32526594249SQin Michael Li 	0x63, 0x58, 0x70, 0xc5,		/* -66dbm  */
32626594249SQin Michael Li };
32726594249SQin Michael Li 
32826594249SQin Michael Li static struct urtw_pair urtw_8225_rf_part1[] = {
32926594249SQin Michael Li 	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
33026594249SQin Michael Li 	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
33126594249SQin Michael Li 	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
33226594249SQin Michael Li 	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
33326594249SQin Michael Li };
33426594249SQin Michael Li 
33526594249SQin Michael Li static struct urtw_pair urtw_8225_rf_part2[] = {
33626594249SQin Michael Li 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
33726594249SQin Michael Li 	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
33826594249SQin Michael Li 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
33926594249SQin Michael Li 	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
34026594249SQin Michael Li 	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
34126594249SQin Michael Li 	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
34226594249SQin Michael Li 	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
34326594249SQin Michael Li 	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
34426594249SQin Michael Li 	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
34526594249SQin Michael Li 	{ 0x27, 0x88 }
34626594249SQin Michael Li };
34726594249SQin Michael Li 
34826594249SQin Michael Li static struct urtw_pair urtw_8225_rf_part3[] = {
34926594249SQin Michael Li 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
35026594249SQin Michael Li 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
35126594249SQin Michael Li 	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
35226594249SQin Michael Li 	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
35326594249SQin Michael Li 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
35426594249SQin Michael Li 	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
35526594249SQin Michael Li 	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
35626594249SQin Michael Li };
35726594249SQin Michael Li 
35826594249SQin Michael Li static uint16_t urtw_8225_rxgain[] = {
35926594249SQin Michael Li 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
36026594249SQin Michael Li 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
36126594249SQin Michael Li 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
36226594249SQin Michael Li 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
36326594249SQin Michael Li 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
36426594249SQin Michael Li 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
36526594249SQin Michael Li 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
36626594249SQin Michael Li 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
36726594249SQin Michael Li 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
36826594249SQin Michael Li 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
36926594249SQin Michael Li 	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
37026594249SQin Michael Li 	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
37126594249SQin Michael Li };
37226594249SQin Michael Li 
37326594249SQin Michael Li static uint8_t urtw_8225_threshold[] = {
37426594249SQin Michael Li 	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
37526594249SQin Michael Li };
37626594249SQin Michael Li 
37726594249SQin Michael Li static uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
37826594249SQin Michael Li 	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
37926594249SQin Michael Li };
38026594249SQin Michael Li 
38126594249SQin Michael Li static uint8_t urtw_8225_txpwr_cck[] = {
38226594249SQin Michael Li 	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
38326594249SQin Michael Li 	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
38426594249SQin Michael Li 	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
38526594249SQin Michael Li 	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
38626594249SQin Michael Li 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
38726594249SQin Michael Li 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
38826594249SQin Michael Li };
38926594249SQin Michael Li 
39026594249SQin Michael Li static uint8_t urtw_8225_txpwr_cck_ch14[] = {
39126594249SQin Michael Li 	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
39226594249SQin Michael Li 	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
39326594249SQin Michael Li 	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
39426594249SQin Michael Li 	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
39526594249SQin Michael Li 	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
39626594249SQin Michael Li 	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
39726594249SQin Michael Li };
39826594249SQin Michael Li 
39926594249SQin Michael Li static uint8_t urtw_8225_txpwr_ofdm[] = {
40026594249SQin Michael Li 	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
40126594249SQin Michael Li };
40226594249SQin Michael Li 
40326594249SQin Michael Li static uint8_t urtw_8225v2_gain_bg[] = {
40426594249SQin Michael Li 	0x23, 0x15, 0xa5,		/* -82-1dbm  */
40526594249SQin Michael Li 	0x23, 0x15, 0xb5,		/* -82-2dbm  */
40626594249SQin Michael Li 	0x23, 0x15, 0xc5,		/* -82-3dbm  */
40726594249SQin Michael Li 	0x33, 0x15, 0xc5,		/* -78dbm  */
40826594249SQin Michael Li 	0x43, 0x15, 0xc5,		/* -74dbm  */
40926594249SQin Michael Li 	0x53, 0x15, 0xc5,		/* -70dbm  */
41026594249SQin Michael Li 	0x63, 0x15, 0xc5,		/* -66dbm  */
41126594249SQin Michael Li };
41226594249SQin Michael Li 
41326594249SQin Michael Li static struct urtw_pair urtw_8225v2_rf_part1[] = {
41426594249SQin Michael Li 	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
41526594249SQin Michael Li 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
41626594249SQin Michael Li 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
41726594249SQin Michael Li 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
41826594249SQin Michael Li };
41926594249SQin Michael Li 
42026594249SQin Michael Li static struct urtw_pair urtw_8225v2_rf_part2[] = {
42126594249SQin Michael Li 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
42226594249SQin Michael Li 	{ 0x04, 0x00 },	{ 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
42326594249SQin Michael Li 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
42426594249SQin Michael Li 	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
42526594249SQin Michael Li 	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
42626594249SQin Michael Li 	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
42726594249SQin Michael Li 	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
42826594249SQin Michael Li 	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
42926594249SQin Michael Li 	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
43026594249SQin Michael Li 	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
43126594249SQin Michael Li };
43226594249SQin Michael Li 
43326594249SQin Michael Li static struct urtw_pair urtw_8225v2_rf_part3[] = {
43426594249SQin Michael Li 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
43526594249SQin Michael Li 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
43626594249SQin Michael Li 	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
43726594249SQin Michael Li 	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
43826594249SQin Michael Li 	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
43926594249SQin Michael Li 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
44026594249SQin Michael Li 	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
44126594249SQin Michael Li 	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
44226594249SQin Michael Li };
44326594249SQin Michael Li 
44426594249SQin Michael Li static uint16_t urtw_8225v2_rxgain[] = {
445dfa03ef6SQin Michael Li 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
446dfa03ef6SQin Michael Li 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
447dfa03ef6SQin Michael Li 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
448dfa03ef6SQin Michael Li 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
449dfa03ef6SQin Michael Li 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
450dfa03ef6SQin Michael Li 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
451dfa03ef6SQin Michael Li 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
452dfa03ef6SQin Michael Li 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
453dfa03ef6SQin Michael Li 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
454dfa03ef6SQin Michael Li 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
45526594249SQin Michael Li 	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
45626594249SQin Michael Li 	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
45726594249SQin Michael Li };
45826594249SQin Michael Li 
45926594249SQin Michael Li static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
46026594249SQin Michael Li 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
46126594249SQin Michael Li 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
46226594249SQin Michael Li 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
46326594249SQin Michael Li 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
46426594249SQin Michael Li 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
46526594249SQin Michael Li 	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
46626594249SQin Michael Li };
46726594249SQin Michael Li 
46826594249SQin Michael Li static uint8_t urtw_8225v2_txpwr_cck[] = {
469dfa03ef6SQin Michael Li 	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
470dfa03ef6SQin Michael Li 	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
471dfa03ef6SQin Michael Li 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
472dfa03ef6SQin Michael Li 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
47326594249SQin Michael Li };
47426594249SQin Michael Li 
47526594249SQin Michael Li static uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
476dfa03ef6SQin Michael Li 	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
477dfa03ef6SQin Michael Li 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
478dfa03ef6SQin Michael Li 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
479dfa03ef6SQin Michael Li 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
480dfa03ef6SQin Michael Li };
481dfa03ef6SQin Michael Li 
482dfa03ef6SQin Michael Li static struct urtw_pair urtw_8225v2_b_rf[] = {
483dfa03ef6SQin Michael Li 	{ 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
484dfa03ef6SQin Michael Li 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
485dfa03ef6SQin Michael Li 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
486dfa03ef6SQin Michael Li 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 },
487dfa03ef6SQin Michael Li 	{ 0x00, 0x01b7 }
48826594249SQin Michael Li };
48926594249SQin Michael Li 
49026594249SQin Michael Li static struct urtw_pair urtw_ratetable[] = {
49126594249SQin Michael Li 	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
49226594249SQin Michael Li 	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
49326594249SQin Michael Li 	{ 96, 10 }, { 108, 11 }
49426594249SQin Michael Li };
49526594249SQin Michael Li 
496dfa03ef6SQin Michael Li static int		urtw_8187_init(void *);
49726594249SQin Michael Li static void		urtw_stop(struct urtw_softc *);
49826594249SQin Michael Li static int		urtw_set_channel(struct urtw_softc *);
49926594249SQin Michael Li static void
50026594249SQin Michael Li urtw_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
50126594249SQin Michael Li static int
50226594249SQin Michael Li urtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
503dfa03ef6SQin Michael Li static usbd_status
504dfa03ef6SQin Michael Li urtw_read8_c(struct urtw_softc *, int, uint8_t *, uint8_t);
505dfa03ef6SQin Michael Li static usbd_status
506dfa03ef6SQin Michael Li urtw_read16_c(struct urtw_softc *, int, uint16_t *, uint8_t);
507dfa03ef6SQin Michael Li static usbd_status
508dfa03ef6SQin Michael Li urtw_read32_c(struct urtw_softc *, int, uint32_t *, uint8_t);
509dfa03ef6SQin Michael Li static usbd_status
510dfa03ef6SQin Michael Li urtw_write8_c(struct urtw_softc *, int, uint8_t, uint8_t);
511dfa03ef6SQin Michael Li static usbd_status
512dfa03ef6SQin Michael Li urtw_write16_c(struct urtw_softc *, int, uint16_t, uint8_t);
513dfa03ef6SQin Michael Li static usbd_status
514dfa03ef6SQin Michael Li urtw_write32_c(struct urtw_softc *, int, uint32_t, uint8_t);
51526594249SQin Michael Li static usbd_status	urtw_eprom_cs(struct urtw_softc *, int);
51626594249SQin Michael Li static usbd_status	urtw_eprom_ck(struct urtw_softc *);
51726594249SQin Michael Li static usbd_status	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
51826594249SQin Michael Li 			    int);
51926594249SQin Michael Li static usbd_status	urtw_eprom_read32(struct urtw_softc *, uint32_t,
52026594249SQin Michael Li 			    uint32_t *);
52126594249SQin Michael Li static usbd_status	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
52226594249SQin Michael Li static usbd_status	urtw_eprom_writebit(struct urtw_softc *, int16_t);
52326594249SQin Michael Li static usbd_status	urtw_get_macaddr(struct urtw_softc *);
52426594249SQin Michael Li static usbd_status	urtw_get_txpwr(struct urtw_softc *);
52526594249SQin Michael Li static usbd_status	urtw_get_rfchip(struct urtw_softc *);
52626594249SQin Michael Li static usbd_status	urtw_led_init(struct urtw_softc *);
52726594249SQin Michael Li static usbd_status
52826594249SQin Michael Li urtw_8225_read(struct urtw_softc *, uint8_t, uint32_t *);
529dfa03ef6SQin Michael Li static usbd_status	urtw_8225_rf_init(struct urtw_rf *);
530dfa03ef6SQin Michael Li static usbd_status	urtw_8225_rf_set_chan(struct urtw_rf *, int);
531dfa03ef6SQin Michael Li static usbd_status	urtw_8225_rf_set_sens(struct urtw_rf *);
532dfa03ef6SQin Michael Li static usbd_status	urtw_8225v2_rf_init(struct urtw_rf *);
533dfa03ef6SQin Michael Li static usbd_status	urtw_8225v2_rf_set_chan(struct urtw_rf *, int);
53426594249SQin Michael Li static usbd_status	urtw_open_pipes(struct urtw_softc *);
53526594249SQin Michael Li static void urtw_close_pipes(struct urtw_softc *);
53626594249SQin Michael Li static void urtw_led_launch(void *);
53726594249SQin Michael Li 
538dfa03ef6SQin Michael Li static void	urtw_8187b_update_wmm(struct urtw_softc *);
539dfa03ef6SQin Michael Li static usbd_status	urtw_8187b_reset(struct urtw_softc *);
540dfa03ef6SQin Michael Li static int	urtw_8187b_init(void *);
541dfa03ef6SQin Michael Li static void	urtw_8225v2_b_config_mac(struct urtw_softc *);
542dfa03ef6SQin Michael Li static void	urtw_8225v2_b_init_rfe(struct urtw_softc *);
543dfa03ef6SQin Michael Li static usbd_status	urtw_8225v2_b_update_chan(struct urtw_softc *);
544dfa03ef6SQin Michael Li static usbd_status	urtw_8225v2_b_rf_init(struct urtw_rf *);
545dfa03ef6SQin Michael Li static usbd_status	urtw_8225v2_b_rf_set_chan(struct urtw_rf *, int);
546dfa03ef6SQin Michael Li static void urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *, int);
547dfa03ef6SQin Michael Li 
54826594249SQin Michael Li #ifdef DEBUG
54926594249SQin Michael Li 
55026594249SQin Michael Li #define	URTW_DEBUG_XMIT		0x00000001
55126594249SQin Michael Li #define	URTW_DEBUG_RECV		0x00000002
55226594249SQin Michael Li #define	URTW_DEBUG_LED 		0x00000004
55326594249SQin Michael Li #define	URTW_DEBUG_GLD 		0x00000008
55426594249SQin Michael Li #define	URTW_DEBUG_RF		0x00000010
55526594249SQin Michael Li #define	URTW_DEBUG_ATTACH 	0x00000020
55626594249SQin Michael Li #define	URTW_DEBUG_ACTIVE 	0x00000040
55726594249SQin Michael Li #define	URTW_DEBUG_HWTYPE	0x00000080
558dfa03ef6SQin Michael Li #define	URTW_DEBUG_DEVREQ	0x00000100
55926594249SQin Michael Li #define	URTW_DEBUG_HOTPLUG	0x00000200
560dfa03ef6SQin Michael Li #define	URTW_DEBUG_STATE	0x00000400
56126594249SQin Michael Li #define	URTW_DEBUG_TX_PROC	0x00000800
56226594249SQin Michael Li #define	URTW_DEBUG_RX_PROC 	0x00001000
56326594249SQin Michael Li #define	URTW_DEBUG_EEPROM	0x00002000
56426594249SQin Michael Li #define	URTW_DEBUG_RESET	0x00004000
56526594249SQin Michael Li #define	URTW_DEBUG_ANY		0xffffffff
56626594249SQin Michael Li 
56726594249SQin Michael Li uint32_t urtw8187_dbg_flags = 0;
56826594249SQin Michael Li static void
urtw8187_dbg(dev_info_t * dip,int level,const char * fmt,...)56926594249SQin Michael Li urtw8187_dbg(dev_info_t *dip, int level, const char *fmt, ...)
57026594249SQin Michael Li {
57126594249SQin Michael Li 	char		msg_buffer[255];
57226594249SQin Michael Li 	va_list	ap;
57326594249SQin Michael Li 
57426594249SQin Michael Li 	if (dip == NULL) {
57526594249SQin Michael Li 		return;
57626594249SQin Michael Li 	}
57726594249SQin Michael Li 
57826594249SQin Michael Li 	va_start(ap, fmt);
57926594249SQin Michael Li 	(void) vsprintf(msg_buffer, fmt, ap);
58026594249SQin Michael Li 	cmn_err(level, "%s%d: %s", ddi_get_name(dip),
58126594249SQin Michael Li 	    ddi_get_instance(dip), msg_buffer);
58226594249SQin Michael Li 	va_end(ap);
58326594249SQin Michael Li }
58426594249SQin Michael Li 
58526594249SQin Michael Li #define	URTW8187_DBG(l, x) do {\
58626594249SQin Michael Li 	_NOTE(CONSTANTCONDITION) \
58726594249SQin Michael Li 	if ((l) & urtw8187_dbg_flags) \
58826594249SQin Michael Li 		urtw8187_dbg x;\
58926594249SQin Michael Li 	_NOTE(CONSTANTCONDITION) \
59026594249SQin Michael Li } while (0)
59126594249SQin Michael Li #else
59226594249SQin Michael Li #define	URTW8187_DBG(l, x)
59326594249SQin Michael Li #endif
59426594249SQin Michael Li 
59526594249SQin Michael Li static usbd_status
urtw_led_init(struct urtw_softc * sc)59626594249SQin Michael Li urtw_led_init(struct urtw_softc *sc)
59726594249SQin Michael Li {
59826594249SQin Michael Li 	uint32_t rev;
59926594249SQin Michael Li 	usbd_status error;
60026594249SQin Michael Li 
601dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_PSR, &sc->sc_psr, 0))
60226594249SQin Michael Li 		goto fail;
60326594249SQin Michael Li 	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
60426594249SQin Michael Li 	if (error != 0)
60526594249SQin Michael Li 		goto fail;
60626594249SQin Michael Li 
60726594249SQin Michael Li 	switch (rev & URTW_EPROM_CID_MASK) {
60826594249SQin Michael Li 	case URTW_EPROM_CID_ALPHA0:
60926594249SQin Michael Li 		sc->sc_strategy = URTW_SW_LED_MODE1;
61026594249SQin Michael Li 		break;
61126594249SQin Michael Li 	case URTW_EPROM_CID_SERCOMM_PS:
61226594249SQin Michael Li 		sc->sc_strategy = URTW_SW_LED_MODE3;
61326594249SQin Michael Li 		break;
61426594249SQin Michael Li 	case URTW_EPROM_CID_HW_LED:
61526594249SQin Michael Li 		sc->sc_strategy = URTW_HW_LED;
61626594249SQin Michael Li 		break;
61726594249SQin Michael Li 	case URTW_EPROM_CID_RSVD0:
61826594249SQin Michael Li 	case URTW_EPROM_CID_RSVD1:
61926594249SQin Michael Li 	default:
62026594249SQin Michael Li 		sc->sc_strategy = URTW_SW_LED_MODE0;
62126594249SQin Michael Li 		break;
62226594249SQin Michael Li 	}
62326594249SQin Michael Li 
62426594249SQin Michael Li 	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
62526594249SQin Michael Li 
62626594249SQin Michael Li fail:
62726594249SQin Michael Li 	return (error);
62826594249SQin Michael Li }
62926594249SQin Michael Li 
63026594249SQin Michael Li static usbd_status
urtw_8225_write_s16(struct urtw_softc * sc,uint8_t addr,int index,uint16_t * data)63126594249SQin Michael Li urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
63226594249SQin Michael Li     uint16_t *data)
63326594249SQin Michael Li {
63426594249SQin Michael Li 	usb_ctrl_setup_t req;
63526594249SQin Michael Li 	usb_cr_t cr;
63626594249SQin Michael Li 	usb_cb_flags_t cf;
63726594249SQin Michael Li 	mblk_t *mp = 0;
63826594249SQin Michael Li 	uint16_t data16;
63926594249SQin Michael Li 	usbd_status error;
64026594249SQin Michael Li 
64126594249SQin Michael Li 	data16 = *data;
64226594249SQin Michael Li 	bzero(&req, sizeof (req));
64326594249SQin Michael Li 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
64426594249SQin Michael Li 	req.bRequest = URTW_8187_SETREGS_REQ;
64526594249SQin Michael Li 	req.wValue = addr;
64626594249SQin Michael Li 	req.wIndex = (uint16_t)index;
64726594249SQin Michael Li 	req.wLength = sizeof (uint16_t);
64826594249SQin Michael Li 	req.attrs = USB_ATTRS_NONE;
64926594249SQin Michael Li 
65026594249SQin Michael Li 	mp = allocb(sizeof (uint16_t), BPRI_MED);
65126594249SQin Michael Li 	if (mp == 0) {
65226594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_8225_write_s16: allocb failed\n");
65326594249SQin Michael Li 		return (-1);
65426594249SQin Michael Li 	}
65526594249SQin Michael Li 	*(mp->b_rptr) = (data16 & 0x00ff);
65626594249SQin Michael Li 	*(mp->b_rptr + 1) = (data16 & 0xff00) >> 8;
65726594249SQin Michael Li 	mp->b_wptr += sizeof (uint16_t);
65826594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
65926594249SQin Michael Li 	    &cr, &cf, 0);
66026594249SQin Michael Li 	if (error != USB_SUCCESS) {
66126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
66226594249SQin Michael Li 		    "urtw_8225_write_s16: could not set regs:"
66326594249SQin Michael Li 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
66426594249SQin Michael Li 	}
66526594249SQin Michael Li 	if (mp)
66626594249SQin Michael Li 		freemsg(mp);
66726594249SQin Michael Li 	return (error);
66826594249SQin Michael Li 
66926594249SQin Michael Li }
67026594249SQin Michael Li 
67126594249SQin Michael Li static usbd_status
urtw_8225_read(struct urtw_softc * sc,uint8_t addr,uint32_t * data)67226594249SQin Michael Li urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
67326594249SQin Michael Li {
67426594249SQin Michael Li 	int i;
67526594249SQin Michael Li 	int16_t bit;
67626594249SQin Michael Li 	uint8_t rlen = 12, wlen = 6;
67726594249SQin Michael Li 	uint16_t o1, o2, o3, tmp;
67826594249SQin Michael Li 	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
67926594249SQin Michael Li 	uint32_t mask = 0x80000000, value = 0;
68026594249SQin Michael Li 	usbd_status error;
68126594249SQin Michael Li 
682dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &o1, 0))
68326594249SQin Michael Li 		goto fail;
684dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &o2, 0))
68526594249SQin Michael Li 		goto fail;
686dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &o3, 0))
68726594249SQin Michael Li 		goto fail;
688dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2 | 0xf, 0))
68926594249SQin Michael Li 		goto fail;
690dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3 | 0xf, 0))
69126594249SQin Michael Li 		goto fail;
69226594249SQin Michael Li 	o1 &= ~0xf;
69326594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
694dfa03ef6SQin Michael Li 	    o1 | URTW_BB_HOST_BANG_EN, 0))
69526594249SQin Michael Li 		goto fail;
69626594249SQin Michael Li 	DELAY(5);
697dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, o1, 0))
69826594249SQin Michael Li 		goto fail;
69926594249SQin Michael Li 	DELAY(5);
70026594249SQin Michael Li 
70126594249SQin Michael Li 	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
70226594249SQin Michael Li 		bit = ((d2w & mask) != 0) ? 1 : 0;
70326594249SQin Michael Li 
704dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
705dfa03ef6SQin Michael Li 		    bit | o1, 0))
70626594249SQin Michael Li 			goto fail;
70726594249SQin Michael Li 		DELAY(2);
708dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
709dfa03ef6SQin Michael Li 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
71026594249SQin Michael Li 			goto fail;
71126594249SQin Michael Li 		DELAY(2);
712dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
713dfa03ef6SQin Michael Li 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
71426594249SQin Michael Li 			goto fail;
71526594249SQin Michael Li 		DELAY(2);
71626594249SQin Michael Li 		mask = mask >> 1;
71726594249SQin Michael Li 		if (i == 2)
71826594249SQin Michael Li 			break;
71926594249SQin Michael Li 		bit = ((d2w & mask) != 0) ? 1 : 0;
720dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
721dfa03ef6SQin Michael Li 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
72226594249SQin Michael Li 			goto fail;
72326594249SQin Michael Li 		DELAY(2);
724dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
725dfa03ef6SQin Michael Li 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
72626594249SQin Michael Li 			goto fail;
72726594249SQin Michael Li 		DELAY(2);
728dfa03ef6SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
729dfa03ef6SQin Michael Li 		    bit | o1, 0))
73026594249SQin Michael Li 			goto fail;
73126594249SQin Michael Li 		DELAY(1);
73226594249SQin Michael Li 	}
73326594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
734dfa03ef6SQin Michael Li 	    bit | o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
73526594249SQin Michael Li 		goto fail;
73626594249SQin Michael Li 	DELAY(2);
73726594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
738dfa03ef6SQin Michael Li 	    bit | o1 | URTW_BB_HOST_BANG_RW, 0))
73926594249SQin Michael Li 		goto fail;
74026594249SQin Michael Li 	DELAY(2);
74126594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
742dfa03ef6SQin Michael Li 	    o1 | URTW_BB_HOST_BANG_RW, 0))
74326594249SQin Michael Li 		goto fail;
74426594249SQin Michael Li 	DELAY(2);
74526594249SQin Michael Li 
74626594249SQin Michael Li 	mask = 0x800;
74726594249SQin Michael Li 	for (i = 0; i < rlen; i++, mask = mask >> 1) {
74826594249SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
749dfa03ef6SQin Michael Li 		    o1 | URTW_BB_HOST_BANG_RW, 0))
75026594249SQin Michael Li 			goto fail;
75126594249SQin Michael Li 		DELAY(2);
75226594249SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
753dfa03ef6SQin Michael Li 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
75426594249SQin Michael Li 			goto fail;
75526594249SQin Michael Li 		DELAY(2);
75626594249SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
757dfa03ef6SQin Michael Li 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
75826594249SQin Michael Li 			goto fail;
75926594249SQin Michael Li 		DELAY(2);
76026594249SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
761dfa03ef6SQin Michael Li 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
76226594249SQin Michael Li 			goto fail;
76326594249SQin Michael Li 		DELAY(2);
76426594249SQin Michael Li 
765dfa03ef6SQin Michael Li 		if (error = urtw_read16_c(sc, URTW_RF_PINS_INPUT, &tmp, 0))
76626594249SQin Michael Li 			goto fail;
76726594249SQin Michael Li 		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
76826594249SQin Michael Li 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
769dfa03ef6SQin Michael Li 		    o1 | URTW_BB_HOST_BANG_RW, 0))
77026594249SQin Michael Li 			goto fail;
77126594249SQin Michael Li 		DELAY(2);
77226594249SQin Michael Li 	}
77326594249SQin Michael Li 
77426594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
77526594249SQin Michael Li 	    o1 | URTW_BB_HOST_BANG_EN |
776dfa03ef6SQin Michael Li 	    URTW_BB_HOST_BANG_RW, 0))
77726594249SQin Michael Li 		goto fail;
77826594249SQin Michael Li 	DELAY(2);
77926594249SQin Michael Li 
780dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2, 0))
78126594249SQin Michael Li 		goto fail;
782dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3, 0))
78326594249SQin Michael Li 		goto fail;
784dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x3a0, 0);
78526594249SQin Michael Li 
78626594249SQin Michael Li 	if (data != NULL)
78726594249SQin Michael Li 		*data = value;
78826594249SQin Michael Li fail:
78926594249SQin Michael Li 	return (error);
79026594249SQin Michael Li }
79126594249SQin Michael Li 
79226594249SQin Michael Li static void
urtw_delay_ms(int t)79326594249SQin Michael Li urtw_delay_ms(int t)
79426594249SQin Michael Li {
79526594249SQin Michael Li 	DELAY(t * 1000);
79626594249SQin Michael Li }
79726594249SQin Michael Li 
79826594249SQin Michael Li static usbd_status
urtw_8225_write_c(struct urtw_softc * sc,uint8_t addr,uint16_t data)79926594249SQin Michael Li urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
80026594249SQin Michael Li {
80126594249SQin Michael Li 	uint16_t d80, d82, d84;
80226594249SQin Michael Li 	usbd_status error;
80326594249SQin Michael Li 
804dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &d80, 0))
80526594249SQin Michael Li 		goto fail;
80626594249SQin Michael Li 	d80 &= 0xfff3;
807dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &d82, 0))
80826594249SQin Michael Li 		goto fail;
809dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &d84, 0))
81026594249SQin Michael Li 		goto fail;
81126594249SQin Michael Li 	d84 &= 0xfff0;
81226594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE,
813dfa03ef6SQin Michael Li 	    d82 | 0x0007, 0))
81426594249SQin Michael Li 		goto fail;
81526594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT,
816dfa03ef6SQin Michael Li 	    d84 | 0x0007, 0))
81726594249SQin Michael Li 		goto fail;
81826594249SQin Michael Li 
81926594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
820dfa03ef6SQin Michael Li 	    d80 | URTW_BB_HOST_BANG_EN, 0))
82126594249SQin Michael Li 		goto fail;
822dfa03ef6SQin Michael Li 	urtw_delay_ms(2);
823dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, d80, 0))
82426594249SQin Michael Li 		goto fail;
82526594249SQin Michael Li 
82626594249SQin Michael Li 	error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
82726594249SQin Michael Li 	if (error != 0)
82826594249SQin Michael Li 		goto fail;
82926594249SQin Michael Li 
83026594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
831dfa03ef6SQin Michael Li 	    d80 | URTW_BB_HOST_BANG_EN, 0))
83226594249SQin Michael Li 		goto fail;
83326594249SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
834dfa03ef6SQin Michael Li 	    d80 | URTW_BB_HOST_BANG_EN, 0))
83526594249SQin Michael Li 		goto fail;
836dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, d84, 0);
83726594249SQin Michael Li 	urtw_delay_ms(2);
83826594249SQin Michael Li fail:
83926594249SQin Michael Li 	return (error);
84026594249SQin Michael Li }
84126594249SQin Michael Li 
84226594249SQin Michael Li static usbd_status
urtw_8225_isv2(struct urtw_softc * sc,int * ret)84326594249SQin Michael Li urtw_8225_isv2(struct urtw_softc *sc, int *ret)
84426594249SQin Michael Li {
84526594249SQin Michael Li 	uint32_t data;
84626594249SQin Michael Li 	usbd_status error;
84726594249SQin Michael Li 
84826594249SQin Michael Li 	*ret = 1;
84926594249SQin Michael Li 
850dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x0080, 0))
85126594249SQin Michael Li 		goto fail;
852dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x0080, 0))
85326594249SQin Michael Li 		goto fail;
854dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x0080, 0))
85526594249SQin Michael Li 		goto fail;
85626594249SQin Michael Li 	urtw_delay_ms(300);
85726594249SQin Michael Li 
85826594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
85926594249SQin Michael Li 		goto fail;
86026594249SQin Michael Li 
86126594249SQin Michael Li 	error = urtw_8225_read(sc, 0x8, &data);
86226594249SQin Michael Li 	if (error != 0)
86326594249SQin Michael Li 		goto fail;
86426594249SQin Michael Li 	if (data != 0x588)
86526594249SQin Michael Li 		*ret = 0;
86626594249SQin Michael Li 	else {
86726594249SQin Michael Li 		error = urtw_8225_read(sc, 0x9, &data);
86826594249SQin Michael Li 		if (error != 0)
86926594249SQin Michael Li 			goto fail;
87026594249SQin Michael Li 		if (data != 0x700)
87126594249SQin Michael Li 			*ret = 0;
87226594249SQin Michael Li 	}
87326594249SQin Michael Li 
87426594249SQin Michael Li 	error = urtw_8225_write_c(sc, 0x0, 0xb7);
87526594249SQin Michael Li fail:
87626594249SQin Michael Li 	return (error);
87726594249SQin Michael Li }
87826594249SQin Michael Li 
87926594249SQin Michael Li static usbd_status
urtw_get_rfchip(struct urtw_softc * sc)88026594249SQin Michael Li urtw_get_rfchip(struct urtw_softc *sc)
88126594249SQin Michael Li {
882dfa03ef6SQin Michael Li 	struct urtw_rf *rf = &sc->sc_rf;
88326594249SQin Michael Li 	int ret;
88426594249SQin Michael Li 	uint32_t data;
88526594249SQin Michael Li 	usbd_status error;
88626594249SQin Michael Li 
887dfa03ef6SQin Michael Li 	rf->rf_sc = sc;
888dfa03ef6SQin Michael Li 
889dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
89026594249SQin Michael Li 		error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
891dfa03ef6SQin Michael Li 		if (error != 0) {
892dfa03ef6SQin Michael Li 			cmn_err(CE_WARN, "RF ID read failed\n");
893dfa03ef6SQin Michael Li 			return (-1);
894dfa03ef6SQin Michael Li 		}
89526594249SQin Michael Li 		switch (data & 0xff) {
89626594249SQin Michael Li 		case URTW_EPROM_RFCHIPID_RTL8225U:
89726594249SQin Michael Li 			error = urtw_8225_isv2(sc, &ret);
898dfa03ef6SQin Michael Li 			if (error != 0) {
899dfa03ef6SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
900dfa03ef6SQin Michael Li 				    (sc->sc_dev, CE_CONT,
901dfa03ef6SQin Michael Li 				    "8225 version check failed\n"));
90226594249SQin Michael Li 				goto fail;
903dfa03ef6SQin Michael Li 			}
90426594249SQin Michael Li 			if (ret == 0) {
90526594249SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
906dfa03ef6SQin Michael Li 				    (sc->sc_dev, CE_CONT,
907dfa03ef6SQin Michael Li 				    "8225 detected\n"));
908dfa03ef6SQin Michael Li 				rf->init = urtw_8225_rf_init;
909dfa03ef6SQin Michael Li 				rf->set_chan = urtw_8225_rf_set_chan;
910dfa03ef6SQin Michael Li 				rf->set_sens = urtw_8225_rf_set_sens;
91126594249SQin Michael Li 			} else {
91226594249SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
91326594249SQin Michael Li 				    (sc->sc_dev, CE_CONT,
914dfa03ef6SQin Michael Li 				    "8225 v2 detected\n"));
915dfa03ef6SQin Michael Li 				rf->init = urtw_8225v2_rf_init;
916dfa03ef6SQin Michael Li 				rf->set_chan = urtw_8225v2_rf_set_chan;
917dfa03ef6SQin Michael Li 				rf->set_sens = NULL;
91826594249SQin Michael Li 			}
91926594249SQin Michael Li 			break;
92026594249SQin Michael Li 		default:
921dfa03ef6SQin Michael Li 			goto fail;
922dfa03ef6SQin Michael Li 		}
923dfa03ef6SQin Michael Li 	} else {
924dfa03ef6SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_HWTYPE,
925dfa03ef6SQin Michael Li 		    (sc->sc_dev, CE_CONT,
926dfa03ef6SQin Michael Li 		    "8225 v2 [b] detected\n"));
927dfa03ef6SQin Michael Li 		rf->init = urtw_8225v2_b_rf_init;
928dfa03ef6SQin Michael Li 		rf->set_chan = urtw_8225v2_b_rf_set_chan;
929dfa03ef6SQin Michael Li 		rf->set_sens = NULL;
93026594249SQin Michael Li 	}
93126594249SQin Michael Li 
932dfa03ef6SQin Michael Li 	rf->max_sens = URTW_8225_RF_MAX_SENS;
933dfa03ef6SQin Michael Li 	rf->sens = URTW_8225_RF_DEF_SENS;
934dfa03ef6SQin Michael Li 
935dfa03ef6SQin Michael Li 	return (0);
936dfa03ef6SQin Michael Li 
93726594249SQin Michael Li fail:
938dfa03ef6SQin Michael Li 	cmn_err(CE_WARN, "unsupported RF chip %d\n", data & 0xff);
939dfa03ef6SQin Michael Li 	return (-1);
94026594249SQin Michael Li }
94126594249SQin Michael Li 
94226594249SQin Michael Li static usbd_status
urtw_get_txpwr(struct urtw_softc * sc)94326594249SQin Michael Li urtw_get_txpwr(struct urtw_softc *sc)
94426594249SQin Michael Li {
94526594249SQin Michael Li 	int i, j;
94626594249SQin Michael Li 	uint32_t data;
94726594249SQin Michael Li 	usbd_status error;
94826594249SQin Michael Li 
94926594249SQin Michael Li 	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
95026594249SQin Michael Li 	if (error != 0)
95126594249SQin Michael Li 		goto fail;
95226594249SQin Michael Li 	sc->sc_txpwr_cck_base = data & 0xf;
95326594249SQin Michael Li 	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
95426594249SQin Michael Li 
95526594249SQin Michael Li 	for (i = 1, j = 0; i < 6; i += 2, j++) {
95626594249SQin Michael Li 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
95726594249SQin Michael Li 		if (error != 0)
95826594249SQin Michael Li 			goto fail;
95926594249SQin Michael Li 		sc->sc_txpwr_cck[i] = data & 0xf;
96026594249SQin Michael Li 		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
96126594249SQin Michael Li 		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
96226594249SQin Michael Li 		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
96326594249SQin Michael Li 	}
96426594249SQin Michael Li 	for (i = 1, j = 0; i < 4; i += 2, j++) {
96526594249SQin Michael Li 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
96626594249SQin Michael Li 		if (error != 0)
96726594249SQin Michael Li 			goto fail;
96826594249SQin Michael Li 		sc->sc_txpwr_cck[i + 6] = data & 0xf;
96926594249SQin Michael Li 		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
97026594249SQin Michael Li 		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
97126594249SQin Michael Li 		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
97226594249SQin Michael Li 	}
973dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
97426594249SQin Michael Li 		for (i = 1, j = 0; i < 4; i += 2, j++) {
975dfa03ef6SQin Michael Li 			error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
976dfa03ef6SQin Michael Li 			    &data);
97726594249SQin Michael Li 			if (error != 0)
97826594249SQin Michael Li 				goto fail;
97926594249SQin Michael Li 			sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
98026594249SQin Michael Li 			sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
98126594249SQin Michael Li 			sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
982dfa03ef6SQin Michael Li 			sc->sc_txpwr_ofdm[i + 6 + 4 + 1] =
983dfa03ef6SQin Michael Li 			    (data & 0xf000) >> 12;
984dfa03ef6SQin Michael Li 		}
985dfa03ef6SQin Michael Li 	} else {
986dfa03ef6SQin Michael Li 		/* Channel 11. */
987dfa03ef6SQin Michael Li 		error = urtw_eprom_read32(sc, 0x1b, &data);
988dfa03ef6SQin Michael Li 		if (error != 0)
989dfa03ef6SQin Michael Li 			goto fail;
990dfa03ef6SQin Michael Li 		sc->sc_txpwr_cck[11] = data & 0xf;
991dfa03ef6SQin Michael Li 		sc->sc_txpwr_ofdm[11] = (data & 0xf0) >> 4;
992dfa03ef6SQin Michael Li 
993dfa03ef6SQin Michael Li 		/* Channel 12. */
994dfa03ef6SQin Michael Li 		error = urtw_eprom_read32(sc, 0xa, &data);
995dfa03ef6SQin Michael Li 		if (error != 0)
996dfa03ef6SQin Michael Li 			goto fail;
997dfa03ef6SQin Michael Li 		sc->sc_txpwr_cck[12] = data & 0xf;
998dfa03ef6SQin Michael Li 		sc->sc_txpwr_ofdm[12] = (data & 0xf0) >> 4;
999dfa03ef6SQin Michael Li 
1000dfa03ef6SQin Michael Li 		/* Channel 13, 14. */
1001dfa03ef6SQin Michael Li 		error = urtw_eprom_read32(sc, 0x1c, &data);
1002dfa03ef6SQin Michael Li 		if (error != 0)
1003dfa03ef6SQin Michael Li 			goto fail;
1004dfa03ef6SQin Michael Li 		sc->sc_txpwr_cck[13] = data & 0xf;
1005dfa03ef6SQin Michael Li 		sc->sc_txpwr_ofdm[13] = (data & 0xf0) >> 4;
1006dfa03ef6SQin Michael Li 		sc->sc_txpwr_cck[14] = (data & 0xf00) >> 8;
1007dfa03ef6SQin Michael Li 		sc->sc_txpwr_ofdm[14] = (data & 0xf000) >> 12;
100826594249SQin Michael Li 	}
100926594249SQin Michael Li fail:
101026594249SQin Michael Li 	return (error);
101126594249SQin Michael Li }
101226594249SQin Michael Li 
1013dfa03ef6SQin Michael Li 
101426594249SQin Michael Li static usbd_status
urtw_get_macaddr(struct urtw_softc * sc)101526594249SQin Michael Li urtw_get_macaddr(struct urtw_softc *sc)
101626594249SQin Michael Li {
101726594249SQin Michael Li 	uint32_t data;
101826594249SQin Michael Li 	usbd_status error;
101926594249SQin Michael Li 	uint8_t *m = 0;
102026594249SQin Michael Li 
102126594249SQin Michael Li 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
102226594249SQin Michael Li 	if (error != 0)
102326594249SQin Michael Li 		goto fail;
102426594249SQin Michael Li 	sc->sc_bssid[0] = data & 0xff;
102526594249SQin Michael Li 	sc->sc_bssid[1] = (data & 0xff00) >> 8;
102626594249SQin Michael Li 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
102726594249SQin Michael Li 	if (error != 0)
102826594249SQin Michael Li 		goto fail;
102926594249SQin Michael Li 	sc->sc_bssid[2] = data & 0xff;
103026594249SQin Michael Li 	sc->sc_bssid[3] = (data & 0xff00) >> 8;
103126594249SQin Michael Li 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
103226594249SQin Michael Li 	if (error != 0)
103326594249SQin Michael Li 		goto fail;
103426594249SQin Michael Li 	sc->sc_bssid[4] = data & 0xff;
103526594249SQin Michael Li 	sc->sc_bssid[5] = (data & 0xff00) >> 8;
103626594249SQin Michael Li 	bcopy(sc->sc_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
103726594249SQin Michael Li 	m = sc->sc_bssid;
103826594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
103926594249SQin Michael Li 	    "MAC: %x:%x:%x:%x:%x:%x\n",
104026594249SQin Michael Li 	    m[0], m[1], m[2], m[3], m[4], m[5]));
104126594249SQin Michael Li fail:
104226594249SQin Michael Li 	return (error);
104326594249SQin Michael Li }
104426594249SQin Michael Li 
104526594249SQin Michael Li static usbd_status
urtw_eprom_read32(struct urtw_softc * sc,uint32_t addr,uint32_t * data)104626594249SQin Michael Li urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
104726594249SQin Michael Li {
104826594249SQin Michael Li #define	URTW_READCMD_LEN	3
104926594249SQin Michael Li 	int addrlen, i;
105026594249SQin Michael Li 	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
105126594249SQin Michael Li 	usbd_status error;
105226594249SQin Michael Li 
105326594249SQin Michael Li 	/* NB: make sure the buffer is initialized  */
105426594249SQin Michael Li 	*data = 0;
105526594249SQin Michael Li 
105626594249SQin Michael Li 	/* enable EPROM programming */
105726594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD,
1058dfa03ef6SQin Michael Li 	    URTW_EPROM_CMD_PROGRAM_MODE, 0))
105926594249SQin Michael Li 		goto fail;
106026594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
106126594249SQin Michael Li 
106226594249SQin Michael Li 	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
106326594249SQin Michael Li 	if (error != 0)
106426594249SQin Michael Li 		goto fail;
106526594249SQin Michael Li 	error = urtw_eprom_ck(sc);
106626594249SQin Michael Li 	if (error != 0)
106726594249SQin Michael Li 		goto fail;
106826594249SQin Michael Li 	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
106926594249SQin Michael Li 	if (error != 0)
107026594249SQin Michael Li 		goto fail;
107126594249SQin Michael Li 	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
107226594249SQin Michael Li 		addrlen = 8;
107326594249SQin Michael Li 		addrstr[0] = addr & (1 << 7);
107426594249SQin Michael Li 		addrstr[1] = addr & (1 << 6);
107526594249SQin Michael Li 		addrstr[2] = addr & (1 << 5);
107626594249SQin Michael Li 		addrstr[3] = addr & (1 << 4);
107726594249SQin Michael Li 		addrstr[4] = addr & (1 << 3);
107826594249SQin Michael Li 		addrstr[5] = addr & (1 << 2);
107926594249SQin Michael Li 		addrstr[6] = addr & (1 << 1);
108026594249SQin Michael Li 		addrstr[7] = addr & (1 << 0);
108126594249SQin Michael Li 	} else {
108226594249SQin Michael Li 		addrlen = 6;
108326594249SQin Michael Li 		addrstr[0] = addr & (1 << 5);
108426594249SQin Michael Li 		addrstr[1] = addr & (1 << 4);
108526594249SQin Michael Li 		addrstr[2] = addr & (1 << 3);
108626594249SQin Michael Li 		addrstr[3] = addr & (1 << 2);
108726594249SQin Michael Li 		addrstr[4] = addr & (1 << 1);
108826594249SQin Michael Li 		addrstr[5] = addr & (1 << 0);
108926594249SQin Michael Li 	}
109026594249SQin Michael Li 	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
109126594249SQin Michael Li 	if (error != 0)
109226594249SQin Michael Li 		goto fail;
109326594249SQin Michael Li 
109426594249SQin Michael Li 	error = urtw_eprom_writebit(sc, 0);
109526594249SQin Michael Li 	if (error != 0)
109626594249SQin Michael Li 		goto fail;
109726594249SQin Michael Li 
109826594249SQin Michael Li 	for (i = 0; i < 16; i++) {
109926594249SQin Michael Li 		error = urtw_eprom_ck(sc);
110026594249SQin Michael Li 		if (error != 0)
110126594249SQin Michael Li 			goto fail;
110226594249SQin Michael Li 		error = urtw_eprom_readbit(sc, &data16);
110326594249SQin Michael Li 		if (error != 0)
110426594249SQin Michael Li 			goto fail;
110526594249SQin Michael Li 
110626594249SQin Michael Li 		(*data) |= (data16 << (15 - i));
110726594249SQin Michael Li 	}
110826594249SQin Michael Li 
110926594249SQin Michael Li 	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
111026594249SQin Michael Li 	if (error != 0)
111126594249SQin Michael Li 		goto fail;
111226594249SQin Michael Li 	error = urtw_eprom_ck(sc);
111326594249SQin Michael Li 	if (error != 0)
111426594249SQin Michael Li 		goto fail;
111526594249SQin Michael Li 
111626594249SQin Michael Li 	/* now disable EPROM programming */
1117dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_EPROM_CMD,
1118dfa03ef6SQin Michael Li 	    URTW_EPROM_CMD_NORMAL_MODE, 0);
111926594249SQin Michael Li fail:
112026594249SQin Michael Li 	return (error);
112126594249SQin Michael Li #undef URTW_READCMD_LEN
112226594249SQin Michael Li }
112326594249SQin Michael Li 
112426594249SQin Michael Li static usbd_status
urtw_eprom_readbit(struct urtw_softc * sc,int16_t * data)112526594249SQin Michael Li urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
112626594249SQin Michael Li {
112726594249SQin Michael Li 	uint8_t data8;
112826594249SQin Michael Li 	usbd_status error;
112926594249SQin Michael Li 
1130dfa03ef6SQin Michael Li 	error = urtw_read8_c(sc, URTW_EPROM_CMD, &data8, 0);
113126594249SQin Michael Li 	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
113226594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
113326594249SQin Michael Li 	return (error);
113426594249SQin Michael Li }
113526594249SQin Michael Li 
113626594249SQin Michael Li static usbd_status
urtw_eprom_sendbits(struct urtw_softc * sc,int16_t * buf,int buflen)113726594249SQin Michael Li urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
113826594249SQin Michael Li {
113926594249SQin Michael Li 	int i = 0;
114026594249SQin Michael Li 	usbd_status error;
114126594249SQin Michael Li 
114226594249SQin Michael Li 	for (i = 0; i < buflen; i++) {
114326594249SQin Michael Li 		error = urtw_eprom_writebit(sc, buf[i]);
114426594249SQin Michael Li 		if (error != 0)
114526594249SQin Michael Li 			goto fail;
114626594249SQin Michael Li 		error = urtw_eprom_ck(sc);
114726594249SQin Michael Li 		if (error != 0)
114826594249SQin Michael Li 			goto fail;
114926594249SQin Michael Li 	}
115026594249SQin Michael Li fail:
115126594249SQin Michael Li 	return (error);
115226594249SQin Michael Li }
115326594249SQin Michael Li 
115426594249SQin Michael Li static usbd_status
urtw_eprom_writebit(struct urtw_softc * sc,int16_t bit)115526594249SQin Michael Li urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
115626594249SQin Michael Li {
115726594249SQin Michael Li 	uint8_t data;
115826594249SQin Michael Li 	usbd_status error;
115926594249SQin Michael Li 
1160dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
116126594249SQin Michael Li 		goto fail;
116226594249SQin Michael Li 	if (bit != 0)
116326594249SQin Michael Li 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1164dfa03ef6SQin Michael Li 		    data | URTW_EPROM_WRITEBIT, 0);
116526594249SQin Michael Li 	else
116626594249SQin Michael Li 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1167dfa03ef6SQin Michael Li 		    data & ~URTW_EPROM_WRITEBIT, 0);
116826594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
116926594249SQin Michael Li fail:
117026594249SQin Michael Li 	return (error);
117126594249SQin Michael Li }
117226594249SQin Michael Li 
117326594249SQin Michael Li static usbd_status
urtw_eprom_ck(struct urtw_softc * sc)117426594249SQin Michael Li urtw_eprom_ck(struct urtw_softc *sc)
117526594249SQin Michael Li {
117626594249SQin Michael Li 	uint8_t data;
117726594249SQin Michael Li 	usbd_status error;
117826594249SQin Michael Li 
117926594249SQin Michael Li 	/* masking  */
1180dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
118126594249SQin Michael Li 		goto fail;
1182dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK, 0))
118326594249SQin Michael Li 		goto fail;
118426594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
118526594249SQin Michael Li 	/* unmasking  */
1186dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
118726594249SQin Michael Li 		goto fail;
1188dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK, 0);
118926594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
119026594249SQin Michael Li fail:
119126594249SQin Michael Li 	return (error);
119226594249SQin Michael Li }
119326594249SQin Michael Li 
119426594249SQin Michael Li static usbd_status
urtw_eprom_cs(struct urtw_softc * sc,int able)119526594249SQin Michael Li urtw_eprom_cs(struct urtw_softc *sc, int able)
119626594249SQin Michael Li {
119726594249SQin Michael Li 	uint8_t data;
119826594249SQin Michael Li 	usbd_status error;
119926594249SQin Michael Li 
1200dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
120126594249SQin Michael Li 		goto fail;
120226594249SQin Michael Li 	if (able == URTW_EPROM_ENABLE)
120326594249SQin Michael Li 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1204dfa03ef6SQin Michael Li 		    data | URTW_EPROM_CS, 0);
120526594249SQin Michael Li 	else
120626594249SQin Michael Li 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1207dfa03ef6SQin Michael Li 		    data & ~URTW_EPROM_CS, 0);
120826594249SQin Michael Li 	DELAY(URTW_EPROM_DELAY);
120926594249SQin Michael Li fail:
121026594249SQin Michael Li 	return (error);
121126594249SQin Michael Li }
121226594249SQin Michael Li 
121326594249SQin Michael Li static usbd_status
urtw_read8_c(struct urtw_softc * sc,int val,uint8_t * data,uint8_t idx)1214dfa03ef6SQin Michael Li urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data, uint8_t idx)
121526594249SQin Michael Li {
121626594249SQin Michael Li 	usb_ctrl_setup_t req;
121726594249SQin Michael Li 	usb_cr_t cr;
121826594249SQin Michael Li 	usb_cb_flags_t cf;
121926594249SQin Michael Li 	mblk_t *mp = NULL;
122026594249SQin Michael Li 	usbd_status error;
122126594249SQin Michael Li 
122226594249SQin Michael Li 	bzero(&req, sizeof (req));
122326594249SQin Michael Li 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
122426594249SQin Michael Li 	req.bRequest = URTW_8187_GETREGS_REQ;
122526594249SQin Michael Li 	req.wValue = val | 0xff00;
1226dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
122726594249SQin Michael Li 	req.wLength = sizeof (uint8_t);
122826594249SQin Michael Li 
122926594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
123026594249SQin Michael Li 	    &cr, &cf, 0);
123126594249SQin Michael Li 
123226594249SQin Michael Li 	if (error != USB_SUCCESS) {
123326594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
123426594249SQin Michael Li 		    "urtw_read8_c: get regs req failed :"
123526594249SQin Michael Li 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
123626594249SQin Michael Li 		return (error);
123726594249SQin Michael Li 	}
123826594249SQin Michael Li 	bcopy(mp->b_rptr, data, sizeof (uint8_t));
123926594249SQin Michael Li 	if (mp)
124026594249SQin Michael Li 		freemsg(mp);
124126594249SQin Michael Li 	return (error);
124226594249SQin Michael Li }
124326594249SQin Michael Li 
124426594249SQin Michael Li static usbd_status
urtw_read8e(struct urtw_softc * sc,int val,uint8_t * data)124526594249SQin Michael Li urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
124626594249SQin Michael Li {
124726594249SQin Michael Li 	usb_ctrl_setup_t req;
124826594249SQin Michael Li 	usb_cr_t cr;
124926594249SQin Michael Li 	usb_cb_flags_t cf;
125026594249SQin Michael Li 	mblk_t *mp = NULL;
125126594249SQin Michael Li 	usbd_status error;
125226594249SQin Michael Li 
125326594249SQin Michael Li 	bzero(&req, sizeof (req));
125426594249SQin Michael Li 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
125526594249SQin Michael Li 	req.bRequest = URTW_8187_GETREGS_REQ;
125626594249SQin Michael Li 	req.wValue = val | 0xfe00;
125726594249SQin Michael Li 	req.wIndex = 0;
125826594249SQin Michael Li 	req.wLength = sizeof (uint8_t);
125926594249SQin Michael Li 	req.attrs = USB_ATTRS_AUTOCLEARING;
126026594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
126126594249SQin Michael Li 	    &cr, &cf, 0);
126226594249SQin Michael Li 
126326594249SQin Michael Li 	if (error != USB_SUCCESS) {
126426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
126526594249SQin Michael Li 		    "urtw_read8e: get regs req failed :"
126626594249SQin Michael Li 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
126726594249SQin Michael Li 		return (error);
126826594249SQin Michael Li 	}
126926594249SQin Michael Li 
127026594249SQin Michael Li 	if (mp) {
127126594249SQin Michael Li 		bcopy(mp->b_rptr, data, sizeof (uint8_t));
127226594249SQin Michael Li 		freemsg(mp);
127326594249SQin Michael Li 	}
127426594249SQin Michael Li 	return (error);
127526594249SQin Michael Li }
127626594249SQin Michael Li 
127726594249SQin Michael Li static usbd_status
urtw_read16_c(struct urtw_softc * sc,int val,uint16_t * data,uint8_t idx)1278dfa03ef6SQin Michael Li urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data, uint8_t idx)
127926594249SQin Michael Li {
128026594249SQin Michael Li 	usb_ctrl_setup_t req;
128126594249SQin Michael Li 	usb_cr_t cr;
128226594249SQin Michael Li 	usb_cb_flags_t cf;
128326594249SQin Michael Li 	mblk_t *mp = NULL;
128426594249SQin Michael Li 	usbd_status error;
128526594249SQin Michael Li 
128626594249SQin Michael Li 	bzero(&req, sizeof (req));
128726594249SQin Michael Li 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
128826594249SQin Michael Li 	req.bRequest = URTW_8187_GETREGS_REQ;
128926594249SQin Michael Li 	req.wValue = val | 0xff00;
1290dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
129126594249SQin Michael Li 	req.wLength = sizeof (uint16_t);
129226594249SQin Michael Li 	req.attrs = USB_ATTRS_AUTOCLEARING;
129326594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
129426594249SQin Michael Li 	    &cr, &cf, 0);
129526594249SQin Michael Li 
129626594249SQin Michael Li 	if (error != USB_SUCCESS) {
129726594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
129826594249SQin Michael Li 		    "urtw_read16_c: get regs req failed :"
129926594249SQin Michael Li 		    " cr:%s(%d), cf:(%x)\n",
130026594249SQin Michael Li 		    usb_str_cr(cr), cr, cf));
130126594249SQin Michael Li 		return (error);
130226594249SQin Michael Li 	}
130326594249SQin Michael Li 	if (mp) {
130426594249SQin Michael Li 		bcopy(mp->b_rptr, data, sizeof (uint16_t));
130526594249SQin Michael Li 		freemsg(mp);
130626594249SQin Michael Li 	}
130726594249SQin Michael Li 	return (error);
130826594249SQin Michael Li }
130926594249SQin Michael Li 
131026594249SQin Michael Li static usbd_status
urtw_read32_c(struct urtw_softc * sc,int val,uint32_t * data,uint8_t idx)1311dfa03ef6SQin Michael Li urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data, uint8_t idx)
131226594249SQin Michael Li {
131326594249SQin Michael Li 	usb_ctrl_setup_t req;
131426594249SQin Michael Li 	usb_cr_t cr;
131526594249SQin Michael Li 	usb_cb_flags_t cf;
131626594249SQin Michael Li 	mblk_t *mp = NULL;
131726594249SQin Michael Li 	usbd_status error;
131826594249SQin Michael Li 
131926594249SQin Michael Li 	bzero(&req, sizeof (req));
132026594249SQin Michael Li 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
132126594249SQin Michael Li 	req.bRequest = URTW_8187_GETREGS_REQ;
132226594249SQin Michael Li 	req.wValue = val | 0xff00;
1323dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
132426594249SQin Michael Li 	req.wLength = sizeof (uint32_t);
132526594249SQin Michael Li 	req.attrs = USB_ATTRS_AUTOCLEARING;
132626594249SQin Michael Li 
132726594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
132826594249SQin Michael Li 	    &cr, &cf, 0);
132926594249SQin Michael Li 
133026594249SQin Michael Li 	if (error != USB_SUCCESS) {
133126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
133226594249SQin Michael Li 		    "urtw_read32_c: get regs req failed :"
133326594249SQin Michael Li 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
133426594249SQin Michael Li 		return (error);
133526594249SQin Michael Li 	}
133626594249SQin Michael Li 
133726594249SQin Michael Li 	if (mp) {
133826594249SQin Michael Li 		bcopy(mp->b_rptr, data, sizeof (uint32_t));
133926594249SQin Michael Li 		freemsg(mp);
134026594249SQin Michael Li 	}
134126594249SQin Michael Li 	return (error);
134226594249SQin Michael Li }
134326594249SQin Michael Li 
134426594249SQin Michael Li static usbd_status
urtw_write8_c(struct urtw_softc * sc,int val,uint8_t data,uint8_t idx)1345dfa03ef6SQin Michael Li urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data, uint8_t idx)
134626594249SQin Michael Li {
134726594249SQin Michael Li 	usb_ctrl_setup_t req;
134826594249SQin Michael Li 	usb_cr_t cr;
134926594249SQin Michael Li 	usb_cb_flags_t cf;
135026594249SQin Michael Li 	mblk_t *mp = 0;
135126594249SQin Michael Li 	int error;
135226594249SQin Michael Li 
135326594249SQin Michael Li 	bzero(&req, sizeof (req));
135426594249SQin Michael Li 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
135526594249SQin Michael Li 	req.bRequest = URTW_8187_SETREGS_REQ;
135626594249SQin Michael Li 	req.wValue = val | 0xff00;
1357dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
135826594249SQin Michael Li 	req.wLength = sizeof (uint8_t);
135926594249SQin Michael Li 	req.attrs = USB_ATTRS_NONE;
136026594249SQin Michael Li 
136126594249SQin Michael Li 	mp = allocb(sizeof (uint32_t), BPRI_MED);
136226594249SQin Michael Li 	if (mp == NULL) {
136326594249SQin Michael Li 		cmn_err(CE_CONT, "urtw_write8_c: failed alloc mblk.");
136426594249SQin Michael Li 		return (-1);
136526594249SQin Michael Li 	}
136626594249SQin Michael Li 	*(uint8_t *)(mp->b_rptr) = data;
136726594249SQin Michael Li 	mp->b_wptr += sizeof (uint8_t);
136826594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
136926594249SQin Michael Li 	    &cr, &cf, 0);
137026594249SQin Michael Li 	if (error != USB_SUCCESS) {
137126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
137226594249SQin Michael Li 		    "urtw_write8_c: could not set regs:"
137326594249SQin Michael Li 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
137426594249SQin Michael Li 	}
137526594249SQin Michael Li 	if (mp)
137626594249SQin Michael Li 		freemsg(mp);
137726594249SQin Michael Li 	return (error);
137826594249SQin Michael Li }
137926594249SQin Michael Li 
138026594249SQin Michael Li static usbd_status
urtw_write8e(struct urtw_softc * sc,int val,uint8_t data)138126594249SQin Michael Li urtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
138226594249SQin Michael Li {
138326594249SQin Michael Li 	usb_ctrl_setup_t req;
138426594249SQin Michael Li 	usb_cr_t cr;
138526594249SQin Michael Li 	usb_cb_flags_t cf;
138626594249SQin Michael Li 	mblk_t *mp = 0;
138726594249SQin Michael Li 	int error;
138826594249SQin Michael Li 
138926594249SQin Michael Li 	bzero(&req, sizeof (req));
139026594249SQin Michael Li 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
139126594249SQin Michael Li 	req.bRequest = URTW_8187_SETREGS_REQ;
139226594249SQin Michael Li 	req.wValue = val | 0xfe00;
139326594249SQin Michael Li 	req.wIndex = 0;
139426594249SQin Michael Li 	req.wLength = sizeof (uint8_t);
139526594249SQin Michael Li 	req.attrs = USB_ATTRS_NONE;
139626594249SQin Michael Li 
139726594249SQin Michael Li 	mp = allocb(sizeof (uint8_t), BPRI_MED);
139826594249SQin Michael Li 	if (mp == NULL) {
139926594249SQin Michael Li 		cmn_err(CE_CONT, "urtw_write8e: failed alloc mblk.");
140026594249SQin Michael Li 		return (-1);
140126594249SQin Michael Li 	}
140226594249SQin Michael Li 	*(mp->b_rptr) = data;
140326594249SQin Michael Li 	mp->b_wptr += sizeof (uint8_t);
140426594249SQin Michael Li 
140526594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
140626594249SQin Michael Li 	    &cr, &cf, 0);
140726594249SQin Michael Li 	if (error != USB_SUCCESS) {
140826594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
140926594249SQin Michael Li 		    "urtw_write8e: could not set regs:"
141026594249SQin Michael Li 		    "cr:%s(%d), cf:(%x)\n",
141126594249SQin Michael Li 		    usb_str_cr(cr), cr, cf));
141226594249SQin Michael Li 	}
141326594249SQin Michael Li 	if (mp)
141426594249SQin Michael Li 		freemsg(mp);
141526594249SQin Michael Li 	return (error);
141626594249SQin Michael Li }
141726594249SQin Michael Li 
141826594249SQin Michael Li static usbd_status
urtw_write16_c(struct urtw_softc * sc,int val,uint16_t data,uint8_t idx)1419dfa03ef6SQin Michael Li urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data, uint8_t idx)
142026594249SQin Michael Li {
142126594249SQin Michael Li 	usb_ctrl_setup_t req;
142226594249SQin Michael Li 	usb_cr_t cr;
142326594249SQin Michael Li 	usb_cb_flags_t cf;
142426594249SQin Michael Li 	mblk_t *mp = 0;
142526594249SQin Michael Li 	int error;
142626594249SQin Michael Li 
142726594249SQin Michael Li 	bzero(&req, sizeof (req));
142826594249SQin Michael Li 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
142926594249SQin Michael Li 	req.bRequest = URTW_8187_SETREGS_REQ;
143026594249SQin Michael Li 	req.wValue = val | 0xff00;
1431dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
143226594249SQin Michael Li 	req.wLength = sizeof (uint16_t);
143326594249SQin Michael Li 	req.attrs = USB_ATTRS_NONE;
143426594249SQin Michael Li 
143526594249SQin Michael Li 	mp = allocb(sizeof (uint16_t), BPRI_MED);
143626594249SQin Michael Li 	if (mp == NULL) {
143726594249SQin Michael Li 		cmn_err(CE_CONT, "urtw_write16_c: failed alloc mblk.");
143826594249SQin Michael Li 		return (-1);
143926594249SQin Michael Li 	}
144026594249SQin Michael Li 	*(uint16_t *)(uintptr_t)(mp->b_rptr) = data;
144126594249SQin Michael Li 	mp->b_wptr += sizeof (uint16_t);
144226594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
144326594249SQin Michael Li 	    &cr, &cf, 0);
144426594249SQin Michael Li 	if (error != USB_SUCCESS) {
144526594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
144626594249SQin Michael Li 		    "urtw_write16_c: could not set regs:"
144726594249SQin Michael Li 		    "cr:%s(%d), cf:(%x)\n",
144826594249SQin Michael Li 		    usb_str_cr(cr), cr, cf));
144926594249SQin Michael Li 	}
145026594249SQin Michael Li 	if (mp)
145126594249SQin Michael Li 		freemsg(mp);
145226594249SQin Michael Li 	return (error);
145326594249SQin Michael Li }
145426594249SQin Michael Li 
145526594249SQin Michael Li static usbd_status
urtw_write32_c(struct urtw_softc * sc,int val,uint32_t data,uint8_t idx)1456dfa03ef6SQin Michael Li urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data, uint8_t idx)
145726594249SQin Michael Li {
145826594249SQin Michael Li 	usb_ctrl_setup_t req;
145926594249SQin Michael Li 	usb_cr_t cr;
146026594249SQin Michael Li 	usb_cb_flags_t cf;
146126594249SQin Michael Li 	mblk_t *mp = 0;
146226594249SQin Michael Li 	int error;
146326594249SQin Michael Li 
146426594249SQin Michael Li 	bzero(&req, sizeof (req));
146526594249SQin Michael Li 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
146626594249SQin Michael Li 	req.bRequest = URTW_8187_SETREGS_REQ;
146726594249SQin Michael Li 	req.wValue = val | 0xff00;
1468dfa03ef6SQin Michael Li 	req.wIndex = idx & 0x03;
146926594249SQin Michael Li 	req.wLength = sizeof (uint32_t);
147026594249SQin Michael Li 	req.attrs = USB_ATTRS_NONE;
147126594249SQin Michael Li 
147226594249SQin Michael Li 	mp = allocb(sizeof (uint32_t), BPRI_MED);
147326594249SQin Michael Li 	if (mp == NULL) {
147426594249SQin Michael Li 		cmn_err(CE_CONT, "urtw_write32_c: failed alloc mblk.");
147526594249SQin Michael Li 		return (-1);
147626594249SQin Michael Li 	}
147726594249SQin Michael Li 	*(uint32_t *)(uintptr_t)(mp->b_rptr) = data;
147826594249SQin Michael Li 	mp->b_wptr += sizeof (uint32_t);
147926594249SQin Michael Li 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
148026594249SQin Michael Li 	    &cr, &cf, 0);
148126594249SQin Michael Li 	if (error != USB_SUCCESS) {
148226594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
148326594249SQin Michael Li 		    "urtw_write32_c: could not set regs:"
148426594249SQin Michael Li 		    "cr:%s(%d), cf:(%x)\n",
148526594249SQin Michael Li 		    usb_str_cr(cr), cr, cf));
148626594249SQin Michael Li 	}
148726594249SQin Michael Li 
148826594249SQin Michael Li 	if (mp)
148926594249SQin Michael Li 		freemsg(mp);
149026594249SQin Michael Li 	return (error);
149126594249SQin Michael Li }
149226594249SQin Michael Li 
149326594249SQin Michael Li static usbd_status
urtw_set_mode(struct urtw_softc * sc,uint32_t mode)149426594249SQin Michael Li urtw_set_mode(struct urtw_softc *sc, uint32_t mode)
149526594249SQin Michael Li {
149626594249SQin Michael Li 	uint8_t data;
149726594249SQin Michael Li 	usbd_status error;
149826594249SQin Michael Li 
1499dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
150026594249SQin Michael Li 		goto fail;
150126594249SQin Michael Li 	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
150226594249SQin Michael Li 	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
1503dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data, 0);
150426594249SQin Michael Li fail:
150526594249SQin Michael Li 	return (error);
150626594249SQin Michael Li }
150726594249SQin Michael Li 
150826594249SQin Michael Li static usbd_status
urtw_8180_set_anaparam(struct urtw_softc * sc,uint32_t val)150926594249SQin Michael Li urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
151026594249SQin Michael Li {
151126594249SQin Michael Li 	uint8_t data;
151226594249SQin Michael Li 	usbd_status error;
151326594249SQin Michael Li 
151426594249SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
151526594249SQin Michael Li 	if (error)
151626594249SQin Michael Li 		goto fail;
151726594249SQin Michael Li 
1518dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
151926594249SQin Michael Li 		goto fail;
152026594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1521dfa03ef6SQin Michael Li 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0))
152226594249SQin Michael Li 		goto fail;
1523dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_ANAPARAM, val, 0))
152426594249SQin Michael Li 		goto fail;
1525dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
152626594249SQin Michael Li 		goto fail;
152726594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1528dfa03ef6SQin Michael Li 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0))
152926594249SQin Michael Li 		goto fail;
153026594249SQin Michael Li 
153126594249SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
153226594249SQin Michael Li 	if (error)
153326594249SQin Michael Li 		goto fail;
153426594249SQin Michael Li fail:
153526594249SQin Michael Li 	return (error);
153626594249SQin Michael Li }
153726594249SQin Michael Li 
153826594249SQin Michael Li static usbd_status
urtw_8185_set_anaparam2(struct urtw_softc * sc,uint32_t val)153926594249SQin Michael Li urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
154026594249SQin Michael Li {
154126594249SQin Michael Li 	uint8_t data;
154226594249SQin Michael Li 	usbd_status error;
154326594249SQin Michael Li 
154426594249SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
154526594249SQin Michael Li 	if (error)
154626594249SQin Michael Li 		goto fail;
154726594249SQin Michael Li 
1548dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
154926594249SQin Michael Li 		goto fail;
155026594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1551dfa03ef6SQin Michael Li 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0))
155226594249SQin Michael Li 		goto fail;
1553dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_ANAPARAM2, val, 0))
155426594249SQin Michael Li 		goto fail;
1555dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
155626594249SQin Michael Li 		goto fail;
155726594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1558dfa03ef6SQin Michael Li 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0))
155926594249SQin Michael Li 		goto fail;
156026594249SQin Michael Li 
156126594249SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
156226594249SQin Michael Li 	if (error)
156326594249SQin Michael Li 		goto fail;
156426594249SQin Michael Li fail:
156526594249SQin Michael Li 	return (error);
156626594249SQin Michael Li }
156726594249SQin Michael Li 
156826594249SQin Michael Li static usbd_status
urtw_intr_disable(struct urtw_softc * sc)156926594249SQin Michael Li urtw_intr_disable(struct urtw_softc *sc)
157026594249SQin Michael Li {
157126594249SQin Michael Li 	usbd_status error;
157226594249SQin Michael Li 
1573dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0, 0);
157426594249SQin Michael Li 	return (error);
157526594249SQin Michael Li }
157626594249SQin Michael Li 
157726594249SQin Michael Li static usbd_status
urtw_8187_reset(struct urtw_softc * sc)1578dfa03ef6SQin Michael Li urtw_8187_reset(struct urtw_softc *sc)
157926594249SQin Michael Li {
158026594249SQin Michael Li 	uint8_t data;
158126594249SQin Michael Li 	usbd_status error;
158226594249SQin Michael Li 
1583dfa03ef6SQin Michael Li 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
158426594249SQin Michael Li 	if (error)
158526594249SQin Michael Li 		goto fail;
1586dfa03ef6SQin Michael Li 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
158726594249SQin Michael Li 	if (error)
158826594249SQin Michael Li 		goto fail;
158926594249SQin Michael Li 
159026594249SQin Michael Li 	error = urtw_intr_disable(sc);
159126594249SQin Michael Li 	if (error)
159226594249SQin Michael Li 		goto fail;
159326594249SQin Michael Li 	urtw_delay_ms(50);
159426594249SQin Michael Li 
159526594249SQin Michael Li 	error = urtw_write8e(sc, 0x18, 0x10);
159626594249SQin Michael Li 	if (error != 0)
159726594249SQin Michael Li 		goto fail;
159826594249SQin Michael Li 	error = urtw_write8e(sc, 0x18, 0x11);
159926594249SQin Michael Li 	if (error != 0)
160026594249SQin Michael Li 		goto fail;
160126594249SQin Michael Li 	error = urtw_write8e(sc, 0x18, 0x00);
160226594249SQin Michael Li 	if (error != 0)
160326594249SQin Michael Li 		goto fail;
160426594249SQin Michael Li 	urtw_delay_ms(50);
160526594249SQin Michael Li 
1606dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
160726594249SQin Michael Li 		goto fail;
160826594249SQin Michael Li 	data = (data & 2) | URTW_CMD_RST;
1609dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CMD, data, 0))
161026594249SQin Michael Li 		goto fail;
161126594249SQin Michael Li 	urtw_delay_ms(50);
161226594249SQin Michael Li 
1613dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
161426594249SQin Michael Li 		goto fail;
161526594249SQin Michael Li 	if (data & URTW_CMD_RST) {
161626594249SQin Michael Li 		cmn_err(CE_CONT, "urtw reset timeout\n");
161726594249SQin Michael Li 		goto fail;
161826594249SQin Michael Li 	}
161926594249SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
162026594249SQin Michael Li 	if (error)
162126594249SQin Michael Li 		goto fail;
162226594249SQin Michael Li 	urtw_delay_ms(50);
162326594249SQin Michael Li 
1624dfa03ef6SQin Michael Li 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
162526594249SQin Michael Li 	if (error)
162626594249SQin Michael Li 		goto fail;
1627dfa03ef6SQin Michael Li 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
162826594249SQin Michael Li 	if (error)
162926594249SQin Michael Li 		goto fail;
163026594249SQin Michael Li fail:
163126594249SQin Michael Li 	return (error);
163226594249SQin Michael Li }
163326594249SQin Michael Li 
163426594249SQin Michael Li static usbd_status
urtw_led_on(struct urtw_softc * sc,int type)163526594249SQin Michael Li urtw_led_on(struct urtw_softc *sc, int type)
163626594249SQin Michael Li {
163726594249SQin Michael Li 	if (type == URTW_LED_GPIO) {
163826594249SQin Michael Li 		switch (sc->sc_gpio_ledpin) {
163926594249SQin Michael Li 		case URTW_LED_PIN_GPIO0:
1640dfa03ef6SQin Michael Li 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01, 0);
1641dfa03ef6SQin Michael Li 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x00, 0);
164226594249SQin Michael Li 			break;
164326594249SQin Michael Li 		default:
164426594249SQin Michael Li 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
164526594249SQin Michael Li 			    sc->sc_gpio_ledpin);
164626594249SQin Michael Li 			/* never reach  */
164726594249SQin Michael Li 		}
164826594249SQin Michael Li 	} else {
164926594249SQin Michael Li 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
165026594249SQin Michael Li 		/* never reach  */
165126594249SQin Michael Li 	}
165226594249SQin Michael Li 
165326594249SQin Michael Li 	sc->sc_gpio_ledon = 1;
165426594249SQin Michael Li 	return (0);
165526594249SQin Michael Li }
165626594249SQin Michael Li 
165726594249SQin Michael Li static usbd_status
urtw_led_off(struct urtw_softc * sc,int type)165826594249SQin Michael Li urtw_led_off(struct urtw_softc *sc, int type)
165926594249SQin Michael Li {
166026594249SQin Michael Li 	if (type == URTW_LED_GPIO) {
166126594249SQin Michael Li 		switch (sc->sc_gpio_ledpin) {
166226594249SQin Michael Li 		case URTW_LED_PIN_GPIO0:
1663dfa03ef6SQin Michael Li 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01, 0);
1664dfa03ef6SQin Michael Li 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x01, 0);
166526594249SQin Michael Li 			break;
166626594249SQin Michael Li 		default:
166726594249SQin Michael Li 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
166826594249SQin Michael Li 			    sc->sc_gpio_ledpin);
166926594249SQin Michael Li 			/* never reach  */
167026594249SQin Michael Li 		}
167126594249SQin Michael Li 	} else {
167226594249SQin Michael Li 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
167326594249SQin Michael Li 		/* never reach  */
167426594249SQin Michael Li 	}
167526594249SQin Michael Li 
167626594249SQin Michael Li 	sc->sc_gpio_ledon = 0;
167726594249SQin Michael Li 	return (0);
167826594249SQin Michael Li }
167926594249SQin Michael Li 
168026594249SQin Michael Li static usbd_status
urtw_led_mode0(struct urtw_softc * sc,int mode)168126594249SQin Michael Li urtw_led_mode0(struct urtw_softc *sc, int mode)
168226594249SQin Michael Li {
168326594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
168426594249SQin Michael Li 	    "urtw_led_mode0: mode = %d\n", mode));
168526594249SQin Michael Li 	switch (mode) {
168626594249SQin Michael Li 	case URTW_LED_CTL_POWER_ON:
168726594249SQin Michael Li 		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
168826594249SQin Michael Li 		break;
168926594249SQin Michael Li 	case URTW_LED_CTL_TX:
169026594249SQin Michael Li 		if (sc->sc_gpio_ledinprogress == 1)
169126594249SQin Michael Li 			return (0);
169226594249SQin Michael Li 		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
169326594249SQin Michael Li 		sc->sc_gpio_blinktime =
169426594249SQin Michael Li 		    (sc->sc_ic.ic_state == IEEE80211_S_RUN ? 4:2);
169526594249SQin Michael Li 		break;
169626594249SQin Michael Li 	case URTW_LED_CTL_LINK:
169726594249SQin Michael Li 		sc->sc_gpio_ledstate = URTW_LED_ON;
169826594249SQin Michael Li 		break;
169926594249SQin Michael Li 	default:
170026594249SQin Michael Li 		cmn_err(CE_CONT, "unsupported LED mode 0x%x", mode);
170126594249SQin Michael Li 		/* never reach  */
170226594249SQin Michael Li 	}
170326594249SQin Michael Li 
170426594249SQin Michael Li 	switch (sc->sc_gpio_ledstate) {
170526594249SQin Michael Li 	case URTW_LED_ON:
170626594249SQin Michael Li 		if (sc->sc_gpio_ledinprogress != 0)
170726594249SQin Michael Li 			break;
170826594249SQin Michael Li 		(void) urtw_led_on(sc, URTW_LED_GPIO);
170926594249SQin Michael Li 		break;
171026594249SQin Michael Li 	case URTW_LED_BLINK_NORMAL:
171126594249SQin Michael Li 		if (sc->sc_gpio_ledinprogress != 0)
171226594249SQin Michael Li 			break;
171326594249SQin Michael Li 		sc->sc_gpio_ledinprogress = 1;
171426594249SQin Michael Li 		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
171526594249SQin Michael Li 		    URTW_LED_OFF : URTW_LED_ON;
171626594249SQin Michael Li 		URTW_LEDLOCK(sc);
171726594249SQin Michael Li 		if (sc->sc_led_ch == 0) {
171826594249SQin Michael Li 			URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
171926594249SQin Michael Li 			    "urtw_led_mode0: restart led timer\n"));
172026594249SQin Michael Li 			sc->sc_led_ch = timeout(urtw_led_launch,
172126594249SQin Michael Li 			    (void *)sc,
172226594249SQin Michael Li 			    drv_usectohz((sc->sc_ic.ic_state ==
172326594249SQin Michael Li 			    IEEE80211_S_RUN) ?
172426594249SQin Michael Li 			    URTW_LED_LINKON_BLINK :
172526594249SQin Michael Li 			    URTW_LED_LINKOFF_BLINK));
172626594249SQin Michael Li 			sc->sc_gpio_ledinprogress = 0;
172726594249SQin Michael Li 		}
172826594249SQin Michael Li 		URTW_LEDUNLOCK(sc);
172926594249SQin Michael Li 		break;
173026594249SQin Michael Li 	case URTW_LED_POWER_ON_BLINK:
173126594249SQin Michael Li 		(void) urtw_led_on(sc, URTW_LED_GPIO);
173226594249SQin Michael Li 		urtw_delay_ms(100);
173326594249SQin Michael Li 		(void) urtw_led_off(sc, URTW_LED_GPIO);
173426594249SQin Michael Li 		break;
173526594249SQin Michael Li 	default:
173626594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
173726594249SQin Michael Li 		    "urtw_led_mode0: unknown LED status 0x%x",
173826594249SQin Michael Li 		    sc->sc_gpio_ledstate));
173926594249SQin Michael Li 	}
174026594249SQin Michael Li 	return (0);
174126594249SQin Michael Li }
174226594249SQin Michael Li 
174326594249SQin Michael Li static usbd_status
urtw_led_mode1(struct urtw_softc * sc,int mode)174426594249SQin Michael Li urtw_led_mode1(struct urtw_softc *sc, int mode)
174526594249SQin Michael Li {
174626594249SQin Michael Li 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
174726594249SQin Michael Li 	return (USBD_INVAL);
174826594249SQin Michael Li }
174926594249SQin Michael Li 
175026594249SQin Michael Li static usbd_status
urtw_led_mode2(struct urtw_softc * sc,int mode)175126594249SQin Michael Li urtw_led_mode2(struct urtw_softc *sc, int mode)
175226594249SQin Michael Li {
175326594249SQin Michael Li 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
175426594249SQin Michael Li 	return (USBD_INVAL);
175526594249SQin Michael Li }
175626594249SQin Michael Li 
175726594249SQin Michael Li static usbd_status
urtw_led_mode3(struct urtw_softc * sc,int mode)175826594249SQin Michael Li urtw_led_mode3(struct urtw_softc *sc, int mode)
175926594249SQin Michael Li {
176026594249SQin Michael Li 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
176126594249SQin Michael Li 	return (USBD_INVAL);
176226594249SQin Michael Li }
176326594249SQin Michael Li 
176426594249SQin Michael Li static usbd_status
urtw_led_blink(struct urtw_softc * sc)176526594249SQin Michael Li urtw_led_blink(struct urtw_softc *sc)
176626594249SQin Michael Li {
176726594249SQin Michael Li 	uint8_t ing = 0;
176826594249SQin Michael Li 
176926594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
177026594249SQin Michael Li 	    "urtw_led_blink: gpio_blinkstate %d\n",
177126594249SQin Michael Li 	    sc->sc_gpio_blinkstate));
177226594249SQin Michael Li 	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
177326594249SQin Michael Li 		(void) urtw_led_on(sc, URTW_LED_GPIO);
177426594249SQin Michael Li 	else
177526594249SQin Michael Li 		(void) urtw_led_off(sc, URTW_LED_GPIO);
177626594249SQin Michael Li 	sc->sc_gpio_blinktime--;
177726594249SQin Michael Li 	if (sc->sc_gpio_blinktime == 0)
177826594249SQin Michael Li 		ing = 1;
177926594249SQin Michael Li 	else {
178026594249SQin Michael Li 		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
178126594249SQin Michael Li 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
178226594249SQin Michael Li 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
178326594249SQin Michael Li 			ing = 1;
178426594249SQin Michael Li 	}
178526594249SQin Michael Li 	if (ing == 1) {
178626594249SQin Michael Li 		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
178726594249SQin Michael Li 		    sc->sc_gpio_ledon == 0)
178826594249SQin Michael Li 			(void) urtw_led_on(sc, URTW_LED_GPIO);
178926594249SQin Michael Li 		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
179026594249SQin Michael Li 		    sc->sc_gpio_ledon == 1)
179126594249SQin Michael Li 			(void) urtw_led_off(sc, URTW_LED_GPIO);
179226594249SQin Michael Li 
179326594249SQin Michael Li 		sc->sc_gpio_blinktime = 0;
179426594249SQin Michael Li 		sc->sc_gpio_ledinprogress = 0;
179526594249SQin Michael Li 		return (0);
179626594249SQin Michael Li 	}
179726594249SQin Michael Li 
179826594249SQin Michael Li 	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
179926594249SQin Michael Li 	    URTW_LED_ON : URTW_LED_OFF;
180026594249SQin Michael Li 
180126594249SQin Michael Li 	switch (sc->sc_gpio_ledstate) {
180226594249SQin Michael Li 	case URTW_LED_BLINK_NORMAL:
180326594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
180426594249SQin Michael Li 		    "URTW_LED_BLINK_NORMAL\n"));
180526594249SQin Michael Li 		return (1);
180626594249SQin Michael Li 	default:
180726594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
180826594249SQin Michael Li 		    "unknown LED status 0x%x", sc->sc_gpio_ledstate));
180926594249SQin Michael Li 	}
181026594249SQin Michael Li 	return (0);
181126594249SQin Michael Li }
181226594249SQin Michael Li 
181326594249SQin Michael Li static usbd_status
urtw_led_ctl(struct urtw_softc * sc,int mode)181426594249SQin Michael Li urtw_led_ctl(struct urtw_softc *sc, int mode)
181526594249SQin Michael Li {
181626594249SQin Michael Li 	usbd_status error = 0;
181726594249SQin Michael Li 
181826594249SQin Michael Li 	switch (sc->sc_strategy) {
181926594249SQin Michael Li 	case URTW_SW_LED_MODE0:
182026594249SQin Michael Li 		error = urtw_led_mode0(sc, mode);
182126594249SQin Michael Li 		break;
182226594249SQin Michael Li 	case URTW_SW_LED_MODE1:
182326594249SQin Michael Li 		error = urtw_led_mode1(sc, mode);
182426594249SQin Michael Li 		break;
182526594249SQin Michael Li 	case URTW_SW_LED_MODE2:
182626594249SQin Michael Li 		error = urtw_led_mode2(sc, mode);
182726594249SQin Michael Li 		break;
182826594249SQin Michael Li 	case URTW_SW_LED_MODE3:
182926594249SQin Michael Li 		error = urtw_led_mode3(sc, mode);
183026594249SQin Michael Li 		break;
183126594249SQin Michael Li 	default:
183226594249SQin Michael Li 		cmn_err(CE_CONT, "unsupported LED mode %d\n", sc->sc_strategy);
183326594249SQin Michael Li 		/* never reach  */
183426594249SQin Michael Li 		return (-1);
183526594249SQin Michael Li 	}
183626594249SQin Michael Li 
183726594249SQin Michael Li 	return (error);
183826594249SQin Michael Li }
183926594249SQin Michael Li 
184026594249SQin Michael Li static usbd_status
urtw_update_msr(struct urtw_softc * sc,int nstate)184126594249SQin Michael Li urtw_update_msr(struct urtw_softc *sc, int nstate)
184226594249SQin Michael Li {
184326594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
184426594249SQin Michael Li 	uint8_t data;
184526594249SQin Michael Li 	usbd_status error;
184626594249SQin Michael Li 
1847dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_MSR, &data, 0))
184826594249SQin Michael Li 		goto fail;
184926594249SQin Michael Li 	data &= ~URTW_MSR_LINK_MASK;
185026594249SQin Michael Li 
1851dfa03ef6SQin Michael Li 	/* Should always be set. */
1852dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187B)
1853dfa03ef6SQin Michael Li 		data |= URTW_MSR_LINK_ENEDCA;
1854dfa03ef6SQin Michael Li 
185526594249SQin Michael Li 	if (nstate == IEEE80211_S_RUN) {
185626594249SQin Michael Li 		switch (ic->ic_opmode) {
185726594249SQin Michael Li 		case IEEE80211_M_STA:
185826594249SQin Michael Li 		case IEEE80211_M_MONITOR:
185926594249SQin Michael Li 			data |= URTW_MSR_LINK_STA;
186026594249SQin Michael Li 			break;
186126594249SQin Michael Li 		case IEEE80211_M_IBSS:
186226594249SQin Michael Li 			data |= URTW_MSR_LINK_ADHOC;
186326594249SQin Michael Li 			break;
186426594249SQin Michael Li 		case IEEE80211_M_HOSTAP:
186526594249SQin Michael Li 			data |= URTW_MSR_LINK_HOSTAP;
186626594249SQin Michael Li 			break;
186726594249SQin Michael Li 		default:
186826594249SQin Michael Li 			cmn_err(CE_CONT, "unsupported operation mode 0x%x\n",
186926594249SQin Michael Li 			    ic->ic_opmode);
187026594249SQin Michael Li 			return (-1);
187126594249SQin Michael Li 		}
187226594249SQin Michael Li 	} else
187326594249SQin Michael Li 		data |= URTW_MSR_LINK_NONE;
187426594249SQin Michael Li 
1875dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_MSR, data, 0);
187626594249SQin Michael Li fail:
187726594249SQin Michael Li 	return (error);
187826594249SQin Michael Li }
187926594249SQin Michael Li 
188026594249SQin Michael Li static uint16_t
urtw_rate2rtl(int rate)188126594249SQin Michael Li urtw_rate2rtl(int rate)
188226594249SQin Michael Li {
188326594249SQin Michael Li #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
188426594249SQin Michael Li 	int i;
188526594249SQin Michael Li 
188626594249SQin Michael Li 	for (i = 0; i < N(urtw_ratetable); i++) {
188726594249SQin Michael Li 		if (rate == urtw_ratetable[i].reg)
188826594249SQin Michael Li 			return (urtw_ratetable[i].val);
188926594249SQin Michael Li 	}
189026594249SQin Michael Li 	return (3);
189126594249SQin Michael Li #undef N
189226594249SQin Michael Li }
189326594249SQin Michael Li 
189426594249SQin Michael Li static uint16_t
urtw_rtl2rate(int rate)189526594249SQin Michael Li urtw_rtl2rate(int rate)
189626594249SQin Michael Li {
189726594249SQin Michael Li #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
189826594249SQin Michael Li 	int i;
189926594249SQin Michael Li 
190026594249SQin Michael Li 	for (i = 0; i < N(urtw_ratetable); i++) {
190126594249SQin Michael Li 		if (rate == urtw_ratetable[i].val)
190226594249SQin Michael Li 			return (urtw_ratetable[i].reg);
190326594249SQin Michael Li 	}
190426594249SQin Michael Li 
190526594249SQin Michael Li 	return (0);
190626594249SQin Michael Li #undef N
190726594249SQin Michael Li }
190826594249SQin Michael Li 
190926594249SQin Michael Li static usbd_status
urtw_set_rate(struct urtw_softc * sc)191026594249SQin Michael Li urtw_set_rate(struct urtw_softc *sc)
191126594249SQin Michael Li {
191226594249SQin Michael Li 	int i, basic_rate, min_rr_rate, max_rr_rate;
191326594249SQin Michael Li 	uint16_t data;
191426594249SQin Michael Li 	usbd_status error;
191526594249SQin Michael Li 
191626594249SQin Michael Li 	basic_rate = urtw_rate2rtl(48);
191726594249SQin Michael Li 	min_rr_rate = urtw_rate2rtl(12);
191826594249SQin Michael Li 	max_rr_rate = urtw_rate2rtl(48);
191926594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_RESP_RATE,
192026594249SQin Michael Li 	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
1921dfa03ef6SQin Michael Li 	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT, 0))
192226594249SQin Michael Li 		goto fail;
192326594249SQin Michael Li 
1924dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
192526594249SQin Michael Li 		goto fail;
192626594249SQin Michael Li 	data &= ~URTW_BRSR_MBR_8185;
192726594249SQin Michael Li 
192826594249SQin Michael Li 	for (i = 0; i <= basic_rate; i++)
192926594249SQin Michael Li 		data |= (1 << i);
193026594249SQin Michael Li 
1931dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_BRSR, data, 0);
193226594249SQin Michael Li fail:
193326594249SQin Michael Li 	return (error);
193426594249SQin Michael Li }
193526594249SQin Michael Li 
193626594249SQin Michael Li static usbd_status
urtw_intr_enable(struct urtw_softc * sc)193726594249SQin Michael Li urtw_intr_enable(struct urtw_softc *sc)
193826594249SQin Michael Li {
193926594249SQin Michael Li 	usbd_status error;
194026594249SQin Michael Li 
1941dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0xffff, 0);
194226594249SQin Michael Li 	return (error);
194326594249SQin Michael Li }
194426594249SQin Michael Li 
194526594249SQin Michael Li static usbd_status
urtw_rx_setconf(struct urtw_softc * sc)194626594249SQin Michael Li urtw_rx_setconf(struct urtw_softc *sc)
194726594249SQin Michael Li {
194826594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
194926594249SQin Michael Li 	uint32_t data, a, b;
195026594249SQin Michael Li 	usbd_status error;
195126594249SQin Michael Li 
1952dfa03ef6SQin Michael Li 	if (urtw_read32_c(sc, URTW_RX, &data, 0))
195326594249SQin Michael Li 		goto fail;
195426594249SQin Michael Li 	data = data &~ URTW_RX_FILTER_MASK;
195526594249SQin Michael Li 	data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
195626594249SQin Michael Li 	data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
195726594249SQin Michael Li 
195826594249SQin Michael Li 	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
195926594249SQin Michael Li 		data = data | URTW_RX_FILTER_ICVERR;
196026594249SQin Michael Li 		data = data | URTW_RX_FILTER_PWR;
196126594249SQin Michael Li 	}
196226594249SQin Michael Li 	if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
196326594249SQin Michael Li 		data = data | URTW_RX_FILTER_CRCERR;
196426594249SQin Michael Li 	data = data | URTW_RX_FILTER_NICMAC;
196526594249SQin Michael Li 	data = data | URTW_RX_CHECK_BSSID;
196626594249SQin Michael Li 	data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
196726594249SQin Michael Li 	data = data | URTW_RX_FIFO_THRESHOLD_NONE | URTW_RX_AUTORESETPHY;
196826594249SQin Michael Li 	data = data &~ URTW_MAX_RX_DMA_MASK;
196926594249SQin Michael Li 	a = URTW_MAX_RX_DMA_2048;
197026594249SQin Michael Li 	b = 0x80000000;
197126594249SQin Michael Li 	data = data | a | b;
197226594249SQin Michael Li 
1973dfa03ef6SQin Michael Li 	error = urtw_write32_c(sc, URTW_RX, data, 0);
197426594249SQin Michael Li fail:
197526594249SQin Michael Li 	return (error);
197626594249SQin Michael Li }
197726594249SQin Michael Li 
197826594249SQin Michael Li static usbd_status
urtw_rx_enable(struct urtw_softc * sc)197926594249SQin Michael Li urtw_rx_enable(struct urtw_softc *sc)
198026594249SQin Michael Li {
198126594249SQin Michael Li 	int i;
198226594249SQin Michael Li 	usbd_status error;
198326594249SQin Michael Li 	uint8_t data;
198426594249SQin Michael Li 
198526594249SQin Michael Li 	sc->rx_queued = 0;
198626594249SQin Michael Li 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
198726594249SQin Michael Li 		if (urtw_rx_start(sc) != 0) {
198826594249SQin Michael Li 			return (USB_FAILURE);
198926594249SQin Michael Li 		}
199026594249SQin Michael Li 	}
199126594249SQin Michael Li 
199226594249SQin Michael Li 	error = urtw_rx_setconf(sc);
199326594249SQin Michael Li 	if (error != 0)
199426594249SQin Michael Li 		goto fail;
199526594249SQin Michael Li 
1996dfa03ef6SQin Michael Li 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
199726594249SQin Michael Li 		goto fail;
1998dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE, 0);
199926594249SQin Michael Li fail:
200026594249SQin Michael Li 	return (error);
200126594249SQin Michael Li }
200226594249SQin Michael Li 
2003dfa03ef6SQin Michael Li void
urtw_tx_enable(struct urtw_softc * sc)200426594249SQin Michael Li urtw_tx_enable(struct urtw_softc *sc)
200526594249SQin Michael Li {
200626594249SQin Michael Li 	uint8_t data8;
200726594249SQin Michael Li 	uint32_t data;
200826594249SQin Michael Li 
2009dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
2010dfa03ef6SQin Michael Li 		(void) urtw_read8_c(sc, URTW_CW_CONF, &data8, 0);
2011dfa03ef6SQin Michael Li 		data8 &= ~(URTW_CW_CONF_PERPACKET_CW |
2012dfa03ef6SQin Michael Li 		    URTW_CW_CONF_PERPACKET_RETRY);
2013dfa03ef6SQin Michael Li 		(void) urtw_write8_c(sc, URTW_CW_CONF, data8, 0);
2014dfa03ef6SQin Michael Li 		(void) urtw_read8_c(sc, URTW_TX_AGC_CTL, &data8, 0);
201526594249SQin Michael Li 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
201626594249SQin Michael Li 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
201726594249SQin Michael Li 		data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
2018dfa03ef6SQin Michael Li 		(void) urtw_write8_c(sc, URTW_TX_AGC_CTL, data8, 0);
201926594249SQin Michael Li 
2020dfa03ef6SQin Michael Li 		(void) urtw_read32_c(sc, URTW_TX_CONF, &data, 0);
202126594249SQin Michael Li 		data &= ~URTW_TX_LOOPBACK_MASK;
202226594249SQin Michael Li 		data |= URTW_TX_LOOPBACK_NONE;
202326594249SQin Michael Li 		data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
202426594249SQin Michael Li 		data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
202526594249SQin Michael Li 		data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
202626594249SQin Michael Li 		data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
2027dfa03ef6SQin Michael Li 		data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
202826594249SQin Michael Li 		data &= ~URTW_TX_SWPLCPLEN;
202926594249SQin Michael Li 		data |= URTW_TX_NOICV;
2030dfa03ef6SQin Michael Li 		(void) urtw_write32_c(sc, URTW_TX_CONF, data, 0);
2031dfa03ef6SQin Michael Li 	} else {
2032dfa03ef6SQin Michael Li 		data = URTW_TX_DURPROCMODE | URTW_TX_DISREQQSIZE |
2033dfa03ef6SQin Michael Li 		    URTW_TX_MXDMA_2048 | URTW_TX_SHORTRETRY |
2034dfa03ef6SQin Michael Li 		    URTW_TX_LONGRETRY;
2035dfa03ef6SQin Michael Li 		(void) urtw_write32_c(sc, URTW_TX_CONF, data, 0);
2036dfa03ef6SQin Michael Li 	}
2037dfa03ef6SQin Michael Li 
2038dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CMD, &data8, 0);
2039dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE, 0);
204026594249SQin Michael Li }
204126594249SQin Michael Li 
204226594249SQin Michael Li static int
urtw_8187_init(void * arg)2043dfa03ef6SQin Michael Li urtw_8187_init(void *arg)
204426594249SQin Michael Li {
204526594249SQin Michael Li 	struct urtw_softc *sc = arg;
204626594249SQin Michael Li 	usbd_status error;
2047dfa03ef6SQin Michael Li 	struct urtw_rf *rf = &sc->sc_rf;
2048dfa03ef6SQin Michael Li 	int i;
204926594249SQin Michael Li 
205026594249SQin Michael Li 	urtw_stop(sc);
205126594249SQin Michael Li 	URTW_LOCK(sc);
2052dfa03ef6SQin Michael Li 	error = urtw_8187_reset(sc);
2053dfa03ef6SQin Michael Li 	if (error)
2054dfa03ef6SQin Michael Li 		goto fail;
2055dfa03ef6SQin Michael Li 
2056dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x85, 0, 0);
2057dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_GPIO, 0, 0);
2058dfa03ef6SQin Michael Li 
2059dfa03ef6SQin Michael Li 	/* for led */
2060dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x85, 4, 0);
2061dfa03ef6SQin Michael Li 	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
206226594249SQin Michael Li 	if (error != 0)
206326594249SQin Michael Li 		goto fail;
2064dfa03ef6SQin Michael Li 
2065dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2066dfa03ef6SQin Michael Li 	if (error)
2067dfa03ef6SQin Michael Li 		goto fail;
2068dfa03ef6SQin Michael Li 
2069dfa03ef6SQin Michael Li 	/* applying MAC address again.  */
2070dfa03ef6SQin Michael Li 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
2071dfa03ef6SQin Michael Li 		(void) urtw_write8_c(sc, URTW_MAC0 + i,
2072dfa03ef6SQin Michael Li 		    sc->sc_ic.ic_macaddr[i], 0);
2073dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2074dfa03ef6SQin Michael Li 	if (error)
2075dfa03ef6SQin Michael Li 		goto fail;
2076dfa03ef6SQin Michael Li 
2077dfa03ef6SQin Michael Li 	error = urtw_update_msr(sc, IEEE80211_S_INIT);
2078dfa03ef6SQin Michael Li 	if (error)
2079dfa03ef6SQin Michael Li 		goto fail;
2080dfa03ef6SQin Michael Li 
2081dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_INT_TIMEOUT, 0, 0);
2082dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_WPA_CONFIG, 0, 0);
2083dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_RATE_FALLBACK, 0x81, 0);
2084dfa03ef6SQin Michael Li 	error = urtw_set_rate(sc);
2085dfa03ef6SQin Michael Li 	if (error != 0)
2086dfa03ef6SQin Michael Li 		goto fail;
2087dfa03ef6SQin Michael Li 
2088dfa03ef6SQin Michael Li 	error = rf->init(rf);
2089dfa03ef6SQin Michael Li 	if (error != 0)
2090dfa03ef6SQin Michael Li 		goto fail;
2091dfa03ef6SQin Michael Li 	if (rf->set_sens != NULL)
2092dfa03ef6SQin Michael Li 		rf->set_sens(rf);
2093dfa03ef6SQin Michael Li 
2094dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x5e, 1, 0);
2095dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0xfe, 0x10, 0);
2096dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TALLY_SEL, 0x80, 0);
2097dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0xff, 0x60, 0);
2098dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x5e, 0, 0);
2099dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x85, 4, 0);
2100dfa03ef6SQin Michael Li 
2101dfa03ef6SQin Michael Li 	error = urtw_intr_enable(sc);
2102dfa03ef6SQin Michael Li 	if (error != 0)
2103dfa03ef6SQin Michael Li 		goto fail;
2104dfa03ef6SQin Michael Li 
2105dfa03ef6SQin Michael Li 	error = urtw_open_pipes(sc);
210626594249SQin Michael Li 	if (error != 0)
210726594249SQin Michael Li 		goto fail;
210826594249SQin Michael Li 	sc->sc_tx_low_queued = 0;
210926594249SQin Michael Li 	sc->sc_tx_normal_queued = 0;
211026594249SQin Michael Li 	error = urtw_rx_enable(sc);
211126594249SQin Michael Li 	if (error != 0)
211226594249SQin Michael Li 		goto fail;
2113dfa03ef6SQin Michael Li 	urtw_tx_enable(sc);
211426594249SQin Michael Li 
211526594249SQin Michael Li 	if (error == 0) {
211626594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev,
2117dfa03ef6SQin Michael Li 		    CE_CONT, "urtw_8187_init: succesfully done\n"));
211826594249SQin Michael Li 		sc->sc_flags |= URTW_FLAG_RUNNING;
211926594249SQin Michael Li 		URTW_UNLOCK(sc);
212026594249SQin Michael Li 		return (error);
212126594249SQin Michael Li 	}
212226594249SQin Michael Li 
212326594249SQin Michael Li fail:
212426594249SQin Michael Li 	URTW_UNLOCK(sc);
212526594249SQin Michael Li 	urtw_stop(sc);
2126dfa03ef6SQin Michael Li 	return (EIO);
212726594249SQin Michael Li }
212826594249SQin Michael Li 
212926594249SQin Michael Li 
213026594249SQin Michael Li static usbd_status
urtw_8225_usb_init(struct urtw_softc * sc)213126594249SQin Michael Li urtw_8225_usb_init(struct urtw_softc *sc)
213226594249SQin Michael Li {
213326594249SQin Michael Li 	uint8_t data;
213426594249SQin Michael Li 	usbd_status error;
213526594249SQin Michael Li 
2136dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 0, 0))
213726594249SQin Michael Li 		goto fail;
2138dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_GPIO, 0, 0))
213926594249SQin Michael Li 		goto fail;
214026594249SQin Michael Li 	if (error = urtw_read8e(sc, 0x53, &data))
214126594249SQin Michael Li 		goto fail;
214226594249SQin Michael Li 	if (error = urtw_write8e(sc, 0x53, data | (1 << 7)))
214326594249SQin Michael Li 		goto fail;
2144dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 4, 0))
214526594249SQin Michael Li 		goto fail;
2146dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_GPIO, 0x20, 0))
214726594249SQin Michael Li 		goto fail;
2148dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_GP_ENABLE, 0, 0))
214926594249SQin Michael Li 		goto fail;
2150dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x80, 0))
215126594249SQin Michael Li 		goto fail;
2152dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x80, 0))
215326594249SQin Michael Li 		goto fail;
2154dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x80, 0);
215526594249SQin Michael Li 
215626594249SQin Michael Li 	urtw_delay_ms(100);
215726594249SQin Michael Li fail:
215826594249SQin Michael Li 	return (error);
215926594249SQin Michael Li }
216026594249SQin Michael Li 
216126594249SQin Michael Li static usbd_status
urtw_8185_rf_pins_enable(struct urtw_softc * sc)216226594249SQin Michael Li urtw_8185_rf_pins_enable(struct urtw_softc *sc)
216326594249SQin Michael Li {
216426594249SQin Michael Li 	usbd_status error = 0;
216526594249SQin Michael Li 
2166dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x1ff7, 0);
216726594249SQin Michael Li 	return (error);
216826594249SQin Michael Li }
216926594249SQin Michael Li 
217026594249SQin Michael Li static usbd_status
urtw_8187_write_phy(struct urtw_softc * sc,uint8_t addr,uint32_t data)217126594249SQin Michael Li urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
217226594249SQin Michael Li {
217326594249SQin Michael Li 	uint32_t phyw;
217426594249SQin Michael Li 	usbd_status error;
217526594249SQin Michael Li 
217626594249SQin Michael Li 	phyw = ((data << 8) | (addr | 0x80));
2177dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, 0x7f, ((phyw & 0xff000000) >> 24), 0))
217826594249SQin Michael Li 		goto fail;
2179dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, 0x7e, ((phyw & 0x00ff0000) >> 16), 0))
218026594249SQin Michael Li 		goto fail;
2181dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, 0x7d, ((phyw & 0x0000ff00) >> 8), 0))
218226594249SQin Michael Li 		goto fail;
2183dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, 0x7c, (phyw & 0x000000ff), 0);
2184dfa03ef6SQin Michael Li 	/*
2185dfa03ef6SQin Michael Li 	 * Delay removed from 8185 to 8187.
2186dfa03ef6SQin Michael Li 	 * usbd_delay_ms(sc->sc_udev, 1);
2187dfa03ef6SQin Michael Li 	 */
218826594249SQin Michael Li fail:
218926594249SQin Michael Li 	return (error);
219026594249SQin Michael Li }
219126594249SQin Michael Li 
219226594249SQin Michael Li static usbd_status
urtw_8187_write_phy_ofdm_c(struct urtw_softc * sc,uint8_t addr,uint32_t data)219326594249SQin Michael Li urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
219426594249SQin Michael Li {
219526594249SQin Michael Li 	data = data & 0xff;
219626594249SQin Michael Li 	return (urtw_8187_write_phy(sc, addr, data));
219726594249SQin Michael Li }
219826594249SQin Michael Li 
219926594249SQin Michael Li static usbd_status
urtw_8187_write_phy_cck_c(struct urtw_softc * sc,uint8_t addr,uint32_t data)220026594249SQin Michael Li urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
220126594249SQin Michael Li {
220226594249SQin Michael Li 	data = data & 0xff;
220326594249SQin Michael Li 	return (urtw_8187_write_phy(sc, addr, (data | 0x10000)));
220426594249SQin Michael Li }
220526594249SQin Michael Li 
220626594249SQin Michael Li static usbd_status
urtw_8225_setgain(struct urtw_softc * sc,int16_t gain)220726594249SQin Michael Li urtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
220826594249SQin Michael Li {
220926594249SQin Michael Li 	usbd_status error;
221026594249SQin Michael Li 
221126594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d,
221226594249SQin Michael Li 	    urtw_8225_gain[gain * 4]))
221326594249SQin Michael Li 		goto fail;
221426594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b,
221526594249SQin Michael Li 	    urtw_8225_gain[gain * 4 + 2]))
221626594249SQin Michael Li 		goto fail;
221726594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d,
221826594249SQin Michael Li 	    urtw_8225_gain[gain * 4 + 3]))
221926594249SQin Michael Li 		goto fail;
222026594249SQin Michael Li 	error = urtw_8187_write_phy_ofdm_c(sc, 0x23,
222126594249SQin Michael Li 	    urtw_8225_gain[gain * 4 + 1]);
222226594249SQin Michael Li fail:
222326594249SQin Michael Li 	return (error);
222426594249SQin Michael Li }
222526594249SQin Michael Li 
222626594249SQin Michael Li static usbd_status
urtw_8225_set_txpwrlvl(struct urtw_softc * sc,int chan)222726594249SQin Michael Li urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
222826594249SQin Michael Li {
222926594249SQin Michael Li 	int i, idx, set;
223026594249SQin Michael Li 	uint8_t *cck_pwltable;
223126594249SQin Michael Li 	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
223226594249SQin Michael Li 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
223326594249SQin Michael Li 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
223426594249SQin Michael Li 	usbd_status error;
223526594249SQin Michael Li 
223626594249SQin Michael Li 	cck_pwrlvl_max = 11;
223726594249SQin Michael Li 	ofdm_pwrlvl_max = 25;	/* 12 -> 25  */
223826594249SQin Michael Li 	ofdm_pwrlvl_min = 10;
223926594249SQin Michael Li 
224026594249SQin Michael Li 	/* CCK power setting */
224126594249SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
224226594249SQin Michael Li 	    cck_pwrlvl_max : cck_pwrlvl;
224326594249SQin Michael Li 	idx = cck_pwrlvl % 6;
224426594249SQin Michael Li 	set = cck_pwrlvl / 6;
224526594249SQin Michael Li 	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
224626594249SQin Michael Li 	    urtw_8225_txpwr_cck;
224726594249SQin Michael Li 
224826594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2249dfa03ef6SQin Michael Li 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1, 0))
225026594249SQin Michael Li 		goto fail;
225126594249SQin Michael Li 	for (i = 0; i < 8; i++) {
225226594249SQin Michael Li 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
225326594249SQin Michael Li 		    cck_pwltable[idx * 8 + i]))
225426594249SQin Michael Li 			goto fail;
225526594249SQin Michael Li 	}
225626594249SQin Michael Li 	urtw_delay_ms(1);
225726594249SQin Michael Li 	/* OFDM power setting */
225826594249SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
225926594249SQin Michael Li 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
226026594249SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
226126594249SQin Michael Li 	idx = ofdm_pwrlvl % 6;
226226594249SQin Michael Li 	set = ofdm_pwrlvl / 6;
226326594249SQin Michael Li 
2264dfa03ef6SQin Michael Li 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
226526594249SQin Michael Li 	if (error)
226626594249SQin Michael Li 		goto fail;
226726594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
226826594249SQin Michael Li 		goto fail;
226926594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0))
227026594249SQin Michael Li 		goto fail;
227126594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0))
227226594249SQin Michael Li 		goto fail;
227326594249SQin Michael Li 
227426594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2275dfa03ef6SQin Michael Li 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1, 0))
227626594249SQin Michael Li 		goto fail;
227726594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x5,
227826594249SQin Michael Li 	    urtw_8225_txpwr_ofdm[idx]))
227926594249SQin Michael Li 		goto fail;
228026594249SQin Michael Li 	error = urtw_8187_write_phy_ofdm_c(sc, 0x7,
228126594249SQin Michael Li 	    urtw_8225_txpwr_ofdm[idx]);
228226594249SQin Michael Li 	urtw_delay_ms(1);
228326594249SQin Michael Li fail:
228426594249SQin Michael Li 	return (error);
228526594249SQin Michael Li }
228626594249SQin Michael Li 
228726594249SQin Michael Li static usbd_status
urtw_8185_tx_antenna(struct urtw_softc * sc,uint8_t ant)228826594249SQin Michael Li urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
228926594249SQin Michael Li {
229026594249SQin Michael Li 	usbd_status error;
229126594249SQin Michael Li 
2292dfa03ef6SQin Michael Li 	error = urtw_write8_c(sc, URTW_TX_ANTENNA, ant, 0);
229326594249SQin Michael Li 	urtw_delay_ms(1);
229426594249SQin Michael Li 	return (error);
229526594249SQin Michael Li }
229626594249SQin Michael Li 
229726594249SQin Michael Li static usbd_status
urtw_8225_rf_init(struct urtw_rf * rf)2298dfa03ef6SQin Michael Li urtw_8225_rf_init(struct urtw_rf *rf)
229926594249SQin Michael Li {
230026594249SQin Michael Li #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
230126594249SQin Michael Li 	int i;
230226594249SQin Michael Li 	uint16_t data;
230326594249SQin Michael Li 	usbd_status error;
2304dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
230526594249SQin Michael Li 
2306dfa03ef6SQin Michael Li 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
230726594249SQin Michael Li 	if (error)
230826594249SQin Michael Li 		goto fail;
230926594249SQin Michael Li 
231026594249SQin Michael Li 	if (error = urtw_8225_usb_init(sc))
231126594249SQin Michael Li 		goto fail;
2312dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008, 0))
231326594249SQin Michael Li 		goto fail;
2314dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
231526594249SQin Michael Li 		goto fail;
2316dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff, 0))
231726594249SQin Michael Li 		goto fail;
2318dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044, 0))
231926594249SQin Michael Li 		goto fail;
232026594249SQin Michael Li 
232126594249SQin Michael Li 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
232226594249SQin Michael Li 		goto fail;
2323dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44, 0))
232426594249SQin Michael Li 		goto fail;
232526594249SQin Michael Li 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
232626594249SQin Michael Li 		goto fail;
232726594249SQin Michael Li 	if (error = urtw_8185_rf_pins_enable(sc))
232826594249SQin Michael Li 		goto fail;
232926594249SQin Michael Li 	urtw_delay_ms(100);
233026594249SQin Michael Li 
233126594249SQin Michael Li 	for (i = 0; i < N(urtw_8225_rf_part1); i++) {
233226594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, urtw_8225_rf_part1[i].reg,
233326594249SQin Michael Li 		    urtw_8225_rf_part1[i].val))
233426594249SQin Michael Li 			goto fail;
233526594249SQin Michael Li 		urtw_delay_ms(1);
233626594249SQin Michael Li 	}
233726594249SQin Michael Li 	urtw_delay_ms(50);
233826594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
233926594249SQin Michael Li 		goto fail;
234026594249SQin Michael Li 	urtw_delay_ms(50);
234126594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
234226594249SQin Michael Li 		goto fail;
234326594249SQin Michael Li 	urtw_delay_ms(50);
234426594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x127))
234526594249SQin Michael Li 		goto fail;
234626594249SQin Michael Li 
234726594249SQin Michael Li 	for (i = 0; i < 95; i++) {
234826594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
234926594249SQin Michael Li 			goto fail;
235026594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225_rxgain[i]))
235126594249SQin Michael Li 			goto fail;
235226594249SQin Michael Li 	}
235326594249SQin Michael Li 
235426594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x27))
235526594249SQin Michael Li 		goto fail;
235626594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x22f))
235726594249SQin Michael Li 		goto fail;
235826594249SQin Michael Li 
235926594249SQin Michael Li 	for (i = 0; i < 128; i++) {
236026594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
236126594249SQin Michael Li 		    urtw_8225_agc[i]))
236226594249SQin Michael Li 			goto fail;
236326594249SQin Michael Li 		urtw_delay_ms(1);
236426594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
236526594249SQin Michael Li 		    (uint8_t)i + 0x80))
236626594249SQin Michael Li 			goto fail;
236726594249SQin Michael Li 		urtw_delay_ms(1);
236826594249SQin Michael Li 	}
236926594249SQin Michael Li 
237026594249SQin Michael Li 	for (i = 0; i < N(urtw_8225_rf_part2); i++) {
237126594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc,
237226594249SQin Michael Li 		    urtw_8225_rf_part2[i].reg,
237326594249SQin Michael Li 		    urtw_8225_rf_part2[i].val))
237426594249SQin Michael Li 			goto fail;
237526594249SQin Michael Li 		urtw_delay_ms(1);
237626594249SQin Michael Li 	}
237726594249SQin Michael Li 	error = urtw_8225_setgain(sc, 4);
237826594249SQin Michael Li 	if (error)
237926594249SQin Michael Li 		goto fail;
238026594249SQin Michael Li 
238126594249SQin Michael Li 	for (i = 0; i < N(urtw_8225_rf_part3); i++) {
238226594249SQin Michael Li 		if (error = urtw_8187_write_phy_cck_c(sc,
238326594249SQin Michael Li 		    urtw_8225_rf_part3[i].reg,
238426594249SQin Michael Li 		    urtw_8225_rf_part3[i].val))
238526594249SQin Michael Li 			goto fail;
238626594249SQin Michael Li 		urtw_delay_ms(1);
238726594249SQin Michael Li 	}
238826594249SQin Michael Li 
2389dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, 0x5b, 0x0d, 0))
239026594249SQin Michael Li 		goto fail;
239126594249SQin Michael Li 	if (error = urtw_8225_set_txpwrlvl(sc, 1))
239226594249SQin Michael Li 		goto fail;
239326594249SQin Michael Li 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
239426594249SQin Michael Li 		goto fail;
239526594249SQin Michael Li 	urtw_delay_ms(1);
239626594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
239726594249SQin Michael Li 		goto fail;
239826594249SQin Michael Li 	urtw_delay_ms(1);
239926594249SQin Michael Li 
240026594249SQin Michael Li 	/* TX ant A, 0x0 for B */
240126594249SQin Michael Li 	if (error = urtw_8185_tx_antenna(sc, 0x3))
240226594249SQin Michael Li 		goto fail;
2403dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002, 0))
240426594249SQin Michael Li 		goto fail;
240526594249SQin Michael Li 
2406dfa03ef6SQin Michael Li 	error = urtw_8225_rf_set_chan(rf,
2407dfa03ef6SQin Michael Li 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
240826594249SQin Michael Li fail:
240926594249SQin Michael Li 	return (error);
241026594249SQin Michael Li #undef N
241126594249SQin Michael Li }
241226594249SQin Michael Li 
241326594249SQin Michael Li static usbd_status
urtw_8225_rf_set_chan(struct urtw_rf * rf,int chan)2414dfa03ef6SQin Michael Li urtw_8225_rf_set_chan(struct urtw_rf *rf, int chan)
241526594249SQin Michael Li {
241626594249SQin Michael Li #define	IEEE80211_CHAN_G	\
241726594249SQin Michael Li 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
241826594249SQin Michael Li #define	IEEE80211_IS_CHAN_G(_c)		\
241926594249SQin Michael Li 	(((_c)->ich_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
242026594249SQin Michael Li 
2421dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
242226594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
242326594249SQin Michael Li 	struct ieee80211_channel *c = ic->ic_curchan;
242426594249SQin Michael Li 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
242526594249SQin Michael Li 	usbd_status error;
242626594249SQin Michael Li 
242726594249SQin Michael Li 	if (error = urtw_8225_set_txpwrlvl(sc, chan))
242826594249SQin Michael Li 		goto fail;
242926594249SQin Michael Li 	if (urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
243026594249SQin Michael Li 		goto fail;
243126594249SQin Michael Li 	urtw_delay_ms(10);
243226594249SQin Michael Li 
2433dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22, 0))
243426594249SQin Michael Li 		goto fail;
243526594249SQin Michael Li 
243626594249SQin Michael Li 	if (ic->ic_state == IEEE80211_S_ASSOC &&
243726594249SQin Michael Li 	    ic->ic_flags & IEEE80211_F_SHSLOT)
2438dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9, 0))
243926594249SQin Michael Li 			goto fail;
244026594249SQin Michael Li 	else
2441dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14, 0))
244226594249SQin Michael Li 			goto fail;
244326594249SQin Michael Li 	if (gset) {
244426594249SQin Michael Li 		/* for G */
2445dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14, 0))
244626594249SQin Michael Li 			goto fail;
2447dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14, 0))
244826594249SQin Michael Li 			goto fail;
2449dfa03ef6SQin Michael Li 		error = urtw_write8_c(sc, URTW_CW_VAL, 0x73, 0);
245026594249SQin Michael Li 	} else {
245126594249SQin Michael Li 		/* for B */
2452dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24, 0))
245326594249SQin Michael Li 			goto fail;
2454dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24, 0))
245526594249SQin Michael Li 			goto fail;
2456dfa03ef6SQin Michael Li 		error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5, 0);
245726594249SQin Michael Li 	}
245826594249SQin Michael Li 
245926594249SQin Michael Li fail:
246026594249SQin Michael Li 	return (error);
246126594249SQin Michael Li }
246226594249SQin Michael Li 
246326594249SQin Michael Li static usbd_status
urtw_8225_rf_set_sens(struct urtw_rf * rf)2464dfa03ef6SQin Michael Li urtw_8225_rf_set_sens(struct urtw_rf *rf)
246526594249SQin Michael Li {
246626594249SQin Michael Li 	usbd_status error;
2467dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
246826594249SQin Michael Li 
2469dfa03ef6SQin Michael Li 	if (rf->sens < 0 || rf->sens > 6)
247026594249SQin Michael Li 		return (-1);
247126594249SQin Michael Li 
2472dfa03ef6SQin Michael Li 	if (rf->sens > 4)
247326594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x0c, 0x850))
247426594249SQin Michael Li 			goto fail;
247526594249SQin Michael Li 	else
247626594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x0c, 0x50))
247726594249SQin Michael Li 			goto fail;
247826594249SQin Michael Li 
2479dfa03ef6SQin Michael Li 	rf->sens = 6 - rf->sens;
2480dfa03ef6SQin Michael Li 	if (error = urtw_8225_setgain(sc, rf->sens))
248126594249SQin Michael Li 		goto fail;
2482dfa03ef6SQin Michael Li 	error = urtw_8187_write_phy_cck_c(sc, 0x41,
2483dfa03ef6SQin Michael Li 	    urtw_8225_threshold[rf->sens]);
248426594249SQin Michael Li fail:
248526594249SQin Michael Li 	return (error);
248626594249SQin Michael Li }
248726594249SQin Michael Li 
248826594249SQin Michael Li static void
urtw_stop(struct urtw_softc * sc)248926594249SQin Michael Li urtw_stop(struct urtw_softc *sc)
249026594249SQin Michael Li {
249126594249SQin Michael Li 	URTW_LOCK(sc);
249226594249SQin Michael Li 	sc->sc_flags &= ~URTW_FLAG_RUNNING;
249326594249SQin Michael Li 	URTW_UNLOCK(sc);
249426594249SQin Michael Li 	urtw_close_pipes(sc);
249526594249SQin Michael Li }
249626594249SQin Michael Li 
249726594249SQin Michael Li static int
urtw_isbmode(uint16_t rate)249826594249SQin Michael Li urtw_isbmode(uint16_t rate)
249926594249SQin Michael Li {
250026594249SQin Michael Li 
250126594249SQin Michael Li 	rate = urtw_rtl2rate(rate);
250226594249SQin Michael Li 
250326594249SQin Michael Li 	return ((rate <= 22 && rate != 12 && rate != 18)?(1) : (0));
250426594249SQin Michael Li }
250526594249SQin Michael Li 
250626594249SQin Michael Li /* ARGSUSED */
250726594249SQin Michael Li static void
urtw_rxeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)250826594249SQin Michael Li urtw_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
250926594249SQin Michael Li {
251026594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
251126594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
251226594249SQin Michael Li 	int actlen, len,  flen,  rssi;
251326594249SQin Michael Li 	uint8_t *desc, rate;
251426594249SQin Michael Li 	struct ieee80211_frame *wh;
251526594249SQin Michael Li 	struct ieee80211_node *ni = 0;
251626594249SQin Michael Li 	mblk_t *mp = 0;
251726594249SQin Michael Li 	uint8_t *rxbuf;
251826594249SQin Michael Li 
251926594249SQin Michael Li 	mp = req->bulk_data;
252026594249SQin Michael Li 	req->bulk_data = NULL;
252126594249SQin Michael Li 	if (req->bulk_completion_reason != USB_CR_OK ||
252226594249SQin Michael Li 	    mp == NULL) {
252326594249SQin Michael Li 		sc->sc_rx_err++;
252426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2525dfa03ef6SQin Michael Li 		    "urtw_rxeof failed! %d, mp %p\n",
2526dfa03ef6SQin Michael Li 		    req->bulk_completion_reason, mp));
252726594249SQin Michael Li 		req->bulk_data = mp;
252826594249SQin Michael Li 		goto fail;
252926594249SQin Michael Li 	}
253026594249SQin Michael Li 
253126594249SQin Michael Li 	actlen = MBLKL(mp);
253226594249SQin Michael Li 	rxbuf = (uint8_t *)mp->b_rptr;
253326594249SQin Michael Li 
2534dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187)
253526594249SQin Michael Li 		/* 4 dword and 4 byte CRC  */
253626594249SQin Michael Li 		len = actlen - (4 * 4);
2537dfa03ef6SQin Michael Li 	else
2538dfa03ef6SQin Michael Li 		/* 5 dword and 4 byte CRC */
2539dfa03ef6SQin Michael Li 		len = actlen - (4 * 5);
2540dfa03ef6SQin Michael Li 
254126594249SQin Michael Li 	desc = rxbuf + len;
254226594249SQin Michael Li 	flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
254326594249SQin Michael Li 	if (flen > actlen) {
254426594249SQin Michael Li 		cmn_err(CE_CONT, "urtw_rxeof: impossible: flen %d, actlen %d\n",
254526594249SQin Michael Li 		    flen, actlen);
254626594249SQin Michael Li 		sc->sc_rx_err++;
254726594249SQin Michael Li 		req->bulk_data = mp;
254826594249SQin Michael Li 		goto fail;
254926594249SQin Michael Li 	}
255026594249SQin Michael Li 
255126594249SQin Michael Li 	rate = (desc[2] & 0xf0) >> 4;
2552dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
255326594249SQin Michael Li 		rssi = (desc[6] & 0xfe) >> 1;
2554dfa03ef6SQin Michael Li 
2555dfa03ef6SQin Michael Li 		/* XXX correct? */
255626594249SQin Michael Li 		if (!urtw_isbmode(rate)) {
255726594249SQin Michael Li 			rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi);
255826594249SQin Michael Li 			rssi = ((90 - rssi) * 100) / 65;
255926594249SQin Michael Li 		} else {
256026594249SQin Michael Li 			rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi);
256126594249SQin Michael Li 			rssi = ((95 - rssi) * 100) / 65;
256226594249SQin Michael Li 		}
2563dfa03ef6SQin Michael Li 	} else {
2564dfa03ef6SQin Michael Li 		rssi = 14 + desc[13]/2;
2565dfa03ef6SQin Michael Li 		if (rssi >= 95)
2566dfa03ef6SQin Michael Li 			rssi = 95;
2567dfa03ef6SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2568dfa03ef6SQin Michael Li 		    "urtw_rxeof: rssi %u\n", rssi));
2569dfa03ef6SQin Michael Li 	}
257026594249SQin Michael Li 
257126594249SQin Michael Li 	mp->b_wptr = mp->b_rptr + flen - 4;
257226594249SQin Michael Li 	wh = (struct ieee80211_frame *)mp->b_rptr;
257326594249SQin Michael Li 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)
257426594249SQin Michael Li 	    == IEEE80211_FC0_TYPE_DATA) {
257526594249SQin Michael Li 		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
257626594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
257726594249SQin Michael Li 		    "urtw_rxeof: update sc_currate to %u\n",
257826594249SQin Michael Li 		    sc->sc_currate));
257926594249SQin Michael Li 	}
258026594249SQin Michael Li 	ni = ieee80211_find_rxnode(ic, wh);
258126594249SQin Michael Li 
258226594249SQin Michael Li 	/* send the frame to the 802.11 layer */
258326594249SQin Michael Li 	(void) ieee80211_input(ic, mp, ni, rssi, 0);
258426594249SQin Michael Li 
258526594249SQin Michael Li 	/* node is no longer needed */
258626594249SQin Michael Li 	ieee80211_free_node(ni);
258726594249SQin Michael Li fail:
258826594249SQin Michael Li 	mutex_enter(&sc->rx_lock);
258926594249SQin Michael Li 	sc->rx_queued--;
259026594249SQin Michael Li 	mutex_exit(&sc->rx_lock);
259126594249SQin Michael Li 	usb_free_bulk_req(req);
259226594249SQin Michael Li 	if (URTW_IS_RUNNING(sc) && !URTW_IS_SUSPENDING(sc))
259326594249SQin Michael Li 		(void) urtw_rx_start(sc);
259426594249SQin Michael Li }
259526594249SQin Michael Li 
259626594249SQin Michael Li static usbd_status
urtw_8225v2_setgain(struct urtw_softc * sc,int16_t gain)259726594249SQin Michael Li urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
259826594249SQin Michael Li {
259926594249SQin Michael Li 	uint8_t *gainp;
260026594249SQin Michael Li 	usbd_status error;
260126594249SQin Michael Li 
260226594249SQin Michael Li 	/* XXX for A?  */
260326594249SQin Michael Li 	gainp = urtw_8225v2_gain_bg;
260426594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d, gainp[gain * 3]))
260526594249SQin Michael Li 		goto fail;
260626594249SQin Michael Li 	urtw_delay_ms(1);
260726594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b, gainp[gain * 3 + 1]))
260826594249SQin Michael Li 	urtw_delay_ms(1);
260926594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d, gainp[gain * 3 + 2]))
261026594249SQin Michael Li 		goto fail;
261126594249SQin Michael Li 	urtw_delay_ms(1);
261226594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x21, 0x17))
261326594249SQin Michael Li 		goto fail;
261426594249SQin Michael Li 	urtw_delay_ms(1);
261526594249SQin Michael Li fail:
261626594249SQin Michael Li 	return (error);
261726594249SQin Michael Li }
261826594249SQin Michael Li 
261926594249SQin Michael Li static usbd_status
urtw_8225v2_set_txpwrlvl(struct urtw_softc * sc,int chan)262026594249SQin Michael Li urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
262126594249SQin Michael Li {
262226594249SQin Michael Li 	int i;
262326594249SQin Michael Li 	uint8_t *cck_pwrtable;
262426594249SQin Michael Li 	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
262526594249SQin Michael Li 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
262626594249SQin Michael Li 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
262726594249SQin Michael Li 	usbd_status error;
262826594249SQin Michael Li 
262926594249SQin Michael Li 	/* CCK power setting */
263026594249SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
263126594249SQin Michael Li 	    cck_pwrlvl_max : cck_pwrlvl;
263226594249SQin Michael Li 	cck_pwrlvl += sc->sc_txpwr_cck_base;
263326594249SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
263426594249SQin Michael Li 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
263526594249SQin Michael Li 	    urtw_8225v2_txpwr_cck;
263626594249SQin Michael Li 
263726594249SQin Michael Li 	for (i = 0; i < 8; i++) {
263826594249SQin Michael Li 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
263926594249SQin Michael Li 		    cck_pwrtable[i]))
264026594249SQin Michael Li 			goto fail;
264126594249SQin Michael Li 	}
264226594249SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2643dfa03ef6SQin Michael Li 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl], 0))
264426594249SQin Michael Li 		goto fail;
264526594249SQin Michael Li 	urtw_delay_ms(1);
264626594249SQin Michael Li 
264726594249SQin Michael Li 	/* OFDM power setting */
264826594249SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
264926594249SQin Michael Li 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
265026594249SQin Michael Li 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
265126594249SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
265226594249SQin Michael Li 
2653dfa03ef6SQin Michael Li 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
265426594249SQin Michael Li 	if (error)
265526594249SQin Michael Li 		goto fail;
265626594249SQin Michael Li 
265726594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
265826594249SQin Michael Li 		goto fail;
265926594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 5, 0x0))
266026594249SQin Michael Li 		goto fail;
266126594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0x40))
266226594249SQin Michael Li 		goto fail;
266326594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 7, 0x0))
266426594249SQin Michael Li 		goto fail;
266526594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0x40))
266626594249SQin Michael Li 		goto fail;
266726594249SQin Michael Li 
266826594249SQin Michael Li 	error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2669dfa03ef6SQin Michael Li 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl], 0);
267026594249SQin Michael Li 	urtw_delay_ms(1);
267126594249SQin Michael Li fail:
267226594249SQin Michael Li 	return (error);
267326594249SQin Michael Li }
267426594249SQin Michael Li 
267526594249SQin Michael Li static usbd_status
urtw_8225v2_rf_init(struct urtw_rf * rf)2676dfa03ef6SQin Michael Li urtw_8225v2_rf_init(struct urtw_rf *rf)
267726594249SQin Michael Li {
267826594249SQin Michael Li #define	N(a)	(sizeof (a)/ sizeof ((a)[0]))
267926594249SQin Michael Li 	int i;
268026594249SQin Michael Li 	uint16_t data;
268126594249SQin Michael Li 	uint32_t data32;
268226594249SQin Michael Li 	usbd_status error;
2683dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
268426594249SQin Michael Li 
2685dfa03ef6SQin Michael Li 	if (error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON))
268626594249SQin Michael Li 		goto fail;
268726594249SQin Michael Li 	if (error = urtw_8225_usb_init(sc))
268826594249SQin Michael Li 		goto fail;
2689dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008, 0))
269026594249SQin Michael Li 		goto fail;
2691dfa03ef6SQin Michael Li 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
269226594249SQin Michael Li 		goto fail;
2693dfa03ef6SQin Michael Li 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff, 0))
269426594249SQin Michael Li 		goto fail;
2695dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044, 0))
269626594249SQin Michael Li 		goto fail;
269726594249SQin Michael Li 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
269826594249SQin Michael Li 		goto fail;
2699dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44, 0))
270026594249SQin Michael Li 		goto fail;
270126594249SQin Michael Li 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
270226594249SQin Michael Li 		goto fail;
270326594249SQin Michael Li 	if (error = urtw_8185_rf_pins_enable(sc))
270426594249SQin Michael Li 		goto fail;
270526594249SQin Michael Li 
270626594249SQin Michael Li 	urtw_delay_ms(500);
270726594249SQin Michael Li 
270826594249SQin Michael Li 	for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
270926594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, urtw_8225v2_rf_part1[i].reg,
271026594249SQin Michael Li 		    urtw_8225v2_rf_part1[i].val))
271126594249SQin Michael Li 			goto fail;
271226594249SQin Michael Li 		urtw_delay_ms(1);
271326594249SQin Michael Li 	}
271426594249SQin Michael Li 	urtw_delay_ms(100);
271526594249SQin Michael Li 
271626594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
271726594249SQin Michael Li 		goto fail;
271826594249SQin Michael Li 
271926594249SQin Michael Li 	for (i = 0; i < 95; i++) {
272026594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
272126594249SQin Michael Li 			goto fail;
272226594249SQin Michael Li 		urtw_delay_ms(1);
272326594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225v2_rxgain[i]))
272426594249SQin Michael Li 			goto fail;
272526594249SQin Michael Li 		urtw_delay_ms(1);
272626594249SQin Michael Li 	}
272726594249SQin Michael Li 
272826594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x3, 0x2))
272926594249SQin Michael Li 		goto fail;
273026594249SQin Michael Li 	urtw_delay_ms(1);
273126594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x5, 0x4))
273226594249SQin Michael Li 		goto fail;
273326594249SQin Michael Li 	urtw_delay_ms(1);
273426594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0xb7))
273526594249SQin Michael Li 		goto fail;
273626594249SQin Michael Li 	urtw_delay_ms(1);
273726594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
273826594249SQin Michael Li 		goto fail;
273926594249SQin Michael Li 	urtw_delay_ms(100);
274026594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
274126594249SQin Michael Li 		goto fail;
274226594249SQin Michael Li 	urtw_delay_ms(100);
274326594249SQin Michael Li 
274426594249SQin Michael Li 	if (error = urtw_8225_read(sc, 0x6, &data32))
274526594249SQin Michael Li 		goto fail;
274626594249SQin Michael Li 	if (data32 != 0xe6) {
274726594249SQin Michael Li 		error = (-1);
274826594249SQin Michael Li 		cmn_err(CE_WARN, "expect 0xe6!! (0x%x)\n", data32);
274926594249SQin Michael Li 		goto fail;
275026594249SQin Michael Li 	}
275126594249SQin Michael Li 	if (!(data32 & 0x80)) {
275226594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x02, 0x0c4d))
275326594249SQin Michael Li 			goto fail;
275426594249SQin Michael Li 		urtw_delay_ms(200);
275526594249SQin Michael Li 		if (error = urtw_8225_write_c(sc, 0x02, 0x044d))
275626594249SQin Michael Li 			goto fail;
275726594249SQin Michael Li 		urtw_delay_ms(100);
275826594249SQin Michael Li 		if (error = urtw_8225_read(sc, 0x6, &data32))
275926594249SQin Michael Li 			goto fail;
276026594249SQin Michael Li 		if (!(data32 & 0x80))
276126594249SQin Michael Li 			cmn_err(CE_CONT, "RF calibration failed\n");
276226594249SQin Michael Li 	}
276326594249SQin Michael Li 	urtw_delay_ms(200);
276426594249SQin Michael Li 
276526594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x0, 0x2bf))
276626594249SQin Michael Li 		goto fail;
276726594249SQin Michael Li 	for (i = 0; i < 128; i++) {
276826594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
276926594249SQin Michael Li 		    urtw_8225_agc[i]))
277026594249SQin Michael Li 			goto fail;
277126594249SQin Michael Li 		urtw_delay_ms(1);
277226594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
277326594249SQin Michael Li 		    (uint8_t)i + 0x80))
277426594249SQin Michael Li 			goto fail;
277526594249SQin Michael Li 		urtw_delay_ms(1);
277626594249SQin Michael Li 	}
277726594249SQin Michael Li 	urtw_delay_ms(1);
277826594249SQin Michael Li 
277926594249SQin Michael Li 	for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
278026594249SQin Michael Li 		if (error = urtw_8187_write_phy_ofdm_c(sc,
278126594249SQin Michael Li 		    urtw_8225v2_rf_part2[i].reg,
278226594249SQin Michael Li 		    urtw_8225v2_rf_part2[i].val))
278326594249SQin Michael Li 			goto fail;
278426594249SQin Michael Li 		urtw_delay_ms(1);
278526594249SQin Michael Li 	}
278626594249SQin Michael Li 	error = urtw_8225v2_setgain(sc, 4);
278726594249SQin Michael Li 	if (error)
278826594249SQin Michael Li 		goto fail;
278926594249SQin Michael Li 
279026594249SQin Michael Li 	for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
279126594249SQin Michael Li 		if (error = urtw_8187_write_phy_cck_c(sc,
279226594249SQin Michael Li 		    urtw_8225v2_rf_part3[i].reg,
279326594249SQin Michael Li 		    urtw_8225v2_rf_part3[i].val))
279426594249SQin Michael Li 			goto fail;
279526594249SQin Michael Li 		urtw_delay_ms(1);
279626594249SQin Michael Li 	}
279726594249SQin Michael Li 
2798dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, 0x5b, 0x0d, 0))
279926594249SQin Michael Li 		goto fail;
280026594249SQin Michael Li 	if (error = urtw_8225v2_set_txpwrlvl(sc, 1))
280126594249SQin Michael Li 		goto fail;
280226594249SQin Michael Li 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
280326594249SQin Michael Li 		goto fail;
280426594249SQin Michael Li 	urtw_delay_ms(1);
280526594249SQin Michael Li 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
280626594249SQin Michael Li 		goto fail;
280726594249SQin Michael Li 	urtw_delay_ms(1);
280826594249SQin Michael Li 
280926594249SQin Michael Li 	/* TX ant A, 0x0 for B */
281026594249SQin Michael Li 	if (error = urtw_8185_tx_antenna(sc, 0x3))
281126594249SQin Michael Li 		goto fail;
2812dfa03ef6SQin Michael Li 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002, 0))
281326594249SQin Michael Li 		goto fail;
281426594249SQin Michael Li 
2815dfa03ef6SQin Michael Li 	error = urtw_8225_rf_set_chan(rf,
2816dfa03ef6SQin Michael Li 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
281726594249SQin Michael Li fail:
281826594249SQin Michael Li 	return (error);
281926594249SQin Michael Li #undef N
282026594249SQin Michael Li }
282126594249SQin Michael Li 
282226594249SQin Michael Li static usbd_status
urtw_8225v2_rf_set_chan(struct urtw_rf * rf,int chan)2823dfa03ef6SQin Michael Li urtw_8225v2_rf_set_chan(struct urtw_rf *rf, int chan)
282426594249SQin Michael Li {
2825dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
282626594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
282726594249SQin Michael Li 	struct ieee80211_channel *c = ic->ic_curchan;
282826594249SQin Michael Li 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
282926594249SQin Michael Li 	usbd_status error;
283026594249SQin Michael Li 
283126594249SQin Michael Li 	if (error = urtw_8225v2_set_txpwrlvl(sc, chan))
283226594249SQin Michael Li 		goto fail;
283326594249SQin Michael Li 
283426594249SQin Michael Li 	if (error = urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
283526594249SQin Michael Li 		goto fail;
283626594249SQin Michael Li 
283726594249SQin Michael Li 	urtw_delay_ms(10);
283826594249SQin Michael Li 
2839dfa03ef6SQin Michael Li 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22, 0))
284026594249SQin Michael Li 		goto fail;
284126594249SQin Michael Li 
284226594249SQin Michael Li 	if (ic->ic_state == IEEE80211_S_ASSOC &&
284326594249SQin Michael Li 	    ic->ic_flags & IEEE80211_F_SHSLOT) {
2844dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9, 0))
284526594249SQin Michael Li 			goto fail;
284626594249SQin Michael Li 	} else
2847dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14, 0))
284826594249SQin Michael Li 			goto fail;
284926594249SQin Michael Li 	if (gset) {
285026594249SQin Michael Li 		/* for G */
2851dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14, 0))
285226594249SQin Michael Li 			goto fail;
2853dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14, 0))
285426594249SQin Michael Li 			goto fail;
2855dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0x73, 0))
285626594249SQin Michael Li 			goto fail;
285726594249SQin Michael Li 	} else {
285826594249SQin Michael Li 		/* for B */
2859dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24, 0))
286026594249SQin Michael Li 			goto fail;
2861dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24, 0))
286226594249SQin Michael Li 			goto fail;
2863dfa03ef6SQin Michael Li 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5, 0))
286426594249SQin Michael Li 			goto fail;
286526594249SQin Michael Li 	}
286626594249SQin Michael Li 
286726594249SQin Michael Li fail:
286826594249SQin Michael Li 	return (error);
286926594249SQin Michael Li }
287026594249SQin Michael Li 
287126594249SQin Michael Li static int
urtw_set_channel(struct urtw_softc * sc)287226594249SQin Michael Li urtw_set_channel(struct urtw_softc *sc)
287326594249SQin Michael Li {
287426594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
2875dfa03ef6SQin Michael Li 	struct urtw_rf *rf = &sc->sc_rf;
287626594249SQin Michael Li 	uint32_t data;
287726594249SQin Michael Li 	usbd_status error;
287826594249SQin Michael Li 
2879dfa03ef6SQin Michael Li 	if (error = urtw_read32_c(sc, URTW_TX_CONF, &data, 0))
288026594249SQin Michael Li 		goto fail;
288126594249SQin Michael Li 	data &= ~URTW_TX_LOOPBACK_MASK;
288226594249SQin Michael Li 	if (error = urtw_write32_c(sc, URTW_TX_CONF,
2883dfa03ef6SQin Michael Li 	    data | URTW_TX_LOOPBACK_MAC, 0))
288426594249SQin Michael Li 		goto fail;
2885dfa03ef6SQin Michael Li 	error = rf->set_chan(rf, ieee80211_chan2ieee(ic, ic->ic_curchan));
288626594249SQin Michael Li 	if (error)
288726594249SQin Michael Li 		goto fail;
2888dfa03ef6SQin Michael Li 	urtw_delay_ms(20);
2889dfa03ef6SQin Michael Li 	error = urtw_write32_c(sc, URTW_TX_CONF,
2890dfa03ef6SQin Michael Li 	    data | URTW_TX_LOOPBACK_NONE, 0);
289126594249SQin Michael Li fail:
289226594249SQin Michael Li 	return (error);
289326594249SQin Michael Li }
289426594249SQin Michael Li 
289526594249SQin Michael Li /* ARGSUSED */
289626594249SQin Michael Li static void
urtw_txeof_low(usb_pipe_handle_t pipe,usb_bulk_req_t * req)289726594249SQin Michael Li urtw_txeof_low(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
289826594249SQin Michael Li {
289926594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
290026594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
290126594249SQin Michael Li 
290226594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
290326594249SQin Michael Li 	    "urtw_txeof_low(): cr:%s(%d), flags:0x%x, tx_queued:%d",
290426594249SQin Michael Li 	    usb_str_cr(req->bulk_completion_reason),
290526594249SQin Michael Li 	    req->bulk_completion_reason,
290626594249SQin Michael Li 	    req->bulk_cb_flags,
290726594249SQin Michael Li 	    sc->sc_tx_low_queued));
290826594249SQin Michael Li 	mutex_enter(&sc->tx_lock);
290926594249SQin Michael Li 	if (req->bulk_completion_reason != USB_CR_OK) {
291026594249SQin Michael Li 		ic->ic_stats.is_tx_failed++;
291126594249SQin Michael Li 		goto fail;
291226594249SQin Michael Li 	}
291326594249SQin Michael Li 
291426594249SQin Michael Li 	if (sc->sc_need_sched) {
291526594249SQin Michael Li 		sc->sc_need_sched = 0;
291626594249SQin Michael Li 		mac_tx_update(ic->ic_mach);
291726594249SQin Michael Li 	}
291826594249SQin Michael Li fail:
291926594249SQin Michael Li 	sc->sc_tx_low_queued--;
292026594249SQin Michael Li 	mutex_exit(&sc->tx_lock);
292126594249SQin Michael Li 	usb_free_bulk_req(req);
292226594249SQin Michael Li }
292326594249SQin Michael Li 
292426594249SQin Michael Li /* ARGSUSED */
292526594249SQin Michael Li static void
urtw_txeof_normal(usb_pipe_handle_t pipe,usb_bulk_req_t * req)292626594249SQin Michael Li urtw_txeof_normal(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
292726594249SQin Michael Li {
292826594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
292926594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
293026594249SQin Michael Li 
293126594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
293226594249SQin Michael Li 	    "urtw_txeof_normal(): cr:%s(%d), flags:0x%x, tx_queued:%d",
293326594249SQin Michael Li 	    usb_str_cr(req->bulk_completion_reason),
293426594249SQin Michael Li 	    req->bulk_completion_reason,
293526594249SQin Michael Li 	    req->bulk_cb_flags,
293626594249SQin Michael Li 	    sc->sc_tx_normal_queued));
293726594249SQin Michael Li 
293826594249SQin Michael Li 	mutex_enter(&sc->tx_lock);
293926594249SQin Michael Li 	if (req->bulk_completion_reason != USB_CR_OK) {
294026594249SQin Michael Li 		ic->ic_stats.is_tx_failed++;
294126594249SQin Michael Li 		goto fail;
294226594249SQin Michael Li 	}
294326594249SQin Michael Li 
294426594249SQin Michael Li 	if (sc->sc_need_sched) {
294526594249SQin Michael Li 		sc->sc_need_sched = 0;
294626594249SQin Michael Li 		mac_tx_update(ic->ic_mach);
294726594249SQin Michael Li 	}
294826594249SQin Michael Li fail:
294926594249SQin Michael Li 	sc->sc_tx_normal_queued--;
295026594249SQin Michael Li 	mutex_exit(&sc->tx_lock);
295126594249SQin Michael Li 	usb_free_bulk_req(req);
295226594249SQin Michael Li }
295326594249SQin Michael Li 
295426594249SQin Michael Li 
295526594249SQin Michael Li static int
urtw_get_rate(struct ieee80211com * ic)295626594249SQin Michael Li urtw_get_rate(struct ieee80211com *ic)
295726594249SQin Michael Li {
295826594249SQin Michael Li 	uint8_t (*rates)[IEEE80211_RATE_MAXSIZE];
295926594249SQin Michael Li 	int rate;
296026594249SQin Michael Li 
296126594249SQin Michael Li 	rates = &ic->ic_bss->in_rates.ir_rates;
296226594249SQin Michael Li 
296326594249SQin Michael Li 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
296426594249SQin Michael Li 		rate = ic->ic_fixed_rate;
296526594249SQin Michael Li 	else if (ic->ic_state == IEEE80211_S_RUN)
296626594249SQin Michael Li 		rate = (*rates)[ic->ic_bss->in_txrate];
296726594249SQin Michael Li 	else
296826594249SQin Michael Li 		rate = 0;
296926594249SQin Michael Li 	return (rate & IEEE80211_RATE_VAL);
297026594249SQin Michael Li }
297126594249SQin Michael Li 
2972dfa03ef6SQin Michael Li void
urtw_8187b_update_wmm(struct urtw_softc * sc)2973dfa03ef6SQin Michael Li urtw_8187b_update_wmm(struct urtw_softc *sc)
2974dfa03ef6SQin Michael Li {
2975dfa03ef6SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
2976dfa03ef6SQin Michael Li 	struct ieee80211_channel *c = ic->ic_curchan;
2977dfa03ef6SQin Michael Li 	uint32_t data;
2978dfa03ef6SQin Michael Li 	uint8_t aifs, sifs, slot, ecwmin, ecwmax;
2979dfa03ef6SQin Michael Li 
2980dfa03ef6SQin Michael Li 	sifs = 0xa;
2981dfa03ef6SQin Michael Li 	if (IEEE80211_IS_CHAN_G(c))
2982dfa03ef6SQin Michael Li 		slot = 0x9;
2983dfa03ef6SQin Michael Li 	else
2984dfa03ef6SQin Michael Li 		slot = 0x14;
2985dfa03ef6SQin Michael Li 
2986dfa03ef6SQin Michael Li 	aifs = (2 * slot) + sifs;
2987dfa03ef6SQin Michael Li 	ecwmin = 3;
2988dfa03ef6SQin Michael Li 	ecwmax = 7;
2989dfa03ef6SQin Michael Li 
2990dfa03ef6SQin Michael Li 	data = ((uint32_t)aifs << 0) |		/* AIFS, offset 0 */
2991dfa03ef6SQin Michael Li 	    ((uint32_t)ecwmin << 8) |		/* ECW minimum, offset 8 */
2992dfa03ef6SQin Michael Li 	    ((uint32_t)ecwmax << 12);		/* ECW maximum, offset 16 */
2993dfa03ef6SQin Michael Li 
2994dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_AC_VO, data, 0);
2995dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_AC_VI, data, 0);
2996dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_AC_BE, data, 0);
2997dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_AC_BK, data, 0);
2998dfa03ef6SQin Michael Li }
2999dfa03ef6SQin Michael Li 
3000dfa03ef6SQin Michael Li usbd_status
urtw_8187b_reset(struct urtw_softc * sc)3001dfa03ef6SQin Michael Li urtw_8187b_reset(struct urtw_softc *sc)
3002dfa03ef6SQin Michael Li {
3003dfa03ef6SQin Michael Li 	uint8_t data;
3004dfa03ef6SQin Michael Li 	usbd_status error;
3005dfa03ef6SQin Michael Li 
3006dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3007dfa03ef6SQin Michael Li 	if (error)
3008dfa03ef6SQin Michael Li 		goto fail;
3009dfa03ef6SQin Michael Li 
3010dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3011dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3012dfa03ef6SQin Michael Li 	    data | URTW_CONFIG3_ANAPARAM_WRITE |
3013dfa03ef6SQin Michael Li 	    URTW_CONFIG3_GNT_SELECT, 0);
3014dfa03ef6SQin Michael Li 
3015dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_ANAPARAM2,
3016dfa03ef6SQin Michael Li 	    URTW_8187B_8225_ANAPARAM2_ON, 0);
3017dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_ANAPARAM,
3018dfa03ef6SQin Michael Li 	    URTW_8187B_8225_ANAPARAM_ON, 0);
3019dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_ANAPARAM3,
3020dfa03ef6SQin Michael Li 	    URTW_8187B_8225_ANAPARAM3_ON, 0);
3021dfa03ef6SQin Michael Li 
3022dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x61, 0x10, 0);
3023dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, 0x62, &data, 0);
3024dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x62, data & ~(1 << 5), 0);
3025dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x62, data | (1 << 5), 0);
3026dfa03ef6SQin Michael Li 
3027dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3028dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3029dfa03ef6SQin Michael Li 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0);
3030dfa03ef6SQin Michael Li 
3031dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3032dfa03ef6SQin Michael Li 	if (error)
3033dfa03ef6SQin Michael Li 		goto fail;
3034dfa03ef6SQin Michael Li 
3035dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CMD, &data, 0);
3036dfa03ef6SQin Michael Li 	data = (data & 2) | URTW_CMD_RST;
3037dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CMD, data, 0);
3038dfa03ef6SQin Michael Li 	urtw_delay_ms(100);
3039dfa03ef6SQin Michael Li 
3040dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CMD, &data, 0);
3041dfa03ef6SQin Michael Li 	if (data & URTW_CMD_RST) {
3042dfa03ef6SQin Michael Li 		cmn_err(CE_WARN, "urtw: 8187b reset timeout\n");
3043dfa03ef6SQin Michael Li 		goto fail;
3044dfa03ef6SQin Michael Li 	}
3045dfa03ef6SQin Michael Li 
3046dfa03ef6SQin Michael Li fail:
3047dfa03ef6SQin Michael Li 	return (error);
3048dfa03ef6SQin Michael Li }
3049dfa03ef6SQin Michael Li 
3050dfa03ef6SQin Michael Li static int
urtw_8187b_init(void * arg)3051dfa03ef6SQin Michael Li urtw_8187b_init(void *arg)
3052dfa03ef6SQin Michael Li {
3053dfa03ef6SQin Michael Li 	struct urtw_softc *sc = arg;
3054dfa03ef6SQin Michael Li 	struct urtw_rf *rf = &sc->sc_rf;
3055dfa03ef6SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
3056dfa03ef6SQin Michael Li 	int i;
3057dfa03ef6SQin Michael Li 	uint8_t data;
3058dfa03ef6SQin Michael Li 	usbd_status error;
3059dfa03ef6SQin Michael Li 
3060dfa03ef6SQin Michael Li 	urtw_stop(sc);
3061dfa03ef6SQin Michael Li 	URTW_LOCK(sc);
3062dfa03ef6SQin Michael Li 	urtw_8187b_update_wmm(sc);
3063dfa03ef6SQin Michael Li 	error = urtw_8187b_reset(sc);
3064dfa03ef6SQin Michael Li 	if (error)
3065dfa03ef6SQin Michael Li 		goto fail;
3066dfa03ef6SQin Michael Li 
3067dfa03ef6SQin Michael Li 	error = urtw_open_pipes(sc);
3068dfa03ef6SQin Michael Li 	if (error != 0)
3069dfa03ef6SQin Michael Li 		goto fail;
3070dfa03ef6SQin Michael Li 	/* Applying MAC address again. */
3071dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3072dfa03ef6SQin Michael Li 	if (error)
3073dfa03ef6SQin Michael Li 		goto fail;
3074dfa03ef6SQin Michael Li 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
3075dfa03ef6SQin Michael Li 		(void) urtw_write8_c(sc, URTW_MAC0 + i,
3076dfa03ef6SQin Michael Li 		    ic->ic_macaddr[i], 0);
3077dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3078dfa03ef6SQin Michael Li 	if (error)
3079dfa03ef6SQin Michael Li 		goto fail;
3080dfa03ef6SQin Michael Li 
3081dfa03ef6SQin Michael Li 	error = urtw_update_msr(sc, IEEE80211_S_INIT);
3082dfa03ef6SQin Michael Li 	if (error)
3083dfa03ef6SQin Michael Li 		goto fail;
3084dfa03ef6SQin Michael Li 
3085dfa03ef6SQin Michael Li 	error = rf->init(rf);
3086dfa03ef6SQin Michael Li 	if (error != 0)
3087dfa03ef6SQin Michael Li 		goto fail;
3088dfa03ef6SQin Michael Li 	error = urtw_intr_enable(sc);
3089dfa03ef6SQin Michael Li 	if (error != 0)
3090dfa03ef6SQin Michael Li 		goto fail;
3091dfa03ef6SQin Michael Li 
3092dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x41, 0xf4);
3093dfa03ef6SQin Michael Li 	if (error != 0)
3094dfa03ef6SQin Michael Li 		goto fail;
3095dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x40, 0x00);
3096dfa03ef6SQin Michael Li 	if (error != 0)
3097dfa03ef6SQin Michael Li 		goto fail;
3098dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x42, 0x00);
3099dfa03ef6SQin Michael Li 	if (error != 0)
3100dfa03ef6SQin Michael Li 		goto fail;
3101dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x42, 0x01);
3102dfa03ef6SQin Michael Li 	if (error != 0)
3103dfa03ef6SQin Michael Li 		goto fail;
3104dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x40, 0x0f);
3105dfa03ef6SQin Michael Li 	if (error != 0)
3106dfa03ef6SQin Michael Li 		goto fail;
3107dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x42, 0x00);
3108dfa03ef6SQin Michael Li 	if (error != 0)
3109dfa03ef6SQin Michael Li 		goto fail;
3110dfa03ef6SQin Michael Li 	error = urtw_write8e(sc, 0x42, 0x01);
3111dfa03ef6SQin Michael Li 	if (error != 0)
3112dfa03ef6SQin Michael Li 		goto fail;
3113dfa03ef6SQin Michael Li 
3114dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, 0xdb, &data, 0);
3115dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0xdb, data | (1 << 2), 0);
3116dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x72, 0x59fa, 3);
3117dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x74, 0x59d2, 3);
3118dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x76, 0x59d2, 3);
3119dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x78, 0x19fa, 3);
3120dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x7a, 0x19fa, 3);
3121dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0x7c, 0x00d0, 3);
3122dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x61, 0, 0);
3123dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x80, 0x0f, 1);
3124dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x83, 0x03, 1);
3125dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0xda, 0x10, 0);
3126dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0x4d, 0x08, 2);
3127dfa03ef6SQin Michael Li 
3128dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_HSSI_PARA, 0x0600321b, 0);
3129dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, 0xec, 0x0800, 1);
3130dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_ACM_CONTROL, 0, 0);
3131dfa03ef6SQin Michael Li 
3132dfa03ef6SQin Michael Li 	sc->sc_tx_low_queued = 0;
3133dfa03ef6SQin Michael Li 	sc->sc_tx_normal_queued = 0;
3134dfa03ef6SQin Michael Li 	error = urtw_rx_enable(sc);
3135dfa03ef6SQin Michael Li 	if (error != 0)
3136dfa03ef6SQin Michael Li 		goto fail;
3137dfa03ef6SQin Michael Li 	urtw_tx_enable(sc);
3138dfa03ef6SQin Michael Li 
3139dfa03ef6SQin Michael Li 	if (error == 0) {
3140dfa03ef6SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev,
3141dfa03ef6SQin Michael Li 		    CE_CONT, "urtw_8187b_init: done\n"));
3142dfa03ef6SQin Michael Li 		sc->sc_flags |= URTW_FLAG_RUNNING;
3143dfa03ef6SQin Michael Li 		URTW_UNLOCK(sc);
3144dfa03ef6SQin Michael Li 		return (error);
3145dfa03ef6SQin Michael Li 	}
3146dfa03ef6SQin Michael Li 
3147dfa03ef6SQin Michael Li fail:
3148dfa03ef6SQin Michael Li 	cmn_err(CE_WARN, "urtw_8187b_init failed\n");
3149dfa03ef6SQin Michael Li 	URTW_UNLOCK(sc);
3150dfa03ef6SQin Michael Li 	urtw_stop(sc);
3151dfa03ef6SQin Michael Li 	return (EIO);
3152dfa03ef6SQin Michael Li }
3153dfa03ef6SQin Michael Li 
3154dfa03ef6SQin Michael Li void
urtw_8225v2_b_config_mac(struct urtw_softc * sc)3155dfa03ef6SQin Michael Li urtw_8225v2_b_config_mac(struct urtw_softc *sc)
3156dfa03ef6SQin Michael Li {
3157dfa03ef6SQin Michael Li 	int i;
3158dfa03ef6SQin Michael Li 	int nitems = sizeof (urtw_8187b_regtbl)
3159dfa03ef6SQin Michael Li 	    / sizeof ((urtw_8187b_regtbl)[0]);
3160dfa03ef6SQin Michael Li 
3161dfa03ef6SQin Michael Li 	for (i = 0; i < nitems; i++) {
3162dfa03ef6SQin Michael Li 		(void) urtw_write8_c(sc, urtw_8187b_regtbl[i].reg,
3163dfa03ef6SQin Michael Li 		    urtw_8187b_regtbl[i].val, urtw_8187b_regtbl[i].idx);
3164dfa03ef6SQin Michael Li 	}
3165dfa03ef6SQin Michael Li 
3166dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_TID_AC_MAP, 0xfa50, 0);
3167dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_INT_MIG, 0, 0);
3168dfa03ef6SQin Michael Li 
3169dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, 0xf0, 0, 1);
3170dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, 0xf4, 0, 1);
3171dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, 0xf8, 0, 1);
3172dfa03ef6SQin Michael Li 
3173dfa03ef6SQin Michael Li 	(void) urtw_write32_c(sc, URTW_RF_TIMING, 0x00004001, 0);
3174dfa03ef6SQin Michael Li }
3175dfa03ef6SQin Michael Li 
3176dfa03ef6SQin Michael Li void
urtw_8225v2_b_init_rfe(struct urtw_softc * sc)3177dfa03ef6SQin Michael Li urtw_8225v2_b_init_rfe(struct urtw_softc *sc)
3178dfa03ef6SQin Michael Li {
3179dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x0480, 0);
3180dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x2488, 0);
3181dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x1fff, 0);
3182dfa03ef6SQin Michael Li 	urtw_delay_ms(100);
3183dfa03ef6SQin Michael Li }
3184dfa03ef6SQin Michael Li 
3185dfa03ef6SQin Michael Li usbd_status
urtw_8225v2_b_update_chan(struct urtw_softc * sc)3186dfa03ef6SQin Michael Li urtw_8225v2_b_update_chan(struct urtw_softc *sc)
3187dfa03ef6SQin Michael Li {
3188dfa03ef6SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
3189dfa03ef6SQin Michael Li 	struct ieee80211_channel *c = ic->ic_curchan;
3190dfa03ef6SQin Michael Li 	uint8_t aifs, difs, eifs, sifs, slot;
3191dfa03ef6SQin Michael Li 
3192dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_SIFS, 0x22, 0);
3193dfa03ef6SQin Michael Li 
3194dfa03ef6SQin Michael Li 	sifs = 0xa;
3195dfa03ef6SQin Michael Li 	if (IEEE80211_IS_CHAN_G(c)) {
3196dfa03ef6SQin Michael Li 		slot = 0x9;
3197dfa03ef6SQin Michael Li 		difs = 0x1c;
3198dfa03ef6SQin Michael Li 		eifs = 0x5b;
3199dfa03ef6SQin Michael Li 	} else {
3200dfa03ef6SQin Michael Li 		slot = 0x14;
3201dfa03ef6SQin Michael Li 		difs = 0x32;
3202dfa03ef6SQin Michael Li 		eifs = 0x5b;
3203dfa03ef6SQin Michael Li 	}
3204dfa03ef6SQin Michael Li 	aifs = (2 * slot) + sifs;
3205dfa03ef6SQin Michael Li 
3206dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_SLOT, slot, 0);
3207dfa03ef6SQin Michael Li 
3208dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_AC_VO, aifs, 0);
3209dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_AC_VI, aifs, 0);
3210dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_AC_BE, aifs, 0);
3211dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_AC_BK, aifs, 0);
3212dfa03ef6SQin Michael Li 
3213dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_DIFS, difs, 0);
3214dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_8187B_EIFS, eifs, 0);
3215dfa03ef6SQin Michael Li 	return (0);
3216dfa03ef6SQin Michael Li }
3217dfa03ef6SQin Michael Li 
3218dfa03ef6SQin Michael Li usbd_status
urtw_8225v2_b_rf_init(struct urtw_rf * rf)3219dfa03ef6SQin Michael Li urtw_8225v2_b_rf_init(struct urtw_rf *rf)
3220dfa03ef6SQin Michael Li {
3221dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
3222dfa03ef6SQin Michael Li 	int i, nitems;
3223dfa03ef6SQin Michael Li 	uint8_t data;
3224dfa03ef6SQin Michael Li 	usbd_status error;
3225dfa03ef6SQin Michael Li 
3226dfa03ef6SQin Michael Li 	/* Set up ACK rate, retry limit, TX AGC, TX antenna. */
3227dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_8187B_BRSR, 0x0fff, 0);
3228dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CW_CONF, &data, 0);
3229dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CW_CONF, data |
3230dfa03ef6SQin Michael Li 	    URTW_CW_CONF_PERPACKET_RETRY, 0);
3231dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_TX_AGC_CTL, &data, 0);
3232dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_AGC_CTL, data |
3233dfa03ef6SQin Michael Li 	    URTW_TX_AGC_CTL_PERPACKET_GAIN |
3234dfa03ef6SQin Michael Li 	    URTW_TX_AGC_CTL_PERPACKET_ANTSEL, 0);
3235dfa03ef6SQin Michael Li 
3236dfa03ef6SQin Michael Li 	/* Auto rate fallback control. */
3237dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_ARFR, 0x0fff, 1);	/* 1M ~ 54M */
3238dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_RATE_FALLBACK, &data, 0);
3239dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_RATE_FALLBACK, data |
3240dfa03ef6SQin Michael Li 	    URTW_RATE_FALLBACK_ENABLE, 0);
3241dfa03ef6SQin Michael Li 
3242dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_BEACON_INTERVAL, 0x3ff, 0);
3243dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_ATIM_WND, 2, 0);
3244dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_FEMR, 0xffff, 1);
3245dfa03ef6SQin Michael Li 
3246dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3247dfa03ef6SQin Michael Li 	if (error)
3248dfa03ef6SQin Michael Li 		goto fail;
3249dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CONFIG1, &data, 0);
3250dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CONFIG1, (data & 0x3f) | 0x80, 0);
3251dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3252dfa03ef6SQin Michael Li 	if (error)
3253dfa03ef6SQin Michael Li 		goto fail;
3254dfa03ef6SQin Michael Li 
3255dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_WPA_CONFIG, 0, 0);
3256dfa03ef6SQin Michael Li 	urtw_8225v2_b_config_mac(sc);
3257dfa03ef6SQin Michael Li 	(void) urtw_write16_c(sc, URTW_RFSW_CTRL, 0x569a, 2);
3258dfa03ef6SQin Michael Li 
3259dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3260dfa03ef6SQin Michael Li 	if (error)
3261dfa03ef6SQin Michael Li 		goto fail;
3262dfa03ef6SQin Michael Li 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3263dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3264dfa03ef6SQin Michael Li 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0);
3265dfa03ef6SQin Michael Li 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3266dfa03ef6SQin Michael Li 	if (error)
3267dfa03ef6SQin Michael Li 		goto fail;
3268dfa03ef6SQin Michael Li 
3269dfa03ef6SQin Michael Li 	urtw_8225v2_b_init_rfe(sc);
3270dfa03ef6SQin Michael Li 
3271dfa03ef6SQin Michael Li 	nitems = sizeof (urtw_8225v2_b_rf) / sizeof ((urtw_8225v2_b_rf)[0]);
3272dfa03ef6SQin Michael Li 	for (i = 0; i < nitems; i++) {
3273dfa03ef6SQin Michael Li 		(void) urtw_8225_write_c(sc, urtw_8225v2_b_rf[i].reg,
3274dfa03ef6SQin Michael Li 		    urtw_8225v2_b_rf[i].val);
3275dfa03ef6SQin Michael Li 	}
3276dfa03ef6SQin Michael Li 
3277dfa03ef6SQin Michael Li 	nitems = sizeof (urtw_8225v2_rxgain) / sizeof ((urtw_8225v2_rxgain)[0]);
3278dfa03ef6SQin Michael Li 	for (i = 0; i < nitems; i++) {
3279dfa03ef6SQin Michael Li 		(void) urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1));
3280dfa03ef6SQin Michael Li 		(void) urtw_8225_write_c(sc, 0x2, urtw_8225v2_rxgain[i]);
3281dfa03ef6SQin Michael Li 	}
3282dfa03ef6SQin Michael Li 
3283dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x03, 0x080);
3284dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x05, 0x004);
3285dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x00, 0x0b7);
3286dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x02, 0xc4d);
3287dfa03ef6SQin Michael Li 	urtw_delay_ms(10);
3288dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x02, 0x44d);
3289dfa03ef6SQin Michael Li 	urtw_delay_ms(10);
3290dfa03ef6SQin Michael Li 	(void) urtw_8225_write_c(sc, 0x00, 0x2bf);
3291dfa03ef6SQin Michael Li 	urtw_delay_ms(10);
3292dfa03ef6SQin Michael Li 
3293dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_GAIN_CCK, 0x03, 0);
3294dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_GAIN_OFDM, 0x07, 0);
3295dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_ANTENNA, 0x03, 0);
3296dfa03ef6SQin Michael Li 
3297dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x80, 0x12);
3298dfa03ef6SQin Michael Li 	nitems = sizeof (urtw_8225v2_agc) / sizeof ((urtw_8225v2_agc)[0]);
3299dfa03ef6SQin Michael Li 	for (i = 0; i < nitems; i++) {
3300dfa03ef6SQin Michael Li 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0f, urtw_8225v2_agc[i]);
3301dfa03ef6SQin Michael Li 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0e, (uint8_t)i + 0x80);
3302dfa03ef6SQin Michael Li 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0e, 0);
3303dfa03ef6SQin Michael Li 	}
3304dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x80, 0x10);
3305dfa03ef6SQin Michael Li 
3306dfa03ef6SQin Michael Li 	nitems = sizeof (urtw_8225v2_ofdm) / sizeof ((urtw_8225v2_ofdm)[0]);
3307dfa03ef6SQin Michael Li 	for (i = 0; i < nitems; i++) {
3308dfa03ef6SQin Michael Li 		(void) urtw_8187_write_phy_ofdm_c(sc, i, urtw_8225v2_ofdm[i]);
3309dfa03ef6SQin Michael Li 	}
3310dfa03ef6SQin Michael Li 	(void) urtw_8225v2_b_update_chan(sc);
3311dfa03ef6SQin Michael Li 
3312dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x97, 0x46);
3313dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_ofdm_c(sc, 0xa4, 0xb6);
3314dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x85, 0xfc);
3315dfa03ef6SQin Michael Li 	(void) urtw_8187_write_phy_cck_c(sc, 0xc1, 0x88);
3316dfa03ef6SQin Michael Li 
3317dfa03ef6SQin Michael Li 	error = urtw_8225v2_b_rf_set_chan(rf,
3318dfa03ef6SQin Michael Li 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
3319dfa03ef6SQin Michael Li fail:
3320dfa03ef6SQin Michael Li 	return (error);
3321dfa03ef6SQin Michael Li }
3322dfa03ef6SQin Michael Li 
3323dfa03ef6SQin Michael Li static usbd_status
urtw_8225v2_b_rf_set_chan(struct urtw_rf * rf,int chan)3324dfa03ef6SQin Michael Li urtw_8225v2_b_rf_set_chan(struct urtw_rf *rf, int chan)
3325dfa03ef6SQin Michael Li {
3326dfa03ef6SQin Michael Li 	struct urtw_softc *sc = rf->rf_sc;
3327dfa03ef6SQin Michael Li 	int error = 0;
3328dfa03ef6SQin Michael Li 
3329dfa03ef6SQin Michael Li 	urtw_8225v2_b_set_txpwrlvl(sc, chan);
3330dfa03ef6SQin Michael Li 	error = urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]);
3331dfa03ef6SQin Michael Li 	if (error)
3332dfa03ef6SQin Michael Li 		goto fail;
3333dfa03ef6SQin Michael Li 	/*
3334dfa03ef6SQin Michael Li 	 * Delay removed from 8185 to 8187.
3335dfa03ef6SQin Michael Li 	 * usbd_delay_ms(sc->sc_udev, 10);
3336dfa03ef6SQin Michael Li 	 */
3337dfa03ef6SQin Michael Li 
3338dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_AC_VO, 0x5114, 0);
3339dfa03ef6SQin Michael Li 	if (error)
3340dfa03ef6SQin Michael Li 		goto fail;
3341dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_AC_VI, 0x5114, 0);
3342dfa03ef6SQin Michael Li 	if (error)
3343dfa03ef6SQin Michael Li 		goto fail;
3344dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_AC_BE, 0x5114, 0);
3345dfa03ef6SQin Michael Li 	if (error)
3346dfa03ef6SQin Michael Li 		goto fail;
3347dfa03ef6SQin Michael Li 	error = urtw_write16_c(sc, URTW_AC_BK, 0x5114, 0);
3348dfa03ef6SQin Michael Li fail:
3349dfa03ef6SQin Michael Li 	return (error);
3350dfa03ef6SQin Michael Li }
3351dfa03ef6SQin Michael Li 
3352dfa03ef6SQin Michael Li void
urtw_8225v2_b_set_txpwrlvl(struct urtw_softc * sc,int chan)3353dfa03ef6SQin Michael Li urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *sc, int chan)
3354dfa03ef6SQin Michael Li {
3355dfa03ef6SQin Michael Li 	int i;
3356dfa03ef6SQin Michael Li 	uint8_t *cck_pwrtable;
3357dfa03ef6SQin Michael Li 	uint8_t cck_pwrlvl_min, cck_pwrlvl_max, ofdm_pwrlvl_min,
3358dfa03ef6SQin Michael Li 	    ofdm_pwrlvl_max;
3359dfa03ef6SQin Michael Li 	int8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3360dfa03ef6SQin Michael Li 	int8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3361dfa03ef6SQin Michael Li 
3362dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3363dfa03ef6SQin Michael Li 		cck_pwrlvl_min = 0;
3364dfa03ef6SQin Michael Li 		cck_pwrlvl_max = 15;
3365dfa03ef6SQin Michael Li 		ofdm_pwrlvl_min = 2;
3366dfa03ef6SQin Michael Li 		ofdm_pwrlvl_max = 17;
3367dfa03ef6SQin Michael Li 	} else {
3368dfa03ef6SQin Michael Li 		cck_pwrlvl_min = 7;
3369dfa03ef6SQin Michael Li 		cck_pwrlvl_max = 22;
3370dfa03ef6SQin Michael Li 		ofdm_pwrlvl_min = 10;
3371dfa03ef6SQin Michael Li 		ofdm_pwrlvl_max = 25;
3372dfa03ef6SQin Michael Li 	}
3373dfa03ef6SQin Michael Li 
3374dfa03ef6SQin Michael Li 	/* CCK power setting */
3375dfa03ef6SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl > (cck_pwrlvl_max - cck_pwrlvl_min)) ?
3376dfa03ef6SQin Michael Li 	    cck_pwrlvl_max : (cck_pwrlvl + cck_pwrlvl_min);
3377dfa03ef6SQin Michael Li 
3378dfa03ef6SQin Michael Li 	cck_pwrlvl += sc->sc_txpwr_cck_base;
3379dfa03ef6SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3380dfa03ef6SQin Michael Li 	cck_pwrlvl = (cck_pwrlvl < 0) ? 0 : cck_pwrlvl;
3381dfa03ef6SQin Michael Li 
3382dfa03ef6SQin Michael Li 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3383dfa03ef6SQin Michael Li 	    urtw_8225v2_txpwr_cck;
3384dfa03ef6SQin Michael Li 
3385dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3386dfa03ef6SQin Michael Li 		if (cck_pwrlvl > 7 && cck_pwrlvl <= 11)
3387dfa03ef6SQin Michael Li 			cck_pwrtable += 8;
3388dfa03ef6SQin Michael Li 		if (cck_pwrlvl > 11)
3389dfa03ef6SQin Michael Li 			cck_pwrtable += 16;
3390dfa03ef6SQin Michael Li 	} else {
3391dfa03ef6SQin Michael Li 		if (cck_pwrlvl > 5 && cck_pwrlvl <= 11)
3392dfa03ef6SQin Michael Li 			cck_pwrtable += 8;
3393dfa03ef6SQin Michael Li 		if (cck_pwrlvl > 12 && cck_pwrlvl <= 17)
3394dfa03ef6SQin Michael Li 			cck_pwrtable += 16;
3395dfa03ef6SQin Michael Li 		if (cck_pwrlvl > 17)
3396dfa03ef6SQin Michael Li 			cck_pwrtable += 24;
3397dfa03ef6SQin Michael Li 	}
3398dfa03ef6SQin Michael Li 
3399dfa03ef6SQin Michael Li 	for (i = 0; i < 8; i++) {
3400dfa03ef6SQin Michael Li 		(void) urtw_8187_write_phy_cck_c(sc, 0x44 + i, cck_pwrtable[i]);
3401dfa03ef6SQin Michael Li 	}
3402dfa03ef6SQin Michael Li 
3403dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_GAIN_CCK,
3404dfa03ef6SQin Michael Li 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1, 0);
3405dfa03ef6SQin Michael Li 	/*
3406dfa03ef6SQin Michael Li 	 * Delay removed from 8185 to 8187.
3407dfa03ef6SQin Michael Li 	 * usbd_delay_ms(sc->sc_udev, 1);
3408dfa03ef6SQin Michael Li 	 */
3409dfa03ef6SQin Michael Li 
3410dfa03ef6SQin Michael Li 	/* OFDM power setting */
3411dfa03ef6SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3412dfa03ef6SQin Michael Li 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3413dfa03ef6SQin Michael Li 
3414dfa03ef6SQin Michael Li 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3415dfa03ef6SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3416dfa03ef6SQin Michael Li 	ofdm_pwrlvl = (ofdm_pwrlvl < 0) ? 0 : ofdm_pwrlvl;
3417dfa03ef6SQin Michael Li 
3418dfa03ef6SQin Michael Li 	(void) urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
3419dfa03ef6SQin Michael Li 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1, 0);
3420dfa03ef6SQin Michael Li 
3421dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3422dfa03ef6SQin Michael Li 		if (ofdm_pwrlvl <= 11) {
3423dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x60);
3424dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x60);
3425dfa03ef6SQin Michael Li 		} else {
3426dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x5c);
3427dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x5c);
3428dfa03ef6SQin Michael Li 		}
3429dfa03ef6SQin Michael Li 	} else {
3430dfa03ef6SQin Michael Li 		if (ofdm_pwrlvl <= 11) {
3431dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x5c);
3432dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x5c);
3433dfa03ef6SQin Michael Li 		} else if (ofdm_pwrlvl <= 17) {
3434dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x54);
3435dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x54);
3436dfa03ef6SQin Michael Li 		} else {
3437dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x50);
3438dfa03ef6SQin Michael Li 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x50);
3439dfa03ef6SQin Michael Li 		}
3440dfa03ef6SQin Michael Li 	}
3441dfa03ef6SQin Michael Li 
3442dfa03ef6SQin Michael Li 	/*
3443dfa03ef6SQin Michael Li 	 * Delay removed from 8185 to 8187.
3444dfa03ef6SQin Michael Li 	 * usbd_delay_ms(sc->sc_udev, 1);
3445dfa03ef6SQin Michael Li 	 */
3446dfa03ef6SQin Michael Li }
3447dfa03ef6SQin Michael Li 
3448dfa03ef6SQin Michael Li 
344926594249SQin Michael Li static int
urtw_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)345026594249SQin Michael Li urtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
345126594249SQin Michael Li {
345226594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)ic;
345326594249SQin Michael Li 	struct ieee80211_frame *wh;
345426594249SQin Michael Li 	struct ieee80211_key *k;
345526594249SQin Michael Li 	struct ieee80211_node *ni = NULL;
345626594249SQin Michael Li 	uint8_t *buf;
345726594249SQin Michael Li 	mblk_t *m = 0, *m0, *mtx;
345826594249SQin Michael Li 	int off, mblen, xferlen, err = 0, priority = 0;
345926594249SQin Michael Li 
346026594249SQin Michael Li 	mutex_enter(&sc->tx_lock);
346126594249SQin Michael Li 	priority = (type == IEEE80211_FC0_TYPE_DATA) ?
346226594249SQin Michael Li 	    LOW_PRIORITY_PIPE: NORMAL_PRIORITY_PIPE;
346326594249SQin Michael Li 
346426594249SQin Michael Li 	if (URTW_IS_SUSPENDING(sc)) {
346526594249SQin Michael Li 		err = 0;
346626594249SQin Michael Li 		goto failed;
346726594249SQin Michael Li 	}
346826594249SQin Michael Li 
346926594249SQin Michael Li 	if (((priority)? sc->sc_tx_normal_queued : sc->sc_tx_low_queued) >=
347026594249SQin Michael Li 	    URTW_TX_DATA_LIST_COUNT) {
347126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
347226594249SQin Michael Li 		    "urtw_send(): no TX buffer!\n"));
347326594249SQin Michael Li 		sc->sc_tx_nobuf++;
347426594249SQin Michael Li 		err = ENOMEM;
347526594249SQin Michael Li 		goto failed;
347626594249SQin Michael Li 	}
347726594249SQin Michael Li 
347826594249SQin Michael Li 	m = allocb(URTW_TXBUF_SIZE, BPRI_MED);
347926594249SQin Michael Li 	if (m == NULL) {
348026594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_send(): can't alloc mblk.\n");
348126594249SQin Michael Li 		err = ENOMEM;
348226594249SQin Michael Li 		goto failed;
348326594249SQin Michael Li 	}
348426594249SQin Michael Li 
348526594249SQin Michael Li 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
348626594249SQin Michael Li 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
348726594249SQin Michael Li 		(void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
348826594249SQin Michael Li 		off += mblen;
348926594249SQin Michael Li 	}
349026594249SQin Michael Li 	m->b_wptr += off;
349126594249SQin Michael Li 
349226594249SQin Michael Li 	wh = (struct ieee80211_frame *)m->b_rptr;
349326594249SQin Michael Li 
349426594249SQin Michael Li 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
349526594249SQin Michael Li 	if (ni == NULL) {
349626594249SQin Michael Li 		err = ENXIO;
349726594249SQin Michael Li 		ic->ic_stats.is_tx_failed++;
349826594249SQin Michael Li 		goto failed;
349926594249SQin Michael Li 	}
350026594249SQin Michael Li 
350126594249SQin Michael Li 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
350226594249SQin Michael Li 	    IEEE80211_FC0_TYPE_DATA) {
350326594249SQin Michael Li 		(void) ieee80211_encap(ic, m, ni);
350426594249SQin Michael Li 	}
350526594249SQin Michael Li 
350626594249SQin Michael Li 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
350726594249SQin Michael Li 		k = ieee80211_crypto_encap(ic, m);
350826594249SQin Michael Li 		if (k == NULL) {
350926594249SQin Michael Li 			ic->ic_stats.is_tx_failed++;
351026594249SQin Michael Li 			err = ENXIO;
351126594249SQin Michael Li 			goto failed;
351226594249SQin Michael Li 		}
351326594249SQin Michael Li 		/* packet header may have moved, reset our local pointer */
351426594249SQin Michael Li 		wh = (struct ieee80211_frame *)m->b_rptr;
351526594249SQin Michael Li 	}
351626594249SQin Michael Li 
3517dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187)
351826594249SQin Michael Li 		xferlen = MBLKL(m) + 4 * 3;
3519dfa03ef6SQin Michael Li 	else
3520dfa03ef6SQin Michael Li 		xferlen = MBLKL(m) + 4 * 8;
3521dfa03ef6SQin Michael Li 
352226594249SQin Michael Li 	if ((0 == xferlen % 64) || (0 == xferlen % 512))
352326594249SQin Michael Li 		xferlen += 1;
352426594249SQin Michael Li 
352526594249SQin Michael Li 	mtx = allocb(xferlen, BPRI_MED);
352626594249SQin Michael Li 	buf = mtx->b_rptr;
352726594249SQin Michael Li 
352826594249SQin Michael Li 	bzero(buf, xferlen);
352926594249SQin Michael Li 	buf[0] = MBLKL(m) & 0xff;
353026594249SQin Michael Li 	buf[1] = (MBLKL(m) & 0x0f00) >> 8;
353126594249SQin Michael Li 	buf[1] |= (1 << 7);
353226594249SQin Michael Li 
353326594249SQin Michael Li 	/* XXX sc_preamble_mode is always 2.  */
353426594249SQin Michael Li 	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
353526594249SQin Michael Li 		buf[2] |= (1 << 1);
353626594249SQin Michael Li 	/* RTS rate - 10 means we use a basic rate.  */
353726594249SQin Michael Li 	buf[2] |= (urtw_rate2rtl(2) << 3);
353826594249SQin Michael Li 	/*
353926594249SQin Michael Li 	 * XXX currently TX rate control depends on the rate value of
354026594249SQin Michael Li 	 * RX descriptor because I don't know how to we can control TX rate
354126594249SQin Michael Li 	 * in more smart way.  Please fix me you find a thing.
354226594249SQin Michael Li 	 */
354326594249SQin Michael Li 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
354426594249SQin Michael Li 		buf[3] = urtw_rate2rtl(MAX(2, urtw_get_rate(ic)));
354526594249SQin Michael Li 	} else
35469530f7fdSQin Michael Li 		buf[3] = 0;
3547dfa03ef6SQin Michael Li 
3548dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
354926594249SQin Michael Li 		buf[8] = 3;		/* CW minimum  */
355026594249SQin Michael Li 		buf[8] |= (7 << 4);	/* CW maximum  */
355126594249SQin Michael Li 		buf[9] |= 11;		/* retry limitation  */
355226594249SQin Michael Li 		bcopy(m->b_rptr, &buf[12], MBLKL(m));
3553dfa03ef6SQin Michael Li 	} else {
3554dfa03ef6SQin Michael Li 		buf[21] |= 11;		/* retry limitation */
3555dfa03ef6SQin Michael Li 		bcopy(m->b_rptr, &buf[32], MBLKL(m));
3556dfa03ef6SQin Michael Li 	}
355726594249SQin Michael Li 
355826594249SQin Michael Li 	(void) urtw_led_ctl(sc, URTW_LED_CTL_TX);
355926594249SQin Michael Li 	mtx->b_wptr = mtx->b_rptr + xferlen;
356026594249SQin Michael Li 
356126594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
3562dfa03ef6SQin Michael Li 	    "sending frame len=%u rate=%u xfer len=%u\n",
356326594249SQin Michael Li 	    MBLKL(m), buf[3], xferlen));
356426594249SQin Michael Li 
356526594249SQin Michael Li 	err = urtw_tx_start(sc, mtx, priority);
356626594249SQin Michael Li 	if (!err) {
356726594249SQin Michael Li 		ic->ic_stats.is_tx_frags++;
356826594249SQin Michael Li 		ic->ic_stats.is_tx_bytes += MBLKL(m);
356926594249SQin Michael Li 	} else {
357026594249SQin Michael Li 		ic->ic_stats.is_tx_failed++;
357126594249SQin Michael Li 	}
357226594249SQin Michael Li 
357326594249SQin Michael Li failed:
357426594249SQin Michael Li 	if (ni != NULL)
357526594249SQin Michael Li 		ieee80211_free_node(ni);
357626594249SQin Michael Li 
357726594249SQin Michael Li 	if ((mp) &&
357826594249SQin Michael Li 	    ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
357926594249SQin Michael Li 	    err == DDI_SUCCESS)) {
358026594249SQin Michael Li 		freemsg(mp);
358126594249SQin Michael Li 	}
358226594249SQin Michael Li 	if (m) freemsg(m);
358326594249SQin Michael Li 
358426594249SQin Michael Li 	if (((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) &&
358526594249SQin Michael Li 	    (err != 0)) {
358626594249SQin Michael Li 		sc->sc_need_sched = 1;
358726594249SQin Michael Li 	}
358826594249SQin Michael Li 	mutex_exit(&sc->tx_lock);
358926594249SQin Michael Li 	return (err);
359026594249SQin Michael Li }
359126594249SQin Michael Li 
359226594249SQin Michael Li static void
urtw_next_scan(void * arg)359326594249SQin Michael Li urtw_next_scan(void *arg)
359426594249SQin Michael Li {
359526594249SQin Michael Li 	ieee80211com_t *ic = arg;
359626594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
359726594249SQin Michael Li 
359826594249SQin Michael Li 	if (URTW_IS_NOT_RUNNING(sc)) {
359926594249SQin Michael Li 		sc->sc_scan_id = 0;
360026594249SQin Michael Li 		return;
360126594249SQin Michael Li 	}
360226594249SQin Michael Li 
360326594249SQin Michael Li 	if (ic->ic_state == IEEE80211_S_SCAN) {
360426594249SQin Michael Li 		(void) ieee80211_next_scan(ic);
360526594249SQin Michael Li 	}
360626594249SQin Michael Li 	sc->sc_scan_id = 0;
360726594249SQin Michael Li }
360826594249SQin Michael Li 
360926594249SQin Michael Li static void
urtw_led_launch(void * arg)361026594249SQin Michael Li urtw_led_launch(void *arg)
361126594249SQin Michael Li {
361226594249SQin Michael Li 	struct urtw_softc *sc = arg;
361326594249SQin Michael Li 	ieee80211com_t *ic = &sc->sc_ic;
361426594249SQin Michael Li 	int error = 0;
361526594249SQin Michael Li 
361626594249SQin Michael Li 	URTW_LEDLOCK(sc);
361726594249SQin Michael Li 	if ((sc->sc_strategy != URTW_SW_LED_MODE0) ||
361826594249SQin Michael Li 	    URTW_IS_NOT_RUNNING(sc) ||
361926594249SQin Michael Li 	    URTW_IS_SUSPENDING(sc)) {
362026594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
362126594249SQin Michael Li 		    "failed process LED strategy 0x%x, run?%d",
362226594249SQin Michael Li 		    sc->sc_strategy,
362326594249SQin Michael Li 		    sc->sc_flags));
362426594249SQin Michael Li 		sc->sc_led_ch = 0;
362526594249SQin Michael Li 		sc->sc_gpio_ledinprogress = 0;
362626594249SQin Michael Li 		URTW_LEDUNLOCK(sc);
362726594249SQin Michael Li 		return;
362826594249SQin Michael Li 	}
362926594249SQin Michael Li 	error = urtw_led_blink(sc);
363026594249SQin Michael Li 	if (error) {
363126594249SQin Michael Li 		sc->sc_led_ch = timeout(urtw_led_launch, (void *)sc,
363226594249SQin Michael Li 		    drv_usectohz((ic->ic_state == IEEE80211_S_RUN) ?
363326594249SQin Michael Li 		    URTW_LED_LINKON_BLINK: URTW_LED_LINKOFF_BLINK));
363426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
363526594249SQin Michael Li 		    "try again led launch"));
363626594249SQin Michael Li 	} else {
363726594249SQin Michael Li 		sc->sc_led_ch = 0;
363826594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
363926594249SQin Michael Li 		    "exit led launch"));
364026594249SQin Michael Li 	}
364126594249SQin Michael Li 	URTW_LEDUNLOCK(sc);
364226594249SQin Michael Li }
364326594249SQin Michael Li 
364426594249SQin Michael Li static int
urtw_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)364526594249SQin Michael Li urtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
364626594249SQin Michael Li {
364726594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)ic;
364826594249SQin Michael Li 	struct ieee80211_node *ni;
364926594249SQin Michael Li 	int error = 0;
365026594249SQin Michael Li 
365126594249SQin Michael Li 	if (sc->sc_scan_id != 0) {
365226594249SQin Michael Li 		(void) untimeout(sc->sc_scan_id);
365326594249SQin Michael Li 		sc->sc_scan_id = 0;
365426594249SQin Michael Li 	}
365526594249SQin Michael Li 	URTW_LOCK(sc);
365626594249SQin Michael Li 	switch (nstate) {
365726594249SQin Michael Li 	case IEEE80211_S_INIT:
365826594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE,
365926594249SQin Michael Li 		    (sc->sc_dev, CE_CONT, "-> IEEE80211_S_INIT...arg(%d)\n",
366026594249SQin Michael Li 		    arg));
3661dfa03ef6SQin Michael Li 		if (sc->sc_flags & URTW_FLAG_HP)
3662dfa03ef6SQin Michael Li 			break;
366326594249SQin Michael Li 		(void) urtw_update_msr(sc, nstate);
366426594249SQin Michael Li 		(void) urtw_led_off(sc, URTW_LED_GPIO);
366526594249SQin Michael Li 		break;
366626594249SQin Michael Li 
366726594249SQin Michael Li 	case IEEE80211_S_SCAN:
366826594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE,
366926594249SQin Michael Li 		    (sc->sc_dev, CE_CONT,
367026594249SQin Michael Li 		    "-> IEEE80211_S_SCAN...arg(%d)...[%d]\n",
367126594249SQin Michael Li 		    arg, ieee80211_chan2ieee(ic, ic->ic_curchan)));
367226594249SQin Michael Li 		error = urtw_set_channel(sc);
367326594249SQin Michael Li 		if (error) {
367426594249SQin Michael Li 			URTW8187_DBG(URTW_DEBUG_STATE,
367526594249SQin Michael Li 			    (sc->sc_dev, CE_CONT, "scan setchan failed"));
367626594249SQin Michael Li 			break;
367726594249SQin Michael Li 		}
367826594249SQin Michael Li 		sc->sc_scan_id = timeout(urtw_next_scan, (void *)sc,
367926594249SQin Michael Li 		    drv_usectohz(sc->dwelltime * 1000));
368026594249SQin Michael Li 		break;
368126594249SQin Michael Li 
368226594249SQin Michael Li 	case IEEE80211_S_AUTH:
368326594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3684dfa03ef6SQin Michael Li 		    "-> IEEE80211_S_AUTH ...arg(%d), chan (%d)\n", arg,
3685dfa03ef6SQin Michael Li 		    ieee80211_chan2ieee(ic, ic->ic_curchan)));
368626594249SQin Michael Li 		error = urtw_set_channel(sc);
368726594249SQin Michael Li 		if (error) {
368826594249SQin Michael Li 			URTW8187_DBG(URTW_DEBUG_STATE,
368926594249SQin Michael Li 			    (sc->sc_dev,  CE_CONT, "auth setchan failed"));
369026594249SQin Michael Li 		}
369126594249SQin Michael Li 		break;
369226594249SQin Michael Li 
369326594249SQin Michael Li 	case IEEE80211_S_ASSOC:
369426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3695dfa03ef6SQin Michael Li 		    "-> IEEE80211_S_ASSOC ...arg(%d), chan (%d)\n", arg,
3696dfa03ef6SQin Michael Li 		    ieee80211_chan2ieee(ic, ic->ic_curchan)));
369726594249SQin Michael Li 		error = urtw_set_channel(sc);
369826594249SQin Michael Li 		if (error) {
369926594249SQin Michael Li 			URTW8187_DBG(URTW_DEBUG_STATE,
370026594249SQin Michael Li 			    (sc->sc_dev, CE_CONT, "assoc setchan failed"));
370126594249SQin Michael Li 		}
370226594249SQin Michael Li 		break;
370326594249SQin Michael Li 
370426594249SQin Michael Li 	case IEEE80211_S_RUN:
370526594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE,
3706dfa03ef6SQin Michael Li 		    (sc->sc_dev, CE_CONT,
3707dfa03ef6SQin Michael Li 		    "-> IEEE80211_S_RUN ...arg(%d), chan (%d)\n",
3708dfa03ef6SQin Michael Li 		    arg, ieee80211_chan2ieee(ic, ic->ic_curchan)));
370926594249SQin Michael Li 		error = urtw_set_channel(sc);
371026594249SQin Michael Li 		if (error) {
371126594249SQin Michael Li 			URTW8187_DBG(URTW_DEBUG_STATE,
371226594249SQin Michael Li 			    (sc->sc_dev, CE_CONT, "run setchan failed"));
371326594249SQin Michael Li 			goto fail;
371426594249SQin Michael Li 		}
371526594249SQin Michael Li 		ni = ic->ic_bss;
371626594249SQin Michael Li 		/* setting bssid.  */
371726594249SQin Michael Li 		(void) urtw_write32_c(sc, URTW_BSSID,
3718dfa03ef6SQin Michael Li 		    ((uint32_t *)(uintptr_t)ni->in_bssid)[0], 0);
371926594249SQin Michael Li 		(void) urtw_write16_c(sc, URTW_BSSID + 4,
3720dfa03ef6SQin Michael Li 		    ((uint16_t *)(uintptr_t)ni->in_bssid)[2], 0);
372126594249SQin Michael Li 		(void) urtw_update_msr(sc, nstate);
372226594249SQin Michael Li 
372326594249SQin Michael Li 		ni->in_txrate = ni->in_rates.ir_nrates - 1;
372426594249SQin Michael Li 		break;
372526594249SQin Michael Li 	}
372626594249SQin Michael Li fail:
372726594249SQin Michael Li 	URTW_UNLOCK(sc);
372826594249SQin Michael Li 
3729dfa03ef6SQin Michael Li 	if (error) {
3730dfa03ef6SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3731dfa03ef6SQin Michael Li 		    "-> newstate error...arg(%d)\n", error));
373226594249SQin Michael Li 		return (EIO);
3733dfa03ef6SQin Michael Li 	}
373426594249SQin Michael Li 	error = sc->sc_newstate(ic, nstate, arg);
373526594249SQin Michael Li 	return (error);
373626594249SQin Michael Li }
373726594249SQin Michael Li 
373826594249SQin Michael Li static void
urtw_close_pipes(struct urtw_softc * sc)373926594249SQin Michael Li urtw_close_pipes(struct urtw_softc *sc)
374026594249SQin Michael Li {
374126594249SQin Michael Li 	usb_flags_t flags = USB_FLAGS_SLEEP;
374226594249SQin Michael Li 
374326594249SQin Michael Li 	if (sc->sc_rxpipe != NULL) {
374426594249SQin Michael Li 		usb_pipe_reset(sc->sc_dev,
374526594249SQin Michael Li 		    sc->sc_rxpipe, flags, NULL, 0);
374626594249SQin Michael Li 		usb_pipe_close(sc->sc_dev,
374726594249SQin Michael Li 		    sc->sc_rxpipe, flags, NULL, 0);
374826594249SQin Michael Li 		sc->sc_rxpipe = NULL;
374926594249SQin Michael Li 	}
375026594249SQin Michael Li 
375126594249SQin Michael Li 	if (sc->sc_txpipe_low != NULL) {
375226594249SQin Michael Li 		usb_pipe_reset(sc->sc_dev,
375326594249SQin Michael Li 		    sc->sc_txpipe_low, flags, NULL, 0);
375426594249SQin Michael Li 		usb_pipe_close(sc->sc_dev,
375526594249SQin Michael Li 		    sc->sc_txpipe_low, flags, NULL, 0);
375626594249SQin Michael Li 		sc->sc_txpipe_low = NULL;
375726594249SQin Michael Li 	}
375826594249SQin Michael Li 
375926594249SQin Michael Li 	if (sc->sc_txpipe_normal != NULL) {
376026594249SQin Michael Li 		usb_pipe_reset(sc->sc_dev,
376126594249SQin Michael Li 		    sc->sc_txpipe_normal, flags, NULL, 0);
376226594249SQin Michael Li 		usb_pipe_close(sc->sc_dev,
376326594249SQin Michael Li 		    sc->sc_txpipe_normal, flags, NULL, 0);
376426594249SQin Michael Li 		sc->sc_txpipe_normal = NULL;
376526594249SQin Michael Li 	}
376626594249SQin Michael Li }
376726594249SQin Michael Li 
376826594249SQin Michael Li static int
urtw_open_pipes(struct urtw_softc * sc)376926594249SQin Michael Li urtw_open_pipes(struct urtw_softc *sc)
377026594249SQin Michael Li {
377126594249SQin Michael Li 	usb_ep_data_t *ep_node;
377226594249SQin Michael Li 	usb_pipe_policy_t policy;
377326594249SQin Michael Li 	int err;
3774dfa03ef6SQin Michael Li 	uint_t skip = 0;
377526594249SQin Michael Li 
377626594249SQin Michael Li 	if (sc->sc_rxpipe || sc->sc_txpipe_low || sc->sc_txpipe_normal)
377726594249SQin Michael Li 		return (USB_SUCCESS);
377826594249SQin Michael Li 
3779dfa03ef6SQin Michael Li 	if ((sc->sc_hwrev & URTW_HWREV_8187) == 0) {
3780dfa03ef6SQin Michael Li 		skip = 2;
3781dfa03ef6SQin Michael Li 	}
378226594249SQin Michael Li 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3783dfa03ef6SQin Michael Li 	    LOW_PRIORITY_PIPE + skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
378426594249SQin Michael Li 
378526594249SQin Michael Li 	bzero(&policy, sizeof (usb_pipe_policy_t));
378626594249SQin Michael Li 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
378726594249SQin Michael Li 
378826594249SQin Michael Li 	if ((err = usb_pipe_open(sc->sc_dev,
378926594249SQin Michael Li 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
379026594249SQin Michael Li 	    &sc->sc_txpipe_low)) != USB_SUCCESS) {
379126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
379226594249SQin Michael Li 		    "urtw_open_pipes(): %x low priority pipe open failed\n",
379326594249SQin Michael Li 		    err));
379426594249SQin Michael Li 		goto fail;
379526594249SQin Michael Li 	}
379626594249SQin Michael Li 
379726594249SQin Michael Li 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3798dfa03ef6SQin Michael Li 	    NORMAL_PRIORITY_PIPE + skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
379926594249SQin Michael Li 
380026594249SQin Michael Li 	bzero(&policy, sizeof (usb_pipe_policy_t));
380126594249SQin Michael Li 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
380226594249SQin Michael Li 
380326594249SQin Michael Li 	if ((err = usb_pipe_open(sc->sc_dev,
380426594249SQin Michael Li 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
380526594249SQin Michael Li 	    &sc->sc_txpipe_normal)) != USB_SUCCESS) {
380626594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
380726594249SQin Michael Li 		    "urtw_open_pipes(): %x failed to open high tx pipe\n",
380826594249SQin Michael Li 		    err));
380926594249SQin Michael Li 		goto fail;
381026594249SQin Michael Li 	}
381126594249SQin Michael Li 
381226594249SQin Michael Li 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
381326594249SQin Michael Li 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
381426594249SQin Michael Li 
381526594249SQin Michael Li 	bzero(&policy, sizeof (usb_pipe_policy_t));
381626594249SQin Michael Li 	policy.pp_max_async_reqs = URTW_RX_DATA_LIST_COUNT;
381726594249SQin Michael Li 
381826594249SQin Michael Li 	if ((err = usb_pipe_open(sc->sc_dev,
381926594249SQin Michael Li 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
382026594249SQin Michael Li 	    &sc->sc_rxpipe)) != USB_SUCCESS) {
382126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
382226594249SQin Michael Li 		    "urtw_open_pipes(): %x failed to open rx pipe\n", err));
382326594249SQin Michael Li 		goto fail;
382426594249SQin Michael Li 	}
382526594249SQin Michael Li 
382626594249SQin Michael Li 	return (USB_SUCCESS);
382726594249SQin Michael Li 
382826594249SQin Michael Li fail:
382926594249SQin Michael Li 	urtw_close_pipes(sc);
383026594249SQin Michael Li 	return (USB_FAILURE);
383126594249SQin Michael Li }
383226594249SQin Michael Li 
383326594249SQin Michael Li static int
urtw_tx_start(struct urtw_softc * sc,mblk_t * mp,int priority)383426594249SQin Michael Li urtw_tx_start(struct urtw_softc *sc, mblk_t *mp, int priority)
383526594249SQin Michael Li {
383626594249SQin Michael Li 	usb_bulk_req_t *req;
383726594249SQin Michael Li 	int err;
383826594249SQin Michael Li 
383926594249SQin Michael Li 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
384026594249SQin Michael Li 	if (req == NULL) {
384126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
384226594249SQin Michael Li 		    "urtw_tx_start(): failed to allocate req"));
384326594249SQin Michael Li 		freemsg(mp);
384426594249SQin Michael Li 		return (-1);
384526594249SQin Michael Li 	}
384626594249SQin Michael Li 
384726594249SQin Michael Li 	req->bulk_len = MBLKL(mp);
384826594249SQin Michael Li 	req->bulk_data = mp;
384926594249SQin Michael Li 	req->bulk_client_private = (usb_opaque_t)sc;
385026594249SQin Michael Li 	req->bulk_timeout = URTW_TX_TIMEOUT;
385126594249SQin Michael Li 	req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
385226594249SQin Michael Li 	req->bulk_cb = (priority)?urtw_txeof_normal : urtw_txeof_low;
385326594249SQin Michael Li 	req->bulk_exc_cb = (priority)?urtw_txeof_normal: urtw_txeof_low;
385426594249SQin Michael Li 	req->bulk_completion_reason = 0;
385526594249SQin Michael Li 	req->bulk_cb_flags = 0;
385626594249SQin Michael Li 
385726594249SQin Michael Li 	if ((err = usb_pipe_bulk_xfer(
385826594249SQin Michael Li 	    (priority)?sc->sc_txpipe_normal:sc->sc_txpipe_low, req, 0))
385926594249SQin Michael Li 	    != USB_SUCCESS) {
386026594249SQin Michael Li 		sc->sc_ic.ic_stats.is_tx_failed++;
386126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
386226594249SQin Michael Li 		    "urtw_tx_start: failed to do tx xfer, %d", err));
386326594249SQin Michael Li 		usb_free_bulk_req(req);
386426594249SQin Michael Li 		return (EIO);
386526594249SQin Michael Li 	}
386626594249SQin Michael Li 
386726594249SQin Michael Li 	if (priority) {
386826594249SQin Michael Li 		sc->sc_tx_normal_queued++;
386926594249SQin Michael Li 	} else {
387026594249SQin Michael Li 		sc->sc_tx_low_queued++;
387126594249SQin Michael Li 	}
387226594249SQin Michael Li 
387326594249SQin Michael Li 	return (0);
387426594249SQin Michael Li }
387526594249SQin Michael Li 
387626594249SQin Michael Li static int
urtw_rx_start(struct urtw_softc * sc)387726594249SQin Michael Li urtw_rx_start(struct urtw_softc *sc)
387826594249SQin Michael Li {
387926594249SQin Michael Li 	usb_bulk_req_t *req;
388026594249SQin Michael Li 	int err;
388126594249SQin Michael Li 
388226594249SQin Michael Li 	req = usb_alloc_bulk_req(sc->sc_dev, URTW_RXBUF_SIZE, USB_FLAGS_SLEEP);
388326594249SQin Michael Li 	if (req == NULL) {
388426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
388526594249SQin Michael Li 		    "urtw_rx_start(): failed to allocate req"));
388626594249SQin Michael Li 		return (-1);
388726594249SQin Michael Li 	}
388826594249SQin Michael Li 
388926594249SQin Michael Li 	req->bulk_len		= URTW_RXBUF_SIZE;
389026594249SQin Michael Li 	req->bulk_client_private = (usb_opaque_t)sc;
389126594249SQin Michael Li 	req->bulk_timeout	= 0;
389226594249SQin Michael Li 	req->bulk_attributes	= USB_ATTRS_SHORT_XFER_OK |
389326594249SQin Michael Li 	    USB_ATTRS_AUTOCLEARING;
389426594249SQin Michael Li 	req->bulk_cb		= urtw_rxeof;
389526594249SQin Michael Li 	req->bulk_exc_cb	= urtw_rxeof;
389626594249SQin Michael Li 	req->bulk_completion_reason = 0;
389726594249SQin Michael Li 	req->bulk_cb_flags	= 0;
389826594249SQin Michael Li 
389926594249SQin Michael Li 	err = usb_pipe_bulk_xfer(sc->sc_rxpipe, req, 0);
390026594249SQin Michael Li 
390126594249SQin Michael Li 	if (err != USB_SUCCESS) {
390226594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
390326594249SQin Michael Li 		    "urtw_rx_start: failed to do rx xfer, %d", err));
390426594249SQin Michael Li 		usb_free_bulk_req(req);
390526594249SQin Michael Li 		return (-1);
390626594249SQin Michael Li 	}
390726594249SQin Michael Li 
390826594249SQin Michael Li 	mutex_enter(&sc->rx_lock);
390926594249SQin Michael Li 	sc->rx_queued++;
391026594249SQin Michael Li 	mutex_exit(&sc->rx_lock);
391126594249SQin Michael Li 
391226594249SQin Michael Li 	return (0);
391326594249SQin Michael Li }
391426594249SQin Michael Li 
391526594249SQin Michael Li static int
urtw_disconnect(dev_info_t * devinfo)391626594249SQin Michael Li urtw_disconnect(dev_info_t *devinfo)
391726594249SQin Michael Li {
391826594249SQin Michael Li 	struct urtw_softc *sc;
391926594249SQin Michael Li 
392026594249SQin Michael Li 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
392126594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_HOTPLUG,
392226594249SQin Michael Li 	    (sc->sc_dev, CE_CONT, "urtw_offline()\n"));
392326594249SQin Michael Li 
392426594249SQin Michael Li 	if (URTW_IS_RUNNING(sc)) {
392526594249SQin Michael Li 		urtw_stop(sc);
392626594249SQin Michael Li 		URTW_LOCK(sc);
392726594249SQin Michael Li 		sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
392826594249SQin Michael Li 		URTW_UNLOCK(sc);
392926594249SQin Michael Li 	}
3930dfa03ef6SQin Michael Li 	sc->sc_flags |= URTW_FLAG_HP;
3931dfa03ef6SQin Michael Li 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3932dfa03ef6SQin Michael Li 	ieee80211_stop_watchdog(&sc->sc_ic);
393326594249SQin Michael Li 	return (DDI_SUCCESS);
393426594249SQin Michael Li }
393526594249SQin Michael Li 
393626594249SQin Michael Li static int
urtw_reconnect(dev_info_t * devinfo)393726594249SQin Michael Li urtw_reconnect(dev_info_t *devinfo)
393826594249SQin Michael Li {
393926594249SQin Michael Li 	struct urtw_softc *sc;
394026594249SQin Michael Li 	int error = 0;
394126594249SQin Michael Li 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
394226594249SQin Michael Li 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
394326594249SQin Michael Li 	    USB_CHK_ALL, NULL) != USB_SUCCESS)
394426594249SQin Michael Li 		return (DDI_FAILURE);
394526594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_HOTPLUG, (sc->sc_dev, CE_CONT,
394626594249SQin Michael Li 	    "urtw_online()\n"));
3947dfa03ef6SQin Michael Li 	sc->sc_flags &= ~URTW_FLAG_HP;
394826594249SQin Michael Li 	if (URTW_IS_PLUGIN_ONLINE(sc)) {
3949dfa03ef6SQin Michael Li 		error = sc->urtw_init(sc);
395026594249SQin Michael Li 		if (!error) {
395126594249SQin Michael Li 			URTW_LOCK(sc);
395226594249SQin Michael Li 			sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
395326594249SQin Michael Li 			URTW_UNLOCK(sc);
395426594249SQin Michael Li 		}
395526594249SQin Michael Li 	}
3956dfa03ef6SQin Michael Li 	return (error? DDI_FAILURE: DDI_SUCCESS);
395726594249SQin Michael Li }
395826594249SQin Michael Li 
395926594249SQin Michael Li static mblk_t *
urtw_m_tx(void * arg,mblk_t * mp)396026594249SQin Michael Li urtw_m_tx(void *arg, mblk_t *mp)
396126594249SQin Michael Li {
396226594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
396326594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
396426594249SQin Michael Li 	mblk_t *next;
396526594249SQin Michael Li 
396626594249SQin Michael Li 	if ((ic->ic_state != IEEE80211_S_RUN) ||
396726594249SQin Michael Li 	    URTW_IS_SUSPENDING(sc)) {
396826594249SQin Michael Li 		freemsgchain(mp);
396926594249SQin Michael Li 		return (NULL);
397026594249SQin Michael Li 	}
397126594249SQin Michael Li 
397226594249SQin Michael Li 	while (mp != NULL) {
397326594249SQin Michael Li 		next = mp->b_next;
397426594249SQin Michael Li 		mp->b_next = NULL;
397526594249SQin Michael Li 		if (urtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
397626594249SQin Michael Li 			mp->b_next = next;
397726594249SQin Michael Li 			break;
397826594249SQin Michael Li 		}
397926594249SQin Michael Li 		mp = next;
398026594249SQin Michael Li 	}
398126594249SQin Michael Li 	return (mp);
398226594249SQin Michael Li }
398326594249SQin Michael Li 
398426594249SQin Michael Li static int
urtw_m_start(void * arg)398526594249SQin Michael Li urtw_m_start(void *arg)
398626594249SQin Michael Li {
398726594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
398826594249SQin Michael Li 	int error = 0;
398926594249SQin Michael Li 
399026594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_ACTIVE,
3991dfa03ef6SQin Michael Li 	    (sc->sc_dev, CE_CONT, "urtw_m_start\n"));
3992dfa03ef6SQin Michael Li 	error = sc->urtw_init(sc);
399326594249SQin Michael Li 	return (error);
399426594249SQin Michael Li }
399526594249SQin Michael Li 
399626594249SQin Michael Li static void
urtw_m_stop(void * arg)399726594249SQin Michael Li urtw_m_stop(void *arg)
399826594249SQin Michael Li {
399926594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
400026594249SQin Michael Li 
400126594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
400226594249SQin Michael Li 	    "urtw_m_stop()\n"));
400326594249SQin Michael Li 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
400426594249SQin Michael Li 	ieee80211_stop_watchdog(&sc->sc_ic);
400526594249SQin Michael Li 	(void) urtw_stop(sc);
400626594249SQin Michael Li }
400726594249SQin Michael Li 
400826594249SQin Michael Li /*ARGSUSED*/
400926594249SQin Michael Li static int
urtw_m_unicst(void * arg,const uint8_t * macaddr)401026594249SQin Michael Li urtw_m_unicst(void *arg, const uint8_t *macaddr)
401126594249SQin Michael Li {
401226594249SQin Michael Li 	return (ENOTSUP);
401326594249SQin Michael Li }
401426594249SQin Michael Li 
401526594249SQin Michael Li /*ARGSUSED*/
401626594249SQin Michael Li static int
urtw_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)401726594249SQin Michael Li urtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
401826594249SQin Michael Li {
401926594249SQin Michael Li 	return (ENOTSUP);
402026594249SQin Michael Li }
402126594249SQin Michael Li 
402226594249SQin Michael Li /*ARGSUSED*/
402326594249SQin Michael Li static int
urtw_m_promisc(void * arg,boolean_t on)402426594249SQin Michael Li urtw_m_promisc(void *arg, boolean_t on)
402526594249SQin Michael Li {
402626594249SQin Michael Li 	return (0);
402726594249SQin Michael Li }
402826594249SQin Michael Li 
402926594249SQin Michael Li static int
urtw_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)4030dfa03ef6SQin Michael Li urtw_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4031*0dc2366fSVenugopal Iyer     uint_t wldp_length, void *wldp_buf)
4032dfa03ef6SQin Michael Li {
4033dfa03ef6SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
4034dfa03ef6SQin Michael Li 	int err = 0;
4035dfa03ef6SQin Michael Li 
4036dfa03ef6SQin Michael Li 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
4037*0dc2366fSVenugopal Iyer 	    wldp_length, wldp_buf);
4038dfa03ef6SQin Michael Li 	return (err);
4039dfa03ef6SQin Michael Li }
4040dfa03ef6SQin Michael Li 
4041*0dc2366fSVenugopal Iyer static void
urtw_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)4042*0dc2366fSVenugopal Iyer urtw_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4043*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t mph)
4044*0dc2366fSVenugopal Iyer {
4045*0dc2366fSVenugopal Iyer 	struct urtw_softc *sc = (struct urtw_softc *)arg;
4046*0dc2366fSVenugopal Iyer 
4047*0dc2366fSVenugopal Iyer 	ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, mph);
4048*0dc2366fSVenugopal Iyer }
4049*0dc2366fSVenugopal Iyer 
4050dfa03ef6SQin Michael Li static int
urtw_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)405126594249SQin Michael Li urtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
405226594249SQin Michael Li     uint_t wldp_length, const void *wldp_buf)
405326594249SQin Michael Li {
405426594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
405526594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
405626594249SQin Michael Li 	int err;
405726594249SQin Michael Li 
405826594249SQin Michael Li 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
405926594249SQin Michael Li 	    wldp_length, wldp_buf);
4060dfa03ef6SQin Michael Li 	URTW_LOCK(sc);
406126594249SQin Michael Li 	if (err == ENETRESET) {
4062dfa03ef6SQin Michael Li 		if (URTW_IS_RUNNING(sc) && ic->ic_des_esslen) {
4063dfa03ef6SQin Michael Li 			URTW_UNLOCK(sc);
4064dfa03ef6SQin Michael Li 			err = sc->urtw_init(sc);
4065dfa03ef6SQin Michael Li 			if (err) {
4066dfa03ef6SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4067dfa03ef6SQin Michael Li 				    (sc->sc_dev, CE_CONT,
4068dfa03ef6SQin Michael Li 				    "urtw: setprop failed\n"));
4069dfa03ef6SQin Michael Li 				return (err);
4070dfa03ef6SQin Michael Li 			}
407126594249SQin Michael Li 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
4072dfa03ef6SQin Michael Li 			URTW_LOCK(sc);
407326594249SQin Michael Li 		}
407426594249SQin Michael Li 		err = 0;
407526594249SQin Michael Li 	}
4076dfa03ef6SQin Michael Li 	URTW_UNLOCK(sc);
407726594249SQin Michael Li 	return (err);
407826594249SQin Michael Li }
407926594249SQin Michael Li 
408026594249SQin Michael Li static void
urtw_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)408126594249SQin Michael Li urtw_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
408226594249SQin Michael Li {
408326594249SQin Michael Li 	struct urtw_softc *sc = (struct urtw_softc *)arg;
408426594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
408526594249SQin Michael Li 	int err;
408626594249SQin Michael Li 
408726594249SQin Michael Li 	err = ieee80211_ioctl(ic, wq, mp);
4088dfa03ef6SQin Michael Li 	URTW_LOCK(sc);
408926594249SQin Michael Li 	if (err == ENETRESET) {
4090dfa03ef6SQin Michael Li 		if (URTW_IS_RUNNING(sc) && ic->ic_des_esslen) {
4091dfa03ef6SQin Michael Li 			URTW_UNLOCK(sc);
4092dfa03ef6SQin Michael Li 			err = sc->urtw_init(sc);
4093dfa03ef6SQin Michael Li 			if (err) {
4094dfa03ef6SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4095dfa03ef6SQin Michael Li 				    (sc->sc_dev,
4096dfa03ef6SQin Michael Li 				    CE_CONT, "urtw: dev init failed\n"));
4097dfa03ef6SQin Michael Li 				return;
4098dfa03ef6SQin Michael Li 			}
4099dfa03ef6SQin Michael Li 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
4100dfa03ef6SQin Michael Li 			URTW_LOCK(sc);
410126594249SQin Michael Li 		}
410226594249SQin Michael Li 	}
4103dfa03ef6SQin Michael Li 	URTW_UNLOCK(sc);
410426594249SQin Michael Li }
410526594249SQin Michael Li 
410626594249SQin Michael Li static int
urtw_m_stat(void * arg,uint_t stat,uint64_t * val)410726594249SQin Michael Li urtw_m_stat(void *arg, uint_t stat, uint64_t *val)
410826594249SQin Michael Li {
410926594249SQin Michael Li 	struct urtw_softc *sc  = (struct urtw_softc *)arg;
411026594249SQin Michael Li 	ieee80211com_t	*ic = &sc->sc_ic;
411126594249SQin Michael Li 	ieee80211_node_t *ni = 0;
411226594249SQin Michael Li 	struct ieee80211_rateset *rs = 0;
411326594249SQin Michael Li 
411426594249SQin Michael Li 	URTW_LOCK(sc);
411526594249SQin Michael Li 	switch (stat) {
411626594249SQin Michael Li 	case MAC_STAT_IFSPEED:
411726594249SQin Michael Li 		ni = ic->ic_bss;
411826594249SQin Michael Li 		rs = &ni->in_rates;
411926594249SQin Michael Li 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
412026594249SQin Michael Li 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
412126594249SQin Michael Li 		    : ic->ic_fixed_rate) / 2 * 1000000;
412226594249SQin Michael Li 		break;
412326594249SQin Michael Li 	case MAC_STAT_NOXMTBUF:
412426594249SQin Michael Li 		*val = sc->sc_tx_nobuf;
412526594249SQin Michael Li 		break;
412626594249SQin Michael Li 	case MAC_STAT_NORCVBUF:
412726594249SQin Michael Li 		*val = sc->sc_rx_nobuf;
412826594249SQin Michael Li 		break;
412926594249SQin Michael Li 	case MAC_STAT_IERRORS:
413026594249SQin Michael Li 		*val = sc->sc_rx_err;
413126594249SQin Michael Li 		break;
413226594249SQin Michael Li 	case MAC_STAT_RBYTES:
413326594249SQin Michael Li 		*val = ic->ic_stats.is_rx_bytes;
413426594249SQin Michael Li 		break;
413526594249SQin Michael Li 	case MAC_STAT_IPACKETS:
413626594249SQin Michael Li 		*val = ic->ic_stats.is_rx_frags;
413726594249SQin Michael Li 		break;
413826594249SQin Michael Li 	case MAC_STAT_OBYTES:
413926594249SQin Michael Li 		*val = ic->ic_stats.is_tx_bytes;
414026594249SQin Michael Li 		break;
414126594249SQin Michael Li 	case MAC_STAT_OPACKETS:
414226594249SQin Michael Li 		*val = ic->ic_stats.is_tx_frags;
414326594249SQin Michael Li 		break;
414426594249SQin Michael Li 	case MAC_STAT_OERRORS:
414526594249SQin Michael Li 		*val = ic->ic_stats.is_tx_failed;
414626594249SQin Michael Li 		break;
414726594249SQin Michael Li 	case WIFI_STAT_TX_FRAGS:
414826594249SQin Michael Li 	case WIFI_STAT_MCAST_TX:
414926594249SQin Michael Li 	case WIFI_STAT_TX_FAILED:
415026594249SQin Michael Li 	case WIFI_STAT_TX_RETRANS:
415126594249SQin Michael Li 	case WIFI_STAT_RTS_SUCCESS:
415226594249SQin Michael Li 	case WIFI_STAT_RTS_FAILURE:
415326594249SQin Michael Li 	case WIFI_STAT_ACK_FAILURE:
415426594249SQin Michael Li 	case WIFI_STAT_RX_FRAGS:
415526594249SQin Michael Li 	case WIFI_STAT_MCAST_RX:
415626594249SQin Michael Li 	case WIFI_STAT_FCS_ERRORS:
415726594249SQin Michael Li 	case WIFI_STAT_WEP_ERRORS:
415826594249SQin Michael Li 	case WIFI_STAT_RX_DUPS:
415926594249SQin Michael Li 		URTW_UNLOCK(sc);
416026594249SQin Michael Li 		return (ieee80211_stat(ic, stat, val));
416126594249SQin Michael Li 	default:
416226594249SQin Michael Li 		URTW_UNLOCK(sc);
416326594249SQin Michael Li 		return (ENOTSUP);
416426594249SQin Michael Li 	}
416526594249SQin Michael Li 	URTW_UNLOCK(sc);
416626594249SQin Michael Li 
416726594249SQin Michael Li 	return (0);
416826594249SQin Michael Li }
416926594249SQin Michael Li 
417026594249SQin Michael Li static void
urtw_watchdog(void * arg)417126594249SQin Michael Li urtw_watchdog(void *arg)
417226594249SQin Michael Li {
417326594249SQin Michael Li 	struct urtw_softc *sc = arg;
417426594249SQin Michael Li 	struct ieee80211com *ic = &sc->sc_ic;
417526594249SQin Michael Li 
417626594249SQin Michael Li 	ieee80211_stop_watchdog(ic);
417726594249SQin Michael Li 
417826594249SQin Michael Li 	URTW_LOCK(sc);
417926594249SQin Michael Li 	if (URTW_IS_NOT_RUNNING(sc)) {
418026594249SQin Michael Li 		URTW_UNLOCK(sc);
418126594249SQin Michael Li 		return;
418226594249SQin Michael Li 	}
418326594249SQin Michael Li 
418426594249SQin Michael Li 	URTW_UNLOCK(sc);
418526594249SQin Michael Li 	switch (ic->ic_state) {
418626594249SQin Michael Li 		case IEEE80211_S_AUTH:
418726594249SQin Michael Li 		case IEEE80211_S_ASSOC:
4188dfa03ef6SQin Michael Li 			if (ic->ic_bss->in_fails > 0) {
418926594249SQin Michael Li 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
4190dfa03ef6SQin Michael Li 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4191dfa03ef6SQin Michael Li 				    (sc->sc_dev, CE_CONT,
4192dfa03ef6SQin Michael Li 				    "urtw: watchdog begin\n"));
4193dfa03ef6SQin Michael Li 			} else
419426594249SQin Michael Li 				ieee80211_watchdog(ic);
419526594249SQin Michael Li 			break;
419626594249SQin Michael Li 	}
419726594249SQin Michael Li }
419826594249SQin Michael Li 
419926594249SQin Michael Li 
420026594249SQin Michael Li static int
urtw_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)420126594249SQin Michael Li urtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
420226594249SQin Michael Li {
420326594249SQin Michael Li 	struct urtw_softc *sc;
420426594249SQin Michael Li 	struct ieee80211com *ic;
420526594249SQin Michael Li 	int error, i, instance;
420626594249SQin Michael Li 	uint32_t data = 0;
4207dfa03ef6SQin Michael Li 	uint8_t data8 = 0;
420826594249SQin Michael Li 	char strbuf[32];
420926594249SQin Michael Li 	wifi_data_t wd = { 0 };
421026594249SQin Michael Li 	mac_register_t *macp;
4211dfa03ef6SQin Michael Li 	struct urtw_type *e = 0;
4212dfa03ef6SQin Michael Li 	char *urtw_name = NULL;
421326594249SQin Michael Li 
421426594249SQin Michael Li 	switch (cmd) {
421526594249SQin Michael Li 	case DDI_ATTACH:
421626594249SQin Michael Li 		break;
421726594249SQin Michael Li 	case DDI_RESUME:
421826594249SQin Michael Li 		sc = ddi_get_soft_state(urtw_soft_state_p,
421926594249SQin Michael Li 		    ddi_get_instance(devinfo));
422026594249SQin Michael Li 		ASSERT(sc != NULL);
422126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ACTIVE,
422226594249SQin Michael Li 		    (sc->sc_dev, CE_CONT, "urtw: resume\n"));
422326594249SQin Michael Li 		URTW_LOCK(sc);
422426594249SQin Michael Li 		sc->sc_flags &= ~URTW_FLAG_SUSPEND;
422526594249SQin Michael Li 		URTW_UNLOCK(sc);
422626594249SQin Michael Li 		if (URTW_IS_PLUGIN_ONLINE(sc)) {
4227dfa03ef6SQin Michael Li 			error = sc->urtw_init(sc);
422826594249SQin Michael Li 			if (error == 0) {
422926594249SQin Michael Li 				URTW_LOCK(sc);
423026594249SQin Michael Li 				sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
423126594249SQin Michael Li 				URTW_UNLOCK(sc);
423226594249SQin Michael Li 			}
423326594249SQin Michael Li 		}
423426594249SQin Michael Li 		return (DDI_SUCCESS);
423526594249SQin Michael Li 	default:
423626594249SQin Michael Li 		return (DDI_FAILURE);
423726594249SQin Michael Li 	}
423826594249SQin Michael Li 
423926594249SQin Michael Li 	instance = ddi_get_instance(devinfo);
424026594249SQin Michael Li 
424126594249SQin Michael Li 	if (ddi_soft_state_zalloc(urtw_soft_state_p, instance) != DDI_SUCCESS) {
424226594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_attach:unable to alloc soft_state_p\n");
424326594249SQin Michael Li 		return (DDI_FAILURE);
424426594249SQin Michael Li 	}
424526594249SQin Michael Li 
424626594249SQin Michael Li 	sc = ddi_get_soft_state(urtw_soft_state_p, instance);
424726594249SQin Michael Li 	ic = (ieee80211com_t *)&sc->sc_ic;
424826594249SQin Michael Li 	sc->sc_dev = devinfo;
424926594249SQin Michael Li 
425026594249SQin Michael Li 	if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) {
425126594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_attach: usb_client_attach failed\n");
425226594249SQin Michael Li 		goto fail1;
425326594249SQin Michael Li 	}
425426594249SQin Michael Li 
425526594249SQin Michael Li 	if (usb_get_dev_data(devinfo, &sc->sc_udev,
425626594249SQin Michael Li 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
425726594249SQin Michael Li 		sc->sc_udev = NULL;
425826594249SQin Michael Li 		goto fail2;
425926594249SQin Michael Li 	}
426026594249SQin Michael Li 
426126594249SQin Michael Li 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
426226594249SQin Michael Li 	mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL);
426326594249SQin Michael Li 	mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL);
426426594249SQin Michael Li 	mutex_init(&sc->sc_ledlock, NULL, MUTEX_DRIVER, NULL);
426526594249SQin Michael Li 
4266dfa03ef6SQin Michael Li 	e = urtw_lookup(sc->sc_udev->dev_descr->idVendor,
4267dfa03ef6SQin Michael Li 	    sc->sc_udev->dev_descr->idProduct);
4268dfa03ef6SQin Michael Li 	if (e == NULL) {
4269dfa03ef6SQin Michael Li 		cmn_err(CE_WARN, "(urtw) unknown device\n");
4270dfa03ef6SQin Michael Li 		goto fail2;
4271dfa03ef6SQin Michael Li 	}
4272dfa03ef6SQin Michael Li 	sc->sc_hwrev = e->rev;
4273dfa03ef6SQin Michael Li 
4274dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
4275dfa03ef6SQin Michael Li 		(void) urtw_read32_c(sc, URTW_TX_CONF, &data, 0);
4276dfa03ef6SQin Michael Li 		data &= URTW_TX_HWREV_MASK;
4277dfa03ef6SQin Michael Li 		switch (data) {
4278dfa03ef6SQin Michael Li 		case URTW_TX_HWREV_8187_D:
4279dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187_D;
4280dfa03ef6SQin Michael Li 			urtw_name = "RTL8187 rev. D";
4281dfa03ef6SQin Michael Li 			break;
4282dfa03ef6SQin Michael Li 		case URTW_TX_HWREV_8187B_D:
4283dfa03ef6SQin Michael Li 			/*
4284dfa03ef6SQin Michael Li 			 * Detect Realtek RTL8187B devices that use
4285dfa03ef6SQin Michael Li 			 * USB IDs of RTL8187.
4286dfa03ef6SQin Michael Li 			 */
4287dfa03ef6SQin Michael Li 			sc->sc_hwrev = URTW_HWREV_8187B | URTW_HWREV_8187B_B;
4288dfa03ef6SQin Michael Li 			urtw_name = "RTL8187B rev. B (early)";
4289dfa03ef6SQin Michael Li 			break;
4290dfa03ef6SQin Michael Li 		default:
4291dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187_B;
4292dfa03ef6SQin Michael Li 			urtw_name = "RTL8187 rev. B (default)";
4293dfa03ef6SQin Michael Li 			break;
4294dfa03ef6SQin Michael Li 		}
4295dfa03ef6SQin Michael Li 	} else {
4296dfa03ef6SQin Michael Li 		/* RTL8187B hwrev register. */
4297dfa03ef6SQin Michael Li 		(void) urtw_read8_c(sc, URTW_8187B_HWREV, &data8, 0);
4298dfa03ef6SQin Michael Li 		switch (data8) {
4299dfa03ef6SQin Michael Li 		case URTW_8187B_HWREV_8187B_B:
4300dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
4301dfa03ef6SQin Michael Li 			urtw_name = "RTL8187B rev. B";
4302dfa03ef6SQin Michael Li 			break;
4303dfa03ef6SQin Michael Li 		case URTW_8187B_HWREV_8187B_D:
4304dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187B_D;
4305dfa03ef6SQin Michael Li 			urtw_name = "RTL8187B rev. D";
4306dfa03ef6SQin Michael Li 			break;
4307dfa03ef6SQin Michael Li 		case URTW_8187B_HWREV_8187B_E:
4308dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187B_E;
4309dfa03ef6SQin Michael Li 			urtw_name = "RTL8187B rev. E";
4310dfa03ef6SQin Michael Li 			break;
4311dfa03ef6SQin Michael Li 		default:
4312dfa03ef6SQin Michael Li 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
4313dfa03ef6SQin Michael Li 			urtw_name = "RTL8187B rev. B (default)";
4314dfa03ef6SQin Michael Li 			break;
4315dfa03ef6SQin Michael Li 		}
4316dfa03ef6SQin Michael Li 	}
4317dfa03ef6SQin Michael Li 
4318dfa03ef6SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
4319dfa03ef6SQin Michael Li 	    "urtw_attach: actual device is %s\n", urtw_name));
4320dfa03ef6SQin Michael Li 	if (sc->sc_hwrev & URTW_HWREV_8187) {
4321dfa03ef6SQin Michael Li 		sc->urtw_init = urtw_8187_init;
4322dfa03ef6SQin Michael Li 	} else {
4323dfa03ef6SQin Michael Li 		sc->urtw_init = urtw_8187b_init;
4324dfa03ef6SQin Michael Li 	}
4325dfa03ef6SQin Michael Li 
4326dfa03ef6SQin Michael Li 	if (urtw_read32_c(sc, URTW_RX, &data, 0))
432726594249SQin Michael Li 		goto fail3;
432826594249SQin Michael Li 	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
432926594249SQin Michael Li 	    URTW_EEPROM_93C46;
433026594249SQin Michael Li 	if (sc->sc_epromtype == URTW_EEPROM_93C56)
433126594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
433226594249SQin Michael Li 		    "urtw_attach: eprom is 93C56\n"));
433326594249SQin Michael Li 	else
433426594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
433526594249SQin Michael Li 		    "urtw_attach: eprom is 93C46\n"));
433626594249SQin Michael Li 	error = urtw_get_rfchip(sc);
433726594249SQin Michael Li 	if (error != 0)
433826594249SQin Michael Li 		goto fail3;
433926594249SQin Michael Li 	error = urtw_get_macaddr(sc);
434026594249SQin Michael Li 	if (error != 0)
434126594249SQin Michael Li 		goto fail3;
434226594249SQin Michael Li 	error = urtw_get_txpwr(sc);
434326594249SQin Michael Li 	if (error != 0)
434426594249SQin Michael Li 		goto fail3;
434526594249SQin Michael Li 	error = urtw_led_init(sc);		/* XXX incompleted  */
434626594249SQin Michael Li 	if (error != 0)
434726594249SQin Michael Li 		goto fail3;
434826594249SQin Michael Li 
434926594249SQin Michael Li 	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
435026594249SQin Michael Li 	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
435126594249SQin Michael Li 	sc->sc_currate = 3;
435226594249SQin Michael Li 	/* XXX for what?  */
435326594249SQin Michael Li 	sc->sc_preamble_mode = 2;
435426594249SQin Michael Li 
435526594249SQin Michael Li 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
435626594249SQin Michael Li 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
435726594249SQin Michael Li 	ic->ic_state = IEEE80211_S_INIT;
435826594249SQin Michael Li 
435926594249SQin Michael Li 	ic->ic_maxrssi = 95;
436026594249SQin Michael Li 	ic->ic_xmit = urtw_send;
436126594249SQin Michael Li 
436226594249SQin Michael Li 	ic->ic_caps |= IEEE80211_C_WPA | /* Support WPA/WPA2 */
436326594249SQin Michael Li 	    IEEE80211_C_TXPMGT |	/* tx power management */
436426594249SQin Michael Li 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
436526594249SQin Michael Li 	    IEEE80211_C_SHSLOT;	/* short slot time supported */
436626594249SQin Michael Li 	/* set supported .11b and .11g rates */
436726594249SQin Michael Li 	ic->ic_sup_rates[IEEE80211_MODE_11B] = urtw_rateset_11b;
436826594249SQin Michael Li 	ic->ic_sup_rates[IEEE80211_MODE_11G] = urtw_rateset_11g;
436926594249SQin Michael Li 
437026594249SQin Michael Li 	/* set supported .11b and .11g channels (1 through 11) */
437126594249SQin Michael Li 	for (i = 1; i <= 11; i++) {
437226594249SQin Michael Li 		ic->ic_sup_channels[i].ich_freq =
437326594249SQin Michael Li 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
437426594249SQin Michael Li 		ic->ic_sup_channels[i].ich_flags =
437526594249SQin Michael Li 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN |
437626594249SQin Michael Li 		    IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM;
437726594249SQin Michael Li 	}
437826594249SQin Michael Li 
437926594249SQin Michael Li 	ieee80211_attach(ic);
4380dfa03ef6SQin Michael Li 	ic->ic_ibss_chan = &ic->ic_sup_channels[1];
4381dfa03ef6SQin Michael Li 	ic->ic_curchan = ic->ic_ibss_chan;
438226594249SQin Michael Li 
438326594249SQin Michael Li 	/* register WPA door */
438426594249SQin Michael Li 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
438526594249SQin Michael Li 	    ddi_get_instance(devinfo));
438626594249SQin Michael Li 
438726594249SQin Michael Li 	/* override state transition machine */
438826594249SQin Michael Li 	sc->sc_newstate = ic->ic_newstate;
438926594249SQin Michael Li 	ic->ic_newstate = urtw_newstate;
439026594249SQin Michael Li 	ic->ic_watchdog = urtw_watchdog;
439126594249SQin Michael Li 	ieee80211_media_init(ic);
439226594249SQin Michael Li 	ic->ic_def_txkey = 0;
439326594249SQin Michael Li 
4394dfa03ef6SQin Michael Li 	sc->dwelltime = 250;
439526594249SQin Michael Li 	sc->sc_flags = 0;
439626594249SQin Michael Li 
439726594249SQin Michael Li 	/*
439826594249SQin Michael Li 	 * Provide initial settings for the WiFi plugin; whenever this
439926594249SQin Michael Li 	 * information changes, we need to call mac_plugindata_update()
440026594249SQin Michael Li 	 */
440126594249SQin Michael Li 	wd.wd_opmode = ic->ic_opmode;
440226594249SQin Michael Li 	wd.wd_secalloc = WIFI_SEC_NONE;
440326594249SQin Michael Li 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
440426594249SQin Michael Li 
440526594249SQin Michael Li 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
440626594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
440726594249SQin Michael Li 		    "MAC version alloc failed\n"));
440826594249SQin Michael Li 		goto fail4;
440926594249SQin Michael Li 	}
441026594249SQin Michael Li 
441126594249SQin Michael Li 	macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
441226594249SQin Michael Li 	macp->m_driver = sc;
441326594249SQin Michael Li 	macp->m_dip = devinfo;
441426594249SQin Michael Li 	macp->m_src_addr = ic->ic_macaddr;
441526594249SQin Michael Li 	macp->m_callbacks = &urtw_m_callbacks;
441626594249SQin Michael Li 	macp->m_min_sdu	= 0;
441726594249SQin Michael Li 	macp->m_max_sdu	= IEEE80211_MTU;
441826594249SQin Michael Li 	macp->m_pdata = &wd;
441926594249SQin Michael Li 	macp->m_pdata_size = sizeof (wd);
442026594249SQin Michael Li 
442126594249SQin Michael Li 	error = mac_register(macp, &ic->ic_mach);
442226594249SQin Michael Li 	mac_free(macp);
442326594249SQin Michael Li 	if (error != 0) {
442426594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_attach: mac_register() err %x\n", error);
442526594249SQin Michael Li 		goto fail4;
442626594249SQin Michael Li 	}
442726594249SQin Michael Li 
442826594249SQin Michael Li 	if (usb_register_hotplug_cbs(devinfo, urtw_disconnect,
442926594249SQin Michael Li 	    urtw_reconnect) != USB_SUCCESS) {
443026594249SQin Michael Li 		cmn_err(CE_WARN, "urtw_attach: failed to register events");
443126594249SQin Michael Li 		goto fail5;
443226594249SQin Michael Li 	}
443326594249SQin Michael Li 
443426594249SQin Michael Li 	/*
443526594249SQin Michael Li 	 * Create minor node of type DDI_NT_NET_WIFI
443626594249SQin Michael Li 	 */
443726594249SQin Michael Li 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
443826594249SQin Michael Li 	    "urtw", instance);
443926594249SQin Michael Li 	error = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
444026594249SQin Michael Li 	    instance + 1, DDI_NT_NET_WIFI, 0);
444126594249SQin Michael Li 
444226594249SQin Michael Li 	if (error != DDI_SUCCESS)
444326594249SQin Michael Li 		cmn_err(CE_WARN, "urtw: ddi_create_minor_node() failed\n");
444426594249SQin Michael Li 	/*
444526594249SQin Michael Li 	 * Notify link is down now
444626594249SQin Michael Li 	 */
444726594249SQin Michael Li 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
444826594249SQin Michael Li 
444926594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
445026594249SQin Michael Li 	    "urtw_attach: successfully.\n"));
445126594249SQin Michael Li 	return (DDI_SUCCESS);
445226594249SQin Michael Li fail5:
4453dfa03ef6SQin Michael Li 	(void) mac_disable(ic->ic_mach);
445426594249SQin Michael Li 	(void) mac_unregister(ic->ic_mach);
445526594249SQin Michael Li fail4:
445626594249SQin Michael Li 	ieee80211_detach(ic);
445726594249SQin Michael Li fail3:
445826594249SQin Michael Li 	mutex_destroy(&sc->sc_genlock);
445926594249SQin Michael Li 	mutex_destroy(&sc->tx_lock);
446026594249SQin Michael Li 	mutex_destroy(&sc->rx_lock);
446126594249SQin Michael Li 	mutex_destroy(&sc->sc_ledlock);
446226594249SQin Michael Li fail2:
446326594249SQin Michael Li 	usb_client_detach(sc->sc_dev, sc->sc_udev);
446426594249SQin Michael Li fail1:
446526594249SQin Michael Li 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
446626594249SQin Michael Li 
446726594249SQin Michael Li 	return (DDI_FAILURE);
446826594249SQin Michael Li }
446926594249SQin Michael Li 
447026594249SQin Michael Li static int
urtw_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)447126594249SQin Michael Li urtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
447226594249SQin Michael Li {
447326594249SQin Michael Li 	struct urtw_softc *sc;
447426594249SQin Michael Li 
447526594249SQin Michael Li 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
447626594249SQin Michael Li 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev,
447726594249SQin Michael Li 	    CE_CONT, "urtw_detach()\n"));
447826594249SQin Michael Li 
447926594249SQin Michael Li 	switch (cmd) {
448026594249SQin Michael Li 	case DDI_DETACH:
448126594249SQin Michael Li 		break;
448226594249SQin Michael Li 	case DDI_SUSPEND:
448326594249SQin Michael Li 		URTW8187_DBG(URTW_DEBUG_ATTACH,
448426594249SQin Michael Li 		    (sc->sc_dev, CE_CONT, "urtw: suspend\n"));
448526594249SQin Michael Li 
448626594249SQin Michael Li 		ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
448726594249SQin Michael Li 		ieee80211_stop_watchdog(&sc->sc_ic);
448826594249SQin Michael Li 
448926594249SQin Michael Li 		URTW_LOCK(sc);
449026594249SQin Michael Li 		sc->sc_flags |= URTW_FLAG_SUSPEND;
449126594249SQin Michael Li 		URTW_UNLOCK(sc);
449226594249SQin Michael Li 		if (URTW_IS_RUNNING(sc)) {
449326594249SQin Michael Li 			urtw_stop(sc);
449426594249SQin Michael Li 			URTW_LOCK(sc);
449526594249SQin Michael Li 			sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
449626594249SQin Michael Li 			URTW_UNLOCK(sc);
449726594249SQin Michael Li 		}
449826594249SQin Michael Li 		return (DDI_SUCCESS);
449926594249SQin Michael Li 	default:
450026594249SQin Michael Li 		return (DDI_FAILURE);
450126594249SQin Michael Li 	}
450226594249SQin Michael Li 
450326594249SQin Michael Li 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
450426594249SQin Michael Li 		return (DDI_FAILURE);
450526594249SQin Michael Li 	urtw_stop(sc);
450626594249SQin Michael Li 	/*
450726594249SQin Michael Li 	 * Unregister from the MAC layer subsystem
450826594249SQin Michael Li 	 */
450926594249SQin Michael Li 	(void) mac_unregister(sc->sc_ic.ic_mach);
451026594249SQin Michael Li 
451126594249SQin Michael Li 	ieee80211_detach(&sc->sc_ic);
451226594249SQin Michael Li 	usb_unregister_hotplug_cbs(devinfo);
451326594249SQin Michael Li 	usb_client_detach(devinfo, sc->sc_udev);
451426594249SQin Michael Li 	mutex_destroy(&sc->sc_genlock);
451526594249SQin Michael Li 	mutex_destroy(&sc->tx_lock);
451626594249SQin Michael Li 	mutex_destroy(&sc->rx_lock);
451726594249SQin Michael Li 	mutex_destroy(&sc->sc_ledlock);
451826594249SQin Michael Li 	sc->sc_udev = NULL;
451926594249SQin Michael Li 
452026594249SQin Michael Li 	ddi_remove_minor_node(devinfo, NULL);
452126594249SQin Michael Li 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
452226594249SQin Michael Li 
452326594249SQin Michael Li 	return (DDI_SUCCESS);
452426594249SQin Michael Li }
452526594249SQin Michael Li 
452626594249SQin Michael Li int
_info(struct modinfo * modinfop)452726594249SQin Michael Li _info(struct modinfo *modinfop)
452826594249SQin Michael Li {
452926594249SQin Michael Li 	return (mod_info(&modlinkage, modinfop));
453026594249SQin Michael Li }
453126594249SQin Michael Li 
453226594249SQin Michael Li int
_init(void)453326594249SQin Michael Li _init(void)
453426594249SQin Michael Li {
453526594249SQin Michael Li 	int status;
453626594249SQin Michael Li 
453726594249SQin Michael Li 	status = ddi_soft_state_init(&urtw_soft_state_p,
453826594249SQin Michael Li 	    sizeof (struct urtw_softc), 1);
453926594249SQin Michael Li 	if (status != 0)
454026594249SQin Michael Li 		return (status);
454126594249SQin Michael Li 
454226594249SQin Michael Li 	mac_init_ops(&urtw_dev_ops, "urtw");
454326594249SQin Michael Li 	status = mod_install(&modlinkage);
454426594249SQin Michael Li 	if (status != 0) {
454526594249SQin Michael Li 		mac_fini_ops(&urtw_dev_ops);
454626594249SQin Michael Li 		ddi_soft_state_fini(&urtw_soft_state_p);
454726594249SQin Michael Li 	}
454826594249SQin Michael Li 	return (status);
454926594249SQin Michael Li }
455026594249SQin Michael Li 
455126594249SQin Michael Li int
_fini(void)455226594249SQin Michael Li _fini(void)
455326594249SQin Michael Li {
455426594249SQin Michael Li 	int status;
455526594249SQin Michael Li 
455626594249SQin Michael Li 	status = mod_remove(&modlinkage);
455726594249SQin Michael Li 	if (status == 0) {
455826594249SQin Michael Li 		mac_fini_ops(&urtw_dev_ops);
455926594249SQin Michael Li 		ddi_soft_state_fini(&urtw_soft_state_p);
456026594249SQin Michael Li 	}
456126594249SQin Michael Li 	return (status);
456226594249SQin Michael Li }
4563