xref: /onnv-gate/usr/src/uts/common/io/urtw/urtw.c (revision 10364:b6fbd1c0a94d)
19485SMikore.Li@Sun.COM /*
29485SMikore.Li@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
39485SMikore.Li@Sun.COM  * Use is subject to license terms.
49485SMikore.Li@Sun.COM  */
59485SMikore.Li@Sun.COM 
69485SMikore.Li@Sun.COM /*
79485SMikore.Li@Sun.COM  * Copyright (c) 2008 Weongyo Jeong
89485SMikore.Li@Sun.COM  * All rights reserved.
99485SMikore.Li@Sun.COM  *
109485SMikore.Li@Sun.COM  * Redistribution and use in source and binary forms, with or without
119485SMikore.Li@Sun.COM  * modification, are permitted provided that the following conditions
129485SMikore.Li@Sun.COM  * are met:
139485SMikore.Li@Sun.COM  * 1. Redistributions of source code must retain the above copyright
149485SMikore.Li@Sun.COM  *    notice, this list of conditions and the following disclaimer,
159485SMikore.Li@Sun.COM  *    without modification.
169485SMikore.Li@Sun.COM  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
179485SMikore.Li@Sun.COM  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
189485SMikore.Li@Sun.COM  *    redistribution must be conditioned upon including a substantially
199485SMikore.Li@Sun.COM  *    similar Disclaimer requirement for further binary redistribution.
209485SMikore.Li@Sun.COM  *
219485SMikore.Li@Sun.COM  * NO WARRANTY
229485SMikore.Li@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
239485SMikore.Li@Sun.COM  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
249485SMikore.Li@Sun.COM  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
259485SMikore.Li@Sun.COM  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
269485SMikore.Li@Sun.COM  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
279485SMikore.Li@Sun.COM  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
289485SMikore.Li@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
299485SMikore.Li@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
309485SMikore.Li@Sun.COM  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
319485SMikore.Li@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
329485SMikore.Li@Sun.COM  * THE POSSIBILITY OF SUCH DAMAGES.
339485SMikore.Li@Sun.COM  */
349485SMikore.Li@Sun.COM #include <sys/sysmacros.h>
359485SMikore.Li@Sun.COM #include <sys/strsubr.h>
369485SMikore.Li@Sun.COM #include <sys/strsun.h>
379485SMikore.Li@Sun.COM #include <sys/mac_provider.h>
389485SMikore.Li@Sun.COM #include <sys/mac_wifi.h>
399485SMikore.Li@Sun.COM #include <sys/net80211.h>
409485SMikore.Li@Sun.COM #define	USBDRV_MAJOR_VER	2
419485SMikore.Li@Sun.COM #define	USBDRV_MINOR_VER	0
429485SMikore.Li@Sun.COM #include <sys/usb/usba.h>
439485SMikore.Li@Sun.COM #include <sys/usb/usba/usba_types.h>
449485SMikore.Li@Sun.COM 
459485SMikore.Li@Sun.COM #include "urtw_reg.h"
469485SMikore.Li@Sun.COM #include "urtw_var.h"
479485SMikore.Li@Sun.COM 
489485SMikore.Li@Sun.COM static void *urtw_soft_state_p = NULL;
499485SMikore.Li@Sun.COM 
509485SMikore.Li@Sun.COM #define	URTW_TXBUF_SIZE  	(IEEE80211_MAX_LEN)
519485SMikore.Li@Sun.COM #define	URTW_RXBUF_SIZE  	(URTW_TXBUF_SIZE)
529485SMikore.Li@Sun.COM /*
539485SMikore.Li@Sun.COM  * device operations
549485SMikore.Li@Sun.COM  */
559485SMikore.Li@Sun.COM static int urtw_attach(dev_info_t *, ddi_attach_cmd_t);
569485SMikore.Li@Sun.COM static int urtw_detach(dev_info_t *, ddi_detach_cmd_t);
579485SMikore.Li@Sun.COM 
589485SMikore.Li@Sun.COM /*
599485SMikore.Li@Sun.COM  * Module Loading Data & Entry Points
609485SMikore.Li@Sun.COM  */
619485SMikore.Li@Sun.COM DDI_DEFINE_STREAM_OPS(urtw_dev_ops, nulldev, nulldev, urtw_attach,
629485SMikore.Li@Sun.COM     urtw_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
639485SMikore.Li@Sun.COM 
649485SMikore.Li@Sun.COM static struct modldrv urtw_modldrv = {
659485SMikore.Li@Sun.COM 	&mod_driverops,		/* Type of module.  This one is a driver */
66*10364SMikore.Li@Sun.COM 	"RTL8187L/B driver v1.2",	/* short description */
679485SMikore.Li@Sun.COM 	&urtw_dev_ops		/* driver specific ops */
689485SMikore.Li@Sun.COM };
699485SMikore.Li@Sun.COM 
709485SMikore.Li@Sun.COM static struct modlinkage modlinkage = {
719485SMikore.Li@Sun.COM 	MODREV_1,
729485SMikore.Li@Sun.COM 	(void *)&urtw_modldrv,
739485SMikore.Li@Sun.COM 	NULL
749485SMikore.Li@Sun.COM };
759485SMikore.Li@Sun.COM 
769485SMikore.Li@Sun.COM static int	urtw_m_stat(void *,  uint_t, uint64_t *);
779485SMikore.Li@Sun.COM static int	urtw_m_start(void *);
789485SMikore.Li@Sun.COM static void	urtw_m_stop(void *);
799485SMikore.Li@Sun.COM static int	urtw_m_promisc(void *, boolean_t);
809485SMikore.Li@Sun.COM static int	urtw_m_multicst(void *, boolean_t, const uint8_t *);
819485SMikore.Li@Sun.COM static int	urtw_m_unicst(void *, const uint8_t *);
829485SMikore.Li@Sun.COM static mblk_t	*urtw_m_tx(void *, mblk_t *);
839485SMikore.Li@Sun.COM static void	urtw_m_ioctl(void *, queue_t *, mblk_t *);
849485SMikore.Li@Sun.COM static int	urtw_m_setprop(void *, const char *, mac_prop_id_t,
859485SMikore.Li@Sun.COM     uint_t, const void *);
86*10364SMikore.Li@Sun.COM static int urtw_m_getprop(void *, const char *, mac_prop_id_t,
87*10364SMikore.Li@Sun.COM     uint_t, uint_t, void *, uint_t *);
889485SMikore.Li@Sun.COM 
899485SMikore.Li@Sun.COM static mac_callbacks_t urtw_m_callbacks = {
909485SMikore.Li@Sun.COM 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
919485SMikore.Li@Sun.COM 	urtw_m_stat,
929485SMikore.Li@Sun.COM 	urtw_m_start,
939485SMikore.Li@Sun.COM 	urtw_m_stop,
949485SMikore.Li@Sun.COM 	urtw_m_promisc,
959485SMikore.Li@Sun.COM 	urtw_m_multicst,
969485SMikore.Li@Sun.COM 	urtw_m_unicst,
979485SMikore.Li@Sun.COM 	urtw_m_tx,
989485SMikore.Li@Sun.COM 	urtw_m_ioctl,
999485SMikore.Li@Sun.COM 	NULL,
1009485SMikore.Li@Sun.COM 	NULL,
1019485SMikore.Li@Sun.COM 	NULL,
1029485SMikore.Li@Sun.COM 	urtw_m_setprop,
103*10364SMikore.Li@Sun.COM 	urtw_m_getprop
1049485SMikore.Li@Sun.COM };
1059485SMikore.Li@Sun.COM 
1069485SMikore.Li@Sun.COM static int  urtw_tx_start(struct urtw_softc *, mblk_t *, int);
1079485SMikore.Li@Sun.COM static int  urtw_rx_start(struct urtw_softc *);
1089485SMikore.Li@Sun.COM 
1099485SMikore.Li@Sun.COM 
1109485SMikore.Li@Sun.COM /*
111*10364SMikore.Li@Sun.COM  * Supported rates for 802.11b/g modes (in 500Kbps unit).
1129485SMikore.Li@Sun.COM  */
1139485SMikore.Li@Sun.COM static const struct ieee80211_rateset urtw_rateset_11b =
1149485SMikore.Li@Sun.COM 	{ 4, { 2, 4, 11, 22 } };
1159485SMikore.Li@Sun.COM 
1169485SMikore.Li@Sun.COM static const struct ieee80211_rateset urtw_rateset_11g =
1179485SMikore.Li@Sun.COM 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
1189485SMikore.Li@Sun.COM 
119*10364SMikore.Li@Sun.COM #define	USB_VENDOR_DICKSMITH	0x1371		/* Dick Smith Electronics */
120*10364SMikore.Li@Sun.COM #define	USB_VENDOR_LOGITEC	0x0789		/* Logitec */
121*10364SMikore.Li@Sun.COM #define	USB_VENDOR_NETGEAR	0x0846		/* BayNETGEAR */
122*10364SMikore.Li@Sun.COM #define	USB_VENDOR_REALTEK	0x0bda		/* Realtek */
123*10364SMikore.Li@Sun.COM #define	USB_VENDOR_SPHAIRON	0x114b		/* Sphairon Access Systems */
124*10364SMikore.Li@Sun.COM #define	USB_VENDOR_SURECOM	0x0769		/* Surecom Technology */
125*10364SMikore.Li@Sun.COM #define	USB_VENDOR_BELKIN	0x050d		/* Belkin Components */
126*10364SMikore.Li@Sun.COM #define	USB_VENDOR_SITECOMEU	0x0df6		/* Sitecom Europe */
127*10364SMikore.Li@Sun.COM 
128*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_SPHAIRON_RTL8187	0x0150		/* RTL8187 */
129*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_DICKSMITH_RTL8187	0x9401		/* RTL8187 */
130*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_LOGITEC_RTL8187	0x010c		/* RTL8187 */
131*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_REALTEK_RTL8187	0x8187		/* RTL8187 */
132*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_NETGEAR_WG111V2	0x6a00		/* WG111v2 */
133*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_SURECOM_EP9001G2A	0x11f2		/* EP-9001-G rev 2A */
134*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_BELKIN_F5D7050E	0x705e		/* F5D705E 54g */
135*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_NETGEAR_WG111V3	0x4260		/* WG111v3 */
136*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_REALTEK_RTL8187B_0	0x8189		/* RTL8187B */
137*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_REALTEK_RTL8187B_1	0x8197		/* RTL8187B */
138*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_REALTEK_RTL8187B_2	0x8198		/* RTL8187B */
139*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_SITECOMEU_WL168	0x0028		/* WL-168 */
140*10364SMikore.Li@Sun.COM 
141*10364SMikore.Li@Sun.COM #define	USB_PRODUCT_ANY	0xffff
142*10364SMikore.Li@Sun.COM 
143*10364SMikore.Li@Sun.COM struct usb_devno {
144*10364SMikore.Li@Sun.COM 	uint16_t v;
145*10364SMikore.Li@Sun.COM 	uint16_t p;
146*10364SMikore.Li@Sun.COM };
147*10364SMikore.Li@Sun.COM 
148*10364SMikore.Li@Sun.COM /*
149*10364SMikore.Li@Sun.COM  * Recognized device vendors/products.
150*10364SMikore.Li@Sun.COM  */
151*10364SMikore.Li@Sun.COM static struct urtw_type {
152*10364SMikore.Li@Sun.COM 	struct usb_devno	dev;
153*10364SMikore.Li@Sun.COM 	uint8_t			rev;
154*10364SMikore.Li@Sun.COM } urtw_devs[] = {
155*10364SMikore.Li@Sun.COM #define	URTW_DEV_RTL8187(v, p)	\
156*10364SMikore.Li@Sun.COM 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187 }
157*10364SMikore.Li@Sun.COM #define	URTW_DEV_RTL8187B(v, p)	\
158*10364SMikore.Li@Sun.COM 	    { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187B }
159*10364SMikore.Li@Sun.COM 	/* Realtek RTL8187 devices. */
160*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(DICKSMITH,	RTL8187),
161*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(LOGITEC,	RTL8187),
162*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(NETGEAR,	WG111V2),
163*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(REALTEK,	RTL8187),
164*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(SPHAIRON,	RTL8187),
165*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187(SURECOM,	EP9001G2A),
166*10364SMikore.Li@Sun.COM 	/* Realtek RTL8187B devices. */
167*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(BELKIN,	F5D7050E),
168*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(NETGEAR,	WG111V3),
169*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_0),
170*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_1),
171*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(REALTEK,	RTL8187B_2),
172*10364SMikore.Li@Sun.COM 	URTW_DEV_RTL8187B(SITECOMEU,	WL168)
173*10364SMikore.Li@Sun.COM #undef	URTW_DEV_RTL8187
174*10364SMikore.Li@Sun.COM #undef	URTW_DEV_RTL8187B
175*10364SMikore.Li@Sun.COM };
176*10364SMikore.Li@Sun.COM 
177*10364SMikore.Li@Sun.COM /*
178*10364SMikore.Li@Sun.COM  * Search for a vendor/product pair in an array.  The item size is
179*10364SMikore.Li@Sun.COM  * given as an argument.
180*10364SMikore.Li@Sun.COM  */
181*10364SMikore.Li@Sun.COM struct urtw_type *
182*10364SMikore.Li@Sun.COM usb_match_device(struct urtw_type *tbl, uint32_t nentries,
183*10364SMikore.Li@Sun.COM 	uint16_t vendor, uint16_t product)
184*10364SMikore.Li@Sun.COM {
185*10364SMikore.Li@Sun.COM 	while (nentries-- > 0) {
186*10364SMikore.Li@Sun.COM 		uint16_t tproduct = tbl[nentries].dev.p;
187*10364SMikore.Li@Sun.COM 		if (tbl[nentries].dev.v == vendor &&
188*10364SMikore.Li@Sun.COM 		    (tproduct == product || tproduct == USB_PRODUCT_ANY))
189*10364SMikore.Li@Sun.COM 		return (&tbl[nentries]);
190*10364SMikore.Li@Sun.COM 	}
191*10364SMikore.Li@Sun.COM 	return (NULL);
192*10364SMikore.Li@Sun.COM }
193*10364SMikore.Li@Sun.COM 
194*10364SMikore.Li@Sun.COM #define	usb_lookup(tbl, vendor, product) \
195*10364SMikore.Li@Sun.COM 	usb_match_device(tbl, sizeof (tbl) / sizeof ((tbl)[0]), \
196*10364SMikore.Li@Sun.COM 		(vendor), (product))
197*10364SMikore.Li@Sun.COM 
198*10364SMikore.Li@Sun.COM #define	urtw_lookup(v, p)	(usb_lookup(urtw_devs, v, p))
1999485SMikore.Li@Sun.COM 
2009485SMikore.Li@Sun.COM struct urtw_pair {
2019485SMikore.Li@Sun.COM 	uint32_t	reg;
2029485SMikore.Li@Sun.COM 	uint32_t	val;
2039485SMikore.Li@Sun.COM };
2049485SMikore.Li@Sun.COM 
205*10364SMikore.Li@Sun.COM struct urtw_pair_idx {
206*10364SMikore.Li@Sun.COM 	uint8_t		reg;
207*10364SMikore.Li@Sun.COM 	uint8_t		val;
208*10364SMikore.Li@Sun.COM 	uint8_t		idx;
209*10364SMikore.Li@Sun.COM };
210*10364SMikore.Li@Sun.COM 
211*10364SMikore.Li@Sun.COM static struct urtw_pair_idx urtw_8187b_regtbl[] = {
212*10364SMikore.Li@Sun.COM 	{ 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
213*10364SMikore.Li@Sun.COM 	{ 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
214*10364SMikore.Li@Sun.COM 	{ 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
215*10364SMikore.Li@Sun.COM 	{ 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
216*10364SMikore.Li@Sun.COM 	{ 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
217*10364SMikore.Li@Sun.COM 	{ 0xff, 0x00, 0 },
218*10364SMikore.Li@Sun.COM 
219*10364SMikore.Li@Sun.COM 	{ 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 }, { 0x5a, 0x4b, 1 },
220*10364SMikore.Li@Sun.COM 	{ 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 }, { 0x61, 0x09, 1 },
221*10364SMikore.Li@Sun.COM 	{ 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 }, { 0xce, 0x0f, 1 },
222*10364SMikore.Li@Sun.COM 	{ 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 }, { 0xe1, 0x0f, 1 },
223*10364SMikore.Li@Sun.COM 	{ 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 }, { 0xf1, 0x01, 1 },
224*10364SMikore.Li@Sun.COM 	{ 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 }, { 0xf4, 0x04, 1 },
225*10364SMikore.Li@Sun.COM 	{ 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 }, { 0xf7, 0x07, 1 },
226*10364SMikore.Li@Sun.COM 	{ 0xf8, 0x08, 1 },
227*10364SMikore.Li@Sun.COM 
228*10364SMikore.Li@Sun.COM 	{ 0x4e, 0x00, 2 }, { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 },
229*10364SMikore.Li@Sun.COM 	{ 0x22, 0x68, 2 }, { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 },
230*10364SMikore.Li@Sun.COM 	{ 0x25, 0x7d, 2 }, { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 },
231*10364SMikore.Li@Sun.COM 	{ 0x4d, 0x08, 2 }, { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 },
232*10364SMikore.Li@Sun.COM 	{ 0x52, 0x04, 2 }, { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 },
233*10364SMikore.Li@Sun.COM 	{ 0x55, 0x23, 2 }, { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 },
234*10364SMikore.Li@Sun.COM 	{ 0x58, 0x08, 2 }, { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 },
235*10364SMikore.Li@Sun.COM 	{ 0x5b, 0x08, 2 }, { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 },
236*10364SMikore.Li@Sun.COM 	{ 0x62, 0x08, 2 }, { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 },
237*10364SMikore.Li@Sun.COM 	{ 0x72, 0x56, 2 }, { 0x73, 0x9a, 2 },
238*10364SMikore.Li@Sun.COM 
239*10364SMikore.Li@Sun.COM 	{ 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 }, { 0x5b, 0x40, 0 },
240*10364SMikore.Li@Sun.COM 	{ 0x84, 0x88, 0 }, { 0x85, 0x24, 0 }, { 0x88, 0x54, 0 },
241*10364SMikore.Li@Sun.COM 	{ 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 }, { 0x8d, 0x00, 0 },
242*10364SMikore.Li@Sun.COM 	{ 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 }, { 0x96, 0x00, 0 },
243*10364SMikore.Li@Sun.COM 	{ 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 }, { 0x9f, 0x10, 0 },
244*10364SMikore.Li@Sun.COM 	{ 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 }, { 0xdb, 0x00, 0 },
245*10364SMikore.Li@Sun.COM 	{ 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
246*10364SMikore.Li@Sun.COM 
247*10364SMikore.Li@Sun.COM 	{ 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
248*10364SMikore.Li@Sun.COM 	{ 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
249*10364SMikore.Li@Sun.COM };
250*10364SMikore.Li@Sun.COM 
2519485SMikore.Li@Sun.COM static uint8_t urtw_8225_agc[] = {
2529485SMikore.Li@Sun.COM 	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
2539485SMikore.Li@Sun.COM 	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
2549485SMikore.Li@Sun.COM 	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
2559485SMikore.Li@Sun.COM 	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
2569485SMikore.Li@Sun.COM 	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
2579485SMikore.Li@Sun.COM 	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
2589485SMikore.Li@Sun.COM 	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
2599485SMikore.Li@Sun.COM 	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
2609485SMikore.Li@Sun.COM 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
2619485SMikore.Li@Sun.COM 	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
2629485SMikore.Li@Sun.COM 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
2639485SMikore.Li@Sun.COM 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
2649485SMikore.Li@Sun.COM };
2659485SMikore.Li@Sun.COM 
266*10364SMikore.Li@Sun.COM static uint8_t urtw_8225v2_agc[] = {
267*10364SMikore.Li@Sun.COM 	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57,
268*10364SMikore.Li@Sun.COM 	0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x47,
269*10364SMikore.Li@Sun.COM 	0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
270*10364SMikore.Li@Sun.COM 	0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27,
271*10364SMikore.Li@Sun.COM 	0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17,
272*10364SMikore.Li@Sun.COM 	0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
273*10364SMikore.Li@Sun.COM 	0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
274*10364SMikore.Li@Sun.COM 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
275*10364SMikore.Li@Sun.COM 	0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
276*10364SMikore.Li@Sun.COM 	0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
277*10364SMikore.Li@Sun.COM 	0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
278*10364SMikore.Li@Sun.COM 	0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
279*10364SMikore.Li@Sun.COM 	0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f,
280*10364SMikore.Li@Sun.COM 	0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
281*10364SMikore.Li@Sun.COM 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
282*10364SMikore.Li@Sun.COM 	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
283*10364SMikore.Li@Sun.COM };
284*10364SMikore.Li@Sun.COM 
285*10364SMikore.Li@Sun.COM static uint8_t urtw_8225v2_ofdm[] = {
286*10364SMikore.Li@Sun.COM 	0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
287*10364SMikore.Li@Sun.COM 	0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
288*10364SMikore.Li@Sun.COM 	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
289*10364SMikore.Li@Sun.COM 	0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
290*10364SMikore.Li@Sun.COM 	0x0a, 0xe1, 0x2c, 0x8a, 0x86, 0x83, 0x34, 0x0f,
291*10364SMikore.Li@Sun.COM 	0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
292*10364SMikore.Li@Sun.COM 	0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
293*10364SMikore.Li@Sun.COM 	0x6d, 0x3c, 0xfb, 0x07
294*10364SMikore.Li@Sun.COM };
295*10364SMikore.Li@Sun.COM 
2969485SMikore.Li@Sun.COM static uint32_t urtw_8225_channel[] = {
2979485SMikore.Li@Sun.COM 	0x0000,		/* dummy channel 0  */
2989485SMikore.Li@Sun.COM 	0x085c,		/* 1  */
2999485SMikore.Li@Sun.COM 	0x08dc,		/* 2  */
3009485SMikore.Li@Sun.COM 	0x095c,		/* 3  */
3019485SMikore.Li@Sun.COM 	0x09dc,		/* 4  */
3029485SMikore.Li@Sun.COM 	0x0a5c,		/* 5  */
3039485SMikore.Li@Sun.COM 	0x0adc,		/* 6  */
3049485SMikore.Li@Sun.COM 	0x0b5c,		/* 7  */
3059485SMikore.Li@Sun.COM 	0x0bdc,		/* 8  */
3069485SMikore.Li@Sun.COM 	0x0c5c,		/* 9  */
3079485SMikore.Li@Sun.COM 	0x0cdc,		/* 10  */
3089485SMikore.Li@Sun.COM 	0x0d5c,		/* 11  */
3099485SMikore.Li@Sun.COM 	0x0ddc,		/* 12  */
3109485SMikore.Li@Sun.COM 	0x0e5c,		/* 13  */
3119485SMikore.Li@Sun.COM 	0x0f72,		/* 14  */
3129485SMikore.Li@Sun.COM };
3139485SMikore.Li@Sun.COM 
3149485SMikore.Li@Sun.COM static uint8_t urtw_8225_gain[] = {
3159485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm  */
3169485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm  */
3179485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm  */
3189485SMikore.Li@Sun.COM 	0x33, 0x80, 0x79, 0xc5,		/* -78dbm  */
3199485SMikore.Li@Sun.COM 	0x43, 0x78, 0x76, 0xc5,		/* -74dbm  */
3209485SMikore.Li@Sun.COM 	0x53, 0x60, 0x73, 0xc5,		/* -70dbm  */
3219485SMikore.Li@Sun.COM 	0x63, 0x58, 0x70, 0xc5,		/* -66dbm  */
3229485SMikore.Li@Sun.COM };
3239485SMikore.Li@Sun.COM 
3249485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part1[] = {
3259485SMikore.Li@Sun.COM 	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
3269485SMikore.Li@Sun.COM 	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
3279485SMikore.Li@Sun.COM 	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
3289485SMikore.Li@Sun.COM 	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
3299485SMikore.Li@Sun.COM };
3309485SMikore.Li@Sun.COM 
3319485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part2[] = {
3329485SMikore.Li@Sun.COM 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
3339485SMikore.Li@Sun.COM 	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
3349485SMikore.Li@Sun.COM 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
3359485SMikore.Li@Sun.COM 	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
3369485SMikore.Li@Sun.COM 	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
3379485SMikore.Li@Sun.COM 	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
3389485SMikore.Li@Sun.COM 	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
3399485SMikore.Li@Sun.COM 	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
3409485SMikore.Li@Sun.COM 	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
3419485SMikore.Li@Sun.COM 	{ 0x27, 0x88 }
3429485SMikore.Li@Sun.COM };
3439485SMikore.Li@Sun.COM 
3449485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part3[] = {
3459485SMikore.Li@Sun.COM 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
3469485SMikore.Li@Sun.COM 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
3479485SMikore.Li@Sun.COM 	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
3489485SMikore.Li@Sun.COM 	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
3499485SMikore.Li@Sun.COM 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
3509485SMikore.Li@Sun.COM 	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
3519485SMikore.Li@Sun.COM 	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
3529485SMikore.Li@Sun.COM };
3539485SMikore.Li@Sun.COM 
3549485SMikore.Li@Sun.COM static uint16_t urtw_8225_rxgain[] = {
3559485SMikore.Li@Sun.COM 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
3569485SMikore.Li@Sun.COM 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
3579485SMikore.Li@Sun.COM 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
3589485SMikore.Li@Sun.COM 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
3599485SMikore.Li@Sun.COM 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
3609485SMikore.Li@Sun.COM 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
3619485SMikore.Li@Sun.COM 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
3629485SMikore.Li@Sun.COM 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
3639485SMikore.Li@Sun.COM 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
3649485SMikore.Li@Sun.COM 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
3659485SMikore.Li@Sun.COM 	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
3669485SMikore.Li@Sun.COM 	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
3679485SMikore.Li@Sun.COM };
3689485SMikore.Li@Sun.COM 
3699485SMikore.Li@Sun.COM static uint8_t urtw_8225_threshold[] = {
3709485SMikore.Li@Sun.COM 	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
3719485SMikore.Li@Sun.COM };
3729485SMikore.Li@Sun.COM 
3739485SMikore.Li@Sun.COM static uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
3749485SMikore.Li@Sun.COM 	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
3759485SMikore.Li@Sun.COM };
3769485SMikore.Li@Sun.COM 
3779485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_cck[] = {
3789485SMikore.Li@Sun.COM 	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
3799485SMikore.Li@Sun.COM 	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
3809485SMikore.Li@Sun.COM 	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
3819485SMikore.Li@Sun.COM 	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
3829485SMikore.Li@Sun.COM 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
3839485SMikore.Li@Sun.COM 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
3849485SMikore.Li@Sun.COM };
3859485SMikore.Li@Sun.COM 
3869485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_cck_ch14[] = {
3879485SMikore.Li@Sun.COM 	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
3889485SMikore.Li@Sun.COM 	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
3899485SMikore.Li@Sun.COM 	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
3909485SMikore.Li@Sun.COM 	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
3919485SMikore.Li@Sun.COM 	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
3929485SMikore.Li@Sun.COM 	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
3939485SMikore.Li@Sun.COM };
3949485SMikore.Li@Sun.COM 
3959485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_ofdm[] = {
3969485SMikore.Li@Sun.COM 	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
3979485SMikore.Li@Sun.COM };
3989485SMikore.Li@Sun.COM 
3999485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_gain_bg[] = {
4009485SMikore.Li@Sun.COM 	0x23, 0x15, 0xa5,		/* -82-1dbm  */
4019485SMikore.Li@Sun.COM 	0x23, 0x15, 0xb5,		/* -82-2dbm  */
4029485SMikore.Li@Sun.COM 	0x23, 0x15, 0xc5,		/* -82-3dbm  */
4039485SMikore.Li@Sun.COM 	0x33, 0x15, 0xc5,		/* -78dbm  */
4049485SMikore.Li@Sun.COM 	0x43, 0x15, 0xc5,		/* -74dbm  */
4059485SMikore.Li@Sun.COM 	0x53, 0x15, 0xc5,		/* -70dbm  */
4069485SMikore.Li@Sun.COM 	0x63, 0x15, 0xc5,		/* -66dbm  */
4079485SMikore.Li@Sun.COM };
4089485SMikore.Li@Sun.COM 
4099485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part1[] = {
4109485SMikore.Li@Sun.COM 	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
4119485SMikore.Li@Sun.COM 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
4129485SMikore.Li@Sun.COM 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
4139485SMikore.Li@Sun.COM 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
4149485SMikore.Li@Sun.COM };
4159485SMikore.Li@Sun.COM 
4169485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part2[] = {
4179485SMikore.Li@Sun.COM 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
4189485SMikore.Li@Sun.COM 	{ 0x04, 0x00 },	{ 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
4199485SMikore.Li@Sun.COM 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
4209485SMikore.Li@Sun.COM 	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
4219485SMikore.Li@Sun.COM 	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
4229485SMikore.Li@Sun.COM 	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
4239485SMikore.Li@Sun.COM 	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
4249485SMikore.Li@Sun.COM 	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
4259485SMikore.Li@Sun.COM 	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
4269485SMikore.Li@Sun.COM 	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
4279485SMikore.Li@Sun.COM };
4289485SMikore.Li@Sun.COM 
4299485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part3[] = {
4309485SMikore.Li@Sun.COM 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
4319485SMikore.Li@Sun.COM 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
4329485SMikore.Li@Sun.COM 	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
4339485SMikore.Li@Sun.COM 	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
4349485SMikore.Li@Sun.COM 	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
4359485SMikore.Li@Sun.COM 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
4369485SMikore.Li@Sun.COM 	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
4379485SMikore.Li@Sun.COM 	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
4389485SMikore.Li@Sun.COM };
4399485SMikore.Li@Sun.COM 
4409485SMikore.Li@Sun.COM static uint16_t urtw_8225v2_rxgain[] = {
441*10364SMikore.Li@Sun.COM 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
442*10364SMikore.Li@Sun.COM 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
443*10364SMikore.Li@Sun.COM 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
444*10364SMikore.Li@Sun.COM 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
445*10364SMikore.Li@Sun.COM 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
446*10364SMikore.Li@Sun.COM 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
447*10364SMikore.Li@Sun.COM 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
448*10364SMikore.Li@Sun.COM 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
449*10364SMikore.Li@Sun.COM 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
450*10364SMikore.Li@Sun.COM 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
4519485SMikore.Li@Sun.COM 	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
4529485SMikore.Li@Sun.COM 	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
4539485SMikore.Li@Sun.COM };
4549485SMikore.Li@Sun.COM 
4559485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
4569485SMikore.Li@Sun.COM 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
4579485SMikore.Li@Sun.COM 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
4589485SMikore.Li@Sun.COM 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
4599485SMikore.Li@Sun.COM 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
4609485SMikore.Li@Sun.COM 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
4619485SMikore.Li@Sun.COM 	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
4629485SMikore.Li@Sun.COM };
4639485SMikore.Li@Sun.COM 
4649485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_txpwr_cck[] = {
465*10364SMikore.Li@Sun.COM 	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
466*10364SMikore.Li@Sun.COM 	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
467*10364SMikore.Li@Sun.COM 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
468*10364SMikore.Li@Sun.COM 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
4699485SMikore.Li@Sun.COM };
4709485SMikore.Li@Sun.COM 
4719485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
472*10364SMikore.Li@Sun.COM 	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
473*10364SMikore.Li@Sun.COM 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
474*10364SMikore.Li@Sun.COM 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
475*10364SMikore.Li@Sun.COM 	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
476*10364SMikore.Li@Sun.COM };
477*10364SMikore.Li@Sun.COM 
478*10364SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_b_rf[] = {
479*10364SMikore.Li@Sun.COM 	{ 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
480*10364SMikore.Li@Sun.COM 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
481*10364SMikore.Li@Sun.COM 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
482*10364SMikore.Li@Sun.COM 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 },
483*10364SMikore.Li@Sun.COM 	{ 0x00, 0x01b7 }
4849485SMikore.Li@Sun.COM };
4859485SMikore.Li@Sun.COM 
4869485SMikore.Li@Sun.COM static struct urtw_pair urtw_ratetable[] = {
4879485SMikore.Li@Sun.COM 	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
4889485SMikore.Li@Sun.COM 	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
4899485SMikore.Li@Sun.COM 	{ 96, 10 }, { 108, 11 }
4909485SMikore.Li@Sun.COM };
4919485SMikore.Li@Sun.COM 
492*10364SMikore.Li@Sun.COM static int		urtw_8187_init(void *);
4939485SMikore.Li@Sun.COM static void		urtw_stop(struct urtw_softc *);
4949485SMikore.Li@Sun.COM static int		urtw_set_channel(struct urtw_softc *);
4959485SMikore.Li@Sun.COM static void
4969485SMikore.Li@Sun.COM urtw_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
4979485SMikore.Li@Sun.COM static int
4989485SMikore.Li@Sun.COM urtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
499*10364SMikore.Li@Sun.COM static usbd_status
500*10364SMikore.Li@Sun.COM urtw_read8_c(struct urtw_softc *, int, uint8_t *, uint8_t);
501*10364SMikore.Li@Sun.COM static usbd_status
502*10364SMikore.Li@Sun.COM urtw_read16_c(struct urtw_softc *, int, uint16_t *, uint8_t);
503*10364SMikore.Li@Sun.COM static usbd_status
504*10364SMikore.Li@Sun.COM urtw_read32_c(struct urtw_softc *, int, uint32_t *, uint8_t);
505*10364SMikore.Li@Sun.COM static usbd_status
506*10364SMikore.Li@Sun.COM urtw_write8_c(struct urtw_softc *, int, uint8_t, uint8_t);
507*10364SMikore.Li@Sun.COM static usbd_status
508*10364SMikore.Li@Sun.COM urtw_write16_c(struct urtw_softc *, int, uint16_t, uint8_t);
509*10364SMikore.Li@Sun.COM static usbd_status
510*10364SMikore.Li@Sun.COM urtw_write32_c(struct urtw_softc *, int, uint32_t, uint8_t);
5119485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_cs(struct urtw_softc *, int);
5129485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_ck(struct urtw_softc *);
5139485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
5149485SMikore.Li@Sun.COM 			    int);
5159485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_read32(struct urtw_softc *, uint32_t,
5169485SMikore.Li@Sun.COM 			    uint32_t *);
5179485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
5189485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_writebit(struct urtw_softc *, int16_t);
5199485SMikore.Li@Sun.COM static usbd_status	urtw_get_macaddr(struct urtw_softc *);
5209485SMikore.Li@Sun.COM static usbd_status	urtw_get_txpwr(struct urtw_softc *);
5219485SMikore.Li@Sun.COM static usbd_status	urtw_get_rfchip(struct urtw_softc *);
5229485SMikore.Li@Sun.COM static usbd_status	urtw_led_init(struct urtw_softc *);
5239485SMikore.Li@Sun.COM static usbd_status
5249485SMikore.Li@Sun.COM urtw_8225_read(struct urtw_softc *, uint8_t, uint32_t *);
525*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_init(struct urtw_rf *);
526*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_set_chan(struct urtw_rf *, int);
527*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_set_sens(struct urtw_rf *);
528*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_rf_init(struct urtw_rf *);
529*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_rf_set_chan(struct urtw_rf *, int);
5309485SMikore.Li@Sun.COM static usbd_status	urtw_open_pipes(struct urtw_softc *);
5319485SMikore.Li@Sun.COM static void urtw_close_pipes(struct urtw_softc *);
5329485SMikore.Li@Sun.COM static void urtw_led_launch(void *);
5339485SMikore.Li@Sun.COM 
534*10364SMikore.Li@Sun.COM static void	urtw_8187b_update_wmm(struct urtw_softc *);
535*10364SMikore.Li@Sun.COM static usbd_status	urtw_8187b_reset(struct urtw_softc *);
536*10364SMikore.Li@Sun.COM static int	urtw_8187b_init(void *);
537*10364SMikore.Li@Sun.COM static void	urtw_8225v2_b_config_mac(struct urtw_softc *);
538*10364SMikore.Li@Sun.COM static void	urtw_8225v2_b_init_rfe(struct urtw_softc *);
539*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_b_update_chan(struct urtw_softc *);
540*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_b_rf_init(struct urtw_rf *);
541*10364SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_b_rf_set_chan(struct urtw_rf *, int);
542*10364SMikore.Li@Sun.COM static void urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *, int);
543*10364SMikore.Li@Sun.COM 
5449485SMikore.Li@Sun.COM #ifdef DEBUG
5459485SMikore.Li@Sun.COM 
5469485SMikore.Li@Sun.COM #define	URTW_DEBUG_XMIT		0x00000001
5479485SMikore.Li@Sun.COM #define	URTW_DEBUG_RECV		0x00000002
5489485SMikore.Li@Sun.COM #define	URTW_DEBUG_LED 		0x00000004
5499485SMikore.Li@Sun.COM #define	URTW_DEBUG_GLD 		0x00000008
5509485SMikore.Li@Sun.COM #define	URTW_DEBUG_RF		0x00000010
5519485SMikore.Li@Sun.COM #define	URTW_DEBUG_ATTACH 	0x00000020
5529485SMikore.Li@Sun.COM #define	URTW_DEBUG_ACTIVE 	0x00000040
5539485SMikore.Li@Sun.COM #define	URTW_DEBUG_HWTYPE	0x00000080
554*10364SMikore.Li@Sun.COM #define	URTW_DEBUG_DEVREQ	0x00000100
5559485SMikore.Li@Sun.COM #define	URTW_DEBUG_HOTPLUG	0x00000200
556*10364SMikore.Li@Sun.COM #define	URTW_DEBUG_STATE	0x00000400
5579485SMikore.Li@Sun.COM #define	URTW_DEBUG_TX_PROC	0x00000800
5589485SMikore.Li@Sun.COM #define	URTW_DEBUG_RX_PROC 	0x00001000
5599485SMikore.Li@Sun.COM #define	URTW_DEBUG_EEPROM	0x00002000
5609485SMikore.Li@Sun.COM #define	URTW_DEBUG_RESET	0x00004000
5619485SMikore.Li@Sun.COM #define	URTW_DEBUG_ANY		0xffffffff
5629485SMikore.Li@Sun.COM 
5639485SMikore.Li@Sun.COM uint32_t urtw8187_dbg_flags = 0;
5649485SMikore.Li@Sun.COM static void
5659485SMikore.Li@Sun.COM urtw8187_dbg(dev_info_t *dip, int level, const char *fmt, ...)
5669485SMikore.Li@Sun.COM {
5679485SMikore.Li@Sun.COM 	char		msg_buffer[255];
5689485SMikore.Li@Sun.COM 	va_list	ap;
5699485SMikore.Li@Sun.COM 
5709485SMikore.Li@Sun.COM 	if (dip == NULL) {
5719485SMikore.Li@Sun.COM 		return;
5729485SMikore.Li@Sun.COM 	}
5739485SMikore.Li@Sun.COM 
5749485SMikore.Li@Sun.COM 	va_start(ap, fmt);
5759485SMikore.Li@Sun.COM 	(void) vsprintf(msg_buffer, fmt, ap);
5769485SMikore.Li@Sun.COM 	cmn_err(level, "%s%d: %s", ddi_get_name(dip),
5779485SMikore.Li@Sun.COM 	    ddi_get_instance(dip), msg_buffer);
5789485SMikore.Li@Sun.COM 	va_end(ap);
5799485SMikore.Li@Sun.COM }
5809485SMikore.Li@Sun.COM 
5819485SMikore.Li@Sun.COM #define	URTW8187_DBG(l, x) do {\
5829485SMikore.Li@Sun.COM 	_NOTE(CONSTANTCONDITION) \
5839485SMikore.Li@Sun.COM 	if ((l) & urtw8187_dbg_flags) \
5849485SMikore.Li@Sun.COM 		urtw8187_dbg x;\
5859485SMikore.Li@Sun.COM 	_NOTE(CONSTANTCONDITION) \
5869485SMikore.Li@Sun.COM } while (0)
5879485SMikore.Li@Sun.COM #else
5889485SMikore.Li@Sun.COM #define	URTW8187_DBG(l, x)
5899485SMikore.Li@Sun.COM #endif
5909485SMikore.Li@Sun.COM 
5919485SMikore.Li@Sun.COM static usbd_status
5929485SMikore.Li@Sun.COM urtw_led_init(struct urtw_softc *sc)
5939485SMikore.Li@Sun.COM {
5949485SMikore.Li@Sun.COM 	uint32_t rev;
5959485SMikore.Li@Sun.COM 	usbd_status error;
5969485SMikore.Li@Sun.COM 
597*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_PSR, &sc->sc_psr, 0))
5989485SMikore.Li@Sun.COM 		goto fail;
5999485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
6009485SMikore.Li@Sun.COM 	if (error != 0)
6019485SMikore.Li@Sun.COM 		goto fail;
6029485SMikore.Li@Sun.COM 
6039485SMikore.Li@Sun.COM 	switch (rev & URTW_EPROM_CID_MASK) {
6049485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_ALPHA0:
6059485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE1;
6069485SMikore.Li@Sun.COM 		break;
6079485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_SERCOMM_PS:
6089485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE3;
6099485SMikore.Li@Sun.COM 		break;
6109485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_HW_LED:
6119485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_HW_LED;
6129485SMikore.Li@Sun.COM 		break;
6139485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_RSVD0:
6149485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_RSVD1:
6159485SMikore.Li@Sun.COM 	default:
6169485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE0;
6179485SMikore.Li@Sun.COM 		break;
6189485SMikore.Li@Sun.COM 	}
6199485SMikore.Li@Sun.COM 
6209485SMikore.Li@Sun.COM 	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
6219485SMikore.Li@Sun.COM 
6229485SMikore.Li@Sun.COM fail:
6239485SMikore.Li@Sun.COM 	return (error);
6249485SMikore.Li@Sun.COM }
6259485SMikore.Li@Sun.COM 
6269485SMikore.Li@Sun.COM static usbd_status
6279485SMikore.Li@Sun.COM urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
6289485SMikore.Li@Sun.COM     uint16_t *data)
6299485SMikore.Li@Sun.COM {
6309485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
6319485SMikore.Li@Sun.COM 	usb_cr_t cr;
6329485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
6339485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
6349485SMikore.Li@Sun.COM 	uint16_t data16;
6359485SMikore.Li@Sun.COM 	usbd_status error;
6369485SMikore.Li@Sun.COM 
6379485SMikore.Li@Sun.COM 	data16 = *data;
6389485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
6399485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
6409485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
6419485SMikore.Li@Sun.COM 	req.wValue = addr;
6429485SMikore.Li@Sun.COM 	req.wIndex = (uint16_t)index;
6439485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
6449485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
6459485SMikore.Li@Sun.COM 
6469485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint16_t), BPRI_MED);
6479485SMikore.Li@Sun.COM 	if (mp == 0) {
6489485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_8225_write_s16: allocb failed\n");
6499485SMikore.Li@Sun.COM 		return (-1);
6509485SMikore.Li@Sun.COM 	}
6519485SMikore.Li@Sun.COM 	*(mp->b_rptr) = (data16 & 0x00ff);
6529485SMikore.Li@Sun.COM 	*(mp->b_rptr + 1) = (data16 & 0xff00) >> 8;
6539485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint16_t);
6549485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
6559485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
6569485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
6579485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
6589485SMikore.Li@Sun.COM 		    "urtw_8225_write_s16: could not set regs:"
6599485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
6609485SMikore.Li@Sun.COM 	}
6619485SMikore.Li@Sun.COM 	if (mp)
6629485SMikore.Li@Sun.COM 		freemsg(mp);
6639485SMikore.Li@Sun.COM 	return (error);
6649485SMikore.Li@Sun.COM 
6659485SMikore.Li@Sun.COM }
6669485SMikore.Li@Sun.COM 
6679485SMikore.Li@Sun.COM static usbd_status
6689485SMikore.Li@Sun.COM urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
6699485SMikore.Li@Sun.COM {
6709485SMikore.Li@Sun.COM 	int i;
6719485SMikore.Li@Sun.COM 	int16_t bit;
6729485SMikore.Li@Sun.COM 	uint8_t rlen = 12, wlen = 6;
6739485SMikore.Li@Sun.COM 	uint16_t o1, o2, o3, tmp;
6749485SMikore.Li@Sun.COM 	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
6759485SMikore.Li@Sun.COM 	uint32_t mask = 0x80000000, value = 0;
6769485SMikore.Li@Sun.COM 	usbd_status error;
6779485SMikore.Li@Sun.COM 
678*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &o1, 0))
6799485SMikore.Li@Sun.COM 		goto fail;
680*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &o2, 0))
6819485SMikore.Li@Sun.COM 		goto fail;
682*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &o3, 0))
6839485SMikore.Li@Sun.COM 		goto fail;
684*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2 | 0xf, 0))
6859485SMikore.Li@Sun.COM 		goto fail;
686*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3 | 0xf, 0))
6879485SMikore.Li@Sun.COM 		goto fail;
6889485SMikore.Li@Sun.COM 	o1 &= ~0xf;
6899485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
690*10364SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_EN, 0))
6919485SMikore.Li@Sun.COM 		goto fail;
6929485SMikore.Li@Sun.COM 	DELAY(5);
693*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, o1, 0))
6949485SMikore.Li@Sun.COM 		goto fail;
6959485SMikore.Li@Sun.COM 	DELAY(5);
6969485SMikore.Li@Sun.COM 
6979485SMikore.Li@Sun.COM 	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
6989485SMikore.Li@Sun.COM 		bit = ((d2w & mask) != 0) ? 1 : 0;
6999485SMikore.Li@Sun.COM 
700*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
701*10364SMikore.Li@Sun.COM 		    bit | o1, 0))
7029485SMikore.Li@Sun.COM 			goto fail;
7039485SMikore.Li@Sun.COM 		DELAY(2);
704*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
705*10364SMikore.Li@Sun.COM 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
7069485SMikore.Li@Sun.COM 			goto fail;
7079485SMikore.Li@Sun.COM 		DELAY(2);
708*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
709*10364SMikore.Li@Sun.COM 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
7109485SMikore.Li@Sun.COM 			goto fail;
7119485SMikore.Li@Sun.COM 		DELAY(2);
7129485SMikore.Li@Sun.COM 		mask = mask >> 1;
7139485SMikore.Li@Sun.COM 		if (i == 2)
7149485SMikore.Li@Sun.COM 			break;
7159485SMikore.Li@Sun.COM 		bit = ((d2w & mask) != 0) ? 1 : 0;
716*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
717*10364SMikore.Li@Sun.COM 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
7189485SMikore.Li@Sun.COM 			goto fail;
7199485SMikore.Li@Sun.COM 		DELAY(2);
720*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
721*10364SMikore.Li@Sun.COM 		    bit | o1 | URTW_BB_HOST_BANG_CLK, 0))
7229485SMikore.Li@Sun.COM 			goto fail;
7239485SMikore.Li@Sun.COM 		DELAY(2);
724*10364SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
725*10364SMikore.Li@Sun.COM 		    bit | o1, 0))
7269485SMikore.Li@Sun.COM 			goto fail;
7279485SMikore.Li@Sun.COM 		DELAY(1);
7289485SMikore.Li@Sun.COM 	}
7299485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
730*10364SMikore.Li@Sun.COM 	    bit | o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
7319485SMikore.Li@Sun.COM 		goto fail;
7329485SMikore.Li@Sun.COM 	DELAY(2);
7339485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
734*10364SMikore.Li@Sun.COM 	    bit | o1 | URTW_BB_HOST_BANG_RW, 0))
7359485SMikore.Li@Sun.COM 		goto fail;
7369485SMikore.Li@Sun.COM 	DELAY(2);
7379485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
738*10364SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_RW, 0))
7399485SMikore.Li@Sun.COM 		goto fail;
7409485SMikore.Li@Sun.COM 	DELAY(2);
7419485SMikore.Li@Sun.COM 
7429485SMikore.Li@Sun.COM 	mask = 0x800;
7439485SMikore.Li@Sun.COM 	for (i = 0; i < rlen; i++, mask = mask >> 1) {
7449485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
745*10364SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW, 0))
7469485SMikore.Li@Sun.COM 			goto fail;
7479485SMikore.Li@Sun.COM 		DELAY(2);
7489485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
749*10364SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
7509485SMikore.Li@Sun.COM 			goto fail;
7519485SMikore.Li@Sun.COM 		DELAY(2);
7529485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
753*10364SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
7549485SMikore.Li@Sun.COM 			goto fail;
7559485SMikore.Li@Sun.COM 		DELAY(2);
7569485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
757*10364SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK, 0))
7589485SMikore.Li@Sun.COM 			goto fail;
7599485SMikore.Li@Sun.COM 		DELAY(2);
7609485SMikore.Li@Sun.COM 
761*10364SMikore.Li@Sun.COM 		if (error = urtw_read16_c(sc, URTW_RF_PINS_INPUT, &tmp, 0))
7629485SMikore.Li@Sun.COM 			goto fail;
7639485SMikore.Li@Sun.COM 		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
7649485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
765*10364SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW, 0))
7669485SMikore.Li@Sun.COM 			goto fail;
7679485SMikore.Li@Sun.COM 		DELAY(2);
7689485SMikore.Li@Sun.COM 	}
7699485SMikore.Li@Sun.COM 
7709485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
7719485SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_EN |
772*10364SMikore.Li@Sun.COM 	    URTW_BB_HOST_BANG_RW, 0))
7739485SMikore.Li@Sun.COM 		goto fail;
7749485SMikore.Li@Sun.COM 	DELAY(2);
7759485SMikore.Li@Sun.COM 
776*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2, 0))
7779485SMikore.Li@Sun.COM 		goto fail;
778*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3, 0))
7799485SMikore.Li@Sun.COM 		goto fail;
780*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x3a0, 0);
7819485SMikore.Li@Sun.COM 
7829485SMikore.Li@Sun.COM 	if (data != NULL)
7839485SMikore.Li@Sun.COM 		*data = value;
7849485SMikore.Li@Sun.COM fail:
7859485SMikore.Li@Sun.COM 	return (error);
7869485SMikore.Li@Sun.COM }
7879485SMikore.Li@Sun.COM 
7889485SMikore.Li@Sun.COM static void
7899485SMikore.Li@Sun.COM urtw_delay_ms(int t)
7909485SMikore.Li@Sun.COM {
7919485SMikore.Li@Sun.COM 	DELAY(t * 1000);
7929485SMikore.Li@Sun.COM }
7939485SMikore.Li@Sun.COM 
7949485SMikore.Li@Sun.COM static usbd_status
7959485SMikore.Li@Sun.COM urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
7969485SMikore.Li@Sun.COM {
7979485SMikore.Li@Sun.COM 	uint16_t d80, d82, d84;
7989485SMikore.Li@Sun.COM 	usbd_status error;
7999485SMikore.Li@Sun.COM 
800*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &d80, 0))
8019485SMikore.Li@Sun.COM 		goto fail;
8029485SMikore.Li@Sun.COM 	d80 &= 0xfff3;
803*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &d82, 0))
8049485SMikore.Li@Sun.COM 		goto fail;
805*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &d84, 0))
8069485SMikore.Li@Sun.COM 		goto fail;
8079485SMikore.Li@Sun.COM 	d84 &= 0xfff0;
8089485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE,
809*10364SMikore.Li@Sun.COM 	    d82 | 0x0007, 0))
8109485SMikore.Li@Sun.COM 		goto fail;
8119485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT,
812*10364SMikore.Li@Sun.COM 	    d84 | 0x0007, 0))
8139485SMikore.Li@Sun.COM 		goto fail;
8149485SMikore.Li@Sun.COM 
8159485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
816*10364SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN, 0))
8179485SMikore.Li@Sun.COM 		goto fail;
818*10364SMikore.Li@Sun.COM 	urtw_delay_ms(2);
819*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, d80, 0))
8209485SMikore.Li@Sun.COM 		goto fail;
8219485SMikore.Li@Sun.COM 
8229485SMikore.Li@Sun.COM 	error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
8239485SMikore.Li@Sun.COM 	if (error != 0)
8249485SMikore.Li@Sun.COM 		goto fail;
8259485SMikore.Li@Sun.COM 
8269485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
827*10364SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN, 0))
8289485SMikore.Li@Sun.COM 		goto fail;
8299485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
830*10364SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN, 0))
8319485SMikore.Li@Sun.COM 		goto fail;
832*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, d84, 0);
8339485SMikore.Li@Sun.COM 	urtw_delay_ms(2);
8349485SMikore.Li@Sun.COM fail:
8359485SMikore.Li@Sun.COM 	return (error);
8369485SMikore.Li@Sun.COM }
8379485SMikore.Li@Sun.COM 
8389485SMikore.Li@Sun.COM static usbd_status
8399485SMikore.Li@Sun.COM urtw_8225_isv2(struct urtw_softc *sc, int *ret)
8409485SMikore.Li@Sun.COM {
8419485SMikore.Li@Sun.COM 	uint32_t data;
8429485SMikore.Li@Sun.COM 	usbd_status error;
8439485SMikore.Li@Sun.COM 
8449485SMikore.Li@Sun.COM 	*ret = 1;
8459485SMikore.Li@Sun.COM 
846*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x0080, 0))
8479485SMikore.Li@Sun.COM 		goto fail;
848*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x0080, 0))
8499485SMikore.Li@Sun.COM 		goto fail;
850*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x0080, 0))
8519485SMikore.Li@Sun.COM 		goto fail;
8529485SMikore.Li@Sun.COM 	urtw_delay_ms(300);
8539485SMikore.Li@Sun.COM 
8549485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
8559485SMikore.Li@Sun.COM 		goto fail;
8569485SMikore.Li@Sun.COM 
8579485SMikore.Li@Sun.COM 	error = urtw_8225_read(sc, 0x8, &data);
8589485SMikore.Li@Sun.COM 	if (error != 0)
8599485SMikore.Li@Sun.COM 		goto fail;
8609485SMikore.Li@Sun.COM 	if (data != 0x588)
8619485SMikore.Li@Sun.COM 		*ret = 0;
8629485SMikore.Li@Sun.COM 	else {
8639485SMikore.Li@Sun.COM 		error = urtw_8225_read(sc, 0x9, &data);
8649485SMikore.Li@Sun.COM 		if (error != 0)
8659485SMikore.Li@Sun.COM 			goto fail;
8669485SMikore.Li@Sun.COM 		if (data != 0x700)
8679485SMikore.Li@Sun.COM 			*ret = 0;
8689485SMikore.Li@Sun.COM 	}
8699485SMikore.Li@Sun.COM 
8709485SMikore.Li@Sun.COM 	error = urtw_8225_write_c(sc, 0x0, 0xb7);
8719485SMikore.Li@Sun.COM fail:
8729485SMikore.Li@Sun.COM 	return (error);
8739485SMikore.Li@Sun.COM }
8749485SMikore.Li@Sun.COM 
8759485SMikore.Li@Sun.COM static usbd_status
8769485SMikore.Li@Sun.COM urtw_get_rfchip(struct urtw_softc *sc)
8779485SMikore.Li@Sun.COM {
878*10364SMikore.Li@Sun.COM 	struct urtw_rf *rf = &sc->sc_rf;
8799485SMikore.Li@Sun.COM 	int ret;
8809485SMikore.Li@Sun.COM 	uint32_t data;
8819485SMikore.Li@Sun.COM 	usbd_status error;
8829485SMikore.Li@Sun.COM 
883*10364SMikore.Li@Sun.COM 	rf->rf_sc = sc;
884*10364SMikore.Li@Sun.COM 
885*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
886*10364SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
887*10364SMikore.Li@Sun.COM 		if (error != 0) {
888*10364SMikore.Li@Sun.COM 			cmn_err(CE_WARN, "RF ID read failed\n");
889*10364SMikore.Li@Sun.COM 			return (-1);
890*10364SMikore.Li@Sun.COM 		}
891*10364SMikore.Li@Sun.COM 		switch (data & 0xff) {
892*10364SMikore.Li@Sun.COM 		case URTW_EPROM_RFCHIPID_RTL8225U:
893*10364SMikore.Li@Sun.COM 			error = urtw_8225_isv2(sc, &ret);
894*10364SMikore.Li@Sun.COM 			if (error != 0) {
895*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
896*10364SMikore.Li@Sun.COM 				    (sc->sc_dev, CE_CONT,
897*10364SMikore.Li@Sun.COM 				    "8225 version check failed\n"));
898*10364SMikore.Li@Sun.COM 				goto fail;
899*10364SMikore.Li@Sun.COM 			}
900*10364SMikore.Li@Sun.COM 			if (ret == 0) {
901*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
902*10364SMikore.Li@Sun.COM 				    (sc->sc_dev, CE_CONT,
903*10364SMikore.Li@Sun.COM 				    "8225 detected\n"));
904*10364SMikore.Li@Sun.COM 				rf->init = urtw_8225_rf_init;
905*10364SMikore.Li@Sun.COM 				rf->set_chan = urtw_8225_rf_set_chan;
906*10364SMikore.Li@Sun.COM 				rf->set_sens = urtw_8225_rf_set_sens;
907*10364SMikore.Li@Sun.COM 			} else {
908*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_HWTYPE,
909*10364SMikore.Li@Sun.COM 				    (sc->sc_dev, CE_CONT,
910*10364SMikore.Li@Sun.COM 				    "8225 v2 detected\n"));
911*10364SMikore.Li@Sun.COM 				rf->init = urtw_8225v2_rf_init;
912*10364SMikore.Li@Sun.COM 				rf->set_chan = urtw_8225v2_rf_set_chan;
913*10364SMikore.Li@Sun.COM 				rf->set_sens = NULL;
914*10364SMikore.Li@Sun.COM 			}
915*10364SMikore.Li@Sun.COM 			break;
916*10364SMikore.Li@Sun.COM 		default:
9179485SMikore.Li@Sun.COM 			goto fail;
9189485SMikore.Li@Sun.COM 		}
919*10364SMikore.Li@Sun.COM 	} else {
920*10364SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_HWTYPE,
921*10364SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT,
922*10364SMikore.Li@Sun.COM 		    "8225 v2 [b] detected\n"));
923*10364SMikore.Li@Sun.COM 		rf->init = urtw_8225v2_b_rf_init;
924*10364SMikore.Li@Sun.COM 		rf->set_chan = urtw_8225v2_b_rf_set_chan;
925*10364SMikore.Li@Sun.COM 		rf->set_sens = NULL;
9269485SMikore.Li@Sun.COM 	}
9279485SMikore.Li@Sun.COM 
928*10364SMikore.Li@Sun.COM 	rf->max_sens = URTW_8225_RF_MAX_SENS;
929*10364SMikore.Li@Sun.COM 	rf->sens = URTW_8225_RF_DEF_SENS;
930*10364SMikore.Li@Sun.COM 
931*10364SMikore.Li@Sun.COM 	return (0);
932*10364SMikore.Li@Sun.COM 
9339485SMikore.Li@Sun.COM fail:
934*10364SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "unsupported RF chip %d\n", data & 0xff);
935*10364SMikore.Li@Sun.COM 	return (-1);
9369485SMikore.Li@Sun.COM }
9379485SMikore.Li@Sun.COM 
9389485SMikore.Li@Sun.COM static usbd_status
9399485SMikore.Li@Sun.COM urtw_get_txpwr(struct urtw_softc *sc)
9409485SMikore.Li@Sun.COM {
9419485SMikore.Li@Sun.COM 	int i, j;
9429485SMikore.Li@Sun.COM 	uint32_t data;
9439485SMikore.Li@Sun.COM 	usbd_status error;
9449485SMikore.Li@Sun.COM 
9459485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
9469485SMikore.Li@Sun.COM 	if (error != 0)
9479485SMikore.Li@Sun.COM 		goto fail;
9489485SMikore.Li@Sun.COM 	sc->sc_txpwr_cck_base = data & 0xf;
9499485SMikore.Li@Sun.COM 	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
9509485SMikore.Li@Sun.COM 
9519485SMikore.Li@Sun.COM 	for (i = 1, j = 0; i < 6; i += 2, j++) {
9529485SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
9539485SMikore.Li@Sun.COM 		if (error != 0)
9549485SMikore.Li@Sun.COM 			goto fail;
9559485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i] = data & 0xf;
9569485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
9579485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
9589485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
9599485SMikore.Li@Sun.COM 	}
9609485SMikore.Li@Sun.COM 	for (i = 1, j = 0; i < 4; i += 2, j++) {
9619485SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
9629485SMikore.Li@Sun.COM 		if (error != 0)
9639485SMikore.Li@Sun.COM 			goto fail;
9649485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6] = data & 0xf;
9659485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
9669485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
9679485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
9689485SMikore.Li@Sun.COM 	}
969*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
970*10364SMikore.Li@Sun.COM 		for (i = 1, j = 0; i < 4; i += 2, j++) {
971*10364SMikore.Li@Sun.COM 			error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
972*10364SMikore.Li@Sun.COM 			    &data);
973*10364SMikore.Li@Sun.COM 			if (error != 0)
974*10364SMikore.Li@Sun.COM 				goto fail;
975*10364SMikore.Li@Sun.COM 			sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
976*10364SMikore.Li@Sun.COM 			sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
977*10364SMikore.Li@Sun.COM 			sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
978*10364SMikore.Li@Sun.COM 			sc->sc_txpwr_ofdm[i + 6 + 4 + 1] =
979*10364SMikore.Li@Sun.COM 			    (data & 0xf000) >> 12;
980*10364SMikore.Li@Sun.COM 		}
981*10364SMikore.Li@Sun.COM 	} else {
982*10364SMikore.Li@Sun.COM 		/* Channel 11. */
983*10364SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, 0x1b, &data);
9849485SMikore.Li@Sun.COM 		if (error != 0)
9859485SMikore.Li@Sun.COM 			goto fail;
986*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[11] = data & 0xf;
987*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[11] = (data & 0xf0) >> 4;
988*10364SMikore.Li@Sun.COM 
989*10364SMikore.Li@Sun.COM 		/* Channel 12. */
990*10364SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, 0xa, &data);
991*10364SMikore.Li@Sun.COM 		if (error != 0)
992*10364SMikore.Li@Sun.COM 			goto fail;
993*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[12] = data & 0xf;
994*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[12] = (data & 0xf0) >> 4;
995*10364SMikore.Li@Sun.COM 
996*10364SMikore.Li@Sun.COM 		/* Channel 13, 14. */
997*10364SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, 0x1c, &data);
998*10364SMikore.Li@Sun.COM 		if (error != 0)
999*10364SMikore.Li@Sun.COM 			goto fail;
1000*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[13] = data & 0xf;
1001*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[13] = (data & 0xf0) >> 4;
1002*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[14] = (data & 0xf00) >> 8;
1003*10364SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[14] = (data & 0xf000) >> 12;
10049485SMikore.Li@Sun.COM 	}
10059485SMikore.Li@Sun.COM fail:
10069485SMikore.Li@Sun.COM 	return (error);
10079485SMikore.Li@Sun.COM }
10089485SMikore.Li@Sun.COM 
1009*10364SMikore.Li@Sun.COM 
10109485SMikore.Li@Sun.COM static usbd_status
10119485SMikore.Li@Sun.COM urtw_get_macaddr(struct urtw_softc *sc)
10129485SMikore.Li@Sun.COM {
10139485SMikore.Li@Sun.COM 	uint32_t data;
10149485SMikore.Li@Sun.COM 	usbd_status error;
10159485SMikore.Li@Sun.COM 	uint8_t *m = 0;
10169485SMikore.Li@Sun.COM 
10179485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
10189485SMikore.Li@Sun.COM 	if (error != 0)
10199485SMikore.Li@Sun.COM 		goto fail;
10209485SMikore.Li@Sun.COM 	sc->sc_bssid[0] = data & 0xff;
10219485SMikore.Li@Sun.COM 	sc->sc_bssid[1] = (data & 0xff00) >> 8;
10229485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
10239485SMikore.Li@Sun.COM 	if (error != 0)
10249485SMikore.Li@Sun.COM 		goto fail;
10259485SMikore.Li@Sun.COM 	sc->sc_bssid[2] = data & 0xff;
10269485SMikore.Li@Sun.COM 	sc->sc_bssid[3] = (data & 0xff00) >> 8;
10279485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
10289485SMikore.Li@Sun.COM 	if (error != 0)
10299485SMikore.Li@Sun.COM 		goto fail;
10309485SMikore.Li@Sun.COM 	sc->sc_bssid[4] = data & 0xff;
10319485SMikore.Li@Sun.COM 	sc->sc_bssid[5] = (data & 0xff00) >> 8;
10329485SMikore.Li@Sun.COM 	bcopy(sc->sc_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
10339485SMikore.Li@Sun.COM 	m = sc->sc_bssid;
10349485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
10359485SMikore.Li@Sun.COM 	    "MAC: %x:%x:%x:%x:%x:%x\n",
10369485SMikore.Li@Sun.COM 	    m[0], m[1], m[2], m[3], m[4], m[5]));
10379485SMikore.Li@Sun.COM fail:
10389485SMikore.Li@Sun.COM 	return (error);
10399485SMikore.Li@Sun.COM }
10409485SMikore.Li@Sun.COM 
10419485SMikore.Li@Sun.COM static usbd_status
10429485SMikore.Li@Sun.COM urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
10439485SMikore.Li@Sun.COM {
10449485SMikore.Li@Sun.COM #define	URTW_READCMD_LEN	3
10459485SMikore.Li@Sun.COM 	int addrlen, i;
10469485SMikore.Li@Sun.COM 	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
10479485SMikore.Li@Sun.COM 	usbd_status error;
10489485SMikore.Li@Sun.COM 
10499485SMikore.Li@Sun.COM 	/* NB: make sure the buffer is initialized  */
10509485SMikore.Li@Sun.COM 	*data = 0;
10519485SMikore.Li@Sun.COM 
10529485SMikore.Li@Sun.COM 	/* enable EPROM programming */
10539485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD,
1054*10364SMikore.Li@Sun.COM 	    URTW_EPROM_CMD_PROGRAM_MODE, 0))
10559485SMikore.Li@Sun.COM 		goto fail;
10569485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
10579485SMikore.Li@Sun.COM 
10589485SMikore.Li@Sun.COM 	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
10599485SMikore.Li@Sun.COM 	if (error != 0)
10609485SMikore.Li@Sun.COM 		goto fail;
10619485SMikore.Li@Sun.COM 	error = urtw_eprom_ck(sc);
10629485SMikore.Li@Sun.COM 	if (error != 0)
10639485SMikore.Li@Sun.COM 		goto fail;
10649485SMikore.Li@Sun.COM 	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
10659485SMikore.Li@Sun.COM 	if (error != 0)
10669485SMikore.Li@Sun.COM 		goto fail;
10679485SMikore.Li@Sun.COM 	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
10689485SMikore.Li@Sun.COM 		addrlen = 8;
10699485SMikore.Li@Sun.COM 		addrstr[0] = addr & (1 << 7);
10709485SMikore.Li@Sun.COM 		addrstr[1] = addr & (1 << 6);
10719485SMikore.Li@Sun.COM 		addrstr[2] = addr & (1 << 5);
10729485SMikore.Li@Sun.COM 		addrstr[3] = addr & (1 << 4);
10739485SMikore.Li@Sun.COM 		addrstr[4] = addr & (1 << 3);
10749485SMikore.Li@Sun.COM 		addrstr[5] = addr & (1 << 2);
10759485SMikore.Li@Sun.COM 		addrstr[6] = addr & (1 << 1);
10769485SMikore.Li@Sun.COM 		addrstr[7] = addr & (1 << 0);
10779485SMikore.Li@Sun.COM 	} else {
10789485SMikore.Li@Sun.COM 		addrlen = 6;
10799485SMikore.Li@Sun.COM 		addrstr[0] = addr & (1 << 5);
10809485SMikore.Li@Sun.COM 		addrstr[1] = addr & (1 << 4);
10819485SMikore.Li@Sun.COM 		addrstr[2] = addr & (1 << 3);
10829485SMikore.Li@Sun.COM 		addrstr[3] = addr & (1 << 2);
10839485SMikore.Li@Sun.COM 		addrstr[4] = addr & (1 << 1);
10849485SMikore.Li@Sun.COM 		addrstr[5] = addr & (1 << 0);
10859485SMikore.Li@Sun.COM 	}
10869485SMikore.Li@Sun.COM 	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
10879485SMikore.Li@Sun.COM 	if (error != 0)
10889485SMikore.Li@Sun.COM 		goto fail;
10899485SMikore.Li@Sun.COM 
10909485SMikore.Li@Sun.COM 	error = urtw_eprom_writebit(sc, 0);
10919485SMikore.Li@Sun.COM 	if (error != 0)
10929485SMikore.Li@Sun.COM 		goto fail;
10939485SMikore.Li@Sun.COM 
10949485SMikore.Li@Sun.COM 	for (i = 0; i < 16; i++) {
10959485SMikore.Li@Sun.COM 		error = urtw_eprom_ck(sc);
10969485SMikore.Li@Sun.COM 		if (error != 0)
10979485SMikore.Li@Sun.COM 			goto fail;
10989485SMikore.Li@Sun.COM 		error = urtw_eprom_readbit(sc, &data16);
10999485SMikore.Li@Sun.COM 		if (error != 0)
11009485SMikore.Li@Sun.COM 			goto fail;
11019485SMikore.Li@Sun.COM 
11029485SMikore.Li@Sun.COM 		(*data) |= (data16 << (15 - i));
11039485SMikore.Li@Sun.COM 	}
11049485SMikore.Li@Sun.COM 
11059485SMikore.Li@Sun.COM 	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
11069485SMikore.Li@Sun.COM 	if (error != 0)
11079485SMikore.Li@Sun.COM 		goto fail;
11089485SMikore.Li@Sun.COM 	error = urtw_eprom_ck(sc);
11099485SMikore.Li@Sun.COM 	if (error != 0)
11109485SMikore.Li@Sun.COM 		goto fail;
11119485SMikore.Li@Sun.COM 
11129485SMikore.Li@Sun.COM 	/* now disable EPROM programming */
1113*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD,
1114*10364SMikore.Li@Sun.COM 	    URTW_EPROM_CMD_NORMAL_MODE, 0);
11159485SMikore.Li@Sun.COM fail:
11169485SMikore.Li@Sun.COM 	return (error);
11179485SMikore.Li@Sun.COM #undef URTW_READCMD_LEN
11189485SMikore.Li@Sun.COM }
11199485SMikore.Li@Sun.COM 
11209485SMikore.Li@Sun.COM static usbd_status
11219485SMikore.Li@Sun.COM urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
11229485SMikore.Li@Sun.COM {
11239485SMikore.Li@Sun.COM 	uint8_t data8;
11249485SMikore.Li@Sun.COM 	usbd_status error;
11259485SMikore.Li@Sun.COM 
1126*10364SMikore.Li@Sun.COM 	error = urtw_read8_c(sc, URTW_EPROM_CMD, &data8, 0);
11279485SMikore.Li@Sun.COM 	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
11289485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
11299485SMikore.Li@Sun.COM 	return (error);
11309485SMikore.Li@Sun.COM }
11319485SMikore.Li@Sun.COM 
11329485SMikore.Li@Sun.COM static usbd_status
11339485SMikore.Li@Sun.COM urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
11349485SMikore.Li@Sun.COM {
11359485SMikore.Li@Sun.COM 	int i = 0;
11369485SMikore.Li@Sun.COM 	usbd_status error;
11379485SMikore.Li@Sun.COM 
11389485SMikore.Li@Sun.COM 	for (i = 0; i < buflen; i++) {
11399485SMikore.Li@Sun.COM 		error = urtw_eprom_writebit(sc, buf[i]);
11409485SMikore.Li@Sun.COM 		if (error != 0)
11419485SMikore.Li@Sun.COM 			goto fail;
11429485SMikore.Li@Sun.COM 		error = urtw_eprom_ck(sc);
11439485SMikore.Li@Sun.COM 		if (error != 0)
11449485SMikore.Li@Sun.COM 			goto fail;
11459485SMikore.Li@Sun.COM 	}
11469485SMikore.Li@Sun.COM fail:
11479485SMikore.Li@Sun.COM 	return (error);
11489485SMikore.Li@Sun.COM }
11499485SMikore.Li@Sun.COM 
11509485SMikore.Li@Sun.COM static usbd_status
11519485SMikore.Li@Sun.COM urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
11529485SMikore.Li@Sun.COM {
11539485SMikore.Li@Sun.COM 	uint8_t data;
11549485SMikore.Li@Sun.COM 	usbd_status error;
11559485SMikore.Li@Sun.COM 
1156*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
11579485SMikore.Li@Sun.COM 		goto fail;
11589485SMikore.Li@Sun.COM 	if (bit != 0)
11599485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1160*10364SMikore.Li@Sun.COM 		    data | URTW_EPROM_WRITEBIT, 0);
11619485SMikore.Li@Sun.COM 	else
11629485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1163*10364SMikore.Li@Sun.COM 		    data & ~URTW_EPROM_WRITEBIT, 0);
11649485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
11659485SMikore.Li@Sun.COM fail:
11669485SMikore.Li@Sun.COM 	return (error);
11679485SMikore.Li@Sun.COM }
11689485SMikore.Li@Sun.COM 
11699485SMikore.Li@Sun.COM static usbd_status
11709485SMikore.Li@Sun.COM urtw_eprom_ck(struct urtw_softc *sc)
11719485SMikore.Li@Sun.COM {
11729485SMikore.Li@Sun.COM 	uint8_t data;
11739485SMikore.Li@Sun.COM 	usbd_status error;
11749485SMikore.Li@Sun.COM 
11759485SMikore.Li@Sun.COM 	/* masking  */
1176*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
11779485SMikore.Li@Sun.COM 		goto fail;
1178*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK, 0))
11799485SMikore.Li@Sun.COM 		goto fail;
11809485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
11819485SMikore.Li@Sun.COM 	/* unmasking  */
1182*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
11839485SMikore.Li@Sun.COM 		goto fail;
1184*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK, 0);
11859485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
11869485SMikore.Li@Sun.COM fail:
11879485SMikore.Li@Sun.COM 	return (error);
11889485SMikore.Li@Sun.COM }
11899485SMikore.Li@Sun.COM 
11909485SMikore.Li@Sun.COM static usbd_status
11919485SMikore.Li@Sun.COM urtw_eprom_cs(struct urtw_softc *sc, int able)
11929485SMikore.Li@Sun.COM {
11939485SMikore.Li@Sun.COM 	uint8_t data;
11949485SMikore.Li@Sun.COM 	usbd_status error;
11959485SMikore.Li@Sun.COM 
1196*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
11979485SMikore.Li@Sun.COM 		goto fail;
11989485SMikore.Li@Sun.COM 	if (able == URTW_EPROM_ENABLE)
11999485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1200*10364SMikore.Li@Sun.COM 		    data | URTW_EPROM_CS, 0);
12019485SMikore.Li@Sun.COM 	else
12029485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
1203*10364SMikore.Li@Sun.COM 		    data & ~URTW_EPROM_CS, 0);
12049485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
12059485SMikore.Li@Sun.COM fail:
12069485SMikore.Li@Sun.COM 	return (error);
12079485SMikore.Li@Sun.COM }
12089485SMikore.Li@Sun.COM 
12099485SMikore.Li@Sun.COM static usbd_status
1210*10364SMikore.Li@Sun.COM urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data, uint8_t idx)
12119485SMikore.Li@Sun.COM {
12129485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
12139485SMikore.Li@Sun.COM 	usb_cr_t cr;
12149485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
12159485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
12169485SMikore.Li@Sun.COM 	usbd_status error;
12179485SMikore.Li@Sun.COM 
12189485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
12199485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
12209485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
12219485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1222*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
12239485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
12249485SMikore.Li@Sun.COM 
12259485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
12269485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
12279485SMikore.Li@Sun.COM 
12289485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
12299485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
12309485SMikore.Li@Sun.COM 		    "urtw_read8_c: get regs req failed :"
12319485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
12329485SMikore.Li@Sun.COM 		return (error);
12339485SMikore.Li@Sun.COM 	}
12349485SMikore.Li@Sun.COM 	bcopy(mp->b_rptr, data, sizeof (uint8_t));
12359485SMikore.Li@Sun.COM 	if (mp)
12369485SMikore.Li@Sun.COM 		freemsg(mp);
12379485SMikore.Li@Sun.COM 	return (error);
12389485SMikore.Li@Sun.COM }
12399485SMikore.Li@Sun.COM 
12409485SMikore.Li@Sun.COM static usbd_status
12419485SMikore.Li@Sun.COM urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
12429485SMikore.Li@Sun.COM {
12439485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
12449485SMikore.Li@Sun.COM 	usb_cr_t cr;
12459485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
12469485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
12479485SMikore.Li@Sun.COM 	usbd_status error;
12489485SMikore.Li@Sun.COM 
12499485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
12509485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
12519485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
12529485SMikore.Li@Sun.COM 	req.wValue = val | 0xfe00;
12539485SMikore.Li@Sun.COM 	req.wIndex = 0;
12549485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
12559485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
12569485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
12579485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
12589485SMikore.Li@Sun.COM 
12599485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
12609485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
12619485SMikore.Li@Sun.COM 		    "urtw_read8e: get regs req failed :"
12629485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
12639485SMikore.Li@Sun.COM 		return (error);
12649485SMikore.Li@Sun.COM 	}
12659485SMikore.Li@Sun.COM 
12669485SMikore.Li@Sun.COM 	if (mp) {
12679485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint8_t));
12689485SMikore.Li@Sun.COM 		freemsg(mp);
12699485SMikore.Li@Sun.COM 	}
12709485SMikore.Li@Sun.COM 	return (error);
12719485SMikore.Li@Sun.COM }
12729485SMikore.Li@Sun.COM 
12739485SMikore.Li@Sun.COM static usbd_status
1274*10364SMikore.Li@Sun.COM urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data, uint8_t idx)
12759485SMikore.Li@Sun.COM {
12769485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
12779485SMikore.Li@Sun.COM 	usb_cr_t cr;
12789485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
12799485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
12809485SMikore.Li@Sun.COM 	usbd_status error;
12819485SMikore.Li@Sun.COM 
12829485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
12839485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
12849485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
12859485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1286*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
12879485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
12889485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
12899485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
12909485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
12919485SMikore.Li@Sun.COM 
12929485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
12939485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
12949485SMikore.Li@Sun.COM 		    "urtw_read16_c: get regs req failed :"
12959485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n",
12969485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
12979485SMikore.Li@Sun.COM 		return (error);
12989485SMikore.Li@Sun.COM 	}
12999485SMikore.Li@Sun.COM 	if (mp) {
13009485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint16_t));
13019485SMikore.Li@Sun.COM 		freemsg(mp);
13029485SMikore.Li@Sun.COM 	}
13039485SMikore.Li@Sun.COM 	return (error);
13049485SMikore.Li@Sun.COM }
13059485SMikore.Li@Sun.COM 
13069485SMikore.Li@Sun.COM static usbd_status
1307*10364SMikore.Li@Sun.COM urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data, uint8_t idx)
13089485SMikore.Li@Sun.COM {
13099485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
13109485SMikore.Li@Sun.COM 	usb_cr_t cr;
13119485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
13129485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
13139485SMikore.Li@Sun.COM 	usbd_status error;
13149485SMikore.Li@Sun.COM 
13159485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
13169485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
13179485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
13189485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1319*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
13209485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint32_t);
13219485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
13229485SMikore.Li@Sun.COM 
13239485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
13249485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
13259485SMikore.Li@Sun.COM 
13269485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
13279485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
13289485SMikore.Li@Sun.COM 		    "urtw_read32_c: get regs req failed :"
13299485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
13309485SMikore.Li@Sun.COM 		return (error);
13319485SMikore.Li@Sun.COM 	}
13329485SMikore.Li@Sun.COM 
13339485SMikore.Li@Sun.COM 	if (mp) {
13349485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint32_t));
13359485SMikore.Li@Sun.COM 		freemsg(mp);
13369485SMikore.Li@Sun.COM 	}
13379485SMikore.Li@Sun.COM 	return (error);
13389485SMikore.Li@Sun.COM }
13399485SMikore.Li@Sun.COM 
13409485SMikore.Li@Sun.COM static usbd_status
1341*10364SMikore.Li@Sun.COM urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data, uint8_t idx)
13429485SMikore.Li@Sun.COM {
13439485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
13449485SMikore.Li@Sun.COM 	usb_cr_t cr;
13459485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
13469485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
13479485SMikore.Li@Sun.COM 	int error;
13489485SMikore.Li@Sun.COM 
13499485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
13509485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
13519485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
13529485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1353*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
13549485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
13559485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
13569485SMikore.Li@Sun.COM 
13579485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint32_t), BPRI_MED);
13589485SMikore.Li@Sun.COM 	if (mp == NULL) {
13599485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write8_c: failed alloc mblk.");
13609485SMikore.Li@Sun.COM 		return (-1);
13619485SMikore.Li@Sun.COM 	}
13629485SMikore.Li@Sun.COM 	*(uint8_t *)(mp->b_rptr) = data;
13639485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint8_t);
13649485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
13659485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
13669485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
13679485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
13689485SMikore.Li@Sun.COM 		    "urtw_write8_c: could not set regs:"
13699485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
13709485SMikore.Li@Sun.COM 	}
13719485SMikore.Li@Sun.COM 	if (mp)
13729485SMikore.Li@Sun.COM 		freemsg(mp);
13739485SMikore.Li@Sun.COM 	return (error);
13749485SMikore.Li@Sun.COM }
13759485SMikore.Li@Sun.COM 
13769485SMikore.Li@Sun.COM static usbd_status
13779485SMikore.Li@Sun.COM urtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
13789485SMikore.Li@Sun.COM {
13799485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
13809485SMikore.Li@Sun.COM 	usb_cr_t cr;
13819485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
13829485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
13839485SMikore.Li@Sun.COM 	int error;
13849485SMikore.Li@Sun.COM 
13859485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
13869485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
13879485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
13889485SMikore.Li@Sun.COM 	req.wValue = val | 0xfe00;
13899485SMikore.Li@Sun.COM 	req.wIndex = 0;
13909485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
13919485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
13929485SMikore.Li@Sun.COM 
13939485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint8_t), BPRI_MED);
13949485SMikore.Li@Sun.COM 	if (mp == NULL) {
13959485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write8e: failed alloc mblk.");
13969485SMikore.Li@Sun.COM 		return (-1);
13979485SMikore.Li@Sun.COM 	}
13989485SMikore.Li@Sun.COM 	*(mp->b_rptr) = data;
13999485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint8_t);
14009485SMikore.Li@Sun.COM 
14019485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
14029485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
14039485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
14049485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
14059485SMikore.Li@Sun.COM 		    "urtw_write8e: could not set regs:"
14069485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
14079485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
14089485SMikore.Li@Sun.COM 	}
14099485SMikore.Li@Sun.COM 	if (mp)
14109485SMikore.Li@Sun.COM 		freemsg(mp);
14119485SMikore.Li@Sun.COM 	return (error);
14129485SMikore.Li@Sun.COM }
14139485SMikore.Li@Sun.COM 
14149485SMikore.Li@Sun.COM static usbd_status
1415*10364SMikore.Li@Sun.COM urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data, uint8_t idx)
14169485SMikore.Li@Sun.COM {
14179485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
14189485SMikore.Li@Sun.COM 	usb_cr_t cr;
14199485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
14209485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
14219485SMikore.Li@Sun.COM 	int error;
14229485SMikore.Li@Sun.COM 
14239485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
14249485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
14259485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
14269485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1427*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
14289485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
14299485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
14309485SMikore.Li@Sun.COM 
14319485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint16_t), BPRI_MED);
14329485SMikore.Li@Sun.COM 	if (mp == NULL) {
14339485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write16_c: failed alloc mblk.");
14349485SMikore.Li@Sun.COM 		return (-1);
14359485SMikore.Li@Sun.COM 	}
14369485SMikore.Li@Sun.COM 	*(uint16_t *)(uintptr_t)(mp->b_rptr) = data;
14379485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint16_t);
14389485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
14399485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
14409485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
14419485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
14429485SMikore.Li@Sun.COM 		    "urtw_write16_c: could not set regs:"
14439485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
14449485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
14459485SMikore.Li@Sun.COM 	}
14469485SMikore.Li@Sun.COM 	if (mp)
14479485SMikore.Li@Sun.COM 		freemsg(mp);
14489485SMikore.Li@Sun.COM 	return (error);
14499485SMikore.Li@Sun.COM }
14509485SMikore.Li@Sun.COM 
14519485SMikore.Li@Sun.COM static usbd_status
1452*10364SMikore.Li@Sun.COM urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data, uint8_t idx)
14539485SMikore.Li@Sun.COM {
14549485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
14559485SMikore.Li@Sun.COM 	usb_cr_t cr;
14569485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
14579485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
14589485SMikore.Li@Sun.COM 	int error;
14599485SMikore.Li@Sun.COM 
14609485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
14619485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
14629485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
14639485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1464*10364SMikore.Li@Sun.COM 	req.wIndex = idx & 0x03;
14659485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint32_t);
14669485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
14679485SMikore.Li@Sun.COM 
14689485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint32_t), BPRI_MED);
14699485SMikore.Li@Sun.COM 	if (mp == NULL) {
14709485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write32_c: failed alloc mblk.");
14719485SMikore.Li@Sun.COM 		return (-1);
14729485SMikore.Li@Sun.COM 	}
14739485SMikore.Li@Sun.COM 	*(uint32_t *)(uintptr_t)(mp->b_rptr) = data;
14749485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint32_t);
14759485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
14769485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
14779485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
14789485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
14799485SMikore.Li@Sun.COM 		    "urtw_write32_c: could not set regs:"
14809485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
14819485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
14829485SMikore.Li@Sun.COM 	}
14839485SMikore.Li@Sun.COM 
14849485SMikore.Li@Sun.COM 	if (mp)
14859485SMikore.Li@Sun.COM 		freemsg(mp);
14869485SMikore.Li@Sun.COM 	return (error);
14879485SMikore.Li@Sun.COM }
14889485SMikore.Li@Sun.COM 
14899485SMikore.Li@Sun.COM static usbd_status
14909485SMikore.Li@Sun.COM urtw_set_mode(struct urtw_softc *sc, uint32_t mode)
14919485SMikore.Li@Sun.COM {
14929485SMikore.Li@Sun.COM 	uint8_t data;
14939485SMikore.Li@Sun.COM 	usbd_status error;
14949485SMikore.Li@Sun.COM 
1495*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data, 0))
14969485SMikore.Li@Sun.COM 		goto fail;
14979485SMikore.Li@Sun.COM 	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
14989485SMikore.Li@Sun.COM 	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
1499*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data, 0);
15009485SMikore.Li@Sun.COM fail:
15019485SMikore.Li@Sun.COM 	return (error);
15029485SMikore.Li@Sun.COM }
15039485SMikore.Li@Sun.COM 
15049485SMikore.Li@Sun.COM static usbd_status
15059485SMikore.Li@Sun.COM urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
15069485SMikore.Li@Sun.COM {
15079485SMikore.Li@Sun.COM 	uint8_t data;
15089485SMikore.Li@Sun.COM 	usbd_status error;
15099485SMikore.Li@Sun.COM 
15109485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
15119485SMikore.Li@Sun.COM 	if (error)
15129485SMikore.Li@Sun.COM 		goto fail;
15139485SMikore.Li@Sun.COM 
1514*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
15159485SMikore.Li@Sun.COM 		goto fail;
15169485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1517*10364SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0))
15189485SMikore.Li@Sun.COM 		goto fail;
1519*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_ANAPARAM, val, 0))
15209485SMikore.Li@Sun.COM 		goto fail;
1521*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
15229485SMikore.Li@Sun.COM 		goto fail;
15239485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1524*10364SMikore.Li@Sun.COM 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0))
15259485SMikore.Li@Sun.COM 		goto fail;
15269485SMikore.Li@Sun.COM 
15279485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
15289485SMikore.Li@Sun.COM 	if (error)
15299485SMikore.Li@Sun.COM 		goto fail;
15309485SMikore.Li@Sun.COM fail:
15319485SMikore.Li@Sun.COM 	return (error);
15329485SMikore.Li@Sun.COM }
15339485SMikore.Li@Sun.COM 
15349485SMikore.Li@Sun.COM static usbd_status
15359485SMikore.Li@Sun.COM urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
15369485SMikore.Li@Sun.COM {
15379485SMikore.Li@Sun.COM 	uint8_t data;
15389485SMikore.Li@Sun.COM 	usbd_status error;
15399485SMikore.Li@Sun.COM 
15409485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
15419485SMikore.Li@Sun.COM 	if (error)
15429485SMikore.Li@Sun.COM 		goto fail;
15439485SMikore.Li@Sun.COM 
1544*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
15459485SMikore.Li@Sun.COM 		goto fail;
15469485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1547*10364SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0))
15489485SMikore.Li@Sun.COM 		goto fail;
1549*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_ANAPARAM2, val, 0))
15509485SMikore.Li@Sun.COM 		goto fail;
1551*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data, 0))
15529485SMikore.Li@Sun.COM 		goto fail;
15539485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1554*10364SMikore.Li@Sun.COM 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0))
15559485SMikore.Li@Sun.COM 		goto fail;
15569485SMikore.Li@Sun.COM 
15579485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
15589485SMikore.Li@Sun.COM 	if (error)
15599485SMikore.Li@Sun.COM 		goto fail;
15609485SMikore.Li@Sun.COM fail:
15619485SMikore.Li@Sun.COM 	return (error);
15629485SMikore.Li@Sun.COM }
15639485SMikore.Li@Sun.COM 
15649485SMikore.Li@Sun.COM static usbd_status
15659485SMikore.Li@Sun.COM urtw_intr_disable(struct urtw_softc *sc)
15669485SMikore.Li@Sun.COM {
15679485SMikore.Li@Sun.COM 	usbd_status error;
15689485SMikore.Li@Sun.COM 
1569*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0, 0);
15709485SMikore.Li@Sun.COM 	return (error);
15719485SMikore.Li@Sun.COM }
15729485SMikore.Li@Sun.COM 
15739485SMikore.Li@Sun.COM static usbd_status
1574*10364SMikore.Li@Sun.COM urtw_8187_reset(struct urtw_softc *sc)
15759485SMikore.Li@Sun.COM {
15769485SMikore.Li@Sun.COM 	uint8_t data;
15779485SMikore.Li@Sun.COM 	usbd_status error;
15789485SMikore.Li@Sun.COM 
1579*10364SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
15809485SMikore.Li@Sun.COM 	if (error)
15819485SMikore.Li@Sun.COM 		goto fail;
1582*10364SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
15839485SMikore.Li@Sun.COM 	if (error)
15849485SMikore.Li@Sun.COM 		goto fail;
15859485SMikore.Li@Sun.COM 
15869485SMikore.Li@Sun.COM 	error = urtw_intr_disable(sc);
15879485SMikore.Li@Sun.COM 	if (error)
15889485SMikore.Li@Sun.COM 		goto fail;
15899485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
15909485SMikore.Li@Sun.COM 
15919485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x10);
15929485SMikore.Li@Sun.COM 	if (error != 0)
15939485SMikore.Li@Sun.COM 		goto fail;
15949485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x11);
15959485SMikore.Li@Sun.COM 	if (error != 0)
15969485SMikore.Li@Sun.COM 		goto fail;
15979485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x00);
15989485SMikore.Li@Sun.COM 	if (error != 0)
15999485SMikore.Li@Sun.COM 		goto fail;
16009485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
16019485SMikore.Li@Sun.COM 
1602*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
16039485SMikore.Li@Sun.COM 		goto fail;
16049485SMikore.Li@Sun.COM 	data = (data & 2) | URTW_CMD_RST;
1605*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CMD, data, 0))
16069485SMikore.Li@Sun.COM 		goto fail;
16079485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
16089485SMikore.Li@Sun.COM 
1609*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
16109485SMikore.Li@Sun.COM 		goto fail;
16119485SMikore.Li@Sun.COM 	if (data & URTW_CMD_RST) {
16129485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw reset timeout\n");
16139485SMikore.Li@Sun.COM 		goto fail;
16149485SMikore.Li@Sun.COM 	}
16159485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
16169485SMikore.Li@Sun.COM 	if (error)
16179485SMikore.Li@Sun.COM 		goto fail;
16189485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
16199485SMikore.Li@Sun.COM 
1620*10364SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
16219485SMikore.Li@Sun.COM 	if (error)
16229485SMikore.Li@Sun.COM 		goto fail;
1623*10364SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
16249485SMikore.Li@Sun.COM 	if (error)
16259485SMikore.Li@Sun.COM 		goto fail;
16269485SMikore.Li@Sun.COM fail:
16279485SMikore.Li@Sun.COM 	return (error);
16289485SMikore.Li@Sun.COM }
16299485SMikore.Li@Sun.COM 
16309485SMikore.Li@Sun.COM static usbd_status
16319485SMikore.Li@Sun.COM urtw_led_on(struct urtw_softc *sc, int type)
16329485SMikore.Li@Sun.COM {
16339485SMikore.Li@Sun.COM 	if (type == URTW_LED_GPIO) {
16349485SMikore.Li@Sun.COM 		switch (sc->sc_gpio_ledpin) {
16359485SMikore.Li@Sun.COM 		case URTW_LED_PIN_GPIO0:
1636*10364SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01, 0);
1637*10364SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x00, 0);
16389485SMikore.Li@Sun.COM 			break;
16399485SMikore.Li@Sun.COM 		default:
16409485SMikore.Li@Sun.COM 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
16419485SMikore.Li@Sun.COM 			    sc->sc_gpio_ledpin);
16429485SMikore.Li@Sun.COM 			/* never reach  */
16439485SMikore.Li@Sun.COM 		}
16449485SMikore.Li@Sun.COM 	} else {
16459485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
16469485SMikore.Li@Sun.COM 		/* never reach  */
16479485SMikore.Li@Sun.COM 	}
16489485SMikore.Li@Sun.COM 
16499485SMikore.Li@Sun.COM 	sc->sc_gpio_ledon = 1;
16509485SMikore.Li@Sun.COM 	return (0);
16519485SMikore.Li@Sun.COM }
16529485SMikore.Li@Sun.COM 
16539485SMikore.Li@Sun.COM static usbd_status
16549485SMikore.Li@Sun.COM urtw_led_off(struct urtw_softc *sc, int type)
16559485SMikore.Li@Sun.COM {
16569485SMikore.Li@Sun.COM 	if (type == URTW_LED_GPIO) {
16579485SMikore.Li@Sun.COM 		switch (sc->sc_gpio_ledpin) {
16589485SMikore.Li@Sun.COM 		case URTW_LED_PIN_GPIO0:
1659*10364SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01, 0);
1660*10364SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x01, 0);
16619485SMikore.Li@Sun.COM 			break;
16629485SMikore.Li@Sun.COM 		default:
16639485SMikore.Li@Sun.COM 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
16649485SMikore.Li@Sun.COM 			    sc->sc_gpio_ledpin);
16659485SMikore.Li@Sun.COM 			/* never reach  */
16669485SMikore.Li@Sun.COM 		}
16679485SMikore.Li@Sun.COM 	} else {
16689485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
16699485SMikore.Li@Sun.COM 		/* never reach  */
16709485SMikore.Li@Sun.COM 	}
16719485SMikore.Li@Sun.COM 
16729485SMikore.Li@Sun.COM 	sc->sc_gpio_ledon = 0;
16739485SMikore.Li@Sun.COM 	return (0);
16749485SMikore.Li@Sun.COM }
16759485SMikore.Li@Sun.COM 
16769485SMikore.Li@Sun.COM static usbd_status
16779485SMikore.Li@Sun.COM urtw_led_mode0(struct urtw_softc *sc, int mode)
16789485SMikore.Li@Sun.COM {
16799485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
16809485SMikore.Li@Sun.COM 	    "urtw_led_mode0: mode = %d\n", mode));
16819485SMikore.Li@Sun.COM 	switch (mode) {
16829485SMikore.Li@Sun.COM 	case URTW_LED_CTL_POWER_ON:
16839485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
16849485SMikore.Li@Sun.COM 		break;
16859485SMikore.Li@Sun.COM 	case URTW_LED_CTL_TX:
16869485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress == 1)
16879485SMikore.Li@Sun.COM 			return (0);
16889485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
16899485SMikore.Li@Sun.COM 		sc->sc_gpio_blinktime =
16909485SMikore.Li@Sun.COM 		    (sc->sc_ic.ic_state == IEEE80211_S_RUN ? 4:2);
16919485SMikore.Li@Sun.COM 		break;
16929485SMikore.Li@Sun.COM 	case URTW_LED_CTL_LINK:
16939485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_ON;
16949485SMikore.Li@Sun.COM 		break;
16959485SMikore.Li@Sun.COM 	default:
16969485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "unsupported LED mode 0x%x", mode);
16979485SMikore.Li@Sun.COM 		/* never reach  */
16989485SMikore.Li@Sun.COM 	}
16999485SMikore.Li@Sun.COM 
17009485SMikore.Li@Sun.COM 	switch (sc->sc_gpio_ledstate) {
17019485SMikore.Li@Sun.COM 	case URTW_LED_ON:
17029485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress != 0)
17039485SMikore.Li@Sun.COM 			break;
17049485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
17059485SMikore.Li@Sun.COM 		break;
17069485SMikore.Li@Sun.COM 	case URTW_LED_BLINK_NORMAL:
17079485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress != 0)
17089485SMikore.Li@Sun.COM 			break;
17099485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 1;
17109485SMikore.Li@Sun.COM 		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
17119485SMikore.Li@Sun.COM 		    URTW_LED_OFF : URTW_LED_ON;
17129485SMikore.Li@Sun.COM 		URTW_LEDLOCK(sc);
17139485SMikore.Li@Sun.COM 		if (sc->sc_led_ch == 0) {
17149485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
17159485SMikore.Li@Sun.COM 			    "urtw_led_mode0: restart led timer\n"));
17169485SMikore.Li@Sun.COM 			sc->sc_led_ch = timeout(urtw_led_launch,
17179485SMikore.Li@Sun.COM 			    (void *)sc,
17189485SMikore.Li@Sun.COM 			    drv_usectohz((sc->sc_ic.ic_state ==
17199485SMikore.Li@Sun.COM 			    IEEE80211_S_RUN) ?
17209485SMikore.Li@Sun.COM 			    URTW_LED_LINKON_BLINK :
17219485SMikore.Li@Sun.COM 			    URTW_LED_LINKOFF_BLINK));
17229485SMikore.Li@Sun.COM 			sc->sc_gpio_ledinprogress = 0;
17239485SMikore.Li@Sun.COM 		}
17249485SMikore.Li@Sun.COM 		URTW_LEDUNLOCK(sc);
17259485SMikore.Li@Sun.COM 		break;
17269485SMikore.Li@Sun.COM 	case URTW_LED_POWER_ON_BLINK:
17279485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
17289485SMikore.Li@Sun.COM 		urtw_delay_ms(100);
17299485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
17309485SMikore.Li@Sun.COM 		break;
17319485SMikore.Li@Sun.COM 	default:
17329485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
17339485SMikore.Li@Sun.COM 		    "urtw_led_mode0: unknown LED status 0x%x",
17349485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate));
17359485SMikore.Li@Sun.COM 	}
17369485SMikore.Li@Sun.COM 	return (0);
17379485SMikore.Li@Sun.COM }
17389485SMikore.Li@Sun.COM 
17399485SMikore.Li@Sun.COM static usbd_status
17409485SMikore.Li@Sun.COM urtw_led_mode1(struct urtw_softc *sc, int mode)
17419485SMikore.Li@Sun.COM {
17429485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
17439485SMikore.Li@Sun.COM 	return (USBD_INVAL);
17449485SMikore.Li@Sun.COM }
17459485SMikore.Li@Sun.COM 
17469485SMikore.Li@Sun.COM static usbd_status
17479485SMikore.Li@Sun.COM urtw_led_mode2(struct urtw_softc *sc, int mode)
17489485SMikore.Li@Sun.COM {
17499485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
17509485SMikore.Li@Sun.COM 	return (USBD_INVAL);
17519485SMikore.Li@Sun.COM }
17529485SMikore.Li@Sun.COM 
17539485SMikore.Li@Sun.COM static usbd_status
17549485SMikore.Li@Sun.COM urtw_led_mode3(struct urtw_softc *sc, int mode)
17559485SMikore.Li@Sun.COM {
17569485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
17579485SMikore.Li@Sun.COM 	return (USBD_INVAL);
17589485SMikore.Li@Sun.COM }
17599485SMikore.Li@Sun.COM 
17609485SMikore.Li@Sun.COM static usbd_status
17619485SMikore.Li@Sun.COM urtw_led_blink(struct urtw_softc *sc)
17629485SMikore.Li@Sun.COM {
17639485SMikore.Li@Sun.COM 	uint8_t ing = 0;
17649485SMikore.Li@Sun.COM 
17659485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
17669485SMikore.Li@Sun.COM 	    "urtw_led_blink: gpio_blinkstate %d\n",
17679485SMikore.Li@Sun.COM 	    sc->sc_gpio_blinkstate));
17689485SMikore.Li@Sun.COM 	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
17699485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
17709485SMikore.Li@Sun.COM 	else
17719485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
17729485SMikore.Li@Sun.COM 	sc->sc_gpio_blinktime--;
17739485SMikore.Li@Sun.COM 	if (sc->sc_gpio_blinktime == 0)
17749485SMikore.Li@Sun.COM 		ing = 1;
17759485SMikore.Li@Sun.COM 	else {
17769485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
17779485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
17789485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
17799485SMikore.Li@Sun.COM 			ing = 1;
17809485SMikore.Li@Sun.COM 	}
17819485SMikore.Li@Sun.COM 	if (ing == 1) {
17829485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
17839485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledon == 0)
17849485SMikore.Li@Sun.COM 			(void) urtw_led_on(sc, URTW_LED_GPIO);
17859485SMikore.Li@Sun.COM 		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
17869485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledon == 1)
17879485SMikore.Li@Sun.COM 			(void) urtw_led_off(sc, URTW_LED_GPIO);
17889485SMikore.Li@Sun.COM 
17899485SMikore.Li@Sun.COM 		sc->sc_gpio_blinktime = 0;
17909485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 0;
17919485SMikore.Li@Sun.COM 		return (0);
17929485SMikore.Li@Sun.COM 	}
17939485SMikore.Li@Sun.COM 
17949485SMikore.Li@Sun.COM 	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
17959485SMikore.Li@Sun.COM 	    URTW_LED_ON : URTW_LED_OFF;
17969485SMikore.Li@Sun.COM 
17979485SMikore.Li@Sun.COM 	switch (sc->sc_gpio_ledstate) {
17989485SMikore.Li@Sun.COM 	case URTW_LED_BLINK_NORMAL:
17999485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
18009485SMikore.Li@Sun.COM 		    "URTW_LED_BLINK_NORMAL\n"));
18019485SMikore.Li@Sun.COM 		return (1);
18029485SMikore.Li@Sun.COM 	default:
18039485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
18049485SMikore.Li@Sun.COM 		    "unknown LED status 0x%x", sc->sc_gpio_ledstate));
18059485SMikore.Li@Sun.COM 	}
18069485SMikore.Li@Sun.COM 	return (0);
18079485SMikore.Li@Sun.COM }
18089485SMikore.Li@Sun.COM 
18099485SMikore.Li@Sun.COM static usbd_status
18109485SMikore.Li@Sun.COM urtw_led_ctl(struct urtw_softc *sc, int mode)
18119485SMikore.Li@Sun.COM {
18129485SMikore.Li@Sun.COM 	usbd_status error = 0;
18139485SMikore.Li@Sun.COM 
18149485SMikore.Li@Sun.COM 	switch (sc->sc_strategy) {
18159485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE0:
18169485SMikore.Li@Sun.COM 		error = urtw_led_mode0(sc, mode);
18179485SMikore.Li@Sun.COM 		break;
18189485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE1:
18199485SMikore.Li@Sun.COM 		error = urtw_led_mode1(sc, mode);
18209485SMikore.Li@Sun.COM 		break;
18219485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE2:
18229485SMikore.Li@Sun.COM 		error = urtw_led_mode2(sc, mode);
18239485SMikore.Li@Sun.COM 		break;
18249485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE3:
18259485SMikore.Li@Sun.COM 		error = urtw_led_mode3(sc, mode);
18269485SMikore.Li@Sun.COM 		break;
18279485SMikore.Li@Sun.COM 	default:
18289485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "unsupported LED mode %d\n", sc->sc_strategy);
18299485SMikore.Li@Sun.COM 		/* never reach  */
18309485SMikore.Li@Sun.COM 		return (-1);
18319485SMikore.Li@Sun.COM 	}
18329485SMikore.Li@Sun.COM 
18339485SMikore.Li@Sun.COM 	return (error);
18349485SMikore.Li@Sun.COM }
18359485SMikore.Li@Sun.COM 
18369485SMikore.Li@Sun.COM static usbd_status
18379485SMikore.Li@Sun.COM urtw_update_msr(struct urtw_softc *sc, int nstate)
18389485SMikore.Li@Sun.COM {
18399485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
18409485SMikore.Li@Sun.COM 	uint8_t data;
18419485SMikore.Li@Sun.COM 	usbd_status error;
18429485SMikore.Li@Sun.COM 
1843*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_MSR, &data, 0))
18449485SMikore.Li@Sun.COM 		goto fail;
18459485SMikore.Li@Sun.COM 	data &= ~URTW_MSR_LINK_MASK;
18469485SMikore.Li@Sun.COM 
1847*10364SMikore.Li@Sun.COM 	/* Should always be set. */
1848*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187B)
1849*10364SMikore.Li@Sun.COM 		data |= URTW_MSR_LINK_ENEDCA;
1850*10364SMikore.Li@Sun.COM 
18519485SMikore.Li@Sun.COM 	if (nstate == IEEE80211_S_RUN) {
18529485SMikore.Li@Sun.COM 		switch (ic->ic_opmode) {
18539485SMikore.Li@Sun.COM 		case IEEE80211_M_STA:
18549485SMikore.Li@Sun.COM 		case IEEE80211_M_MONITOR:
18559485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_STA;
18569485SMikore.Li@Sun.COM 			break;
18579485SMikore.Li@Sun.COM 		case IEEE80211_M_IBSS:
18589485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_ADHOC;
18599485SMikore.Li@Sun.COM 			break;
18609485SMikore.Li@Sun.COM 		case IEEE80211_M_HOSTAP:
18619485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_HOSTAP;
18629485SMikore.Li@Sun.COM 			break;
18639485SMikore.Li@Sun.COM 		default:
18649485SMikore.Li@Sun.COM 			cmn_err(CE_CONT, "unsupported operation mode 0x%x\n",
18659485SMikore.Li@Sun.COM 			    ic->ic_opmode);
18669485SMikore.Li@Sun.COM 			return (-1);
18679485SMikore.Li@Sun.COM 		}
18689485SMikore.Li@Sun.COM 	} else
18699485SMikore.Li@Sun.COM 		data |= URTW_MSR_LINK_NONE;
18709485SMikore.Li@Sun.COM 
1871*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_MSR, data, 0);
18729485SMikore.Li@Sun.COM fail:
18739485SMikore.Li@Sun.COM 	return (error);
18749485SMikore.Li@Sun.COM }
18759485SMikore.Li@Sun.COM 
18769485SMikore.Li@Sun.COM static uint16_t
18779485SMikore.Li@Sun.COM urtw_rate2rtl(int rate)
18789485SMikore.Li@Sun.COM {
18799485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
18809485SMikore.Li@Sun.COM 	int i;
18819485SMikore.Li@Sun.COM 
18829485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_ratetable); i++) {
18839485SMikore.Li@Sun.COM 		if (rate == urtw_ratetable[i].reg)
18849485SMikore.Li@Sun.COM 			return (urtw_ratetable[i].val);
18859485SMikore.Li@Sun.COM 	}
18869485SMikore.Li@Sun.COM 	return (3);
18879485SMikore.Li@Sun.COM #undef N
18889485SMikore.Li@Sun.COM }
18899485SMikore.Li@Sun.COM 
18909485SMikore.Li@Sun.COM static uint16_t
18919485SMikore.Li@Sun.COM urtw_rtl2rate(int rate)
18929485SMikore.Li@Sun.COM {
18939485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
18949485SMikore.Li@Sun.COM 	int i;
18959485SMikore.Li@Sun.COM 
18969485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_ratetable); i++) {
18979485SMikore.Li@Sun.COM 		if (rate == urtw_ratetable[i].val)
18989485SMikore.Li@Sun.COM 			return (urtw_ratetable[i].reg);
18999485SMikore.Li@Sun.COM 	}
19009485SMikore.Li@Sun.COM 
19019485SMikore.Li@Sun.COM 	return (0);
19029485SMikore.Li@Sun.COM #undef N
19039485SMikore.Li@Sun.COM }
19049485SMikore.Li@Sun.COM 
19059485SMikore.Li@Sun.COM static usbd_status
19069485SMikore.Li@Sun.COM urtw_set_rate(struct urtw_softc *sc)
19079485SMikore.Li@Sun.COM {
19089485SMikore.Li@Sun.COM 	int i, basic_rate, min_rr_rate, max_rr_rate;
19099485SMikore.Li@Sun.COM 	uint16_t data;
19109485SMikore.Li@Sun.COM 	usbd_status error;
19119485SMikore.Li@Sun.COM 
19129485SMikore.Li@Sun.COM 	basic_rate = urtw_rate2rtl(48);
19139485SMikore.Li@Sun.COM 	min_rr_rate = urtw_rate2rtl(12);
19149485SMikore.Li@Sun.COM 	max_rr_rate = urtw_rate2rtl(48);
19159485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RESP_RATE,
19169485SMikore.Li@Sun.COM 	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
1917*10364SMikore.Li@Sun.COM 	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT, 0))
19189485SMikore.Li@Sun.COM 		goto fail;
19199485SMikore.Li@Sun.COM 
1920*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
19219485SMikore.Li@Sun.COM 		goto fail;
19229485SMikore.Li@Sun.COM 	data &= ~URTW_BRSR_MBR_8185;
19239485SMikore.Li@Sun.COM 
19249485SMikore.Li@Sun.COM 	for (i = 0; i <= basic_rate; i++)
19259485SMikore.Li@Sun.COM 		data |= (1 << i);
19269485SMikore.Li@Sun.COM 
1927*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_BRSR, data, 0);
19289485SMikore.Li@Sun.COM fail:
19299485SMikore.Li@Sun.COM 	return (error);
19309485SMikore.Li@Sun.COM }
19319485SMikore.Li@Sun.COM 
19329485SMikore.Li@Sun.COM static usbd_status
19339485SMikore.Li@Sun.COM urtw_intr_enable(struct urtw_softc *sc)
19349485SMikore.Li@Sun.COM {
19359485SMikore.Li@Sun.COM 	usbd_status error;
19369485SMikore.Li@Sun.COM 
1937*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0xffff, 0);
19389485SMikore.Li@Sun.COM 	return (error);
19399485SMikore.Li@Sun.COM }
19409485SMikore.Li@Sun.COM 
19419485SMikore.Li@Sun.COM static usbd_status
19429485SMikore.Li@Sun.COM urtw_rx_setconf(struct urtw_softc *sc)
19439485SMikore.Li@Sun.COM {
19449485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
19459485SMikore.Li@Sun.COM 	uint32_t data, a, b;
19469485SMikore.Li@Sun.COM 	usbd_status error;
19479485SMikore.Li@Sun.COM 
1948*10364SMikore.Li@Sun.COM 	if (urtw_read32_c(sc, URTW_RX, &data, 0))
19499485SMikore.Li@Sun.COM 		goto fail;
19509485SMikore.Li@Sun.COM 	data = data &~ URTW_RX_FILTER_MASK;
19519485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
19529485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
19539485SMikore.Li@Sun.COM 
19549485SMikore.Li@Sun.COM 	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
19559485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_ICVERR;
19569485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_PWR;
19579485SMikore.Li@Sun.COM 	}
19589485SMikore.Li@Sun.COM 	if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
19599485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_CRCERR;
19609485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_NICMAC;
19619485SMikore.Li@Sun.COM 	data = data | URTW_RX_CHECK_BSSID;
19629485SMikore.Li@Sun.COM 	data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
19639485SMikore.Li@Sun.COM 	data = data | URTW_RX_FIFO_THRESHOLD_NONE | URTW_RX_AUTORESETPHY;
19649485SMikore.Li@Sun.COM 	data = data &~ URTW_MAX_RX_DMA_MASK;
19659485SMikore.Li@Sun.COM 	a = URTW_MAX_RX_DMA_2048;
19669485SMikore.Li@Sun.COM 	b = 0x80000000;
19679485SMikore.Li@Sun.COM 	data = data | a | b;
19689485SMikore.Li@Sun.COM 
1969*10364SMikore.Li@Sun.COM 	error = urtw_write32_c(sc, URTW_RX, data, 0);
19709485SMikore.Li@Sun.COM fail:
19719485SMikore.Li@Sun.COM 	return (error);
19729485SMikore.Li@Sun.COM }
19739485SMikore.Li@Sun.COM 
19749485SMikore.Li@Sun.COM static usbd_status
19759485SMikore.Li@Sun.COM urtw_rx_enable(struct urtw_softc *sc)
19769485SMikore.Li@Sun.COM {
19779485SMikore.Li@Sun.COM 	int i;
19789485SMikore.Li@Sun.COM 	usbd_status error;
19799485SMikore.Li@Sun.COM 	uint8_t data;
19809485SMikore.Li@Sun.COM 
19819485SMikore.Li@Sun.COM 	sc->rx_queued = 0;
19829485SMikore.Li@Sun.COM 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
19839485SMikore.Li@Sun.COM 		if (urtw_rx_start(sc) != 0) {
19849485SMikore.Li@Sun.COM 			return (USB_FAILURE);
19859485SMikore.Li@Sun.COM 		}
19869485SMikore.Li@Sun.COM 	}
19879485SMikore.Li@Sun.COM 
19889485SMikore.Li@Sun.COM 	error = urtw_rx_setconf(sc);
19899485SMikore.Li@Sun.COM 	if (error != 0)
19909485SMikore.Li@Sun.COM 		goto fail;
19919485SMikore.Li@Sun.COM 
1992*10364SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data, 0))
19939485SMikore.Li@Sun.COM 		goto fail;
1994*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE, 0);
19959485SMikore.Li@Sun.COM fail:
19969485SMikore.Li@Sun.COM 	return (error);
19979485SMikore.Li@Sun.COM }
19989485SMikore.Li@Sun.COM 
1999*10364SMikore.Li@Sun.COM void
20009485SMikore.Li@Sun.COM urtw_tx_enable(struct urtw_softc *sc)
20019485SMikore.Li@Sun.COM {
20029485SMikore.Li@Sun.COM 	uint8_t data8;
20039485SMikore.Li@Sun.COM 	uint32_t data;
2004*10364SMikore.Li@Sun.COM 
2005*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
2006*10364SMikore.Li@Sun.COM 		(void) urtw_read8_c(sc, URTW_CW_CONF, &data8, 0);
2007*10364SMikore.Li@Sun.COM 		data8 &= ~(URTW_CW_CONF_PERPACKET_CW |
2008*10364SMikore.Li@Sun.COM 		    URTW_CW_CONF_PERPACKET_RETRY);
2009*10364SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, URTW_CW_CONF, data8, 0);
2010*10364SMikore.Li@Sun.COM 		(void) urtw_read8_c(sc, URTW_TX_AGC_CTL, &data8, 0);
2011*10364SMikore.Li@Sun.COM 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
2012*10364SMikore.Li@Sun.COM 		data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
2013*10364SMikore.Li@Sun.COM 		data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
2014*10364SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, URTW_TX_AGC_CTL, data8, 0);
2015*10364SMikore.Li@Sun.COM 
2016*10364SMikore.Li@Sun.COM 		(void) urtw_read32_c(sc, URTW_TX_CONF, &data, 0);
2017*10364SMikore.Li@Sun.COM 		data &= ~URTW_TX_LOOPBACK_MASK;
2018*10364SMikore.Li@Sun.COM 		data |= URTW_TX_LOOPBACK_NONE;
2019*10364SMikore.Li@Sun.COM 		data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
2020*10364SMikore.Li@Sun.COM 		data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
2021*10364SMikore.Li@Sun.COM 		data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
2022*10364SMikore.Li@Sun.COM 		data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
2023*10364SMikore.Li@Sun.COM 		data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
2024*10364SMikore.Li@Sun.COM 		data &= ~URTW_TX_SWPLCPLEN;
2025*10364SMikore.Li@Sun.COM 		data |= URTW_TX_NOICV;
2026*10364SMikore.Li@Sun.COM 		(void) urtw_write32_c(sc, URTW_TX_CONF, data, 0);
2027*10364SMikore.Li@Sun.COM 	} else {
2028*10364SMikore.Li@Sun.COM 		data = URTW_TX_DURPROCMODE | URTW_TX_DISREQQSIZE |
2029*10364SMikore.Li@Sun.COM 		    URTW_TX_MXDMA_2048 | URTW_TX_SHORTRETRY |
2030*10364SMikore.Li@Sun.COM 		    URTW_TX_LONGRETRY;
2031*10364SMikore.Li@Sun.COM 		(void) urtw_write32_c(sc, URTW_TX_CONF, data, 0);
2032*10364SMikore.Li@Sun.COM 	}
2033*10364SMikore.Li@Sun.COM 
2034*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CMD, &data8, 0);
2035*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE, 0);
20369485SMikore.Li@Sun.COM }
20379485SMikore.Li@Sun.COM 
20389485SMikore.Li@Sun.COM static int
2039*10364SMikore.Li@Sun.COM urtw_8187_init(void *arg)
20409485SMikore.Li@Sun.COM {
20419485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
20429485SMikore.Li@Sun.COM 	usbd_status error;
2043*10364SMikore.Li@Sun.COM 	struct urtw_rf *rf = &sc->sc_rf;
2044*10364SMikore.Li@Sun.COM 	int i;
20459485SMikore.Li@Sun.COM 
20469485SMikore.Li@Sun.COM 	urtw_stop(sc);
20479485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
2048*10364SMikore.Li@Sun.COM 	error = urtw_8187_reset(sc);
2049*10364SMikore.Li@Sun.COM 	if (error)
2050*10364SMikore.Li@Sun.COM 		goto fail;
2051*10364SMikore.Li@Sun.COM 
2052*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x85, 0, 0);
2053*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_GPIO, 0, 0);
2054*10364SMikore.Li@Sun.COM 
2055*10364SMikore.Li@Sun.COM 	/* for led */
2056*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x85, 4, 0);
2057*10364SMikore.Li@Sun.COM 	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
20589485SMikore.Li@Sun.COM 	if (error != 0)
20599485SMikore.Li@Sun.COM 		goto fail;
2060*10364SMikore.Li@Sun.COM 
2061*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2062*10364SMikore.Li@Sun.COM 	if (error)
2063*10364SMikore.Li@Sun.COM 		goto fail;
2064*10364SMikore.Li@Sun.COM 
2065*10364SMikore.Li@Sun.COM 	/* applying MAC address again.  */
2066*10364SMikore.Li@Sun.COM 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
2067*10364SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, URTW_MAC0 + i,
2068*10364SMikore.Li@Sun.COM 		    sc->sc_ic.ic_macaddr[i], 0);
2069*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2070*10364SMikore.Li@Sun.COM 	if (error)
2071*10364SMikore.Li@Sun.COM 		goto fail;
2072*10364SMikore.Li@Sun.COM 
2073*10364SMikore.Li@Sun.COM 	error = urtw_update_msr(sc, IEEE80211_S_INIT);
2074*10364SMikore.Li@Sun.COM 	if (error)
2075*10364SMikore.Li@Sun.COM 		goto fail;
2076*10364SMikore.Li@Sun.COM 
2077*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_INT_TIMEOUT, 0, 0);
2078*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_WPA_CONFIG, 0, 0);
2079*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_RATE_FALLBACK, 0x81, 0);
2080*10364SMikore.Li@Sun.COM 	error = urtw_set_rate(sc);
2081*10364SMikore.Li@Sun.COM 	if (error != 0)
2082*10364SMikore.Li@Sun.COM 		goto fail;
2083*10364SMikore.Li@Sun.COM 
2084*10364SMikore.Li@Sun.COM 	error = rf->init(rf);
2085*10364SMikore.Li@Sun.COM 	if (error != 0)
2086*10364SMikore.Li@Sun.COM 		goto fail;
2087*10364SMikore.Li@Sun.COM 	if (rf->set_sens != NULL)
2088*10364SMikore.Li@Sun.COM 		rf->set_sens(rf);
2089*10364SMikore.Li@Sun.COM 
2090*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x5e, 1, 0);
2091*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0xfe, 0x10, 0);
2092*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TALLY_SEL, 0x80, 0);
2093*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0xff, 0x60, 0);
2094*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x5e, 0, 0);
2095*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x85, 4, 0);
2096*10364SMikore.Li@Sun.COM 
2097*10364SMikore.Li@Sun.COM 	error = urtw_intr_enable(sc);
2098*10364SMikore.Li@Sun.COM 	if (error != 0)
2099*10364SMikore.Li@Sun.COM 		goto fail;
2100*10364SMikore.Li@Sun.COM 
2101*10364SMikore.Li@Sun.COM 	error = urtw_open_pipes(sc);
21029485SMikore.Li@Sun.COM 	if (error != 0)
21039485SMikore.Li@Sun.COM 		goto fail;
21049485SMikore.Li@Sun.COM 	sc->sc_tx_low_queued = 0;
21059485SMikore.Li@Sun.COM 	sc->sc_tx_normal_queued = 0;
21069485SMikore.Li@Sun.COM 	error = urtw_rx_enable(sc);
21079485SMikore.Li@Sun.COM 	if (error != 0)
21089485SMikore.Li@Sun.COM 		goto fail;
2109*10364SMikore.Li@Sun.COM 	urtw_tx_enable(sc);
21109485SMikore.Li@Sun.COM 
21119485SMikore.Li@Sun.COM 	if (error == 0) {
21129485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev,
2113*10364SMikore.Li@Sun.COM 		    CE_CONT, "urtw_8187_init: succesfully done\n"));
21149485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_RUNNING;
21159485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
21169485SMikore.Li@Sun.COM 		return (error);
21179485SMikore.Li@Sun.COM 	}
21189485SMikore.Li@Sun.COM 
21199485SMikore.Li@Sun.COM fail:
21209485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
21219485SMikore.Li@Sun.COM 	urtw_stop(sc);
2122*10364SMikore.Li@Sun.COM 	return (EIO);
21239485SMikore.Li@Sun.COM }
21249485SMikore.Li@Sun.COM 
21259485SMikore.Li@Sun.COM 
21269485SMikore.Li@Sun.COM static usbd_status
21279485SMikore.Li@Sun.COM urtw_8225_usb_init(struct urtw_softc *sc)
21289485SMikore.Li@Sun.COM {
21299485SMikore.Li@Sun.COM 	uint8_t data;
21309485SMikore.Li@Sun.COM 	usbd_status error;
21319485SMikore.Li@Sun.COM 
2132*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 0, 0))
21339485SMikore.Li@Sun.COM 		goto fail;
2134*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GPIO, 0, 0))
21359485SMikore.Li@Sun.COM 		goto fail;
21369485SMikore.Li@Sun.COM 	if (error = urtw_read8e(sc, 0x53, &data))
21379485SMikore.Li@Sun.COM 		goto fail;
21389485SMikore.Li@Sun.COM 	if (error = urtw_write8e(sc, 0x53, data | (1 << 7)))
21399485SMikore.Li@Sun.COM 		goto fail;
2140*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 4, 0))
21419485SMikore.Li@Sun.COM 		goto fail;
2142*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GPIO, 0x20, 0))
21439485SMikore.Li@Sun.COM 		goto fail;
2144*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GP_ENABLE, 0, 0))
21459485SMikore.Li@Sun.COM 		goto fail;
2146*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x80, 0))
21479485SMikore.Li@Sun.COM 		goto fail;
2148*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x80, 0))
21499485SMikore.Li@Sun.COM 		goto fail;
2150*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x80, 0);
21519485SMikore.Li@Sun.COM 
21529485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
21539485SMikore.Li@Sun.COM fail:
21549485SMikore.Li@Sun.COM 	return (error);
21559485SMikore.Li@Sun.COM }
21569485SMikore.Li@Sun.COM 
21579485SMikore.Li@Sun.COM static usbd_status
21589485SMikore.Li@Sun.COM urtw_8185_rf_pins_enable(struct urtw_softc *sc)
21599485SMikore.Li@Sun.COM {
21609485SMikore.Li@Sun.COM 	usbd_status error = 0;
21619485SMikore.Li@Sun.COM 
2162*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x1ff7, 0);
21639485SMikore.Li@Sun.COM 	return (error);
21649485SMikore.Li@Sun.COM }
21659485SMikore.Li@Sun.COM 
21669485SMikore.Li@Sun.COM static usbd_status
21679485SMikore.Li@Sun.COM urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
21689485SMikore.Li@Sun.COM {
21699485SMikore.Li@Sun.COM 	uint32_t phyw;
21709485SMikore.Li@Sun.COM 	usbd_status error;
21719485SMikore.Li@Sun.COM 
21729485SMikore.Li@Sun.COM 	phyw = ((data << 8) | (addr | 0x80));
2173*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7f, ((phyw & 0xff000000) >> 24), 0))
21749485SMikore.Li@Sun.COM 		goto fail;
2175*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7e, ((phyw & 0x00ff0000) >> 16), 0))
2176*10364SMikore.Li@Sun.COM 		goto fail;
2177*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7d, ((phyw & 0x0000ff00) >> 8), 0))
21789485SMikore.Li@Sun.COM 		goto fail;
2179*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, 0x7c, (phyw & 0x000000ff), 0);
2180*10364SMikore.Li@Sun.COM 	/*
2181*10364SMikore.Li@Sun.COM 	 * Delay removed from 8185 to 8187.
2182*10364SMikore.Li@Sun.COM 	 * usbd_delay_ms(sc->sc_udev, 1);
2183*10364SMikore.Li@Sun.COM 	 */
21849485SMikore.Li@Sun.COM fail:
21859485SMikore.Li@Sun.COM 	return (error);
21869485SMikore.Li@Sun.COM }
21879485SMikore.Li@Sun.COM 
21889485SMikore.Li@Sun.COM static usbd_status
21899485SMikore.Li@Sun.COM urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
21909485SMikore.Li@Sun.COM {
21919485SMikore.Li@Sun.COM 	data = data & 0xff;
21929485SMikore.Li@Sun.COM 	return (urtw_8187_write_phy(sc, addr, data));
21939485SMikore.Li@Sun.COM }
21949485SMikore.Li@Sun.COM 
21959485SMikore.Li@Sun.COM static usbd_status
21969485SMikore.Li@Sun.COM urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
21979485SMikore.Li@Sun.COM {
21989485SMikore.Li@Sun.COM 	data = data & 0xff;
21999485SMikore.Li@Sun.COM 	return (urtw_8187_write_phy(sc, addr, (data | 0x10000)));
22009485SMikore.Li@Sun.COM }
22019485SMikore.Li@Sun.COM 
22029485SMikore.Li@Sun.COM static usbd_status
22039485SMikore.Li@Sun.COM urtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
22049485SMikore.Li@Sun.COM {
22059485SMikore.Li@Sun.COM 	usbd_status error;
22069485SMikore.Li@Sun.COM 
22079485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d,
22089485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4]))
22099485SMikore.Li@Sun.COM 		goto fail;
22109485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b,
22119485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 2]))
22129485SMikore.Li@Sun.COM 		goto fail;
22139485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d,
22149485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 3]))
22159485SMikore.Li@Sun.COM 		goto fail;
22169485SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_ofdm_c(sc, 0x23,
22179485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 1]);
22189485SMikore.Li@Sun.COM fail:
22199485SMikore.Li@Sun.COM 	return (error);
22209485SMikore.Li@Sun.COM }
22219485SMikore.Li@Sun.COM 
22229485SMikore.Li@Sun.COM static usbd_status
22239485SMikore.Li@Sun.COM urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
22249485SMikore.Li@Sun.COM {
22259485SMikore.Li@Sun.COM 	int i, idx, set;
22269485SMikore.Li@Sun.COM 	uint8_t *cck_pwltable;
22279485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
22289485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
22299485SMikore.Li@Sun.COM 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
22309485SMikore.Li@Sun.COM 	usbd_status error;
22319485SMikore.Li@Sun.COM 
22329485SMikore.Li@Sun.COM 	cck_pwrlvl_max = 11;
22339485SMikore.Li@Sun.COM 	ofdm_pwrlvl_max = 25;	/* 12 -> 25  */
22349485SMikore.Li@Sun.COM 	ofdm_pwrlvl_min = 10;
22359485SMikore.Li@Sun.COM 
22369485SMikore.Li@Sun.COM 	/* CCK power setting */
22379485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
22389485SMikore.Li@Sun.COM 	    cck_pwrlvl_max : cck_pwrlvl;
22399485SMikore.Li@Sun.COM 	idx = cck_pwrlvl % 6;
22409485SMikore.Li@Sun.COM 	set = cck_pwrlvl / 6;
22419485SMikore.Li@Sun.COM 	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
22429485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_cck;
22439485SMikore.Li@Sun.COM 
22449485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2245*10364SMikore.Li@Sun.COM 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1, 0))
22469485SMikore.Li@Sun.COM 		goto fail;
22479485SMikore.Li@Sun.COM 	for (i = 0; i < 8; i++) {
22489485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
22499485SMikore.Li@Sun.COM 		    cck_pwltable[idx * 8 + i]))
22509485SMikore.Li@Sun.COM 			goto fail;
22519485SMikore.Li@Sun.COM 	}
22529485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
22539485SMikore.Li@Sun.COM 	/* OFDM power setting */
22549485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
22559485SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
22569485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
22579485SMikore.Li@Sun.COM 	idx = ofdm_pwrlvl % 6;
22589485SMikore.Li@Sun.COM 	set = ofdm_pwrlvl / 6;
22599485SMikore.Li@Sun.COM 
2260*10364SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
22619485SMikore.Li@Sun.COM 	if (error)
22629485SMikore.Li@Sun.COM 		goto fail;
22639485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
22649485SMikore.Li@Sun.COM 		goto fail;
22659485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0))
22669485SMikore.Li@Sun.COM 		goto fail;
22679485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0))
22689485SMikore.Li@Sun.COM 		goto fail;
22699485SMikore.Li@Sun.COM 
22709485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2271*10364SMikore.Li@Sun.COM 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1, 0))
22729485SMikore.Li@Sun.COM 		goto fail;
22739485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x5,
22749485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_ofdm[idx]))
22759485SMikore.Li@Sun.COM 		goto fail;
22769485SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_ofdm_c(sc, 0x7,
22779485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_ofdm[idx]);
22789485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
22799485SMikore.Li@Sun.COM fail:
22809485SMikore.Li@Sun.COM 	return (error);
22819485SMikore.Li@Sun.COM }
22829485SMikore.Li@Sun.COM 
22839485SMikore.Li@Sun.COM static usbd_status
22849485SMikore.Li@Sun.COM urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
22859485SMikore.Li@Sun.COM {
22869485SMikore.Li@Sun.COM 	usbd_status error;
22879485SMikore.Li@Sun.COM 
2288*10364SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_TX_ANTENNA, ant, 0);
22899485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
22909485SMikore.Li@Sun.COM 	return (error);
22919485SMikore.Li@Sun.COM }
22929485SMikore.Li@Sun.COM 
22939485SMikore.Li@Sun.COM static usbd_status
2294*10364SMikore.Li@Sun.COM urtw_8225_rf_init(struct urtw_rf *rf)
22959485SMikore.Li@Sun.COM {
22969485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
22979485SMikore.Li@Sun.COM 	int i;
22989485SMikore.Li@Sun.COM 	uint16_t data;
22999485SMikore.Li@Sun.COM 	usbd_status error;
2300*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
2301*10364SMikore.Li@Sun.COM 
2302*10364SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON);
23039485SMikore.Li@Sun.COM 	if (error)
23049485SMikore.Li@Sun.COM 		goto fail;
23059485SMikore.Li@Sun.COM 
23069485SMikore.Li@Sun.COM 	if (error = urtw_8225_usb_init(sc))
23079485SMikore.Li@Sun.COM 		goto fail;
2308*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008, 0))
23099485SMikore.Li@Sun.COM 		goto fail;
2310*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
23119485SMikore.Li@Sun.COM 		goto fail;
2312*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff, 0))
23139485SMikore.Li@Sun.COM 		goto fail;
2314*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044, 0))
23159485SMikore.Li@Sun.COM 		goto fail;
23169485SMikore.Li@Sun.COM 
23179485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
23189485SMikore.Li@Sun.COM 		goto fail;
2319*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44, 0))
23209485SMikore.Li@Sun.COM 		goto fail;
23219485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
23229485SMikore.Li@Sun.COM 		goto fail;
23239485SMikore.Li@Sun.COM 	if (error = urtw_8185_rf_pins_enable(sc))
23249485SMikore.Li@Sun.COM 		goto fail;
23259485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
23269485SMikore.Li@Sun.COM 
23279485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part1); i++) {
23289485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, urtw_8225_rf_part1[i].reg,
23299485SMikore.Li@Sun.COM 		    urtw_8225_rf_part1[i].val))
23309485SMikore.Li@Sun.COM 			goto fail;
23319485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
23329485SMikore.Li@Sun.COM 	}
23339485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
23349485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
23359485SMikore.Li@Sun.COM 		goto fail;
23369485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
23379485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
23389485SMikore.Li@Sun.COM 		goto fail;
23399485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
23409485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x127))
23419485SMikore.Li@Sun.COM 		goto fail;
23429485SMikore.Li@Sun.COM 
23439485SMikore.Li@Sun.COM 	for (i = 0; i < 95; i++) {
23449485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
23459485SMikore.Li@Sun.COM 			goto fail;
23469485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225_rxgain[i]))
23479485SMikore.Li@Sun.COM 			goto fail;
23489485SMikore.Li@Sun.COM 	}
23499485SMikore.Li@Sun.COM 
23509485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x27))
23519485SMikore.Li@Sun.COM 		goto fail;
23529485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x22f))
23539485SMikore.Li@Sun.COM 		goto fail;
23549485SMikore.Li@Sun.COM 
23559485SMikore.Li@Sun.COM 	for (i = 0; i < 128; i++) {
23569485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
23579485SMikore.Li@Sun.COM 		    urtw_8225_agc[i]))
23589485SMikore.Li@Sun.COM 			goto fail;
23599485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
23609485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
23619485SMikore.Li@Sun.COM 		    (uint8_t)i + 0x80))
23629485SMikore.Li@Sun.COM 			goto fail;
23639485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
23649485SMikore.Li@Sun.COM 	}
23659485SMikore.Li@Sun.COM 
23669485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part2); i++) {
23679485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc,
23689485SMikore.Li@Sun.COM 		    urtw_8225_rf_part2[i].reg,
23699485SMikore.Li@Sun.COM 		    urtw_8225_rf_part2[i].val))
23709485SMikore.Li@Sun.COM 			goto fail;
23719485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
23729485SMikore.Li@Sun.COM 	}
23739485SMikore.Li@Sun.COM 	error = urtw_8225_setgain(sc, 4);
23749485SMikore.Li@Sun.COM 	if (error)
23759485SMikore.Li@Sun.COM 		goto fail;
23769485SMikore.Li@Sun.COM 
23779485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part3); i++) {
23789485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc,
23799485SMikore.Li@Sun.COM 		    urtw_8225_rf_part3[i].reg,
23809485SMikore.Li@Sun.COM 		    urtw_8225_rf_part3[i].val))
23819485SMikore.Li@Sun.COM 			goto fail;
23829485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
23839485SMikore.Li@Sun.COM 	}
23849485SMikore.Li@Sun.COM 
2385*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x5b, 0x0d, 0))
23869485SMikore.Li@Sun.COM 		goto fail;
23879485SMikore.Li@Sun.COM 	if (error = urtw_8225_set_txpwrlvl(sc, 1))
23889485SMikore.Li@Sun.COM 		goto fail;
23899485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
23909485SMikore.Li@Sun.COM 		goto fail;
23919485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
23929485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
23939485SMikore.Li@Sun.COM 		goto fail;
23949485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
23959485SMikore.Li@Sun.COM 
23969485SMikore.Li@Sun.COM 	/* TX ant A, 0x0 for B */
23979485SMikore.Li@Sun.COM 	if (error = urtw_8185_tx_antenna(sc, 0x3))
23989485SMikore.Li@Sun.COM 		goto fail;
2399*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002, 0))
24009485SMikore.Li@Sun.COM 		goto fail;
24019485SMikore.Li@Sun.COM 
2402*10364SMikore.Li@Sun.COM 	error = urtw_8225_rf_set_chan(rf,
2403*10364SMikore.Li@Sun.COM 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
24049485SMikore.Li@Sun.COM fail:
24059485SMikore.Li@Sun.COM 	return (error);
24069485SMikore.Li@Sun.COM #undef N
24079485SMikore.Li@Sun.COM }
24089485SMikore.Li@Sun.COM 
24099485SMikore.Li@Sun.COM static usbd_status
2410*10364SMikore.Li@Sun.COM urtw_8225_rf_set_chan(struct urtw_rf *rf, int chan)
24119485SMikore.Li@Sun.COM {
24129485SMikore.Li@Sun.COM #define	IEEE80211_CHAN_G	\
24139485SMikore.Li@Sun.COM 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
24149485SMikore.Li@Sun.COM #define	IEEE80211_IS_CHAN_G(_c)		\
24159485SMikore.Li@Sun.COM 	(((_c)->ich_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
24169485SMikore.Li@Sun.COM 
2417*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
24189485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
24199485SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
24209485SMikore.Li@Sun.COM 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
24219485SMikore.Li@Sun.COM 	usbd_status error;
24229485SMikore.Li@Sun.COM 
24239485SMikore.Li@Sun.COM 	if (error = urtw_8225_set_txpwrlvl(sc, chan))
24249485SMikore.Li@Sun.COM 		goto fail;
24259485SMikore.Li@Sun.COM 	if (urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
24269485SMikore.Li@Sun.COM 		goto fail;
24279485SMikore.Li@Sun.COM 	urtw_delay_ms(10);
24289485SMikore.Li@Sun.COM 
2429*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22, 0))
24309485SMikore.Li@Sun.COM 		goto fail;
24319485SMikore.Li@Sun.COM 
24329485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_ASSOC &&
24339485SMikore.Li@Sun.COM 	    ic->ic_flags & IEEE80211_F_SHSLOT)
2434*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9, 0))
24359485SMikore.Li@Sun.COM 			goto fail;
24369485SMikore.Li@Sun.COM 	else
2437*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14, 0))
24389485SMikore.Li@Sun.COM 			goto fail;
24399485SMikore.Li@Sun.COM 	if (gset) {
24409485SMikore.Li@Sun.COM 		/* for G */
2441*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14, 0))
24429485SMikore.Li@Sun.COM 			goto fail;
2443*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14, 0))
24449485SMikore.Li@Sun.COM 			goto fail;
2445*10364SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_CW_VAL, 0x73, 0);
24469485SMikore.Li@Sun.COM 	} else {
24479485SMikore.Li@Sun.COM 		/* for B */
2448*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24, 0))
24499485SMikore.Li@Sun.COM 			goto fail;
2450*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24, 0))
24519485SMikore.Li@Sun.COM 			goto fail;
2452*10364SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5, 0);
24539485SMikore.Li@Sun.COM 	}
24549485SMikore.Li@Sun.COM 
24559485SMikore.Li@Sun.COM fail:
24569485SMikore.Li@Sun.COM 	return (error);
24579485SMikore.Li@Sun.COM }
24589485SMikore.Li@Sun.COM 
24599485SMikore.Li@Sun.COM static usbd_status
2460*10364SMikore.Li@Sun.COM urtw_8225_rf_set_sens(struct urtw_rf *rf)
24619485SMikore.Li@Sun.COM {
24629485SMikore.Li@Sun.COM 	usbd_status error;
2463*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
2464*10364SMikore.Li@Sun.COM 
2465*10364SMikore.Li@Sun.COM 	if (rf->sens < 0 || rf->sens > 6)
24669485SMikore.Li@Sun.COM 		return (-1);
24679485SMikore.Li@Sun.COM 
2468*10364SMikore.Li@Sun.COM 	if (rf->sens > 4)
24699485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x0c, 0x850))
24709485SMikore.Li@Sun.COM 			goto fail;
24719485SMikore.Li@Sun.COM 	else
24729485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x0c, 0x50))
24739485SMikore.Li@Sun.COM 			goto fail;
24749485SMikore.Li@Sun.COM 
2475*10364SMikore.Li@Sun.COM 	rf->sens = 6 - rf->sens;
2476*10364SMikore.Li@Sun.COM 	if (error = urtw_8225_setgain(sc, rf->sens))
24779485SMikore.Li@Sun.COM 		goto fail;
2478*10364SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_cck_c(sc, 0x41,
2479*10364SMikore.Li@Sun.COM 	    urtw_8225_threshold[rf->sens]);
24809485SMikore.Li@Sun.COM fail:
24819485SMikore.Li@Sun.COM 	return (error);
24829485SMikore.Li@Sun.COM }
24839485SMikore.Li@Sun.COM 
24849485SMikore.Li@Sun.COM static void
24859485SMikore.Li@Sun.COM urtw_stop(struct urtw_softc *sc)
24869485SMikore.Li@Sun.COM {
24879485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
24889485SMikore.Li@Sun.COM 	sc->sc_flags &= ~URTW_FLAG_RUNNING;
24899485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
24909485SMikore.Li@Sun.COM 	urtw_close_pipes(sc);
24919485SMikore.Li@Sun.COM }
24929485SMikore.Li@Sun.COM 
24939485SMikore.Li@Sun.COM static int
24949485SMikore.Li@Sun.COM urtw_isbmode(uint16_t rate)
24959485SMikore.Li@Sun.COM {
24969485SMikore.Li@Sun.COM 
24979485SMikore.Li@Sun.COM 	rate = urtw_rtl2rate(rate);
24989485SMikore.Li@Sun.COM 
24999485SMikore.Li@Sun.COM 	return ((rate <= 22 && rate != 12 && rate != 18)?(1) : (0));
25009485SMikore.Li@Sun.COM }
25019485SMikore.Li@Sun.COM 
25029485SMikore.Li@Sun.COM /* ARGSUSED */
25039485SMikore.Li@Sun.COM static void
25049485SMikore.Li@Sun.COM urtw_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
25059485SMikore.Li@Sun.COM {
25069485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
25079485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
25089485SMikore.Li@Sun.COM 	int actlen, len,  flen,  rssi;
25099485SMikore.Li@Sun.COM 	uint8_t *desc, rate;
25109485SMikore.Li@Sun.COM 	struct ieee80211_frame *wh;
25119485SMikore.Li@Sun.COM 	struct ieee80211_node *ni = 0;
25129485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
25139485SMikore.Li@Sun.COM 	uint8_t *rxbuf;
25149485SMikore.Li@Sun.COM 
25159485SMikore.Li@Sun.COM 	mp = req->bulk_data;
25169485SMikore.Li@Sun.COM 	req->bulk_data = NULL;
25179485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK ||
25189485SMikore.Li@Sun.COM 	    mp == NULL) {
25199485SMikore.Li@Sun.COM 		sc->sc_rx_err++;
25209485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2521*10364SMikore.Li@Sun.COM 		    "urtw_rxeof failed! %d, mp %p\n",
2522*10364SMikore.Li@Sun.COM 		    req->bulk_completion_reason, mp));
25239485SMikore.Li@Sun.COM 		req->bulk_data = mp;
25249485SMikore.Li@Sun.COM 		goto fail;
25259485SMikore.Li@Sun.COM 	}
25269485SMikore.Li@Sun.COM 
25279485SMikore.Li@Sun.COM 	actlen = MBLKL(mp);
25289485SMikore.Li@Sun.COM 	rxbuf = (uint8_t *)mp->b_rptr;
25299485SMikore.Li@Sun.COM 
2530*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187)
2531*10364SMikore.Li@Sun.COM 		/* 4 dword and 4 byte CRC  */
2532*10364SMikore.Li@Sun.COM 		len = actlen - (4 * 4);
2533*10364SMikore.Li@Sun.COM 	else
2534*10364SMikore.Li@Sun.COM 		/* 5 dword and 4 byte CRC */
2535*10364SMikore.Li@Sun.COM 		len = actlen - (4 * 5);
2536*10364SMikore.Li@Sun.COM 
25379485SMikore.Li@Sun.COM 	desc = rxbuf + len;
25389485SMikore.Li@Sun.COM 	flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
25399485SMikore.Li@Sun.COM 	if (flen > actlen) {
25409485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_rxeof: impossible: flen %d, actlen %d\n",
25419485SMikore.Li@Sun.COM 		    flen, actlen);
25429485SMikore.Li@Sun.COM 		sc->sc_rx_err++;
25439485SMikore.Li@Sun.COM 		req->bulk_data = mp;
25449485SMikore.Li@Sun.COM 		goto fail;
25459485SMikore.Li@Sun.COM 	}
25469485SMikore.Li@Sun.COM 
25479485SMikore.Li@Sun.COM 	rate = (desc[2] & 0xf0) >> 4;
2548*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
2549*10364SMikore.Li@Sun.COM 		rssi = (desc[6] & 0xfe) >> 1;
2550*10364SMikore.Li@Sun.COM 
2551*10364SMikore.Li@Sun.COM 		/* XXX correct? */
2552*10364SMikore.Li@Sun.COM 		if (!urtw_isbmode(rate)) {
2553*10364SMikore.Li@Sun.COM 			rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi);
2554*10364SMikore.Li@Sun.COM 			rssi = ((90 - rssi) * 100) / 65;
2555*10364SMikore.Li@Sun.COM 		} else {
2556*10364SMikore.Li@Sun.COM 			rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi);
2557*10364SMikore.Li@Sun.COM 			rssi = ((95 - rssi) * 100) / 65;
2558*10364SMikore.Li@Sun.COM 		}
25599485SMikore.Li@Sun.COM 	} else {
2560*10364SMikore.Li@Sun.COM 		rssi = 14 + desc[13]/2;
2561*10364SMikore.Li@Sun.COM 		if (rssi >= 95)
2562*10364SMikore.Li@Sun.COM 			rssi = 95;
2563*10364SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2564*10364SMikore.Li@Sun.COM 		    "urtw_rxeof: rssi %u\n", rssi));
25659485SMikore.Li@Sun.COM 	}
25669485SMikore.Li@Sun.COM 
25679485SMikore.Li@Sun.COM 	mp->b_wptr = mp->b_rptr + flen - 4;
25689485SMikore.Li@Sun.COM 	wh = (struct ieee80211_frame *)mp->b_rptr;
25699485SMikore.Li@Sun.COM 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)
25709485SMikore.Li@Sun.COM 	    == IEEE80211_FC0_TYPE_DATA) {
25719485SMikore.Li@Sun.COM 		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
25729485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
25739485SMikore.Li@Sun.COM 		    "urtw_rxeof: update sc_currate to %u\n",
25749485SMikore.Li@Sun.COM 		    sc->sc_currate));
25759485SMikore.Li@Sun.COM 	}
25769485SMikore.Li@Sun.COM 	ni = ieee80211_find_rxnode(ic, wh);
25779485SMikore.Li@Sun.COM 
25789485SMikore.Li@Sun.COM 	/* send the frame to the 802.11 layer */
25799485SMikore.Li@Sun.COM 	(void) ieee80211_input(ic, mp, ni, rssi, 0);
25809485SMikore.Li@Sun.COM 
25819485SMikore.Li@Sun.COM 	/* node is no longer needed */
25829485SMikore.Li@Sun.COM 	ieee80211_free_node(ni);
25839485SMikore.Li@Sun.COM fail:
25849485SMikore.Li@Sun.COM 	mutex_enter(&sc->rx_lock);
25859485SMikore.Li@Sun.COM 	sc->rx_queued--;
25869485SMikore.Li@Sun.COM 	mutex_exit(&sc->rx_lock);
25879485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
25889485SMikore.Li@Sun.COM 	if (URTW_IS_RUNNING(sc) && !URTW_IS_SUSPENDING(sc))
25899485SMikore.Li@Sun.COM 		(void) urtw_rx_start(sc);
25909485SMikore.Li@Sun.COM }
25919485SMikore.Li@Sun.COM 
25929485SMikore.Li@Sun.COM static usbd_status
25939485SMikore.Li@Sun.COM urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
25949485SMikore.Li@Sun.COM {
25959485SMikore.Li@Sun.COM 	uint8_t *gainp;
25969485SMikore.Li@Sun.COM 	usbd_status error;
25979485SMikore.Li@Sun.COM 
25989485SMikore.Li@Sun.COM 	/* XXX for A?  */
25999485SMikore.Li@Sun.COM 	gainp = urtw_8225v2_gain_bg;
26009485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d, gainp[gain * 3]))
26019485SMikore.Li@Sun.COM 		goto fail;
26029485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26039485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b, gainp[gain * 3 + 1]))
26049485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26059485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d, gainp[gain * 3 + 2]))
26069485SMikore.Li@Sun.COM 		goto fail;
26079485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26089485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x21, 0x17))
26099485SMikore.Li@Sun.COM 		goto fail;
26109485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26119485SMikore.Li@Sun.COM fail:
26129485SMikore.Li@Sun.COM 	return (error);
26139485SMikore.Li@Sun.COM }
26149485SMikore.Li@Sun.COM 
26159485SMikore.Li@Sun.COM static usbd_status
26169485SMikore.Li@Sun.COM urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
26179485SMikore.Li@Sun.COM {
26189485SMikore.Li@Sun.COM 	int i;
26199485SMikore.Li@Sun.COM 	uint8_t *cck_pwrtable;
26209485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
26219485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
26229485SMikore.Li@Sun.COM 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
26239485SMikore.Li@Sun.COM 	usbd_status error;
26249485SMikore.Li@Sun.COM 
26259485SMikore.Li@Sun.COM 	/* CCK power setting */
26269485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
26279485SMikore.Li@Sun.COM 	    cck_pwrlvl_max : cck_pwrlvl;
26289485SMikore.Li@Sun.COM 	cck_pwrlvl += sc->sc_txpwr_cck_base;
26299485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
26309485SMikore.Li@Sun.COM 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
26319485SMikore.Li@Sun.COM 	    urtw_8225v2_txpwr_cck;
26329485SMikore.Li@Sun.COM 
26339485SMikore.Li@Sun.COM 	for (i = 0; i < 8; i++) {
26349485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
26359485SMikore.Li@Sun.COM 		    cck_pwrtable[i]))
26369485SMikore.Li@Sun.COM 			goto fail;
26379485SMikore.Li@Sun.COM 	}
26389485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2639*10364SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl], 0))
26409485SMikore.Li@Sun.COM 		goto fail;
26419485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26429485SMikore.Li@Sun.COM 
26439485SMikore.Li@Sun.COM 	/* OFDM power setting */
26449485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
26459485SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
26469485SMikore.Li@Sun.COM 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
26479485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
26489485SMikore.Li@Sun.COM 
2649*10364SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON);
26509485SMikore.Li@Sun.COM 	if (error)
26519485SMikore.Li@Sun.COM 		goto fail;
26529485SMikore.Li@Sun.COM 
26539485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
26549485SMikore.Li@Sun.COM 		goto fail;
26559485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 5, 0x0))
26569485SMikore.Li@Sun.COM 		goto fail;
26579485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0x40))
26589485SMikore.Li@Sun.COM 		goto fail;
26599485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 7, 0x0))
26609485SMikore.Li@Sun.COM 		goto fail;
26619485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0x40))
26629485SMikore.Li@Sun.COM 		goto fail;
26639485SMikore.Li@Sun.COM 
26649485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2665*10364SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl], 0);
26669485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
26679485SMikore.Li@Sun.COM fail:
26689485SMikore.Li@Sun.COM 	return (error);
26699485SMikore.Li@Sun.COM }
26709485SMikore.Li@Sun.COM 
26719485SMikore.Li@Sun.COM static usbd_status
2672*10364SMikore.Li@Sun.COM urtw_8225v2_rf_init(struct urtw_rf *rf)
26739485SMikore.Li@Sun.COM {
26749485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a)/ sizeof ((a)[0]))
26759485SMikore.Li@Sun.COM 	int i;
26769485SMikore.Li@Sun.COM 	uint16_t data;
26779485SMikore.Li@Sun.COM 	uint32_t data32;
26789485SMikore.Li@Sun.COM 	usbd_status error;
2679*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
2680*10364SMikore.Li@Sun.COM 
2681*10364SMikore.Li@Sun.COM 	if (error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON))
26829485SMikore.Li@Sun.COM 		goto fail;
26839485SMikore.Li@Sun.COM 	if (error = urtw_8225_usb_init(sc))
26849485SMikore.Li@Sun.COM 		goto fail;
2685*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008, 0))
26869485SMikore.Li@Sun.COM 		goto fail;
2687*10364SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data, 0))
26889485SMikore.Li@Sun.COM 		goto fail;
2689*10364SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff, 0))
26909485SMikore.Li@Sun.COM 		goto fail;
2691*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044, 0))
26929485SMikore.Li@Sun.COM 		goto fail;
26939485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
26949485SMikore.Li@Sun.COM 		goto fail;
2695*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44, 0))
26969485SMikore.Li@Sun.COM 		goto fail;
26979485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
26989485SMikore.Li@Sun.COM 		goto fail;
26999485SMikore.Li@Sun.COM 	if (error = urtw_8185_rf_pins_enable(sc))
27009485SMikore.Li@Sun.COM 		goto fail;
27019485SMikore.Li@Sun.COM 
27029485SMikore.Li@Sun.COM 	urtw_delay_ms(500);
27039485SMikore.Li@Sun.COM 
27049485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
27059485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, urtw_8225v2_rf_part1[i].reg,
27069485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part1[i].val))
27079485SMikore.Li@Sun.COM 			goto fail;
27089485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27099485SMikore.Li@Sun.COM 	}
27109485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
27119485SMikore.Li@Sun.COM 
27129485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
27139485SMikore.Li@Sun.COM 		goto fail;
27149485SMikore.Li@Sun.COM 
27159485SMikore.Li@Sun.COM 	for (i = 0; i < 95; i++) {
27169485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
27179485SMikore.Li@Sun.COM 			goto fail;
27189485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27199485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225v2_rxgain[i]))
27209485SMikore.Li@Sun.COM 			goto fail;
27219485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27229485SMikore.Li@Sun.COM 	}
27239485SMikore.Li@Sun.COM 
27249485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x3, 0x2))
27259485SMikore.Li@Sun.COM 		goto fail;
27269485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
27279485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x5, 0x4))
27289485SMikore.Li@Sun.COM 		goto fail;
27299485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
27309485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0xb7))
27319485SMikore.Li@Sun.COM 		goto fail;
27329485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
27339485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
27349485SMikore.Li@Sun.COM 		goto fail;
27359485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
27369485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
27379485SMikore.Li@Sun.COM 		goto fail;
27389485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
27399485SMikore.Li@Sun.COM 
27409485SMikore.Li@Sun.COM 	if (error = urtw_8225_read(sc, 0x6, &data32))
27419485SMikore.Li@Sun.COM 		goto fail;
27429485SMikore.Li@Sun.COM 	if (data32 != 0xe6) {
27439485SMikore.Li@Sun.COM 		error = (-1);
27449485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "expect 0xe6!! (0x%x)\n", data32);
27459485SMikore.Li@Sun.COM 		goto fail;
27469485SMikore.Li@Sun.COM 	}
27479485SMikore.Li@Sun.COM 	if (!(data32 & 0x80)) {
27489485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x02, 0x0c4d))
27499485SMikore.Li@Sun.COM 			goto fail;
27509485SMikore.Li@Sun.COM 		urtw_delay_ms(200);
27519485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x02, 0x044d))
27529485SMikore.Li@Sun.COM 			goto fail;
27539485SMikore.Li@Sun.COM 		urtw_delay_ms(100);
27549485SMikore.Li@Sun.COM 		if (error = urtw_8225_read(sc, 0x6, &data32))
27559485SMikore.Li@Sun.COM 			goto fail;
27569485SMikore.Li@Sun.COM 		if (!(data32 & 0x80))
27579485SMikore.Li@Sun.COM 			cmn_err(CE_CONT, "RF calibration failed\n");
27589485SMikore.Li@Sun.COM 	}
27599485SMikore.Li@Sun.COM 	urtw_delay_ms(200);
27609485SMikore.Li@Sun.COM 
27619485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x2bf))
27629485SMikore.Li@Sun.COM 		goto fail;
27639485SMikore.Li@Sun.COM 	for (i = 0; i < 128; i++) {
27649485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
27659485SMikore.Li@Sun.COM 		    urtw_8225_agc[i]))
27669485SMikore.Li@Sun.COM 			goto fail;
27679485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27689485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
27699485SMikore.Li@Sun.COM 		    (uint8_t)i + 0x80))
27709485SMikore.Li@Sun.COM 			goto fail;
27719485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27729485SMikore.Li@Sun.COM 	}
27739485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
27749485SMikore.Li@Sun.COM 
27759485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
27769485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc,
27779485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part2[i].reg,
27789485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part2[i].val))
27799485SMikore.Li@Sun.COM 			goto fail;
27809485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27819485SMikore.Li@Sun.COM 	}
27829485SMikore.Li@Sun.COM 	error = urtw_8225v2_setgain(sc, 4);
27839485SMikore.Li@Sun.COM 	if (error)
27849485SMikore.Li@Sun.COM 		goto fail;
27859485SMikore.Li@Sun.COM 
27869485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
27879485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc,
27889485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part3[i].reg,
27899485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part3[i].val))
27909485SMikore.Li@Sun.COM 			goto fail;
27919485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
27929485SMikore.Li@Sun.COM 	}
27939485SMikore.Li@Sun.COM 
2794*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x5b, 0x0d, 0))
27959485SMikore.Li@Sun.COM 		goto fail;
27969485SMikore.Li@Sun.COM 	if (error = urtw_8225v2_set_txpwrlvl(sc, 1))
27979485SMikore.Li@Sun.COM 		goto fail;
27989485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
27999485SMikore.Li@Sun.COM 		goto fail;
28009485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
28019485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
28029485SMikore.Li@Sun.COM 		goto fail;
28039485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
28049485SMikore.Li@Sun.COM 
28059485SMikore.Li@Sun.COM 	/* TX ant A, 0x0 for B */
28069485SMikore.Li@Sun.COM 	if (error = urtw_8185_tx_antenna(sc, 0x3))
28079485SMikore.Li@Sun.COM 		goto fail;
2808*10364SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002, 0))
28099485SMikore.Li@Sun.COM 		goto fail;
28109485SMikore.Li@Sun.COM 
2811*10364SMikore.Li@Sun.COM 	error = urtw_8225_rf_set_chan(rf,
2812*10364SMikore.Li@Sun.COM 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
28139485SMikore.Li@Sun.COM fail:
28149485SMikore.Li@Sun.COM 	return (error);
28159485SMikore.Li@Sun.COM #undef N
28169485SMikore.Li@Sun.COM }
28179485SMikore.Li@Sun.COM 
28189485SMikore.Li@Sun.COM static usbd_status
2819*10364SMikore.Li@Sun.COM urtw_8225v2_rf_set_chan(struct urtw_rf *rf, int chan)
28209485SMikore.Li@Sun.COM {
2821*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
28229485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
28239485SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
28249485SMikore.Li@Sun.COM 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
28259485SMikore.Li@Sun.COM 	usbd_status error;
28269485SMikore.Li@Sun.COM 
28279485SMikore.Li@Sun.COM 	if (error = urtw_8225v2_set_txpwrlvl(sc, chan))
28289485SMikore.Li@Sun.COM 		goto fail;
28299485SMikore.Li@Sun.COM 
28309485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
28319485SMikore.Li@Sun.COM 		goto fail;
28329485SMikore.Li@Sun.COM 
28339485SMikore.Li@Sun.COM 	urtw_delay_ms(10);
28349485SMikore.Li@Sun.COM 
2835*10364SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22, 0))
28369485SMikore.Li@Sun.COM 		goto fail;
28379485SMikore.Li@Sun.COM 
28389485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_ASSOC &&
28399485SMikore.Li@Sun.COM 	    ic->ic_flags & IEEE80211_F_SHSLOT) {
2840*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9, 0))
28419485SMikore.Li@Sun.COM 			goto fail;
28429485SMikore.Li@Sun.COM 	} else
2843*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14, 0))
28449485SMikore.Li@Sun.COM 			goto fail;
28459485SMikore.Li@Sun.COM 	if (gset) {
28469485SMikore.Li@Sun.COM 		/* for G */
2847*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14, 0))
28489485SMikore.Li@Sun.COM 			goto fail;
2849*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14, 0))
28509485SMikore.Li@Sun.COM 			goto fail;
2851*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0x73, 0))
28529485SMikore.Li@Sun.COM 			goto fail;
28539485SMikore.Li@Sun.COM 	} else {
28549485SMikore.Li@Sun.COM 		/* for B */
2855*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24, 0))
28569485SMikore.Li@Sun.COM 			goto fail;
2857*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24, 0))
28589485SMikore.Li@Sun.COM 			goto fail;
2859*10364SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5, 0))
28609485SMikore.Li@Sun.COM 			goto fail;
28619485SMikore.Li@Sun.COM 	}
28629485SMikore.Li@Sun.COM 
28639485SMikore.Li@Sun.COM fail:
28649485SMikore.Li@Sun.COM 	return (error);
28659485SMikore.Li@Sun.COM }
28669485SMikore.Li@Sun.COM 
28679485SMikore.Li@Sun.COM static int
28689485SMikore.Li@Sun.COM urtw_set_channel(struct urtw_softc *sc)
28699485SMikore.Li@Sun.COM {
28709485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2871*10364SMikore.Li@Sun.COM 	struct urtw_rf *rf = &sc->sc_rf;
28729485SMikore.Li@Sun.COM 	uint32_t data;
28739485SMikore.Li@Sun.COM 	usbd_status error;
28749485SMikore.Li@Sun.COM 
2875*10364SMikore.Li@Sun.COM 	if (error = urtw_read32_c(sc, URTW_TX_CONF, &data, 0))
28769485SMikore.Li@Sun.COM 		goto fail;
28779485SMikore.Li@Sun.COM 	data &= ~URTW_TX_LOOPBACK_MASK;
28789485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_TX_CONF,
2879*10364SMikore.Li@Sun.COM 	    data | URTW_TX_LOOPBACK_MAC, 0))
28809485SMikore.Li@Sun.COM 		goto fail;
2881*10364SMikore.Li@Sun.COM 	error = rf->set_chan(rf, ieee80211_chan2ieee(ic, ic->ic_curchan));
28829485SMikore.Li@Sun.COM 	if (error)
28839485SMikore.Li@Sun.COM 		goto fail;
2884*10364SMikore.Li@Sun.COM 	urtw_delay_ms(20);
2885*10364SMikore.Li@Sun.COM 	error = urtw_write32_c(sc, URTW_TX_CONF,
2886*10364SMikore.Li@Sun.COM 	    data | URTW_TX_LOOPBACK_NONE, 0);
28879485SMikore.Li@Sun.COM fail:
28889485SMikore.Li@Sun.COM 	return (error);
28899485SMikore.Li@Sun.COM }
28909485SMikore.Li@Sun.COM 
28919485SMikore.Li@Sun.COM /* ARGSUSED */
28929485SMikore.Li@Sun.COM static void
28939485SMikore.Li@Sun.COM urtw_txeof_low(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
28949485SMikore.Li@Sun.COM {
28959485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
28969485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
28979485SMikore.Li@Sun.COM 
28989485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
28999485SMikore.Li@Sun.COM 	    "urtw_txeof_low(): cr:%s(%d), flags:0x%x, tx_queued:%d",
29009485SMikore.Li@Sun.COM 	    usb_str_cr(req->bulk_completion_reason),
29019485SMikore.Li@Sun.COM 	    req->bulk_completion_reason,
29029485SMikore.Li@Sun.COM 	    req->bulk_cb_flags,
29039485SMikore.Li@Sun.COM 	    sc->sc_tx_low_queued));
29049485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
29059485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK) {
29069485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
29079485SMikore.Li@Sun.COM 		goto fail;
29089485SMikore.Li@Sun.COM 	}
29099485SMikore.Li@Sun.COM 
29109485SMikore.Li@Sun.COM 	if (sc->sc_need_sched) {
29119485SMikore.Li@Sun.COM 		sc->sc_need_sched = 0;
29129485SMikore.Li@Sun.COM 		mac_tx_update(ic->ic_mach);
29139485SMikore.Li@Sun.COM 	}
29149485SMikore.Li@Sun.COM fail:
29159485SMikore.Li@Sun.COM 	sc->sc_tx_low_queued--;
29169485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
29179485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
29189485SMikore.Li@Sun.COM }
29199485SMikore.Li@Sun.COM 
29209485SMikore.Li@Sun.COM /* ARGSUSED */
29219485SMikore.Li@Sun.COM static void
29229485SMikore.Li@Sun.COM urtw_txeof_normal(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
29239485SMikore.Li@Sun.COM {
29249485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
29259485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
29269485SMikore.Li@Sun.COM 
29279485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
29289485SMikore.Li@Sun.COM 	    "urtw_txeof_normal(): cr:%s(%d), flags:0x%x, tx_queued:%d",
29299485SMikore.Li@Sun.COM 	    usb_str_cr(req->bulk_completion_reason),
29309485SMikore.Li@Sun.COM 	    req->bulk_completion_reason,
29319485SMikore.Li@Sun.COM 	    req->bulk_cb_flags,
29329485SMikore.Li@Sun.COM 	    sc->sc_tx_normal_queued));
29339485SMikore.Li@Sun.COM 
29349485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
29359485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK) {
29369485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
29379485SMikore.Li@Sun.COM 		goto fail;
29389485SMikore.Li@Sun.COM 	}
29399485SMikore.Li@Sun.COM 
29409485SMikore.Li@Sun.COM 	if (sc->sc_need_sched) {
29419485SMikore.Li@Sun.COM 		sc->sc_need_sched = 0;
29429485SMikore.Li@Sun.COM 		mac_tx_update(ic->ic_mach);
29439485SMikore.Li@Sun.COM 	}
29449485SMikore.Li@Sun.COM fail:
29459485SMikore.Li@Sun.COM 	sc->sc_tx_normal_queued--;
29469485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
29479485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
29489485SMikore.Li@Sun.COM }
29499485SMikore.Li@Sun.COM 
29509485SMikore.Li@Sun.COM 
29519485SMikore.Li@Sun.COM static int
29529485SMikore.Li@Sun.COM urtw_get_rate(struct ieee80211com *ic)
29539485SMikore.Li@Sun.COM {
29549485SMikore.Li@Sun.COM 	uint8_t (*rates)[IEEE80211_RATE_MAXSIZE];
29559485SMikore.Li@Sun.COM 	int rate;
29569485SMikore.Li@Sun.COM 
29579485SMikore.Li@Sun.COM 	rates = &ic->ic_bss->in_rates.ir_rates;
29589485SMikore.Li@Sun.COM 
29599485SMikore.Li@Sun.COM 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
29609485SMikore.Li@Sun.COM 		rate = ic->ic_fixed_rate;
29619485SMikore.Li@Sun.COM 	else if (ic->ic_state == IEEE80211_S_RUN)
29629485SMikore.Li@Sun.COM 		rate = (*rates)[ic->ic_bss->in_txrate];
29639485SMikore.Li@Sun.COM 	else
29649485SMikore.Li@Sun.COM 		rate = 0;
29659485SMikore.Li@Sun.COM 	return (rate & IEEE80211_RATE_VAL);
29669485SMikore.Li@Sun.COM }
29679485SMikore.Li@Sun.COM 
2968*10364SMikore.Li@Sun.COM void
2969*10364SMikore.Li@Sun.COM urtw_8187b_update_wmm(struct urtw_softc *sc)
2970*10364SMikore.Li@Sun.COM {
2971*10364SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2972*10364SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
2973*10364SMikore.Li@Sun.COM 	uint32_t data;
2974*10364SMikore.Li@Sun.COM 	uint8_t aifs, sifs, slot, ecwmin, ecwmax;
2975*10364SMikore.Li@Sun.COM 
2976*10364SMikore.Li@Sun.COM 	sifs = 0xa;
2977*10364SMikore.Li@Sun.COM 	if (IEEE80211_IS_CHAN_G(c))
2978*10364SMikore.Li@Sun.COM 		slot = 0x9;
2979*10364SMikore.Li@Sun.COM 	else
2980*10364SMikore.Li@Sun.COM 		slot = 0x14;
2981*10364SMikore.Li@Sun.COM 
2982*10364SMikore.Li@Sun.COM 	aifs = (2 * slot) + sifs;
2983*10364SMikore.Li@Sun.COM 	ecwmin = 3;
2984*10364SMikore.Li@Sun.COM 	ecwmax = 7;
2985*10364SMikore.Li@Sun.COM 
2986*10364SMikore.Li@Sun.COM 	data = ((uint32_t)aifs << 0) |		/* AIFS, offset 0 */
2987*10364SMikore.Li@Sun.COM 	    ((uint32_t)ecwmin << 8) |		/* ECW minimum, offset 8 */
2988*10364SMikore.Li@Sun.COM 	    ((uint32_t)ecwmax << 12);		/* ECW maximum, offset 16 */
2989*10364SMikore.Li@Sun.COM 
2990*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_AC_VO, data, 0);
2991*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_AC_VI, data, 0);
2992*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_AC_BE, data, 0);
2993*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_AC_BK, data, 0);
2994*10364SMikore.Li@Sun.COM }
2995*10364SMikore.Li@Sun.COM 
2996*10364SMikore.Li@Sun.COM usbd_status
2997*10364SMikore.Li@Sun.COM urtw_8187b_reset(struct urtw_softc *sc)
2998*10364SMikore.Li@Sun.COM {
2999*10364SMikore.Li@Sun.COM 	uint8_t data;
3000*10364SMikore.Li@Sun.COM 	usbd_status error;
3001*10364SMikore.Li@Sun.COM 
3002*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3003*10364SMikore.Li@Sun.COM 	if (error)
3004*10364SMikore.Li@Sun.COM 		goto fail;
3005*10364SMikore.Li@Sun.COM 
3006*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3007*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3008*10364SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE |
3009*10364SMikore.Li@Sun.COM 	    URTW_CONFIG3_GNT_SELECT, 0);
3010*10364SMikore.Li@Sun.COM 
3011*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_ANAPARAM2,
3012*10364SMikore.Li@Sun.COM 	    URTW_8187B_8225_ANAPARAM2_ON, 0);
3013*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_ANAPARAM,
3014*10364SMikore.Li@Sun.COM 	    URTW_8187B_8225_ANAPARAM_ON, 0);
3015*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_ANAPARAM3,
3016*10364SMikore.Li@Sun.COM 	    URTW_8187B_8225_ANAPARAM3_ON, 0);
3017*10364SMikore.Li@Sun.COM 
3018*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x61, 0x10, 0);
3019*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, 0x62, &data, 0);
3020*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x62, data & ~(1 << 5), 0);
3021*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x62, data | (1 << 5), 0);
3022*10364SMikore.Li@Sun.COM 
3023*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3024*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3025*10364SMikore.Li@Sun.COM 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE, 0);
3026*10364SMikore.Li@Sun.COM 
3027*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3028*10364SMikore.Li@Sun.COM 	if (error)
3029*10364SMikore.Li@Sun.COM 		goto fail;
3030*10364SMikore.Li@Sun.COM 
3031*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CMD, &data, 0);
3032*10364SMikore.Li@Sun.COM 	data = (data & 2) | URTW_CMD_RST;
3033*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CMD, data, 0);
3034*10364SMikore.Li@Sun.COM 	urtw_delay_ms(100);
3035*10364SMikore.Li@Sun.COM 
3036*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CMD, &data, 0);
3037*10364SMikore.Li@Sun.COM 	if (data & URTW_CMD_RST) {
3038*10364SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw: 8187b reset timeout\n");
3039*10364SMikore.Li@Sun.COM 		goto fail;
3040*10364SMikore.Li@Sun.COM 	}
3041*10364SMikore.Li@Sun.COM 
3042*10364SMikore.Li@Sun.COM fail:
3043*10364SMikore.Li@Sun.COM 	return (error);
3044*10364SMikore.Li@Sun.COM }
3045*10364SMikore.Li@Sun.COM 
3046*10364SMikore.Li@Sun.COM static int
3047*10364SMikore.Li@Sun.COM urtw_8187b_init(void *arg)
3048*10364SMikore.Li@Sun.COM {
3049*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
3050*10364SMikore.Li@Sun.COM 	struct urtw_rf *rf = &sc->sc_rf;
3051*10364SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3052*10364SMikore.Li@Sun.COM 	int i;
3053*10364SMikore.Li@Sun.COM 	uint8_t data;
3054*10364SMikore.Li@Sun.COM 	usbd_status error;
3055*10364SMikore.Li@Sun.COM 
3056*10364SMikore.Li@Sun.COM 	urtw_stop(sc);
3057*10364SMikore.Li@Sun.COM 	URTW_LOCK(sc);
3058*10364SMikore.Li@Sun.COM 	urtw_8187b_update_wmm(sc);
3059*10364SMikore.Li@Sun.COM 	error = urtw_8187b_reset(sc);
3060*10364SMikore.Li@Sun.COM 	if (error)
3061*10364SMikore.Li@Sun.COM 		goto fail;
3062*10364SMikore.Li@Sun.COM 
3063*10364SMikore.Li@Sun.COM 	error = urtw_open_pipes(sc);
3064*10364SMikore.Li@Sun.COM 	if (error != 0)
3065*10364SMikore.Li@Sun.COM 		goto fail;
3066*10364SMikore.Li@Sun.COM 	/* Applying MAC address again. */
3067*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3068*10364SMikore.Li@Sun.COM 	if (error)
3069*10364SMikore.Li@Sun.COM 		goto fail;
3070*10364SMikore.Li@Sun.COM 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
3071*10364SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, URTW_MAC0 + i,
3072*10364SMikore.Li@Sun.COM 		    ic->ic_macaddr[i], 0);
3073*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3074*10364SMikore.Li@Sun.COM 	if (error)
3075*10364SMikore.Li@Sun.COM 		goto fail;
3076*10364SMikore.Li@Sun.COM 
3077*10364SMikore.Li@Sun.COM 	error = urtw_update_msr(sc, IEEE80211_S_INIT);
3078*10364SMikore.Li@Sun.COM 	if (error)
3079*10364SMikore.Li@Sun.COM 		goto fail;
3080*10364SMikore.Li@Sun.COM 
3081*10364SMikore.Li@Sun.COM 	error = rf->init(rf);
3082*10364SMikore.Li@Sun.COM 	if (error != 0)
3083*10364SMikore.Li@Sun.COM 		goto fail;
3084*10364SMikore.Li@Sun.COM 	error = urtw_intr_enable(sc);
3085*10364SMikore.Li@Sun.COM 	if (error != 0)
3086*10364SMikore.Li@Sun.COM 		goto fail;
3087*10364SMikore.Li@Sun.COM 
3088*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x41, 0xf4);
3089*10364SMikore.Li@Sun.COM 	if (error != 0)
3090*10364SMikore.Li@Sun.COM 		goto fail;
3091*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x40, 0x00);
3092*10364SMikore.Li@Sun.COM 	if (error != 0)
3093*10364SMikore.Li@Sun.COM 		goto fail;
3094*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x42, 0x00);
3095*10364SMikore.Li@Sun.COM 	if (error != 0)
3096*10364SMikore.Li@Sun.COM 		goto fail;
3097*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x42, 0x01);
3098*10364SMikore.Li@Sun.COM 	if (error != 0)
3099*10364SMikore.Li@Sun.COM 		goto fail;
3100*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x40, 0x0f);
3101*10364SMikore.Li@Sun.COM 	if (error != 0)
3102*10364SMikore.Li@Sun.COM 		goto fail;
3103*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x42, 0x00);
3104*10364SMikore.Li@Sun.COM 	if (error != 0)
3105*10364SMikore.Li@Sun.COM 		goto fail;
3106*10364SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x42, 0x01);
3107*10364SMikore.Li@Sun.COM 	if (error != 0)
3108*10364SMikore.Li@Sun.COM 		goto fail;
3109*10364SMikore.Li@Sun.COM 
3110*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, 0xdb, &data, 0);
3111*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0xdb, data | (1 << 2), 0);
3112*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x72, 0x59fa, 3);
3113*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x74, 0x59d2, 3);
3114*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x76, 0x59d2, 3);
3115*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x78, 0x19fa, 3);
3116*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x7a, 0x19fa, 3);
3117*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0x7c, 0x00d0, 3);
3118*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x61, 0, 0);
3119*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x80, 0x0f, 1);
3120*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x83, 0x03, 1);
3121*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0xda, 0x10, 0);
3122*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0x4d, 0x08, 2);
3123*10364SMikore.Li@Sun.COM 
3124*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_HSSI_PARA, 0x0600321b, 0);
3125*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, 0xec, 0x0800, 1);
3126*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_ACM_CONTROL, 0, 0);
3127*10364SMikore.Li@Sun.COM 
3128*10364SMikore.Li@Sun.COM 	sc->sc_tx_low_queued = 0;
3129*10364SMikore.Li@Sun.COM 	sc->sc_tx_normal_queued = 0;
3130*10364SMikore.Li@Sun.COM 	error = urtw_rx_enable(sc);
3131*10364SMikore.Li@Sun.COM 	if (error != 0)
3132*10364SMikore.Li@Sun.COM 		goto fail;
3133*10364SMikore.Li@Sun.COM 	urtw_tx_enable(sc);
3134*10364SMikore.Li@Sun.COM 
3135*10364SMikore.Li@Sun.COM 	if (error == 0) {
3136*10364SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev,
3137*10364SMikore.Li@Sun.COM 		    CE_CONT, "urtw_8187b_init: done\n"));
3138*10364SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_RUNNING;
3139*10364SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3140*10364SMikore.Li@Sun.COM 		return (error);
3141*10364SMikore.Li@Sun.COM 	}
3142*10364SMikore.Li@Sun.COM 
3143*10364SMikore.Li@Sun.COM fail:
3144*10364SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw_8187b_init failed\n");
3145*10364SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
3146*10364SMikore.Li@Sun.COM 	urtw_stop(sc);
3147*10364SMikore.Li@Sun.COM 	return (EIO);
3148*10364SMikore.Li@Sun.COM }
3149*10364SMikore.Li@Sun.COM 
3150*10364SMikore.Li@Sun.COM void
3151*10364SMikore.Li@Sun.COM urtw_8225v2_b_config_mac(struct urtw_softc *sc)
3152*10364SMikore.Li@Sun.COM {
3153*10364SMikore.Li@Sun.COM 	int i;
3154*10364SMikore.Li@Sun.COM 	int nitems = sizeof (urtw_8187b_regtbl)
3155*10364SMikore.Li@Sun.COM 	    / sizeof ((urtw_8187b_regtbl)[0]);
3156*10364SMikore.Li@Sun.COM 
3157*10364SMikore.Li@Sun.COM 	for (i = 0; i < nitems; i++) {
3158*10364SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, urtw_8187b_regtbl[i].reg,
3159*10364SMikore.Li@Sun.COM 		    urtw_8187b_regtbl[i].val, urtw_8187b_regtbl[i].idx);
3160*10364SMikore.Li@Sun.COM 	}
3161*10364SMikore.Li@Sun.COM 
3162*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_TID_AC_MAP, 0xfa50, 0);
3163*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_INT_MIG, 0, 0);
3164*10364SMikore.Li@Sun.COM 
3165*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, 0xf0, 0, 1);
3166*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, 0xf4, 0, 1);
3167*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, 0xf8, 0, 1);
3168*10364SMikore.Li@Sun.COM 
3169*10364SMikore.Li@Sun.COM 	(void) urtw_write32_c(sc, URTW_RF_TIMING, 0x00004001, 0);
3170*10364SMikore.Li@Sun.COM }
3171*10364SMikore.Li@Sun.COM 
3172*10364SMikore.Li@Sun.COM void
3173*10364SMikore.Li@Sun.COM urtw_8225v2_b_init_rfe(struct urtw_softc *sc)
3174*10364SMikore.Li@Sun.COM {
3175*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x0480, 0);
3176*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x2488, 0);
3177*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x1fff, 0);
3178*10364SMikore.Li@Sun.COM 	urtw_delay_ms(100);
3179*10364SMikore.Li@Sun.COM }
3180*10364SMikore.Li@Sun.COM 
3181*10364SMikore.Li@Sun.COM usbd_status
3182*10364SMikore.Li@Sun.COM urtw_8225v2_b_update_chan(struct urtw_softc *sc)
3183*10364SMikore.Li@Sun.COM {
3184*10364SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3185*10364SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
3186*10364SMikore.Li@Sun.COM 	uint8_t aifs, difs, eifs, sifs, slot;
3187*10364SMikore.Li@Sun.COM 
3188*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_SIFS, 0x22, 0);
3189*10364SMikore.Li@Sun.COM 
3190*10364SMikore.Li@Sun.COM 	sifs = 0xa;
3191*10364SMikore.Li@Sun.COM 	if (IEEE80211_IS_CHAN_G(c)) {
3192*10364SMikore.Li@Sun.COM 		slot = 0x9;
3193*10364SMikore.Li@Sun.COM 		difs = 0x1c;
3194*10364SMikore.Li@Sun.COM 		eifs = 0x5b;
3195*10364SMikore.Li@Sun.COM 	} else {
3196*10364SMikore.Li@Sun.COM 		slot = 0x14;
3197*10364SMikore.Li@Sun.COM 		difs = 0x32;
3198*10364SMikore.Li@Sun.COM 		eifs = 0x5b;
3199*10364SMikore.Li@Sun.COM 	}
3200*10364SMikore.Li@Sun.COM 	aifs = (2 * slot) + sifs;
3201*10364SMikore.Li@Sun.COM 
3202*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_SLOT, slot, 0);
3203*10364SMikore.Li@Sun.COM 
3204*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_AC_VO, aifs, 0);
3205*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_AC_VI, aifs, 0);
3206*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_AC_BE, aifs, 0);
3207*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_AC_BK, aifs, 0);
3208*10364SMikore.Li@Sun.COM 
3209*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_DIFS, difs, 0);
3210*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_8187B_EIFS, eifs, 0);
3211*10364SMikore.Li@Sun.COM 	return (0);
3212*10364SMikore.Li@Sun.COM }
3213*10364SMikore.Li@Sun.COM 
3214*10364SMikore.Li@Sun.COM usbd_status
3215*10364SMikore.Li@Sun.COM urtw_8225v2_b_rf_init(struct urtw_rf *rf)
3216*10364SMikore.Li@Sun.COM {
3217*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
3218*10364SMikore.Li@Sun.COM 	int i, nitems;
3219*10364SMikore.Li@Sun.COM 	uint8_t data;
3220*10364SMikore.Li@Sun.COM 	usbd_status error;
3221*10364SMikore.Li@Sun.COM 
3222*10364SMikore.Li@Sun.COM 	/* Set up ACK rate, retry limit, TX AGC, TX antenna. */
3223*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_8187B_BRSR, 0x0fff, 0);
3224*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CW_CONF, &data, 0);
3225*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CW_CONF, data |
3226*10364SMikore.Li@Sun.COM 	    URTW_CW_CONF_PERPACKET_RETRY, 0);
3227*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_TX_AGC_CTL, &data, 0);
3228*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_AGC_CTL, data |
3229*10364SMikore.Li@Sun.COM 	    URTW_TX_AGC_CTL_PERPACKET_GAIN |
3230*10364SMikore.Li@Sun.COM 	    URTW_TX_AGC_CTL_PERPACKET_ANTSEL, 0);
3231*10364SMikore.Li@Sun.COM 
3232*10364SMikore.Li@Sun.COM 	/* Auto rate fallback control. */
3233*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_ARFR, 0x0fff, 1);	/* 1M ~ 54M */
3234*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_RATE_FALLBACK, &data, 0);
3235*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_RATE_FALLBACK, data |
3236*10364SMikore.Li@Sun.COM 	    URTW_RATE_FALLBACK_ENABLE, 0);
3237*10364SMikore.Li@Sun.COM 
3238*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_BEACON_INTERVAL, 0x3ff, 0);
3239*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_ATIM_WND, 2, 0);
3240*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_FEMR, 0xffff, 1);
3241*10364SMikore.Li@Sun.COM 
3242*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3243*10364SMikore.Li@Sun.COM 	if (error)
3244*10364SMikore.Li@Sun.COM 		goto fail;
3245*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CONFIG1, &data, 0);
3246*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CONFIG1, (data & 0x3f) | 0x80, 0);
3247*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3248*10364SMikore.Li@Sun.COM 	if (error)
3249*10364SMikore.Li@Sun.COM 		goto fail;
3250*10364SMikore.Li@Sun.COM 
3251*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_WPA_CONFIG, 0, 0);
3252*10364SMikore.Li@Sun.COM 	urtw_8225v2_b_config_mac(sc);
3253*10364SMikore.Li@Sun.COM 	(void) urtw_write16_c(sc, URTW_RFSW_CTRL, 0x569a, 2);
3254*10364SMikore.Li@Sun.COM 
3255*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3256*10364SMikore.Li@Sun.COM 	if (error)
3257*10364SMikore.Li@Sun.COM 		goto fail;
3258*10364SMikore.Li@Sun.COM 	(void) urtw_read8_c(sc, URTW_CONFIG3, &data, 0);
3259*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_CONFIG3,
3260*10364SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE, 0);
3261*10364SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3262*10364SMikore.Li@Sun.COM 	if (error)
3263*10364SMikore.Li@Sun.COM 		goto fail;
3264*10364SMikore.Li@Sun.COM 
3265*10364SMikore.Li@Sun.COM 	urtw_8225v2_b_init_rfe(sc);
3266*10364SMikore.Li@Sun.COM 
3267*10364SMikore.Li@Sun.COM 	nitems = sizeof (urtw_8225v2_b_rf) / sizeof ((urtw_8225v2_b_rf)[0]);
3268*10364SMikore.Li@Sun.COM 	for (i = 0; i < nitems; i++) {
3269*10364SMikore.Li@Sun.COM 		(void) urtw_8225_write_c(sc, urtw_8225v2_b_rf[i].reg,
3270*10364SMikore.Li@Sun.COM 		    urtw_8225v2_b_rf[i].val);
3271*10364SMikore.Li@Sun.COM 	}
3272*10364SMikore.Li@Sun.COM 
3273*10364SMikore.Li@Sun.COM 	nitems = sizeof (urtw_8225v2_rxgain) / sizeof ((urtw_8225v2_rxgain)[0]);
3274*10364SMikore.Li@Sun.COM 	for (i = 0; i < nitems; i++) {
3275*10364SMikore.Li@Sun.COM 		(void) urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1));
3276*10364SMikore.Li@Sun.COM 		(void) urtw_8225_write_c(sc, 0x2, urtw_8225v2_rxgain[i]);
3277*10364SMikore.Li@Sun.COM 	}
3278*10364SMikore.Li@Sun.COM 
3279*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x03, 0x080);
3280*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x05, 0x004);
3281*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x00, 0x0b7);
3282*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x02, 0xc4d);
3283*10364SMikore.Li@Sun.COM 	urtw_delay_ms(10);
3284*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x02, 0x44d);
3285*10364SMikore.Li@Sun.COM 	urtw_delay_ms(10);
3286*10364SMikore.Li@Sun.COM 	(void) urtw_8225_write_c(sc, 0x00, 0x2bf);
3287*10364SMikore.Li@Sun.COM 	urtw_delay_ms(10);
3288*10364SMikore.Li@Sun.COM 
3289*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_GAIN_CCK, 0x03, 0);
3290*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_GAIN_OFDM, 0x07, 0);
3291*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_ANTENNA, 0x03, 0);
3292*10364SMikore.Li@Sun.COM 
3293*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x80, 0x12);
3294*10364SMikore.Li@Sun.COM 	nitems = sizeof (urtw_8225v2_agc) / sizeof ((urtw_8225v2_agc)[0]);
3295*10364SMikore.Li@Sun.COM 	for (i = 0; i < nitems; i++) {
3296*10364SMikore.Li@Sun.COM 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0f, urtw_8225v2_agc[i]);
3297*10364SMikore.Li@Sun.COM 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0e, (uint8_t)i + 0x80);
3298*10364SMikore.Li@Sun.COM 		(void) urtw_8187_write_phy_ofdm_c(sc, 0x0e, 0);
3299*10364SMikore.Li@Sun.COM 	}
3300*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x80, 0x10);
3301*10364SMikore.Li@Sun.COM 
3302*10364SMikore.Li@Sun.COM 	nitems = sizeof (urtw_8225v2_ofdm) / sizeof ((urtw_8225v2_ofdm)[0]);
3303*10364SMikore.Li@Sun.COM 	for (i = 0; i < nitems; i++) {
3304*10364SMikore.Li@Sun.COM 		(void) urtw_8187_write_phy_ofdm_c(sc, i, urtw_8225v2_ofdm[i]);
3305*10364SMikore.Li@Sun.COM 	}
3306*10364SMikore.Li@Sun.COM 	(void) urtw_8225v2_b_update_chan(sc);
3307*10364SMikore.Li@Sun.COM 
3308*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x97, 0x46);
3309*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_ofdm_c(sc, 0xa4, 0xb6);
3310*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_ofdm_c(sc, 0x85, 0xfc);
3311*10364SMikore.Li@Sun.COM 	(void) urtw_8187_write_phy_cck_c(sc, 0xc1, 0x88);
3312*10364SMikore.Li@Sun.COM 
3313*10364SMikore.Li@Sun.COM 	error = urtw_8225v2_b_rf_set_chan(rf,
3314*10364SMikore.Li@Sun.COM 	    ieee80211_chan2ieee(&sc->sc_ic, sc->sc_ic.ic_curchan));
3315*10364SMikore.Li@Sun.COM fail:
3316*10364SMikore.Li@Sun.COM 	return (error);
3317*10364SMikore.Li@Sun.COM }
3318*10364SMikore.Li@Sun.COM 
3319*10364SMikore.Li@Sun.COM static usbd_status
3320*10364SMikore.Li@Sun.COM urtw_8225v2_b_rf_set_chan(struct urtw_rf *rf, int chan)
3321*10364SMikore.Li@Sun.COM {
3322*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = rf->rf_sc;
3323*10364SMikore.Li@Sun.COM 	int error = 0;
3324*10364SMikore.Li@Sun.COM 
3325*10364SMikore.Li@Sun.COM 	urtw_8225v2_b_set_txpwrlvl(sc, chan);
3326*10364SMikore.Li@Sun.COM 	error = urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]);
3327*10364SMikore.Li@Sun.COM 	if (error)
3328*10364SMikore.Li@Sun.COM 		goto fail;
3329*10364SMikore.Li@Sun.COM 	/*
3330*10364SMikore.Li@Sun.COM 	 * Delay removed from 8185 to 8187.
3331*10364SMikore.Li@Sun.COM 	 * usbd_delay_ms(sc->sc_udev, 10);
3332*10364SMikore.Li@Sun.COM 	 */
3333*10364SMikore.Li@Sun.COM 
3334*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_AC_VO, 0x5114, 0);
3335*10364SMikore.Li@Sun.COM 	if (error)
3336*10364SMikore.Li@Sun.COM 		goto fail;
3337*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_AC_VI, 0x5114, 0);
3338*10364SMikore.Li@Sun.COM 	if (error)
3339*10364SMikore.Li@Sun.COM 		goto fail;
3340*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_AC_BE, 0x5114, 0);
3341*10364SMikore.Li@Sun.COM 	if (error)
3342*10364SMikore.Li@Sun.COM 		goto fail;
3343*10364SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_AC_BK, 0x5114, 0);
3344*10364SMikore.Li@Sun.COM fail:
3345*10364SMikore.Li@Sun.COM 	return (error);
3346*10364SMikore.Li@Sun.COM }
3347*10364SMikore.Li@Sun.COM 
3348*10364SMikore.Li@Sun.COM void
3349*10364SMikore.Li@Sun.COM urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *sc, int chan)
3350*10364SMikore.Li@Sun.COM {
3351*10364SMikore.Li@Sun.COM 	int i;
3352*10364SMikore.Li@Sun.COM 	uint8_t *cck_pwrtable;
3353*10364SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl_min, cck_pwrlvl_max, ofdm_pwrlvl_min,
3354*10364SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max;
3355*10364SMikore.Li@Sun.COM 	int8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3356*10364SMikore.Li@Sun.COM 	int8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3357*10364SMikore.Li@Sun.COM 
3358*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3359*10364SMikore.Li@Sun.COM 		cck_pwrlvl_min = 0;
3360*10364SMikore.Li@Sun.COM 		cck_pwrlvl_max = 15;
3361*10364SMikore.Li@Sun.COM 		ofdm_pwrlvl_min = 2;
3362*10364SMikore.Li@Sun.COM 		ofdm_pwrlvl_max = 17;
3363*10364SMikore.Li@Sun.COM 	} else {
3364*10364SMikore.Li@Sun.COM 		cck_pwrlvl_min = 7;
3365*10364SMikore.Li@Sun.COM 		cck_pwrlvl_max = 22;
3366*10364SMikore.Li@Sun.COM 		ofdm_pwrlvl_min = 10;
3367*10364SMikore.Li@Sun.COM 		ofdm_pwrlvl_max = 25;
3368*10364SMikore.Li@Sun.COM 	}
3369*10364SMikore.Li@Sun.COM 
3370*10364SMikore.Li@Sun.COM 	/* CCK power setting */
3371*10364SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > (cck_pwrlvl_max - cck_pwrlvl_min)) ?
3372*10364SMikore.Li@Sun.COM 	    cck_pwrlvl_max : (cck_pwrlvl + cck_pwrlvl_min);
3373*10364SMikore.Li@Sun.COM 
3374*10364SMikore.Li@Sun.COM 	cck_pwrlvl += sc->sc_txpwr_cck_base;
3375*10364SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3376*10364SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl < 0) ? 0 : cck_pwrlvl;
3377*10364SMikore.Li@Sun.COM 
3378*10364SMikore.Li@Sun.COM 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3379*10364SMikore.Li@Sun.COM 	    urtw_8225v2_txpwr_cck;
3380*10364SMikore.Li@Sun.COM 
3381*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3382*10364SMikore.Li@Sun.COM 		if (cck_pwrlvl > 7 && cck_pwrlvl <= 11)
3383*10364SMikore.Li@Sun.COM 			cck_pwrtable += 8;
3384*10364SMikore.Li@Sun.COM 		if (cck_pwrlvl > 11)
3385*10364SMikore.Li@Sun.COM 			cck_pwrtable += 16;
3386*10364SMikore.Li@Sun.COM 	} else {
3387*10364SMikore.Li@Sun.COM 		if (cck_pwrlvl > 5 && cck_pwrlvl <= 11)
3388*10364SMikore.Li@Sun.COM 			cck_pwrtable += 8;
3389*10364SMikore.Li@Sun.COM 		if (cck_pwrlvl > 12 && cck_pwrlvl <= 17)
3390*10364SMikore.Li@Sun.COM 			cck_pwrtable += 16;
3391*10364SMikore.Li@Sun.COM 		if (cck_pwrlvl > 17)
3392*10364SMikore.Li@Sun.COM 			cck_pwrtable += 24;
3393*10364SMikore.Li@Sun.COM 	}
3394*10364SMikore.Li@Sun.COM 
3395*10364SMikore.Li@Sun.COM 	for (i = 0; i < 8; i++) {
3396*10364SMikore.Li@Sun.COM 		(void) urtw_8187_write_phy_cck_c(sc, 0x44 + i, cck_pwrtable[i]);
3397*10364SMikore.Li@Sun.COM 	}
3398*10364SMikore.Li@Sun.COM 
3399*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_GAIN_CCK,
3400*10364SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1, 0);
3401*10364SMikore.Li@Sun.COM 	/*
3402*10364SMikore.Li@Sun.COM 	 * Delay removed from 8185 to 8187.
3403*10364SMikore.Li@Sun.COM 	 * usbd_delay_ms(sc->sc_udev, 1);
3404*10364SMikore.Li@Sun.COM 	 */
3405*10364SMikore.Li@Sun.COM 
3406*10364SMikore.Li@Sun.COM 	/* OFDM power setting */
3407*10364SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3408*10364SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3409*10364SMikore.Li@Sun.COM 
3410*10364SMikore.Li@Sun.COM 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3411*10364SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3412*10364SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl < 0) ? 0 : ofdm_pwrlvl;
3413*10364SMikore.Li@Sun.COM 
3414*10364SMikore.Li@Sun.COM 	(void) urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
3415*10364SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1, 0);
3416*10364SMikore.Li@Sun.COM 
3417*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187B_B) {
3418*10364SMikore.Li@Sun.COM 		if (ofdm_pwrlvl <= 11) {
3419*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x60);
3420*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x60);
3421*10364SMikore.Li@Sun.COM 		} else {
3422*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x5c);
3423*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x5c);
3424*10364SMikore.Li@Sun.COM 		}
3425*10364SMikore.Li@Sun.COM 	} else {
3426*10364SMikore.Li@Sun.COM 		if (ofdm_pwrlvl <= 11) {
3427*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x5c);
3428*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x5c);
3429*10364SMikore.Li@Sun.COM 		} else if (ofdm_pwrlvl <= 17) {
3430*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x54);
3431*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x54);
3432*10364SMikore.Li@Sun.COM 		} else {
3433*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x87, 0x50);
3434*10364SMikore.Li@Sun.COM 			(void) urtw_8187_write_phy_ofdm_c(sc, 0x89, 0x50);
3435*10364SMikore.Li@Sun.COM 		}
3436*10364SMikore.Li@Sun.COM 	}
3437*10364SMikore.Li@Sun.COM 
3438*10364SMikore.Li@Sun.COM 	/*
3439*10364SMikore.Li@Sun.COM 	 * Delay removed from 8185 to 8187.
3440*10364SMikore.Li@Sun.COM 	 * usbd_delay_ms(sc->sc_udev, 1);
3441*10364SMikore.Li@Sun.COM 	 */
3442*10364SMikore.Li@Sun.COM }
3443*10364SMikore.Li@Sun.COM 
3444*10364SMikore.Li@Sun.COM 
34459485SMikore.Li@Sun.COM static int
34469485SMikore.Li@Sun.COM urtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
34479485SMikore.Li@Sun.COM {
34489485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)ic;
34499485SMikore.Li@Sun.COM 	struct ieee80211_frame *wh;
34509485SMikore.Li@Sun.COM 	struct ieee80211_key *k;
34519485SMikore.Li@Sun.COM 	struct ieee80211_node *ni = NULL;
34529485SMikore.Li@Sun.COM 	uint8_t *buf;
34539485SMikore.Li@Sun.COM 	mblk_t *m = 0, *m0, *mtx;
34549485SMikore.Li@Sun.COM 	int off, mblen, xferlen, err = 0, priority = 0;
34559485SMikore.Li@Sun.COM 
34569485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
34579485SMikore.Li@Sun.COM 	priority = (type == IEEE80211_FC0_TYPE_DATA) ?
34589485SMikore.Li@Sun.COM 	    LOW_PRIORITY_PIPE: NORMAL_PRIORITY_PIPE;
34599485SMikore.Li@Sun.COM 
34609485SMikore.Li@Sun.COM 	if (URTW_IS_SUSPENDING(sc)) {
34619485SMikore.Li@Sun.COM 		err = 0;
34629485SMikore.Li@Sun.COM 		goto failed;
34639485SMikore.Li@Sun.COM 	}
34649485SMikore.Li@Sun.COM 
34659485SMikore.Li@Sun.COM 	if (((priority)? sc->sc_tx_normal_queued : sc->sc_tx_low_queued) >=
34669485SMikore.Li@Sun.COM 	    URTW_TX_DATA_LIST_COUNT) {
34679485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
34689485SMikore.Li@Sun.COM 		    "urtw_send(): no TX buffer!\n"));
34699485SMikore.Li@Sun.COM 		sc->sc_tx_nobuf++;
34709485SMikore.Li@Sun.COM 		err = ENOMEM;
34719485SMikore.Li@Sun.COM 		goto failed;
34729485SMikore.Li@Sun.COM 	}
34739485SMikore.Li@Sun.COM 
34749485SMikore.Li@Sun.COM 	m = allocb(URTW_TXBUF_SIZE, BPRI_MED);
34759485SMikore.Li@Sun.COM 	if (m == NULL) {
34769485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_send(): can't alloc mblk.\n");
34779485SMikore.Li@Sun.COM 		err = ENOMEM;
34789485SMikore.Li@Sun.COM 		goto failed;
34799485SMikore.Li@Sun.COM 	}
34809485SMikore.Li@Sun.COM 
34819485SMikore.Li@Sun.COM 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
34829485SMikore.Li@Sun.COM 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
34839485SMikore.Li@Sun.COM 		(void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
34849485SMikore.Li@Sun.COM 		off += mblen;
34859485SMikore.Li@Sun.COM 	}
34869485SMikore.Li@Sun.COM 	m->b_wptr += off;
34879485SMikore.Li@Sun.COM 
34889485SMikore.Li@Sun.COM 	wh = (struct ieee80211_frame *)m->b_rptr;
34899485SMikore.Li@Sun.COM 
34909485SMikore.Li@Sun.COM 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
34919485SMikore.Li@Sun.COM 	if (ni == NULL) {
34929485SMikore.Li@Sun.COM 		err = ENXIO;
34939485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
34949485SMikore.Li@Sun.COM 		goto failed;
34959485SMikore.Li@Sun.COM 	}
34969485SMikore.Li@Sun.COM 
34979485SMikore.Li@Sun.COM 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
34989485SMikore.Li@Sun.COM 	    IEEE80211_FC0_TYPE_DATA) {
34999485SMikore.Li@Sun.COM 		(void) ieee80211_encap(ic, m, ni);
35009485SMikore.Li@Sun.COM 	}
35019485SMikore.Li@Sun.COM 
35029485SMikore.Li@Sun.COM 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
35039485SMikore.Li@Sun.COM 		k = ieee80211_crypto_encap(ic, m);
35049485SMikore.Li@Sun.COM 		if (k == NULL) {
35059485SMikore.Li@Sun.COM 			ic->ic_stats.is_tx_failed++;
35069485SMikore.Li@Sun.COM 			err = ENXIO;
35079485SMikore.Li@Sun.COM 			goto failed;
35089485SMikore.Li@Sun.COM 		}
35099485SMikore.Li@Sun.COM 		/* packet header may have moved, reset our local pointer */
35109485SMikore.Li@Sun.COM 		wh = (struct ieee80211_frame *)m->b_rptr;
35119485SMikore.Li@Sun.COM 	}
35129485SMikore.Li@Sun.COM 
3513*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187)
3514*10364SMikore.Li@Sun.COM 		xferlen = MBLKL(m) + 4 * 3;
3515*10364SMikore.Li@Sun.COM 	else
3516*10364SMikore.Li@Sun.COM 		xferlen = MBLKL(m) + 4 * 8;
3517*10364SMikore.Li@Sun.COM 
35189485SMikore.Li@Sun.COM 	if ((0 == xferlen % 64) || (0 == xferlen % 512))
35199485SMikore.Li@Sun.COM 		xferlen += 1;
35209485SMikore.Li@Sun.COM 
35219485SMikore.Li@Sun.COM 	mtx = allocb(xferlen, BPRI_MED);
35229485SMikore.Li@Sun.COM 	buf = mtx->b_rptr;
35239485SMikore.Li@Sun.COM 
35249485SMikore.Li@Sun.COM 	bzero(buf, xferlen);
35259485SMikore.Li@Sun.COM 	buf[0] = MBLKL(m) & 0xff;
35269485SMikore.Li@Sun.COM 	buf[1] = (MBLKL(m) & 0x0f00) >> 8;
35279485SMikore.Li@Sun.COM 	buf[1] |= (1 << 7);
35289485SMikore.Li@Sun.COM 
35299485SMikore.Li@Sun.COM 	/* XXX sc_preamble_mode is always 2.  */
35309485SMikore.Li@Sun.COM 	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
35319485SMikore.Li@Sun.COM 		buf[2] |= (1 << 1);
35329485SMikore.Li@Sun.COM 	/* RTS rate - 10 means we use a basic rate.  */
35339485SMikore.Li@Sun.COM 	buf[2] |= (urtw_rate2rtl(2) << 3);
35349485SMikore.Li@Sun.COM 	/*
35359485SMikore.Li@Sun.COM 	 * XXX currently TX rate control depends on the rate value of
35369485SMikore.Li@Sun.COM 	 * RX descriptor because I don't know how to we can control TX rate
35379485SMikore.Li@Sun.COM 	 * in more smart way.  Please fix me you find a thing.
35389485SMikore.Li@Sun.COM 	 */
35399485SMikore.Li@Sun.COM 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
35409485SMikore.Li@Sun.COM 		buf[3] = urtw_rate2rtl(MAX(2, urtw_get_rate(ic)));
35419485SMikore.Li@Sun.COM 	} else
35429485SMikore.Li@Sun.COM 		buf[3] = sc->sc_currate;
3543*10364SMikore.Li@Sun.COM 
3544*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
3545*10364SMikore.Li@Sun.COM 		buf[8] = 3;		/* CW minimum  */
3546*10364SMikore.Li@Sun.COM 		buf[8] |= (7 << 4);	/* CW maximum  */
3547*10364SMikore.Li@Sun.COM 		buf[9] |= 11;		/* retry limitation  */
3548*10364SMikore.Li@Sun.COM 		bcopy(m->b_rptr, &buf[12], MBLKL(m));
3549*10364SMikore.Li@Sun.COM 	} else {
3550*10364SMikore.Li@Sun.COM 		buf[21] |= 11;		/* retry limitation */
3551*10364SMikore.Li@Sun.COM 		bcopy(m->b_rptr, &buf[32], MBLKL(m));
3552*10364SMikore.Li@Sun.COM 	}
35539485SMikore.Li@Sun.COM 
35549485SMikore.Li@Sun.COM 	(void) urtw_led_ctl(sc, URTW_LED_CTL_TX);
35559485SMikore.Li@Sun.COM 	mtx->b_wptr = mtx->b_rptr + xferlen;
35569485SMikore.Li@Sun.COM 
35579485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
3558*10364SMikore.Li@Sun.COM 	    "sending frame len=%u rate=%u xfer len=%u\n",
35599485SMikore.Li@Sun.COM 	    MBLKL(m), buf[3], xferlen));
35609485SMikore.Li@Sun.COM 
35619485SMikore.Li@Sun.COM 	err = urtw_tx_start(sc, mtx, priority);
35629485SMikore.Li@Sun.COM 	if (!err) {
35639485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_frags++;
35649485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_bytes += MBLKL(m);
35659485SMikore.Li@Sun.COM 	} else {
35669485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
35679485SMikore.Li@Sun.COM 	}
35689485SMikore.Li@Sun.COM 
35699485SMikore.Li@Sun.COM failed:
35709485SMikore.Li@Sun.COM 	if (ni != NULL)
35719485SMikore.Li@Sun.COM 		ieee80211_free_node(ni);
35729485SMikore.Li@Sun.COM 
35739485SMikore.Li@Sun.COM 	if ((mp) &&
35749485SMikore.Li@Sun.COM 	    ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
35759485SMikore.Li@Sun.COM 	    err == DDI_SUCCESS)) {
35769485SMikore.Li@Sun.COM 		freemsg(mp);
35779485SMikore.Li@Sun.COM 	}
35789485SMikore.Li@Sun.COM 	if (m) freemsg(m);
35799485SMikore.Li@Sun.COM 
35809485SMikore.Li@Sun.COM 	if (((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) &&
35819485SMikore.Li@Sun.COM 	    (err != 0)) {
35829485SMikore.Li@Sun.COM 		sc->sc_need_sched = 1;
35839485SMikore.Li@Sun.COM 	}
35849485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
35859485SMikore.Li@Sun.COM 	return (err);
35869485SMikore.Li@Sun.COM }
35879485SMikore.Li@Sun.COM 
35889485SMikore.Li@Sun.COM static void
35899485SMikore.Li@Sun.COM urtw_next_scan(void *arg)
35909485SMikore.Li@Sun.COM {
35919485SMikore.Li@Sun.COM 	ieee80211com_t *ic = arg;
35929485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
35939485SMikore.Li@Sun.COM 
35949485SMikore.Li@Sun.COM 	if (URTW_IS_NOT_RUNNING(sc)) {
35959485SMikore.Li@Sun.COM 		sc->sc_scan_id = 0;
35969485SMikore.Li@Sun.COM 		return;
35979485SMikore.Li@Sun.COM 	}
35989485SMikore.Li@Sun.COM 
35999485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_SCAN) {
36009485SMikore.Li@Sun.COM 		(void) ieee80211_next_scan(ic);
36019485SMikore.Li@Sun.COM 	}
36029485SMikore.Li@Sun.COM 	sc->sc_scan_id = 0;
36039485SMikore.Li@Sun.COM }
36049485SMikore.Li@Sun.COM 
36059485SMikore.Li@Sun.COM static void
36069485SMikore.Li@Sun.COM urtw_led_launch(void *arg)
36079485SMikore.Li@Sun.COM {
36089485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
36099485SMikore.Li@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
36109485SMikore.Li@Sun.COM 	int error = 0;
36119485SMikore.Li@Sun.COM 
36129485SMikore.Li@Sun.COM 	URTW_LEDLOCK(sc);
36139485SMikore.Li@Sun.COM 	if ((sc->sc_strategy != URTW_SW_LED_MODE0) ||
36149485SMikore.Li@Sun.COM 	    URTW_IS_NOT_RUNNING(sc) ||
36159485SMikore.Li@Sun.COM 	    URTW_IS_SUSPENDING(sc)) {
36169485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
36179485SMikore.Li@Sun.COM 		    "failed process LED strategy 0x%x, run?%d",
36189485SMikore.Li@Sun.COM 		    sc->sc_strategy,
36199485SMikore.Li@Sun.COM 		    sc->sc_flags));
36209485SMikore.Li@Sun.COM 		sc->sc_led_ch = 0;
36219485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 0;
36229485SMikore.Li@Sun.COM 		URTW_LEDUNLOCK(sc);
36239485SMikore.Li@Sun.COM 		return;
36249485SMikore.Li@Sun.COM 	}
36259485SMikore.Li@Sun.COM 	error = urtw_led_blink(sc);
36269485SMikore.Li@Sun.COM 	if (error) {
36279485SMikore.Li@Sun.COM 		sc->sc_led_ch = timeout(urtw_led_launch, (void *)sc,
36289485SMikore.Li@Sun.COM 		    drv_usectohz((ic->ic_state == IEEE80211_S_RUN) ?
36299485SMikore.Li@Sun.COM 		    URTW_LED_LINKON_BLINK: URTW_LED_LINKOFF_BLINK));
36309485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
36319485SMikore.Li@Sun.COM 		    "try again led launch"));
36329485SMikore.Li@Sun.COM 	} else {
36339485SMikore.Li@Sun.COM 		sc->sc_led_ch = 0;
36349485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
36359485SMikore.Li@Sun.COM 		    "exit led launch"));
36369485SMikore.Li@Sun.COM 	}
36379485SMikore.Li@Sun.COM 	URTW_LEDUNLOCK(sc);
36389485SMikore.Li@Sun.COM }
36399485SMikore.Li@Sun.COM 
36409485SMikore.Li@Sun.COM static int
36419485SMikore.Li@Sun.COM urtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
36429485SMikore.Li@Sun.COM {
36439485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)ic;
36449485SMikore.Li@Sun.COM 	struct ieee80211_node *ni;
36459485SMikore.Li@Sun.COM 	int error = 0;
36469485SMikore.Li@Sun.COM 
36479485SMikore.Li@Sun.COM 	if (sc->sc_scan_id != 0) {
36489485SMikore.Li@Sun.COM 		(void) untimeout(sc->sc_scan_id);
36499485SMikore.Li@Sun.COM 		sc->sc_scan_id = 0;
36509485SMikore.Li@Sun.COM 	}
36519485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
36529485SMikore.Li@Sun.COM 	switch (nstate) {
36539485SMikore.Li@Sun.COM 	case IEEE80211_S_INIT:
36549485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
36559485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "-> IEEE80211_S_INIT...arg(%d)\n",
36569485SMikore.Li@Sun.COM 		    arg));
3657*10364SMikore.Li@Sun.COM 		if (sc->sc_flags & URTW_FLAG_HP)
3658*10364SMikore.Li@Sun.COM 			break;
36599485SMikore.Li@Sun.COM 		(void) urtw_update_msr(sc, nstate);
36609485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
36619485SMikore.Li@Sun.COM 		break;
36629485SMikore.Li@Sun.COM 
36639485SMikore.Li@Sun.COM 	case IEEE80211_S_SCAN:
36649485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
36659485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT,
36669485SMikore.Li@Sun.COM 		    "-> IEEE80211_S_SCAN...arg(%d)...[%d]\n",
36679485SMikore.Li@Sun.COM 		    arg, ieee80211_chan2ieee(ic, ic->ic_curchan)));
36689485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
36699485SMikore.Li@Sun.COM 		if (error) {
36709485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
36719485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "scan setchan failed"));
36729485SMikore.Li@Sun.COM 			break;
36739485SMikore.Li@Sun.COM 		}
36749485SMikore.Li@Sun.COM 		sc->sc_scan_id = timeout(urtw_next_scan, (void *)sc,
36759485SMikore.Li@Sun.COM 		    drv_usectohz(sc->dwelltime * 1000));
36769485SMikore.Li@Sun.COM 		break;
36779485SMikore.Li@Sun.COM 
36789485SMikore.Li@Sun.COM 	case IEEE80211_S_AUTH:
36799485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3680*10364SMikore.Li@Sun.COM 		    "-> IEEE80211_S_AUTH ...arg(%d), chan (%d)\n", arg,
3681*10364SMikore.Li@Sun.COM 		    ieee80211_chan2ieee(ic, ic->ic_curchan)));
36829485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
36839485SMikore.Li@Sun.COM 		if (error) {
36849485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
36859485SMikore.Li@Sun.COM 			    (sc->sc_dev,  CE_CONT, "auth setchan failed"));
36869485SMikore.Li@Sun.COM 		}
36879485SMikore.Li@Sun.COM 		break;
36889485SMikore.Li@Sun.COM 
36899485SMikore.Li@Sun.COM 	case IEEE80211_S_ASSOC:
36909485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3691*10364SMikore.Li@Sun.COM 		    "-> IEEE80211_S_ASSOC ...arg(%d), chan (%d)\n", arg,
3692*10364SMikore.Li@Sun.COM 		    ieee80211_chan2ieee(ic, ic->ic_curchan)));
36939485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
36949485SMikore.Li@Sun.COM 		if (error) {
36959485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
36969485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "assoc setchan failed"));
36979485SMikore.Li@Sun.COM 		}
36989485SMikore.Li@Sun.COM 		break;
36999485SMikore.Li@Sun.COM 
37009485SMikore.Li@Sun.COM 	case IEEE80211_S_RUN:
37019485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
3702*10364SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT,
3703*10364SMikore.Li@Sun.COM 		    "-> IEEE80211_S_RUN ...arg(%d), chan (%d)\n",
3704*10364SMikore.Li@Sun.COM 		    arg, ieee80211_chan2ieee(ic, ic->ic_curchan)));
37059485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
37069485SMikore.Li@Sun.COM 		if (error) {
37079485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
37089485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "run setchan failed"));
37099485SMikore.Li@Sun.COM 			goto fail;
37109485SMikore.Li@Sun.COM 		}
37119485SMikore.Li@Sun.COM 		ni = ic->ic_bss;
37129485SMikore.Li@Sun.COM 		/* setting bssid.  */
37139485SMikore.Li@Sun.COM 		(void) urtw_write32_c(sc, URTW_BSSID,
3714*10364SMikore.Li@Sun.COM 		    ((uint32_t *)(uintptr_t)ni->in_bssid)[0], 0);
37159485SMikore.Li@Sun.COM 		(void) urtw_write16_c(sc, URTW_BSSID + 4,
3716*10364SMikore.Li@Sun.COM 		    ((uint16_t *)(uintptr_t)ni->in_bssid)[2], 0);
37179485SMikore.Li@Sun.COM 		(void) urtw_update_msr(sc, nstate);
37189485SMikore.Li@Sun.COM 
37199485SMikore.Li@Sun.COM 		ni->in_txrate = ni->in_rates.ir_nrates - 1;
37209485SMikore.Li@Sun.COM 		break;
37219485SMikore.Li@Sun.COM 	}
37229485SMikore.Li@Sun.COM fail:
37239485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
37249485SMikore.Li@Sun.COM 
3725*10364SMikore.Li@Sun.COM 	if (error) {
3726*10364SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
3727*10364SMikore.Li@Sun.COM 		    "-> newstate error...arg(%d)\n", error));
37289485SMikore.Li@Sun.COM 		return (EIO);
3729*10364SMikore.Li@Sun.COM 	}
37309485SMikore.Li@Sun.COM 	error = sc->sc_newstate(ic, nstate, arg);
37319485SMikore.Li@Sun.COM 	return (error);
37329485SMikore.Li@Sun.COM }
37339485SMikore.Li@Sun.COM 
37349485SMikore.Li@Sun.COM static void
37359485SMikore.Li@Sun.COM urtw_close_pipes(struct urtw_softc *sc)
37369485SMikore.Li@Sun.COM {
37379485SMikore.Li@Sun.COM 	usb_flags_t flags = USB_FLAGS_SLEEP;
37389485SMikore.Li@Sun.COM 
37399485SMikore.Li@Sun.COM 	if (sc->sc_rxpipe != NULL) {
37409485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
37419485SMikore.Li@Sun.COM 		    sc->sc_rxpipe, flags, NULL, 0);
37429485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
37439485SMikore.Li@Sun.COM 		    sc->sc_rxpipe, flags, NULL, 0);
37449485SMikore.Li@Sun.COM 		sc->sc_rxpipe = NULL;
37459485SMikore.Li@Sun.COM 	}
37469485SMikore.Li@Sun.COM 
37479485SMikore.Li@Sun.COM 	if (sc->sc_txpipe_low != NULL) {
37489485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
37499485SMikore.Li@Sun.COM 		    sc->sc_txpipe_low, flags, NULL, 0);
37509485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
37519485SMikore.Li@Sun.COM 		    sc->sc_txpipe_low, flags, NULL, 0);
37529485SMikore.Li@Sun.COM 		sc->sc_txpipe_low = NULL;
37539485SMikore.Li@Sun.COM 	}
37549485SMikore.Li@Sun.COM 
37559485SMikore.Li@Sun.COM 	if (sc->sc_txpipe_normal != NULL) {
37569485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
37579485SMikore.Li@Sun.COM 		    sc->sc_txpipe_normal, flags, NULL, 0);
37589485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
37599485SMikore.Li@Sun.COM 		    sc->sc_txpipe_normal, flags, NULL, 0);
37609485SMikore.Li@Sun.COM 		sc->sc_txpipe_normal = NULL;
37619485SMikore.Li@Sun.COM 	}
37629485SMikore.Li@Sun.COM }
37639485SMikore.Li@Sun.COM 
37649485SMikore.Li@Sun.COM static int
37659485SMikore.Li@Sun.COM urtw_open_pipes(struct urtw_softc *sc)
37669485SMikore.Li@Sun.COM {
37679485SMikore.Li@Sun.COM 	usb_ep_data_t *ep_node;
37689485SMikore.Li@Sun.COM 	usb_pipe_policy_t policy;
37699485SMikore.Li@Sun.COM 	int err;
3770*10364SMikore.Li@Sun.COM 	uint_t skip = 0;
37719485SMikore.Li@Sun.COM 
37729485SMikore.Li@Sun.COM 	if (sc->sc_rxpipe || sc->sc_txpipe_low || sc->sc_txpipe_normal)
37739485SMikore.Li@Sun.COM 		return (USB_SUCCESS);
37749485SMikore.Li@Sun.COM 
3775*10364SMikore.Li@Sun.COM 	if ((sc->sc_hwrev & URTW_HWREV_8187) == 0) {
3776*10364SMikore.Li@Sun.COM 		skip = 2;
3777*10364SMikore.Li@Sun.COM 	}
37789485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3779*10364SMikore.Li@Sun.COM 	    LOW_PRIORITY_PIPE + skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
37809485SMikore.Li@Sun.COM 
37819485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
37829485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
37839485SMikore.Li@Sun.COM 
37849485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
37859485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
37869485SMikore.Li@Sun.COM 	    &sc->sc_txpipe_low)) != USB_SUCCESS) {
37879485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
37889485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x low priority pipe open failed\n",
37899485SMikore.Li@Sun.COM 		    err));
37909485SMikore.Li@Sun.COM 		goto fail;
37919485SMikore.Li@Sun.COM 	}
37929485SMikore.Li@Sun.COM 
37939485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3794*10364SMikore.Li@Sun.COM 	    NORMAL_PRIORITY_PIPE + skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
37959485SMikore.Li@Sun.COM 
37969485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
37979485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
37989485SMikore.Li@Sun.COM 
37999485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
38009485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
38019485SMikore.Li@Sun.COM 	    &sc->sc_txpipe_normal)) != USB_SUCCESS) {
38029485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
38039485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x failed to open high tx pipe\n",
38049485SMikore.Li@Sun.COM 		    err));
38059485SMikore.Li@Sun.COM 		goto fail;
38069485SMikore.Li@Sun.COM 	}
38079485SMikore.Li@Sun.COM 
38089485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
38099485SMikore.Li@Sun.COM 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
38109485SMikore.Li@Sun.COM 
38119485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
38129485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_RX_DATA_LIST_COUNT;
38139485SMikore.Li@Sun.COM 
38149485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
38159485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
38169485SMikore.Li@Sun.COM 	    &sc->sc_rxpipe)) != USB_SUCCESS) {
38179485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
38189485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x failed to open rx pipe\n", err));
38199485SMikore.Li@Sun.COM 		goto fail;
38209485SMikore.Li@Sun.COM 	}
38219485SMikore.Li@Sun.COM 
38229485SMikore.Li@Sun.COM 	return (USB_SUCCESS);
38239485SMikore.Li@Sun.COM 
38249485SMikore.Li@Sun.COM fail:
38259485SMikore.Li@Sun.COM 	urtw_close_pipes(sc);
38269485SMikore.Li@Sun.COM 	return (USB_FAILURE);
38279485SMikore.Li@Sun.COM }
38289485SMikore.Li@Sun.COM 
38299485SMikore.Li@Sun.COM static int
38309485SMikore.Li@Sun.COM urtw_tx_start(struct urtw_softc *sc, mblk_t *mp, int priority)
38319485SMikore.Li@Sun.COM {
38329485SMikore.Li@Sun.COM 	usb_bulk_req_t *req;
38339485SMikore.Li@Sun.COM 	int err;
38349485SMikore.Li@Sun.COM 
38359485SMikore.Li@Sun.COM 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
38369485SMikore.Li@Sun.COM 	if (req == NULL) {
38379485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
38389485SMikore.Li@Sun.COM 		    "urtw_tx_start(): failed to allocate req"));
38399485SMikore.Li@Sun.COM 		freemsg(mp);
38409485SMikore.Li@Sun.COM 		return (-1);
38419485SMikore.Li@Sun.COM 	}
38429485SMikore.Li@Sun.COM 
38439485SMikore.Li@Sun.COM 	req->bulk_len = MBLKL(mp);
38449485SMikore.Li@Sun.COM 	req->bulk_data = mp;
38459485SMikore.Li@Sun.COM 	req->bulk_client_private = (usb_opaque_t)sc;
38469485SMikore.Li@Sun.COM 	req->bulk_timeout = URTW_TX_TIMEOUT;
38479485SMikore.Li@Sun.COM 	req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
38489485SMikore.Li@Sun.COM 	req->bulk_cb = (priority)?urtw_txeof_normal : urtw_txeof_low;
38499485SMikore.Li@Sun.COM 	req->bulk_exc_cb = (priority)?urtw_txeof_normal: urtw_txeof_low;
38509485SMikore.Li@Sun.COM 	req->bulk_completion_reason = 0;
38519485SMikore.Li@Sun.COM 	req->bulk_cb_flags = 0;
38529485SMikore.Li@Sun.COM 
38539485SMikore.Li@Sun.COM 	if ((err = usb_pipe_bulk_xfer(
38549485SMikore.Li@Sun.COM 	    (priority)?sc->sc_txpipe_normal:sc->sc_txpipe_low, req, 0))
38559485SMikore.Li@Sun.COM 	    != USB_SUCCESS) {
38569485SMikore.Li@Sun.COM 		sc->sc_ic.ic_stats.is_tx_failed++;
38579485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
38589485SMikore.Li@Sun.COM 		    "urtw_tx_start: failed to do tx xfer, %d", err));
38599485SMikore.Li@Sun.COM 		usb_free_bulk_req(req);
38609485SMikore.Li@Sun.COM 		return (EIO);
38619485SMikore.Li@Sun.COM 	}
38629485SMikore.Li@Sun.COM 
38639485SMikore.Li@Sun.COM 	if (priority) {
38649485SMikore.Li@Sun.COM 		sc->sc_tx_normal_queued++;
38659485SMikore.Li@Sun.COM 	} else {
38669485SMikore.Li@Sun.COM 		sc->sc_tx_low_queued++;
38679485SMikore.Li@Sun.COM 	}
38689485SMikore.Li@Sun.COM 
38699485SMikore.Li@Sun.COM 	return (0);
38709485SMikore.Li@Sun.COM }
38719485SMikore.Li@Sun.COM 
38729485SMikore.Li@Sun.COM static int
38739485SMikore.Li@Sun.COM urtw_rx_start(struct urtw_softc *sc)
38749485SMikore.Li@Sun.COM {
38759485SMikore.Li@Sun.COM 	usb_bulk_req_t *req;
38769485SMikore.Li@Sun.COM 	int err;
38779485SMikore.Li@Sun.COM 
38789485SMikore.Li@Sun.COM 	req = usb_alloc_bulk_req(sc->sc_dev, URTW_RXBUF_SIZE, USB_FLAGS_SLEEP);
38799485SMikore.Li@Sun.COM 	if (req == NULL) {
38809485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
38819485SMikore.Li@Sun.COM 		    "urtw_rx_start(): failed to allocate req"));
38829485SMikore.Li@Sun.COM 		return (-1);
38839485SMikore.Li@Sun.COM 	}
38849485SMikore.Li@Sun.COM 
38859485SMikore.Li@Sun.COM 	req->bulk_len		= URTW_RXBUF_SIZE;
38869485SMikore.Li@Sun.COM 	req->bulk_client_private = (usb_opaque_t)sc;
38879485SMikore.Li@Sun.COM 	req->bulk_timeout	= 0;
38889485SMikore.Li@Sun.COM 	req->bulk_attributes	= USB_ATTRS_SHORT_XFER_OK |
38899485SMikore.Li@Sun.COM 	    USB_ATTRS_AUTOCLEARING;
38909485SMikore.Li@Sun.COM 	req->bulk_cb		= urtw_rxeof;
38919485SMikore.Li@Sun.COM 	req->bulk_exc_cb	= urtw_rxeof;
38929485SMikore.Li@Sun.COM 	req->bulk_completion_reason = 0;
38939485SMikore.Li@Sun.COM 	req->bulk_cb_flags	= 0;
38949485SMikore.Li@Sun.COM 
38959485SMikore.Li@Sun.COM 	err = usb_pipe_bulk_xfer(sc->sc_rxpipe, req, 0);
38969485SMikore.Li@Sun.COM 
38979485SMikore.Li@Sun.COM 	if (err != USB_SUCCESS) {
38989485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
38999485SMikore.Li@Sun.COM 		    "urtw_rx_start: failed to do rx xfer, %d", err));
39009485SMikore.Li@Sun.COM 		usb_free_bulk_req(req);
39019485SMikore.Li@Sun.COM 		return (-1);
39029485SMikore.Li@Sun.COM 	}
39039485SMikore.Li@Sun.COM 
39049485SMikore.Li@Sun.COM 	mutex_enter(&sc->rx_lock);
39059485SMikore.Li@Sun.COM 	sc->rx_queued++;
39069485SMikore.Li@Sun.COM 	mutex_exit(&sc->rx_lock);
39079485SMikore.Li@Sun.COM 
39089485SMikore.Li@Sun.COM 	return (0);
39099485SMikore.Li@Sun.COM }
39109485SMikore.Li@Sun.COM 
39119485SMikore.Li@Sun.COM static int
39129485SMikore.Li@Sun.COM urtw_disconnect(dev_info_t *devinfo)
39139485SMikore.Li@Sun.COM {
39149485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
39159485SMikore.Li@Sun.COM 
39169485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
39179485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HOTPLUG,
39189485SMikore.Li@Sun.COM 	    (sc->sc_dev, CE_CONT, "urtw_offline()\n"));
39199485SMikore.Li@Sun.COM 
39209485SMikore.Li@Sun.COM 	if (URTW_IS_RUNNING(sc)) {
39219485SMikore.Li@Sun.COM 		urtw_stop(sc);
39229485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
39239485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
39249485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
39259485SMikore.Li@Sun.COM 	}
3926*10364SMikore.Li@Sun.COM 	sc->sc_flags |= URTW_FLAG_HP;
3927*10364SMikore.Li@Sun.COM 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3928*10364SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(&sc->sc_ic);
39299485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
39309485SMikore.Li@Sun.COM }
39319485SMikore.Li@Sun.COM 
39329485SMikore.Li@Sun.COM static int
39339485SMikore.Li@Sun.COM urtw_reconnect(dev_info_t *devinfo)
39349485SMikore.Li@Sun.COM {
39359485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
39369485SMikore.Li@Sun.COM 	int error = 0;
39379485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
39389485SMikore.Li@Sun.COM 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
39399485SMikore.Li@Sun.COM 	    USB_CHK_ALL, NULL) != USB_SUCCESS)
39409485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
39419485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HOTPLUG, (sc->sc_dev, CE_CONT,
39429485SMikore.Li@Sun.COM 	    "urtw_online()\n"));
3943*10364SMikore.Li@Sun.COM 	sc->sc_flags &= ~URTW_FLAG_HP;
39449485SMikore.Li@Sun.COM 	if (URTW_IS_PLUGIN_ONLINE(sc)) {
3945*10364SMikore.Li@Sun.COM 		error = sc->urtw_init(sc);
39469485SMikore.Li@Sun.COM 		if (!error) {
39479485SMikore.Li@Sun.COM 			URTW_LOCK(sc);
39489485SMikore.Li@Sun.COM 			sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
39499485SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
39509485SMikore.Li@Sun.COM 		}
39519485SMikore.Li@Sun.COM 	}
3952*10364SMikore.Li@Sun.COM 	return (error? DDI_FAILURE: DDI_SUCCESS);
39539485SMikore.Li@Sun.COM }
39549485SMikore.Li@Sun.COM 
39559485SMikore.Li@Sun.COM static mblk_t *
39569485SMikore.Li@Sun.COM urtw_m_tx(void *arg, mblk_t *mp)
39579485SMikore.Li@Sun.COM {
39589485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
39599485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
39609485SMikore.Li@Sun.COM 	mblk_t *next;
39619485SMikore.Li@Sun.COM 
39629485SMikore.Li@Sun.COM 	if ((ic->ic_state != IEEE80211_S_RUN) ||
39639485SMikore.Li@Sun.COM 	    URTW_IS_SUSPENDING(sc)) {
39649485SMikore.Li@Sun.COM 		freemsgchain(mp);
39659485SMikore.Li@Sun.COM 		return (NULL);
39669485SMikore.Li@Sun.COM 	}
39679485SMikore.Li@Sun.COM 
39689485SMikore.Li@Sun.COM 	while (mp != NULL) {
39699485SMikore.Li@Sun.COM 		next = mp->b_next;
39709485SMikore.Li@Sun.COM 		mp->b_next = NULL;
39719485SMikore.Li@Sun.COM 		if (urtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
39729485SMikore.Li@Sun.COM 			mp->b_next = next;
39739485SMikore.Li@Sun.COM 			break;
39749485SMikore.Li@Sun.COM 		}
39759485SMikore.Li@Sun.COM 		mp = next;
39769485SMikore.Li@Sun.COM 	}
39779485SMikore.Li@Sun.COM 	return (mp);
39789485SMikore.Li@Sun.COM }
39799485SMikore.Li@Sun.COM 
39809485SMikore.Li@Sun.COM static int
39819485SMikore.Li@Sun.COM urtw_m_start(void *arg)
39829485SMikore.Li@Sun.COM {
39839485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
39849485SMikore.Li@Sun.COM 	int error = 0;
39859485SMikore.Li@Sun.COM 
39869485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE,
3987*10364SMikore.Li@Sun.COM 	    (sc->sc_dev, CE_CONT, "urtw_m_start\n"));
3988*10364SMikore.Li@Sun.COM 	error = sc->urtw_init(sc);
39899485SMikore.Li@Sun.COM 	return (error);
39909485SMikore.Li@Sun.COM }
39919485SMikore.Li@Sun.COM 
39929485SMikore.Li@Sun.COM static void
39939485SMikore.Li@Sun.COM urtw_m_stop(void *arg)
39949485SMikore.Li@Sun.COM {
39959485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
39969485SMikore.Li@Sun.COM 
39979485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
39989485SMikore.Li@Sun.COM 	    "urtw_m_stop()\n"));
39999485SMikore.Li@Sun.COM 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
40009485SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(&sc->sc_ic);
40019485SMikore.Li@Sun.COM 	(void) urtw_stop(sc);
40029485SMikore.Li@Sun.COM }
40039485SMikore.Li@Sun.COM 
40049485SMikore.Li@Sun.COM /*ARGSUSED*/
40059485SMikore.Li@Sun.COM static int
40069485SMikore.Li@Sun.COM urtw_m_unicst(void *arg, const uint8_t *macaddr)
40079485SMikore.Li@Sun.COM {
40089485SMikore.Li@Sun.COM 	return (ENOTSUP);
40099485SMikore.Li@Sun.COM }
40109485SMikore.Li@Sun.COM 
40119485SMikore.Li@Sun.COM /*ARGSUSED*/
40129485SMikore.Li@Sun.COM static int
40139485SMikore.Li@Sun.COM urtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
40149485SMikore.Li@Sun.COM {
40159485SMikore.Li@Sun.COM 	return (ENOTSUP);
40169485SMikore.Li@Sun.COM }
40179485SMikore.Li@Sun.COM 
40189485SMikore.Li@Sun.COM /*ARGSUSED*/
40199485SMikore.Li@Sun.COM static int
40209485SMikore.Li@Sun.COM urtw_m_promisc(void *arg, boolean_t on)
40219485SMikore.Li@Sun.COM {
40229485SMikore.Li@Sun.COM 	return (0);
40239485SMikore.Li@Sun.COM }
40249485SMikore.Li@Sun.COM 
40259485SMikore.Li@Sun.COM static int
4026*10364SMikore.Li@Sun.COM urtw_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4027*10364SMikore.Li@Sun.COM     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
4028*10364SMikore.Li@Sun.COM {
4029*10364SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
4030*10364SMikore.Li@Sun.COM 	int err = 0;
4031*10364SMikore.Li@Sun.COM 
4032*10364SMikore.Li@Sun.COM 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
4033*10364SMikore.Li@Sun.COM 	    pr_flags, wldp_length, wldp_buf, perm);
4034*10364SMikore.Li@Sun.COM 	return (err);
4035*10364SMikore.Li@Sun.COM }
4036*10364SMikore.Li@Sun.COM 
4037*10364SMikore.Li@Sun.COM static int
40389485SMikore.Li@Sun.COM urtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
40399485SMikore.Li@Sun.COM     uint_t wldp_length, const void *wldp_buf)
40409485SMikore.Li@Sun.COM {
40419485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
40429485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
40439485SMikore.Li@Sun.COM 	int err;
40449485SMikore.Li@Sun.COM 
40459485SMikore.Li@Sun.COM 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
40469485SMikore.Li@Sun.COM 	    wldp_length, wldp_buf);
4047*10364SMikore.Li@Sun.COM 	URTW_LOCK(sc);
40489485SMikore.Li@Sun.COM 	if (err == ENETRESET) {
4049*10364SMikore.Li@Sun.COM 		if (URTW_IS_RUNNING(sc) && ic->ic_des_esslen) {
4050*10364SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
4051*10364SMikore.Li@Sun.COM 			err = sc->urtw_init(sc);
4052*10364SMikore.Li@Sun.COM 			if (err) {
4053*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4054*10364SMikore.Li@Sun.COM 				    (sc->sc_dev, CE_CONT,
4055*10364SMikore.Li@Sun.COM 				    "urtw: setprop failed\n"));
4056*10364SMikore.Li@Sun.COM 				return (err);
4057*10364SMikore.Li@Sun.COM 			}
40589485SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
4059*10364SMikore.Li@Sun.COM 			URTW_LOCK(sc);
40609485SMikore.Li@Sun.COM 		}
40619485SMikore.Li@Sun.COM 		err = 0;
40629485SMikore.Li@Sun.COM 	}
4063*10364SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
40649485SMikore.Li@Sun.COM 	return (err);
40659485SMikore.Li@Sun.COM }
40669485SMikore.Li@Sun.COM 
40679485SMikore.Li@Sun.COM static void
40689485SMikore.Li@Sun.COM urtw_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
40699485SMikore.Li@Sun.COM {
40709485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
40719485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
40729485SMikore.Li@Sun.COM 	int err;
40739485SMikore.Li@Sun.COM 
40749485SMikore.Li@Sun.COM 	err = ieee80211_ioctl(ic, wq, mp);
4075*10364SMikore.Li@Sun.COM 	URTW_LOCK(sc);
40769485SMikore.Li@Sun.COM 	if (err == ENETRESET) {
4077*10364SMikore.Li@Sun.COM 		if (URTW_IS_RUNNING(sc) && ic->ic_des_esslen) {
4078*10364SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
4079*10364SMikore.Li@Sun.COM 			err = sc->urtw_init(sc);
4080*10364SMikore.Li@Sun.COM 			if (err) {
4081*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4082*10364SMikore.Li@Sun.COM 				    (sc->sc_dev,
4083*10364SMikore.Li@Sun.COM 				    CE_CONT, "urtw: dev init failed\n"));
4084*10364SMikore.Li@Sun.COM 				return;
4085*10364SMikore.Li@Sun.COM 			}
4086*10364SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
4087*10364SMikore.Li@Sun.COM 			URTW_LOCK(sc);
40889485SMikore.Li@Sun.COM 		}
40899485SMikore.Li@Sun.COM 	}
4090*10364SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
40919485SMikore.Li@Sun.COM }
40929485SMikore.Li@Sun.COM 
40939485SMikore.Li@Sun.COM static int
40949485SMikore.Li@Sun.COM urtw_m_stat(void *arg, uint_t stat, uint64_t *val)
40959485SMikore.Li@Sun.COM {
40969485SMikore.Li@Sun.COM 	struct urtw_softc *sc  = (struct urtw_softc *)arg;
40979485SMikore.Li@Sun.COM 	ieee80211com_t	*ic = &sc->sc_ic;
40989485SMikore.Li@Sun.COM 	ieee80211_node_t *ni = 0;
40999485SMikore.Li@Sun.COM 	struct ieee80211_rateset *rs = 0;
41009485SMikore.Li@Sun.COM 
41019485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
41029485SMikore.Li@Sun.COM 	switch (stat) {
41039485SMikore.Li@Sun.COM 	case MAC_STAT_IFSPEED:
41049485SMikore.Li@Sun.COM 		ni = ic->ic_bss;
41059485SMikore.Li@Sun.COM 		rs = &ni->in_rates;
41069485SMikore.Li@Sun.COM 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
41079485SMikore.Li@Sun.COM 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
41089485SMikore.Li@Sun.COM 		    : ic->ic_fixed_rate) / 2 * 1000000;
41099485SMikore.Li@Sun.COM 		break;
41109485SMikore.Li@Sun.COM 	case MAC_STAT_NOXMTBUF:
41119485SMikore.Li@Sun.COM 		*val = sc->sc_tx_nobuf;
41129485SMikore.Li@Sun.COM 		break;
41139485SMikore.Li@Sun.COM 	case MAC_STAT_NORCVBUF:
41149485SMikore.Li@Sun.COM 		*val = sc->sc_rx_nobuf;
41159485SMikore.Li@Sun.COM 		break;
41169485SMikore.Li@Sun.COM 	case MAC_STAT_IERRORS:
41179485SMikore.Li@Sun.COM 		*val = sc->sc_rx_err;
41189485SMikore.Li@Sun.COM 		break;
41199485SMikore.Li@Sun.COM 	case MAC_STAT_RBYTES:
41209485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_rx_bytes;
41219485SMikore.Li@Sun.COM 		break;
41229485SMikore.Li@Sun.COM 	case MAC_STAT_IPACKETS:
41239485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_rx_frags;
41249485SMikore.Li@Sun.COM 		break;
41259485SMikore.Li@Sun.COM 	case MAC_STAT_OBYTES:
41269485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_bytes;
41279485SMikore.Li@Sun.COM 		break;
41289485SMikore.Li@Sun.COM 	case MAC_STAT_OPACKETS:
41299485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_frags;
41309485SMikore.Li@Sun.COM 		break;
41319485SMikore.Li@Sun.COM 	case MAC_STAT_OERRORS:
41329485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_failed;
41339485SMikore.Li@Sun.COM 		break;
41349485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_FRAGS:
41359485SMikore.Li@Sun.COM 	case WIFI_STAT_MCAST_TX:
41369485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_FAILED:
41379485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_RETRANS:
41389485SMikore.Li@Sun.COM 	case WIFI_STAT_RTS_SUCCESS:
41399485SMikore.Li@Sun.COM 	case WIFI_STAT_RTS_FAILURE:
41409485SMikore.Li@Sun.COM 	case WIFI_STAT_ACK_FAILURE:
41419485SMikore.Li@Sun.COM 	case WIFI_STAT_RX_FRAGS:
41429485SMikore.Li@Sun.COM 	case WIFI_STAT_MCAST_RX:
41439485SMikore.Li@Sun.COM 	case WIFI_STAT_FCS_ERRORS:
41449485SMikore.Li@Sun.COM 	case WIFI_STAT_WEP_ERRORS:
41459485SMikore.Li@Sun.COM 	case WIFI_STAT_RX_DUPS:
41469485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
41479485SMikore.Li@Sun.COM 		return (ieee80211_stat(ic, stat, val));
41489485SMikore.Li@Sun.COM 	default:
41499485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
41509485SMikore.Li@Sun.COM 		return (ENOTSUP);
41519485SMikore.Li@Sun.COM 	}
41529485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
41539485SMikore.Li@Sun.COM 
41549485SMikore.Li@Sun.COM 	return (0);
41559485SMikore.Li@Sun.COM }
41569485SMikore.Li@Sun.COM 
41579485SMikore.Li@Sun.COM static void
41589485SMikore.Li@Sun.COM urtw_watchdog(void *arg)
41599485SMikore.Li@Sun.COM {
41609485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
41619485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
41629485SMikore.Li@Sun.COM 
41639485SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(ic);
41649485SMikore.Li@Sun.COM 
41659485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
41669485SMikore.Li@Sun.COM 	if (URTW_IS_NOT_RUNNING(sc)) {
41679485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
41689485SMikore.Li@Sun.COM 		return;
41699485SMikore.Li@Sun.COM 	}
41709485SMikore.Li@Sun.COM 
41719485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
41729485SMikore.Li@Sun.COM 	switch (ic->ic_state) {
41739485SMikore.Li@Sun.COM 		case IEEE80211_S_AUTH:
41749485SMikore.Li@Sun.COM 		case IEEE80211_S_ASSOC:
4175*10364SMikore.Li@Sun.COM 			if (ic->ic_bss->in_fails > 0) {
41769485SMikore.Li@Sun.COM 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
4177*10364SMikore.Li@Sun.COM 				URTW8187_DBG(URTW_DEBUG_ACTIVE,
4178*10364SMikore.Li@Sun.COM 				    (sc->sc_dev, CE_CONT,
4179*10364SMikore.Li@Sun.COM 				    "urtw: watchdog begin\n"));
4180*10364SMikore.Li@Sun.COM 			} else
41819485SMikore.Li@Sun.COM 				ieee80211_watchdog(ic);
41829485SMikore.Li@Sun.COM 			break;
41839485SMikore.Li@Sun.COM 	}
41849485SMikore.Li@Sun.COM }
41859485SMikore.Li@Sun.COM 
41869485SMikore.Li@Sun.COM 
41879485SMikore.Li@Sun.COM static int
41889485SMikore.Li@Sun.COM urtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
41899485SMikore.Li@Sun.COM {
41909485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
41919485SMikore.Li@Sun.COM 	struct ieee80211com *ic;
41929485SMikore.Li@Sun.COM 	int error, i, instance;
41939485SMikore.Li@Sun.COM 	uint32_t data = 0;
4194*10364SMikore.Li@Sun.COM 	uint8_t data8 = 0;
41959485SMikore.Li@Sun.COM 	char strbuf[32];
41969485SMikore.Li@Sun.COM 	wifi_data_t wd = { 0 };
41979485SMikore.Li@Sun.COM 	mac_register_t *macp;
4198*10364SMikore.Li@Sun.COM 	struct urtw_type *e = 0;
4199*10364SMikore.Li@Sun.COM 	char *urtw_name = NULL;
42009485SMikore.Li@Sun.COM 
42019485SMikore.Li@Sun.COM 	switch (cmd) {
42029485SMikore.Li@Sun.COM 	case DDI_ATTACH:
42039485SMikore.Li@Sun.COM 		break;
42049485SMikore.Li@Sun.COM 	case DDI_RESUME:
42059485SMikore.Li@Sun.COM 		sc = ddi_get_soft_state(urtw_soft_state_p,
42069485SMikore.Li@Sun.COM 		    ddi_get_instance(devinfo));
42079485SMikore.Li@Sun.COM 		ASSERT(sc != NULL);
42089485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE,
42099485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "urtw: resume\n"));
42109485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
42119485SMikore.Li@Sun.COM 		sc->sc_flags &= ~URTW_FLAG_SUSPEND;
42129485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
42139485SMikore.Li@Sun.COM 		if (URTW_IS_PLUGIN_ONLINE(sc)) {
4214*10364SMikore.Li@Sun.COM 			error = sc->urtw_init(sc);
42159485SMikore.Li@Sun.COM 			if (error == 0) {
42169485SMikore.Li@Sun.COM 				URTW_LOCK(sc);
42179485SMikore.Li@Sun.COM 				sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
42189485SMikore.Li@Sun.COM 				URTW_UNLOCK(sc);
42199485SMikore.Li@Sun.COM 			}
42209485SMikore.Li@Sun.COM 		}
42219485SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
42229485SMikore.Li@Sun.COM 	default:
42239485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
42249485SMikore.Li@Sun.COM 	}
42259485SMikore.Li@Sun.COM 
42269485SMikore.Li@Sun.COM 	instance = ddi_get_instance(devinfo);
42279485SMikore.Li@Sun.COM 
42289485SMikore.Li@Sun.COM 	if (ddi_soft_state_zalloc(urtw_soft_state_p, instance) != DDI_SUCCESS) {
42299485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach:unable to alloc soft_state_p\n");
42309485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
42319485SMikore.Li@Sun.COM 	}
42329485SMikore.Li@Sun.COM 
42339485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, instance);
42349485SMikore.Li@Sun.COM 	ic = (ieee80211com_t *)&sc->sc_ic;
42359485SMikore.Li@Sun.COM 	sc->sc_dev = devinfo;
42369485SMikore.Li@Sun.COM 
42379485SMikore.Li@Sun.COM 	if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) {
42389485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: usb_client_attach failed\n");
42399485SMikore.Li@Sun.COM 		goto fail1;
42409485SMikore.Li@Sun.COM 	}
42419485SMikore.Li@Sun.COM 
42429485SMikore.Li@Sun.COM 	if (usb_get_dev_data(devinfo, &sc->sc_udev,
42439485SMikore.Li@Sun.COM 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
42449485SMikore.Li@Sun.COM 		sc->sc_udev = NULL;
42459485SMikore.Li@Sun.COM 		goto fail2;
42469485SMikore.Li@Sun.COM 	}
42479485SMikore.Li@Sun.COM 
42489485SMikore.Li@Sun.COM 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
42499485SMikore.Li@Sun.COM 	mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL);
42509485SMikore.Li@Sun.COM 	mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL);
42519485SMikore.Li@Sun.COM 	mutex_init(&sc->sc_ledlock, NULL, MUTEX_DRIVER, NULL);
42529485SMikore.Li@Sun.COM 
4253*10364SMikore.Li@Sun.COM 	e = urtw_lookup(sc->sc_udev->dev_descr->idVendor,
4254*10364SMikore.Li@Sun.COM 	    sc->sc_udev->dev_descr->idProduct);
4255*10364SMikore.Li@Sun.COM 	if (e == NULL) {
4256*10364SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "(urtw) unknown device\n");
4257*10364SMikore.Li@Sun.COM 		goto fail2;
4258*10364SMikore.Li@Sun.COM 	}
4259*10364SMikore.Li@Sun.COM 	sc->sc_hwrev = e->rev;
4260*10364SMikore.Li@Sun.COM 
4261*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
4262*10364SMikore.Li@Sun.COM 		(void) urtw_read32_c(sc, URTW_TX_CONF, &data, 0);
4263*10364SMikore.Li@Sun.COM 		data &= URTW_TX_HWREV_MASK;
4264*10364SMikore.Li@Sun.COM 		switch (data) {
4265*10364SMikore.Li@Sun.COM 		case URTW_TX_HWREV_8187_D:
4266*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187_D;
4267*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187 rev. D";
4268*10364SMikore.Li@Sun.COM 			break;
4269*10364SMikore.Li@Sun.COM 		case URTW_TX_HWREV_8187B_D:
4270*10364SMikore.Li@Sun.COM 			/*
4271*10364SMikore.Li@Sun.COM 			 * Detect Realtek RTL8187B devices that use
4272*10364SMikore.Li@Sun.COM 			 * USB IDs of RTL8187.
4273*10364SMikore.Li@Sun.COM 			 */
4274*10364SMikore.Li@Sun.COM 			sc->sc_hwrev = URTW_HWREV_8187B | URTW_HWREV_8187B_B;
4275*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187B rev. B (early)";
4276*10364SMikore.Li@Sun.COM 			break;
4277*10364SMikore.Li@Sun.COM 		default:
4278*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187_B;
4279*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187 rev. B (default)";
4280*10364SMikore.Li@Sun.COM 			break;
4281*10364SMikore.Li@Sun.COM 		}
4282*10364SMikore.Li@Sun.COM 	} else {
4283*10364SMikore.Li@Sun.COM 		/* RTL8187B hwrev register. */
4284*10364SMikore.Li@Sun.COM 		(void) urtw_read8_c(sc, URTW_8187B_HWREV, &data8, 0);
4285*10364SMikore.Li@Sun.COM 		switch (data8) {
4286*10364SMikore.Li@Sun.COM 		case URTW_8187B_HWREV_8187B_B:
4287*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
4288*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187B rev. B";
4289*10364SMikore.Li@Sun.COM 			break;
4290*10364SMikore.Li@Sun.COM 		case URTW_8187B_HWREV_8187B_D:
4291*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187B_D;
4292*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187B rev. D";
4293*10364SMikore.Li@Sun.COM 			break;
4294*10364SMikore.Li@Sun.COM 		case URTW_8187B_HWREV_8187B_E:
4295*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187B_E;
4296*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187B rev. E";
4297*10364SMikore.Li@Sun.COM 			break;
4298*10364SMikore.Li@Sun.COM 		default:
4299*10364SMikore.Li@Sun.COM 			sc->sc_hwrev |= URTW_HWREV_8187B_B;
4300*10364SMikore.Li@Sun.COM 			urtw_name = "RTL8187B rev. B (default)";
4301*10364SMikore.Li@Sun.COM 			break;
4302*10364SMikore.Li@Sun.COM 		}
4303*10364SMikore.Li@Sun.COM 	}
4304*10364SMikore.Li@Sun.COM 
4305*10364SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
4306*10364SMikore.Li@Sun.COM 	    "urtw_attach: actual device is %s\n", urtw_name));
4307*10364SMikore.Li@Sun.COM 	if (sc->sc_hwrev & URTW_HWREV_8187) {
4308*10364SMikore.Li@Sun.COM 		sc->urtw_init = urtw_8187_init;
4309*10364SMikore.Li@Sun.COM 	} else {
4310*10364SMikore.Li@Sun.COM 		sc->urtw_init = urtw_8187b_init;
4311*10364SMikore.Li@Sun.COM 	}
4312*10364SMikore.Li@Sun.COM 
4313*10364SMikore.Li@Sun.COM 	if (urtw_read32_c(sc, URTW_RX, &data, 0))
43149485SMikore.Li@Sun.COM 		goto fail3;
43159485SMikore.Li@Sun.COM 	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
43169485SMikore.Li@Sun.COM 	    URTW_EEPROM_93C46;
43179485SMikore.Li@Sun.COM 	if (sc->sc_epromtype == URTW_EEPROM_93C56)
43189485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
43199485SMikore.Li@Sun.COM 		    "urtw_attach: eprom is 93C56\n"));
43209485SMikore.Li@Sun.COM 	else
43219485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
43229485SMikore.Li@Sun.COM 		    "urtw_attach: eprom is 93C46\n"));
43239485SMikore.Li@Sun.COM 	error = urtw_get_rfchip(sc);
43249485SMikore.Li@Sun.COM 	if (error != 0)
43259485SMikore.Li@Sun.COM 		goto fail3;
43269485SMikore.Li@Sun.COM 	error = urtw_get_macaddr(sc);
43279485SMikore.Li@Sun.COM 	if (error != 0)
43289485SMikore.Li@Sun.COM 		goto fail3;
43299485SMikore.Li@Sun.COM 	error = urtw_get_txpwr(sc);
43309485SMikore.Li@Sun.COM 	if (error != 0)
43319485SMikore.Li@Sun.COM 		goto fail3;
43329485SMikore.Li@Sun.COM 	error = urtw_led_init(sc);		/* XXX incompleted  */
43339485SMikore.Li@Sun.COM 	if (error != 0)
43349485SMikore.Li@Sun.COM 		goto fail3;
43359485SMikore.Li@Sun.COM 
43369485SMikore.Li@Sun.COM 	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
43379485SMikore.Li@Sun.COM 	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
43389485SMikore.Li@Sun.COM 	sc->sc_currate = 3;
43399485SMikore.Li@Sun.COM 	/* XXX for what?  */
43409485SMikore.Li@Sun.COM 	sc->sc_preamble_mode = 2;
43419485SMikore.Li@Sun.COM 
43429485SMikore.Li@Sun.COM 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
43439485SMikore.Li@Sun.COM 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
43449485SMikore.Li@Sun.COM 	ic->ic_state = IEEE80211_S_INIT;
43459485SMikore.Li@Sun.COM 
43469485SMikore.Li@Sun.COM 	ic->ic_maxrssi = 95;
43479485SMikore.Li@Sun.COM 	ic->ic_xmit = urtw_send;
43489485SMikore.Li@Sun.COM 
43499485SMikore.Li@Sun.COM 	ic->ic_caps |= IEEE80211_C_WPA | /* Support WPA/WPA2 */
43509485SMikore.Li@Sun.COM 	    IEEE80211_C_TXPMGT |	/* tx power management */
43519485SMikore.Li@Sun.COM 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
43529485SMikore.Li@Sun.COM 	    IEEE80211_C_SHSLOT;	/* short slot time supported */
43539485SMikore.Li@Sun.COM 	/* set supported .11b and .11g rates */
43549485SMikore.Li@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11B] = urtw_rateset_11b;
43559485SMikore.Li@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11G] = urtw_rateset_11g;
43569485SMikore.Li@Sun.COM 
43579485SMikore.Li@Sun.COM 	/* set supported .11b and .11g channels (1 through 11) */
43589485SMikore.Li@Sun.COM 	for (i = 1; i <= 11; i++) {
43599485SMikore.Li@Sun.COM 		ic->ic_sup_channels[i].ich_freq =
43609485SMikore.Li@Sun.COM 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
43619485SMikore.Li@Sun.COM 		ic->ic_sup_channels[i].ich_flags =
43629485SMikore.Li@Sun.COM 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN |
43639485SMikore.Li@Sun.COM 		    IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM;
43649485SMikore.Li@Sun.COM 	}
43659485SMikore.Li@Sun.COM 
43669485SMikore.Li@Sun.COM 	ieee80211_attach(ic);
4367*10364SMikore.Li@Sun.COM 	ic->ic_ibss_chan = &ic->ic_sup_channels[1];
4368*10364SMikore.Li@Sun.COM 	ic->ic_curchan = ic->ic_ibss_chan;
43699485SMikore.Li@Sun.COM 
43709485SMikore.Li@Sun.COM 	/* register WPA door */
43719485SMikore.Li@Sun.COM 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
43729485SMikore.Li@Sun.COM 	    ddi_get_instance(devinfo));
43739485SMikore.Li@Sun.COM 
43749485SMikore.Li@Sun.COM 	/* override state transition machine */
43759485SMikore.Li@Sun.COM 	sc->sc_newstate = ic->ic_newstate;
43769485SMikore.Li@Sun.COM 	ic->ic_newstate = urtw_newstate;
43779485SMikore.Li@Sun.COM 	ic->ic_watchdog = urtw_watchdog;
43789485SMikore.Li@Sun.COM 	ieee80211_media_init(ic);
43799485SMikore.Li@Sun.COM 	ic->ic_def_txkey = 0;
43809485SMikore.Li@Sun.COM 
4381*10364SMikore.Li@Sun.COM 	sc->dwelltime = 250;
43829485SMikore.Li@Sun.COM 	sc->sc_flags = 0;
43839485SMikore.Li@Sun.COM 
43849485SMikore.Li@Sun.COM 	/*
43859485SMikore.Li@Sun.COM 	 * Provide initial settings for the WiFi plugin; whenever this
43869485SMikore.Li@Sun.COM 	 * information changes, we need to call mac_plugindata_update()
43879485SMikore.Li@Sun.COM 	 */
43889485SMikore.Li@Sun.COM 	wd.wd_opmode = ic->ic_opmode;
43899485SMikore.Li@Sun.COM 	wd.wd_secalloc = WIFI_SEC_NONE;
43909485SMikore.Li@Sun.COM 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
43919485SMikore.Li@Sun.COM 
43929485SMikore.Li@Sun.COM 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
43939485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
43949485SMikore.Li@Sun.COM 		    "MAC version alloc failed\n"));
43959485SMikore.Li@Sun.COM 		goto fail4;
43969485SMikore.Li@Sun.COM 	}
43979485SMikore.Li@Sun.COM 
43989485SMikore.Li@Sun.COM 	macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
43999485SMikore.Li@Sun.COM 	macp->m_driver = sc;
44009485SMikore.Li@Sun.COM 	macp->m_dip = devinfo;
44019485SMikore.Li@Sun.COM 	macp->m_src_addr = ic->ic_macaddr;
44029485SMikore.Li@Sun.COM 	macp->m_callbacks = &urtw_m_callbacks;
44039485SMikore.Li@Sun.COM 	macp->m_min_sdu	= 0;
44049485SMikore.Li@Sun.COM 	macp->m_max_sdu	= IEEE80211_MTU;
44059485SMikore.Li@Sun.COM 	macp->m_pdata = &wd;
44069485SMikore.Li@Sun.COM 	macp->m_pdata_size = sizeof (wd);
44079485SMikore.Li@Sun.COM 
44089485SMikore.Li@Sun.COM 	error = mac_register(macp, &ic->ic_mach);
44099485SMikore.Li@Sun.COM 	mac_free(macp);
44109485SMikore.Li@Sun.COM 	if (error != 0) {
44119485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: mac_register() err %x\n", error);
44129485SMikore.Li@Sun.COM 		goto fail4;
44139485SMikore.Li@Sun.COM 	}
44149485SMikore.Li@Sun.COM 
44159485SMikore.Li@Sun.COM 	if (usb_register_hotplug_cbs(devinfo, urtw_disconnect,
44169485SMikore.Li@Sun.COM 	    urtw_reconnect) != USB_SUCCESS) {
44179485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: failed to register events");
44189485SMikore.Li@Sun.COM 		goto fail5;
44199485SMikore.Li@Sun.COM 	}
44209485SMikore.Li@Sun.COM 
44219485SMikore.Li@Sun.COM 	/*
44229485SMikore.Li@Sun.COM 	 * Create minor node of type DDI_NT_NET_WIFI
44239485SMikore.Li@Sun.COM 	 */
44249485SMikore.Li@Sun.COM 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
44259485SMikore.Li@Sun.COM 	    "urtw", instance);
44269485SMikore.Li@Sun.COM 	error = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
44279485SMikore.Li@Sun.COM 	    instance + 1, DDI_NT_NET_WIFI, 0);
44289485SMikore.Li@Sun.COM 
44299485SMikore.Li@Sun.COM 	if (error != DDI_SUCCESS)
44309485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw: ddi_create_minor_node() failed\n");
44319485SMikore.Li@Sun.COM 	/*
44329485SMikore.Li@Sun.COM 	 * Notify link is down now
44339485SMikore.Li@Sun.COM 	 */
44349485SMikore.Li@Sun.COM 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
44359485SMikore.Li@Sun.COM 
44369485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
44379485SMikore.Li@Sun.COM 	    "urtw_attach: successfully.\n"));
44389485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
44399485SMikore.Li@Sun.COM fail5:
4440*10364SMikore.Li@Sun.COM 	(void) mac_disable(ic->ic_mach);
44419485SMikore.Li@Sun.COM 	(void) mac_unregister(ic->ic_mach);
44429485SMikore.Li@Sun.COM fail4:
44439485SMikore.Li@Sun.COM 	ieee80211_detach(ic);
44449485SMikore.Li@Sun.COM fail3:
44459485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_genlock);
44469485SMikore.Li@Sun.COM 	mutex_destroy(&sc->tx_lock);
44479485SMikore.Li@Sun.COM 	mutex_destroy(&sc->rx_lock);
44489485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_ledlock);
44499485SMikore.Li@Sun.COM fail2:
44509485SMikore.Li@Sun.COM 	usb_client_detach(sc->sc_dev, sc->sc_udev);
44519485SMikore.Li@Sun.COM fail1:
44529485SMikore.Li@Sun.COM 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
44539485SMikore.Li@Sun.COM 
44549485SMikore.Li@Sun.COM 	return (DDI_FAILURE);
44559485SMikore.Li@Sun.COM }
44569485SMikore.Li@Sun.COM 
44579485SMikore.Li@Sun.COM static int
44589485SMikore.Li@Sun.COM urtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
44599485SMikore.Li@Sun.COM {
44609485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
44619485SMikore.Li@Sun.COM 
44629485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
44639485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev,
44649485SMikore.Li@Sun.COM 	    CE_CONT, "urtw_detach()\n"));
44659485SMikore.Li@Sun.COM 
44669485SMikore.Li@Sun.COM 	switch (cmd) {
44679485SMikore.Li@Sun.COM 	case DDI_DETACH:
44689485SMikore.Li@Sun.COM 		break;
44699485SMikore.Li@Sun.COM 	case DDI_SUSPEND:
44709485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ATTACH,
44719485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "urtw: suspend\n"));
44729485SMikore.Li@Sun.COM 
44739485SMikore.Li@Sun.COM 		ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
44749485SMikore.Li@Sun.COM 		ieee80211_stop_watchdog(&sc->sc_ic);
44759485SMikore.Li@Sun.COM 
44769485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
44779485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_SUSPEND;
44789485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
44799485SMikore.Li@Sun.COM 		if (URTW_IS_RUNNING(sc)) {
44809485SMikore.Li@Sun.COM 			urtw_stop(sc);
44819485SMikore.Li@Sun.COM 			URTW_LOCK(sc);
44829485SMikore.Li@Sun.COM 			sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
44839485SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
44849485SMikore.Li@Sun.COM 		}
44859485SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
44869485SMikore.Li@Sun.COM 	default:
44879485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
44889485SMikore.Li@Sun.COM 	}
44899485SMikore.Li@Sun.COM 
44909485SMikore.Li@Sun.COM 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
44919485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
44929485SMikore.Li@Sun.COM 	urtw_stop(sc);
44939485SMikore.Li@Sun.COM 	/*
44949485SMikore.Li@Sun.COM 	 * Unregister from the MAC layer subsystem
44959485SMikore.Li@Sun.COM 	 */
44969485SMikore.Li@Sun.COM 	(void) mac_unregister(sc->sc_ic.ic_mach);
44979485SMikore.Li@Sun.COM 
44989485SMikore.Li@Sun.COM 	ieee80211_detach(&sc->sc_ic);
44999485SMikore.Li@Sun.COM 	usb_unregister_hotplug_cbs(devinfo);
45009485SMikore.Li@Sun.COM 	usb_client_detach(devinfo, sc->sc_udev);
45019485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_genlock);
45029485SMikore.Li@Sun.COM 	mutex_destroy(&sc->tx_lock);
45039485SMikore.Li@Sun.COM 	mutex_destroy(&sc->rx_lock);
45049485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_ledlock);
45059485SMikore.Li@Sun.COM 	sc->sc_udev = NULL;
45069485SMikore.Li@Sun.COM 
45079485SMikore.Li@Sun.COM 	ddi_remove_minor_node(devinfo, NULL);
45089485SMikore.Li@Sun.COM 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
45099485SMikore.Li@Sun.COM 
45109485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
45119485SMikore.Li@Sun.COM }
45129485SMikore.Li@Sun.COM 
45139485SMikore.Li@Sun.COM int
45149485SMikore.Li@Sun.COM _info(struct modinfo *modinfop)
45159485SMikore.Li@Sun.COM {
45169485SMikore.Li@Sun.COM 	return (mod_info(&modlinkage, modinfop));
45179485SMikore.Li@Sun.COM }
45189485SMikore.Li@Sun.COM 
45199485SMikore.Li@Sun.COM int
45209485SMikore.Li@Sun.COM _init(void)
45219485SMikore.Li@Sun.COM {
45229485SMikore.Li@Sun.COM 	int status;
45239485SMikore.Li@Sun.COM 
45249485SMikore.Li@Sun.COM 	status = ddi_soft_state_init(&urtw_soft_state_p,
45259485SMikore.Li@Sun.COM 	    sizeof (struct urtw_softc), 1);
45269485SMikore.Li@Sun.COM 	if (status != 0)
45279485SMikore.Li@Sun.COM 		return (status);
45289485SMikore.Li@Sun.COM 
45299485SMikore.Li@Sun.COM 	mac_init_ops(&urtw_dev_ops, "urtw");
45309485SMikore.Li@Sun.COM 	status = mod_install(&modlinkage);
45319485SMikore.Li@Sun.COM 	if (status != 0) {
45329485SMikore.Li@Sun.COM 		mac_fini_ops(&urtw_dev_ops);
45339485SMikore.Li@Sun.COM 		ddi_soft_state_fini(&urtw_soft_state_p);
45349485SMikore.Li@Sun.COM 	}
45359485SMikore.Li@Sun.COM 	return (status);
45369485SMikore.Li@Sun.COM }
45379485SMikore.Li@Sun.COM 
45389485SMikore.Li@Sun.COM int
45399485SMikore.Li@Sun.COM _fini(void)
45409485SMikore.Li@Sun.COM {
45419485SMikore.Li@Sun.COM 	int status;
45429485SMikore.Li@Sun.COM 
45439485SMikore.Li@Sun.COM 	status = mod_remove(&modlinkage);
45449485SMikore.Li@Sun.COM 	if (status == 0) {
45459485SMikore.Li@Sun.COM 		mac_fini_ops(&urtw_dev_ops);
45469485SMikore.Li@Sun.COM 		ddi_soft_state_fini(&urtw_soft_state_p);
45479485SMikore.Li@Sun.COM 	}
45489485SMikore.Li@Sun.COM 	return (status);
45499485SMikore.Li@Sun.COM }
4550