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