xref: /onnv-gate/usr/src/uts/common/io/urtw/urtw.c (revision 9485:da1442e8c885)
1*9485SMikore.Li@Sun.COM /*
2*9485SMikore.Li@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3*9485SMikore.Li@Sun.COM  * Use is subject to license terms.
4*9485SMikore.Li@Sun.COM  */
5*9485SMikore.Li@Sun.COM 
6*9485SMikore.Li@Sun.COM /*
7*9485SMikore.Li@Sun.COM  * Copyright (c) 2008 Weongyo Jeong
8*9485SMikore.Li@Sun.COM  * All rights reserved.
9*9485SMikore.Li@Sun.COM  *
10*9485SMikore.Li@Sun.COM  * Redistribution and use in source and binary forms, with or without
11*9485SMikore.Li@Sun.COM  * modification, are permitted provided that the following conditions
12*9485SMikore.Li@Sun.COM  * are met:
13*9485SMikore.Li@Sun.COM  * 1. Redistributions of source code must retain the above copyright
14*9485SMikore.Li@Sun.COM  *    notice, this list of conditions and the following disclaimer,
15*9485SMikore.Li@Sun.COM  *    without modification.
16*9485SMikore.Li@Sun.COM  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17*9485SMikore.Li@Sun.COM  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
18*9485SMikore.Li@Sun.COM  *    redistribution must be conditioned upon including a substantially
19*9485SMikore.Li@Sun.COM  *    similar Disclaimer requirement for further binary redistribution.
20*9485SMikore.Li@Sun.COM  *
21*9485SMikore.Li@Sun.COM  * NO WARRANTY
22*9485SMikore.Li@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23*9485SMikore.Li@Sun.COM  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24*9485SMikore.Li@Sun.COM  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
25*9485SMikore.Li@Sun.COM  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26*9485SMikore.Li@Sun.COM  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
27*9485SMikore.Li@Sun.COM  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28*9485SMikore.Li@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29*9485SMikore.Li@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
30*9485SMikore.Li@Sun.COM  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31*9485SMikore.Li@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32*9485SMikore.Li@Sun.COM  * THE POSSIBILITY OF SUCH DAMAGES.
33*9485SMikore.Li@Sun.COM  */
34*9485SMikore.Li@Sun.COM #include <sys/sysmacros.h>
35*9485SMikore.Li@Sun.COM #include <sys/strsubr.h>
36*9485SMikore.Li@Sun.COM #include <sys/strsun.h>
37*9485SMikore.Li@Sun.COM #include <sys/mac_provider.h>
38*9485SMikore.Li@Sun.COM #include <sys/mac_wifi.h>
39*9485SMikore.Li@Sun.COM #include <sys/net80211.h>
40*9485SMikore.Li@Sun.COM #define	USBDRV_MAJOR_VER	2
41*9485SMikore.Li@Sun.COM #define	USBDRV_MINOR_VER	0
42*9485SMikore.Li@Sun.COM #include <sys/usb/usba.h>
43*9485SMikore.Li@Sun.COM #include <sys/usb/usba/usba_types.h>
44*9485SMikore.Li@Sun.COM 
45*9485SMikore.Li@Sun.COM #include "urtw_reg.h"
46*9485SMikore.Li@Sun.COM #include "urtw_var.h"
47*9485SMikore.Li@Sun.COM 
48*9485SMikore.Li@Sun.COM static void *urtw_soft_state_p = NULL;
49*9485SMikore.Li@Sun.COM 
50*9485SMikore.Li@Sun.COM #define	URTW_TXBUF_SIZE  	(IEEE80211_MAX_LEN)
51*9485SMikore.Li@Sun.COM #define	URTW_RXBUF_SIZE  	(URTW_TXBUF_SIZE)
52*9485SMikore.Li@Sun.COM /*
53*9485SMikore.Li@Sun.COM  * device operations
54*9485SMikore.Li@Sun.COM  */
55*9485SMikore.Li@Sun.COM static int urtw_attach(dev_info_t *, ddi_attach_cmd_t);
56*9485SMikore.Li@Sun.COM static int urtw_detach(dev_info_t *, ddi_detach_cmd_t);
57*9485SMikore.Li@Sun.COM 
58*9485SMikore.Li@Sun.COM /*
59*9485SMikore.Li@Sun.COM  * Module Loading Data & Entry Points
60*9485SMikore.Li@Sun.COM  */
61*9485SMikore.Li@Sun.COM DDI_DEFINE_STREAM_OPS(urtw_dev_ops, nulldev, nulldev, urtw_attach,
62*9485SMikore.Li@Sun.COM     urtw_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
63*9485SMikore.Li@Sun.COM 
64*9485SMikore.Li@Sun.COM static struct modldrv urtw_modldrv = {
65*9485SMikore.Li@Sun.COM 	&mod_driverops,		/* Type of module.  This one is a driver */
66*9485SMikore.Li@Sun.COM 	"RTL8187L driver v1.1",	/* short description */
67*9485SMikore.Li@Sun.COM 	&urtw_dev_ops		/* driver specific ops */
68*9485SMikore.Li@Sun.COM };
69*9485SMikore.Li@Sun.COM 
70*9485SMikore.Li@Sun.COM static struct modlinkage modlinkage = {
71*9485SMikore.Li@Sun.COM 	MODREV_1,
72*9485SMikore.Li@Sun.COM 	(void *)&urtw_modldrv,
73*9485SMikore.Li@Sun.COM 	NULL
74*9485SMikore.Li@Sun.COM };
75*9485SMikore.Li@Sun.COM 
76*9485SMikore.Li@Sun.COM static int	urtw_m_stat(void *,  uint_t, uint64_t *);
77*9485SMikore.Li@Sun.COM static int	urtw_m_start(void *);
78*9485SMikore.Li@Sun.COM static void	urtw_m_stop(void *);
79*9485SMikore.Li@Sun.COM static int	urtw_m_promisc(void *, boolean_t);
80*9485SMikore.Li@Sun.COM static int	urtw_m_multicst(void *, boolean_t, const uint8_t *);
81*9485SMikore.Li@Sun.COM static int	urtw_m_unicst(void *, const uint8_t *);
82*9485SMikore.Li@Sun.COM static mblk_t	*urtw_m_tx(void *, mblk_t *);
83*9485SMikore.Li@Sun.COM static void	urtw_m_ioctl(void *, queue_t *, mblk_t *);
84*9485SMikore.Li@Sun.COM static int	urtw_m_setprop(void *, const char *, mac_prop_id_t,
85*9485SMikore.Li@Sun.COM     uint_t, const void *);
86*9485SMikore.Li@Sun.COM 
87*9485SMikore.Li@Sun.COM static mac_callbacks_t urtw_m_callbacks = {
88*9485SMikore.Li@Sun.COM 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
89*9485SMikore.Li@Sun.COM 	urtw_m_stat,
90*9485SMikore.Li@Sun.COM 	urtw_m_start,
91*9485SMikore.Li@Sun.COM 	urtw_m_stop,
92*9485SMikore.Li@Sun.COM 	urtw_m_promisc,
93*9485SMikore.Li@Sun.COM 	urtw_m_multicst,
94*9485SMikore.Li@Sun.COM 	urtw_m_unicst,
95*9485SMikore.Li@Sun.COM 	urtw_m_tx,
96*9485SMikore.Li@Sun.COM 	urtw_m_ioctl,
97*9485SMikore.Li@Sun.COM 	NULL,
98*9485SMikore.Li@Sun.COM 	NULL,
99*9485SMikore.Li@Sun.COM 	NULL,
100*9485SMikore.Li@Sun.COM 	urtw_m_setprop,
101*9485SMikore.Li@Sun.COM 	ieee80211_getprop
102*9485SMikore.Li@Sun.COM };
103*9485SMikore.Li@Sun.COM 
104*9485SMikore.Li@Sun.COM static int  urtw_tx_start(struct urtw_softc *, mblk_t *, int);
105*9485SMikore.Li@Sun.COM static int  urtw_rx_start(struct urtw_softc *);
106*9485SMikore.Li@Sun.COM 
107*9485SMikore.Li@Sun.COM 
108*9485SMikore.Li@Sun.COM /*
109*9485SMikore.Li@Sun.COM  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
110*9485SMikore.Li@Sun.COM  */
111*9485SMikore.Li@Sun.COM static const struct ieee80211_rateset urtw_rateset_11b =
112*9485SMikore.Li@Sun.COM 	{ 4, { 2, 4, 11, 22 } };
113*9485SMikore.Li@Sun.COM 
114*9485SMikore.Li@Sun.COM static const struct ieee80211_rateset urtw_rateset_11g =
115*9485SMikore.Li@Sun.COM 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
116*9485SMikore.Li@Sun.COM 
117*9485SMikore.Li@Sun.COM 
118*9485SMikore.Li@Sun.COM struct urtw_pair {
119*9485SMikore.Li@Sun.COM 	uint32_t	reg;
120*9485SMikore.Li@Sun.COM 	uint32_t	val;
121*9485SMikore.Li@Sun.COM };
122*9485SMikore.Li@Sun.COM 
123*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_agc[] = {
124*9485SMikore.Li@Sun.COM 	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
125*9485SMikore.Li@Sun.COM 	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
126*9485SMikore.Li@Sun.COM 	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
127*9485SMikore.Li@Sun.COM 	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
128*9485SMikore.Li@Sun.COM 	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
129*9485SMikore.Li@Sun.COM 	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
130*9485SMikore.Li@Sun.COM 	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
131*9485SMikore.Li@Sun.COM 	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
132*9485SMikore.Li@Sun.COM 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
133*9485SMikore.Li@Sun.COM 	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
134*9485SMikore.Li@Sun.COM 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
135*9485SMikore.Li@Sun.COM 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
136*9485SMikore.Li@Sun.COM };
137*9485SMikore.Li@Sun.COM 
138*9485SMikore.Li@Sun.COM static uint32_t urtw_8225_channel[] = {
139*9485SMikore.Li@Sun.COM 	0x0000,		/* dummy channel 0  */
140*9485SMikore.Li@Sun.COM 	0x085c,		/* 1  */
141*9485SMikore.Li@Sun.COM 	0x08dc,		/* 2  */
142*9485SMikore.Li@Sun.COM 	0x095c,		/* 3  */
143*9485SMikore.Li@Sun.COM 	0x09dc,		/* 4  */
144*9485SMikore.Li@Sun.COM 	0x0a5c,		/* 5  */
145*9485SMikore.Li@Sun.COM 	0x0adc,		/* 6  */
146*9485SMikore.Li@Sun.COM 	0x0b5c,		/* 7  */
147*9485SMikore.Li@Sun.COM 	0x0bdc,		/* 8  */
148*9485SMikore.Li@Sun.COM 	0x0c5c,		/* 9  */
149*9485SMikore.Li@Sun.COM 	0x0cdc,		/* 10  */
150*9485SMikore.Li@Sun.COM 	0x0d5c,		/* 11  */
151*9485SMikore.Li@Sun.COM 	0x0ddc,		/* 12  */
152*9485SMikore.Li@Sun.COM 	0x0e5c,		/* 13  */
153*9485SMikore.Li@Sun.COM 	0x0f72,		/* 14  */
154*9485SMikore.Li@Sun.COM };
155*9485SMikore.Li@Sun.COM 
156*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_gain[] = {
157*9485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm  */
158*9485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm  */
159*9485SMikore.Li@Sun.COM 	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm  */
160*9485SMikore.Li@Sun.COM 	0x33, 0x80, 0x79, 0xc5,		/* -78dbm  */
161*9485SMikore.Li@Sun.COM 	0x43, 0x78, 0x76, 0xc5,		/* -74dbm  */
162*9485SMikore.Li@Sun.COM 	0x53, 0x60, 0x73, 0xc5,		/* -70dbm  */
163*9485SMikore.Li@Sun.COM 	0x63, 0x58, 0x70, 0xc5,		/* -66dbm  */
164*9485SMikore.Li@Sun.COM };
165*9485SMikore.Li@Sun.COM 
166*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part1[] = {
167*9485SMikore.Li@Sun.COM 	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
168*9485SMikore.Li@Sun.COM 	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
169*9485SMikore.Li@Sun.COM 	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
170*9485SMikore.Li@Sun.COM 	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
171*9485SMikore.Li@Sun.COM };
172*9485SMikore.Li@Sun.COM 
173*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part2[] = {
174*9485SMikore.Li@Sun.COM 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
175*9485SMikore.Li@Sun.COM 	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
176*9485SMikore.Li@Sun.COM 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
177*9485SMikore.Li@Sun.COM 	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
178*9485SMikore.Li@Sun.COM 	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
179*9485SMikore.Li@Sun.COM 	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
180*9485SMikore.Li@Sun.COM 	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
181*9485SMikore.Li@Sun.COM 	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
182*9485SMikore.Li@Sun.COM 	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
183*9485SMikore.Li@Sun.COM 	{ 0x27, 0x88 }
184*9485SMikore.Li@Sun.COM };
185*9485SMikore.Li@Sun.COM 
186*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225_rf_part3[] = {
187*9485SMikore.Li@Sun.COM 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
188*9485SMikore.Li@Sun.COM 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
189*9485SMikore.Li@Sun.COM 	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
190*9485SMikore.Li@Sun.COM 	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
191*9485SMikore.Li@Sun.COM 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
192*9485SMikore.Li@Sun.COM 	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
193*9485SMikore.Li@Sun.COM 	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
194*9485SMikore.Li@Sun.COM };
195*9485SMikore.Li@Sun.COM 
196*9485SMikore.Li@Sun.COM static uint16_t urtw_8225_rxgain[] = {
197*9485SMikore.Li@Sun.COM 	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
198*9485SMikore.Li@Sun.COM 	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
199*9485SMikore.Li@Sun.COM 	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
200*9485SMikore.Li@Sun.COM 	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
201*9485SMikore.Li@Sun.COM 	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
202*9485SMikore.Li@Sun.COM 	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
203*9485SMikore.Li@Sun.COM 	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
204*9485SMikore.Li@Sun.COM 	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
205*9485SMikore.Li@Sun.COM 	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
206*9485SMikore.Li@Sun.COM 	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
207*9485SMikore.Li@Sun.COM 	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
208*9485SMikore.Li@Sun.COM 	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
209*9485SMikore.Li@Sun.COM };
210*9485SMikore.Li@Sun.COM 
211*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_threshold[] = {
212*9485SMikore.Li@Sun.COM 	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
213*9485SMikore.Li@Sun.COM };
214*9485SMikore.Li@Sun.COM 
215*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
216*9485SMikore.Li@Sun.COM 	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
217*9485SMikore.Li@Sun.COM };
218*9485SMikore.Li@Sun.COM 
219*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_cck[] = {
220*9485SMikore.Li@Sun.COM 	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
221*9485SMikore.Li@Sun.COM 	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
222*9485SMikore.Li@Sun.COM 	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
223*9485SMikore.Li@Sun.COM 	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
224*9485SMikore.Li@Sun.COM 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
225*9485SMikore.Li@Sun.COM 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
226*9485SMikore.Li@Sun.COM };
227*9485SMikore.Li@Sun.COM 
228*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_cck_ch14[] = {
229*9485SMikore.Li@Sun.COM 	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
230*9485SMikore.Li@Sun.COM 	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
231*9485SMikore.Li@Sun.COM 	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
232*9485SMikore.Li@Sun.COM 	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
233*9485SMikore.Li@Sun.COM 	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
234*9485SMikore.Li@Sun.COM 	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
235*9485SMikore.Li@Sun.COM };
236*9485SMikore.Li@Sun.COM 
237*9485SMikore.Li@Sun.COM static uint8_t urtw_8225_txpwr_ofdm[] = {
238*9485SMikore.Li@Sun.COM 	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
239*9485SMikore.Li@Sun.COM };
240*9485SMikore.Li@Sun.COM 
241*9485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_gain_bg[] = {
242*9485SMikore.Li@Sun.COM 	0x23, 0x15, 0xa5,		/* -82-1dbm  */
243*9485SMikore.Li@Sun.COM 	0x23, 0x15, 0xb5,		/* -82-2dbm  */
244*9485SMikore.Li@Sun.COM 	0x23, 0x15, 0xc5,		/* -82-3dbm  */
245*9485SMikore.Li@Sun.COM 	0x33, 0x15, 0xc5,		/* -78dbm  */
246*9485SMikore.Li@Sun.COM 	0x43, 0x15, 0xc5,		/* -74dbm  */
247*9485SMikore.Li@Sun.COM 	0x53, 0x15, 0xc5,		/* -70dbm  */
248*9485SMikore.Li@Sun.COM 	0x63, 0x15, 0xc5,		/* -66dbm  */
249*9485SMikore.Li@Sun.COM };
250*9485SMikore.Li@Sun.COM 
251*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part1[] = {
252*9485SMikore.Li@Sun.COM 	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
253*9485SMikore.Li@Sun.COM 	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
254*9485SMikore.Li@Sun.COM 	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
255*9485SMikore.Li@Sun.COM 	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
256*9485SMikore.Li@Sun.COM };
257*9485SMikore.Li@Sun.COM 
258*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part2[] = {
259*9485SMikore.Li@Sun.COM 	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
260*9485SMikore.Li@Sun.COM 	{ 0x04, 0x00 },	{ 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
261*9485SMikore.Li@Sun.COM 	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
262*9485SMikore.Li@Sun.COM 	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
263*9485SMikore.Li@Sun.COM 	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
264*9485SMikore.Li@Sun.COM 	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
265*9485SMikore.Li@Sun.COM 	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
266*9485SMikore.Li@Sun.COM 	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
267*9485SMikore.Li@Sun.COM 	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
268*9485SMikore.Li@Sun.COM 	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
269*9485SMikore.Li@Sun.COM };
270*9485SMikore.Li@Sun.COM 
271*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_8225v2_rf_part3[] = {
272*9485SMikore.Li@Sun.COM 	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
273*9485SMikore.Li@Sun.COM 	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
274*9485SMikore.Li@Sun.COM 	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
275*9485SMikore.Li@Sun.COM 	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
276*9485SMikore.Li@Sun.COM 	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
277*9485SMikore.Li@Sun.COM 	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
278*9485SMikore.Li@Sun.COM 	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
279*9485SMikore.Li@Sun.COM 	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
280*9485SMikore.Li@Sun.COM };
281*9485SMikore.Li@Sun.COM 
282*9485SMikore.Li@Sun.COM static uint16_t urtw_8225v2_rxgain[] = {
283*9485SMikore.Li@Sun.COM 	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
284*9485SMikore.Li@Sun.COM 	0x000a,	0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
285*9485SMikore.Li@Sun.COM 	0x0142,	0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
286*9485SMikore.Li@Sun.COM 	0x0184,	0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
287*9485SMikore.Li@Sun.COM 	0x0245,	0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
288*9485SMikore.Li@Sun.COM 	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
289*9485SMikore.Li@Sun.COM 	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
290*9485SMikore.Li@Sun.COM 	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
291*9485SMikore.Li@Sun.COM 	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
292*9485SMikore.Li@Sun.COM 	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
293*9485SMikore.Li@Sun.COM 	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
294*9485SMikore.Li@Sun.COM 	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
295*9485SMikore.Li@Sun.COM };
296*9485SMikore.Li@Sun.COM 
297*9485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
298*9485SMikore.Li@Sun.COM 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
299*9485SMikore.Li@Sun.COM 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
300*9485SMikore.Li@Sun.COM 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
301*9485SMikore.Li@Sun.COM 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
302*9485SMikore.Li@Sun.COM 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
303*9485SMikore.Li@Sun.COM 	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
304*9485SMikore.Li@Sun.COM };
305*9485SMikore.Li@Sun.COM 
306*9485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_txpwr_cck[] = {
307*9485SMikore.Li@Sun.COM 	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
308*9485SMikore.Li@Sun.COM };
309*9485SMikore.Li@Sun.COM 
310*9485SMikore.Li@Sun.COM static uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
311*9485SMikore.Li@Sun.COM 	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
312*9485SMikore.Li@Sun.COM };
313*9485SMikore.Li@Sun.COM 
314*9485SMikore.Li@Sun.COM static struct urtw_pair urtw_ratetable[] = {
315*9485SMikore.Li@Sun.COM 	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
316*9485SMikore.Li@Sun.COM 	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
317*9485SMikore.Li@Sun.COM 	{ 96, 10 }, { 108, 11 }
318*9485SMikore.Li@Sun.COM };
319*9485SMikore.Li@Sun.COM 
320*9485SMikore.Li@Sun.COM static int		urtw_init(void *);
321*9485SMikore.Li@Sun.COM static void		urtw_stop(struct urtw_softc *);
322*9485SMikore.Li@Sun.COM static int		urtw_set_channel(struct urtw_softc *);
323*9485SMikore.Li@Sun.COM static void
324*9485SMikore.Li@Sun.COM urtw_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
325*9485SMikore.Li@Sun.COM static int
326*9485SMikore.Li@Sun.COM urtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
327*9485SMikore.Li@Sun.COM static usbd_status	urtw_read8_c(struct urtw_softc *, int, uint8_t *);
328*9485SMikore.Li@Sun.COM static usbd_status	urtw_read16_c(struct urtw_softc *, int, uint16_t *);
329*9485SMikore.Li@Sun.COM static usbd_status	urtw_read32_c(struct urtw_softc *, int, uint32_t *);
330*9485SMikore.Li@Sun.COM static usbd_status	urtw_write8_c(struct urtw_softc *, int, uint8_t);
331*9485SMikore.Li@Sun.COM static usbd_status	urtw_write16_c(struct urtw_softc *, int, uint16_t);
332*9485SMikore.Li@Sun.COM static usbd_status	urtw_write32_c(struct urtw_softc *, int, uint32_t);
333*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_cs(struct urtw_softc *, int);
334*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_ck(struct urtw_softc *);
335*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
336*9485SMikore.Li@Sun.COM 			    int);
337*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_read32(struct urtw_softc *, uint32_t,
338*9485SMikore.Li@Sun.COM 			    uint32_t *);
339*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
340*9485SMikore.Li@Sun.COM static usbd_status	urtw_eprom_writebit(struct urtw_softc *, int16_t);
341*9485SMikore.Li@Sun.COM static usbd_status	urtw_get_macaddr(struct urtw_softc *);
342*9485SMikore.Li@Sun.COM static usbd_status	urtw_get_txpwr(struct urtw_softc *);
343*9485SMikore.Li@Sun.COM static usbd_status	urtw_get_rfchip(struct urtw_softc *);
344*9485SMikore.Li@Sun.COM static usbd_status	urtw_led_init(struct urtw_softc *);
345*9485SMikore.Li@Sun.COM static usbd_status
346*9485SMikore.Li@Sun.COM urtw_8225_read(struct urtw_softc *, uint8_t, uint32_t *);
347*9485SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_init(struct urtw_softc *);
348*9485SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_set_chan(struct urtw_softc *, int);
349*9485SMikore.Li@Sun.COM static usbd_status	urtw_8225_rf_set_sens(struct urtw_softc *, int);
350*9485SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_rf_init(struct urtw_softc *);
351*9485SMikore.Li@Sun.COM static usbd_status	urtw_8225v2_rf_set_chan(struct urtw_softc *, int);
352*9485SMikore.Li@Sun.COM static usbd_status	urtw_open_pipes(struct urtw_softc *);
353*9485SMikore.Li@Sun.COM static void urtw_close_pipes(struct urtw_softc *);
354*9485SMikore.Li@Sun.COM static void urtw_led_launch(void *);
355*9485SMikore.Li@Sun.COM 
356*9485SMikore.Li@Sun.COM #ifdef DEBUG
357*9485SMikore.Li@Sun.COM 
358*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_XMIT		0x00000001
359*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_RECV		0x00000002
360*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_LED 		0x00000004
361*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_GLD 		0x00000008
362*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_RF		0x00000010
363*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_ATTACH 	0x00000020
364*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_ACTIVE 	0x00000040
365*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_HWTYPE	0x00000080
366*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_STATE	0x00000100
367*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_HOTPLUG	0x00000200
368*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_STAT		0x00000400
369*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_TX_PROC	0x00000800
370*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_RX_PROC 	0x00001000
371*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_EEPROM	0x00002000
372*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_RESET	0x00004000
373*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_DEVREQ	0x00010000
374*9485SMikore.Li@Sun.COM #define	URTW_DEBUG_ANY		0xffffffff
375*9485SMikore.Li@Sun.COM 
376*9485SMikore.Li@Sun.COM uint32_t urtw8187_dbg_flags = 0;
377*9485SMikore.Li@Sun.COM static void
378*9485SMikore.Li@Sun.COM urtw8187_dbg(dev_info_t *dip, int level, const char *fmt, ...)
379*9485SMikore.Li@Sun.COM {
380*9485SMikore.Li@Sun.COM 	char		msg_buffer[255];
381*9485SMikore.Li@Sun.COM 	va_list	ap;
382*9485SMikore.Li@Sun.COM 
383*9485SMikore.Li@Sun.COM 	if (dip == NULL) {
384*9485SMikore.Li@Sun.COM 		return;
385*9485SMikore.Li@Sun.COM 	}
386*9485SMikore.Li@Sun.COM 
387*9485SMikore.Li@Sun.COM 	va_start(ap, fmt);
388*9485SMikore.Li@Sun.COM 	(void) vsprintf(msg_buffer, fmt, ap);
389*9485SMikore.Li@Sun.COM 	cmn_err(level, "%s%d: %s", ddi_get_name(dip),
390*9485SMikore.Li@Sun.COM 	    ddi_get_instance(dip), msg_buffer);
391*9485SMikore.Li@Sun.COM 	va_end(ap);
392*9485SMikore.Li@Sun.COM }
393*9485SMikore.Li@Sun.COM 
394*9485SMikore.Li@Sun.COM #define	URTW8187_DBG(l, x) do {\
395*9485SMikore.Li@Sun.COM 	_NOTE(CONSTANTCONDITION) \
396*9485SMikore.Li@Sun.COM 	if ((l) & urtw8187_dbg_flags) \
397*9485SMikore.Li@Sun.COM 		urtw8187_dbg x;\
398*9485SMikore.Li@Sun.COM 	_NOTE(CONSTANTCONDITION) \
399*9485SMikore.Li@Sun.COM } while (0)
400*9485SMikore.Li@Sun.COM #else
401*9485SMikore.Li@Sun.COM #define	URTW8187_DBG(l, x)
402*9485SMikore.Li@Sun.COM #endif
403*9485SMikore.Li@Sun.COM 
404*9485SMikore.Li@Sun.COM static usbd_status
405*9485SMikore.Li@Sun.COM urtw_led_init(struct urtw_softc *sc)
406*9485SMikore.Li@Sun.COM {
407*9485SMikore.Li@Sun.COM 	uint32_t rev;
408*9485SMikore.Li@Sun.COM 	usbd_status error;
409*9485SMikore.Li@Sun.COM 
410*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_PSR, &sc->sc_psr))
411*9485SMikore.Li@Sun.COM 		goto fail;
412*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
413*9485SMikore.Li@Sun.COM 	if (error != 0)
414*9485SMikore.Li@Sun.COM 		goto fail;
415*9485SMikore.Li@Sun.COM 
416*9485SMikore.Li@Sun.COM 	switch (rev & URTW_EPROM_CID_MASK) {
417*9485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_ALPHA0:
418*9485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE1;
419*9485SMikore.Li@Sun.COM 		break;
420*9485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_SERCOMM_PS:
421*9485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE3;
422*9485SMikore.Li@Sun.COM 		break;
423*9485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_HW_LED:
424*9485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_HW_LED;
425*9485SMikore.Li@Sun.COM 		break;
426*9485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_RSVD0:
427*9485SMikore.Li@Sun.COM 	case URTW_EPROM_CID_RSVD1:
428*9485SMikore.Li@Sun.COM 	default:
429*9485SMikore.Li@Sun.COM 		sc->sc_strategy = URTW_SW_LED_MODE0;
430*9485SMikore.Li@Sun.COM 		break;
431*9485SMikore.Li@Sun.COM 	}
432*9485SMikore.Li@Sun.COM 
433*9485SMikore.Li@Sun.COM 	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
434*9485SMikore.Li@Sun.COM 
435*9485SMikore.Li@Sun.COM fail:
436*9485SMikore.Li@Sun.COM 	return (error);
437*9485SMikore.Li@Sun.COM }
438*9485SMikore.Li@Sun.COM 
439*9485SMikore.Li@Sun.COM static usbd_status
440*9485SMikore.Li@Sun.COM urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
441*9485SMikore.Li@Sun.COM     uint16_t *data)
442*9485SMikore.Li@Sun.COM {
443*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
444*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
445*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
446*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
447*9485SMikore.Li@Sun.COM 	uint16_t data16;
448*9485SMikore.Li@Sun.COM 	usbd_status error;
449*9485SMikore.Li@Sun.COM 
450*9485SMikore.Li@Sun.COM 	data16 = *data;
451*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
452*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
453*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
454*9485SMikore.Li@Sun.COM 	req.wValue = addr;
455*9485SMikore.Li@Sun.COM 	req.wIndex = (uint16_t)index;
456*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
457*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
458*9485SMikore.Li@Sun.COM 
459*9485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint16_t), BPRI_MED);
460*9485SMikore.Li@Sun.COM 	if (mp == 0) {
461*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_8225_write_s16: allocb failed\n");
462*9485SMikore.Li@Sun.COM 		return (-1);
463*9485SMikore.Li@Sun.COM 	}
464*9485SMikore.Li@Sun.COM 	*(mp->b_rptr) = (data16 & 0x00ff);
465*9485SMikore.Li@Sun.COM 	*(mp->b_rptr + 1) = (data16 & 0xff00) >> 8;
466*9485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint16_t);
467*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
468*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
469*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
470*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
471*9485SMikore.Li@Sun.COM 		    "urtw_8225_write_s16: could not set regs:"
472*9485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
473*9485SMikore.Li@Sun.COM 	}
474*9485SMikore.Li@Sun.COM 	if (mp)
475*9485SMikore.Li@Sun.COM 		freemsg(mp);
476*9485SMikore.Li@Sun.COM 	return (error);
477*9485SMikore.Li@Sun.COM 
478*9485SMikore.Li@Sun.COM }
479*9485SMikore.Li@Sun.COM 
480*9485SMikore.Li@Sun.COM static usbd_status
481*9485SMikore.Li@Sun.COM urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
482*9485SMikore.Li@Sun.COM {
483*9485SMikore.Li@Sun.COM 	int i;
484*9485SMikore.Li@Sun.COM 	int16_t bit;
485*9485SMikore.Li@Sun.COM 	uint8_t rlen = 12, wlen = 6;
486*9485SMikore.Li@Sun.COM 	uint16_t o1, o2, o3, tmp;
487*9485SMikore.Li@Sun.COM 	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
488*9485SMikore.Li@Sun.COM 	uint32_t mask = 0x80000000, value = 0;
489*9485SMikore.Li@Sun.COM 	usbd_status error;
490*9485SMikore.Li@Sun.COM 
491*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &o1))
492*9485SMikore.Li@Sun.COM 		goto fail;
493*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &o2))
494*9485SMikore.Li@Sun.COM 		goto fail;
495*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &o3))
496*9485SMikore.Li@Sun.COM 		goto fail;
497*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2 | 0xf))
498*9485SMikore.Li@Sun.COM 		goto fail;
499*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3 | 0xf))
500*9485SMikore.Li@Sun.COM 		goto fail;
501*9485SMikore.Li@Sun.COM 	o1 &= ~0xf;
502*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
503*9485SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_EN))
504*9485SMikore.Li@Sun.COM 		goto fail;
505*9485SMikore.Li@Sun.COM 	DELAY(5);
506*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, o1))
507*9485SMikore.Li@Sun.COM 		goto fail;
508*9485SMikore.Li@Sun.COM 	DELAY(5);
509*9485SMikore.Li@Sun.COM 
510*9485SMikore.Li@Sun.COM 	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
511*9485SMikore.Li@Sun.COM 		bit = ((d2w & mask) != 0) ? 1 : 0;
512*9485SMikore.Li@Sun.COM 
513*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1))
514*9485SMikore.Li@Sun.COM 			goto fail;
515*9485SMikore.Li@Sun.COM 		DELAY(2);
516*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
517*9485SMikore.Li@Sun.COM 		    URTW_BB_HOST_BANG_CLK))
518*9485SMikore.Li@Sun.COM 			goto fail;
519*9485SMikore.Li@Sun.COM 		DELAY(2);
520*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
521*9485SMikore.Li@Sun.COM 		    URTW_BB_HOST_BANG_CLK))
522*9485SMikore.Li@Sun.COM 			goto fail;
523*9485SMikore.Li@Sun.COM 		DELAY(2);
524*9485SMikore.Li@Sun.COM 		mask = mask >> 1;
525*9485SMikore.Li@Sun.COM 		if (i == 2)
526*9485SMikore.Li@Sun.COM 			break;
527*9485SMikore.Li@Sun.COM 		bit = ((d2w & mask) != 0) ? 1 : 0;
528*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
529*9485SMikore.Li@Sun.COM 		    URTW_BB_HOST_BANG_CLK))
530*9485SMikore.Li@Sun.COM 			goto fail;
531*9485SMikore.Li@Sun.COM 		DELAY(2);
532*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
533*9485SMikore.Li@Sun.COM 		    URTW_BB_HOST_BANG_CLK))
534*9485SMikore.Li@Sun.COM 			goto fail;
535*9485SMikore.Li@Sun.COM 		DELAY(2);
536*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, bit | o1))
537*9485SMikore.Li@Sun.COM 			goto fail;
538*9485SMikore.Li@Sun.COM 		DELAY(1);
539*9485SMikore.Li@Sun.COM 	}
540*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
541*9485SMikore.Li@Sun.COM 	    bit | o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK))
542*9485SMikore.Li@Sun.COM 		goto fail;
543*9485SMikore.Li@Sun.COM 	DELAY(2);
544*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
545*9485SMikore.Li@Sun.COM 	    bit | o1 | URTW_BB_HOST_BANG_RW))
546*9485SMikore.Li@Sun.COM 		goto fail;
547*9485SMikore.Li@Sun.COM 	DELAY(2);
548*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
549*9485SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_RW))
550*9485SMikore.Li@Sun.COM 		goto fail;
551*9485SMikore.Li@Sun.COM 	DELAY(2);
552*9485SMikore.Li@Sun.COM 
553*9485SMikore.Li@Sun.COM 	mask = 0x800;
554*9485SMikore.Li@Sun.COM 	for (i = 0; i < rlen; i++, mask = mask >> 1) {
555*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
556*9485SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW))
557*9485SMikore.Li@Sun.COM 			goto fail;
558*9485SMikore.Li@Sun.COM 		DELAY(2);
559*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
560*9485SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK))
561*9485SMikore.Li@Sun.COM 			goto fail;
562*9485SMikore.Li@Sun.COM 		DELAY(2);
563*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
564*9485SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK))
565*9485SMikore.Li@Sun.COM 			goto fail;
566*9485SMikore.Li@Sun.COM 		DELAY(2);
567*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
568*9485SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK))
569*9485SMikore.Li@Sun.COM 			goto fail;
570*9485SMikore.Li@Sun.COM 		DELAY(2);
571*9485SMikore.Li@Sun.COM 
572*9485SMikore.Li@Sun.COM 		if (error = urtw_read16_c(sc, URTW_RF_PINS_INPUT, &tmp))
573*9485SMikore.Li@Sun.COM 			goto fail;
574*9485SMikore.Li@Sun.COM 		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
575*9485SMikore.Li@Sun.COM 		if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
576*9485SMikore.Li@Sun.COM 		    o1 | URTW_BB_HOST_BANG_RW))
577*9485SMikore.Li@Sun.COM 			goto fail;
578*9485SMikore.Li@Sun.COM 		DELAY(2);
579*9485SMikore.Li@Sun.COM 	}
580*9485SMikore.Li@Sun.COM 
581*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
582*9485SMikore.Li@Sun.COM 	    o1 | URTW_BB_HOST_BANG_EN |
583*9485SMikore.Li@Sun.COM 	    URTW_BB_HOST_BANG_RW))
584*9485SMikore.Li@Sun.COM 		goto fail;
585*9485SMikore.Li@Sun.COM 	DELAY(2);
586*9485SMikore.Li@Sun.COM 
587*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, o2))
588*9485SMikore.Li@Sun.COM 		goto fail;
589*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, o3))
590*9485SMikore.Li@Sun.COM 		goto fail;
591*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x3a0);
592*9485SMikore.Li@Sun.COM 
593*9485SMikore.Li@Sun.COM 	if (data != NULL)
594*9485SMikore.Li@Sun.COM 		*data = value;
595*9485SMikore.Li@Sun.COM fail:
596*9485SMikore.Li@Sun.COM 	return (error);
597*9485SMikore.Li@Sun.COM }
598*9485SMikore.Li@Sun.COM 
599*9485SMikore.Li@Sun.COM static void
600*9485SMikore.Li@Sun.COM urtw_delay_ms(int t)
601*9485SMikore.Li@Sun.COM {
602*9485SMikore.Li@Sun.COM 	DELAY(t * 1000);
603*9485SMikore.Li@Sun.COM }
604*9485SMikore.Li@Sun.COM 
605*9485SMikore.Li@Sun.COM static usbd_status
606*9485SMikore.Li@Sun.COM urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
607*9485SMikore.Li@Sun.COM {
608*9485SMikore.Li@Sun.COM 	uint16_t d80, d82, d84;
609*9485SMikore.Li@Sun.COM 	usbd_status error;
610*9485SMikore.Li@Sun.COM 
611*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_OUTPUT, &d80))
612*9485SMikore.Li@Sun.COM 		goto fail;
613*9485SMikore.Li@Sun.COM 	d80 &= 0xfff3;
614*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_ENABLE, &d82))
615*9485SMikore.Li@Sun.COM 		goto fail;
616*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_RF_PINS_SELECT, &d84))
617*9485SMikore.Li@Sun.COM 		goto fail;
618*9485SMikore.Li@Sun.COM 	d84 &= 0xfff0;
619*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE,
620*9485SMikore.Li@Sun.COM 	    d82 | 0x0007))
621*9485SMikore.Li@Sun.COM 		goto fail;
622*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT,
623*9485SMikore.Li@Sun.COM 	    d84 | 0x0007))
624*9485SMikore.Li@Sun.COM 		goto fail;
625*9485SMikore.Li@Sun.COM 	DELAY(10);
626*9485SMikore.Li@Sun.COM 
627*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
628*9485SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN))
629*9485SMikore.Li@Sun.COM 		goto fail;
630*9485SMikore.Li@Sun.COM 	DELAY(2);
631*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, d80))
632*9485SMikore.Li@Sun.COM 		goto fail;
633*9485SMikore.Li@Sun.COM 	DELAY(10);
634*9485SMikore.Li@Sun.COM 
635*9485SMikore.Li@Sun.COM 	error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
636*9485SMikore.Li@Sun.COM 	if (error != 0)
637*9485SMikore.Li@Sun.COM 		goto fail;
638*9485SMikore.Li@Sun.COM 
639*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
640*9485SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN))
641*9485SMikore.Li@Sun.COM 		goto fail;
642*9485SMikore.Li@Sun.COM 	DELAY(10);
643*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT,
644*9485SMikore.Li@Sun.COM 	    d80 | URTW_BB_HOST_BANG_EN))
645*9485SMikore.Li@Sun.COM 		goto fail;
646*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, d84);
647*9485SMikore.Li@Sun.COM 	urtw_delay_ms(2);
648*9485SMikore.Li@Sun.COM fail:
649*9485SMikore.Li@Sun.COM 	return (error);
650*9485SMikore.Li@Sun.COM }
651*9485SMikore.Li@Sun.COM 
652*9485SMikore.Li@Sun.COM static usbd_status
653*9485SMikore.Li@Sun.COM urtw_8225_isv2(struct urtw_softc *sc, int *ret)
654*9485SMikore.Li@Sun.COM {
655*9485SMikore.Li@Sun.COM 	uint32_t data;
656*9485SMikore.Li@Sun.COM 	usbd_status error;
657*9485SMikore.Li@Sun.COM 
658*9485SMikore.Li@Sun.COM 	*ret = 1;
659*9485SMikore.Li@Sun.COM 
660*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x0080))
661*9485SMikore.Li@Sun.COM 		goto fail;
662*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x0080))
663*9485SMikore.Li@Sun.COM 		goto fail;
664*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x0080))
665*9485SMikore.Li@Sun.COM 		goto fail;
666*9485SMikore.Li@Sun.COM 	urtw_delay_ms(300);
667*9485SMikore.Li@Sun.COM 
668*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
669*9485SMikore.Li@Sun.COM 		goto fail;
670*9485SMikore.Li@Sun.COM 
671*9485SMikore.Li@Sun.COM 	error = urtw_8225_read(sc, 0x8, &data);
672*9485SMikore.Li@Sun.COM 	if (error != 0)
673*9485SMikore.Li@Sun.COM 		goto fail;
674*9485SMikore.Li@Sun.COM 	if (data != 0x588)
675*9485SMikore.Li@Sun.COM 		*ret = 0;
676*9485SMikore.Li@Sun.COM 	else {
677*9485SMikore.Li@Sun.COM 		error = urtw_8225_read(sc, 0x9, &data);
678*9485SMikore.Li@Sun.COM 		if (error != 0)
679*9485SMikore.Li@Sun.COM 			goto fail;
680*9485SMikore.Li@Sun.COM 		if (data != 0x700)
681*9485SMikore.Li@Sun.COM 			*ret = 0;
682*9485SMikore.Li@Sun.COM 	}
683*9485SMikore.Li@Sun.COM 
684*9485SMikore.Li@Sun.COM 	error = urtw_8225_write_c(sc, 0x0, 0xb7);
685*9485SMikore.Li@Sun.COM fail:
686*9485SMikore.Li@Sun.COM 	return (error);
687*9485SMikore.Li@Sun.COM }
688*9485SMikore.Li@Sun.COM 
689*9485SMikore.Li@Sun.COM static usbd_status
690*9485SMikore.Li@Sun.COM urtw_get_rfchip(struct urtw_softc *sc)
691*9485SMikore.Li@Sun.COM {
692*9485SMikore.Li@Sun.COM 	int ret;
693*9485SMikore.Li@Sun.COM 	uint32_t data;
694*9485SMikore.Li@Sun.COM 	usbd_status error;
695*9485SMikore.Li@Sun.COM 
696*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
697*9485SMikore.Li@Sun.COM 	if (error != 0)
698*9485SMikore.Li@Sun.COM 		goto fail;
699*9485SMikore.Li@Sun.COM 	switch (data & 0xff) {
700*9485SMikore.Li@Sun.COM 	case URTW_EPROM_RFCHIPID_RTL8225U:
701*9485SMikore.Li@Sun.COM 		error = urtw_8225_isv2(sc, &ret);
702*9485SMikore.Li@Sun.COM 		if (error != 0)
703*9485SMikore.Li@Sun.COM 			goto fail;
704*9485SMikore.Li@Sun.COM 		if (ret == 0) {
705*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_HWTYPE,
706*9485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "8225 RF chip detected\n"));
707*9485SMikore.Li@Sun.COM 			sc->sc_rf_init = urtw_8225_rf_init;
708*9485SMikore.Li@Sun.COM 			sc->sc_rf_set_sens = urtw_8225_rf_set_sens;
709*9485SMikore.Li@Sun.COM 			sc->sc_rf_set_chan = urtw_8225_rf_set_chan;
710*9485SMikore.Li@Sun.COM 		} else {
711*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_HWTYPE,
712*9485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT,
713*9485SMikore.Li@Sun.COM 			    "8225 v2 RF chip detected\n"));
714*9485SMikore.Li@Sun.COM 			sc->sc_rf_init = urtw_8225v2_rf_init;
715*9485SMikore.Li@Sun.COM 			sc->sc_rf_set_chan = urtw_8225v2_rf_set_chan;
716*9485SMikore.Li@Sun.COM 		}
717*9485SMikore.Li@Sun.COM 		sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
718*9485SMikore.Li@Sun.COM 		sc->sc_sens = URTW_8225_RF_DEF_SENS;
719*9485SMikore.Li@Sun.COM 		break;
720*9485SMikore.Li@Sun.COM 	default:
721*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "unsupported RF chip %d\n", data & 0xff);
722*9485SMikore.Li@Sun.COM 		error = -1;
723*9485SMikore.Li@Sun.COM 	}
724*9485SMikore.Li@Sun.COM 
725*9485SMikore.Li@Sun.COM fail:
726*9485SMikore.Li@Sun.COM 	return (error);
727*9485SMikore.Li@Sun.COM }
728*9485SMikore.Li@Sun.COM 
729*9485SMikore.Li@Sun.COM static usbd_status
730*9485SMikore.Li@Sun.COM urtw_get_txpwr(struct urtw_softc *sc)
731*9485SMikore.Li@Sun.COM {
732*9485SMikore.Li@Sun.COM 	int i, j;
733*9485SMikore.Li@Sun.COM 	uint32_t data;
734*9485SMikore.Li@Sun.COM 	usbd_status error;
735*9485SMikore.Li@Sun.COM 
736*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
737*9485SMikore.Li@Sun.COM 	if (error != 0)
738*9485SMikore.Li@Sun.COM 		goto fail;
739*9485SMikore.Li@Sun.COM 	sc->sc_txpwr_cck_base = data & 0xf;
740*9485SMikore.Li@Sun.COM 	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
741*9485SMikore.Li@Sun.COM 
742*9485SMikore.Li@Sun.COM 	for (i = 1, j = 0; i < 6; i += 2, j++) {
743*9485SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
744*9485SMikore.Li@Sun.COM 		if (error != 0)
745*9485SMikore.Li@Sun.COM 			goto fail;
746*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i] = data & 0xf;
747*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
748*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
749*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
750*9485SMikore.Li@Sun.COM 	}
751*9485SMikore.Li@Sun.COM 	for (i = 1, j = 0; i < 4; i += 2, j++) {
752*9485SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
753*9485SMikore.Li@Sun.COM 		if (error != 0)
754*9485SMikore.Li@Sun.COM 			goto fail;
755*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6] = data & 0xf;
756*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
757*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
758*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
759*9485SMikore.Li@Sun.COM 	}
760*9485SMikore.Li@Sun.COM 	for (i = 1, j = 0; i < 4; i += 2, j++) {
761*9485SMikore.Li@Sun.COM 		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j, &data);
762*9485SMikore.Li@Sun.COM 		if (error != 0)
763*9485SMikore.Li@Sun.COM 			goto fail;
764*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
765*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
766*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
767*9485SMikore.Li@Sun.COM 		sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = (data & 0xf000) >> 12;
768*9485SMikore.Li@Sun.COM 	}
769*9485SMikore.Li@Sun.COM fail:
770*9485SMikore.Li@Sun.COM 	return (error);
771*9485SMikore.Li@Sun.COM }
772*9485SMikore.Li@Sun.COM 
773*9485SMikore.Li@Sun.COM static usbd_status
774*9485SMikore.Li@Sun.COM urtw_get_macaddr(struct urtw_softc *sc)
775*9485SMikore.Li@Sun.COM {
776*9485SMikore.Li@Sun.COM 	uint32_t data;
777*9485SMikore.Li@Sun.COM 	usbd_status error;
778*9485SMikore.Li@Sun.COM 	uint8_t *m = 0;
779*9485SMikore.Li@Sun.COM 
780*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
781*9485SMikore.Li@Sun.COM 	if (error != 0)
782*9485SMikore.Li@Sun.COM 		goto fail;
783*9485SMikore.Li@Sun.COM 	sc->sc_bssid[0] = data & 0xff;
784*9485SMikore.Li@Sun.COM 	sc->sc_bssid[1] = (data & 0xff00) >> 8;
785*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
786*9485SMikore.Li@Sun.COM 	if (error != 0)
787*9485SMikore.Li@Sun.COM 		goto fail;
788*9485SMikore.Li@Sun.COM 	sc->sc_bssid[2] = data & 0xff;
789*9485SMikore.Li@Sun.COM 	sc->sc_bssid[3] = (data & 0xff00) >> 8;
790*9485SMikore.Li@Sun.COM 	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
791*9485SMikore.Li@Sun.COM 	if (error != 0)
792*9485SMikore.Li@Sun.COM 		goto fail;
793*9485SMikore.Li@Sun.COM 	sc->sc_bssid[4] = data & 0xff;
794*9485SMikore.Li@Sun.COM 	sc->sc_bssid[5] = (data & 0xff00) >> 8;
795*9485SMikore.Li@Sun.COM 	bcopy(sc->sc_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
796*9485SMikore.Li@Sun.COM 	m = sc->sc_bssid;
797*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
798*9485SMikore.Li@Sun.COM 	    "MAC: %x:%x:%x:%x:%x:%x\n",
799*9485SMikore.Li@Sun.COM 	    m[0], m[1], m[2], m[3], m[4], m[5]));
800*9485SMikore.Li@Sun.COM fail:
801*9485SMikore.Li@Sun.COM 	return (error);
802*9485SMikore.Li@Sun.COM }
803*9485SMikore.Li@Sun.COM 
804*9485SMikore.Li@Sun.COM static usbd_status
805*9485SMikore.Li@Sun.COM urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
806*9485SMikore.Li@Sun.COM {
807*9485SMikore.Li@Sun.COM #define	URTW_READCMD_LEN	3
808*9485SMikore.Li@Sun.COM 	int addrlen, i;
809*9485SMikore.Li@Sun.COM 	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
810*9485SMikore.Li@Sun.COM 	usbd_status error;
811*9485SMikore.Li@Sun.COM 
812*9485SMikore.Li@Sun.COM 	/* NB: make sure the buffer is initialized  */
813*9485SMikore.Li@Sun.COM 	*data = 0;
814*9485SMikore.Li@Sun.COM 
815*9485SMikore.Li@Sun.COM 	/* enable EPROM programming */
816*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD,
817*9485SMikore.Li@Sun.COM 	    URTW_EPROM_CMD_PROGRAM_MODE))
818*9485SMikore.Li@Sun.COM 		goto fail;
819*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
820*9485SMikore.Li@Sun.COM 
821*9485SMikore.Li@Sun.COM 	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
822*9485SMikore.Li@Sun.COM 	if (error != 0)
823*9485SMikore.Li@Sun.COM 		goto fail;
824*9485SMikore.Li@Sun.COM 	error = urtw_eprom_ck(sc);
825*9485SMikore.Li@Sun.COM 	if (error != 0)
826*9485SMikore.Li@Sun.COM 		goto fail;
827*9485SMikore.Li@Sun.COM 	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
828*9485SMikore.Li@Sun.COM 	if (error != 0)
829*9485SMikore.Li@Sun.COM 		goto fail;
830*9485SMikore.Li@Sun.COM 	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
831*9485SMikore.Li@Sun.COM 		addrlen = 8;
832*9485SMikore.Li@Sun.COM 		addrstr[0] = addr & (1 << 7);
833*9485SMikore.Li@Sun.COM 		addrstr[1] = addr & (1 << 6);
834*9485SMikore.Li@Sun.COM 		addrstr[2] = addr & (1 << 5);
835*9485SMikore.Li@Sun.COM 		addrstr[3] = addr & (1 << 4);
836*9485SMikore.Li@Sun.COM 		addrstr[4] = addr & (1 << 3);
837*9485SMikore.Li@Sun.COM 		addrstr[5] = addr & (1 << 2);
838*9485SMikore.Li@Sun.COM 		addrstr[6] = addr & (1 << 1);
839*9485SMikore.Li@Sun.COM 		addrstr[7] = addr & (1 << 0);
840*9485SMikore.Li@Sun.COM 	} else {
841*9485SMikore.Li@Sun.COM 		addrlen = 6;
842*9485SMikore.Li@Sun.COM 		addrstr[0] = addr & (1 << 5);
843*9485SMikore.Li@Sun.COM 		addrstr[1] = addr & (1 << 4);
844*9485SMikore.Li@Sun.COM 		addrstr[2] = addr & (1 << 3);
845*9485SMikore.Li@Sun.COM 		addrstr[3] = addr & (1 << 2);
846*9485SMikore.Li@Sun.COM 		addrstr[4] = addr & (1 << 1);
847*9485SMikore.Li@Sun.COM 		addrstr[5] = addr & (1 << 0);
848*9485SMikore.Li@Sun.COM 	}
849*9485SMikore.Li@Sun.COM 	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
850*9485SMikore.Li@Sun.COM 	if (error != 0)
851*9485SMikore.Li@Sun.COM 		goto fail;
852*9485SMikore.Li@Sun.COM 
853*9485SMikore.Li@Sun.COM 	error = urtw_eprom_writebit(sc, 0);
854*9485SMikore.Li@Sun.COM 	if (error != 0)
855*9485SMikore.Li@Sun.COM 		goto fail;
856*9485SMikore.Li@Sun.COM 
857*9485SMikore.Li@Sun.COM 	for (i = 0; i < 16; i++) {
858*9485SMikore.Li@Sun.COM 		error = urtw_eprom_ck(sc);
859*9485SMikore.Li@Sun.COM 		if (error != 0)
860*9485SMikore.Li@Sun.COM 			goto fail;
861*9485SMikore.Li@Sun.COM 		error = urtw_eprom_readbit(sc, &data16);
862*9485SMikore.Li@Sun.COM 		if (error != 0)
863*9485SMikore.Li@Sun.COM 			goto fail;
864*9485SMikore.Li@Sun.COM 
865*9485SMikore.Li@Sun.COM 		(*data) |= (data16 << (15 - i));
866*9485SMikore.Li@Sun.COM 	}
867*9485SMikore.Li@Sun.COM 
868*9485SMikore.Li@Sun.COM 	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
869*9485SMikore.Li@Sun.COM 	if (error != 0)
870*9485SMikore.Li@Sun.COM 		goto fail;
871*9485SMikore.Li@Sun.COM 	error = urtw_eprom_ck(sc);
872*9485SMikore.Li@Sun.COM 	if (error != 0)
873*9485SMikore.Li@Sun.COM 		goto fail;
874*9485SMikore.Li@Sun.COM 
875*9485SMikore.Li@Sun.COM 	/* now disable EPROM programming */
876*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE);
877*9485SMikore.Li@Sun.COM fail:
878*9485SMikore.Li@Sun.COM 	return (error);
879*9485SMikore.Li@Sun.COM #undef URTW_READCMD_LEN
880*9485SMikore.Li@Sun.COM }
881*9485SMikore.Li@Sun.COM 
882*9485SMikore.Li@Sun.COM static usbd_status
883*9485SMikore.Li@Sun.COM urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
884*9485SMikore.Li@Sun.COM {
885*9485SMikore.Li@Sun.COM 	uint8_t data8;
886*9485SMikore.Li@Sun.COM 	usbd_status error;
887*9485SMikore.Li@Sun.COM 
888*9485SMikore.Li@Sun.COM 	error = urtw_read8_c(sc, URTW_EPROM_CMD, &data8);
889*9485SMikore.Li@Sun.COM 	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
890*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
891*9485SMikore.Li@Sun.COM 	return (error);
892*9485SMikore.Li@Sun.COM }
893*9485SMikore.Li@Sun.COM 
894*9485SMikore.Li@Sun.COM static usbd_status
895*9485SMikore.Li@Sun.COM urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
896*9485SMikore.Li@Sun.COM {
897*9485SMikore.Li@Sun.COM 	int i = 0;
898*9485SMikore.Li@Sun.COM 	usbd_status error;
899*9485SMikore.Li@Sun.COM 
900*9485SMikore.Li@Sun.COM 	for (i = 0; i < buflen; i++) {
901*9485SMikore.Li@Sun.COM 		error = urtw_eprom_writebit(sc, buf[i]);
902*9485SMikore.Li@Sun.COM 		if (error != 0)
903*9485SMikore.Li@Sun.COM 			goto fail;
904*9485SMikore.Li@Sun.COM 		error = urtw_eprom_ck(sc);
905*9485SMikore.Li@Sun.COM 		if (error != 0)
906*9485SMikore.Li@Sun.COM 			goto fail;
907*9485SMikore.Li@Sun.COM 	}
908*9485SMikore.Li@Sun.COM fail:
909*9485SMikore.Li@Sun.COM 	return (error);
910*9485SMikore.Li@Sun.COM }
911*9485SMikore.Li@Sun.COM 
912*9485SMikore.Li@Sun.COM static usbd_status
913*9485SMikore.Li@Sun.COM urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
914*9485SMikore.Li@Sun.COM {
915*9485SMikore.Li@Sun.COM 	uint8_t data;
916*9485SMikore.Li@Sun.COM 	usbd_status error;
917*9485SMikore.Li@Sun.COM 
918*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data))
919*9485SMikore.Li@Sun.COM 		goto fail;
920*9485SMikore.Li@Sun.COM 	if (bit != 0)
921*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
922*9485SMikore.Li@Sun.COM 		    data | URTW_EPROM_WRITEBIT);
923*9485SMikore.Li@Sun.COM 	else
924*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
925*9485SMikore.Li@Sun.COM 		    data & ~URTW_EPROM_WRITEBIT);
926*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
927*9485SMikore.Li@Sun.COM fail:
928*9485SMikore.Li@Sun.COM 	return (error);
929*9485SMikore.Li@Sun.COM }
930*9485SMikore.Li@Sun.COM 
931*9485SMikore.Li@Sun.COM static usbd_status
932*9485SMikore.Li@Sun.COM urtw_eprom_ck(struct urtw_softc *sc)
933*9485SMikore.Li@Sun.COM {
934*9485SMikore.Li@Sun.COM 	uint8_t data;
935*9485SMikore.Li@Sun.COM 	usbd_status error;
936*9485SMikore.Li@Sun.COM 
937*9485SMikore.Li@Sun.COM 	/* masking  */
938*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data))
939*9485SMikore.Li@Sun.COM 		goto fail;
940*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK))
941*9485SMikore.Li@Sun.COM 		goto fail;
942*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
943*9485SMikore.Li@Sun.COM 	/* unmasking  */
944*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data))
945*9485SMikore.Li@Sun.COM 		goto fail;
946*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK);
947*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
948*9485SMikore.Li@Sun.COM fail:
949*9485SMikore.Li@Sun.COM 	return (error);
950*9485SMikore.Li@Sun.COM }
951*9485SMikore.Li@Sun.COM 
952*9485SMikore.Li@Sun.COM static usbd_status
953*9485SMikore.Li@Sun.COM urtw_eprom_cs(struct urtw_softc *sc, int able)
954*9485SMikore.Li@Sun.COM {
955*9485SMikore.Li@Sun.COM 	uint8_t data;
956*9485SMikore.Li@Sun.COM 	usbd_status error;
957*9485SMikore.Li@Sun.COM 
958*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data))
959*9485SMikore.Li@Sun.COM 		goto fail;
960*9485SMikore.Li@Sun.COM 	if (able == URTW_EPROM_ENABLE)
961*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
962*9485SMikore.Li@Sun.COM 		    data | URTW_EPROM_CS);
963*9485SMikore.Li@Sun.COM 	else
964*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_EPROM_CMD,
965*9485SMikore.Li@Sun.COM 		    data & ~URTW_EPROM_CS);
966*9485SMikore.Li@Sun.COM 	DELAY(URTW_EPROM_DELAY);
967*9485SMikore.Li@Sun.COM fail:
968*9485SMikore.Li@Sun.COM 	return (error);
969*9485SMikore.Li@Sun.COM }
970*9485SMikore.Li@Sun.COM 
971*9485SMikore.Li@Sun.COM static usbd_status
972*9485SMikore.Li@Sun.COM urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data)
973*9485SMikore.Li@Sun.COM {
974*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
975*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
976*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
977*9485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
978*9485SMikore.Li@Sun.COM 	usbd_status error;
979*9485SMikore.Li@Sun.COM 
980*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
981*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
982*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
983*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
984*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
985*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
986*9485SMikore.Li@Sun.COM 
987*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
988*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
989*9485SMikore.Li@Sun.COM 
990*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
991*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
992*9485SMikore.Li@Sun.COM 		    "urtw_read8_c: get regs req failed :"
993*9485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
994*9485SMikore.Li@Sun.COM 		return (error);
995*9485SMikore.Li@Sun.COM 	}
996*9485SMikore.Li@Sun.COM 	bcopy(mp->b_rptr, data, sizeof (uint8_t));
997*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
998*9485SMikore.Li@Sun.COM 	    "urtw_read8_c: get regs data1 ok :0x%x", *data));
999*9485SMikore.Li@Sun.COM 	if (mp)
1000*9485SMikore.Li@Sun.COM 		freemsg(mp);
1001*9485SMikore.Li@Sun.COM 	return (error);
1002*9485SMikore.Li@Sun.COM }
1003*9485SMikore.Li@Sun.COM 
1004*9485SMikore.Li@Sun.COM static usbd_status
1005*9485SMikore.Li@Sun.COM urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
1006*9485SMikore.Li@Sun.COM {
1007*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1008*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1009*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1010*9485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
1011*9485SMikore.Li@Sun.COM 	usbd_status error;
1012*9485SMikore.Li@Sun.COM 
1013*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1014*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1015*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
1016*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xfe00;
1017*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1018*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
1019*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
1020*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1021*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1022*9485SMikore.Li@Sun.COM 
1023*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1024*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1025*9485SMikore.Li@Sun.COM 		    "urtw_read8e: get regs req failed :"
1026*9485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
1027*9485SMikore.Li@Sun.COM 		return (error);
1028*9485SMikore.Li@Sun.COM 	}
1029*9485SMikore.Li@Sun.COM 
1030*9485SMikore.Li@Sun.COM 	if (mp) {
1031*9485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint8_t));
1032*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1033*9485SMikore.Li@Sun.COM 		    "urtw_read8e: get regs data1 ok :0x%x", *data));
1034*9485SMikore.Li@Sun.COM 		freemsg(mp);
1035*9485SMikore.Li@Sun.COM 	}
1036*9485SMikore.Li@Sun.COM 	return (error);
1037*9485SMikore.Li@Sun.COM }
1038*9485SMikore.Li@Sun.COM 
1039*9485SMikore.Li@Sun.COM static usbd_status
1040*9485SMikore.Li@Sun.COM urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data)
1041*9485SMikore.Li@Sun.COM {
1042*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1043*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1044*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1045*9485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
1046*9485SMikore.Li@Sun.COM 	usbd_status error;
1047*9485SMikore.Li@Sun.COM 
1048*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1049*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1050*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
1051*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1052*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1053*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
1054*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
1055*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1056*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1057*9485SMikore.Li@Sun.COM 
1058*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1059*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1060*9485SMikore.Li@Sun.COM 		    "urtw_read16_c: get regs req failed :"
1061*9485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n",
1062*9485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
1063*9485SMikore.Li@Sun.COM 		return (error);
1064*9485SMikore.Li@Sun.COM 	}
1065*9485SMikore.Li@Sun.COM 	if (mp) {
1066*9485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint16_t));
1067*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1068*9485SMikore.Li@Sun.COM 		    "urtw_read16_c: get regs data2 ok :0x%x", *data));
1069*9485SMikore.Li@Sun.COM 		freemsg(mp);
1070*9485SMikore.Li@Sun.COM 	}
1071*9485SMikore.Li@Sun.COM 	return (error);
1072*9485SMikore.Li@Sun.COM }
1073*9485SMikore.Li@Sun.COM 
1074*9485SMikore.Li@Sun.COM static usbd_status
1075*9485SMikore.Li@Sun.COM urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data)
1076*9485SMikore.Li@Sun.COM {
1077*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1078*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1079*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1080*9485SMikore.Li@Sun.COM 	mblk_t *mp = NULL;
1081*9485SMikore.Li@Sun.COM 	usbd_status error;
1082*9485SMikore.Li@Sun.COM 
1083*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1084*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1085*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_GETREGS_REQ;
1086*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1087*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1088*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint32_t);
1089*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_AUTOCLEARING;
1090*9485SMikore.Li@Sun.COM 
1091*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1092*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1093*9485SMikore.Li@Sun.COM 
1094*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1095*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1096*9485SMikore.Li@Sun.COM 		    "urtw_read32_c: get regs req failed :"
1097*9485SMikore.Li@Sun.COM 		    " cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
1098*9485SMikore.Li@Sun.COM 		return (error);
1099*9485SMikore.Li@Sun.COM 	}
1100*9485SMikore.Li@Sun.COM 
1101*9485SMikore.Li@Sun.COM 	if (mp) {
1102*9485SMikore.Li@Sun.COM 		bcopy(mp->b_rptr, data, sizeof (uint32_t));
1103*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1104*9485SMikore.Li@Sun.COM 		    "urtw_read32_c: get regs data4 ok :0x%x", *data));
1105*9485SMikore.Li@Sun.COM 		freemsg(mp);
1106*9485SMikore.Li@Sun.COM 	}
1107*9485SMikore.Li@Sun.COM 	return (error);
1108*9485SMikore.Li@Sun.COM }
1109*9485SMikore.Li@Sun.COM 
1110*9485SMikore.Li@Sun.COM static usbd_status
1111*9485SMikore.Li@Sun.COM urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data)
1112*9485SMikore.Li@Sun.COM {
1113*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1114*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1115*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1116*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
1117*9485SMikore.Li@Sun.COM 	int error;
1118*9485SMikore.Li@Sun.COM 
1119*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1120*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1121*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
1122*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1123*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1124*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
1125*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
1126*9485SMikore.Li@Sun.COM 
1127*9485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint32_t), BPRI_MED);
1128*9485SMikore.Li@Sun.COM 	if (mp == NULL) {
1129*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write8_c: failed alloc mblk.");
1130*9485SMikore.Li@Sun.COM 		return (-1);
1131*9485SMikore.Li@Sun.COM 	}
1132*9485SMikore.Li@Sun.COM 	*(uint8_t *)(mp->b_rptr) = data;
1133*9485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint8_t);
1134*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1135*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1136*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1137*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1138*9485SMikore.Li@Sun.COM 		    "urtw_write8_c: could not set regs:"
1139*9485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n", usb_str_cr(cr), cr, cf));
1140*9485SMikore.Li@Sun.COM 	}
1141*9485SMikore.Li@Sun.COM 	if (mp)
1142*9485SMikore.Li@Sun.COM 		freemsg(mp);
1143*9485SMikore.Li@Sun.COM 	return (error);
1144*9485SMikore.Li@Sun.COM }
1145*9485SMikore.Li@Sun.COM 
1146*9485SMikore.Li@Sun.COM static usbd_status
1147*9485SMikore.Li@Sun.COM urtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
1148*9485SMikore.Li@Sun.COM {
1149*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1150*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1151*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1152*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
1153*9485SMikore.Li@Sun.COM 	int error;
1154*9485SMikore.Li@Sun.COM 
1155*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1156*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1157*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
1158*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xfe00;
1159*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1160*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint8_t);
1161*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
1162*9485SMikore.Li@Sun.COM 
1163*9485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint8_t), BPRI_MED);
1164*9485SMikore.Li@Sun.COM 	if (mp == NULL) {
1165*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write8e: failed alloc mblk.");
1166*9485SMikore.Li@Sun.COM 		return (-1);
1167*9485SMikore.Li@Sun.COM 	}
1168*9485SMikore.Li@Sun.COM 	*(mp->b_rptr) = data;
1169*9485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint8_t);
1170*9485SMikore.Li@Sun.COM 
1171*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1172*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1173*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1174*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1175*9485SMikore.Li@Sun.COM 		    "urtw_write8e: could not set regs:"
1176*9485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
1177*9485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
1178*9485SMikore.Li@Sun.COM 	}
1179*9485SMikore.Li@Sun.COM 	if (mp)
1180*9485SMikore.Li@Sun.COM 		freemsg(mp);
1181*9485SMikore.Li@Sun.COM 	return (error);
1182*9485SMikore.Li@Sun.COM }
1183*9485SMikore.Li@Sun.COM 
1184*9485SMikore.Li@Sun.COM static usbd_status
1185*9485SMikore.Li@Sun.COM urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data)
1186*9485SMikore.Li@Sun.COM {
1187*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1188*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1189*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1190*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
1191*9485SMikore.Li@Sun.COM 	int error;
1192*9485SMikore.Li@Sun.COM 
1193*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1194*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1195*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
1196*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1197*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1198*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint16_t);
1199*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
1200*9485SMikore.Li@Sun.COM 
1201*9485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint16_t), BPRI_MED);
1202*9485SMikore.Li@Sun.COM 	if (mp == NULL) {
1203*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write16_c: failed alloc mblk.");
1204*9485SMikore.Li@Sun.COM 		return (-1);
1205*9485SMikore.Li@Sun.COM 	}
1206*9485SMikore.Li@Sun.COM 	*(uint16_t *)(uintptr_t)(mp->b_rptr) = data;
1207*9485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint16_t);
1208*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1209*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1210*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1211*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1212*9485SMikore.Li@Sun.COM 		    "urtw_write16_c: could not set regs:"
1213*9485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
1214*9485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
1215*9485SMikore.Li@Sun.COM 	}
1216*9485SMikore.Li@Sun.COM 	if (mp)
1217*9485SMikore.Li@Sun.COM 		freemsg(mp);
1218*9485SMikore.Li@Sun.COM 	return (error);
1219*9485SMikore.Li@Sun.COM }
1220*9485SMikore.Li@Sun.COM 
1221*9485SMikore.Li@Sun.COM static usbd_status
1222*9485SMikore.Li@Sun.COM urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data)
1223*9485SMikore.Li@Sun.COM {
1224*9485SMikore.Li@Sun.COM 	usb_ctrl_setup_t req;
1225*9485SMikore.Li@Sun.COM 	usb_cr_t cr;
1226*9485SMikore.Li@Sun.COM 	usb_cb_flags_t cf;
1227*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
1228*9485SMikore.Li@Sun.COM 	int error;
1229*9485SMikore.Li@Sun.COM 
1230*9485SMikore.Li@Sun.COM 	bzero(&req, sizeof (req));
1231*9485SMikore.Li@Sun.COM 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1232*9485SMikore.Li@Sun.COM 	req.bRequest = URTW_8187_SETREGS_REQ;
1233*9485SMikore.Li@Sun.COM 	req.wValue = val | 0xff00;
1234*9485SMikore.Li@Sun.COM 	req.wIndex = 0;
1235*9485SMikore.Li@Sun.COM 	req.wLength = sizeof (uint32_t);
1236*9485SMikore.Li@Sun.COM 	req.attrs = USB_ATTRS_NONE;
1237*9485SMikore.Li@Sun.COM 
1238*9485SMikore.Li@Sun.COM 	mp = allocb(sizeof (uint32_t), BPRI_MED);
1239*9485SMikore.Li@Sun.COM 	if (mp == NULL) {
1240*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_write32_c: failed alloc mblk.");
1241*9485SMikore.Li@Sun.COM 		return (-1);
1242*9485SMikore.Li@Sun.COM 	}
1243*9485SMikore.Li@Sun.COM 	*(uint32_t *)(uintptr_t)(mp->b_rptr) = data;
1244*9485SMikore.Li@Sun.COM 	mp->b_wptr += sizeof (uint32_t);
1245*9485SMikore.Li@Sun.COM 	error = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
1246*9485SMikore.Li@Sun.COM 	    &cr, &cf, 0);
1247*9485SMikore.Li@Sun.COM 	if (error != USB_SUCCESS) {
1248*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_DEVREQ, (sc->sc_dev, CE_CONT,
1249*9485SMikore.Li@Sun.COM 		    "urtw_write32_c: could not set regs:"
1250*9485SMikore.Li@Sun.COM 		    "cr:%s(%d), cf:(%x)\n",
1251*9485SMikore.Li@Sun.COM 		    usb_str_cr(cr), cr, cf));
1252*9485SMikore.Li@Sun.COM 	}
1253*9485SMikore.Li@Sun.COM 
1254*9485SMikore.Li@Sun.COM 	if (mp)
1255*9485SMikore.Li@Sun.COM 		freemsg(mp);
1256*9485SMikore.Li@Sun.COM 	return (error);
1257*9485SMikore.Li@Sun.COM }
1258*9485SMikore.Li@Sun.COM 
1259*9485SMikore.Li@Sun.COM static usbd_status
1260*9485SMikore.Li@Sun.COM urtw_set_mode(struct urtw_softc *sc, uint32_t mode)
1261*9485SMikore.Li@Sun.COM {
1262*9485SMikore.Li@Sun.COM 	uint8_t data;
1263*9485SMikore.Li@Sun.COM 	usbd_status error;
1264*9485SMikore.Li@Sun.COM 
1265*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_EPROM_CMD, &data))
1266*9485SMikore.Li@Sun.COM 		goto fail;
1267*9485SMikore.Li@Sun.COM 	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
1268*9485SMikore.Li@Sun.COM 	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
1269*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_EPROM_CMD, data);
1270*9485SMikore.Li@Sun.COM fail:
1271*9485SMikore.Li@Sun.COM 	return (error);
1272*9485SMikore.Li@Sun.COM }
1273*9485SMikore.Li@Sun.COM 
1274*9485SMikore.Li@Sun.COM static usbd_status
1275*9485SMikore.Li@Sun.COM urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
1276*9485SMikore.Li@Sun.COM {
1277*9485SMikore.Li@Sun.COM 	uint8_t data;
1278*9485SMikore.Li@Sun.COM 	usbd_status error;
1279*9485SMikore.Li@Sun.COM 
1280*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1281*9485SMikore.Li@Sun.COM 	if (error)
1282*9485SMikore.Li@Sun.COM 		goto fail;
1283*9485SMikore.Li@Sun.COM 
1284*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data))
1285*9485SMikore.Li@Sun.COM 		goto fail;
1286*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1287*9485SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE))
1288*9485SMikore.Li@Sun.COM 		goto fail;
1289*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_ANAPARAM, val))
1290*9485SMikore.Li@Sun.COM 		goto fail;
1291*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data))
1292*9485SMikore.Li@Sun.COM 		goto fail;
1293*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1294*9485SMikore.Li@Sun.COM 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE))
1295*9485SMikore.Li@Sun.COM 		goto fail;
1296*9485SMikore.Li@Sun.COM 
1297*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1298*9485SMikore.Li@Sun.COM 	if (error)
1299*9485SMikore.Li@Sun.COM 		goto fail;
1300*9485SMikore.Li@Sun.COM fail:
1301*9485SMikore.Li@Sun.COM 	return (error);
1302*9485SMikore.Li@Sun.COM }
1303*9485SMikore.Li@Sun.COM 
1304*9485SMikore.Li@Sun.COM static usbd_status
1305*9485SMikore.Li@Sun.COM urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
1306*9485SMikore.Li@Sun.COM {
1307*9485SMikore.Li@Sun.COM 	uint8_t data;
1308*9485SMikore.Li@Sun.COM 	usbd_status error;
1309*9485SMikore.Li@Sun.COM 
1310*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1311*9485SMikore.Li@Sun.COM 	if (error)
1312*9485SMikore.Li@Sun.COM 		goto fail;
1313*9485SMikore.Li@Sun.COM 
1314*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data))
1315*9485SMikore.Li@Sun.COM 		goto fail;
1316*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1317*9485SMikore.Li@Sun.COM 	    data | URTW_CONFIG3_ANAPARAM_WRITE))
1318*9485SMikore.Li@Sun.COM 		goto fail;
1319*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_ANAPARAM2, val))
1320*9485SMikore.Li@Sun.COM 		goto fail;
1321*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CONFIG3, &data))
1322*9485SMikore.Li@Sun.COM 		goto fail;
1323*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3,
1324*9485SMikore.Li@Sun.COM 	    data & ~URTW_CONFIG3_ANAPARAM_WRITE))
1325*9485SMikore.Li@Sun.COM 		goto fail;
1326*9485SMikore.Li@Sun.COM 
1327*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1328*9485SMikore.Li@Sun.COM 	if (error)
1329*9485SMikore.Li@Sun.COM 		goto fail;
1330*9485SMikore.Li@Sun.COM fail:
1331*9485SMikore.Li@Sun.COM 	return (error);
1332*9485SMikore.Li@Sun.COM }
1333*9485SMikore.Li@Sun.COM 
1334*9485SMikore.Li@Sun.COM static usbd_status
1335*9485SMikore.Li@Sun.COM urtw_intr_disable(struct urtw_softc *sc)
1336*9485SMikore.Li@Sun.COM {
1337*9485SMikore.Li@Sun.COM 	usbd_status error;
1338*9485SMikore.Li@Sun.COM 
1339*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0);
1340*9485SMikore.Li@Sun.COM 	return (error);
1341*9485SMikore.Li@Sun.COM }
1342*9485SMikore.Li@Sun.COM 
1343*9485SMikore.Li@Sun.COM static usbd_status
1344*9485SMikore.Li@Sun.COM urtw_reset(struct urtw_softc *sc)
1345*9485SMikore.Li@Sun.COM {
1346*9485SMikore.Li@Sun.COM 	uint8_t data;
1347*9485SMikore.Li@Sun.COM 	usbd_status error;
1348*9485SMikore.Li@Sun.COM 
1349*9485SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
1350*9485SMikore.Li@Sun.COM 	if (error)
1351*9485SMikore.Li@Sun.COM 		goto fail;
1352*9485SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
1353*9485SMikore.Li@Sun.COM 	if (error)
1354*9485SMikore.Li@Sun.COM 		goto fail;
1355*9485SMikore.Li@Sun.COM 
1356*9485SMikore.Li@Sun.COM 	error = urtw_intr_disable(sc);
1357*9485SMikore.Li@Sun.COM 	if (error)
1358*9485SMikore.Li@Sun.COM 		goto fail;
1359*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
1360*9485SMikore.Li@Sun.COM 
1361*9485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x10);
1362*9485SMikore.Li@Sun.COM 	if (error != 0)
1363*9485SMikore.Li@Sun.COM 		goto fail;
1364*9485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x11);
1365*9485SMikore.Li@Sun.COM 	if (error != 0)
1366*9485SMikore.Li@Sun.COM 		goto fail;
1367*9485SMikore.Li@Sun.COM 	error = urtw_write8e(sc, 0x18, 0x00);
1368*9485SMikore.Li@Sun.COM 	if (error != 0)
1369*9485SMikore.Li@Sun.COM 		goto fail;
1370*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
1371*9485SMikore.Li@Sun.COM 
1372*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data))
1373*9485SMikore.Li@Sun.COM 		goto fail;
1374*9485SMikore.Li@Sun.COM 	data = (data & 2) | URTW_CMD_RST;
1375*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CMD, data))
1376*9485SMikore.Li@Sun.COM 		goto fail;
1377*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
1378*9485SMikore.Li@Sun.COM 
1379*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data))
1380*9485SMikore.Li@Sun.COM 		goto fail;
1381*9485SMikore.Li@Sun.COM 	if (data & URTW_CMD_RST) {
1382*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw reset timeout\n");
1383*9485SMikore.Li@Sun.COM 		goto fail;
1384*9485SMikore.Li@Sun.COM 	}
1385*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
1386*9485SMikore.Li@Sun.COM 	if (error)
1387*9485SMikore.Li@Sun.COM 		goto fail;
1388*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
1389*9485SMikore.Li@Sun.COM 
1390*9485SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
1391*9485SMikore.Li@Sun.COM 	if (error)
1392*9485SMikore.Li@Sun.COM 		goto fail;
1393*9485SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
1394*9485SMikore.Li@Sun.COM 	if (error)
1395*9485SMikore.Li@Sun.COM 		goto fail;
1396*9485SMikore.Li@Sun.COM fail:
1397*9485SMikore.Li@Sun.COM 	return (error);
1398*9485SMikore.Li@Sun.COM }
1399*9485SMikore.Li@Sun.COM 
1400*9485SMikore.Li@Sun.COM static usbd_status
1401*9485SMikore.Li@Sun.COM urtw_led_on(struct urtw_softc *sc, int type)
1402*9485SMikore.Li@Sun.COM {
1403*9485SMikore.Li@Sun.COM 	if (type == URTW_LED_GPIO) {
1404*9485SMikore.Li@Sun.COM 		switch (sc->sc_gpio_ledpin) {
1405*9485SMikore.Li@Sun.COM 		case URTW_LED_PIN_GPIO0:
1406*9485SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01);
1407*9485SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x00);
1408*9485SMikore.Li@Sun.COM 			break;
1409*9485SMikore.Li@Sun.COM 		default:
1410*9485SMikore.Li@Sun.COM 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
1411*9485SMikore.Li@Sun.COM 			    sc->sc_gpio_ledpin);
1412*9485SMikore.Li@Sun.COM 			/* never reach  */
1413*9485SMikore.Li@Sun.COM 		}
1414*9485SMikore.Li@Sun.COM 	} else {
1415*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
1416*9485SMikore.Li@Sun.COM 		/* never reach  */
1417*9485SMikore.Li@Sun.COM 	}
1418*9485SMikore.Li@Sun.COM 
1419*9485SMikore.Li@Sun.COM 	sc->sc_gpio_ledon = 1;
1420*9485SMikore.Li@Sun.COM 	return (0);
1421*9485SMikore.Li@Sun.COM }
1422*9485SMikore.Li@Sun.COM 
1423*9485SMikore.Li@Sun.COM static usbd_status
1424*9485SMikore.Li@Sun.COM urtw_led_off(struct urtw_softc *sc, int type)
1425*9485SMikore.Li@Sun.COM {
1426*9485SMikore.Li@Sun.COM 	if (type == URTW_LED_GPIO) {
1427*9485SMikore.Li@Sun.COM 		switch (sc->sc_gpio_ledpin) {
1428*9485SMikore.Li@Sun.COM 		case URTW_LED_PIN_GPIO0:
1429*9485SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GPIO, 0x01);
1430*9485SMikore.Li@Sun.COM 			(void) urtw_write8_c(sc, URTW_GP_ENABLE, 0x01);
1431*9485SMikore.Li@Sun.COM 			break;
1432*9485SMikore.Li@Sun.COM 		default:
1433*9485SMikore.Li@Sun.COM 			cmn_err(CE_WARN, "unsupported LED PIN type 0x%x",
1434*9485SMikore.Li@Sun.COM 			    sc->sc_gpio_ledpin);
1435*9485SMikore.Li@Sun.COM 			/* never reach  */
1436*9485SMikore.Li@Sun.COM 		}
1437*9485SMikore.Li@Sun.COM 	} else {
1438*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "unsupported LED type 0x%x", type);
1439*9485SMikore.Li@Sun.COM 		/* never reach  */
1440*9485SMikore.Li@Sun.COM 	}
1441*9485SMikore.Li@Sun.COM 
1442*9485SMikore.Li@Sun.COM 	sc->sc_gpio_ledon = 0;
1443*9485SMikore.Li@Sun.COM 	return (0);
1444*9485SMikore.Li@Sun.COM }
1445*9485SMikore.Li@Sun.COM 
1446*9485SMikore.Li@Sun.COM static usbd_status
1447*9485SMikore.Li@Sun.COM urtw_led_mode0(struct urtw_softc *sc, int mode)
1448*9485SMikore.Li@Sun.COM {
1449*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1450*9485SMikore.Li@Sun.COM 	    "urtw_led_mode0: mode = %d\n", mode));
1451*9485SMikore.Li@Sun.COM 	switch (mode) {
1452*9485SMikore.Li@Sun.COM 	case URTW_LED_CTL_POWER_ON:
1453*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
1454*9485SMikore.Li@Sun.COM 		break;
1455*9485SMikore.Li@Sun.COM 	case URTW_LED_CTL_TX:
1456*9485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress == 1)
1457*9485SMikore.Li@Sun.COM 			return (0);
1458*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
1459*9485SMikore.Li@Sun.COM 		sc->sc_gpio_blinktime =
1460*9485SMikore.Li@Sun.COM 		    (sc->sc_ic.ic_state == IEEE80211_S_RUN ? 4:2);
1461*9485SMikore.Li@Sun.COM 		break;
1462*9485SMikore.Li@Sun.COM 	case URTW_LED_CTL_LINK:
1463*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledstate = URTW_LED_ON;
1464*9485SMikore.Li@Sun.COM 		break;
1465*9485SMikore.Li@Sun.COM 	default:
1466*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "unsupported LED mode 0x%x", mode);
1467*9485SMikore.Li@Sun.COM 		/* never reach  */
1468*9485SMikore.Li@Sun.COM 	}
1469*9485SMikore.Li@Sun.COM 
1470*9485SMikore.Li@Sun.COM 	switch (sc->sc_gpio_ledstate) {
1471*9485SMikore.Li@Sun.COM 	case URTW_LED_ON:
1472*9485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress != 0)
1473*9485SMikore.Li@Sun.COM 			break;
1474*9485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
1475*9485SMikore.Li@Sun.COM 		break;
1476*9485SMikore.Li@Sun.COM 	case URTW_LED_BLINK_NORMAL:
1477*9485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledinprogress != 0)
1478*9485SMikore.Li@Sun.COM 			break;
1479*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 1;
1480*9485SMikore.Li@Sun.COM 		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
1481*9485SMikore.Li@Sun.COM 		    URTW_LED_OFF : URTW_LED_ON;
1482*9485SMikore.Li@Sun.COM 		URTW_LEDLOCK(sc);
1483*9485SMikore.Li@Sun.COM 		if (sc->sc_led_ch == 0) {
1484*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1485*9485SMikore.Li@Sun.COM 			    "urtw_led_mode0: restart led timer\n"));
1486*9485SMikore.Li@Sun.COM 			sc->sc_led_ch = timeout(urtw_led_launch,
1487*9485SMikore.Li@Sun.COM 			    (void *)sc,
1488*9485SMikore.Li@Sun.COM 			    drv_usectohz((sc->sc_ic.ic_state ==
1489*9485SMikore.Li@Sun.COM 			    IEEE80211_S_RUN) ?
1490*9485SMikore.Li@Sun.COM 			    URTW_LED_LINKON_BLINK :
1491*9485SMikore.Li@Sun.COM 			    URTW_LED_LINKOFF_BLINK));
1492*9485SMikore.Li@Sun.COM 			sc->sc_gpio_ledinprogress = 0;
1493*9485SMikore.Li@Sun.COM 		}
1494*9485SMikore.Li@Sun.COM 		URTW_LEDUNLOCK(sc);
1495*9485SMikore.Li@Sun.COM 		break;
1496*9485SMikore.Li@Sun.COM 	case URTW_LED_POWER_ON_BLINK:
1497*9485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
1498*9485SMikore.Li@Sun.COM 		urtw_delay_ms(100);
1499*9485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
1500*9485SMikore.Li@Sun.COM 		break;
1501*9485SMikore.Li@Sun.COM 	default:
1502*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1503*9485SMikore.Li@Sun.COM 		    "urtw_led_mode0: unknown LED status 0x%x",
1504*9485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate));
1505*9485SMikore.Li@Sun.COM 	}
1506*9485SMikore.Li@Sun.COM 	return (0);
1507*9485SMikore.Li@Sun.COM }
1508*9485SMikore.Li@Sun.COM 
1509*9485SMikore.Li@Sun.COM static usbd_status
1510*9485SMikore.Li@Sun.COM urtw_led_mode1(struct urtw_softc *sc, int mode)
1511*9485SMikore.Li@Sun.COM {
1512*9485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
1513*9485SMikore.Li@Sun.COM 	return (USBD_INVAL);
1514*9485SMikore.Li@Sun.COM }
1515*9485SMikore.Li@Sun.COM 
1516*9485SMikore.Li@Sun.COM static usbd_status
1517*9485SMikore.Li@Sun.COM urtw_led_mode2(struct urtw_softc *sc, int mode)
1518*9485SMikore.Li@Sun.COM {
1519*9485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
1520*9485SMikore.Li@Sun.COM 	return (USBD_INVAL);
1521*9485SMikore.Li@Sun.COM }
1522*9485SMikore.Li@Sun.COM 
1523*9485SMikore.Li@Sun.COM static usbd_status
1524*9485SMikore.Li@Sun.COM urtw_led_mode3(struct urtw_softc *sc, int mode)
1525*9485SMikore.Li@Sun.COM {
1526*9485SMikore.Li@Sun.COM 	cmn_err(CE_WARN, "urtw sc %p, mode %d not supported", (void *)sc, mode);
1527*9485SMikore.Li@Sun.COM 	return (USBD_INVAL);
1528*9485SMikore.Li@Sun.COM }
1529*9485SMikore.Li@Sun.COM 
1530*9485SMikore.Li@Sun.COM static usbd_status
1531*9485SMikore.Li@Sun.COM urtw_led_blink(struct urtw_softc *sc)
1532*9485SMikore.Li@Sun.COM {
1533*9485SMikore.Li@Sun.COM 	uint8_t ing = 0;
1534*9485SMikore.Li@Sun.COM 
1535*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1536*9485SMikore.Li@Sun.COM 	    "urtw_led_blink: gpio_blinkstate %d\n",
1537*9485SMikore.Li@Sun.COM 	    sc->sc_gpio_blinkstate));
1538*9485SMikore.Li@Sun.COM 	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
1539*9485SMikore.Li@Sun.COM 		(void) urtw_led_on(sc, URTW_LED_GPIO);
1540*9485SMikore.Li@Sun.COM 	else
1541*9485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
1542*9485SMikore.Li@Sun.COM 	sc->sc_gpio_blinktime--;
1543*9485SMikore.Li@Sun.COM 	if (sc->sc_gpio_blinktime == 0)
1544*9485SMikore.Li@Sun.COM 		ing = 1;
1545*9485SMikore.Li@Sun.COM 	else {
1546*9485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
1547*9485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
1548*9485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
1549*9485SMikore.Li@Sun.COM 			ing = 1;
1550*9485SMikore.Li@Sun.COM 	}
1551*9485SMikore.Li@Sun.COM 	if (ing == 1) {
1552*9485SMikore.Li@Sun.COM 		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
1553*9485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledon == 0)
1554*9485SMikore.Li@Sun.COM 			(void) urtw_led_on(sc, URTW_LED_GPIO);
1555*9485SMikore.Li@Sun.COM 		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
1556*9485SMikore.Li@Sun.COM 		    sc->sc_gpio_ledon == 1)
1557*9485SMikore.Li@Sun.COM 			(void) urtw_led_off(sc, URTW_LED_GPIO);
1558*9485SMikore.Li@Sun.COM 
1559*9485SMikore.Li@Sun.COM 		sc->sc_gpio_blinktime = 0;
1560*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 0;
1561*9485SMikore.Li@Sun.COM 		return (0);
1562*9485SMikore.Li@Sun.COM 	}
1563*9485SMikore.Li@Sun.COM 
1564*9485SMikore.Li@Sun.COM 	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
1565*9485SMikore.Li@Sun.COM 	    URTW_LED_ON : URTW_LED_OFF;
1566*9485SMikore.Li@Sun.COM 
1567*9485SMikore.Li@Sun.COM 	switch (sc->sc_gpio_ledstate) {
1568*9485SMikore.Li@Sun.COM 	case URTW_LED_BLINK_NORMAL:
1569*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1570*9485SMikore.Li@Sun.COM 		    "URTW_LED_BLINK_NORMAL\n"));
1571*9485SMikore.Li@Sun.COM 		return (1);
1572*9485SMikore.Li@Sun.COM 	default:
1573*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
1574*9485SMikore.Li@Sun.COM 		    "unknown LED status 0x%x", sc->sc_gpio_ledstate));
1575*9485SMikore.Li@Sun.COM 	}
1576*9485SMikore.Li@Sun.COM 	return (0);
1577*9485SMikore.Li@Sun.COM }
1578*9485SMikore.Li@Sun.COM 
1579*9485SMikore.Li@Sun.COM static usbd_status
1580*9485SMikore.Li@Sun.COM urtw_led_ctl(struct urtw_softc *sc, int mode)
1581*9485SMikore.Li@Sun.COM {
1582*9485SMikore.Li@Sun.COM 	usbd_status error = 0;
1583*9485SMikore.Li@Sun.COM 
1584*9485SMikore.Li@Sun.COM 	switch (sc->sc_strategy) {
1585*9485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE0:
1586*9485SMikore.Li@Sun.COM 		error = urtw_led_mode0(sc, mode);
1587*9485SMikore.Li@Sun.COM 		break;
1588*9485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE1:
1589*9485SMikore.Li@Sun.COM 		error = urtw_led_mode1(sc, mode);
1590*9485SMikore.Li@Sun.COM 		break;
1591*9485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE2:
1592*9485SMikore.Li@Sun.COM 		error = urtw_led_mode2(sc, mode);
1593*9485SMikore.Li@Sun.COM 		break;
1594*9485SMikore.Li@Sun.COM 	case URTW_SW_LED_MODE3:
1595*9485SMikore.Li@Sun.COM 		error = urtw_led_mode3(sc, mode);
1596*9485SMikore.Li@Sun.COM 		break;
1597*9485SMikore.Li@Sun.COM 	default:
1598*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "unsupported LED mode %d\n", sc->sc_strategy);
1599*9485SMikore.Li@Sun.COM 		/* never reach  */
1600*9485SMikore.Li@Sun.COM 		return (-1);
1601*9485SMikore.Li@Sun.COM 	}
1602*9485SMikore.Li@Sun.COM 
1603*9485SMikore.Li@Sun.COM 	return (error);
1604*9485SMikore.Li@Sun.COM }
1605*9485SMikore.Li@Sun.COM 
1606*9485SMikore.Li@Sun.COM static usbd_status
1607*9485SMikore.Li@Sun.COM urtw_update_msr(struct urtw_softc *sc, int nstate)
1608*9485SMikore.Li@Sun.COM {
1609*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
1610*9485SMikore.Li@Sun.COM 	uint8_t data;
1611*9485SMikore.Li@Sun.COM 	usbd_status error;
1612*9485SMikore.Li@Sun.COM 
1613*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_MSR, &data))
1614*9485SMikore.Li@Sun.COM 		goto fail;
1615*9485SMikore.Li@Sun.COM 	data &= ~URTW_MSR_LINK_MASK;
1616*9485SMikore.Li@Sun.COM 
1617*9485SMikore.Li@Sun.COM 	if (nstate == IEEE80211_S_RUN) {
1618*9485SMikore.Li@Sun.COM 		switch (ic->ic_opmode) {
1619*9485SMikore.Li@Sun.COM 		case IEEE80211_M_STA:
1620*9485SMikore.Li@Sun.COM 		case IEEE80211_M_MONITOR:
1621*9485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_STA;
1622*9485SMikore.Li@Sun.COM 			break;
1623*9485SMikore.Li@Sun.COM 		case IEEE80211_M_IBSS:
1624*9485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_ADHOC;
1625*9485SMikore.Li@Sun.COM 			break;
1626*9485SMikore.Li@Sun.COM 		case IEEE80211_M_HOSTAP:
1627*9485SMikore.Li@Sun.COM 			data |= URTW_MSR_LINK_HOSTAP;
1628*9485SMikore.Li@Sun.COM 			break;
1629*9485SMikore.Li@Sun.COM 		default:
1630*9485SMikore.Li@Sun.COM 			cmn_err(CE_CONT, "unsupported operation mode 0x%x\n",
1631*9485SMikore.Li@Sun.COM 			    ic->ic_opmode);
1632*9485SMikore.Li@Sun.COM 			return (-1);
1633*9485SMikore.Li@Sun.COM 		}
1634*9485SMikore.Li@Sun.COM 	} else
1635*9485SMikore.Li@Sun.COM 		data |= URTW_MSR_LINK_NONE;
1636*9485SMikore.Li@Sun.COM 
1637*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_MSR, data);
1638*9485SMikore.Li@Sun.COM 	drv_usecwait(10000);
1639*9485SMikore.Li@Sun.COM fail:
1640*9485SMikore.Li@Sun.COM 	return (error);
1641*9485SMikore.Li@Sun.COM }
1642*9485SMikore.Li@Sun.COM 
1643*9485SMikore.Li@Sun.COM static uint16_t
1644*9485SMikore.Li@Sun.COM urtw_rate2rtl(int rate)
1645*9485SMikore.Li@Sun.COM {
1646*9485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
1647*9485SMikore.Li@Sun.COM 	int i;
1648*9485SMikore.Li@Sun.COM 
1649*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_ratetable); i++) {
1650*9485SMikore.Li@Sun.COM 		if (rate == urtw_ratetable[i].reg)
1651*9485SMikore.Li@Sun.COM 			return (urtw_ratetable[i].val);
1652*9485SMikore.Li@Sun.COM 	}
1653*9485SMikore.Li@Sun.COM 	return (3);
1654*9485SMikore.Li@Sun.COM #undef N
1655*9485SMikore.Li@Sun.COM }
1656*9485SMikore.Li@Sun.COM 
1657*9485SMikore.Li@Sun.COM static uint16_t
1658*9485SMikore.Li@Sun.COM urtw_rtl2rate(int rate)
1659*9485SMikore.Li@Sun.COM {
1660*9485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
1661*9485SMikore.Li@Sun.COM 	int i;
1662*9485SMikore.Li@Sun.COM 
1663*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_ratetable); i++) {
1664*9485SMikore.Li@Sun.COM 		if (rate == urtw_ratetable[i].val)
1665*9485SMikore.Li@Sun.COM 			return (urtw_ratetable[i].reg);
1666*9485SMikore.Li@Sun.COM 	}
1667*9485SMikore.Li@Sun.COM 
1668*9485SMikore.Li@Sun.COM 	return (0);
1669*9485SMikore.Li@Sun.COM #undef N
1670*9485SMikore.Li@Sun.COM }
1671*9485SMikore.Li@Sun.COM 
1672*9485SMikore.Li@Sun.COM static usbd_status
1673*9485SMikore.Li@Sun.COM urtw_set_rate(struct urtw_softc *sc)
1674*9485SMikore.Li@Sun.COM {
1675*9485SMikore.Li@Sun.COM 	int i, basic_rate, min_rr_rate, max_rr_rate;
1676*9485SMikore.Li@Sun.COM 	uint16_t data;
1677*9485SMikore.Li@Sun.COM 	usbd_status error;
1678*9485SMikore.Li@Sun.COM 
1679*9485SMikore.Li@Sun.COM 	basic_rate = urtw_rate2rtl(48);
1680*9485SMikore.Li@Sun.COM 	min_rr_rate = urtw_rate2rtl(12);
1681*9485SMikore.Li@Sun.COM 	max_rr_rate = urtw_rate2rtl(48);
1682*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RESP_RATE,
1683*9485SMikore.Li@Sun.COM 	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
1684*9485SMikore.Li@Sun.COM 	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT))
1685*9485SMikore.Li@Sun.COM 		goto fail;
1686*9485SMikore.Li@Sun.COM 
1687*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data))
1688*9485SMikore.Li@Sun.COM 		goto fail;
1689*9485SMikore.Li@Sun.COM 	data &= ~URTW_BRSR_MBR_8185;
1690*9485SMikore.Li@Sun.COM 
1691*9485SMikore.Li@Sun.COM 	for (i = 0; i <= basic_rate; i++)
1692*9485SMikore.Li@Sun.COM 		data |= (1 << i);
1693*9485SMikore.Li@Sun.COM 
1694*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_BRSR, data);
1695*9485SMikore.Li@Sun.COM fail:
1696*9485SMikore.Li@Sun.COM 	return (error);
1697*9485SMikore.Li@Sun.COM }
1698*9485SMikore.Li@Sun.COM 
1699*9485SMikore.Li@Sun.COM static usbd_status
1700*9485SMikore.Li@Sun.COM urtw_intr_enable(struct urtw_softc *sc)
1701*9485SMikore.Li@Sun.COM {
1702*9485SMikore.Li@Sun.COM 	usbd_status error;
1703*9485SMikore.Li@Sun.COM 
1704*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_INTR_MASK, 0xffff);
1705*9485SMikore.Li@Sun.COM 	return (error);
1706*9485SMikore.Li@Sun.COM }
1707*9485SMikore.Li@Sun.COM 
1708*9485SMikore.Li@Sun.COM static usbd_status
1709*9485SMikore.Li@Sun.COM urtw_adapter_start(struct urtw_softc *sc)
1710*9485SMikore.Li@Sun.COM {
1711*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
1712*9485SMikore.Li@Sun.COM 	usbd_status error;
1713*9485SMikore.Li@Sun.COM 	int i = 0;
1714*9485SMikore.Li@Sun.COM 
1715*9485SMikore.Li@Sun.COM 	error = urtw_reset(sc);
1716*9485SMikore.Li@Sun.COM 	if (error)
1717*9485SMikore.Li@Sun.COM 		goto fail;
1718*9485SMikore.Li@Sun.COM 
1719*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x85, 0))
1720*9485SMikore.Li@Sun.COM 		goto fail;
1721*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GPIO, 0))
1722*9485SMikore.Li@Sun.COM 		goto fail;
1723*9485SMikore.Li@Sun.COM 
1724*9485SMikore.Li@Sun.COM 	/* for led  */
1725*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x85, 4))
1726*9485SMikore.Li@Sun.COM 		goto fail;
1727*9485SMikore.Li@Sun.COM 	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
1728*9485SMikore.Li@Sun.COM 	if (error != 0)
1729*9485SMikore.Li@Sun.COM 		goto fail;
1730*9485SMikore.Li@Sun.COM 
1731*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
1732*9485SMikore.Li@Sun.COM 	if (error)
1733*9485SMikore.Li@Sun.COM 		goto fail;
1734*9485SMikore.Li@Sun.COM 	/* applying MAC address again.  */
1735*9485SMikore.Li@Sun.COM 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
1736*9485SMikore.Li@Sun.COM 		(void) urtw_write8_c(sc, URTW_MAC0 + i,
1737*9485SMikore.Li@Sun.COM 		    ic->ic_macaddr[i]);
1738*9485SMikore.Li@Sun.COM 	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1739*9485SMikore.Li@Sun.COM 	if (error)
1740*9485SMikore.Li@Sun.COM 		goto fail;
1741*9485SMikore.Li@Sun.COM 
1742*9485SMikore.Li@Sun.COM 	error = urtw_update_msr(sc, IEEE80211_S_INIT);
1743*9485SMikore.Li@Sun.COM 	if (error)
1744*9485SMikore.Li@Sun.COM 		goto fail;
1745*9485SMikore.Li@Sun.COM 
1746*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_INT_TIMEOUT, 0))
1747*9485SMikore.Li@Sun.COM 		goto fail;
1748*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_WPA_CONFIG, 0))
1749*9485SMikore.Li@Sun.COM 		goto fail;
1750*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RATE_FALLBACK, 0x81))
1751*9485SMikore.Li@Sun.COM 		goto fail;
1752*9485SMikore.Li@Sun.COM 	error = urtw_set_rate(sc);
1753*9485SMikore.Li@Sun.COM 	if (error != 0)
1754*9485SMikore.Li@Sun.COM 		goto fail;
1755*9485SMikore.Li@Sun.COM 
1756*9485SMikore.Li@Sun.COM 	error = sc->sc_rf_init(sc);
1757*9485SMikore.Li@Sun.COM 	if (error != 0)
1758*9485SMikore.Li@Sun.COM 		goto fail;
1759*9485SMikore.Li@Sun.COM 	if (sc->sc_rf_set_sens != NULL)
1760*9485SMikore.Li@Sun.COM 		sc->sc_rf_set_sens(sc, sc->sc_sens);
1761*9485SMikore.Li@Sun.COM 
1762*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, 0x5e, 1))
1763*9485SMikore.Li@Sun.COM 		goto fail;
1764*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, 0xfe, 0x10))
1765*9485SMikore.Li@Sun.COM 		goto fail;
1766*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TALLY_SEL, 0x80))
1767*9485SMikore.Li@Sun.COM 		goto fail;
1768*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0xff, 0x60))
1769*9485SMikore.Li@Sun.COM 		goto fail;
1770*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, 0x5e, 0))
1771*9485SMikore.Li@Sun.COM 		goto fail;
1772*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x85, 4))
1773*9485SMikore.Li@Sun.COM 		goto fail;
1774*9485SMikore.Li@Sun.COM 	ic->ic_curchan = &ic->ic_sup_channels[1];
1775*9485SMikore.Li@Sun.COM 	error = urtw_intr_enable(sc);
1776*9485SMikore.Li@Sun.COM 	if (error != 0)
1777*9485SMikore.Li@Sun.COM 		goto fail;
1778*9485SMikore.Li@Sun.COM 
1779*9485SMikore.Li@Sun.COM fail:
1780*9485SMikore.Li@Sun.COM 	return (error);
1781*9485SMikore.Li@Sun.COM }
1782*9485SMikore.Li@Sun.COM 
1783*9485SMikore.Li@Sun.COM static usbd_status
1784*9485SMikore.Li@Sun.COM urtw_rx_setconf(struct urtw_softc *sc)
1785*9485SMikore.Li@Sun.COM {
1786*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
1787*9485SMikore.Li@Sun.COM 	uint32_t data, a, b;
1788*9485SMikore.Li@Sun.COM 	usbd_status error;
1789*9485SMikore.Li@Sun.COM 
1790*9485SMikore.Li@Sun.COM 	if (urtw_read32_c(sc, URTW_RX, &data))
1791*9485SMikore.Li@Sun.COM 		goto fail;
1792*9485SMikore.Li@Sun.COM 	data = data &~ URTW_RX_FILTER_MASK;
1793*9485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
1794*9485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
1795*9485SMikore.Li@Sun.COM 
1796*9485SMikore.Li@Sun.COM 	if (ic->ic_opmode == IEEE80211_M_MONITOR) {
1797*9485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_ICVERR;
1798*9485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_PWR;
1799*9485SMikore.Li@Sun.COM 	}
1800*9485SMikore.Li@Sun.COM 	if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
1801*9485SMikore.Li@Sun.COM 		data = data | URTW_RX_FILTER_CRCERR;
1802*9485SMikore.Li@Sun.COM 	data = data | URTW_RX_FILTER_NICMAC;
1803*9485SMikore.Li@Sun.COM 	data = data | URTW_RX_CHECK_BSSID;
1804*9485SMikore.Li@Sun.COM 	data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
1805*9485SMikore.Li@Sun.COM 	data = data | URTW_RX_FIFO_THRESHOLD_NONE | URTW_RX_AUTORESETPHY;
1806*9485SMikore.Li@Sun.COM 	data = data &~ URTW_MAX_RX_DMA_MASK;
1807*9485SMikore.Li@Sun.COM 	a = URTW_MAX_RX_DMA_2048;
1808*9485SMikore.Li@Sun.COM 	b = 0x80000000;
1809*9485SMikore.Li@Sun.COM 	data = data | a | b;
1810*9485SMikore.Li@Sun.COM 
1811*9485SMikore.Li@Sun.COM 	error = urtw_write32_c(sc, URTW_RX, data);
1812*9485SMikore.Li@Sun.COM fail:
1813*9485SMikore.Li@Sun.COM 	return (error);
1814*9485SMikore.Li@Sun.COM }
1815*9485SMikore.Li@Sun.COM 
1816*9485SMikore.Li@Sun.COM static usbd_status
1817*9485SMikore.Li@Sun.COM urtw_rx_enable(struct urtw_softc *sc)
1818*9485SMikore.Li@Sun.COM {
1819*9485SMikore.Li@Sun.COM 	int i;
1820*9485SMikore.Li@Sun.COM 	usbd_status error;
1821*9485SMikore.Li@Sun.COM 	uint8_t data;
1822*9485SMikore.Li@Sun.COM 
1823*9485SMikore.Li@Sun.COM 	sc->rx_queued = 0;
1824*9485SMikore.Li@Sun.COM 	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) {
1825*9485SMikore.Li@Sun.COM 		if (urtw_rx_start(sc) != 0) {
1826*9485SMikore.Li@Sun.COM 			return (USB_FAILURE);
1827*9485SMikore.Li@Sun.COM 		}
1828*9485SMikore.Li@Sun.COM 	}
1829*9485SMikore.Li@Sun.COM 
1830*9485SMikore.Li@Sun.COM 	error = urtw_rx_setconf(sc);
1831*9485SMikore.Li@Sun.COM 	if (error != 0)
1832*9485SMikore.Li@Sun.COM 		goto fail;
1833*9485SMikore.Li@Sun.COM 
1834*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data))
1835*9485SMikore.Li@Sun.COM 		goto fail;
1836*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE);
1837*9485SMikore.Li@Sun.COM fail:
1838*9485SMikore.Li@Sun.COM 	return (error);
1839*9485SMikore.Li@Sun.COM }
1840*9485SMikore.Li@Sun.COM 
1841*9485SMikore.Li@Sun.COM static usbd_status
1842*9485SMikore.Li@Sun.COM urtw_tx_enable(struct urtw_softc *sc)
1843*9485SMikore.Li@Sun.COM {
1844*9485SMikore.Li@Sun.COM 	uint8_t data8;
1845*9485SMikore.Li@Sun.COM 	uint32_t data;
1846*9485SMikore.Li@Sun.COM 	usbd_status error;
1847*9485SMikore.Li@Sun.COM 
1848*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CW_CONF, &data8))
1849*9485SMikore.Li@Sun.COM 		goto fail;
1850*9485SMikore.Li@Sun.COM 	data8 &= ~(URTW_CW_CONF_PERPACKET_CW | URTW_CW_CONF_PERPACKET_RETRY);
1851*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CW_CONF, data8))
1852*9485SMikore.Li@Sun.COM 		goto fail;
1853*9485SMikore.Li@Sun.COM 
1854*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_TX_AGC_CTL, &data8))
1855*9485SMikore.Li@Sun.COM 		goto fail;
1856*9485SMikore.Li@Sun.COM 	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
1857*9485SMikore.Li@Sun.COM 	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
1858*9485SMikore.Li@Sun.COM 	data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
1859*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_AGC_CTL, data8))
1860*9485SMikore.Li@Sun.COM 		goto fail;
1861*9485SMikore.Li@Sun.COM 
1862*9485SMikore.Li@Sun.COM 	if (error = urtw_read32_c(sc, URTW_TX_CONF, &data))
1863*9485SMikore.Li@Sun.COM 		goto fail;
1864*9485SMikore.Li@Sun.COM 	data &= ~URTW_TX_LOOPBACK_MASK;
1865*9485SMikore.Li@Sun.COM 	data |= URTW_TX_LOOPBACK_NONE;
1866*9485SMikore.Li@Sun.COM 	data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
1867*9485SMikore.Li@Sun.COM 	data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
1868*9485SMikore.Li@Sun.COM 	data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
1869*9485SMikore.Li@Sun.COM 	data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
1870*9485SMikore.Li@Sun.COM 	data |= URTW_TX_MXDMA_2048 | 0x80000000 | URTW_TX_DISCW;
1871*9485SMikore.Li@Sun.COM 	data &= ~URTW_TX_SWPLCPLEN;
1872*9485SMikore.Li@Sun.COM 	data |= URTW_TX_NOICV;
1873*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_TX_CONF, data))
1874*9485SMikore.Li@Sun.COM 		goto fail;
1875*9485SMikore.Li@Sun.COM 	if (error = urtw_read8_c(sc, URTW_CMD, &data8))
1876*9485SMikore.Li@Sun.COM 		goto fail;
1877*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
1878*9485SMikore.Li@Sun.COM fail:
1879*9485SMikore.Li@Sun.COM 	return (error);
1880*9485SMikore.Li@Sun.COM }
1881*9485SMikore.Li@Sun.COM 
1882*9485SMikore.Li@Sun.COM static int
1883*9485SMikore.Li@Sun.COM urtw_init(void *arg)
1884*9485SMikore.Li@Sun.COM {
1885*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
1886*9485SMikore.Li@Sun.COM 	usbd_status error;
1887*9485SMikore.Li@Sun.COM 
1888*9485SMikore.Li@Sun.COM 	urtw_stop(sc);
1889*9485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
1890*9485SMikore.Li@Sun.COM 	error = urtw_open_pipes(sc);
1891*9485SMikore.Li@Sun.COM 	if (error != 0)
1892*9485SMikore.Li@Sun.COM 		goto fail;
1893*9485SMikore.Li@Sun.COM 	error = urtw_adapter_start(sc);
1894*9485SMikore.Li@Sun.COM 	if (error != 0)
1895*9485SMikore.Li@Sun.COM 		goto fail;
1896*9485SMikore.Li@Sun.COM 	sc->sc_tx_low_queued = 0;
1897*9485SMikore.Li@Sun.COM 	sc->sc_tx_normal_queued = 0;
1898*9485SMikore.Li@Sun.COM 	error = urtw_rx_enable(sc);
1899*9485SMikore.Li@Sun.COM 	if (error != 0)
1900*9485SMikore.Li@Sun.COM 		goto fail;
1901*9485SMikore.Li@Sun.COM 	error = urtw_tx_enable(sc);
1902*9485SMikore.Li@Sun.COM 	if (error != 0)
1903*9485SMikore.Li@Sun.COM 		goto fail;
1904*9485SMikore.Li@Sun.COM 
1905*9485SMikore.Li@Sun.COM 	if (error == 0) {
1906*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev,
1907*9485SMikore.Li@Sun.COM 		    CE_CONT, "urtw_init: succesfully done\n"));
1908*9485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_RUNNING;
1909*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
1910*9485SMikore.Li@Sun.COM 		return (error);
1911*9485SMikore.Li@Sun.COM 	}
1912*9485SMikore.Li@Sun.COM 
1913*9485SMikore.Li@Sun.COM fail:
1914*9485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
1915*9485SMikore.Li@Sun.COM 	urtw_stop(sc);
1916*9485SMikore.Li@Sun.COM 	return (error);
1917*9485SMikore.Li@Sun.COM }
1918*9485SMikore.Li@Sun.COM 
1919*9485SMikore.Li@Sun.COM 
1920*9485SMikore.Li@Sun.COM static usbd_status
1921*9485SMikore.Li@Sun.COM urtw_8225_usb_init(struct urtw_softc *sc)
1922*9485SMikore.Li@Sun.COM {
1923*9485SMikore.Li@Sun.COM 	uint8_t data;
1924*9485SMikore.Li@Sun.COM 	usbd_status error;
1925*9485SMikore.Li@Sun.COM 
1926*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 0))
1927*9485SMikore.Li@Sun.COM 		goto fail;
1928*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GPIO, 0))
1929*9485SMikore.Li@Sun.COM 		goto fail;
1930*9485SMikore.Li@Sun.COM 	if (error = urtw_read8e(sc, 0x53, &data))
1931*9485SMikore.Li@Sun.COM 		goto fail;
1932*9485SMikore.Li@Sun.COM 	if (error = urtw_write8e(sc, 0x53, data | (1 << 7)))
1933*9485SMikore.Li@Sun.COM 		goto fail;
1934*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_RF_PINS_SELECT + 1, 4))
1935*9485SMikore.Li@Sun.COM 		goto fail;
1936*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GPIO, 0x20))
1937*9485SMikore.Li@Sun.COM 		goto fail;
1938*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_GP_ENABLE, 0))
1939*9485SMikore.Li@Sun.COM 		goto fail;
1940*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_OUTPUT, 0x80))
1941*9485SMikore.Li@Sun.COM 		goto fail;
1942*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_RF_PINS_SELECT, 0x80))
1943*9485SMikore.Li@Sun.COM 		goto fail;
1944*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x80);
1945*9485SMikore.Li@Sun.COM 
1946*9485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
1947*9485SMikore.Li@Sun.COM fail:
1948*9485SMikore.Li@Sun.COM 	return (error);
1949*9485SMikore.Li@Sun.COM }
1950*9485SMikore.Li@Sun.COM 
1951*9485SMikore.Li@Sun.COM static usbd_status
1952*9485SMikore.Li@Sun.COM urtw_8185_rf_pins_enable(struct urtw_softc *sc)
1953*9485SMikore.Li@Sun.COM {
1954*9485SMikore.Li@Sun.COM 	usbd_status error = 0;
1955*9485SMikore.Li@Sun.COM 
1956*9485SMikore.Li@Sun.COM 	error = urtw_write16_c(sc, URTW_RF_PINS_ENABLE, 0x1ff7);
1957*9485SMikore.Li@Sun.COM 	return (error);
1958*9485SMikore.Li@Sun.COM }
1959*9485SMikore.Li@Sun.COM 
1960*9485SMikore.Li@Sun.COM static usbd_status
1961*9485SMikore.Li@Sun.COM urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
1962*9485SMikore.Li@Sun.COM {
1963*9485SMikore.Li@Sun.COM 	uint32_t phyw;
1964*9485SMikore.Li@Sun.COM 	usbd_status error;
1965*9485SMikore.Li@Sun.COM 
1966*9485SMikore.Li@Sun.COM 	phyw = ((data << 8) | (addr | 0x80));
1967*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7f, ((phyw & 0xff000000) >> 24)))
1968*9485SMikore.Li@Sun.COM 		goto fail;
1969*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7e, ((phyw & 0x00ff0000) >> 16)))
1970*9485SMikore.Li@Sun.COM 		goto fail;
1971*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x7d, ((phyw & 0x0000ff00) >> 8)))
1972*9485SMikore.Li@Sun.COM 		goto fail;
1973*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, 0x7c, ((phyw & 0x000000ff)));
1974*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
1975*9485SMikore.Li@Sun.COM fail:
1976*9485SMikore.Li@Sun.COM 	return (error);
1977*9485SMikore.Li@Sun.COM }
1978*9485SMikore.Li@Sun.COM 
1979*9485SMikore.Li@Sun.COM static usbd_status
1980*9485SMikore.Li@Sun.COM urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
1981*9485SMikore.Li@Sun.COM {
1982*9485SMikore.Li@Sun.COM 	data = data & 0xff;
1983*9485SMikore.Li@Sun.COM 	return (urtw_8187_write_phy(sc, addr, data));
1984*9485SMikore.Li@Sun.COM }
1985*9485SMikore.Li@Sun.COM 
1986*9485SMikore.Li@Sun.COM static usbd_status
1987*9485SMikore.Li@Sun.COM urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
1988*9485SMikore.Li@Sun.COM {
1989*9485SMikore.Li@Sun.COM 	data = data & 0xff;
1990*9485SMikore.Li@Sun.COM 	return (urtw_8187_write_phy(sc, addr, (data | 0x10000)));
1991*9485SMikore.Li@Sun.COM }
1992*9485SMikore.Li@Sun.COM 
1993*9485SMikore.Li@Sun.COM static usbd_status
1994*9485SMikore.Li@Sun.COM urtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
1995*9485SMikore.Li@Sun.COM {
1996*9485SMikore.Li@Sun.COM 	usbd_status error;
1997*9485SMikore.Li@Sun.COM 
1998*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d,
1999*9485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4]))
2000*9485SMikore.Li@Sun.COM 		goto fail;
2001*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b,
2002*9485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 2]))
2003*9485SMikore.Li@Sun.COM 		goto fail;
2004*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d,
2005*9485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 3]))
2006*9485SMikore.Li@Sun.COM 		goto fail;
2007*9485SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_ofdm_c(sc, 0x23,
2008*9485SMikore.Li@Sun.COM 	    urtw_8225_gain[gain * 4 + 1]);
2009*9485SMikore.Li@Sun.COM fail:
2010*9485SMikore.Li@Sun.COM 	return (error);
2011*9485SMikore.Li@Sun.COM }
2012*9485SMikore.Li@Sun.COM 
2013*9485SMikore.Li@Sun.COM static usbd_status
2014*9485SMikore.Li@Sun.COM urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
2015*9485SMikore.Li@Sun.COM {
2016*9485SMikore.Li@Sun.COM 	int i, idx, set;
2017*9485SMikore.Li@Sun.COM 	uint8_t *cck_pwltable;
2018*9485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
2019*9485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
2020*9485SMikore.Li@Sun.COM 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
2021*9485SMikore.Li@Sun.COM 	usbd_status error;
2022*9485SMikore.Li@Sun.COM 
2023*9485SMikore.Li@Sun.COM 	cck_pwrlvl_max = 11;
2024*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl_max = 25;	/* 12 -> 25  */
2025*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl_min = 10;
2026*9485SMikore.Li@Sun.COM 
2027*9485SMikore.Li@Sun.COM 	/* CCK power setting */
2028*9485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
2029*9485SMikore.Li@Sun.COM 	    cck_pwrlvl_max : cck_pwrlvl;
2030*9485SMikore.Li@Sun.COM 	idx = cck_pwrlvl % 6;
2031*9485SMikore.Li@Sun.COM 	set = cck_pwrlvl / 6;
2032*9485SMikore.Li@Sun.COM 	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
2033*9485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_cck;
2034*9485SMikore.Li@Sun.COM 
2035*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2036*9485SMikore.Li@Sun.COM 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1))
2037*9485SMikore.Li@Sun.COM 		goto fail;
2038*9485SMikore.Li@Sun.COM 	for (i = 0; i < 8; i++) {
2039*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
2040*9485SMikore.Li@Sun.COM 		    cck_pwltable[idx * 8 + i]))
2041*9485SMikore.Li@Sun.COM 			goto fail;
2042*9485SMikore.Li@Sun.COM 	}
2043*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2044*9485SMikore.Li@Sun.COM 	/* OFDM power setting */
2045*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
2046*9485SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
2047*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
2048*9485SMikore.Li@Sun.COM 	idx = ofdm_pwrlvl % 6;
2049*9485SMikore.Li@Sun.COM 	set = ofdm_pwrlvl / 6;
2050*9485SMikore.Li@Sun.COM 
2051*9485SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
2052*9485SMikore.Li@Sun.COM 	if (error)
2053*9485SMikore.Li@Sun.COM 		goto fail;
2054*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
2055*9485SMikore.Li@Sun.COM 		goto fail;
2056*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0))
2057*9485SMikore.Li@Sun.COM 		goto fail;
2058*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0))
2059*9485SMikore.Li@Sun.COM 		goto fail;
2060*9485SMikore.Li@Sun.COM 
2061*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2062*9485SMikore.Li@Sun.COM 	    urtw_8225_tx_gain_cck_ofdm[set] >> 1))
2063*9485SMikore.Li@Sun.COM 		goto fail;
2064*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x5,
2065*9485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_ofdm[idx]))
2066*9485SMikore.Li@Sun.COM 		goto fail;
2067*9485SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_ofdm_c(sc, 0x7,
2068*9485SMikore.Li@Sun.COM 	    urtw_8225_txpwr_ofdm[idx]);
2069*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2070*9485SMikore.Li@Sun.COM fail:
2071*9485SMikore.Li@Sun.COM 	return (error);
2072*9485SMikore.Li@Sun.COM }
2073*9485SMikore.Li@Sun.COM 
2074*9485SMikore.Li@Sun.COM static usbd_status
2075*9485SMikore.Li@Sun.COM urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
2076*9485SMikore.Li@Sun.COM {
2077*9485SMikore.Li@Sun.COM 	usbd_status error;
2078*9485SMikore.Li@Sun.COM 
2079*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_TX_ANTENNA, ant);
2080*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2081*9485SMikore.Li@Sun.COM 	return (error);
2082*9485SMikore.Li@Sun.COM }
2083*9485SMikore.Li@Sun.COM 
2084*9485SMikore.Li@Sun.COM static usbd_status
2085*9485SMikore.Li@Sun.COM urtw_8225_rf_init(struct urtw_softc *sc)
2086*9485SMikore.Li@Sun.COM {
2087*9485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a) / sizeof ((a)[0]))
2088*9485SMikore.Li@Sun.COM 	int i;
2089*9485SMikore.Li@Sun.COM 	uint16_t data;
2090*9485SMikore.Li@Sun.COM 	usbd_status error;
2091*9485SMikore.Li@Sun.COM 
2092*9485SMikore.Li@Sun.COM 	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
2093*9485SMikore.Li@Sun.COM 	if (error)
2094*9485SMikore.Li@Sun.COM 		goto fail;
2095*9485SMikore.Li@Sun.COM 
2096*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_usb_init(sc))
2097*9485SMikore.Li@Sun.COM 		goto fail;
2098*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008))
2099*9485SMikore.Li@Sun.COM 		goto fail;
2100*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data))
2101*9485SMikore.Li@Sun.COM 		goto fail;
2102*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff))
2103*9485SMikore.Li@Sun.COM 		goto fail;
2104*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044))
2105*9485SMikore.Li@Sun.COM 		goto fail;
2106*9485SMikore.Li@Sun.COM 
2107*9485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
2108*9485SMikore.Li@Sun.COM 		goto fail;
2109*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44))
2110*9485SMikore.Li@Sun.COM 		goto fail;
2111*9485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
2112*9485SMikore.Li@Sun.COM 		goto fail;
2113*9485SMikore.Li@Sun.COM 	if (error = urtw_8185_rf_pins_enable(sc))
2114*9485SMikore.Li@Sun.COM 		goto fail;
2115*9485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
2116*9485SMikore.Li@Sun.COM 
2117*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part1); i++) {
2118*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, urtw_8225_rf_part1[i].reg,
2119*9485SMikore.Li@Sun.COM 		    urtw_8225_rf_part1[i].val))
2120*9485SMikore.Li@Sun.COM 			goto fail;
2121*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2122*9485SMikore.Li@Sun.COM 	}
2123*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
2124*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
2125*9485SMikore.Li@Sun.COM 		goto fail;
2126*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
2127*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
2128*9485SMikore.Li@Sun.COM 		goto fail;
2129*9485SMikore.Li@Sun.COM 	urtw_delay_ms(50);
2130*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x127))
2131*9485SMikore.Li@Sun.COM 		goto fail;
2132*9485SMikore.Li@Sun.COM 
2133*9485SMikore.Li@Sun.COM 	for (i = 0; i < 95; i++) {
2134*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
2135*9485SMikore.Li@Sun.COM 			goto fail;
2136*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225_rxgain[i]))
2137*9485SMikore.Li@Sun.COM 			goto fail;
2138*9485SMikore.Li@Sun.COM 	}
2139*9485SMikore.Li@Sun.COM 
2140*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x27))
2141*9485SMikore.Li@Sun.COM 		goto fail;
2142*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x22f))
2143*9485SMikore.Li@Sun.COM 		goto fail;
2144*9485SMikore.Li@Sun.COM 
2145*9485SMikore.Li@Sun.COM 	for (i = 0; i < 128; i++) {
2146*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
2147*9485SMikore.Li@Sun.COM 		    urtw_8225_agc[i]))
2148*9485SMikore.Li@Sun.COM 			goto fail;
2149*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2150*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
2151*9485SMikore.Li@Sun.COM 		    (uint8_t)i + 0x80))
2152*9485SMikore.Li@Sun.COM 			goto fail;
2153*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2154*9485SMikore.Li@Sun.COM 	}
2155*9485SMikore.Li@Sun.COM 
2156*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part2); i++) {
2157*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc,
2158*9485SMikore.Li@Sun.COM 		    urtw_8225_rf_part2[i].reg,
2159*9485SMikore.Li@Sun.COM 		    urtw_8225_rf_part2[i].val))
2160*9485SMikore.Li@Sun.COM 			goto fail;
2161*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2162*9485SMikore.Li@Sun.COM 	}
2163*9485SMikore.Li@Sun.COM 	error = urtw_8225_setgain(sc, 4);
2164*9485SMikore.Li@Sun.COM 	if (error)
2165*9485SMikore.Li@Sun.COM 		goto fail;
2166*9485SMikore.Li@Sun.COM 
2167*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225_rf_part3); i++) {
2168*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc,
2169*9485SMikore.Li@Sun.COM 		    urtw_8225_rf_part3[i].reg,
2170*9485SMikore.Li@Sun.COM 		    urtw_8225_rf_part3[i].val))
2171*9485SMikore.Li@Sun.COM 			goto fail;
2172*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2173*9485SMikore.Li@Sun.COM 	}
2174*9485SMikore.Li@Sun.COM 
2175*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x5b, 0x0d))
2176*9485SMikore.Li@Sun.COM 		goto fail;
2177*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_set_txpwrlvl(sc, 1))
2178*9485SMikore.Li@Sun.COM 		goto fail;
2179*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
2180*9485SMikore.Li@Sun.COM 		goto fail;
2181*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2182*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
2183*9485SMikore.Li@Sun.COM 		goto fail;
2184*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2185*9485SMikore.Li@Sun.COM 
2186*9485SMikore.Li@Sun.COM 	/* TX ant A, 0x0 for B */
2187*9485SMikore.Li@Sun.COM 	if (error = urtw_8185_tx_antenna(sc, 0x3))
2188*9485SMikore.Li@Sun.COM 		goto fail;
2189*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002))
2190*9485SMikore.Li@Sun.COM 		goto fail;
2191*9485SMikore.Li@Sun.COM 
2192*9485SMikore.Li@Sun.COM 	error = urtw_8225_rf_set_chan(sc, 1);
2193*9485SMikore.Li@Sun.COM fail:
2194*9485SMikore.Li@Sun.COM 	return (error);
2195*9485SMikore.Li@Sun.COM #undef N
2196*9485SMikore.Li@Sun.COM }
2197*9485SMikore.Li@Sun.COM 
2198*9485SMikore.Li@Sun.COM static usbd_status
2199*9485SMikore.Li@Sun.COM urtw_8225_rf_set_chan(struct urtw_softc *sc, int chan)
2200*9485SMikore.Li@Sun.COM {
2201*9485SMikore.Li@Sun.COM #define	IEEE80211_CHAN_G	\
2202*9485SMikore.Li@Sun.COM 	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
2203*9485SMikore.Li@Sun.COM #define	IEEE80211_IS_CHAN_G(_c)		\
2204*9485SMikore.Li@Sun.COM 	(((_c)->ich_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
2205*9485SMikore.Li@Sun.COM 
2206*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2207*9485SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
2208*9485SMikore.Li@Sun.COM 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
2209*9485SMikore.Li@Sun.COM 	usbd_status error;
2210*9485SMikore.Li@Sun.COM 
2211*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_set_txpwrlvl(sc, chan))
2212*9485SMikore.Li@Sun.COM 		goto fail;
2213*9485SMikore.Li@Sun.COM 	if (urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
2214*9485SMikore.Li@Sun.COM 		goto fail;
2215*9485SMikore.Li@Sun.COM 	urtw_delay_ms(10);
2216*9485SMikore.Li@Sun.COM 
2217*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22))
2218*9485SMikore.Li@Sun.COM 		goto fail;
2219*9485SMikore.Li@Sun.COM 
2220*9485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_ASSOC &&
2221*9485SMikore.Li@Sun.COM 	    ic->ic_flags & IEEE80211_F_SHSLOT)
2222*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9))
2223*9485SMikore.Li@Sun.COM 			goto fail;
2224*9485SMikore.Li@Sun.COM 	else
2225*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14))
2226*9485SMikore.Li@Sun.COM 			goto fail;
2227*9485SMikore.Li@Sun.COM 	if (gset) {
2228*9485SMikore.Li@Sun.COM 		/* for G */
2229*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14))
2230*9485SMikore.Li@Sun.COM 			goto fail;
2231*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14))
2232*9485SMikore.Li@Sun.COM 			goto fail;
2233*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_CW_VAL, 0x73);
2234*9485SMikore.Li@Sun.COM 	} else {
2235*9485SMikore.Li@Sun.COM 		/* for B */
2236*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24))
2237*9485SMikore.Li@Sun.COM 			goto fail;
2238*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24))
2239*9485SMikore.Li@Sun.COM 			goto fail;
2240*9485SMikore.Li@Sun.COM 		error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5);
2241*9485SMikore.Li@Sun.COM 	}
2242*9485SMikore.Li@Sun.COM 
2243*9485SMikore.Li@Sun.COM fail:
2244*9485SMikore.Li@Sun.COM 	return (error);
2245*9485SMikore.Li@Sun.COM }
2246*9485SMikore.Li@Sun.COM 
2247*9485SMikore.Li@Sun.COM static usbd_status
2248*9485SMikore.Li@Sun.COM urtw_8225_rf_set_sens(struct urtw_softc *sc, int sens)
2249*9485SMikore.Li@Sun.COM {
2250*9485SMikore.Li@Sun.COM 	usbd_status error;
2251*9485SMikore.Li@Sun.COM 
2252*9485SMikore.Li@Sun.COM 	if (sens < 0 || sens > 6)
2253*9485SMikore.Li@Sun.COM 		return (-1);
2254*9485SMikore.Li@Sun.COM 
2255*9485SMikore.Li@Sun.COM 	if (sens > 4)
2256*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x0c, 0x850))
2257*9485SMikore.Li@Sun.COM 			goto fail;
2258*9485SMikore.Li@Sun.COM 	else
2259*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x0c, 0x50))
2260*9485SMikore.Li@Sun.COM 			goto fail;
2261*9485SMikore.Li@Sun.COM 
2262*9485SMikore.Li@Sun.COM 	sens = 6 - sens;
2263*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_setgain(sc, sens))
2264*9485SMikore.Li@Sun.COM 		goto fail;
2265*9485SMikore.Li@Sun.COM 	error = urtw_8187_write_phy_cck_c(sc, 0x41, urtw_8225_threshold[sens]);
2266*9485SMikore.Li@Sun.COM fail:
2267*9485SMikore.Li@Sun.COM 	return (error);
2268*9485SMikore.Li@Sun.COM }
2269*9485SMikore.Li@Sun.COM 
2270*9485SMikore.Li@Sun.COM static void
2271*9485SMikore.Li@Sun.COM urtw_stop(struct urtw_softc *sc)
2272*9485SMikore.Li@Sun.COM {
2273*9485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
2274*9485SMikore.Li@Sun.COM 	sc->sc_flags &= ~URTW_FLAG_RUNNING;
2275*9485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
2276*9485SMikore.Li@Sun.COM 	urtw_close_pipes(sc);
2277*9485SMikore.Li@Sun.COM }
2278*9485SMikore.Li@Sun.COM 
2279*9485SMikore.Li@Sun.COM static int
2280*9485SMikore.Li@Sun.COM urtw_isbmode(uint16_t rate)
2281*9485SMikore.Li@Sun.COM {
2282*9485SMikore.Li@Sun.COM 
2283*9485SMikore.Li@Sun.COM 	rate = urtw_rtl2rate(rate);
2284*9485SMikore.Li@Sun.COM 
2285*9485SMikore.Li@Sun.COM 	return ((rate <= 22 && rate != 12 && rate != 18)?(1) : (0));
2286*9485SMikore.Li@Sun.COM }
2287*9485SMikore.Li@Sun.COM 
2288*9485SMikore.Li@Sun.COM /* ARGSUSED */
2289*9485SMikore.Li@Sun.COM static void
2290*9485SMikore.Li@Sun.COM urtw_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2291*9485SMikore.Li@Sun.COM {
2292*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
2293*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2294*9485SMikore.Li@Sun.COM 	int actlen, len,  flen,  rssi;
2295*9485SMikore.Li@Sun.COM 	uint8_t *desc, rate;
2296*9485SMikore.Li@Sun.COM 	struct ieee80211_frame *wh;
2297*9485SMikore.Li@Sun.COM 	struct ieee80211_node *ni = 0;
2298*9485SMikore.Li@Sun.COM 	mblk_t *mp = 0;
2299*9485SMikore.Li@Sun.COM 	uint8_t *rxbuf;
2300*9485SMikore.Li@Sun.COM 
2301*9485SMikore.Li@Sun.COM 	mp = req->bulk_data;
2302*9485SMikore.Li@Sun.COM 	req->bulk_data = NULL;
2303*9485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK ||
2304*9485SMikore.Li@Sun.COM 	    mp == NULL) {
2305*9485SMikore.Li@Sun.COM 		sc->sc_rx_err++;
2306*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2307*9485SMikore.Li@Sun.COM 		    "urtw_rxeof failed! %d\n",
2308*9485SMikore.Li@Sun.COM 		    req->bulk_completion_reason));
2309*9485SMikore.Li@Sun.COM 		req->bulk_data = mp;
2310*9485SMikore.Li@Sun.COM 		goto fail;
2311*9485SMikore.Li@Sun.COM 	}
2312*9485SMikore.Li@Sun.COM 
2313*9485SMikore.Li@Sun.COM 	actlen = MBLKL(mp);
2314*9485SMikore.Li@Sun.COM 	rxbuf = (uint8_t *)mp->b_rptr;
2315*9485SMikore.Li@Sun.COM 
2316*9485SMikore.Li@Sun.COM 	/* 4 dword and 4 byte CRC  */
2317*9485SMikore.Li@Sun.COM 	len = actlen - (4 * 4);
2318*9485SMikore.Li@Sun.COM 	desc = rxbuf + len;
2319*9485SMikore.Li@Sun.COM 	flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
2320*9485SMikore.Li@Sun.COM 	if (flen > actlen) {
2321*9485SMikore.Li@Sun.COM 		cmn_err(CE_CONT, "urtw_rxeof: impossible: flen %d, actlen %d\n",
2322*9485SMikore.Li@Sun.COM 		    flen, actlen);
2323*9485SMikore.Li@Sun.COM 		sc->sc_rx_err++;
2324*9485SMikore.Li@Sun.COM 		req->bulk_data = mp;
2325*9485SMikore.Li@Sun.COM 		goto fail;
2326*9485SMikore.Li@Sun.COM 	}
2327*9485SMikore.Li@Sun.COM 
2328*9485SMikore.Li@Sun.COM 	rate = (desc[2] & 0xf0) >> 4;
2329*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2330*9485SMikore.Li@Sun.COM 	    "urtw_rxeof: rate is %u\n", rate));
2331*9485SMikore.Li@Sun.COM 	/* XXX correct?  */
2332*9485SMikore.Li@Sun.COM 	rssi = (desc[6] & 0xfe) >> 1;
2333*9485SMikore.Li@Sun.COM 	if (!urtw_isbmode(rate)) {
2334*9485SMikore.Li@Sun.COM 		rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi);
2335*9485SMikore.Li@Sun.COM 		rssi = ((90 - rssi) * 100) / 65;
2336*9485SMikore.Li@Sun.COM 	} else {
2337*9485SMikore.Li@Sun.COM 		rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi);
2338*9485SMikore.Li@Sun.COM 		rssi = ((95 - rssi) * 100) / 65;
2339*9485SMikore.Li@Sun.COM 	}
2340*9485SMikore.Li@Sun.COM 
2341*9485SMikore.Li@Sun.COM 	mp->b_wptr = mp->b_rptr + flen - 4;
2342*9485SMikore.Li@Sun.COM 
2343*9485SMikore.Li@Sun.COM 	wh = (struct ieee80211_frame *)mp->b_rptr;
2344*9485SMikore.Li@Sun.COM 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)
2345*9485SMikore.Li@Sun.COM 	    == IEEE80211_FC0_TYPE_DATA) {
2346*9485SMikore.Li@Sun.COM 		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
2347*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RX_PROC, (sc->sc_dev, CE_CONT,
2348*9485SMikore.Li@Sun.COM 		    "urtw_rxeof: update sc_currate to %u\n",
2349*9485SMikore.Li@Sun.COM 		    sc->sc_currate));
2350*9485SMikore.Li@Sun.COM 	}
2351*9485SMikore.Li@Sun.COM 	ni = ieee80211_find_rxnode(ic, wh);
2352*9485SMikore.Li@Sun.COM 
2353*9485SMikore.Li@Sun.COM 	/* send the frame to the 802.11 layer */
2354*9485SMikore.Li@Sun.COM 	(void) ieee80211_input(ic, mp, ni, rssi, 0);
2355*9485SMikore.Li@Sun.COM 
2356*9485SMikore.Li@Sun.COM 	/* node is no longer needed */
2357*9485SMikore.Li@Sun.COM 	ieee80211_free_node(ni);
2358*9485SMikore.Li@Sun.COM fail:
2359*9485SMikore.Li@Sun.COM 	mutex_enter(&sc->rx_lock);
2360*9485SMikore.Li@Sun.COM 	sc->rx_queued--;
2361*9485SMikore.Li@Sun.COM 	mutex_exit(&sc->rx_lock);
2362*9485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
2363*9485SMikore.Li@Sun.COM 	if (URTW_IS_RUNNING(sc) && !URTW_IS_SUSPENDING(sc))
2364*9485SMikore.Li@Sun.COM 		(void) urtw_rx_start(sc);
2365*9485SMikore.Li@Sun.COM }
2366*9485SMikore.Li@Sun.COM 
2367*9485SMikore.Li@Sun.COM static usbd_status
2368*9485SMikore.Li@Sun.COM urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
2369*9485SMikore.Li@Sun.COM {
2370*9485SMikore.Li@Sun.COM 	uint8_t *gainp;
2371*9485SMikore.Li@Sun.COM 	usbd_status error;
2372*9485SMikore.Li@Sun.COM 
2373*9485SMikore.Li@Sun.COM 	/* XXX for A?  */
2374*9485SMikore.Li@Sun.COM 	gainp = urtw_8225v2_gain_bg;
2375*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x0d, gainp[gain * 3]))
2376*9485SMikore.Li@Sun.COM 		goto fail;
2377*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2378*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1b, gainp[gain * 3 + 1]))
2379*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2380*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x1d, gainp[gain * 3 + 2]))
2381*9485SMikore.Li@Sun.COM 		goto fail;
2382*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2383*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x21, 0x17))
2384*9485SMikore.Li@Sun.COM 		goto fail;
2385*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2386*9485SMikore.Li@Sun.COM fail:
2387*9485SMikore.Li@Sun.COM 	return (error);
2388*9485SMikore.Li@Sun.COM }
2389*9485SMikore.Li@Sun.COM 
2390*9485SMikore.Li@Sun.COM static usbd_status
2391*9485SMikore.Li@Sun.COM urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
2392*9485SMikore.Li@Sun.COM {
2393*9485SMikore.Li@Sun.COM 	int i;
2394*9485SMikore.Li@Sun.COM 	uint8_t *cck_pwrtable;
2395*9485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
2396*9485SMikore.Li@Sun.COM 	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
2397*9485SMikore.Li@Sun.COM 	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
2398*9485SMikore.Li@Sun.COM 	usbd_status error;
2399*9485SMikore.Li@Sun.COM 
2400*9485SMikore.Li@Sun.COM 	/* CCK power setting */
2401*9485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
2402*9485SMikore.Li@Sun.COM 	    cck_pwrlvl_max : cck_pwrlvl;
2403*9485SMikore.Li@Sun.COM 	cck_pwrlvl += sc->sc_txpwr_cck_base;
2404*9485SMikore.Li@Sun.COM 	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
2405*9485SMikore.Li@Sun.COM 	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
2406*9485SMikore.Li@Sun.COM 	    urtw_8225v2_txpwr_cck;
2407*9485SMikore.Li@Sun.COM 
2408*9485SMikore.Li@Sun.COM 	for (i = 0; i < 8; i++) {
2409*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc, 0x44 + i,
2410*9485SMikore.Li@Sun.COM 		    cck_pwrtable[i]))
2411*9485SMikore.Li@Sun.COM 			goto fail;
2412*9485SMikore.Li@Sun.COM 	}
2413*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_TX_GAIN_CCK,
2414*9485SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]))
2415*9485SMikore.Li@Sun.COM 		goto fail;
2416*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2417*9485SMikore.Li@Sun.COM 
2418*9485SMikore.Li@Sun.COM 	/* OFDM power setting */
2419*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
2420*9485SMikore.Li@Sun.COM 	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
2421*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
2422*9485SMikore.Li@Sun.COM 	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
2423*9485SMikore.Li@Sun.COM 
2424*9485SMikore.Li@Sun.COM 	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
2425*9485SMikore.Li@Sun.COM 	if (error)
2426*9485SMikore.Li@Sun.COM 		goto fail;
2427*9485SMikore.Li@Sun.COM 
2428*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 2, 0x42))
2429*9485SMikore.Li@Sun.COM 		goto fail;
2430*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 5, 0x0))
2431*9485SMikore.Li@Sun.COM 		goto fail;
2432*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 6, 0x40))
2433*9485SMikore.Li@Sun.COM 		goto fail;
2434*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 7, 0x0))
2435*9485SMikore.Li@Sun.COM 		goto fail;
2436*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 8, 0x40))
2437*9485SMikore.Li@Sun.COM 		goto fail;
2438*9485SMikore.Li@Sun.COM 
2439*9485SMikore.Li@Sun.COM 	error = urtw_write8_c(sc, URTW_TX_GAIN_OFDM,
2440*9485SMikore.Li@Sun.COM 	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]);
2441*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2442*9485SMikore.Li@Sun.COM fail:
2443*9485SMikore.Li@Sun.COM 	return (error);
2444*9485SMikore.Li@Sun.COM }
2445*9485SMikore.Li@Sun.COM 
2446*9485SMikore.Li@Sun.COM static usbd_status
2447*9485SMikore.Li@Sun.COM urtw_8225v2_rf_init(struct urtw_softc *sc)
2448*9485SMikore.Li@Sun.COM {
2449*9485SMikore.Li@Sun.COM #define	N(a)	(sizeof (a)/ sizeof ((a)[0]))
2450*9485SMikore.Li@Sun.COM 	int i;
2451*9485SMikore.Li@Sun.COM 	uint16_t data;
2452*9485SMikore.Li@Sun.COM 	uint32_t data32;
2453*9485SMikore.Li@Sun.COM 	usbd_status error;
2454*9485SMikore.Li@Sun.COM 
2455*9485SMikore.Li@Sun.COM 	if (error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON))
2456*9485SMikore.Li@Sun.COM 		goto fail;
2457*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_usb_init(sc))
2458*9485SMikore.Li@Sun.COM 		goto fail;
2459*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_TIMING, 0x000a8008))
2460*9485SMikore.Li@Sun.COM 		goto fail;
2461*9485SMikore.Li@Sun.COM 	if (error = urtw_read16_c(sc, URTW_BRSR, &data))
2462*9485SMikore.Li@Sun.COM 		goto fail;
2463*9485SMikore.Li@Sun.COM 	if (error = urtw_write16_c(sc, URTW_BRSR, 0xffff))
2464*9485SMikore.Li@Sun.COM 		goto fail;
2465*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_RF_PARA, 0x100044))
2466*9485SMikore.Li@Sun.COM 		goto fail;
2467*9485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG))
2468*9485SMikore.Li@Sun.COM 		goto fail;
2469*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_CONFIG3, 0x44))
2470*9485SMikore.Li@Sun.COM 		goto fail;
2471*9485SMikore.Li@Sun.COM 	if (error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL))
2472*9485SMikore.Li@Sun.COM 		goto fail;
2473*9485SMikore.Li@Sun.COM 	if (error = urtw_8185_rf_pins_enable(sc))
2474*9485SMikore.Li@Sun.COM 		goto fail;
2475*9485SMikore.Li@Sun.COM 
2476*9485SMikore.Li@Sun.COM 	urtw_delay_ms(500);
2477*9485SMikore.Li@Sun.COM 
2478*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
2479*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, urtw_8225v2_rf_part1[i].reg,
2480*9485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part1[i].val))
2481*9485SMikore.Li@Sun.COM 			goto fail;
2482*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2483*9485SMikore.Li@Sun.COM 	}
2484*9485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
2485*9485SMikore.Li@Sun.COM 
2486*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x1b7))
2487*9485SMikore.Li@Sun.COM 		goto fail;
2488*9485SMikore.Li@Sun.COM 
2489*9485SMikore.Li@Sun.COM 	for (i = 0; i < 95; i++) {
2490*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x1, (uint8_t)(i + 1)))
2491*9485SMikore.Li@Sun.COM 			goto fail;
2492*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2493*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x2, urtw_8225v2_rxgain[i]))
2494*9485SMikore.Li@Sun.COM 			goto fail;
2495*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2496*9485SMikore.Li@Sun.COM 	}
2497*9485SMikore.Li@Sun.COM 
2498*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x3, 0x2))
2499*9485SMikore.Li@Sun.COM 		goto fail;
2500*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2501*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x5, 0x4))
2502*9485SMikore.Li@Sun.COM 		goto fail;
2503*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2504*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0xb7))
2505*9485SMikore.Li@Sun.COM 		goto fail;
2506*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2507*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0xc4d))
2508*9485SMikore.Li@Sun.COM 		goto fail;
2509*9485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
2510*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x2, 0x44d))
2511*9485SMikore.Li@Sun.COM 		goto fail;
2512*9485SMikore.Li@Sun.COM 	urtw_delay_ms(100);
2513*9485SMikore.Li@Sun.COM 
2514*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_read(sc, 0x6, &data32))
2515*9485SMikore.Li@Sun.COM 		goto fail;
2516*9485SMikore.Li@Sun.COM 	if (data32 != 0xe6) {
2517*9485SMikore.Li@Sun.COM 		error = (-1);
2518*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "expect 0xe6!! (0x%x)\n", data32);
2519*9485SMikore.Li@Sun.COM 		goto fail;
2520*9485SMikore.Li@Sun.COM 	}
2521*9485SMikore.Li@Sun.COM 	if (!(data32 & 0x80)) {
2522*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x02, 0x0c4d))
2523*9485SMikore.Li@Sun.COM 			goto fail;
2524*9485SMikore.Li@Sun.COM 		urtw_delay_ms(200);
2525*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_write_c(sc, 0x02, 0x044d))
2526*9485SMikore.Li@Sun.COM 			goto fail;
2527*9485SMikore.Li@Sun.COM 		urtw_delay_ms(100);
2528*9485SMikore.Li@Sun.COM 		if (error = urtw_8225_read(sc, 0x6, &data32))
2529*9485SMikore.Li@Sun.COM 			goto fail;
2530*9485SMikore.Li@Sun.COM 		if (!(data32 & 0x80))
2531*9485SMikore.Li@Sun.COM 			cmn_err(CE_CONT, "RF calibration failed\n");
2532*9485SMikore.Li@Sun.COM 	}
2533*9485SMikore.Li@Sun.COM 	urtw_delay_ms(200);
2534*9485SMikore.Li@Sun.COM 
2535*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x0, 0x2bf))
2536*9485SMikore.Li@Sun.COM 		goto fail;
2537*9485SMikore.Li@Sun.COM 	for (i = 0; i < 128; i++) {
2538*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xb,
2539*9485SMikore.Li@Sun.COM 		    urtw_8225_agc[i]))
2540*9485SMikore.Li@Sun.COM 			goto fail;
2541*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2542*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc, 0xa,
2543*9485SMikore.Li@Sun.COM 		    (uint8_t)i + 0x80))
2544*9485SMikore.Li@Sun.COM 			goto fail;
2545*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2546*9485SMikore.Li@Sun.COM 	}
2547*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2548*9485SMikore.Li@Sun.COM 
2549*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
2550*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_ofdm_c(sc,
2551*9485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part2[i].reg,
2552*9485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part2[i].val))
2553*9485SMikore.Li@Sun.COM 			goto fail;
2554*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2555*9485SMikore.Li@Sun.COM 	}
2556*9485SMikore.Li@Sun.COM 	error = urtw_8225v2_setgain(sc, 4);
2557*9485SMikore.Li@Sun.COM 	if (error)
2558*9485SMikore.Li@Sun.COM 		goto fail;
2559*9485SMikore.Li@Sun.COM 
2560*9485SMikore.Li@Sun.COM 	for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
2561*9485SMikore.Li@Sun.COM 		if (error = urtw_8187_write_phy_cck_c(sc,
2562*9485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part3[i].reg,
2563*9485SMikore.Li@Sun.COM 		    urtw_8225v2_rf_part3[i].val))
2564*9485SMikore.Li@Sun.COM 			goto fail;
2565*9485SMikore.Li@Sun.COM 		urtw_delay_ms(1);
2566*9485SMikore.Li@Sun.COM 	}
2567*9485SMikore.Li@Sun.COM 
2568*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, 0x5b, 0x0d))
2569*9485SMikore.Li@Sun.COM 		goto fail;
2570*9485SMikore.Li@Sun.COM 	if (error = urtw_8225v2_set_txpwrlvl(sc, 1))
2571*9485SMikore.Li@Sun.COM 		goto fail;
2572*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_cck_c(sc, 0x10, 0x9b))
2573*9485SMikore.Li@Sun.COM 		goto fail;
2574*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2575*9485SMikore.Li@Sun.COM 	if (error = urtw_8187_write_phy_ofdm_c(sc, 0x26, 0x90))
2576*9485SMikore.Li@Sun.COM 		goto fail;
2577*9485SMikore.Li@Sun.COM 	urtw_delay_ms(1);
2578*9485SMikore.Li@Sun.COM 
2579*9485SMikore.Li@Sun.COM 	/* TX ant A, 0x0 for B */
2580*9485SMikore.Li@Sun.COM 	if (error = urtw_8185_tx_antenna(sc, 0x3))
2581*9485SMikore.Li@Sun.COM 		goto fail;
2582*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, 0x94, 0x3dc00002))
2583*9485SMikore.Li@Sun.COM 		goto fail;
2584*9485SMikore.Li@Sun.COM 
2585*9485SMikore.Li@Sun.COM 	error = urtw_8225_rf_set_chan(sc, 1);
2586*9485SMikore.Li@Sun.COM fail:
2587*9485SMikore.Li@Sun.COM 	return (error);
2588*9485SMikore.Li@Sun.COM #undef N
2589*9485SMikore.Li@Sun.COM }
2590*9485SMikore.Li@Sun.COM 
2591*9485SMikore.Li@Sun.COM static usbd_status
2592*9485SMikore.Li@Sun.COM urtw_8225v2_rf_set_chan(struct urtw_softc *sc, int chan)
2593*9485SMikore.Li@Sun.COM {
2594*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2595*9485SMikore.Li@Sun.COM 	struct ieee80211_channel *c = ic->ic_curchan;
2596*9485SMikore.Li@Sun.COM 	short gset = (IEEE80211_IS_CHAN_G(c)) ? 1 : 0;
2597*9485SMikore.Li@Sun.COM 	usbd_status error;
2598*9485SMikore.Li@Sun.COM 
2599*9485SMikore.Li@Sun.COM 	if (error = urtw_8225v2_set_txpwrlvl(sc, chan))
2600*9485SMikore.Li@Sun.COM 		goto fail;
2601*9485SMikore.Li@Sun.COM 
2602*9485SMikore.Li@Sun.COM 	if (error = urtw_8225_write_c(sc, 0x7, urtw_8225_channel[chan]))
2603*9485SMikore.Li@Sun.COM 		goto fail;
2604*9485SMikore.Li@Sun.COM 
2605*9485SMikore.Li@Sun.COM 	urtw_delay_ms(10);
2606*9485SMikore.Li@Sun.COM 
2607*9485SMikore.Li@Sun.COM 	if (error = urtw_write8_c(sc, URTW_SIFS, 0x22))
2608*9485SMikore.Li@Sun.COM 		goto fail;
2609*9485SMikore.Li@Sun.COM 
2610*9485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_ASSOC &&
2611*9485SMikore.Li@Sun.COM 	    ic->ic_flags & IEEE80211_F_SHSLOT) {
2612*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x9))
2613*9485SMikore.Li@Sun.COM 			goto fail;
2614*9485SMikore.Li@Sun.COM 	} else
2615*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_SLOT, 0x14))
2616*9485SMikore.Li@Sun.COM 			goto fail;
2617*9485SMikore.Li@Sun.COM 	if (gset) {
2618*9485SMikore.Li@Sun.COM 		/* for G */
2619*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x14))
2620*9485SMikore.Li@Sun.COM 			goto fail;
2621*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x14))
2622*9485SMikore.Li@Sun.COM 			goto fail;
2623*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0x73))
2624*9485SMikore.Li@Sun.COM 			goto fail;
2625*9485SMikore.Li@Sun.COM 	} else {
2626*9485SMikore.Li@Sun.COM 		/* for B */
2627*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_DIFS, 0x24))
2628*9485SMikore.Li@Sun.COM 			goto fail;
2629*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_EIFS, 0x5b - 0x24))
2630*9485SMikore.Li@Sun.COM 			goto fail;
2631*9485SMikore.Li@Sun.COM 		if (error = urtw_write8_c(sc, URTW_CW_VAL, 0xa5))
2632*9485SMikore.Li@Sun.COM 			goto fail;
2633*9485SMikore.Li@Sun.COM 	}
2634*9485SMikore.Li@Sun.COM 
2635*9485SMikore.Li@Sun.COM fail:
2636*9485SMikore.Li@Sun.COM 	return (error);
2637*9485SMikore.Li@Sun.COM }
2638*9485SMikore.Li@Sun.COM 
2639*9485SMikore.Li@Sun.COM static int
2640*9485SMikore.Li@Sun.COM urtw_set_channel(struct urtw_softc *sc)
2641*9485SMikore.Li@Sun.COM {
2642*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2643*9485SMikore.Li@Sun.COM 	uint32_t data;
2644*9485SMikore.Li@Sun.COM 	usbd_status error;
2645*9485SMikore.Li@Sun.COM 
2646*9485SMikore.Li@Sun.COM 	if (error = urtw_read32_c(sc, URTW_TX_CONF, &data))
2647*9485SMikore.Li@Sun.COM 		goto fail;
2648*9485SMikore.Li@Sun.COM 	data &= ~URTW_TX_LOOPBACK_MASK;
2649*9485SMikore.Li@Sun.COM 	if (error = urtw_write32_c(sc, URTW_TX_CONF,
2650*9485SMikore.Li@Sun.COM 	    data | URTW_TX_LOOPBACK_MAC))
2651*9485SMikore.Li@Sun.COM 		goto fail;
2652*9485SMikore.Li@Sun.COM 	error = sc->sc_rf_set_chan(sc,
2653*9485SMikore.Li@Sun.COM 	    ieee80211_chan2ieee(ic, ic->ic_curchan));
2654*9485SMikore.Li@Sun.COM 	if (error)
2655*9485SMikore.Li@Sun.COM 		goto fail;
2656*9485SMikore.Li@Sun.COM 	urtw_delay_ms(10);
2657*9485SMikore.Li@Sun.COM 	error = urtw_write32_c(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_NONE);
2658*9485SMikore.Li@Sun.COM fail:
2659*9485SMikore.Li@Sun.COM 	return (error);
2660*9485SMikore.Li@Sun.COM }
2661*9485SMikore.Li@Sun.COM 
2662*9485SMikore.Li@Sun.COM /* ARGSUSED */
2663*9485SMikore.Li@Sun.COM static void
2664*9485SMikore.Li@Sun.COM urtw_txeof_low(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2665*9485SMikore.Li@Sun.COM {
2666*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
2667*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2668*9485SMikore.Li@Sun.COM 
2669*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
2670*9485SMikore.Li@Sun.COM 	    "urtw_txeof_low(): cr:%s(%d), flags:0x%x, tx_queued:%d",
2671*9485SMikore.Li@Sun.COM 	    usb_str_cr(req->bulk_completion_reason),
2672*9485SMikore.Li@Sun.COM 	    req->bulk_completion_reason,
2673*9485SMikore.Li@Sun.COM 	    req->bulk_cb_flags,
2674*9485SMikore.Li@Sun.COM 	    sc->sc_tx_low_queued));
2675*9485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
2676*9485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK) {
2677*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
2678*9485SMikore.Li@Sun.COM 		goto fail;
2679*9485SMikore.Li@Sun.COM 	}
2680*9485SMikore.Li@Sun.COM 
2681*9485SMikore.Li@Sun.COM 	if (sc->sc_need_sched) {
2682*9485SMikore.Li@Sun.COM 		sc->sc_need_sched = 0;
2683*9485SMikore.Li@Sun.COM 		mac_tx_update(ic->ic_mach);
2684*9485SMikore.Li@Sun.COM 	}
2685*9485SMikore.Li@Sun.COM fail:
2686*9485SMikore.Li@Sun.COM 	sc->sc_tx_low_queued--;
2687*9485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
2688*9485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
2689*9485SMikore.Li@Sun.COM }
2690*9485SMikore.Li@Sun.COM 
2691*9485SMikore.Li@Sun.COM /* ARGSUSED */
2692*9485SMikore.Li@Sun.COM static void
2693*9485SMikore.Li@Sun.COM urtw_txeof_normal(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
2694*9485SMikore.Li@Sun.COM {
2695*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)req->bulk_client_private;
2696*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
2697*9485SMikore.Li@Sun.COM 
2698*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
2699*9485SMikore.Li@Sun.COM 	    "urtw_txeof_normal(): cr:%s(%d), flags:0x%x, tx_queued:%d",
2700*9485SMikore.Li@Sun.COM 	    usb_str_cr(req->bulk_completion_reason),
2701*9485SMikore.Li@Sun.COM 	    req->bulk_completion_reason,
2702*9485SMikore.Li@Sun.COM 	    req->bulk_cb_flags,
2703*9485SMikore.Li@Sun.COM 	    sc->sc_tx_normal_queued));
2704*9485SMikore.Li@Sun.COM 
2705*9485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
2706*9485SMikore.Li@Sun.COM 	if (req->bulk_completion_reason != USB_CR_OK) {
2707*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
2708*9485SMikore.Li@Sun.COM 		goto fail;
2709*9485SMikore.Li@Sun.COM 	}
2710*9485SMikore.Li@Sun.COM 
2711*9485SMikore.Li@Sun.COM 	if (sc->sc_need_sched) {
2712*9485SMikore.Li@Sun.COM 		sc->sc_need_sched = 0;
2713*9485SMikore.Li@Sun.COM 		mac_tx_update(ic->ic_mach);
2714*9485SMikore.Li@Sun.COM 	}
2715*9485SMikore.Li@Sun.COM fail:
2716*9485SMikore.Li@Sun.COM 	sc->sc_tx_normal_queued--;
2717*9485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
2718*9485SMikore.Li@Sun.COM 	usb_free_bulk_req(req);
2719*9485SMikore.Li@Sun.COM }
2720*9485SMikore.Li@Sun.COM 
2721*9485SMikore.Li@Sun.COM 
2722*9485SMikore.Li@Sun.COM static int
2723*9485SMikore.Li@Sun.COM urtw_get_rate(struct ieee80211com *ic)
2724*9485SMikore.Li@Sun.COM {
2725*9485SMikore.Li@Sun.COM 	uint8_t (*rates)[IEEE80211_RATE_MAXSIZE];
2726*9485SMikore.Li@Sun.COM 	int rate;
2727*9485SMikore.Li@Sun.COM 
2728*9485SMikore.Li@Sun.COM 	rates = &ic->ic_bss->in_rates.ir_rates;
2729*9485SMikore.Li@Sun.COM 
2730*9485SMikore.Li@Sun.COM 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
2731*9485SMikore.Li@Sun.COM 		rate = ic->ic_fixed_rate;
2732*9485SMikore.Li@Sun.COM 	else if (ic->ic_state == IEEE80211_S_RUN)
2733*9485SMikore.Li@Sun.COM 		rate = (*rates)[ic->ic_bss->in_txrate];
2734*9485SMikore.Li@Sun.COM 	else
2735*9485SMikore.Li@Sun.COM 		rate = 0;
2736*9485SMikore.Li@Sun.COM 	return (rate & IEEE80211_RATE_VAL);
2737*9485SMikore.Li@Sun.COM }
2738*9485SMikore.Li@Sun.COM 
2739*9485SMikore.Li@Sun.COM static int
2740*9485SMikore.Li@Sun.COM urtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2741*9485SMikore.Li@Sun.COM {
2742*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)ic;
2743*9485SMikore.Li@Sun.COM 	struct ieee80211_frame *wh;
2744*9485SMikore.Li@Sun.COM 	struct ieee80211_key *k;
2745*9485SMikore.Li@Sun.COM 	struct ieee80211_node *ni = NULL;
2746*9485SMikore.Li@Sun.COM 	uint8_t *buf;
2747*9485SMikore.Li@Sun.COM 	mblk_t *m = 0, *m0, *mtx;
2748*9485SMikore.Li@Sun.COM 	int off, mblen, xferlen, err = 0, priority = 0;
2749*9485SMikore.Li@Sun.COM 
2750*9485SMikore.Li@Sun.COM 	mutex_enter(&sc->tx_lock);
2751*9485SMikore.Li@Sun.COM 	priority = (type == IEEE80211_FC0_TYPE_DATA) ?
2752*9485SMikore.Li@Sun.COM 	    LOW_PRIORITY_PIPE: NORMAL_PRIORITY_PIPE;
2753*9485SMikore.Li@Sun.COM 
2754*9485SMikore.Li@Sun.COM 	if (URTW_IS_SUSPENDING(sc)) {
2755*9485SMikore.Li@Sun.COM 		err = 0;
2756*9485SMikore.Li@Sun.COM 		goto failed;
2757*9485SMikore.Li@Sun.COM 	}
2758*9485SMikore.Li@Sun.COM 
2759*9485SMikore.Li@Sun.COM 	if (((priority)? sc->sc_tx_normal_queued : sc->sc_tx_low_queued) >=
2760*9485SMikore.Li@Sun.COM 	    URTW_TX_DATA_LIST_COUNT) {
2761*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
2762*9485SMikore.Li@Sun.COM 		    "urtw_send(): no TX buffer!\n"));
2763*9485SMikore.Li@Sun.COM 		sc->sc_tx_nobuf++;
2764*9485SMikore.Li@Sun.COM 		err = ENOMEM;
2765*9485SMikore.Li@Sun.COM 		goto failed;
2766*9485SMikore.Li@Sun.COM 	}
2767*9485SMikore.Li@Sun.COM 
2768*9485SMikore.Li@Sun.COM 	m = allocb(URTW_TXBUF_SIZE, BPRI_MED);
2769*9485SMikore.Li@Sun.COM 	if (m == NULL) {
2770*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_send(): can't alloc mblk.\n");
2771*9485SMikore.Li@Sun.COM 		err = ENOMEM;
2772*9485SMikore.Li@Sun.COM 		goto failed;
2773*9485SMikore.Li@Sun.COM 	}
2774*9485SMikore.Li@Sun.COM 
2775*9485SMikore.Li@Sun.COM 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2776*9485SMikore.Li@Sun.COM 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
2777*9485SMikore.Li@Sun.COM 		(void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
2778*9485SMikore.Li@Sun.COM 		off += mblen;
2779*9485SMikore.Li@Sun.COM 	}
2780*9485SMikore.Li@Sun.COM 	m->b_wptr += off;
2781*9485SMikore.Li@Sun.COM 
2782*9485SMikore.Li@Sun.COM 	wh = (struct ieee80211_frame *)m->b_rptr;
2783*9485SMikore.Li@Sun.COM 
2784*9485SMikore.Li@Sun.COM 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
2785*9485SMikore.Li@Sun.COM 	if (ni == NULL) {
2786*9485SMikore.Li@Sun.COM 		err = ENXIO;
2787*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
2788*9485SMikore.Li@Sun.COM 		goto failed;
2789*9485SMikore.Li@Sun.COM 	}
2790*9485SMikore.Li@Sun.COM 
2791*9485SMikore.Li@Sun.COM 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
2792*9485SMikore.Li@Sun.COM 	    IEEE80211_FC0_TYPE_DATA) {
2793*9485SMikore.Li@Sun.COM 		(void) ieee80211_encap(ic, m, ni);
2794*9485SMikore.Li@Sun.COM 	}
2795*9485SMikore.Li@Sun.COM 
2796*9485SMikore.Li@Sun.COM 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2797*9485SMikore.Li@Sun.COM 		k = ieee80211_crypto_encap(ic, m);
2798*9485SMikore.Li@Sun.COM 		if (k == NULL) {
2799*9485SMikore.Li@Sun.COM 			ic->ic_stats.is_tx_failed++;
2800*9485SMikore.Li@Sun.COM 			err = ENXIO;
2801*9485SMikore.Li@Sun.COM 			goto failed;
2802*9485SMikore.Li@Sun.COM 		}
2803*9485SMikore.Li@Sun.COM 		/* packet header may have moved, reset our local pointer */
2804*9485SMikore.Li@Sun.COM 		wh = (struct ieee80211_frame *)m->b_rptr;
2805*9485SMikore.Li@Sun.COM 	}
2806*9485SMikore.Li@Sun.COM 
2807*9485SMikore.Li@Sun.COM 	xferlen = MBLKL(m) + 4 * 3;
2808*9485SMikore.Li@Sun.COM 	if ((0 == xferlen % 64) || (0 == xferlen % 512))
2809*9485SMikore.Li@Sun.COM 		xferlen += 1;
2810*9485SMikore.Li@Sun.COM 
2811*9485SMikore.Li@Sun.COM 	mtx = allocb(xferlen, BPRI_MED);
2812*9485SMikore.Li@Sun.COM 	buf = mtx->b_rptr;
2813*9485SMikore.Li@Sun.COM 
2814*9485SMikore.Li@Sun.COM 	bzero(buf, xferlen);
2815*9485SMikore.Li@Sun.COM 	buf[0] = MBLKL(m) & 0xff;
2816*9485SMikore.Li@Sun.COM 	buf[1] = (MBLKL(m) & 0x0f00) >> 8;
2817*9485SMikore.Li@Sun.COM 	buf[1] |= (1 << 7);
2818*9485SMikore.Li@Sun.COM 
2819*9485SMikore.Li@Sun.COM 	/* XXX sc_preamble_mode is always 2.  */
2820*9485SMikore.Li@Sun.COM 	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
2821*9485SMikore.Li@Sun.COM 		buf[2] |= (1 << 1);
2822*9485SMikore.Li@Sun.COM 	/* RTS rate - 10 means we use a basic rate.  */
2823*9485SMikore.Li@Sun.COM 	buf[2] |= (urtw_rate2rtl(2) << 3);
2824*9485SMikore.Li@Sun.COM 	/*
2825*9485SMikore.Li@Sun.COM 	 * XXX currently TX rate control depends on the rate value of
2826*9485SMikore.Li@Sun.COM 	 * RX descriptor because I don't know how to we can control TX rate
2827*9485SMikore.Li@Sun.COM 	 * in more smart way.  Please fix me you find a thing.
2828*9485SMikore.Li@Sun.COM 	 */
2829*9485SMikore.Li@Sun.COM 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
2830*9485SMikore.Li@Sun.COM 		buf[3] = urtw_rate2rtl(MAX(2, urtw_get_rate(ic)));
2831*9485SMikore.Li@Sun.COM 	} else
2832*9485SMikore.Li@Sun.COM 		buf[3] = sc->sc_currate;
2833*9485SMikore.Li@Sun.COM 	buf[8] = 3;		/* CW minimum  */
2834*9485SMikore.Li@Sun.COM 	buf[8] |= (7 << 4);	/* CW maximum  */
2835*9485SMikore.Li@Sun.COM 	buf[9] |= 11;		/* retry limitation  */
2836*9485SMikore.Li@Sun.COM 
2837*9485SMikore.Li@Sun.COM 	bcopy(m->b_rptr, &buf[12], MBLKL(m));
2838*9485SMikore.Li@Sun.COM 
2839*9485SMikore.Li@Sun.COM 	(void) urtw_led_ctl(sc, URTW_LED_CTL_TX);
2840*9485SMikore.Li@Sun.COM 	mtx->b_wptr = mtx->b_rptr + xferlen;
2841*9485SMikore.Li@Sun.COM 
2842*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_XMIT, (sc->sc_dev, CE_CONT,
2843*9485SMikore.Li@Sun.COM 	    "sending data frame len=%u rate=%u xfer len=%u\n",
2844*9485SMikore.Li@Sun.COM 	    MBLKL(m), buf[3], xferlen));
2845*9485SMikore.Li@Sun.COM 
2846*9485SMikore.Li@Sun.COM 	err = urtw_tx_start(sc, mtx, priority);
2847*9485SMikore.Li@Sun.COM 	if (!err) {
2848*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_frags++;
2849*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_bytes += MBLKL(m);
2850*9485SMikore.Li@Sun.COM 	} else {
2851*9485SMikore.Li@Sun.COM 		ic->ic_stats.is_tx_failed++;
2852*9485SMikore.Li@Sun.COM 	}
2853*9485SMikore.Li@Sun.COM 
2854*9485SMikore.Li@Sun.COM failed:
2855*9485SMikore.Li@Sun.COM 	if (ni != NULL)
2856*9485SMikore.Li@Sun.COM 		ieee80211_free_node(ni);
2857*9485SMikore.Li@Sun.COM 
2858*9485SMikore.Li@Sun.COM 	if ((mp) &&
2859*9485SMikore.Li@Sun.COM 	    ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
2860*9485SMikore.Li@Sun.COM 	    err == DDI_SUCCESS)) {
2861*9485SMikore.Li@Sun.COM 		freemsg(mp);
2862*9485SMikore.Li@Sun.COM 	}
2863*9485SMikore.Li@Sun.COM 	if (m) freemsg(m);
2864*9485SMikore.Li@Sun.COM 
2865*9485SMikore.Li@Sun.COM 	if (((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) &&
2866*9485SMikore.Li@Sun.COM 	    (err != 0)) {
2867*9485SMikore.Li@Sun.COM 		sc->sc_need_sched = 1;
2868*9485SMikore.Li@Sun.COM 	}
2869*9485SMikore.Li@Sun.COM 	mutex_exit(&sc->tx_lock);
2870*9485SMikore.Li@Sun.COM 	return (err);
2871*9485SMikore.Li@Sun.COM }
2872*9485SMikore.Li@Sun.COM 
2873*9485SMikore.Li@Sun.COM static void
2874*9485SMikore.Li@Sun.COM urtw_next_scan(void *arg)
2875*9485SMikore.Li@Sun.COM {
2876*9485SMikore.Li@Sun.COM 	ieee80211com_t *ic = arg;
2877*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
2878*9485SMikore.Li@Sun.COM 
2879*9485SMikore.Li@Sun.COM 	if (URTW_IS_NOT_RUNNING(sc)) {
2880*9485SMikore.Li@Sun.COM 		sc->sc_scan_id = 0;
2881*9485SMikore.Li@Sun.COM 		return;
2882*9485SMikore.Li@Sun.COM 	}
2883*9485SMikore.Li@Sun.COM 
2884*9485SMikore.Li@Sun.COM 	if (ic->ic_state == IEEE80211_S_SCAN) {
2885*9485SMikore.Li@Sun.COM 		(void) ieee80211_next_scan(ic);
2886*9485SMikore.Li@Sun.COM 	}
2887*9485SMikore.Li@Sun.COM 	sc->sc_scan_id = 0;
2888*9485SMikore.Li@Sun.COM }
2889*9485SMikore.Li@Sun.COM 
2890*9485SMikore.Li@Sun.COM static void
2891*9485SMikore.Li@Sun.COM urtw_led_launch(void *arg)
2892*9485SMikore.Li@Sun.COM {
2893*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
2894*9485SMikore.Li@Sun.COM 	ieee80211com_t *ic = &sc->sc_ic;
2895*9485SMikore.Li@Sun.COM 	int error = 0;
2896*9485SMikore.Li@Sun.COM 
2897*9485SMikore.Li@Sun.COM 	URTW_LEDLOCK(sc);
2898*9485SMikore.Li@Sun.COM 	if ((sc->sc_strategy != URTW_SW_LED_MODE0) ||
2899*9485SMikore.Li@Sun.COM 	    URTW_IS_NOT_RUNNING(sc) ||
2900*9485SMikore.Li@Sun.COM 	    URTW_IS_SUSPENDING(sc)) {
2901*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
2902*9485SMikore.Li@Sun.COM 		    "failed process LED strategy 0x%x, run?%d",
2903*9485SMikore.Li@Sun.COM 		    sc->sc_strategy,
2904*9485SMikore.Li@Sun.COM 		    sc->sc_flags));
2905*9485SMikore.Li@Sun.COM 		sc->sc_led_ch = 0;
2906*9485SMikore.Li@Sun.COM 		sc->sc_gpio_ledinprogress = 0;
2907*9485SMikore.Li@Sun.COM 		URTW_LEDUNLOCK(sc);
2908*9485SMikore.Li@Sun.COM 		return;
2909*9485SMikore.Li@Sun.COM 	}
2910*9485SMikore.Li@Sun.COM 	error = urtw_led_blink(sc);
2911*9485SMikore.Li@Sun.COM 	if (error) {
2912*9485SMikore.Li@Sun.COM 		sc->sc_led_ch = timeout(urtw_led_launch, (void *)sc,
2913*9485SMikore.Li@Sun.COM 		    drv_usectohz((ic->ic_state == IEEE80211_S_RUN) ?
2914*9485SMikore.Li@Sun.COM 		    URTW_LED_LINKON_BLINK: URTW_LED_LINKOFF_BLINK));
2915*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
2916*9485SMikore.Li@Sun.COM 		    "try again led launch"));
2917*9485SMikore.Li@Sun.COM 	} else {
2918*9485SMikore.Li@Sun.COM 		sc->sc_led_ch = 0;
2919*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_LED, (sc->sc_dev, CE_CONT,
2920*9485SMikore.Li@Sun.COM 		    "exit led launch"));
2921*9485SMikore.Li@Sun.COM 	}
2922*9485SMikore.Li@Sun.COM 	URTW_LEDUNLOCK(sc);
2923*9485SMikore.Li@Sun.COM }
2924*9485SMikore.Li@Sun.COM 
2925*9485SMikore.Li@Sun.COM static int
2926*9485SMikore.Li@Sun.COM urtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2927*9485SMikore.Li@Sun.COM {
2928*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)ic;
2929*9485SMikore.Li@Sun.COM 	struct ieee80211_node *ni;
2930*9485SMikore.Li@Sun.COM 	int error = 0;
2931*9485SMikore.Li@Sun.COM 
2932*9485SMikore.Li@Sun.COM 	if (sc->sc_scan_id != 0) {
2933*9485SMikore.Li@Sun.COM 		(void) untimeout(sc->sc_scan_id);
2934*9485SMikore.Li@Sun.COM 		sc->sc_scan_id = 0;
2935*9485SMikore.Li@Sun.COM 	}
2936*9485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
2937*9485SMikore.Li@Sun.COM 	switch (nstate) {
2938*9485SMikore.Li@Sun.COM 	case IEEE80211_S_INIT:
2939*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
2940*9485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "-> IEEE80211_S_INIT...arg(%d)\n",
2941*9485SMikore.Li@Sun.COM 		    arg));
2942*9485SMikore.Li@Sun.COM 		(void) urtw_update_msr(sc, nstate);
2943*9485SMikore.Li@Sun.COM 		(void) urtw_led_off(sc, URTW_LED_GPIO);
2944*9485SMikore.Li@Sun.COM 		break;
2945*9485SMikore.Li@Sun.COM 
2946*9485SMikore.Li@Sun.COM 	case IEEE80211_S_SCAN:
2947*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
2948*9485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT,
2949*9485SMikore.Li@Sun.COM 		    "-> IEEE80211_S_SCAN...arg(%d)...[%d]\n",
2950*9485SMikore.Li@Sun.COM 		    arg, ieee80211_chan2ieee(ic, ic->ic_curchan)));
2951*9485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
2952*9485SMikore.Li@Sun.COM 		if (error) {
2953*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
2954*9485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "scan setchan failed"));
2955*9485SMikore.Li@Sun.COM 			break;
2956*9485SMikore.Li@Sun.COM 		}
2957*9485SMikore.Li@Sun.COM 		sc->sc_scan_id = timeout(urtw_next_scan, (void *)sc,
2958*9485SMikore.Li@Sun.COM 		    drv_usectohz(sc->dwelltime * 1000));
2959*9485SMikore.Li@Sun.COM 		break;
2960*9485SMikore.Li@Sun.COM 
2961*9485SMikore.Li@Sun.COM 	case IEEE80211_S_AUTH:
2962*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
2963*9485SMikore.Li@Sun.COM 		    "-> IEEE80211_S_AUTH ...arg(%d)\n", arg));
2964*9485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
2965*9485SMikore.Li@Sun.COM 		if (error) {
2966*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
2967*9485SMikore.Li@Sun.COM 			    (sc->sc_dev,  CE_CONT, "auth setchan failed"));
2968*9485SMikore.Li@Sun.COM 		}
2969*9485SMikore.Li@Sun.COM 		break;
2970*9485SMikore.Li@Sun.COM 
2971*9485SMikore.Li@Sun.COM 	case IEEE80211_S_ASSOC:
2972*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE, (sc->sc_dev, CE_CONT,
2973*9485SMikore.Li@Sun.COM 		    "-> IEEE80211_S_ASSOC ...arg(%d)\n", arg));
2974*9485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
2975*9485SMikore.Li@Sun.COM 		if (error) {
2976*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
2977*9485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "assoc setchan failed"));
2978*9485SMikore.Li@Sun.COM 		}
2979*9485SMikore.Li@Sun.COM 		break;
2980*9485SMikore.Li@Sun.COM 
2981*9485SMikore.Li@Sun.COM 	case IEEE80211_S_RUN:
2982*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_STATE,
2983*9485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "-> IEEE80211_S_RUN ...arg(%d)\n",
2984*9485SMikore.Li@Sun.COM 		    arg));
2985*9485SMikore.Li@Sun.COM 		error = urtw_set_channel(sc);
2986*9485SMikore.Li@Sun.COM 		if (error) {
2987*9485SMikore.Li@Sun.COM 			URTW8187_DBG(URTW_DEBUG_STATE,
2988*9485SMikore.Li@Sun.COM 			    (sc->sc_dev, CE_CONT, "run setchan failed"));
2989*9485SMikore.Li@Sun.COM 			goto fail;
2990*9485SMikore.Li@Sun.COM 		}
2991*9485SMikore.Li@Sun.COM 		ni = ic->ic_bss;
2992*9485SMikore.Li@Sun.COM 		/* setting bssid.  */
2993*9485SMikore.Li@Sun.COM 		(void) urtw_write32_c(sc, URTW_BSSID,
2994*9485SMikore.Li@Sun.COM 		    ((uint32_t *)(uintptr_t)ni->in_bssid)[0]);
2995*9485SMikore.Li@Sun.COM 		(void) urtw_write16_c(sc, URTW_BSSID + 4,
2996*9485SMikore.Li@Sun.COM 		    ((uint16_t *)(uintptr_t)ni->in_bssid)[2]);
2997*9485SMikore.Li@Sun.COM 		(void) urtw_update_msr(sc, nstate);
2998*9485SMikore.Li@Sun.COM 
2999*9485SMikore.Li@Sun.COM 		ni->in_txrate = ni->in_rates.ir_nrates - 1;
3000*9485SMikore.Li@Sun.COM 		break;
3001*9485SMikore.Li@Sun.COM 	}
3002*9485SMikore.Li@Sun.COM fail:
3003*9485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
3004*9485SMikore.Li@Sun.COM 
3005*9485SMikore.Li@Sun.COM 	if (error)
3006*9485SMikore.Li@Sun.COM 		return (EIO);
3007*9485SMikore.Li@Sun.COM 	error = sc->sc_newstate(ic, nstate, arg);
3008*9485SMikore.Li@Sun.COM 	return (error);
3009*9485SMikore.Li@Sun.COM }
3010*9485SMikore.Li@Sun.COM 
3011*9485SMikore.Li@Sun.COM static void
3012*9485SMikore.Li@Sun.COM urtw_close_pipes(struct urtw_softc *sc)
3013*9485SMikore.Li@Sun.COM {
3014*9485SMikore.Li@Sun.COM 	usb_flags_t flags = USB_FLAGS_SLEEP;
3015*9485SMikore.Li@Sun.COM 
3016*9485SMikore.Li@Sun.COM 	if (sc->sc_rxpipe != NULL) {
3017*9485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
3018*9485SMikore.Li@Sun.COM 		    sc->sc_rxpipe, flags, NULL, 0);
3019*9485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
3020*9485SMikore.Li@Sun.COM 		    sc->sc_rxpipe, flags, NULL, 0);
3021*9485SMikore.Li@Sun.COM 		sc->sc_rxpipe = NULL;
3022*9485SMikore.Li@Sun.COM 	}
3023*9485SMikore.Li@Sun.COM 
3024*9485SMikore.Li@Sun.COM 	if (sc->sc_txpipe_low != NULL) {
3025*9485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
3026*9485SMikore.Li@Sun.COM 		    sc->sc_txpipe_low, flags, NULL, 0);
3027*9485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
3028*9485SMikore.Li@Sun.COM 		    sc->sc_txpipe_low, flags, NULL, 0);
3029*9485SMikore.Li@Sun.COM 		sc->sc_txpipe_low = NULL;
3030*9485SMikore.Li@Sun.COM 	}
3031*9485SMikore.Li@Sun.COM 
3032*9485SMikore.Li@Sun.COM 	if (sc->sc_txpipe_normal != NULL) {
3033*9485SMikore.Li@Sun.COM 		usb_pipe_reset(sc->sc_dev,
3034*9485SMikore.Li@Sun.COM 		    sc->sc_txpipe_normal, flags, NULL, 0);
3035*9485SMikore.Li@Sun.COM 		usb_pipe_close(sc->sc_dev,
3036*9485SMikore.Li@Sun.COM 		    sc->sc_txpipe_normal, flags, NULL, 0);
3037*9485SMikore.Li@Sun.COM 		sc->sc_txpipe_normal = NULL;
3038*9485SMikore.Li@Sun.COM 	}
3039*9485SMikore.Li@Sun.COM }
3040*9485SMikore.Li@Sun.COM 
3041*9485SMikore.Li@Sun.COM static int
3042*9485SMikore.Li@Sun.COM urtw_open_pipes(struct urtw_softc *sc)
3043*9485SMikore.Li@Sun.COM {
3044*9485SMikore.Li@Sun.COM 	usb_ep_data_t *ep_node;
3045*9485SMikore.Li@Sun.COM 	usb_pipe_policy_t policy;
3046*9485SMikore.Li@Sun.COM 	int err;
3047*9485SMikore.Li@Sun.COM 
3048*9485SMikore.Li@Sun.COM 	if (sc->sc_rxpipe || sc->sc_txpipe_low || sc->sc_txpipe_normal)
3049*9485SMikore.Li@Sun.COM 		return (USB_SUCCESS);
3050*9485SMikore.Li@Sun.COM 
3051*9485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3052*9485SMikore.Li@Sun.COM 	    LOW_PRIORITY_PIPE, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
3053*9485SMikore.Li@Sun.COM 
3054*9485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
3055*9485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
3056*9485SMikore.Li@Sun.COM 
3057*9485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
3058*9485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
3059*9485SMikore.Li@Sun.COM 	    &sc->sc_txpipe_low)) != USB_SUCCESS) {
3060*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
3061*9485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x low priority pipe open failed\n",
3062*9485SMikore.Li@Sun.COM 		    err));
3063*9485SMikore.Li@Sun.COM 		goto fail;
3064*9485SMikore.Li@Sun.COM 	}
3065*9485SMikore.Li@Sun.COM 
3066*9485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0,
3067*9485SMikore.Li@Sun.COM 	    NORMAL_PRIORITY_PIPE, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
3068*9485SMikore.Li@Sun.COM 
3069*9485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
3070*9485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_TX_DATA_LIST_COUNT;
3071*9485SMikore.Li@Sun.COM 
3072*9485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
3073*9485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
3074*9485SMikore.Li@Sun.COM 	    &sc->sc_txpipe_normal)) != USB_SUCCESS) {
3075*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
3076*9485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x failed to open high tx pipe\n",
3077*9485SMikore.Li@Sun.COM 		    err));
3078*9485SMikore.Li@Sun.COM 		goto fail;
3079*9485SMikore.Li@Sun.COM 	}
3080*9485SMikore.Li@Sun.COM 
3081*9485SMikore.Li@Sun.COM 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
3082*9485SMikore.Li@Sun.COM 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
3083*9485SMikore.Li@Sun.COM 
3084*9485SMikore.Li@Sun.COM 	bzero(&policy, sizeof (usb_pipe_policy_t));
3085*9485SMikore.Li@Sun.COM 	policy.pp_max_async_reqs = URTW_RX_DATA_LIST_COUNT;
3086*9485SMikore.Li@Sun.COM 
3087*9485SMikore.Li@Sun.COM 	if ((err = usb_pipe_open(sc->sc_dev,
3088*9485SMikore.Li@Sun.COM 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
3089*9485SMikore.Li@Sun.COM 	    &sc->sc_rxpipe)) != USB_SUCCESS) {
3090*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
3091*9485SMikore.Li@Sun.COM 		    "urtw_open_pipes(): %x failed to open rx pipe\n", err));
3092*9485SMikore.Li@Sun.COM 		goto fail;
3093*9485SMikore.Li@Sun.COM 	}
3094*9485SMikore.Li@Sun.COM 
3095*9485SMikore.Li@Sun.COM 	return (USB_SUCCESS);
3096*9485SMikore.Li@Sun.COM 
3097*9485SMikore.Li@Sun.COM fail:
3098*9485SMikore.Li@Sun.COM 	urtw_close_pipes(sc);
3099*9485SMikore.Li@Sun.COM 	return (USB_FAILURE);
3100*9485SMikore.Li@Sun.COM }
3101*9485SMikore.Li@Sun.COM 
3102*9485SMikore.Li@Sun.COM static int
3103*9485SMikore.Li@Sun.COM urtw_tx_start(struct urtw_softc *sc, mblk_t *mp, int priority)
3104*9485SMikore.Li@Sun.COM {
3105*9485SMikore.Li@Sun.COM 	usb_bulk_req_t *req;
3106*9485SMikore.Li@Sun.COM 	int err;
3107*9485SMikore.Li@Sun.COM 
3108*9485SMikore.Li@Sun.COM 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
3109*9485SMikore.Li@Sun.COM 	if (req == NULL) {
3110*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
3111*9485SMikore.Li@Sun.COM 		    "urtw_tx_start(): failed to allocate req"));
3112*9485SMikore.Li@Sun.COM 		freemsg(mp);
3113*9485SMikore.Li@Sun.COM 		return (-1);
3114*9485SMikore.Li@Sun.COM 	}
3115*9485SMikore.Li@Sun.COM 
3116*9485SMikore.Li@Sun.COM 	req->bulk_len = MBLKL(mp);
3117*9485SMikore.Li@Sun.COM 	req->bulk_data = mp;
3118*9485SMikore.Li@Sun.COM 	req->bulk_client_private = (usb_opaque_t)sc;
3119*9485SMikore.Li@Sun.COM 	req->bulk_timeout = URTW_TX_TIMEOUT;
3120*9485SMikore.Li@Sun.COM 	req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
3121*9485SMikore.Li@Sun.COM 	req->bulk_cb = (priority)?urtw_txeof_normal : urtw_txeof_low;
3122*9485SMikore.Li@Sun.COM 	req->bulk_exc_cb = (priority)?urtw_txeof_normal: urtw_txeof_low;
3123*9485SMikore.Li@Sun.COM 	req->bulk_completion_reason = 0;
3124*9485SMikore.Li@Sun.COM 	req->bulk_cb_flags = 0;
3125*9485SMikore.Li@Sun.COM 
3126*9485SMikore.Li@Sun.COM 	if ((err = usb_pipe_bulk_xfer(
3127*9485SMikore.Li@Sun.COM 	    (priority)?sc->sc_txpipe_normal:sc->sc_txpipe_low, req, 0))
3128*9485SMikore.Li@Sun.COM 	    != USB_SUCCESS) {
3129*9485SMikore.Li@Sun.COM 		sc->sc_ic.ic_stats.is_tx_failed++;
3130*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_TX_PROC, (sc->sc_dev, CE_CONT,
3131*9485SMikore.Li@Sun.COM 		    "urtw_tx_start: failed to do tx xfer, %d", err));
3132*9485SMikore.Li@Sun.COM 		usb_free_bulk_req(req);
3133*9485SMikore.Li@Sun.COM 		return (EIO);
3134*9485SMikore.Li@Sun.COM 	}
3135*9485SMikore.Li@Sun.COM 
3136*9485SMikore.Li@Sun.COM 	if (priority) {
3137*9485SMikore.Li@Sun.COM 		sc->sc_tx_normal_queued++;
3138*9485SMikore.Li@Sun.COM 	} else {
3139*9485SMikore.Li@Sun.COM 		sc->sc_tx_low_queued++;
3140*9485SMikore.Li@Sun.COM 	}
3141*9485SMikore.Li@Sun.COM 
3142*9485SMikore.Li@Sun.COM 	return (0);
3143*9485SMikore.Li@Sun.COM }
3144*9485SMikore.Li@Sun.COM 
3145*9485SMikore.Li@Sun.COM static int
3146*9485SMikore.Li@Sun.COM urtw_rx_start(struct urtw_softc *sc)
3147*9485SMikore.Li@Sun.COM {
3148*9485SMikore.Li@Sun.COM 	usb_bulk_req_t *req;
3149*9485SMikore.Li@Sun.COM 	int err;
3150*9485SMikore.Li@Sun.COM 
3151*9485SMikore.Li@Sun.COM 	req = usb_alloc_bulk_req(sc->sc_dev, URTW_RXBUF_SIZE, USB_FLAGS_SLEEP);
3152*9485SMikore.Li@Sun.COM 	if (req == NULL) {
3153*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
3154*9485SMikore.Li@Sun.COM 		    "urtw_rx_start(): failed to allocate req"));
3155*9485SMikore.Li@Sun.COM 		return (-1);
3156*9485SMikore.Li@Sun.COM 	}
3157*9485SMikore.Li@Sun.COM 
3158*9485SMikore.Li@Sun.COM 	req->bulk_len		= URTW_RXBUF_SIZE;
3159*9485SMikore.Li@Sun.COM 	req->bulk_client_private = (usb_opaque_t)sc;
3160*9485SMikore.Li@Sun.COM 	req->bulk_timeout	= 0;
3161*9485SMikore.Li@Sun.COM 	req->bulk_attributes	= USB_ATTRS_SHORT_XFER_OK |
3162*9485SMikore.Li@Sun.COM 	    USB_ATTRS_AUTOCLEARING;
3163*9485SMikore.Li@Sun.COM 	req->bulk_cb		= urtw_rxeof;
3164*9485SMikore.Li@Sun.COM 	req->bulk_exc_cb	= urtw_rxeof;
3165*9485SMikore.Li@Sun.COM 	req->bulk_completion_reason = 0;
3166*9485SMikore.Li@Sun.COM 	req->bulk_cb_flags	= 0;
3167*9485SMikore.Li@Sun.COM 
3168*9485SMikore.Li@Sun.COM 	err = usb_pipe_bulk_xfer(sc->sc_rxpipe, req, 0);
3169*9485SMikore.Li@Sun.COM 
3170*9485SMikore.Li@Sun.COM 	if (err != USB_SUCCESS) {
3171*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_RECV, (sc->sc_dev, CE_CONT,
3172*9485SMikore.Li@Sun.COM 		    "urtw_rx_start: failed to do rx xfer, %d", err));
3173*9485SMikore.Li@Sun.COM 		usb_free_bulk_req(req);
3174*9485SMikore.Li@Sun.COM 		return (-1);
3175*9485SMikore.Li@Sun.COM 	}
3176*9485SMikore.Li@Sun.COM 
3177*9485SMikore.Li@Sun.COM 	mutex_enter(&sc->rx_lock);
3178*9485SMikore.Li@Sun.COM 	sc->rx_queued++;
3179*9485SMikore.Li@Sun.COM 	mutex_exit(&sc->rx_lock);
3180*9485SMikore.Li@Sun.COM 
3181*9485SMikore.Li@Sun.COM 	return (0);
3182*9485SMikore.Li@Sun.COM }
3183*9485SMikore.Li@Sun.COM 
3184*9485SMikore.Li@Sun.COM static int
3185*9485SMikore.Li@Sun.COM urtw_disconnect(dev_info_t *devinfo)
3186*9485SMikore.Li@Sun.COM {
3187*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
3188*9485SMikore.Li@Sun.COM 
3189*9485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
3190*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HOTPLUG,
3191*9485SMikore.Li@Sun.COM 	    (sc->sc_dev, CE_CONT, "urtw_offline()\n"));
3192*9485SMikore.Li@Sun.COM 
3193*9485SMikore.Li@Sun.COM 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3194*9485SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(&sc->sc_ic);
3195*9485SMikore.Li@Sun.COM 	if (URTW_IS_RUNNING(sc)) {
3196*9485SMikore.Li@Sun.COM 		urtw_stop(sc);
3197*9485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
3198*9485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
3199*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3200*9485SMikore.Li@Sun.COM 	}
3201*9485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
3202*9485SMikore.Li@Sun.COM }
3203*9485SMikore.Li@Sun.COM 
3204*9485SMikore.Li@Sun.COM static int
3205*9485SMikore.Li@Sun.COM urtw_reconnect(dev_info_t *devinfo)
3206*9485SMikore.Li@Sun.COM {
3207*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
3208*9485SMikore.Li@Sun.COM 	int error = 0;
3209*9485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
3210*9485SMikore.Li@Sun.COM 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
3211*9485SMikore.Li@Sun.COM 	    USB_CHK_ALL, NULL) != USB_SUCCESS)
3212*9485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
3213*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_HOTPLUG, (sc->sc_dev, CE_CONT,
3214*9485SMikore.Li@Sun.COM 	    "urtw_online()\n"));
3215*9485SMikore.Li@Sun.COM 	if (URTW_IS_PLUGIN_ONLINE(sc)) {
3216*9485SMikore.Li@Sun.COM 		error = urtw_init(sc);
3217*9485SMikore.Li@Sun.COM 		if (!error) {
3218*9485SMikore.Li@Sun.COM 			URTW_LOCK(sc);
3219*9485SMikore.Li@Sun.COM 			sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
3220*9485SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
3221*9485SMikore.Li@Sun.COM 		}
3222*9485SMikore.Li@Sun.COM 	}
3223*9485SMikore.Li@Sun.COM 	return (error);
3224*9485SMikore.Li@Sun.COM }
3225*9485SMikore.Li@Sun.COM 
3226*9485SMikore.Li@Sun.COM static mblk_t *
3227*9485SMikore.Li@Sun.COM urtw_m_tx(void *arg, mblk_t *mp)
3228*9485SMikore.Li@Sun.COM {
3229*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
3230*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3231*9485SMikore.Li@Sun.COM 	mblk_t *next;
3232*9485SMikore.Li@Sun.COM 
3233*9485SMikore.Li@Sun.COM 	if ((ic->ic_state != IEEE80211_S_RUN) ||
3234*9485SMikore.Li@Sun.COM 	    URTW_IS_SUSPENDING(sc)) {
3235*9485SMikore.Li@Sun.COM 		freemsgchain(mp);
3236*9485SMikore.Li@Sun.COM 		return (NULL);
3237*9485SMikore.Li@Sun.COM 	}
3238*9485SMikore.Li@Sun.COM 
3239*9485SMikore.Li@Sun.COM 	while (mp != NULL) {
3240*9485SMikore.Li@Sun.COM 		next = mp->b_next;
3241*9485SMikore.Li@Sun.COM 		mp->b_next = NULL;
3242*9485SMikore.Li@Sun.COM 		if (urtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
3243*9485SMikore.Li@Sun.COM 			mp->b_next = next;
3244*9485SMikore.Li@Sun.COM 			break;
3245*9485SMikore.Li@Sun.COM 		}
3246*9485SMikore.Li@Sun.COM 		mp = next;
3247*9485SMikore.Li@Sun.COM 	}
3248*9485SMikore.Li@Sun.COM 	return (mp);
3249*9485SMikore.Li@Sun.COM }
3250*9485SMikore.Li@Sun.COM 
3251*9485SMikore.Li@Sun.COM static int
3252*9485SMikore.Li@Sun.COM urtw_m_start(void *arg)
3253*9485SMikore.Li@Sun.COM {
3254*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
3255*9485SMikore.Li@Sun.COM 	int error = 0;
3256*9485SMikore.Li@Sun.COM 
3257*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE,
3258*9485SMikore.Li@Sun.COM 	    (sc->sc_dev, CE_CONT, "urtw_m_start)\n"));
3259*9485SMikore.Li@Sun.COM 	error = urtw_init(sc);
3260*9485SMikore.Li@Sun.COM 	return (error);
3261*9485SMikore.Li@Sun.COM }
3262*9485SMikore.Li@Sun.COM 
3263*9485SMikore.Li@Sun.COM static void
3264*9485SMikore.Li@Sun.COM urtw_m_stop(void *arg)
3265*9485SMikore.Li@Sun.COM {
3266*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
3267*9485SMikore.Li@Sun.COM 
3268*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ACTIVE, (sc->sc_dev, CE_CONT,
3269*9485SMikore.Li@Sun.COM 	    "urtw_m_stop()\n"));
3270*9485SMikore.Li@Sun.COM 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3271*9485SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(&sc->sc_ic);
3272*9485SMikore.Li@Sun.COM 	(void) urtw_stop(sc);
3273*9485SMikore.Li@Sun.COM }
3274*9485SMikore.Li@Sun.COM 
3275*9485SMikore.Li@Sun.COM /*ARGSUSED*/
3276*9485SMikore.Li@Sun.COM static int
3277*9485SMikore.Li@Sun.COM urtw_m_unicst(void *arg, const uint8_t *macaddr)
3278*9485SMikore.Li@Sun.COM {
3279*9485SMikore.Li@Sun.COM 	return (ENOTSUP);
3280*9485SMikore.Li@Sun.COM }
3281*9485SMikore.Li@Sun.COM 
3282*9485SMikore.Li@Sun.COM /*ARGSUSED*/
3283*9485SMikore.Li@Sun.COM static int
3284*9485SMikore.Li@Sun.COM urtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
3285*9485SMikore.Li@Sun.COM {
3286*9485SMikore.Li@Sun.COM 	return (ENOTSUP);
3287*9485SMikore.Li@Sun.COM }
3288*9485SMikore.Li@Sun.COM 
3289*9485SMikore.Li@Sun.COM /*ARGSUSED*/
3290*9485SMikore.Li@Sun.COM static int
3291*9485SMikore.Li@Sun.COM urtw_m_promisc(void *arg, boolean_t on)
3292*9485SMikore.Li@Sun.COM {
3293*9485SMikore.Li@Sun.COM 	return (0);
3294*9485SMikore.Li@Sun.COM }
3295*9485SMikore.Li@Sun.COM 
3296*9485SMikore.Li@Sun.COM static int
3297*9485SMikore.Li@Sun.COM urtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3298*9485SMikore.Li@Sun.COM     uint_t wldp_length, const void *wldp_buf)
3299*9485SMikore.Li@Sun.COM {
3300*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
3301*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3302*9485SMikore.Li@Sun.COM 	int err;
3303*9485SMikore.Li@Sun.COM 
3304*9485SMikore.Li@Sun.COM 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
3305*9485SMikore.Li@Sun.COM 	    wldp_length, wldp_buf);
3306*9485SMikore.Li@Sun.COM 	if (err == ENETRESET) {
3307*9485SMikore.Li@Sun.COM 		if (ic->ic_des_esslen && URTW_IS_RUNNING(sc)) {
3308*9485SMikore.Li@Sun.COM 			(void) urtw_init(sc);
3309*9485SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
3310*9485SMikore.Li@Sun.COM 		}
3311*9485SMikore.Li@Sun.COM 		err = 0;
3312*9485SMikore.Li@Sun.COM 	}
3313*9485SMikore.Li@Sun.COM 	return (err);
3314*9485SMikore.Li@Sun.COM }
3315*9485SMikore.Li@Sun.COM 
3316*9485SMikore.Li@Sun.COM static void
3317*9485SMikore.Li@Sun.COM urtw_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3318*9485SMikore.Li@Sun.COM {
3319*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = (struct urtw_softc *)arg;
3320*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3321*9485SMikore.Li@Sun.COM 	int err;
3322*9485SMikore.Li@Sun.COM 
3323*9485SMikore.Li@Sun.COM 	err = ieee80211_ioctl(ic, wq, mp);
3324*9485SMikore.Li@Sun.COM 	if (err == ENETRESET) {
3325*9485SMikore.Li@Sun.COM 		if (ic->ic_des_esslen && URTW_IS_RUNNING(sc)) {
3326*9485SMikore.Li@Sun.COM 			(void) urtw_init(sc);
3327*9485SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic,
3328*9485SMikore.Li@Sun.COM 			    IEEE80211_S_SCAN, -1);
3329*9485SMikore.Li@Sun.COM 		}
3330*9485SMikore.Li@Sun.COM 	}
3331*9485SMikore.Li@Sun.COM }
3332*9485SMikore.Li@Sun.COM 
3333*9485SMikore.Li@Sun.COM static int
3334*9485SMikore.Li@Sun.COM urtw_m_stat(void *arg, uint_t stat, uint64_t *val)
3335*9485SMikore.Li@Sun.COM {
3336*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc  = (struct urtw_softc *)arg;
3337*9485SMikore.Li@Sun.COM 	ieee80211com_t	*ic = &sc->sc_ic;
3338*9485SMikore.Li@Sun.COM 	ieee80211_node_t *ni = 0;
3339*9485SMikore.Li@Sun.COM 	struct ieee80211_rateset *rs = 0;
3340*9485SMikore.Li@Sun.COM 
3341*9485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
3342*9485SMikore.Li@Sun.COM 	switch (stat) {
3343*9485SMikore.Li@Sun.COM 	case MAC_STAT_IFSPEED:
3344*9485SMikore.Li@Sun.COM 		ni = ic->ic_bss;
3345*9485SMikore.Li@Sun.COM 		rs = &ni->in_rates;
3346*9485SMikore.Li@Sun.COM 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
3347*9485SMikore.Li@Sun.COM 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
3348*9485SMikore.Li@Sun.COM 		    : ic->ic_fixed_rate) / 2 * 1000000;
3349*9485SMikore.Li@Sun.COM 		break;
3350*9485SMikore.Li@Sun.COM 	case MAC_STAT_NOXMTBUF:
3351*9485SMikore.Li@Sun.COM 		*val = sc->sc_tx_nobuf;
3352*9485SMikore.Li@Sun.COM 		break;
3353*9485SMikore.Li@Sun.COM 	case MAC_STAT_NORCVBUF:
3354*9485SMikore.Li@Sun.COM 		*val = sc->sc_rx_nobuf;
3355*9485SMikore.Li@Sun.COM 		break;
3356*9485SMikore.Li@Sun.COM 	case MAC_STAT_IERRORS:
3357*9485SMikore.Li@Sun.COM 		*val = sc->sc_rx_err;
3358*9485SMikore.Li@Sun.COM 		break;
3359*9485SMikore.Li@Sun.COM 	case MAC_STAT_RBYTES:
3360*9485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_rx_bytes;
3361*9485SMikore.Li@Sun.COM 		break;
3362*9485SMikore.Li@Sun.COM 	case MAC_STAT_IPACKETS:
3363*9485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_rx_frags;
3364*9485SMikore.Li@Sun.COM 		break;
3365*9485SMikore.Li@Sun.COM 	case MAC_STAT_OBYTES:
3366*9485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_bytes;
3367*9485SMikore.Li@Sun.COM 		break;
3368*9485SMikore.Li@Sun.COM 	case MAC_STAT_OPACKETS:
3369*9485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_frags;
3370*9485SMikore.Li@Sun.COM 		break;
3371*9485SMikore.Li@Sun.COM 	case MAC_STAT_OERRORS:
3372*9485SMikore.Li@Sun.COM 		*val = ic->ic_stats.is_tx_failed;
3373*9485SMikore.Li@Sun.COM 		break;
3374*9485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_FRAGS:
3375*9485SMikore.Li@Sun.COM 	case WIFI_STAT_MCAST_TX:
3376*9485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_FAILED:
3377*9485SMikore.Li@Sun.COM 	case WIFI_STAT_TX_RETRANS:
3378*9485SMikore.Li@Sun.COM 	case WIFI_STAT_RTS_SUCCESS:
3379*9485SMikore.Li@Sun.COM 	case WIFI_STAT_RTS_FAILURE:
3380*9485SMikore.Li@Sun.COM 	case WIFI_STAT_ACK_FAILURE:
3381*9485SMikore.Li@Sun.COM 	case WIFI_STAT_RX_FRAGS:
3382*9485SMikore.Li@Sun.COM 	case WIFI_STAT_MCAST_RX:
3383*9485SMikore.Li@Sun.COM 	case WIFI_STAT_FCS_ERRORS:
3384*9485SMikore.Li@Sun.COM 	case WIFI_STAT_WEP_ERRORS:
3385*9485SMikore.Li@Sun.COM 	case WIFI_STAT_RX_DUPS:
3386*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3387*9485SMikore.Li@Sun.COM 		return (ieee80211_stat(ic, stat, val));
3388*9485SMikore.Li@Sun.COM 	default:
3389*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3390*9485SMikore.Li@Sun.COM 		return (ENOTSUP);
3391*9485SMikore.Li@Sun.COM 	}
3392*9485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
3393*9485SMikore.Li@Sun.COM 
3394*9485SMikore.Li@Sun.COM 	return (0);
3395*9485SMikore.Li@Sun.COM }
3396*9485SMikore.Li@Sun.COM 
3397*9485SMikore.Li@Sun.COM static void
3398*9485SMikore.Li@Sun.COM urtw_watchdog(void *arg)
3399*9485SMikore.Li@Sun.COM {
3400*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc = arg;
3401*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
3402*9485SMikore.Li@Sun.COM 
3403*9485SMikore.Li@Sun.COM 	ieee80211_stop_watchdog(ic);
3404*9485SMikore.Li@Sun.COM 
3405*9485SMikore.Li@Sun.COM 	URTW_LOCK(sc);
3406*9485SMikore.Li@Sun.COM 	if (URTW_IS_NOT_RUNNING(sc)) {
3407*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3408*9485SMikore.Li@Sun.COM 		return;
3409*9485SMikore.Li@Sun.COM 	}
3410*9485SMikore.Li@Sun.COM 
3411*9485SMikore.Li@Sun.COM 	URTW_UNLOCK(sc);
3412*9485SMikore.Li@Sun.COM 	switch (ic->ic_state) {
3413*9485SMikore.Li@Sun.COM 		case IEEE80211_S_AUTH:
3414*9485SMikore.Li@Sun.COM 		case IEEE80211_S_ASSOC:
3415*9485SMikore.Li@Sun.COM 			if (ic->ic_bss->in_fails > 0)
3416*9485SMikore.Li@Sun.COM 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3417*9485SMikore.Li@Sun.COM 			else
3418*9485SMikore.Li@Sun.COM 				ieee80211_watchdog(ic);
3419*9485SMikore.Li@Sun.COM 			break;
3420*9485SMikore.Li@Sun.COM 	}
3421*9485SMikore.Li@Sun.COM }
3422*9485SMikore.Li@Sun.COM 
3423*9485SMikore.Li@Sun.COM 
3424*9485SMikore.Li@Sun.COM static int
3425*9485SMikore.Li@Sun.COM urtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3426*9485SMikore.Li@Sun.COM {
3427*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
3428*9485SMikore.Li@Sun.COM 	struct ieee80211com *ic;
3429*9485SMikore.Li@Sun.COM 	int error, i, instance;
3430*9485SMikore.Li@Sun.COM 	uint32_t data = 0;
3431*9485SMikore.Li@Sun.COM 	char strbuf[32];
3432*9485SMikore.Li@Sun.COM 	wifi_data_t wd = { 0 };
3433*9485SMikore.Li@Sun.COM 	mac_register_t *macp;
3434*9485SMikore.Li@Sun.COM 
3435*9485SMikore.Li@Sun.COM 	switch (cmd) {
3436*9485SMikore.Li@Sun.COM 	case DDI_ATTACH:
3437*9485SMikore.Li@Sun.COM 		break;
3438*9485SMikore.Li@Sun.COM 	case DDI_RESUME:
3439*9485SMikore.Li@Sun.COM 		sc = ddi_get_soft_state(urtw_soft_state_p,
3440*9485SMikore.Li@Sun.COM 		    ddi_get_instance(devinfo));
3441*9485SMikore.Li@Sun.COM 		ASSERT(sc != NULL);
3442*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ACTIVE,
3443*9485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "urtw: resume\n"));
3444*9485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
3445*9485SMikore.Li@Sun.COM 		sc->sc_flags &= ~URTW_FLAG_SUSPEND;
3446*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3447*9485SMikore.Li@Sun.COM 		if (URTW_IS_PLUGIN_ONLINE(sc)) {
3448*9485SMikore.Li@Sun.COM 			error = urtw_init(sc);
3449*9485SMikore.Li@Sun.COM 			if (error == 0) {
3450*9485SMikore.Li@Sun.COM 				URTW_LOCK(sc);
3451*9485SMikore.Li@Sun.COM 				sc->sc_flags &= ~URTW_FLAG_PLUGIN_ONLINE;
3452*9485SMikore.Li@Sun.COM 				URTW_UNLOCK(sc);
3453*9485SMikore.Li@Sun.COM 			}
3454*9485SMikore.Li@Sun.COM 		}
3455*9485SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
3456*9485SMikore.Li@Sun.COM 	default:
3457*9485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
3458*9485SMikore.Li@Sun.COM 	}
3459*9485SMikore.Li@Sun.COM 
3460*9485SMikore.Li@Sun.COM 	instance = ddi_get_instance(devinfo);
3461*9485SMikore.Li@Sun.COM 
3462*9485SMikore.Li@Sun.COM 	if (ddi_soft_state_zalloc(urtw_soft_state_p, instance) != DDI_SUCCESS) {
3463*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach:unable to alloc soft_state_p\n");
3464*9485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
3465*9485SMikore.Li@Sun.COM 	}
3466*9485SMikore.Li@Sun.COM 
3467*9485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, instance);
3468*9485SMikore.Li@Sun.COM 	ic = (ieee80211com_t *)&sc->sc_ic;
3469*9485SMikore.Li@Sun.COM 	sc->sc_dev = devinfo;
3470*9485SMikore.Li@Sun.COM 
3471*9485SMikore.Li@Sun.COM 	if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) {
3472*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: usb_client_attach failed\n");
3473*9485SMikore.Li@Sun.COM 		goto fail1;
3474*9485SMikore.Li@Sun.COM 	}
3475*9485SMikore.Li@Sun.COM 
3476*9485SMikore.Li@Sun.COM 	if (usb_get_dev_data(devinfo, &sc->sc_udev,
3477*9485SMikore.Li@Sun.COM 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
3478*9485SMikore.Li@Sun.COM 		sc->sc_udev = NULL;
3479*9485SMikore.Li@Sun.COM 		goto fail2;
3480*9485SMikore.Li@Sun.COM 	}
3481*9485SMikore.Li@Sun.COM 
3482*9485SMikore.Li@Sun.COM 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
3483*9485SMikore.Li@Sun.COM 	mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL);
3484*9485SMikore.Li@Sun.COM 	mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL);
3485*9485SMikore.Li@Sun.COM 	mutex_init(&sc->sc_ledlock, NULL, MUTEX_DRIVER, NULL);
3486*9485SMikore.Li@Sun.COM 
3487*9485SMikore.Li@Sun.COM 	if (urtw_read32_c(sc, URTW_RX, &data))
3488*9485SMikore.Li@Sun.COM 		goto fail3;
3489*9485SMikore.Li@Sun.COM 	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
3490*9485SMikore.Li@Sun.COM 	    URTW_EEPROM_93C46;
3491*9485SMikore.Li@Sun.COM 	if (sc->sc_epromtype == URTW_EEPROM_93C56)
3492*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
3493*9485SMikore.Li@Sun.COM 		    "urtw_attach: eprom is 93C56\n"));
3494*9485SMikore.Li@Sun.COM 	else
3495*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_HWTYPE, (sc->sc_dev, CE_CONT,
3496*9485SMikore.Li@Sun.COM 		    "urtw_attach: eprom is 93C46\n"));
3497*9485SMikore.Li@Sun.COM 	error = urtw_get_rfchip(sc);
3498*9485SMikore.Li@Sun.COM 	if (error != 0)
3499*9485SMikore.Li@Sun.COM 		goto fail3;
3500*9485SMikore.Li@Sun.COM 	error = urtw_get_macaddr(sc);
3501*9485SMikore.Li@Sun.COM 	if (error != 0)
3502*9485SMikore.Li@Sun.COM 		goto fail3;
3503*9485SMikore.Li@Sun.COM 	error = urtw_get_txpwr(sc);
3504*9485SMikore.Li@Sun.COM 	if (error != 0)
3505*9485SMikore.Li@Sun.COM 		goto fail3;
3506*9485SMikore.Li@Sun.COM 	error = urtw_led_init(sc);		/* XXX incompleted  */
3507*9485SMikore.Li@Sun.COM 	if (error != 0)
3508*9485SMikore.Li@Sun.COM 		goto fail3;
3509*9485SMikore.Li@Sun.COM 
3510*9485SMikore.Li@Sun.COM 	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
3511*9485SMikore.Li@Sun.COM 	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
3512*9485SMikore.Li@Sun.COM 	sc->sc_currate = 3;
3513*9485SMikore.Li@Sun.COM 	/* XXX for what?  */
3514*9485SMikore.Li@Sun.COM 	sc->sc_preamble_mode = 2;
3515*9485SMikore.Li@Sun.COM 
3516*9485SMikore.Li@Sun.COM 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
3517*9485SMikore.Li@Sun.COM 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
3518*9485SMikore.Li@Sun.COM 	ic->ic_state = IEEE80211_S_INIT;
3519*9485SMikore.Li@Sun.COM 
3520*9485SMikore.Li@Sun.COM 	ic->ic_maxrssi = 95;
3521*9485SMikore.Li@Sun.COM 	ic->ic_xmit = urtw_send;
3522*9485SMikore.Li@Sun.COM 
3523*9485SMikore.Li@Sun.COM 	ic->ic_caps |= IEEE80211_C_WPA | /* Support WPA/WPA2 */
3524*9485SMikore.Li@Sun.COM 	    IEEE80211_C_TXPMGT |	/* tx power management */
3525*9485SMikore.Li@Sun.COM 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
3526*9485SMikore.Li@Sun.COM 	    IEEE80211_C_SHSLOT;	/* short slot time supported */
3527*9485SMikore.Li@Sun.COM 	/* set supported .11b and .11g rates */
3528*9485SMikore.Li@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11B] = urtw_rateset_11b;
3529*9485SMikore.Li@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11G] = urtw_rateset_11g;
3530*9485SMikore.Li@Sun.COM 
3531*9485SMikore.Li@Sun.COM 	/* set supported .11b and .11g channels (1 through 11) */
3532*9485SMikore.Li@Sun.COM 	for (i = 1; i <= 11; i++) {
3533*9485SMikore.Li@Sun.COM 		ic->ic_sup_channels[i].ich_freq =
3534*9485SMikore.Li@Sun.COM 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
3535*9485SMikore.Li@Sun.COM 		ic->ic_sup_channels[i].ich_flags =
3536*9485SMikore.Li@Sun.COM 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN |
3537*9485SMikore.Li@Sun.COM 		    IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM;
3538*9485SMikore.Li@Sun.COM 	}
3539*9485SMikore.Li@Sun.COM 
3540*9485SMikore.Li@Sun.COM 	ieee80211_attach(ic);
3541*9485SMikore.Li@Sun.COM 
3542*9485SMikore.Li@Sun.COM 	/* register WPA door */
3543*9485SMikore.Li@Sun.COM 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
3544*9485SMikore.Li@Sun.COM 	    ddi_get_instance(devinfo));
3545*9485SMikore.Li@Sun.COM 
3546*9485SMikore.Li@Sun.COM 	/* override state transition machine */
3547*9485SMikore.Li@Sun.COM 	sc->sc_newstate = ic->ic_newstate;
3548*9485SMikore.Li@Sun.COM 	ic->ic_newstate = urtw_newstate;
3549*9485SMikore.Li@Sun.COM 	ic->ic_watchdog = urtw_watchdog;
3550*9485SMikore.Li@Sun.COM 	ieee80211_media_init(ic);
3551*9485SMikore.Li@Sun.COM 	ic->ic_def_txkey = 0;
3552*9485SMikore.Li@Sun.COM 
3553*9485SMikore.Li@Sun.COM 	sc->dwelltime = 400;
3554*9485SMikore.Li@Sun.COM 	sc->sc_flags = 0;
3555*9485SMikore.Li@Sun.COM 
3556*9485SMikore.Li@Sun.COM 	/*
3557*9485SMikore.Li@Sun.COM 	 * Provide initial settings for the WiFi plugin; whenever this
3558*9485SMikore.Li@Sun.COM 	 * information changes, we need to call mac_plugindata_update()
3559*9485SMikore.Li@Sun.COM 	 */
3560*9485SMikore.Li@Sun.COM 	wd.wd_opmode = ic->ic_opmode;
3561*9485SMikore.Li@Sun.COM 	wd.wd_secalloc = WIFI_SEC_NONE;
3562*9485SMikore.Li@Sun.COM 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
3563*9485SMikore.Li@Sun.COM 
3564*9485SMikore.Li@Sun.COM 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
3565*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
3566*9485SMikore.Li@Sun.COM 		    "MAC version alloc failed\n"));
3567*9485SMikore.Li@Sun.COM 		goto fail4;
3568*9485SMikore.Li@Sun.COM 	}
3569*9485SMikore.Li@Sun.COM 
3570*9485SMikore.Li@Sun.COM 	macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3571*9485SMikore.Li@Sun.COM 	macp->m_driver = sc;
3572*9485SMikore.Li@Sun.COM 	macp->m_dip = devinfo;
3573*9485SMikore.Li@Sun.COM 	macp->m_src_addr = ic->ic_macaddr;
3574*9485SMikore.Li@Sun.COM 	macp->m_callbacks = &urtw_m_callbacks;
3575*9485SMikore.Li@Sun.COM 	macp->m_min_sdu	= 0;
3576*9485SMikore.Li@Sun.COM 	macp->m_max_sdu	= IEEE80211_MTU;
3577*9485SMikore.Li@Sun.COM 	macp->m_pdata = &wd;
3578*9485SMikore.Li@Sun.COM 	macp->m_pdata_size = sizeof (wd);
3579*9485SMikore.Li@Sun.COM 
3580*9485SMikore.Li@Sun.COM 	error = mac_register(macp, &ic->ic_mach);
3581*9485SMikore.Li@Sun.COM 	mac_free(macp);
3582*9485SMikore.Li@Sun.COM 	if (error != 0) {
3583*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: mac_register() err %x\n", error);
3584*9485SMikore.Li@Sun.COM 		goto fail4;
3585*9485SMikore.Li@Sun.COM 	}
3586*9485SMikore.Li@Sun.COM 
3587*9485SMikore.Li@Sun.COM 	if (usb_register_hotplug_cbs(devinfo, urtw_disconnect,
3588*9485SMikore.Li@Sun.COM 	    urtw_reconnect) != USB_SUCCESS) {
3589*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw_attach: failed to register events");
3590*9485SMikore.Li@Sun.COM 		goto fail5;
3591*9485SMikore.Li@Sun.COM 	}
3592*9485SMikore.Li@Sun.COM 
3593*9485SMikore.Li@Sun.COM 	/*
3594*9485SMikore.Li@Sun.COM 	 * Create minor node of type DDI_NT_NET_WIFI
3595*9485SMikore.Li@Sun.COM 	 */
3596*9485SMikore.Li@Sun.COM 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
3597*9485SMikore.Li@Sun.COM 	    "urtw", instance);
3598*9485SMikore.Li@Sun.COM 	error = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
3599*9485SMikore.Li@Sun.COM 	    instance + 1, DDI_NT_NET_WIFI, 0);
3600*9485SMikore.Li@Sun.COM 
3601*9485SMikore.Li@Sun.COM 	if (error != DDI_SUCCESS)
3602*9485SMikore.Li@Sun.COM 		cmn_err(CE_WARN, "urtw: ddi_create_minor_node() failed\n");
3603*9485SMikore.Li@Sun.COM 
3604*9485SMikore.Li@Sun.COM 	/*
3605*9485SMikore.Li@Sun.COM 	 * Notify link is down now
3606*9485SMikore.Li@Sun.COM 	 */
3607*9485SMikore.Li@Sun.COM 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
3608*9485SMikore.Li@Sun.COM 
3609*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev, CE_CONT,
3610*9485SMikore.Li@Sun.COM 	    "urtw_attach: successfully.\n"));
3611*9485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
3612*9485SMikore.Li@Sun.COM fail5:
3613*9485SMikore.Li@Sun.COM 	(void) mac_unregister(ic->ic_mach);
3614*9485SMikore.Li@Sun.COM fail4:
3615*9485SMikore.Li@Sun.COM 	ieee80211_detach(ic);
3616*9485SMikore.Li@Sun.COM fail3:
3617*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_genlock);
3618*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->tx_lock);
3619*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->rx_lock);
3620*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_ledlock);
3621*9485SMikore.Li@Sun.COM fail2:
3622*9485SMikore.Li@Sun.COM 	usb_client_detach(sc->sc_dev, sc->sc_udev);
3623*9485SMikore.Li@Sun.COM fail1:
3624*9485SMikore.Li@Sun.COM 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
3625*9485SMikore.Li@Sun.COM 
3626*9485SMikore.Li@Sun.COM 	return (DDI_FAILURE);
3627*9485SMikore.Li@Sun.COM }
3628*9485SMikore.Li@Sun.COM 
3629*9485SMikore.Li@Sun.COM static int
3630*9485SMikore.Li@Sun.COM urtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
3631*9485SMikore.Li@Sun.COM {
3632*9485SMikore.Li@Sun.COM 	struct urtw_softc *sc;
3633*9485SMikore.Li@Sun.COM 
3634*9485SMikore.Li@Sun.COM 	sc = ddi_get_soft_state(urtw_soft_state_p, ddi_get_instance(devinfo));
3635*9485SMikore.Li@Sun.COM 	URTW8187_DBG(URTW_DEBUG_ATTACH, (sc->sc_dev,
3636*9485SMikore.Li@Sun.COM 	    CE_CONT, "urtw_detach()\n"));
3637*9485SMikore.Li@Sun.COM 
3638*9485SMikore.Li@Sun.COM 	switch (cmd) {
3639*9485SMikore.Li@Sun.COM 	case DDI_DETACH:
3640*9485SMikore.Li@Sun.COM 		break;
3641*9485SMikore.Li@Sun.COM 	case DDI_SUSPEND:
3642*9485SMikore.Li@Sun.COM 		URTW8187_DBG(URTW_DEBUG_ATTACH,
3643*9485SMikore.Li@Sun.COM 		    (sc->sc_dev, CE_CONT, "urtw: suspend\n"));
3644*9485SMikore.Li@Sun.COM 
3645*9485SMikore.Li@Sun.COM 		ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3646*9485SMikore.Li@Sun.COM 		ieee80211_stop_watchdog(&sc->sc_ic);
3647*9485SMikore.Li@Sun.COM 
3648*9485SMikore.Li@Sun.COM 		URTW_LOCK(sc);
3649*9485SMikore.Li@Sun.COM 		sc->sc_flags |= URTW_FLAG_SUSPEND;
3650*9485SMikore.Li@Sun.COM 		URTW_UNLOCK(sc);
3651*9485SMikore.Li@Sun.COM 		if (URTW_IS_RUNNING(sc)) {
3652*9485SMikore.Li@Sun.COM 			urtw_stop(sc);
3653*9485SMikore.Li@Sun.COM 			URTW_LOCK(sc);
3654*9485SMikore.Li@Sun.COM 			sc->sc_flags |= URTW_FLAG_PLUGIN_ONLINE;
3655*9485SMikore.Li@Sun.COM 			URTW_UNLOCK(sc);
3656*9485SMikore.Li@Sun.COM 		}
3657*9485SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
3658*9485SMikore.Li@Sun.COM 	default:
3659*9485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
3660*9485SMikore.Li@Sun.COM 	}
3661*9485SMikore.Li@Sun.COM 
3662*9485SMikore.Li@Sun.COM 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
3663*9485SMikore.Li@Sun.COM 		return (DDI_FAILURE);
3664*9485SMikore.Li@Sun.COM 	urtw_stop(sc);
3665*9485SMikore.Li@Sun.COM 	/*
3666*9485SMikore.Li@Sun.COM 	 * Unregister from the MAC layer subsystem
3667*9485SMikore.Li@Sun.COM 	 */
3668*9485SMikore.Li@Sun.COM 	(void) mac_unregister(sc->sc_ic.ic_mach);
3669*9485SMikore.Li@Sun.COM 
3670*9485SMikore.Li@Sun.COM 	ieee80211_detach(&sc->sc_ic);
3671*9485SMikore.Li@Sun.COM 	usb_unregister_hotplug_cbs(devinfo);
3672*9485SMikore.Li@Sun.COM 	usb_client_detach(devinfo, sc->sc_udev);
3673*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_genlock);
3674*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->tx_lock);
3675*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->rx_lock);
3676*9485SMikore.Li@Sun.COM 	mutex_destroy(&sc->sc_ledlock);
3677*9485SMikore.Li@Sun.COM 	sc->sc_udev = NULL;
3678*9485SMikore.Li@Sun.COM 
3679*9485SMikore.Li@Sun.COM 	ddi_remove_minor_node(devinfo, NULL);
3680*9485SMikore.Li@Sun.COM 	ddi_soft_state_free(urtw_soft_state_p, ddi_get_instance(devinfo));
3681*9485SMikore.Li@Sun.COM 
3682*9485SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
3683*9485SMikore.Li@Sun.COM }
3684*9485SMikore.Li@Sun.COM 
3685*9485SMikore.Li@Sun.COM int
3686*9485SMikore.Li@Sun.COM _info(struct modinfo *modinfop)
3687*9485SMikore.Li@Sun.COM {
3688*9485SMikore.Li@Sun.COM 	return (mod_info(&modlinkage, modinfop));
3689*9485SMikore.Li@Sun.COM }
3690*9485SMikore.Li@Sun.COM 
3691*9485SMikore.Li@Sun.COM int
3692*9485SMikore.Li@Sun.COM _init(void)
3693*9485SMikore.Li@Sun.COM {
3694*9485SMikore.Li@Sun.COM 	int status;
3695*9485SMikore.Li@Sun.COM 
3696*9485SMikore.Li@Sun.COM 	status = ddi_soft_state_init(&urtw_soft_state_p,
3697*9485SMikore.Li@Sun.COM 	    sizeof (struct urtw_softc), 1);
3698*9485SMikore.Li@Sun.COM 	if (status != 0)
3699*9485SMikore.Li@Sun.COM 		return (status);
3700*9485SMikore.Li@Sun.COM 
3701*9485SMikore.Li@Sun.COM 	mac_init_ops(&urtw_dev_ops, "urtw");
3702*9485SMikore.Li@Sun.COM 	status = mod_install(&modlinkage);
3703*9485SMikore.Li@Sun.COM 	if (status != 0) {
3704*9485SMikore.Li@Sun.COM 		mac_fini_ops(&urtw_dev_ops);
3705*9485SMikore.Li@Sun.COM 		ddi_soft_state_fini(&urtw_soft_state_p);
3706*9485SMikore.Li@Sun.COM 	}
3707*9485SMikore.Li@Sun.COM 	return (status);
3708*9485SMikore.Li@Sun.COM }
3709*9485SMikore.Li@Sun.COM 
3710*9485SMikore.Li@Sun.COM int
3711*9485SMikore.Li@Sun.COM _fini(void)
3712*9485SMikore.Li@Sun.COM {
3713*9485SMikore.Li@Sun.COM 	int status;
3714*9485SMikore.Li@Sun.COM 
3715*9485SMikore.Li@Sun.COM 	status = mod_remove(&modlinkage);
3716*9485SMikore.Li@Sun.COM 	if (status == 0) {
3717*9485SMikore.Li@Sun.COM 		mac_fini_ops(&urtw_dev_ops);
3718*9485SMikore.Li@Sun.COM 		ddi_soft_state_fini(&urtw_soft_state_p);
3719*9485SMikore.Li@Sun.COM 	}
3720*9485SMikore.Li@Sun.COM 	return (status);
3721*9485SMikore.Li@Sun.COM }
3722