if_urtw.c revision 257743
168651Skris/*-
268651Skris * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
3238405Sjkim *
4238405Sjkim * Permission to use, copy, modify, and distribute this software for any
5238405Sjkim * purpose with or without fee is hereby granted, provided that the above
6238405Sjkim * copyright notice and this permission notice appear in all copies.
768651Skris *
868651Skris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
968651Skris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1068651Skris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1168651Skris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1268651Skris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1368651Skris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1468651Skris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1568651Skris */
1668651Skris
1768651Skris#include <sys/cdefs.h>
18109998Smarkm__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_urtw.c 257743 2013-11-06 12:57:01Z hselasky $");
1968651Skris#include <sys/param.h>
2068651Skris#include <sys/sockio.h>
2168651Skris#include <sys/sysctl.h>
2268651Skris#include <sys/lock.h>
2368651Skris#include <sys/mutex.h>
2468651Skris#include <sys/mbuf.h>
25109998Smarkm#include <sys/kernel.h>
2668651Skris#include <sys/socket.h>
2768651Skris#include <sys/systm.h>
28109998Smarkm#include <sys/malloc.h>
2968651Skris#include <sys/module.h>
30109998Smarkm#include <sys/bus.h>
3168651Skris#include <sys/endian.h>
3268651Skris#include <sys/kdb.h>
33109998Smarkm
3468651Skris#include <machine/bus.h>
3568651Skris#include <machine/resource.h>
36109998Smarkm#include <sys/rman.h>
3768651Skris
38109998Smarkm#include <net/if.h>
39109998Smarkm#include <net/if_var.h>
4068651Skris#include <net/if_arp.h>
4168651Skris#include <net/ethernet.h>
4268651Skris#include <net/if_dl.h>
4368651Skris#include <net/if_media.h>
4468651Skris#include <net/if_types.h>
4568651Skris
4668651Skris#ifdef INET
4768651Skris#include <netinet/in.h>
4868651Skris#include <netinet/in_systm.h>
4968651Skris#include <netinet/in_var.h>
5068651Skris#include <netinet/if_ether.h>
5168651Skris#include <netinet/ip.h>
5268651Skris#endif
5368651Skris
5468651Skris#include <net80211/ieee80211_var.h>
55109998Smarkm#include <net80211/ieee80211_regdomain.h>
5668651Skris#include <net80211/ieee80211_radiotap.h>
57109998Smarkm
58109998Smarkm#include <dev/usb/usb.h>
5968651Skris#include <dev/usb/usbdi.h>
6068651Skris#include "usbdevs.h"
6168651Skris
6268651Skris#include <dev/usb/wlan/if_urtwreg.h>
6368651Skris#include <dev/usb/wlan/if_urtwvar.h>
6468651Skris
6568651Skrisstatic SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L");
6668651Skris#ifdef URTW_DEBUG
6768651Skrisint urtw_debug = 0;
6868651SkrisSYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &urtw_debug, 0,
6968651Skris    "control debugging printfs");
7068651SkrisTUNABLE_INT("hw.usb.urtw.debug", &urtw_debug);
7168651Skrisenum {
7268651Skris	URTW_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
7368651Skris	URTW_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
7468651Skris	URTW_DEBUG_RESET	= 0x00000004,	/* reset processing */
7568651Skris	URTW_DEBUG_TX_PROC	= 0x00000008,	/* tx ISR proc */
7668651Skris	URTW_DEBUG_RX_PROC	= 0x00000010,	/* rx ISR proc */
7768651Skris	URTW_DEBUG_STATE	= 0x00000020,	/* 802.11 state transitions */
78238405Sjkim	URTW_DEBUG_STAT		= 0x00000040,	/* statistic */
79238405Sjkim	URTW_DEBUG_INIT		= 0x00000080,	/* initialization of dev */
8068651Skris	URTW_DEBUG_TXSTATUS	= 0x00000100,	/* tx status */
8168651Skris	URTW_DEBUG_ANY		= 0xffffffff
8268651Skris};
8368651Skris#define	DPRINTF(sc, m, fmt, ...) do {				\
8468651Skris	if (sc->sc_debug & (m))					\
8568651Skris		printf(fmt, __VA_ARGS__);			\
8668651Skris} while (0)
8768651Skris#else
8868651Skris#define	DPRINTF(sc, m, fmt, ...) do {				\
89238405Sjkim	(void) sc;						\
9068651Skris} while (0)
9168651Skris#endif
9268651Skrisstatic int urtw_preamble_mode = URTW_PREAMBLE_MODE_LONG;
9368651SkrisSYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW | CTLFLAG_TUN,
9468651Skris    &urtw_preamble_mode, 0, "set the preable mode (long or short)");
95109998SmarkmTUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode);
9668651Skris
9768651Skris/* recognized device vendors/products */
9868651Skris#define urtw_lookup(v, p)						\
9968651Skris	((const struct urtw_type *)usb_lookup(urtw_devs, v, p))
10068651Skris#define	URTW_DEV_B(v,p)							\
10168651Skris	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187B) }
10268651Skris#define	URTW_DEV_L(v,p)							\
10368651Skris	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) }
10468651Skris#define	URTW_REV_RTL8187B	0
10568651Skris#define	URTW_REV_RTL8187L	1
10668651Skrisstatic const STRUCT_USB_HOST_ID urtw_devs[] = {
10768651Skris	URTW_DEV_B(NETGEAR, WG111V3),
10868651Skris	URTW_DEV_B(REALTEK, RTL8187B_0),
10968651Skris	URTW_DEV_B(REALTEK, RTL8187B_1),
11068651Skris	URTW_DEV_B(REALTEK, RTL8187B_2),
11168651Skris	URTW_DEV_B(SITECOMEU, WL168V4),
11268651Skris	URTW_DEV_L(ASUS, P5B_WIFI),
11368651Skris	URTW_DEV_L(BELKIN, F5D7050E),
11468651Skris	URTW_DEV_L(LINKSYS4, WUSB54GCV2),
11568651Skris	URTW_DEV_L(NETGEAR, WG111V2),
11668651Skris	URTW_DEV_L(REALTEK, RTL8187),
11768651Skris	URTW_DEV_L(SITECOMEU, WL168V1),
11868651Skris	URTW_DEV_L(SURECOM, EP9001G2A),
11968651Skris	{ USB_VPI(USB_VENDOR_OVISLINK, 0x8187, URTW_REV_RTL8187L) },
12068651Skris	{ USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) },
12168651Skris	{ USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) },
12268651Skris	{ USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) },
12368651Skris	{ USB_VPI(USB_VENDOR_NETGEAR, 0x6100, URTW_REV_RTL8187L) },
12468651Skris	{ USB_VPI(USB_VENDOR_SPHAIRON, 0x0150, URTW_REV_RTL8187L) },
12568651Skris	{ USB_VPI(USB_VENDOR_QCOM, 0x6232, URTW_REV_RTL8187L) },
126160814Ssimon#undef URTW_DEV_L
12768651Skris#undef URTW_DEV_B
12868651Skris};
129160814Ssimon
13068651Skris#define urtw_read8_m(sc, val, data)	do {			\
13168651Skris	error = urtw_read8_c(sc, val, data);			\
13268651Skris	if (error != 0)						\
133109998Smarkm		goto fail;					\
13468651Skris} while (0)
13568651Skris#define urtw_write8_m(sc, val, data)	do {			\
13668651Skris	error = urtw_write8_c(sc, val, data);			\
13768651Skris	if (error != 0)						\
13868651Skris		goto fail;					\
13968651Skris} while (0)
14068651Skris#define urtw_read16_m(sc, val, data)	do {			\
14168651Skris	error = urtw_read16_c(sc, val, data);			\
14268651Skris	if (error != 0)						\
14368651Skris		goto fail;					\
14468651Skris} while (0)
14568651Skris#define urtw_write16_m(sc, val, data)	do {			\
14668651Skris	error = urtw_write16_c(sc, val, data);			\
14768651Skris	if (error != 0)						\
14868651Skris		goto fail;					\
14968651Skris} while (0)
15068651Skris#define urtw_read32_m(sc, val, data)	do {			\
15168651Skris	error = urtw_read32_c(sc, val, data);			\
15268651Skris	if (error != 0)						\
15368651Skris		goto fail;					\
15468651Skris} while (0)
15568651Skris#define urtw_write32_m(sc, val, data)	do {			\
15668651Skris	error = urtw_write32_c(sc, val, data);			\
15768651Skris	if (error != 0)						\
15868651Skris		goto fail;					\
15968651Skris} while (0)
16068651Skris#define urtw_8187_write_phy_ofdm(sc, val, data)	do {		\
16168651Skris	error = urtw_8187_write_phy_ofdm_c(sc, val, data);	\
16268651Skris	if (error != 0)						\
16368651Skris		goto fail;					\
16468651Skris} while (0)
16568651Skris#define urtw_8187_write_phy_cck(sc, val, data)	do {		\
16668651Skris	error = urtw_8187_write_phy_cck_c(sc, val, data);	\
16768651Skris	if (error != 0)						\
16868651Skris		goto fail;					\
16968651Skris} while (0)
17068651Skris#define urtw_8225_write(sc, val, data)	do {			\
17168651Skris	error = urtw_8225_write_c(sc, val, data);		\
17268651Skris	if (error != 0)						\
17368651Skris		goto fail;					\
17468651Skris} while (0)
175238405Sjkim
17668651Skrisstruct urtw_pair {
17768651Skris	uint32_t	reg;
17868651Skris	uint32_t	val;
17968651Skris};
18068651Skris
18168651Skrisstatic uint8_t urtw_8225_agc[] = {
18268651Skris	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
18368651Skris	0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
18468651Skris	0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
18568651Skris	0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
18668651Skris	0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
18768651Skris	0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
188238405Sjkim	0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
18968651Skris	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
19068651Skris	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
191238405Sjkim	0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
19268651Skris	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
19368651Skris	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
19468651Skris};
19568651Skris
196160814Ssimonstatic uint8_t urtw_8225z2_agc[] = {
19768651Skris	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51,
19868651Skris	0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b,
199109998Smarkm	0x39, 0x37, 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25,
200109998Smarkm	0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f,
20168651Skris	0x0d, 0x0b, 0x09, 0x07, 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
20268651Skris	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x19,
203160814Ssimon	0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x20, 0x21, 0x22, 0x23,
20468651Skris	0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
20568651Skris	0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
206109998Smarkm	0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31,
20768651Skris	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
20868651Skris	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
20968651Skris};
21068651Skris
21168651Skrisstatic uint32_t urtw_8225_channel[] = {
212109998Smarkm	0x0000,		/* dummy channel 0  */
21368651Skris	0x085c,		/* 1  */
21468651Skris	0x08dc,		/* 2  */
21568651Skris	0x095c,		/* 3  */
21668651Skris	0x09dc,		/* 4  */
21768651Skris	0x0a5c,		/* 5  */
218109998Smarkm	0x0adc,		/* 6  */
21968651Skris	0x0b5c,		/* 7  */
22068651Skris	0x0bdc,		/* 8  */
22168651Skris	0x0c5c,		/* 9  */
222109998Smarkm	0x0cdc,		/* 10  */
22368651Skris	0x0d5c,		/* 11  */
22468651Skris	0x0ddc,		/* 12  */
22568651Skris	0x0e5c,		/* 13  */
22668651Skris	0x0f72,		/* 14  */
22768651Skris};
22868651Skris
22968651Skrisstatic uint8_t urtw_8225_gain[] = {
23068651Skris	0x23, 0x88, 0x7c, 0xa5,		/* -82dbm  */
23168651Skris	0x23, 0x88, 0x7c, 0xb5,		/* -82dbm  */
23268651Skris	0x23, 0x88, 0x7c, 0xc5,		/* -82dbm  */
23368651Skris	0x33, 0x80, 0x79, 0xc5,		/* -78dbm  */
23468651Skris	0x43, 0x78, 0x76, 0xc5,		/* -74dbm  */
23568651Skris	0x53, 0x60, 0x73, 0xc5,		/* -70dbm  */
23668651Skris	0x63, 0x58, 0x70, 0xc5,		/* -66dbm  */
23768651Skris};
23868651Skris
23968651Skrisstatic struct urtw_pair urtw_8225_rf_part1[] = {
24068651Skris	{ 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
24168651Skris	{ 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
242109998Smarkm	{ 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
24368651Skris	{ 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
24468651Skris};
24568651Skris
246238405Sjkimstatic struct urtw_pair urtw_8225_rf_part2[] = {
24768651Skris	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
24868651Skris	{ 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
24968651Skris	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
25068651Skris	{ 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
25168651Skris	{ 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
25268651Skris	{ 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
25368651Skris	{ 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
25468651Skris	{ 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
25568651Skris	{ 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
25668651Skris	{ 0x27, 0x88 }
25768651Skris};
25868651Skris
25968651Skrisstatic struct urtw_pair urtw_8225_rf_part3[] = {
26068651Skris	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
26168651Skris	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
26268651Skris	{ 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
26368651Skris	{ 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
26468651Skris	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
26568651Skris	{ 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
26668651Skris	{ 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
26768651Skris};
26868651Skris
26968651Skrisstatic uint16_t urtw_8225_rxgain[] = {
27068651Skris	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
27168651Skris	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
27268651Skris	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
27368651Skris	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
27468651Skris	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
27568651Skris	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
27668651Skris	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
27768651Skris	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
27868651Skris	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
27968651Skris	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
28068651Skris	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
28168651Skris	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
28268651Skris};
28368651Skris
28468651Skrisstatic uint8_t urtw_8225_threshold[] = {
28568651Skris	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
28668651Skris};
287142425Snectar
28868651Skrisstatic uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
28968651Skris	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
29068651Skris};
29168651Skris
292142425Snectarstatic uint8_t urtw_8225_txpwr_cck[] = {
29368651Skris	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
29468651Skris	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
29568651Skris	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
29668651Skris	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
297142425Snectar	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
29868651Skris	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
29968651Skris};
300142425Snectar
30168651Skrisstatic uint8_t urtw_8225_txpwr_cck_ch14[] = {
30268651Skris	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
30368651Skris	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
304109998Smarkm	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
305109998Smarkm	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
30668651Skris	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
30768651Skris	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
30868651Skris};
30968651Skris
31068651Skrisstatic uint8_t urtw_8225_txpwr_ofdm[]={
311142425Snectar	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
31268651Skris};
31368651Skris
31468651Skrisstatic uint8_t urtw_8225v2_gain_bg[]={
31568651Skris	0x23, 0x15, 0xa5,		/* -82-1dbm  */
31668651Skris	0x23, 0x15, 0xb5,		/* -82-2dbm  */
31768651Skris	0x23, 0x15, 0xc5,		/* -82-3dbm  */
318142425Snectar	0x33, 0x15, 0xc5,		/* -78dbm  */
31968651Skris	0x43, 0x15, 0xc5,		/* -74dbm  */
32068651Skris	0x53, 0x15, 0xc5,		/* -70dbm  */
32168651Skris	0x63, 0x15, 0xc5,		/* -66dbm  */
32268651Skris};
32368651Skris
32468651Skrisstatic struct urtw_pair urtw_8225v2_rf_part1[] = {
32568651Skris	{ 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
32668651Skris	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
32768651Skris	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
32868651Skris	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
32968651Skris};
33068651Skris
33168651Skrisstatic struct urtw_pair urtw_8225v2b_rf_part0[] = {
33268651Skris	{ 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
33368651Skris	{ 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
33468651Skris	{ 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
33568651Skris	{ 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
33668651Skris};
33768651Skris
33868651Skrisstatic struct urtw_pair urtw_8225v2b_rf_part1[] = {
33968651Skris	{0x0f0, 0x32}, {0x0f1, 0x32}, {0x0f2, 0x00},
34068651Skris	{0x0f3, 0x00}, {0x0f4, 0x32}, {0x0f5, 0x43},
34168651Skris	{0x0f6, 0x00}, {0x0f7, 0x00}, {0x0f8, 0x46},
34268651Skris	{0x0f9, 0xa4}, {0x0fa, 0x00}, {0x0fb, 0x00},
343109998Smarkm	{0x0fc, 0x96}, {0x0fd, 0xa4}, {0x0fe, 0x00},
344109998Smarkm	{0x0ff, 0x00}, {0x158, 0x4b}, {0x159, 0x00},
34568651Skris	{0x15a, 0x4b}, {0x15b, 0x00}, {0x160, 0x4b},
346238405Sjkim	{0x161, 0x09}, {0x162, 0x4b}, {0x163, 0x09},
34768651Skris	{0x1ce, 0x0f}, {0x1cf, 0x00}, {0x1e0, 0xff},
34868651Skris	{0x1e1, 0x0f}, {0x1e2, 0x00}, {0x1f0, 0x4e},
34968651Skris	{0x1f1, 0x01}, {0x1f2, 0x02}, {0x1f3, 0x03},
35068651Skris	{0x1f4, 0x04}, {0x1f5, 0x05}, {0x1f6, 0x06},
35168651Skris	{0x1f7, 0x07}, {0x1f8, 0x08}, {0x24e, 0x00},
35268651Skris	{0x20c, 0x04}, {0x221, 0x61}, {0x222, 0x68},
35368651Skris	{0x223, 0x6f}, {0x224, 0x76}, {0x225, 0x7d},
35468651Skris	{0x226, 0x84}, {0x227, 0x8d}, {0x24d, 0x08},
35568651Skris	{0x250, 0x05}, {0x251, 0xf5}, {0x252, 0x04},
35668651Skris	{0x253, 0xa0}, {0x254, 0x1f}, {0x255, 0x23},
35768651Skris	{0x256, 0x45}, {0x257, 0x67}, {0x258, 0x08},
35868651Skris	{0x259, 0x08}, {0x25a, 0x08}, {0x25b, 0x08},
359238405Sjkim	{0x260, 0x08}, {0x261, 0x08}, {0x262, 0x08},
360109998Smarkm	{0x263, 0x08}, {0x264, 0xcf}, {0x272, 0x56},
361238405Sjkim	{0x273, 0x9a}, {0x034, 0xf0}, {0x035, 0x0f},
362109998Smarkm	{0x05b, 0x40}, {0x084, 0x88}, {0x085, 0x24},
36368651Skris	{0x088, 0x54}, {0x08b, 0xb8}, {0x08c, 0x07},
36468651Skris	{0x08d, 0x00}, {0x094, 0x1b}, {0x095, 0x12},
36568651Skris	{0x096, 0x00}, {0x097, 0x06}, {0x09d, 0x1a},
36668651Skris	{0x09f, 0x10}, {0x0b4, 0x22}, {0x0be, 0x80},
36768651Skris	{0x0db, 0x00}, {0x0ee, 0x00}, {0x091, 0x03},
36868651Skris	{0x24c, 0x00}, {0x39f, 0x00}, {0x08c, 0x01},
369238405Sjkim	{0x08d, 0x10}, {0x08e, 0x08}, {0x08f, 0x00}
370109998Smarkm};
371109998Smarkm
37268651Skrisstatic struct urtw_pair urtw_8225v2_rf_part2[] = {
37368651Skris	{ 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
37468651Skris	{ 0x04, 0x00 },	{ 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
37568651Skris	{ 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
376238405Sjkim	{ 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
37768651Skris	{ 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
37868651Skris	{ 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
37968651Skris	{ 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
38068651Skris	{ 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
38168651Skris	{ 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
38268651Skris	{ 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
38368651Skris};
38468651Skris
38568651Skrisstatic struct urtw_pair urtw_8225v2b_rf_part2[] = {
386109998Smarkm	{ 0x00, 0x10 }, { 0x01, 0x0d }, { 0x02, 0x01 }, { 0x03, 0x00 },
38768651Skris	{ 0x04, 0x14 }, { 0x05, 0xfb }, { 0x06, 0xfb }, { 0x07, 0x60 },
38868651Skris	{ 0x08, 0x00 }, { 0x09, 0x60 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
38968651Skris	{ 0x0c, 0x00 }, { 0x0d, 0x5c }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
39068651Skris	{ 0x10, 0x40 }, { 0x11, 0x00 }, { 0x12, 0x40 }, { 0x13, 0x00 },
39168651Skris	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0xa8 }, { 0x17, 0x26 },
39268651Skris	{ 0x18, 0x32 }, { 0x19, 0x33 }, { 0x1a, 0x07 }, { 0x1b, 0xa5 },
39368651Skris	{ 0x1c, 0x6f }, { 0x1d, 0x55 }, { 0x1e, 0xc8 }, { 0x1f, 0xb3 },
39468651Skris	{ 0x20, 0x0a }, { 0x21, 0xe1 }, { 0x22, 0x2C }, { 0x23, 0x8a },
39568651Skris	{ 0x24, 0x86 }, { 0x25, 0x83 }, { 0x26, 0x34 }, { 0x27, 0x0f },
396238405Sjkim	{ 0x28, 0x4f }, { 0x29, 0x24 }, { 0x2a, 0x6f }, { 0x2b, 0xc2 },
39768651Skris	{ 0x2c, 0x6b }, { 0x2d, 0x40 }, { 0x2e, 0x80 }, { 0x2f, 0x00 },
39868651Skris	{ 0x30, 0xc0 }, { 0x31, 0xc1 }, { 0x32, 0x58 }, { 0x33, 0xf1 },
39968651Skris	{ 0x34, 0x00 }, { 0x35, 0xe4 }, { 0x36, 0x90 }, { 0x37, 0x3e },
40068651Skris	{ 0x38, 0x6d }, { 0x39, 0x3c }, { 0x3a, 0xfb }, { 0x3b, 0x07 }
40168651Skris};
40268651Skris
40368651Skrisstatic struct urtw_pair urtw_8225v2_rf_part3[] = {
40468651Skris	{ 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
40568651Skris	{ 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
406109998Smarkm	{ 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
40768651Skris	{ 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
40868651Skris	{ 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
40968651Skris	{ 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
41068651Skris	{ 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
41168651Skris	{ 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
41268651Skris};
41368651Skris
41468651Skrisstatic uint16_t urtw_8225v2_rxgain[] = {
41568651Skris	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
41668651Skris	0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
41768651Skris	0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
41868651Skris	0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
41968651Skris	0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
42068651Skris	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
42168651Skris	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
42268651Skris	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
42368651Skris	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
42468651Skris	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
42568651Skris	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
42668651Skris	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
42768651Skris};
42868651Skris
42968651Skrisstatic uint16_t urtw_8225v2b_rxgain[] = {
43068651Skris	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
43168651Skris	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
43268651Skris	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
43368651Skris	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
43468651Skris	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
43568651Skris	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
43668651Skris	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
43768651Skris	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
43868651Skris	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
43968651Skris	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
44068651Skris	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
44168651Skris	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
44268651Skris};
44368651Skris
44468651Skrisstatic uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
44568651Skris	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
44668651Skris	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
44768651Skris	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
44868651Skris	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
44968651Skris	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
45068651Skris	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
45168651Skris};
45268651Skris
45368651Skrisstatic uint8_t urtw_8225v2_txpwr_cck[] = {
45468651Skris	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
45568651Skris};
45668651Skris
45768651Skrisstatic uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
45868651Skris	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
45968651Skris};
460109998Smarkm
46168651Skrisstatic uint8_t urtw_8225v2b_txpwr_cck[] = {
46268651Skris	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
46368651Skris	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
46468651Skris	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
46568651Skris	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
46668651Skris};
46768651Skris
46868651Skrisstatic uint8_t urtw_8225v2b_txpwr_cck_ch14[] = {
46968651Skris	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
47068651Skris	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
47168651Skris	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
472238405Sjkim	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
47368651Skris};
47468651Skris
47568651Skrisstatic struct urtw_pair urtw_ratetable[] = {
47668651Skris	{  2,  0 }, {   4,  1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
477160814Ssimon	{ 22,  3 }, {  24,  6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
47868651Skris	{ 96, 10 }, { 108, 11 }
47968651Skris};
480109998Smarkm
48189837Skrisstatic const uint8_t urtw_8187b_reg_table[][3] = {
48268651Skris	{ 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
48368651Skris	{ 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
48468651Skris	{ 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
48568651Skris	{ 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
48668651Skris	{ 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
48768651Skris	{ 0xff, 0x00, 0 }, { 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 },
48868651Skris	{ 0x5a, 0x4b, 1 }, { 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 },
48968651Skris	{ 0x61, 0x09, 1 }, { 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 },
49068651Skris	{ 0xce, 0x0f, 1 }, { 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 },
49168651Skris	{ 0xe1, 0x0f, 1 }, { 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 },
492109998Smarkm	{ 0xf1, 0x01, 1 }, { 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 },
493109998Smarkm	{ 0xf4, 0x04, 1 }, { 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 },
494109998Smarkm	{ 0xf7, 0x07, 1 }, { 0xf8, 0x08, 1 }, { 0x4e, 0x00, 2 },
495109998Smarkm	{ 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 }, { 0x22, 0x68, 2 },
496109998Smarkm	{ 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 }, { 0x25, 0x7d, 2 },
497109998Smarkm	{ 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 }, { 0x4d, 0x08, 2 },
498109998Smarkm	{ 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 }, { 0x52, 0x04, 2 },
499109998Smarkm	{ 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 }, { 0x55, 0x23, 2 },
500109998Smarkm	{ 0x56, 0x45, 2 }, { 0x57, 0x67, 2 }, { 0x58, 0x08, 2 },
50168651Skris	{ 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 }, { 0x5b, 0x08, 2 },
50268651Skris	{ 0x60, 0x08, 2 }, { 0x61, 0x08, 2 }, { 0x62, 0x08, 2 },
50368651Skris	{ 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 }, { 0x72, 0x56, 2 },
50468651Skris	{ 0x73, 0x9a, 2 }, { 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 },
50568651Skris	{ 0x5b, 0x40, 0 }, { 0x84, 0x88, 0 }, { 0x85, 0x24, 0 },
50668651Skris	{ 0x88, 0x54, 0 }, { 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 },
507109998Smarkm	{ 0x8d, 0x00, 0 }, { 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 },
508109998Smarkm	{ 0x96, 0x00, 0 }, { 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 },
50968651Skris	{ 0x9f, 0x10, 0 }, { 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 },
51068651Skris	{ 0xdb, 0x00, 0 }, { 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
51168651Skris	{ 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
51268651Skris	{ 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
51368651Skris};
51468651Skris
51568651Skrisstatic usb_callback_t urtw_bulk_rx_callback;
51668651Skrisstatic usb_callback_t urtw_bulk_tx_callback;
51768651Skrisstatic usb_callback_t urtw_bulk_tx_status_callback;
51868651Skris
51968651Skrisstatic const struct usb_config urtw_8187b_usbconfig[URTW_8187B_N_XFERS] = {
52068651Skris	[URTW_8187B_BULK_RX] = {
52168651Skris		.type = UE_BULK,
52268651Skris		.endpoint = 0x83,
52368651Skris		.direction = UE_DIR_IN,
52468651Skris		.bufsize = MCLBYTES,
52568651Skris		.flags = {
52668651Skris			.ext_buffer = 1,
52768651Skris			.pipe_bof = 1,
528109998Smarkm			.short_xfer_ok = 1
529109998Smarkm		},
53068651Skris		.callback = urtw_bulk_rx_callback
53168651Skris	},
53268651Skris	[URTW_8187B_BULK_TX_STATUS] = {
53368651Skris		.type = UE_BULK,
53468651Skris		.endpoint = 0x89,
53568651Skris		.direction = UE_DIR_IN,
53668651Skris		.bufsize = sizeof(uint64_t),
53768651Skris		.flags = {
53868651Skris			.pipe_bof = 1,
53968651Skris			.short_xfer_ok = 1
54068651Skris		},
541109998Smarkm		.callback = urtw_bulk_tx_status_callback
542109998Smarkm	},
54368651Skris	[URTW_8187B_BULK_TX_BE] = {
54468651Skris		.type = UE_BULK,
54568651Skris		.endpoint = URTW_8187B_TXPIPE_BE,
54668651Skris		.direction = UE_DIR_OUT,
54768651Skris		.bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT,
54868651Skris		.flags = {
54968651Skris			.force_short_xfer = 1,
55068651Skris			.pipe_bof = 1,
55168651Skris		},
55268651Skris		.callback = urtw_bulk_tx_callback,
55368651Skris		.timeout = URTW_DATA_TIMEOUT
55468651Skris	},
55568651Skris	[URTW_8187B_BULK_TX_BK] = {
55668651Skris		.type = UE_BULK,
55768651Skris		.endpoint = URTW_8187B_TXPIPE_BK,
55868651Skris		.direction = UE_DIR_OUT,
55968651Skris		.bufsize = URTW_TX_MAXSIZE,
56068651Skris		.flags = {
56168651Skris			.ext_buffer = 1,
56268651Skris			.force_short_xfer = 1,
56368651Skris			.pipe_bof = 1,
56468651Skris		},
56568651Skris		.callback = urtw_bulk_tx_callback,
566109998Smarkm		.timeout = URTW_DATA_TIMEOUT
56768651Skris	},
56868651Skris	[URTW_8187B_BULK_TX_VI] = {
56968651Skris		.type = UE_BULK,
57068651Skris		.endpoint = URTW_8187B_TXPIPE_VI,
57168651Skris		.direction = UE_DIR_OUT,
57268651Skris		.bufsize = URTW_TX_MAXSIZE,
57368651Skris		.flags = {
57468651Skris			.ext_buffer = 1,
57568651Skris			.force_short_xfer = 1,
57668651Skris			.pipe_bof = 1,
577109998Smarkm		},
578109998Smarkm		.callback = urtw_bulk_tx_callback,
57968651Skris		.timeout = URTW_DATA_TIMEOUT
58068651Skris	},
58168651Skris	[URTW_8187B_BULK_TX_VO] = {
58268651Skris		.type = UE_BULK,
58368651Skris		.endpoint = URTW_8187B_TXPIPE_VO,
58468651Skris		.direction = UE_DIR_OUT,
58568651Skris		.bufsize = URTW_TX_MAXSIZE,
58668651Skris		.flags = {
58768651Skris			.ext_buffer = 1,
58868651Skris			.force_short_xfer = 1,
58968651Skris			.pipe_bof = 1,
59068651Skris		},
59168651Skris		.callback = urtw_bulk_tx_callback,
59268651Skris		.timeout = URTW_DATA_TIMEOUT
59368651Skris	},
59468651Skris	[URTW_8187B_BULK_TX_EP12] = {
595109998Smarkm		.type = UE_BULK,
59668651Skris		.endpoint = 0xc,
59768651Skris		.direction = UE_DIR_OUT,
59868651Skris		.bufsize = URTW_TX_MAXSIZE,
59968651Skris		.flags = {
600109998Smarkm			.ext_buffer = 1,
60168651Skris			.force_short_xfer = 1,
602109998Smarkm			.pipe_bof = 1,
60368651Skris		},
60468651Skris		.callback = urtw_bulk_tx_callback,
60568651Skris		.timeout = URTW_DATA_TIMEOUT
60668651Skris	}
60768651Skris};
60868651Skris
60968651Skrisstatic const struct usb_config urtw_8187l_usbconfig[URTW_8187L_N_XFERS] = {
61068651Skris	[URTW_8187L_BULK_RX] = {
61168651Skris		.type = UE_BULK,
61268651Skris		.endpoint = 0x81,
61368651Skris		.direction = UE_DIR_IN,
61468651Skris		.bufsize = MCLBYTES,
61568651Skris		.flags = {
61668651Skris			.ext_buffer = 1,
61768651Skris			.pipe_bof = 1,
61868651Skris			.short_xfer_ok = 1
61968651Skris		},
62068651Skris		.callback = urtw_bulk_rx_callback
621109998Smarkm	},
62268651Skris	[URTW_8187L_BULK_TX_LOW] = {
623109998Smarkm		.type = UE_BULK,
62468651Skris		.endpoint = 0x2,
62568651Skris		.direction = UE_DIR_OUT,
62668651Skris		.bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT,
627238405Sjkim		.flags = {
62868651Skris			.force_short_xfer = 1,
62968651Skris			.pipe_bof = 1,
63068651Skris		},
63168651Skris		.callback = urtw_bulk_tx_callback,
632109998Smarkm		.timeout = URTW_DATA_TIMEOUT
63368651Skris	},
63468651Skris	[URTW_8187L_BULK_TX_NORMAL] = {
63568651Skris		.type = UE_BULK,
63668651Skris		.endpoint = 0x3,
63768651Skris		.direction = UE_DIR_OUT,
63868651Skris		.bufsize = URTW_TX_MAXSIZE,
63968651Skris		.flags = {
64068651Skris			.ext_buffer = 1,
64168651Skris			.force_short_xfer = 1,
64268651Skris			.pipe_bof = 1,
64368651Skris		},
64468651Skris		.callback = urtw_bulk_tx_callback,
64568651Skris		.timeout = URTW_DATA_TIMEOUT
64668651Skris	},
64768651Skris};
64868651Skris
64968651Skrisstatic struct ieee80211vap *urtw_vap_create(struct ieee80211com *,
65068651Skris			    const char [IFNAMSIZ], int, enum ieee80211_opmode,
65168651Skris			    int, const uint8_t [IEEE80211_ADDR_LEN],
65268651Skris			    const uint8_t [IEEE80211_ADDR_LEN]);
65368651Skrisstatic void		urtw_vap_delete(struct ieee80211vap *);
65468651Skrisstatic void		urtw_init(void *);
65568651Skrisstatic void		urtw_stop(struct ifnet *);
656109998Smarkmstatic void		urtw_stop_locked(struct ifnet *);
65768651Skrisstatic int		urtw_ioctl(struct ifnet *, u_long, caddr_t);
658109998Smarkmstatic void		urtw_start(struct ifnet *);
65968651Skrisstatic int		urtw_alloc_rx_data_list(struct urtw_softc *);
66068651Skrisstatic int		urtw_alloc_tx_data_list(struct urtw_softc *);
66168651Skrisstatic int		urtw_raw_xmit(struct ieee80211_node *, struct mbuf *,
66268651Skris			    const struct ieee80211_bpf_params *);
66368651Skrisstatic void		urtw_scan_start(struct ieee80211com *);
66468651Skrisstatic void		urtw_scan_end(struct ieee80211com *);
66568651Skrisstatic void		urtw_set_channel(struct ieee80211com *);
66668651Skrisstatic void		urtw_update_mcast(struct ifnet *);
667109998Smarkmstatic int		urtw_tx_start(struct urtw_softc *,
66868651Skris			    struct ieee80211_node *, struct mbuf *,
66968651Skris			    struct urtw_data *, int);
67068651Skrisstatic int		urtw_newstate(struct ieee80211vap *,
671109998Smarkm			    enum ieee80211_state, int);
67268651Skrisstatic void		urtw_led_ch(void *);
67368651Skrisstatic void		urtw_ledtask(void *, int);
67468651Skrisstatic void		urtw_watchdog(void *);
67568651Skrisstatic void		urtw_set_multi(void *);
67668651Skrisstatic int		urtw_isbmode(uint16_t);
67768651Skrisstatic uint16_t		urtw_rate2rtl(uint32_t);
67868651Skrisstatic uint16_t		urtw_rtl2rate(uint32_t);
67968651Skrisstatic usb_error_t	urtw_set_rate(struct urtw_softc *);
68068651Skrisstatic usb_error_t	urtw_update_msr(struct urtw_softc *);
68168651Skrisstatic usb_error_t	urtw_read8_c(struct urtw_softc *, int, uint8_t *);
68268651Skrisstatic usb_error_t	urtw_read16_c(struct urtw_softc *, int, uint16_t *);
68368651Skrisstatic usb_error_t	urtw_read32_c(struct urtw_softc *, int, uint32_t *);
68468651Skrisstatic usb_error_t	urtw_write8_c(struct urtw_softc *, int, uint8_t);
68568651Skrisstatic usb_error_t	urtw_write16_c(struct urtw_softc *, int, uint16_t);
68668651Skrisstatic usb_error_t	urtw_write32_c(struct urtw_softc *, int, uint32_t);
68768651Skrisstatic usb_error_t	urtw_eprom_cs(struct urtw_softc *, int);
68868651Skrisstatic usb_error_t	urtw_eprom_ck(struct urtw_softc *);
68968651Skrisstatic usb_error_t	urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
69068651Skris			    int);
69168651Skrisstatic usb_error_t	urtw_eprom_read32(struct urtw_softc *, uint32_t,
69268651Skris			    uint32_t *);
693109998Smarkmstatic usb_error_t	urtw_eprom_readbit(struct urtw_softc *, int16_t *);
694109998Smarkmstatic usb_error_t	urtw_eprom_writebit(struct urtw_softc *, int16_t);
69568651Skrisstatic usb_error_t	urtw_get_macaddr(struct urtw_softc *);
69668651Skrisstatic usb_error_t	urtw_get_txpwr(struct urtw_softc *);
69768651Skrisstatic usb_error_t	urtw_get_rfchip(struct urtw_softc *);
69868651Skrisstatic usb_error_t	urtw_led_init(struct urtw_softc *);
69968651Skrisstatic usb_error_t	urtw_8185_rf_pins_enable(struct urtw_softc *);
70068651Skrisstatic usb_error_t	urtw_8185_tx_antenna(struct urtw_softc *, uint8_t);
70168651Skrisstatic usb_error_t	urtw_8187_write_phy(struct urtw_softc *, uint8_t,
70268651Skris			    uint32_t);
70368651Skrisstatic usb_error_t	urtw_8187_write_phy_ofdm_c(struct urtw_softc *,
704109998Smarkm			    uint8_t, uint32_t);
70568651Skrisstatic usb_error_t	urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t,
70668651Skris			    uint32_t);
707238405Sjkimstatic usb_error_t	urtw_8225_setgain(struct urtw_softc *, int16_t);
70868651Skrisstatic usb_error_t	urtw_8225_usb_init(struct urtw_softc *);
70968651Skrisstatic usb_error_t	urtw_8225_write_c(struct urtw_softc *, uint8_t,
71068651Skris			    uint16_t);
71168651Skrisstatic usb_error_t	urtw_8225_write_s16(struct urtw_softc *, uint8_t, int,
71268651Skris			    uint16_t *);
71368651Skrisstatic usb_error_t	urtw_8225_read(struct urtw_softc *, uint8_t,
71468651Skris			    uint32_t *);
71568651Skrisstatic usb_error_t	urtw_8225_rf_init(struct urtw_softc *);
71668651Skrisstatic usb_error_t	urtw_8225_rf_set_chan(struct urtw_softc *, int);
71768651Skrisstatic usb_error_t	urtw_8225_rf_set_sens(struct urtw_softc *, int);
71868651Skrisstatic usb_error_t	urtw_8225_set_txpwrlvl(struct urtw_softc *, int);
71968651Skrisstatic usb_error_t	urtw_8225_rf_stop(struct urtw_softc *);
72068651Skrisstatic usb_error_t	urtw_8225v2_rf_init(struct urtw_softc *);
72168651Skrisstatic usb_error_t	urtw_8225v2_rf_set_chan(struct urtw_softc *, int);
722109998Smarkmstatic usb_error_t	urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int);
72368651Skrisstatic usb_error_t	urtw_8225v2_setgain(struct urtw_softc *, int16_t);
72468651Skrisstatic usb_error_t	urtw_8225_isv2(struct urtw_softc *, int *);
72568651Skrisstatic usb_error_t	urtw_8225v2b_rf_init(struct urtw_softc *);
72668651Skrisstatic usb_error_t	urtw_8225v2b_rf_set_chan(struct urtw_softc *, int);
72768651Skrisstatic usb_error_t	urtw_read8e(struct urtw_softc *, int, uint8_t *);
728194206Ssimonstatic usb_error_t	urtw_write8e(struct urtw_softc *, int, uint8_t);
72968651Skrisstatic usb_error_t	urtw_8180_set_anaparam(struct urtw_softc *, uint32_t);
73068651Skrisstatic usb_error_t	urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t);
73168651Skrisstatic usb_error_t	urtw_intr_enable(struct urtw_softc *);
73268651Skrisstatic usb_error_t	urtw_intr_disable(struct urtw_softc *);
73368651Skrisstatic usb_error_t	urtw_reset(struct urtw_softc *);
73468651Skrisstatic usb_error_t	urtw_led_on(struct urtw_softc *, int);
73568651Skrisstatic usb_error_t	urtw_led_ctl(struct urtw_softc *, int);
73668651Skrisstatic usb_error_t	urtw_led_blink(struct urtw_softc *);
73768651Skrisstatic usb_error_t	urtw_led_mode0(struct urtw_softc *, int);
73868651Skrisstatic usb_error_t	urtw_led_mode1(struct urtw_softc *, int);
73968651Skrisstatic usb_error_t	urtw_led_mode2(struct urtw_softc *, int);
74068651Skrisstatic usb_error_t	urtw_led_mode3(struct urtw_softc *, int);
74168651Skrisstatic usb_error_t	urtw_rx_setconf(struct urtw_softc *);
74268651Skrisstatic usb_error_t	urtw_rx_enable(struct urtw_softc *);
74368651Skrisstatic usb_error_t	urtw_tx_enable(struct urtw_softc *sc);
744109998Smarkmstatic void		urtw_free_tx_data_list(struct urtw_softc *);
74589837Skrisstatic void		urtw_free_rx_data_list(struct urtw_softc *);
74668651Skrisstatic void		urtw_free_data_list(struct urtw_softc *,
74768651Skris			    struct urtw_data data[], int, int);
74868651Skrisstatic usb_error_t	urtw_adapter_start(struct urtw_softc *);
74968651Skrisstatic usb_error_t	urtw_adapter_start_b(struct urtw_softc *);
75068651Skrisstatic usb_error_t	urtw_set_mode(struct urtw_softc *, uint32_t);
75168651Skrisstatic usb_error_t	urtw_8187b_cmd_reset(struct urtw_softc *);
75268651Skrisstatic usb_error_t	urtw_do_request(struct urtw_softc *,
753109998Smarkm			    struct usb_device_request *, void *);
75468651Skrisstatic usb_error_t	urtw_8225v2b_set_txpwrlvl(struct urtw_softc *, int);
75568651Skrisstatic usb_error_t	urtw_led_off(struct urtw_softc *, int);
75668651Skrisstatic void		urtw_abort_xfers(struct urtw_softc *);
75768651Skrisstatic struct urtw_data *
75868651Skris			urtw_getbuf(struct urtw_softc *sc);
75968651Skrisstatic int		urtw_compute_txtime(uint16_t, uint16_t, uint8_t,
76068651Skris			    uint8_t);
76168651Skrisstatic void		urtw_updateslot(struct ifnet *);
762109998Smarkmstatic void		urtw_updateslottask(void *, int);
76368651Skrisstatic void		urtw_sysctl_node(struct urtw_softc *);
76468651Skris
76568651Skrisstatic int
76668651Skrisurtw_match(device_t dev)
767109998Smarkm{
76868651Skris	struct usb_attach_arg *uaa = device_get_ivars(dev);
769109998Smarkm
770109998Smarkm	if (uaa->usb_mode != USB_MODE_HOST)
771109998Smarkm		return (ENXIO);
772109998Smarkm	if (uaa->info.bConfigIndex != URTW_CONFIG_INDEX)
773109998Smarkm		return (ENXIO);
774109998Smarkm	if (uaa->info.bIfaceIndex != URTW_IFACE_INDEX)
775109998Smarkm		return (ENXIO);
776109998Smarkm
777109998Smarkm	return (usbd_lookup_id_by_uaa(urtw_devs, sizeof(urtw_devs), uaa));
778109998Smarkm}
779109998Smarkm
780109998Smarkmstatic int
781109998Smarkmurtw_attach(device_t dev)
782109998Smarkm{
783109998Smarkm	const struct usb_config *setup_start;
784109998Smarkm	int ret = ENXIO;
785109998Smarkm	struct urtw_softc *sc = device_get_softc(dev);
786109998Smarkm	struct usb_attach_arg *uaa = device_get_ivars(dev);
787109998Smarkm	struct ieee80211com *ic;
788109998Smarkm	struct ifnet *ifp;
789109998Smarkm	uint8_t bands, iface_index = URTW_IFACE_INDEX;		/* XXX */
790109998Smarkm	uint16_t n_setup;
791109998Smarkm	uint32_t data;
792109998Smarkm	usb_error_t error;
793109998Smarkm
794109998Smarkm	device_set_usb_desc(dev);
795109998Smarkm
796109998Smarkm	sc->sc_dev = dev;
797109998Smarkm	sc->sc_udev = uaa->device;
798109998Smarkm	if (USB_GET_DRIVER_INFO(uaa) == URTW_REV_RTL8187B)
799109998Smarkm		sc->sc_flags |= URTW_RTL8187B;
800109998Smarkm#ifdef URTW_DEBUG
801109998Smarkm	sc->sc_debug = urtw_debug;
802109998Smarkm#endif
803109998Smarkm
804109998Smarkm	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK,
805194206Ssimon	    MTX_DEF);
80668651Skris	usb_callout_init_mtx(&sc->sc_led_ch, &sc->sc_mtx, 0);
807109998Smarkm	TASK_INIT(&sc->sc_led_task, 0, urtw_ledtask, sc);
808109998Smarkm	TASK_INIT(&sc->sc_updateslot_task, 0, urtw_updateslottask, sc);
809109998Smarkm	callout_init(&sc->sc_watchdog_ch, 0);
81068651Skris
81168651Skris	if (sc->sc_flags & URTW_RTL8187B) {
812238405Sjkim		setup_start = urtw_8187b_usbconfig;
81368651Skris		n_setup = URTW_8187B_N_XFERS;
81468651Skris	} else {
81568651Skris		setup_start = urtw_8187l_usbconfig;
81668651Skris		n_setup = URTW_8187L_N_XFERS;
81768651Skris	}
81868651Skris
81968651Skris	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
82068651Skris	    setup_start, n_setup, sc, &sc->sc_mtx);
82168651Skris	if (error) {
82268651Skris		device_printf(dev, "could not allocate USB transfers, "
82368651Skris		    "err=%s\n", usbd_errstr(error));
824109998Smarkm		ret = ENXIO;
82568651Skris		goto fail0;
82668651Skris	}
82768651Skris
82868651Skris	if (sc->sc_flags & URTW_RTL8187B) {
82968651Skris		sc->sc_tx_dma_buf =
830194206Ssimon		    usbd_xfer_get_frame_buffer(sc->sc_xfer[
83168651Skris		    URTW_8187B_BULK_TX_BE], 0);
83268651Skris	} else {
83368651Skris		sc->sc_tx_dma_buf =
83468651Skris		    usbd_xfer_get_frame_buffer(sc->sc_xfer[
83568651Skris		    URTW_8187L_BULK_TX_LOW], 0);
83668651Skris	}
83768651Skris
83868651Skris	URTW_LOCK(sc);
83968651Skris
84068651Skris	urtw_read32_m(sc, URTW_RX, &data);
84168651Skris	sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
84268651Skris	    URTW_EEPROM_93C46;
84368651Skris
84468651Skris	error = urtw_get_rfchip(sc);
84568651Skris	if (error != 0)
846109998Smarkm		goto fail;
84789837Skris	error = urtw_get_macaddr(sc);
84868651Skris	if (error != 0)
84968651Skris		goto fail;
85068651Skris	error = urtw_get_txpwr(sc);
85168651Skris	if (error != 0)
85268651Skris		goto fail;
85368651Skris	error = urtw_led_init(sc);
85468651Skris	if (error != 0)
855109998Smarkm		goto fail;
85668651Skris
85768651Skris	URTW_UNLOCK(sc);
85868651Skris
85968651Skris	sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
86068651Skris	sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
86168651Skris	sc->sc_currate = 3;
86268651Skris	sc->sc_preamble_mode = urtw_preamble_mode;
86368651Skris
864109998Smarkm	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
86568651Skris	if (ifp == NULL) {
86668651Skris		device_printf(sc->sc_dev, "can not allocate ifnet\n");
86768651Skris		ret = ENOMEM;
86868651Skris		goto fail1;
869109998Smarkm	}
87068651Skris
87168651Skris	ifp->if_softc = sc;
87268651Skris	if_initname(ifp, "urtw", device_get_unit(sc->sc_dev));
87368651Skris	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
87468651Skris	ifp->if_init = urtw_init;
87568651Skris	ifp->if_ioctl = urtw_ioctl;
87668651Skris	ifp->if_start = urtw_start;
87768651Skris	/* XXX URTW_TX_DATA_LIST_COUNT */
87868651Skris	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
87968651Skris	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
88068651Skris	IFQ_SET_READY(&ifp->if_snd);
88168651Skris
88268651Skris	ic = ifp->if_l2com;
88368651Skris	ic->ic_ifp = ifp;
88468651Skris	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
88568651Skris	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
886109998Smarkm
88768651Skris	/* set device capabilities */
888109998Smarkm	ic->ic_caps =
88968651Skris	    IEEE80211_C_STA |		/* station mode */
89068651Skris	    IEEE80211_C_MONITOR |	/* monitor mode supported */
891109998Smarkm	    IEEE80211_C_TXPMGT |	/* tx power management */
89268651Skris	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
89368651Skris	    IEEE80211_C_SHSLOT |	/* short slot time supported */
89468651Skris	    IEEE80211_C_BGSCAN |	/* capable of bg scanning */
89568651Skris	    IEEE80211_C_WPA;		/* 802.11i */
89668651Skris
89768651Skris	bands = 0;
89868651Skris	setbit(&bands, IEEE80211_MODE_11B);
89968651Skris	setbit(&bands, IEEE80211_MODE_11G);
90068651Skris	ieee80211_init_channels(ic, NULL, &bands);
90168651Skris
90268651Skris	ieee80211_ifattach(ic, sc->sc_bssid);
90368651Skris	ic->ic_raw_xmit = urtw_raw_xmit;
90468651Skris	ic->ic_scan_start = urtw_scan_start;
90568651Skris	ic->ic_scan_end = urtw_scan_end;
90668651Skris	ic->ic_set_channel = urtw_set_channel;
90768651Skris	ic->ic_updateslot = urtw_updateslot;
90868651Skris	ic->ic_vap_create = urtw_vap_create;
90968651Skris	ic->ic_vap_delete = urtw_vap_delete;
910109998Smarkm	ic->ic_update_mcast = urtw_update_mcast;
91168651Skris
91268651Skris	ieee80211_radiotap_attach(ic,
91368651Skris	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
91468651Skris	    URTW_TX_RADIOTAP_PRESENT,
91568651Skris	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
91668651Skris	    URTW_RX_RADIOTAP_PRESENT);
91768651Skris
91868651Skris	urtw_sysctl_node(sc);
91968651Skris
92068651Skris	if (bootverbose)
92168651Skris		ieee80211_announce(ic);
92268651Skris	return (0);
92368651Skris
92468651Skrisfail:	URTW_UNLOCK(sc);
92568651Skrisfail1:	usbd_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ?
92668651Skris	    URTW_8187B_N_XFERS : URTW_8187L_N_XFERS);
92768651Skrisfail0:
92868651Skris	return (ret);
92972613Skris}
93068651Skris
93168651Skrisstatic int
932109998Smarkmurtw_detach(device_t dev)
933109998Smarkm{
93468651Skris	struct urtw_softc *sc = device_get_softc(dev);
93568651Skris	struct ifnet *ifp = sc->sc_ifp;
93689837Skris	struct ieee80211com *ic = ifp->if_l2com;
93789837Skris	unsigned int x;
93868651Skris	unsigned int n_xfers;
93968651Skris
94068651Skris	/* Prevent further ioctls */
941109998Smarkm	URTW_LOCK(sc);
94268651Skris	sc->sc_flags |= URTW_DETACHED;
94368651Skris	URTW_UNLOCK(sc);
94468651Skris
94568651Skris	urtw_stop(ifp);
94668651Skris
94768651Skris	ieee80211_draintask(ic, &sc->sc_updateslot_task);
94868651Skris	ieee80211_draintask(ic, &sc->sc_led_task);
94968651Skris
95068651Skris	usb_callout_drain(&sc->sc_led_ch);
951109998Smarkm	callout_drain(&sc->sc_watchdog_ch);
95268651Skris
953238405Sjkim	n_xfers = (sc->sc_flags & URTW_RTL8187B) ?
954238405Sjkim	    URTW_8187B_N_XFERS : URTW_8187L_N_XFERS;
955238405Sjkim
95668651Skris	/* prevent further allocations from RX/TX data lists */
95768651Skris	URTW_LOCK(sc);
95868651Skris	STAILQ_INIT(&sc->sc_tx_active);
95968651Skris	STAILQ_INIT(&sc->sc_tx_inactive);
96068651Skris	STAILQ_INIT(&sc->sc_tx_pending);
96168651Skris
96268651Skris	STAILQ_INIT(&sc->sc_rx_active);
96368651Skris	STAILQ_INIT(&sc->sc_rx_inactive);
96468651Skris	URTW_UNLOCK(sc);
965142425Snectar
96668651Skris	/* drain USB transfers */
96768651Skris	for (x = 0; x != n_xfers; x++)
96868651Skris		usbd_transfer_drain(sc->sc_xfer[x]);
96968651Skris
97068651Skris	/* free data buffers */
97168651Skris	URTW_LOCK(sc);
97268651Skris	urtw_free_tx_data_list(sc);
97368651Skris	urtw_free_rx_data_list(sc);
97468651Skris	URTW_UNLOCK(sc);
97568651Skris
97668651Skris	/* free USB transfers and some data buffers */
97768651Skris	usbd_transfer_unsetup(sc->sc_xfer, n_xfers);
97868651Skris
97968651Skris	ieee80211_ifdetach(ic);
98068651Skris	if_free(ifp);
98168651Skris	mtx_destroy(&sc->sc_mtx);
98268651Skris	return (0);
983109998Smarkm}
98468651Skris
98568651Skrisstatic void
98668651Skrisurtw_free_tx_data_list(struct urtw_softc *sc)
987238405Sjkim{
988238405Sjkim	urtw_free_data_list(sc, sc->sc_tx, URTW_TX_DATA_LIST_COUNT, 0);
98968651Skris}
99068651Skris
991109998Smarkmstatic void
992109998Smarkmurtw_free_rx_data_list(struct urtw_softc *sc)
99368651Skris{
99468651Skris	urtw_free_data_list(sc, sc->sc_rx, URTW_RX_DATA_LIST_COUNT, 1);
99568651Skris}
99668651Skris
99768651Skrisstatic void
99868651Skrisurtw_free_data_list(struct urtw_softc *sc, struct urtw_data data[], int ndata,
99968651Skris    int fillmbuf)
100068651Skris{
100168651Skris	int i;
100268651Skris
100368651Skris	for (i = 0; i < ndata; i++) {
100468651Skris		struct urtw_data *dp = &data[i];
100568651Skris
100668651Skris		if (fillmbuf == 1) {
100768651Skris			if (dp->m != NULL) {
100868651Skris				m_freem(dp->m);
100968651Skris				dp->m = NULL;
101068651Skris				dp->buf = NULL;
101168651Skris			}
101268651Skris		} else {
101368651Skris			dp->buf = NULL;
101468651Skris		}
101568651Skris		if (dp->ni != NULL) {
101668651Skris			ieee80211_free_node(dp->ni);
1017109998Smarkm			dp->ni = NULL;
101868651Skris		}
101968651Skris	}
102068651Skris}
102168651Skris
102268651Skrisstatic struct ieee80211vap *
102368651Skrisurtw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
102468651Skris    enum ieee80211_opmode opmode, int flags,
102568651Skris    const uint8_t bssid[IEEE80211_ADDR_LEN],
102668651Skris    const uint8_t mac[IEEE80211_ADDR_LEN])
102768651Skris{
102868651Skris	struct urtw_vap *uvp;
102968651Skris	struct ieee80211vap *vap;
103068651Skris
103168651Skris	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
103268651Skris		return (NULL);
103368651Skris	uvp = (struct urtw_vap *) malloc(sizeof(struct urtw_vap),
103468651Skris	    M_80211_VAP, M_NOWAIT | M_ZERO);
103568651Skris	if (uvp == NULL)
103668651Skris		return (NULL);
103768651Skris	vap = &uvp->vap;
103868651Skris	/* enable s/w bmiss handling for sta mode */
103968651Skris
104068651Skris	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
104168651Skris	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) {
104268651Skris		/* out of memory */
104368651Skris		free(uvp, M_80211_VAP);
104468651Skris		return (NULL);
104568651Skris	}
104668651Skris
104768651Skris	/* override state transition machine */
104868651Skris	uvp->newstate = vap->iv_newstate;
104968651Skris	vap->iv_newstate = urtw_newstate;
105068651Skris
105168651Skris	/* complete setup */
105268651Skris	ieee80211_vap_attach(vap, ieee80211_media_change,
1053238405Sjkim	    ieee80211_media_status);
105468651Skris	ic->ic_opmode = opmode;
105568651Skris	return (vap);
105668651Skris}
105768651Skris
105868651Skrisstatic void
105968651Skrisurtw_vap_delete(struct ieee80211vap *vap)
1060142425Snectar{
106168651Skris	struct urtw_vap *uvp = URTW_VAP(vap);
106268651Skris
106368651Skris	ieee80211_vap_detach(vap);
106468651Skris	free(uvp, M_80211_VAP);
106568651Skris}
106668651Skris
106768651Skrisstatic void
1068298998Sjkimurtw_init_locked(void *arg)
1069298998Sjkim{
107068651Skris	int ret;
107168651Skris	struct urtw_softc *sc = arg;
107268651Skris	struct ifnet *ifp = sc->sc_ifp;
107368651Skris	usb_error_t error;
107468651Skris
107568651Skris	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
107668651Skris		urtw_stop_locked(ifp);
107768651Skris
107868651Skris	error = (sc->sc_flags & URTW_RTL8187B) ? urtw_adapter_start_b(sc) :
107968651Skris	    urtw_adapter_start(sc);
108068651Skris	if (error != 0)
108168651Skris		goto fail;
108268651Skris
108368651Skris	/* reset softc variables  */
108468651Skris	sc->sc_txtimer = 0;
108568651Skris
108668651Skris	if (!(sc->sc_flags & URTW_INIT_ONCE)) {
108768651Skris		ret = urtw_alloc_rx_data_list(sc);
108868651Skris		if (ret != 0)
108968651Skris			goto fail;
109068651Skris		ret = urtw_alloc_tx_data_list(sc);
109168651Skris		if (ret != 0)
109268651Skris			goto fail;
109368651Skris		sc->sc_flags |= URTW_INIT_ONCE;
109468651Skris	}
109568651Skris
109668651Skris	error = urtw_rx_enable(sc);
109768651Skris	if (error != 0)
109868651Skris		goto fail;
109968651Skris	error = urtw_tx_enable(sc);
110068651Skris	if (error != 0)
110168651Skris		goto fail;
110268651Skris
110368651Skris	if (sc->sc_flags & URTW_RTL8187B)
110468651Skris		usbd_transfer_start(sc->sc_xfer[URTW_8187B_BULK_TX_STATUS]);
110568651Skris
110668651Skris	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1107160814Ssimon	ifp->if_drv_flags |= IFF_DRV_RUNNING;
110868651Skris
110968651Skris	callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
111068651Skrisfail:
111168651Skris	return;
111268651Skris}
111368651Skris
111468651Skrisstatic void
111568651Skrisurtw_init(void *arg)
1116298998Sjkim{
1117298998Sjkim	struct urtw_softc *sc = arg;
1118298998Sjkim
1119298998Sjkim	URTW_LOCK(sc);
1120238405Sjkim	urtw_init_locked(arg);
1121238405Sjkim	URTW_UNLOCK(sc);
1122238405Sjkim}
1123238405Sjkim
1124238405Sjkimstatic usb_error_t
112568651Skrisurtw_adapter_start_b(struct urtw_softc *sc)
112668651Skris{
112768651Skris#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
112868651Skris	uint8_t data8;
112968651Skris	usb_error_t error;
1130109998Smarkm
113168651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
113268651Skris	if (error)
1133109998Smarkm		goto fail;
113468651Skris
113568651Skris	urtw_read8_m(sc, URTW_CONFIG3, &data8);
113668651Skris	urtw_write8_m(sc, URTW_CONFIG3,
113768651Skris	    data8 | URTW_CONFIG3_ANAPARAM_WRITE | URTW_CONFIG3_GNT_SELECT);
113868651Skris	urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON);
113968651Skris	urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON);
1140109998Smarkm	urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON);
1141109998Smarkm
1142109998Smarkm	urtw_write8_m(sc, 0x61, 0x10);
1143109998Smarkm	urtw_read8_m(sc, 0x62, &data8);
1144109998Smarkm	urtw_write8_m(sc, 0x62, data8 & ~(1 << 5));
1145109998Smarkm	urtw_write8_m(sc, 0x62, data8 | (1 << 5));
1146109998Smarkm
1147109998Smarkm	urtw_read8_m(sc, URTW_CONFIG3, &data8);
114868651Skris	data8 &= ~URTW_CONFIG3_ANAPARAM_WRITE;
114968651Skris	urtw_write8_m(sc, URTW_CONFIG3, data8);
115068651Skris
115168651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
115268651Skris	if (error)
115368651Skris		goto fail;
115468651Skris
115568651Skris	error = urtw_8187b_cmd_reset(sc);
115668651Skris	if (error)
115768651Skris		goto fail;
115868651Skris
115968651Skris	error = sc->sc_rf_init(sc);
116068651Skris	if (error != 0)
116168651Skris		goto fail;
116268651Skris	urtw_write8_m(sc, URTW_CMD, URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE);
116368651Skris
116468651Skris	/* fix RTL8187B RX stall */
116568651Skris	error = urtw_intr_enable(sc);
116668651Skris	if (error)
116768651Skris		goto fail;
116868651Skris
116968651Skris	error = urtw_write8e(sc, 0x41, 0xf4);
1170109998Smarkm	if (error)
1171109998Smarkm		goto fail;
1172109998Smarkm	error = urtw_write8e(sc, 0x40, 0x00);
117368651Skris	if (error)
117468651Skris		goto fail;
117568651Skris	error = urtw_write8e(sc, 0x42, 0x00);
117668651Skris	if (error)
1177109998Smarkm		goto fail;
117868651Skris	error = urtw_write8e(sc, 0x42, 0x01);
117968651Skris	if (error)
118068651Skris		goto fail;
118168651Skris	error = urtw_write8e(sc, 0x40, 0x0f);
118268651Skris	if (error)
118368651Skris		goto fail;
118468651Skris	error = urtw_write8e(sc, 0x42, 0x00);
1185109998Smarkm	if (error)
1186109998Smarkm		goto fail;
118768651Skris	error = urtw_write8e(sc, 0x42, 0x01);
118868651Skris	if (error)
118968651Skris		goto fail;
119068651Skris
119168651Skris	urtw_read8_m(sc, 0xdb, &data8);
119268651Skris	urtw_write8_m(sc, 0xdb, data8 | (1 << 2));
119368651Skris	urtw_write16_m(sc, 0x372, 0x59fa);
119468651Skris	urtw_write16_m(sc, 0x374, 0x59d2);
119568651Skris	urtw_write16_m(sc, 0x376, 0x59d2);
119668651Skris	urtw_write16_m(sc, 0x378, 0x19fa);
119768651Skris	urtw_write16_m(sc, 0x37a, 0x19fa);
119868651Skris	urtw_write16_m(sc, 0x37c, 0x00d0);
119968651Skris	urtw_write8_m(sc, 0x61, 0);
120068651Skris
1201109998Smarkm	urtw_write8_m(sc, 0x180, 0x0f);
120268651Skris	urtw_write8_m(sc, 0x183, 0x03);
120368651Skris	urtw_write8_m(sc, 0xda, 0x10);
120468651Skris	urtw_write8_m(sc, 0x24d, 0x08);
1205109998Smarkm	urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321b);
120668651Skris
120768651Skris	urtw_write16_m(sc, 0x1ec, 0x800);	/* RX MAX SIZE */
120868651Skrisfail:
120968651Skris	return (error);
121068651Skris#undef N
121168651Skris}
121268651Skris
121368651Skrisstatic usb_error_t
121468651Skrisurtw_adapter_start(struct urtw_softc *sc)
121568651Skris{
121668651Skris	usb_error_t error;
121768651Skris
121868651Skris	error = urtw_reset(sc);
1219109998Smarkm	if (error)
1220109998Smarkm		goto fail;
122168651Skris
122268651Skris	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 0);
122368651Skris	urtw_write8_m(sc, URTW_GPIO, 0);
1224160814Ssimon
1225160814Ssimon	/* for led  */
122668651Skris	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
122768651Skris	error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
122868651Skris	if (error != 0)
122968651Skris		goto fail;
123068651Skris
123168651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
123268651Skris	if (error)
123368651Skris		goto fail;
123468651Skris	/* applying MAC address again.  */
123568651Skris	urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]);
123668651Skris	urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff);
123768651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
1238109998Smarkm	if (error)
123968651Skris		goto fail;
124068651Skris
124168651Skris	error = urtw_update_msr(sc);
124268651Skris	if (error)
124368651Skris		goto fail;
124468651Skris
124568651Skris	urtw_write32_m(sc, URTW_INT_TIMEOUT, 0);
124668651Skris	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
124768651Skris	urtw_write8_m(sc, URTW_RATE_FALLBACK, URTW_RATE_FALLBACK_ENABLE | 0x1);
124868651Skris	error = urtw_set_rate(sc);
1249109998Smarkm	if (error != 0)
1250109998Smarkm		goto fail;
125168651Skris
125268651Skris	error = sc->sc_rf_init(sc);
125368651Skris	if (error != 0)
125468651Skris		goto fail;
125568651Skris	if (sc->sc_rf_set_sens != NULL)
125668651Skris		sc->sc_rf_set_sens(sc, sc->sc_sens);
125768651Skris
1258238405Sjkim	/* XXX correct? to call write16  */
1259238405Sjkim	urtw_write16_m(sc, URTW_PSR, 1);
126068651Skris	urtw_write16_m(sc, URTW_ADDR_MAGIC2, 0x10);
126168651Skris	urtw_write8_m(sc, URTW_TALLY_SEL, 0x80);
126268651Skris	urtw_write8_m(sc, URTW_ADDR_MAGIC3, 0x60);
126368651Skris	/* XXX correct? to call write16  */
126468651Skris	urtw_write16_m(sc, URTW_PSR, 0);
126568651Skris	urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
126668651Skris
126768651Skris	error = urtw_intr_enable(sc);
126868651Skris	if (error != 0)
126968651Skris		goto fail;
127068651Skris
127168651Skrisfail:
127268651Skris	return (error);
127368651Skris}
127468651Skris
127568651Skrisstatic usb_error_t
127668651Skrisurtw_set_mode(struct urtw_softc *sc, uint32_t mode)
127768651Skris{
127868651Skris	uint8_t data;
127968651Skris	usb_error_t error;
128068651Skris
128168651Skris	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
128268651Skris	data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
128368651Skris	data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
128468651Skris	urtw_write8_m(sc, URTW_EPROM_CMD, data);
128568651Skrisfail:
128668651Skris	return (error);
128768651Skris}
128868651Skris
128968651Skrisstatic usb_error_t
129068651Skrisurtw_8187b_cmd_reset(struct urtw_softc *sc)
129168651Skris{
129268651Skris	int i;
129368651Skris	uint8_t data8;
129468651Skris	usb_error_t error;
129568651Skris
129668651Skris	/* XXX the code can be duplicate with urtw_reset().  */
129768651Skris	urtw_read8_m(sc, URTW_CMD, &data8);
129868651Skris	data8 = (data8 & 0x2) | URTW_CMD_RST;
129968651Skris	urtw_write8_m(sc, URTW_CMD, data8);
130068651Skris
130168651Skris	for (i = 0; i < 20; i++) {
130268651Skris		usb_pause_mtx(&sc->sc_mtx, 2);
130368651Skris		urtw_read8_m(sc, URTW_CMD, &data8);
130468651Skris		if (!(data8 & URTW_CMD_RST))
130568651Skris			break;
130668651Skris	}
130768651Skris	if (i >= 20) {
130868651Skris		device_printf(sc->sc_dev, "reset timeout\n");
130968651Skris		goto fail;
131068651Skris	}
131168651Skrisfail:
131268651Skris	return (error);
131368651Skris}
131468651Skris
131568651Skrisstatic usb_error_t
131668651Skrisurtw_do_request(struct urtw_softc *sc,
131768651Skris    struct usb_device_request *req, void *data)
131868651Skris{
131968651Skris	usb_error_t err;
132068651Skris	int ntries = 10;
132168651Skris
132268651Skris	URTW_ASSERT_LOCKED(sc);
132368651Skris
132468651Skris	while (ntries--) {
132568651Skris		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
132668651Skris		    req, data, 0, NULL, 250 /* ms */);
132768651Skris		if (err == 0)
132868651Skris			break;
132968651Skris
133068651Skris		DPRINTF(sc, URTW_DEBUG_INIT,
133168651Skris		    "Control request failed, %s (retrying)\n",
133268651Skris		    usbd_errstr(err));
133368651Skris		usb_pause_mtx(&sc->sc_mtx, hz / 100);
133468651Skris	}
133568651Skris	return (err);
133668651Skris}
133768651Skris
133868651Skrisstatic void
133968651Skrisurtw_stop_locked(struct ifnet *ifp)
134068651Skris{
134168651Skris	struct urtw_softc *sc = ifp->if_softc;
134268651Skris	uint8_t data8;
134368651Skris	usb_error_t error;
134468651Skris
134568651Skris	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
134668651Skris
134768651Skris	error = urtw_intr_disable(sc);
134868651Skris	if (error)
134968651Skris		goto fail;
135068651Skris	urtw_read8_m(sc, URTW_CMD, &data8);
135168651Skris	data8 &= ~(URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE);
135268651Skris	urtw_write8_m(sc, URTW_CMD, data8);
135368651Skris
135468651Skris	error = sc->sc_rf_stop(sc);
135568651Skris	if (error != 0)
135668651Skris		goto fail;
135768651Skris
135868651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
135968651Skris	if (error)
136068651Skris		goto fail;
136168651Skris	urtw_read8_m(sc, URTW_CONFIG4, &data8);
136268651Skris	urtw_write8_m(sc, URTW_CONFIG4, data8 | URTW_CONFIG4_VCOOFF);
136368651Skris	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
136468651Skris	if (error)
136568651Skris		goto fail;
136668651Skrisfail:
136768651Skris	if (error)
136868651Skris		device_printf(sc->sc_dev, "failed to stop (%s)\n",
136968651Skris		    usbd_errstr(error));
137068651Skris
137168651Skris	usb_callout_stop(&sc->sc_led_ch);
137268651Skris	callout_stop(&sc->sc_watchdog_ch);
137368651Skris
137468651Skris	urtw_abort_xfers(sc);
137568651Skris}
137668651Skris
137768651Skrisstatic void
137868651Skrisurtw_stop(struct ifnet *ifp)
137968651Skris{
138068651Skris	struct urtw_softc *sc = ifp->if_softc;
138168651Skris
138268651Skris	URTW_LOCK(sc);
138368651Skris	urtw_stop_locked(ifp);
138468651Skris	URTW_UNLOCK(sc);
138568651Skris}
138668651Skris
138768651Skrisstatic void
138868651Skrisurtw_abort_xfers(struct urtw_softc *sc)
138968651Skris{
139068651Skris	int i, max;
139168651Skris
139268651Skris	URTW_ASSERT_LOCKED(sc);
139368651Skris
139468651Skris	max = (sc->sc_flags & URTW_RTL8187B) ? URTW_8187B_N_XFERS :
139568651Skris	    URTW_8187L_N_XFERS;
139668651Skris
139768651Skris	/* abort any pending transfers */
139868651Skris	for (i = 0; i < max; i++)
139968651Skris		usbd_transfer_stop(sc->sc_xfer[i]);
140068651Skris}
140168651Skris
140268651Skrisstatic int
140368651Skrisurtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
140468651Skris{
140568651Skris	struct urtw_softc *sc = ifp->if_softc;
140668651Skris	struct ieee80211com *ic = ifp->if_l2com;
140768651Skris	struct ifreq *ifr = (struct ifreq *) data;
140868651Skris	int error;
140968651Skris	int startall = 0;
141068651Skris
141168651Skris	URTW_LOCK(sc);
141268651Skris	error = (sc->sc_flags & URTW_DETACHED) ? ENXIO : 0;
141368651Skris	URTW_UNLOCK(sc);
141468651Skris	if (error)
141568651Skris		return (error);
141668651Skris
141768651Skris	switch (cmd) {
141868651Skris	case SIOCSIFFLAGS:
141968651Skris		if (ifp->if_flags & IFF_UP) {
142068651Skris			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
142168651Skris				if ((ifp->if_flags ^ sc->sc_if_flags) &
142268651Skris				    (IFF_ALLMULTI | IFF_PROMISC))
142368651Skris					urtw_set_multi(sc);
142468651Skris			} else {
142568651Skris				urtw_init(ifp->if_softc);
142668651Skris				startall = 1;
142768651Skris			}
142868651Skris		} else {
142968651Skris			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1430109998Smarkm				urtw_stop(ifp);
1431109998Smarkm		}
1432109998Smarkm		sc->sc_if_flags = ifp->if_flags;
143368651Skris		if (startall)
1434109998Smarkm			ieee80211_start_all(ic);
1435109998Smarkm		break;
143668651Skris	case SIOCGIFMEDIA:
1437109998Smarkm		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
143868651Skris		break;
143968651Skris	case SIOCGIFADDR:
1440109998Smarkm		error = ether_ioctl(ifp, cmd, data);
1441109998Smarkm		break;
144268651Skris	default:
1443109998Smarkm		error = EINVAL;
1444109998Smarkm		break;
144568651Skris	}
1446109998Smarkm	return (error);
144768651Skris}
1448109998Smarkm
144968651Skrisstatic void
145068651Skrisurtw_start(struct ifnet *ifp)
145168651Skris{
145268651Skris	struct urtw_data *bf;
145368651Skris	struct urtw_softc *sc = ifp->if_softc;
145468651Skris	struct ieee80211_node *ni;
145568651Skris	struct mbuf *m;
145668651Skris
145768651Skris	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
145868651Skris		return;
145968651Skris
146068651Skris	URTW_LOCK(sc);
146168651Skris	for (;;) {
146268651Skris		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
146368651Skris		if (m == NULL)
146468651Skris			break;
146568651Skris		bf = urtw_getbuf(sc);
146668651Skris		if (bf == NULL) {
146768651Skris			IFQ_DRV_PREPEND(&ifp->if_snd, m);
146868651Skris			break;
146968651Skris		}
147068651Skris
1471109998Smarkm		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
147268651Skris		m->m_pkthdr.rcvif = NULL;
147368651Skris
147468651Skris		if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_NORMAL) != 0) {
147568651Skris			ifp->if_oerrors++;
147668651Skris			STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
147768651Skris			ieee80211_free_node(ni);
147868651Skris			break;
147968651Skris		}
148068651Skris
148168651Skris		sc->sc_txtimer = 5;
148268651Skris		callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
148368651Skris	}
148468651Skris	URTW_UNLOCK(sc);
148568651Skris}
148668651Skris
148768651Skrisstatic int
148868651Skrisurtw_alloc_data_list(struct urtw_softc *sc, struct urtw_data data[],
148968651Skris    int ndata, int maxsz, void *dma_buf)
149068651Skris{
149168651Skris	int i, error;
149268651Skris
149368651Skris	for (i = 0; i < ndata; i++) {
149468651Skris		struct urtw_data *dp = &data[i];
149568651Skris
149668651Skris		dp->sc = sc;
1497109998Smarkm		if (dma_buf == NULL) {
1498109998Smarkm			dp->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1499109998Smarkm			if (dp->m == NULL) {
1500109998Smarkm				device_printf(sc->sc_dev,
1501109998Smarkm				    "could not allocate rx mbuf\n");
150268651Skris				error = ENOMEM;
150368651Skris				goto fail;
150468651Skris			}
150568651Skris			dp->buf = mtod(dp->m, uint8_t *);
150668651Skris		} else {
150768651Skris			dp->m = NULL;
150868651Skris			dp->buf = ((uint8_t *)dma_buf) +
150968651Skris			    (i * maxsz);
151068651Skris		}
151168651Skris		dp->ni = NULL;
151268651Skris	}
151368651Skris	return (0);
151468651Skris
151568651Skrisfail:	urtw_free_data_list(sc, data, ndata, 1);
151668651Skris	return (error);
151768651Skris}
151868651Skris
151968651Skrisstatic int
152068651Skrisurtw_alloc_rx_data_list(struct urtw_softc *sc)
152168651Skris{
152268651Skris	int error, i;
152368651Skris
152468651Skris	error = urtw_alloc_data_list(sc,
152568651Skris	    sc->sc_rx, URTW_RX_DATA_LIST_COUNT,
152668651Skris	    MCLBYTES, NULL /* mbufs */);
152768651Skris	if (error != 0)
152868651Skris		return (error);
152968651Skris
153068651Skris	STAILQ_INIT(&sc->sc_rx_active);
153168651Skris	STAILQ_INIT(&sc->sc_rx_inactive);
153268651Skris
153368651Skris	for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++)
153468651Skris		STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next);
153568651Skris
153668651Skris	return (0);
153768651Skris}
153868651Skris
153968651Skrisstatic int
154068651Skrisurtw_alloc_tx_data_list(struct urtw_softc *sc)
154168651Skris{
154268651Skris	int error, i;
154368651Skris
154468651Skris	error = urtw_alloc_data_list(sc,
154568651Skris	    sc->sc_tx, URTW_TX_DATA_LIST_COUNT, URTW_TX_MAXSIZE,
154689837Skris	    sc->sc_tx_dma_buf /* no mbufs */);
154768651Skris	if (error != 0)
1548109998Smarkm		return (error);
154968651Skris
155068651Skris	STAILQ_INIT(&sc->sc_tx_active);
155168651Skris	STAILQ_INIT(&sc->sc_tx_inactive);
1552109998Smarkm	STAILQ_INIT(&sc->sc_tx_pending);
155368651Skris
155468651Skris	for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++)
155568651Skris		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i],
155668651Skris		    next);
155768651Skris
155868651Skris	return (0);
1559109998Smarkm}
1560109998Smarkm
1561109998Smarkmstatic int
156268651Skrisurtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
156368651Skris    const struct ieee80211_bpf_params *params)
156468651Skris{
156568651Skris	struct ieee80211com *ic = ni->ni_ic;
156668651Skris	struct ifnet *ifp = ic->ic_ifp;
156768651Skris	struct urtw_data *bf;
156868651Skris	struct urtw_softc *sc = ifp->if_softc;
156968651Skris
157068651Skris	/* prevent management frames from being sent if we're not ready */
157168651Skris	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
157268651Skris		m_freem(m);
157368651Skris		ieee80211_free_node(ni);
157468651Skris		return ENETDOWN;
157568651Skris	}
157668651Skris	URTW_LOCK(sc);
157768651Skris	bf = urtw_getbuf(sc);
157868651Skris	if (bf == NULL) {
1579109998Smarkm		ieee80211_free_node(ni);
158068651Skris		m_freem(m);
158168651Skris		URTW_UNLOCK(sc);
158268651Skris		return (ENOBUFS);		/* XXX */
158368651Skris	}
158468651Skris
158568651Skris	ifp->if_opackets++;
158668651Skris	if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_LOW) != 0) {
158768651Skris		ieee80211_free_node(ni);
158868651Skris		ifp->if_oerrors++;
158968651Skris		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
159068651Skris		URTW_UNLOCK(sc);
159168651Skris		return (EIO);
159268651Skris	}
159368651Skris	URTW_UNLOCK(sc);
159468651Skris
159568651Skris	sc->sc_txtimer = 5;
159668651Skris	return (0);
159768651Skris}
159868651Skris
159968651Skrisstatic void
160068651Skrisurtw_scan_start(struct ieee80211com *ic)
160168651Skris{
160268651Skris
160368651Skris	/* XXX do nothing?  */
160468651Skris}
160568651Skris
160668651Skrisstatic void
160768651Skrisurtw_scan_end(struct ieee80211com *ic)
160868651Skris{
1609109998Smarkm
161068651Skris	/* XXX do nothing?  */
161168651Skris}
161268651Skris
161368651Skrisstatic void
161468651Skrisurtw_set_channel(struct ieee80211com *ic)
161568651Skris{
161668651Skris	struct urtw_softc *sc  = ic->ic_ifp->if_softc;
161768651Skris	struct ifnet *ifp = sc->sc_ifp;
161868651Skris	uint32_t data, orig;
161968651Skris	usb_error_t error;
162068651Skris
162168651Skris	/*
162268651Skris	 * if the user set a channel explicitly using ifconfig(8) this function
162368651Skris	 * can be called earlier than we're expected that in some cases the
162468651Skris	 * initialization would be failed if setting a channel is called before
162568651Skris	 * the init have done.
162668651Skris	 */
162768651Skris	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
162868651Skris		return;
162968651Skris
163068651Skris	if (sc->sc_curchan != NULL && sc->sc_curchan == ic->ic_curchan)
163168651Skris		return;
163268651Skris
1633109998Smarkm	URTW_LOCK(sc);
163468651Skris
163568651Skris	/*
163668651Skris	 * during changing th channel we need to temporarily be disable
1637109998Smarkm	 * TX.
163868651Skris	 */
163968651Skris	urtw_read32_m(sc, URTW_TX_CONF, &orig);
164068651Skris	data = orig & ~URTW_TX_LOOPBACK_MASK;
1641109998Smarkm	urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC);
164268651Skris
164368651Skris	error = sc->sc_rf_set_chan(sc, ieee80211_chan2ieee(ic, ic->ic_curchan));
164468651Skris	if (error != 0)
164568651Skris		goto fail;
164668651Skris	usb_pause_mtx(&sc->sc_mtx, 10);
164768651Skris	urtw_write32_m(sc, URTW_TX_CONF, orig);
164868651Skris
164989837Skris	urtw_write16_m(sc, URTW_ATIM_WND, 2);
165068651Skris	urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
165168651Skris	urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
165268651Skris	urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
165368651Skris
165468651Skrisfail:
165568651Skris	URTW_UNLOCK(sc);
165668651Skris
165768651Skris	sc->sc_curchan = ic->ic_curchan;
165868651Skris
165968651Skris	if (error != 0)
166068651Skris		device_printf(sc->sc_dev, "could not change the channel\n");
1661109998Smarkm}
166268651Skris
166368651Skrisstatic void
166468651Skrisurtw_update_mcast(struct ifnet *ifp)
166568651Skris{
166668651Skris
166768651Skris	/* XXX do nothing?  */
166868651Skris}
1669109998Smarkm
167068651Skrisstatic int
167168651Skrisurtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0,
1672109998Smarkm    struct urtw_data *data, int prior)
167368651Skris{
167468651Skris	struct ifnet *ifp = sc->sc_ifp;
167568651Skris	struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
167668651Skris	struct ieee80211_key *k;
167768651Skris	const struct ieee80211_txparam *tp;
167868651Skris	struct ieee80211com *ic = ifp->if_l2com;
167968651Skris	struct ieee80211vap *vap = ni->ni_vap;
168068651Skris	struct usb_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = {
168168651Skris		sc->sc_xfer[URTW_8187B_BULK_TX_BE],
168268651Skris		sc->sc_xfer[URTW_8187B_BULK_TX_BK],
168368651Skris		sc->sc_xfer[URTW_8187B_BULK_TX_VI],
168468651Skris		sc->sc_xfer[URTW_8187B_BULK_TX_VO]
168568651Skris	};
168668651Skris	struct usb_xfer *xfer;
168768651Skris	int dur = 0, rtsdur = 0, rtsenable = 0, ctsenable = 0, rate,
168868651Skris	    pkttime = 0, txdur = 0, isshort = 0, xferlen;
168968651Skris	uint16_t acktime, rtstime, ctstime;
169068651Skris	uint32_t flags;
169168651Skris	usb_error_t error;
169268651Skris
169368651Skris	URTW_ASSERT_LOCKED(sc);
169468651Skris
169568651Skris	/*
169668651Skris	 * Software crypto.
169768651Skris	 */
169868651Skris	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
169968651Skris		k = ieee80211_crypto_encap(ni, m0);
170068651Skris		if (k == NULL) {
170168651Skris			device_printf(sc->sc_dev,
170268651Skris			    "ieee80211_crypto_encap returns NULL.\n");
170368651Skris			/* XXX we don't expect the fragmented frames  */
1704109998Smarkm			m_freem(m0);
170568651Skris			return (ENOBUFS);
170668651Skris		}
1707109998Smarkm
170868651Skris		/* in case packet header moved, reset pointer */
1709109998Smarkm		wh = mtod(m0, struct ieee80211_frame *);
171068651Skris	}
171168651Skris
171268651Skris	if (ieee80211_radiotap_active_vap(vap)) {
171368651Skris		struct urtw_tx_radiotap_header *tap = &sc->sc_txtap;
171468651Skris
171568651Skris		/* XXX Are variables correct?  */
171668651Skris		tap->wt_flags = 0;
171768651Skris		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
171868651Skris		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
171968651Skris
172068651Skris		ieee80211_radiotap_tx(vap, m0);
172168651Skris	}
172268651Skris
172368651Skris	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT ||
172468651Skris	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) {
172568651Skris		tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
172668651Skris		rate = tp->mgmtrate;
172768651Skris	} else {
172868651Skris		tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
172968651Skris		/* for data frames */
173068651Skris		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
173168651Skris			rate = tp->mcastrate;
173268651Skris		else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
173368651Skris			rate = tp->ucastrate;
173468651Skris		else
173568651Skris			rate = urtw_rtl2rate(sc->sc_currate);
173668651Skris	}
173768651Skris
173868651Skris	sc->sc_stats.txrates[sc->sc_currate]++;
173968651Skris
174068651Skris	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
174168651Skris		txdur = pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
174268651Skris		    IEEE80211_CRC_LEN, rate, 0, 0);
174368651Skris	else {
174468651Skris		acktime = urtw_compute_txtime(14, 2,0, 0);
174568651Skris		if ((m0->m_pkthdr.len + 4) > vap->iv_rtsthreshold) {
174668651Skris			rtsenable = 1;
1747160814Ssimon			ctsenable = 0;
174868651Skris			rtstime = urtw_compute_txtime(URTW_ACKCTS_LEN, 2, 0, 0);
174968651Skris			ctstime = urtw_compute_txtime(14, 2, 0, 0);
175068651Skris			pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
175168651Skris			    IEEE80211_CRC_LEN, rate, 0, isshort);
175268651Skris			rtsdur = ctstime + pkttime + acktime +
175368651Skris			    3 * URTW_ASIFS_TIME;
175468651Skris			txdur = rtstime + rtsdur;
175568651Skris		} else {
1756109998Smarkm			rtsenable = ctsenable = rtsdur = 0;
175768651Skris			pkttime = urtw_compute_txtime(m0->m_pkthdr.len +
175868651Skris			    IEEE80211_CRC_LEN, rate, 0, isshort);
175968651Skris			txdur = pkttime + URTW_ASIFS_TIME + acktime;
176068651Skris		}
176168651Skris
176268651Skris		if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
1763109998Smarkm			dur = urtw_compute_txtime(m0->m_pkthdr.len +
176468651Skris			    IEEE80211_CRC_LEN, rate, 0, isshort) +
1765109998Smarkm			    3 * URTW_ASIFS_TIME +
176668651Skris			    2 * acktime;
176768651Skris		else
176868651Skris			dur = URTW_ASIFS_TIME + acktime;
176968651Skris	}
1770109998Smarkm	*(uint16_t *)wh->i_dur = htole16(dur);
177168651Skris
177268651Skris	xferlen = m0->m_pkthdr.len;
177368651Skris	xferlen += (sc->sc_flags & URTW_RTL8187B) ? (4 * 8) : (4 * 3);
177468651Skris	if ((0 == xferlen % 64) || (0 == xferlen % 512))
177568651Skris		xferlen += 1;
177668651Skris
177768651Skris	memset(data->buf, 0, URTW_TX_MAXSIZE);
177868651Skris	flags = m0->m_pkthdr.len & 0xfff;
177968651Skris	flags |= URTW_TX_FLAG_NO_ENC;
178068651Skris	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
178168651Skris	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) &&
178268651Skris	    (sc->sc_preamble_mode == URTW_PREAMBLE_MODE_SHORT) &&
178368651Skris	    (sc->sc_currate != 0))
178468651Skris		flags |= URTW_TX_FLAG_SPLCP;
178568651Skris	if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
178668651Skris		flags |= URTW_TX_FLAG_MOREFRAG;
178768651Skris
1788109998Smarkm	flags |= (sc->sc_currate & 0xf) << URTW_TX_FLAG_TXRATE_SHIFT;
178968651Skris
179068651Skris	if (sc->sc_flags & URTW_RTL8187B) {
179168651Skris		struct urtw_8187b_txhdr *tx;
179268651Skris
179368651Skris		tx = (struct urtw_8187b_txhdr *)data->buf;
179468651Skris		if (ctsenable)
179568651Skris			flags |= URTW_TX_FLAG_CTS;
179668651Skris		if (rtsenable) {
179768651Skris			flags |= URTW_TX_FLAG_RTS;
179868651Skris			flags |= (urtw_rate2rtl(11) & 0xf) <<
179968651Skris			    URTW_TX_FLAG_RTSRATE_SHIFT;
180068651Skris			tx->rtsdur = rtsdur;
180168651Skris		}
180268651Skris		tx->flag = htole32(flags);
180368651Skris		tx->txdur = txdur;
180468651Skris		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
180568651Skris		    IEEE80211_FC0_TYPE_MGT &&
1806109998Smarkm		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
1807109998Smarkm		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
1808109998Smarkm			tx->retry = 1;
1809280297Sjkim		else
1810296279Sjkim			tx->retry = URTW_TX_MAXRETRY;
1811296279Sjkim		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1));
181268651Skris	} else {
1813276861Sjkim		struct urtw_8187l_txhdr *tx;
181468651Skris
181568651Skris		tx = (struct urtw_8187l_txhdr *)data->buf;
181668651Skris		if (rtsenable) {
181768651Skris			flags |= URTW_TX_FLAG_RTS;
181868651Skris			tx->rtsdur = rtsdur;
181968651Skris		}
182068651Skris		flags |= (urtw_rate2rtl(11) & 0xf) << URTW_TX_FLAG_RTSRATE_SHIFT;
1821194206Ssimon		tx->flag = htole32(flags);
1822109998Smarkm		tx->retry = 3;		/* CW minimum  */
1823194206Ssimon		tx->retry = 7 << 4;	/* CW maximum  */
182468651Skris		tx->retry = URTW_TX_MAXRETRY << 8;	/* retry limitation  */
182568651Skris		m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1));
182668651Skris	}
182768651Skris
182868651Skris	data->buflen = xferlen;
182968651Skris	data->ni = ni;
183068651Skris	data->m = m0;
183168651Skris
183268651Skris	if (sc->sc_flags & URTW_RTL8187B) {
183368651Skris		switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
183468651Skris		case IEEE80211_FC0_TYPE_CTL:
183568651Skris		case IEEE80211_FC0_TYPE_MGT:
183668651Skris			xfer = sc->sc_xfer[URTW_8187B_BULK_TX_EP12];
183768651Skris			break;
183868651Skris		default:
183968651Skris			KASSERT(M_WME_GETAC(m0) < URTW_8187B_TXPIPE_MAX,
184068651Skris			    ("unsupported WME pipe %d", M_WME_GETAC(m0)));
184168651Skris			xfer = rtl8187b_pipes[M_WME_GETAC(m0)];
184268651Skris			break;
184368651Skris		}
184468651Skris	} else
184568651Skris		xfer = (prior == URTW_PRIORITY_LOW) ?
184668651Skris		    sc->sc_xfer[URTW_8187L_BULK_TX_LOW] :
184768651Skris		    sc->sc_xfer[URTW_8187L_BULK_TX_NORMAL];
1848109998Smarkm
184968651Skris	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
185068651Skris	usbd_transfer_start(xfer);
185168651Skris
1852109998Smarkm	error = urtw_led_ctl(sc, URTW_LED_CTL_TX);
1853109998Smarkm	if (error != 0)
185468651Skris		device_printf(sc->sc_dev, "could not control LED (%d)\n",
185568651Skris		    error);
185668651Skris	return (0);
185768651Skris}
185868651Skris
185968651Skrisstatic int
1860109998Smarkmurtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
186168651Skris{
1862109998Smarkm	struct ieee80211com *ic = vap->iv_ic;
186368651Skris	struct urtw_softc *sc = ic->ic_ifp->if_softc;
186468651Skris	struct urtw_vap *uvp = URTW_VAP(vap);
186568651Skris	struct ieee80211_node *ni;
186668651Skris	usb_error_t error = 0;
186768651Skris
186868651Skris	DPRINTF(sc, URTW_DEBUG_STATE, "%s: %s -> %s\n", __func__,
186968651Skris	    ieee80211_state_name[vap->iv_state],
187068651Skris	    ieee80211_state_name[nstate]);
187168651Skris
187268651Skris	sc->sc_state = nstate;
187368651Skris
187468651Skris	IEEE80211_UNLOCK(ic);
187568651Skris	URTW_LOCK(sc);
187668651Skris	usb_callout_stop(&sc->sc_led_ch);
1877109998Smarkm	callout_stop(&sc->sc_watchdog_ch);
1878109998Smarkm
1879109998Smarkm	switch (nstate) {
1880109998Smarkm	case IEEE80211_S_INIT:
188168651Skris	case IEEE80211_S_SCAN:
188268651Skris	case IEEE80211_S_AUTH:
188368651Skris	case IEEE80211_S_ASSOC:
188468651Skris		break;
188576866Skris	case IEEE80211_S_RUN:
188676866Skris		ni = ieee80211_ref_node(vap->iv_bss);
188776866Skris		/* setting bssid.  */
1888111147Snectar		urtw_write32_m(sc, URTW_BSSID, ((uint32_t *)ni->ni_bssid)[0]);
1889111147Snectar		urtw_write16_m(sc, URTW_BSSID + 4,
1890111147Snectar		    ((uint16_t *)ni->ni_bssid)[2]);
1891111147Snectar		urtw_update_msr(sc);
1892100928Snectar		/* XXX maybe the below would be incorrect.  */
1893100928Snectar		urtw_write16_m(sc, URTW_ATIM_WND, 2);
1894111147Snectar		urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
1895100928Snectar		urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64);
1896100928Snectar		urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
1897111147Snectar		error = urtw_led_ctl(sc, URTW_LED_CTL_LINK);
1898100928Snectar		if (error != 0)
1899100928Snectar			device_printf(sc->sc_dev,
1900111147Snectar			    "could not control LED (%d)\n", error);
1901111147Snectar		ieee80211_free_node(ni);
1902111147Snectar		break;
1903111147Snectar	default:
1904111147Snectar		break;
1905111147Snectar	}
1906111147Snectarfail:
1907111147Snectar	URTW_UNLOCK(sc);
1908111147Snectar	IEEE80211_LOCK(ic);
1909111147Snectar	return (uvp->newstate(vap, nstate, arg));
1910111147Snectar}
1911111147Snectar
1912111147Snectarstatic void
1913111147Snectarurtw_watchdog(void *arg)
1914111147Snectar{
1915111147Snectar	struct urtw_softc *sc = arg;
1916111147Snectar	struct ifnet *ifp = sc->sc_ifp;
1917109998Smarkm
1918100928Snectar	if (sc->sc_txtimer > 0) {
1919100928Snectar		if (--sc->sc_txtimer == 0) {
1920111147Snectar			device_printf(sc->sc_dev, "device timeout\n");
1921111147Snectar			ifp->if_oerrors++;
1922111147Snectar			return;
1923100928Snectar		}
1924111147Snectar		callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
1925111147Snectar	}
1926100928Snectar}
1927111147Snectar
1928111147Snectarstatic void
1929111147Snectarurtw_set_multi(void *arg)
1930100928Snectar{
1931111147Snectar	struct urtw_softc *sc = arg;
1932111147Snectar	struct ifnet *ifp = sc->sc_ifp;
1933100928Snectar
1934111147Snectar	if (!(ifp->if_flags & IFF_UP))
1935111147Snectar		return;
1936100928Snectar
1937111147Snectar	/*
1938111147Snectar	 * XXX don't know how to set a device.  Lack of docs.  Just try to set
1939111147Snectar	 * IFF_ALLMULTI flag here.
1940100928Snectar	 */
1941111147Snectar	ifp->if_flags |= IFF_ALLMULTI;
1942100928Snectar}
1943111147Snectar
1944111147Snectarstatic usb_error_t
1945111147Snectarurtw_set_rate(struct urtw_softc *sc)
194689837Skris{
194789837Skris	int i, basic_rate, min_rr_rate, max_rr_rate;
1948298998Sjkim	uint16_t data;
1949109998Smarkm	usb_error_t error;
1950109998Smarkm
1951109998Smarkm	basic_rate = urtw_rate2rtl(48);
1952111147Snectar	min_rr_rate = urtw_rate2rtl(12);
1953111147Snectar	max_rr_rate = urtw_rate2rtl(48);
1954109998Smarkm
1955109998Smarkm	urtw_write8_m(sc, URTW_RESP_RATE,
1956109998Smarkm	    max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
1957109998Smarkm	    min_rr_rate << URTW_RESP_MIN_RATE_SHIFT);
1958109998Smarkm
1959109998Smarkm	urtw_read16_m(sc, URTW_BRSR, &data);
1960109998Smarkm	data &= ~URTW_BRSR_MBR_8185;
1961109998Smarkm
1962109998Smarkm	for (i = 0; i <= basic_rate; i++)
1963109998Smarkm		data |= (1 << i);
1964109998Smarkm
1965109998Smarkm	urtw_write16_m(sc, URTW_BRSR, data);
1966111147Snectarfail:
1967109998Smarkm	return (error);
1968109998Smarkm}
1969109998Smarkm
1970109998Smarkmstatic uint16_t
1971109998Smarkmurtw_rate2rtl(uint32_t rate)
1972109998Smarkm{
1973111147Snectar#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
1974111147Snectar	int i;
1975109998Smarkm
1976109998Smarkm	for (i = 0; i < N(urtw_ratetable); i++) {
1977109998Smarkm		if (rate == urtw_ratetable[i].reg)
1978109998Smarkm			return urtw_ratetable[i].val;
1979109998Smarkm	}
1980109998Smarkm
1981109998Smarkm	return (3);
1982109998Smarkm#undef N
1983109998Smarkm}
1984109998Smarkm
1985109998Smarkmstatic uint16_t
1986109998Smarkmurtw_rtl2rate(uint32_t rate)
1987109998Smarkm{
1988109998Smarkm#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
1989109998Smarkm	int i;
1990109998Smarkm
1991109998Smarkm	for (i = 0; i < N(urtw_ratetable); i++) {
1992109998Smarkm		if (rate == urtw_ratetable[i].val)
1993109998Smarkm			return urtw_ratetable[i].reg;
1994111147Snectar	}
1995109998Smarkm
1996109998Smarkm	return (0);
1997109998Smarkm#undef N
1998109998Smarkm}
1999109998Smarkm
2000109998Smarkmstatic usb_error_t
2001109998Smarkmurtw_update_msr(struct urtw_softc *sc)
2002109998Smarkm{
2003109998Smarkm	struct ifnet *ifp = sc->sc_ifp;
2004109998Smarkm	struct ieee80211com *ic = ifp->if_l2com;
2005109998Smarkm	uint8_t data;
2006109998Smarkm	usb_error_t error;
2007109998Smarkm
2008109998Smarkm	urtw_read8_m(sc, URTW_MSR, &data);
2009109998Smarkm	data &= ~URTW_MSR_LINK_MASK;
2010109998Smarkm
2011109998Smarkm	if (sc->sc_state == IEEE80211_S_RUN) {
2012109998Smarkm		switch (ic->ic_opmode) {
2013109998Smarkm		case IEEE80211_M_STA:
2014109998Smarkm		case IEEE80211_M_MONITOR:
2015109998Smarkm			data |= URTW_MSR_LINK_STA;
2016109998Smarkm			if (sc->sc_flags & URTW_RTL8187B)
2017109998Smarkm				data |= URTW_MSR_LINK_ENEDCA;
2018111147Snectar			break;
2019109998Smarkm		case IEEE80211_M_IBSS:
2020109998Smarkm			data |= URTW_MSR_LINK_ADHOC;
2021109998Smarkm			break;
2022109998Smarkm		case IEEE80211_M_HOSTAP:
2023109998Smarkm			data |= URTW_MSR_LINK_HOSTAP;
2024109998Smarkm			break;
2025109998Smarkm		default:
2026109998Smarkm			DPRINTF(sc, URTW_DEBUG_STATE,
2027109998Smarkm			    "unsupported operation mode 0x%x\n",
2028109998Smarkm			    ic->ic_opmode);
2029109998Smarkm			error = USB_ERR_INVAL;
2030109998Smarkm			goto fail;
2031109998Smarkm		}
2032109998Smarkm	} else
2033109998Smarkm		data |= URTW_MSR_LINK_NONE;
2034109998Smarkm
2035109998Smarkm	urtw_write8_m(sc, URTW_MSR, data);
2036109998Smarkmfail:
2037109998Smarkm	return (error);
2038109998Smarkm}
2039109998Smarkm
2040109998Smarkmstatic usb_error_t
2041109998Smarkmurtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data)
2042109998Smarkm{
2043109998Smarkm	struct usb_device_request req;
2044109998Smarkm	usb_error_t error;
2045109998Smarkm
2046111147Snectar	URTW_ASSERT_LOCKED(sc);
2047109998Smarkm
2048109998Smarkm	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2049109998Smarkm	req.bRequest = URTW_8187_GETREGS_REQ;
2050109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2051109998Smarkm	USETW(req.wIndex, (val >> 8) & 0x3);
2052109998Smarkm	USETW(req.wLength, sizeof(uint8_t));
2053109998Smarkm
2054109998Smarkm	error = urtw_do_request(sc, &req, data);
2055109998Smarkm	return (error);
2056111147Snectar}
2057109998Smarkm
2058109998Smarkmstatic usb_error_t
2059109998Smarkmurtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data)
2060111147Snectar{
2061109998Smarkm	struct usb_device_request req;
2062109998Smarkm	usb_error_t error;
2063109998Smarkm
2064109998Smarkm	URTW_ASSERT_LOCKED(sc);
2065109998Smarkm
2066109998Smarkm	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2067109998Smarkm	req.bRequest = URTW_8187_GETREGS_REQ;
2068109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2069111147Snectar	USETW(req.wIndex, (val >> 8) & 0x3);
2070109998Smarkm	USETW(req.wLength, sizeof(uint16_t));
2071109998Smarkm
2072109998Smarkm	error = urtw_do_request(sc, &req, data);
2073109998Smarkm	return (error);
2074109998Smarkm}
2075109998Smarkm
2076109998Smarkmstatic usb_error_t
2077109998Smarkmurtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data)
2078160814Ssimon{
2079111147Snectar	struct usb_device_request req;
2080109998Smarkm	usb_error_t error;
2081109998Smarkm
2082109998Smarkm	URTW_ASSERT_LOCKED(sc);
2083109998Smarkm
2084109998Smarkm	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2085109998Smarkm	req.bRequest = URTW_8187_GETREGS_REQ;
2086109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2087109998Smarkm	USETW(req.wIndex, (val >> 8) & 0x3);
2088238405Sjkim	USETW(req.wLength, sizeof(uint32_t));
2089109998Smarkm
2090109998Smarkm	error = urtw_do_request(sc, &req, data);
2091109998Smarkm	return (error);
2092109998Smarkm}
2093109998Smarkm
2094109998Smarkmstatic usb_error_t
2095109998Smarkmurtw_write8_c(struct urtw_softc *sc, int val, uint8_t data)
2096194206Ssimon{
2097109998Smarkm	struct usb_device_request req;
2098109998Smarkm
2099109998Smarkm	URTW_ASSERT_LOCKED(sc);
2100109998Smarkm
2101109998Smarkm	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2102109998Smarkm	req.bRequest = URTW_8187_SETREGS_REQ;
2103109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2104109998Smarkm	USETW(req.wIndex, (val >> 8) & 0x3);
2105111147Snectar	USETW(req.wLength, sizeof(uint8_t));
2106111147Snectar
2107111147Snectar	return (urtw_do_request(sc, &req, &data));
2108111147Snectar}
2109109998Smarkm
2110111147Snectarstatic usb_error_t
2111109998Smarkmurtw_write16_c(struct urtw_softc *sc, int val, uint16_t data)
2112109998Smarkm{
2113111147Snectar	struct usb_device_request req;
2114111147Snectar
2115109998Smarkm	URTW_ASSERT_LOCKED(sc);
2116109998Smarkm
2117109998Smarkm	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2118109998Smarkm	req.bRequest = URTW_8187_SETREGS_REQ;
2119109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2120109998Smarkm	USETW(req.wIndex, (val >> 8) & 0x3);
2121109998Smarkm	USETW(req.wLength, sizeof(uint16_t));
2122109998Smarkm
2123109998Smarkm	return (urtw_do_request(sc, &req, &data));
2124109998Smarkm}
2125109998Smarkm
2126109998Smarkmstatic usb_error_t
2127111147Snectarurtw_write32_c(struct urtw_softc *sc, int val, uint32_t data)
2128109998Smarkm{
2129109998Smarkm	struct usb_device_request req;
2130109998Smarkm
2131109998Smarkm	URTW_ASSERT_LOCKED(sc);
2132109998Smarkm
2133109998Smarkm	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2134109998Smarkm	req.bRequest = URTW_8187_SETREGS_REQ;
2135109998Smarkm	USETW(req.wValue, (val & 0xff) | 0xff00);
2136109998Smarkm	USETW(req.wIndex, (val >> 8) & 0x3);
2137109998Smarkm	USETW(req.wLength, sizeof(uint32_t));
2138109998Smarkm
2139109998Smarkm	return (urtw_do_request(sc, &req, &data));
2140109998Smarkm}
2141109998Smarkm
2142109998Smarkmstatic usb_error_t
2143109998Smarkmurtw_get_macaddr(struct urtw_softc *sc)
2144109998Smarkm{
2145109998Smarkm	uint32_t data;
2146109998Smarkm	usb_error_t error;
2147109998Smarkm
2148109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
2149109998Smarkm	if (error != 0)
2150109998Smarkm		goto fail;
2151109998Smarkm	sc->sc_bssid[0] = data & 0xff;
2152109998Smarkm	sc->sc_bssid[1] = (data & 0xff00) >> 8;
2153109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
2154109998Smarkm	if (error != 0)
2155109998Smarkm		goto fail;
2156109998Smarkm	sc->sc_bssid[2] = data & 0xff;
2157109998Smarkm	sc->sc_bssid[3] = (data & 0xff00) >> 8;
2158109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
2159109998Smarkm	if (error != 0)
2160109998Smarkm		goto fail;
2161109998Smarkm	sc->sc_bssid[4] = data & 0xff;
2162109998Smarkm	sc->sc_bssid[5] = (data & 0xff00) >> 8;
2163111147Snectarfail:
2164109998Smarkm	return (error);
2165109998Smarkm}
2166109998Smarkm
2167109998Smarkmstatic usb_error_t
2168109998Smarkmurtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
2169109998Smarkm{
2170109998Smarkm#define URTW_READCMD_LEN		3
2171109998Smarkm	int addrlen, i;
2172109998Smarkm	int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
2173109998Smarkm	usb_error_t error;
2174109998Smarkm
2175109998Smarkm	/* NB: make sure the buffer is initialized  */
2176109998Smarkm	*data = 0;
2177109998Smarkm
2178109998Smarkm	/* enable EPROM programming */
2179109998Smarkm	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE);
2180109998Smarkm	DELAY(URTW_EPROM_DELAY);
2181109998Smarkm
2182109998Smarkm	error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
2183109998Smarkm	if (error != 0)
2184109998Smarkm		goto fail;
2185109998Smarkm	error = urtw_eprom_ck(sc);
2186109998Smarkm	if (error != 0)
2187109998Smarkm		goto fail;
2188109998Smarkm	error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
2189109998Smarkm	if (error != 0)
2190109998Smarkm		goto fail;
2191111147Snectar	if (sc->sc_epromtype == URTW_EEPROM_93C56) {
2192109998Smarkm		addrlen = 8;
2193109998Smarkm		addrstr[0] = addr & (1 << 7);
2194109998Smarkm		addrstr[1] = addr & (1 << 6);
2195109998Smarkm		addrstr[2] = addr & (1 << 5);
2196109998Smarkm		addrstr[3] = addr & (1 << 4);
2197109998Smarkm		addrstr[4] = addr & (1 << 3);
2198109998Smarkm		addrstr[5] = addr & (1 << 2);
2199109998Smarkm		addrstr[6] = addr & (1 << 1);
2200109998Smarkm		addrstr[7] = addr & (1 << 0);
2201109998Smarkm	} else {
2202109998Smarkm		addrlen=6;
2203109998Smarkm		addrstr[0] = addr & (1 << 5);
2204109998Smarkm		addrstr[1] = addr & (1 << 4);
2205109998Smarkm		addrstr[2] = addr & (1 << 3);
2206109998Smarkm		addrstr[3] = addr & (1 << 2);
2207109998Smarkm		addrstr[4] = addr & (1 << 1);
2208109998Smarkm		addrstr[5] = addr & (1 << 0);
2209109998Smarkm	}
2210109998Smarkm	error = urtw_eprom_sendbits(sc, addrstr, addrlen);
2211109998Smarkm	if (error != 0)
2212109998Smarkm		goto fail;
2213111147Snectar
2214109998Smarkm	error = urtw_eprom_writebit(sc, 0);
2215109998Smarkm	if (error != 0)
2216109998Smarkm		goto fail;
2217109998Smarkm
2218109998Smarkm	for (i = 0; i < 16; i++) {
2219109998Smarkm		error = urtw_eprom_ck(sc);
2220109998Smarkm		if (error != 0)
2221109998Smarkm			goto fail;
2222109998Smarkm		error = urtw_eprom_readbit(sc, &data16);
2223109998Smarkm		if (error != 0)
2224109998Smarkm			goto fail;
2225109998Smarkm
2226111147Snectar		(*data) |= (data16 << (15 - i));
2227109998Smarkm	}
2228109998Smarkm
2229111147Snectar	error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
2230109998Smarkm	if (error != 0)
2231109998Smarkm		goto fail;
2232109998Smarkm	error = urtw_eprom_ck(sc);
2233111147Snectar	if (error != 0)
2234109998Smarkm		goto fail;
2235111147Snectar
2236109998Smarkm	/* now disable EPROM programming */
2237109998Smarkm	urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE);
2238109998Smarkmfail:
2239109998Smarkm	return (error);
2240109998Smarkm#undef URTW_READCMD_LEN
2241109998Smarkm}
2242109998Smarkm
2243109998Smarkmstatic usb_error_t
2244109998Smarkmurtw_eprom_cs(struct urtw_softc *sc, int able)
2245109998Smarkm{
2246109998Smarkm	uint8_t data;
2247109998Smarkm	usb_error_t error;
2248109998Smarkm
2249109998Smarkm	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2250109998Smarkm	if (able == URTW_EPROM_ENABLE)
2251109998Smarkm		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS);
2252109998Smarkm	else
2253109998Smarkm		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS);
2254109998Smarkm	DELAY(URTW_EPROM_DELAY);
2255109998Smarkmfail:
2256109998Smarkm	return (error);
2257109998Smarkm}
2258109998Smarkm
2259109998Smarkmstatic usb_error_t
2260109998Smarkmurtw_eprom_ck(struct urtw_softc *sc)
2261109998Smarkm{
2262109998Smarkm	uint8_t data;
2263109998Smarkm	usb_error_t error;
2264109998Smarkm
2265109998Smarkm	/* masking  */
2266109998Smarkm	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2267109998Smarkm	urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK);
2268109998Smarkm	DELAY(URTW_EPROM_DELAY);
2269109998Smarkm	/* unmasking  */
2270109998Smarkm	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2271109998Smarkm	urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK);
2272111147Snectar	DELAY(URTW_EPROM_DELAY);
2273109998Smarkmfail:
2274109998Smarkm	return (error);
2275109998Smarkm}
2276109998Smarkm
2277109998Smarkmstatic usb_error_t
2278109998Smarkmurtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
2279109998Smarkm{
2280109998Smarkm	uint8_t data8;
2281109998Smarkm	usb_error_t error;
2282109998Smarkm
2283109998Smarkm	urtw_read8_m(sc, URTW_EPROM_CMD, &data8);
2284109998Smarkm	*data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
2285109998Smarkm	DELAY(URTW_EPROM_DELAY);
2286109998Smarkm
2287109998Smarkmfail:
2288109998Smarkm	return (error);
2289109998Smarkm}
2290109998Smarkm
2291109998Smarkmstatic usb_error_t
2292109998Smarkmurtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
2293109998Smarkm{
2294109998Smarkm	uint8_t data;
2295109998Smarkm	usb_error_t error;
2296111147Snectar
2297109998Smarkm	urtw_read8_m(sc, URTW_EPROM_CMD, &data);
2298109998Smarkm	if (bit != 0)
2299109998Smarkm		urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT);
2300109998Smarkm	else
2301109998Smarkm		urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT);
2302111147Snectar	DELAY(URTW_EPROM_DELAY);
2303109998Smarkmfail:
2304109998Smarkm	return (error);
2305111147Snectar}
2306109998Smarkm
2307109998Smarkmstatic usb_error_t
2308109998Smarkmurtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
2309109998Smarkm{
2310109998Smarkm	int i = 0;
2311109998Smarkm	usb_error_t error = 0;
2312109998Smarkm
2313109998Smarkm	for (i = 0; i < buflen; i++) {
2314109998Smarkm		error = urtw_eprom_writebit(sc, buf[i]);
2315109998Smarkm		if (error != 0)
2316111147Snectar			goto fail;
2317109998Smarkm		error = urtw_eprom_ck(sc);
2318109998Smarkm		if (error != 0)
2319109998Smarkm			goto fail;
2320109998Smarkm	}
2321109998Smarkmfail:
2322109998Smarkm	return (error);
2323109998Smarkm}
2324109998Smarkm
2325109998Smarkm
2326109998Smarkmstatic usb_error_t
2327109998Smarkmurtw_get_txpwr(struct urtw_softc *sc)
2328109998Smarkm{
2329109998Smarkm	int i, j;
2330109998Smarkm	uint32_t data;
2331109998Smarkm	usb_error_t error;
2332109998Smarkm
2333109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
2334109998Smarkm	if (error != 0)
2335109998Smarkm		goto fail;
2336109998Smarkm	sc->sc_txpwr_cck_base = data & 0xf;
2337109998Smarkm	sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
2338109998Smarkm
2339109998Smarkm	for (i = 1, j = 0; i < 6; i += 2, j++) {
2340109998Smarkm		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
2341109998Smarkm		if (error != 0)
2342109998Smarkm			goto fail;
2343109998Smarkm		sc->sc_txpwr_cck[i] = data & 0xf;
2344109998Smarkm		sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
2345109998Smarkm		sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
2346109998Smarkm		sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
2347109998Smarkm	}
2348109998Smarkm	for (i = 1, j = 0; i < 4; i += 2, j++) {
2349109998Smarkm		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
2350111147Snectar		if (error != 0)
2351109998Smarkm			goto fail;
2352109998Smarkm		sc->sc_txpwr_cck[i + 6] = data & 0xf;
2353109998Smarkm		sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
2354109998Smarkm		sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
2355109998Smarkm		sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
2356109998Smarkm	}
2357109998Smarkm	if (sc->sc_flags & URTW_RTL8187B) {
2358109998Smarkm		error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2, &data);
2359109998Smarkm		if (error != 0)
2360109998Smarkm			goto fail;
2361109998Smarkm		sc->sc_txpwr_cck[1 + 6 + 4] = data & 0xf;
2362109998Smarkm		sc->sc_txpwr_ofdm[1 + 6 + 4] = (data & 0xf0) >> 4;
2363109998Smarkm		error = urtw_eprom_read32(sc, 0x0a, &data);
2364109998Smarkm		if (error != 0)
2365109998Smarkm			goto fail;
2366109998Smarkm		sc->sc_txpwr_cck[2 + 6 + 4] = data & 0xf;
2367109998Smarkm		sc->sc_txpwr_ofdm[2 + 6 + 4] = (data & 0xf0) >> 4;
2368109998Smarkm		error = urtw_eprom_read32(sc, 0x1c, &data);
2369109998Smarkm		if (error != 0)
2370109998Smarkm			goto fail;
2371109998Smarkm		sc->sc_txpwr_cck[3 + 6 + 4] = data & 0xf;
2372109998Smarkm		sc->sc_txpwr_cck[3 + 6 + 4 + 1] = (data & 0xf00) >> 8;
2373109998Smarkm		sc->sc_txpwr_ofdm[3 + 6 + 4] = (data & 0xf0) >> 4;
2374111147Snectar		sc->sc_txpwr_ofdm[3 + 6 + 4 + 1] = (data & 0xf000) >> 12;
2375109998Smarkm	} else {
2376109998Smarkm		for (i = 1, j = 0; i < 4; i += 2, j++) {
2377109998Smarkm			error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
2378109998Smarkm			    &data);
2379109998Smarkm			if (error != 0)
2380109998Smarkm				goto fail;
2381109998Smarkm			sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
2382109998Smarkm			sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
2383109998Smarkm			sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
2384109998Smarkm			sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = (data & 0xf000) >> 12;
2385109998Smarkm		}
2386109998Smarkm	}
2387109998Smarkmfail:
2388109998Smarkm	return (error);
2389109998Smarkm}
2390109998Smarkm
2391111147Snectar
2392109998Smarkmstatic usb_error_t
2393109998Smarkmurtw_get_rfchip(struct urtw_softc *sc)
2394109998Smarkm{
2395109998Smarkm	int ret;
2396109998Smarkm	uint8_t data8;
2397109998Smarkm	uint32_t data;
2398109998Smarkm	usb_error_t error;
2399109998Smarkm
2400109998Smarkm	if (sc->sc_flags & URTW_RTL8187B) {
2401109998Smarkm		urtw_read8_m(sc, 0xe1, &data8);
2402111147Snectar		switch (data8) {
2403109998Smarkm		case 0:
2404109998Smarkm			sc->sc_flags |= URTW_RTL8187B_REV_B;
2405109998Smarkm			break;
2406109998Smarkm		case 1:
2407109998Smarkm			sc->sc_flags |= URTW_RTL8187B_REV_D;
2408109998Smarkm			break;
2409109998Smarkm		case 2:
2410111147Snectar			sc->sc_flags |= URTW_RTL8187B_REV_E;
2411109998Smarkm			break;
2412109998Smarkm		default:
2413109998Smarkm			device_printf(sc->sc_dev, "unknown type: %#x\n", data8);
2414109998Smarkm			sc->sc_flags |= URTW_RTL8187B_REV_B;
2415111147Snectar			break;
2416109998Smarkm		}
2417109998Smarkm	} else {
2418109998Smarkm		urtw_read32_m(sc, URTW_TX_CONF, &data);
2419109998Smarkm		switch (data & URTW_TX_HWMASK) {
2420109998Smarkm		case URTW_TX_R8187vD_B:
2421109998Smarkm			sc->sc_flags |= URTW_RTL8187B;
2422109998Smarkm			break;
2423111147Snectar		case URTW_TX_R8187vD:
2424111147Snectar			break;
2425109998Smarkm		default:
2426160814Ssimon			device_printf(sc->sc_dev, "unknown RTL8187L type: %#x\n",
2427109998Smarkm			    data & URTW_TX_HWMASK);
2428109998Smarkm			break;
2429109998Smarkm		}
2430109998Smarkm	}
2431109998Smarkm
2432109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
2433109998Smarkm	if (error != 0)
2434109998Smarkm		goto fail;
2435109998Smarkm	switch (data & 0xff) {
2436109998Smarkm	case URTW_EPROM_RFCHIPID_RTL8225U:
2437109998Smarkm		error = urtw_8225_isv2(sc, &ret);
2438109998Smarkm		if (error != 0)
2439109998Smarkm			goto fail;
2440109998Smarkm		if (ret == 0) {
2441109998Smarkm			sc->sc_rf_init = urtw_8225_rf_init;
2442109998Smarkm			sc->sc_rf_set_sens = urtw_8225_rf_set_sens;
2443109998Smarkm			sc->sc_rf_set_chan = urtw_8225_rf_set_chan;
2444109998Smarkm			sc->sc_rf_stop = urtw_8225_rf_stop;
2445111147Snectar		} else {
2446109998Smarkm			sc->sc_rf_init = urtw_8225v2_rf_init;
2447109998Smarkm			sc->sc_rf_set_chan = urtw_8225v2_rf_set_chan;
2448109998Smarkm			sc->sc_rf_stop = urtw_8225_rf_stop;
2449111147Snectar		}
2450109998Smarkm		sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
2451109998Smarkm		sc->sc_sens = URTW_8225_RF_DEF_SENS;
2452109998Smarkm		break;
2453109998Smarkm	case URTW_EPROM_RFCHIPID_RTL8225Z2:
2454109998Smarkm		sc->sc_rf_init = urtw_8225v2b_rf_init;
2455109998Smarkm		sc->sc_rf_set_chan = urtw_8225v2b_rf_set_chan;
2456109998Smarkm		sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
2457109998Smarkm		sc->sc_sens = URTW_8225_RF_DEF_SENS;
2458111147Snectar		sc->sc_rf_stop = urtw_8225_rf_stop;
2459109998Smarkm		break;
2460109998Smarkm	default:
2461109998Smarkm		DPRINTF(sc, URTW_DEBUG_STATE,
2462109998Smarkm		    "unsupported RF chip %d\n", data & 0xff);
2463109998Smarkm		error = USB_ERR_INVAL;
2464109998Smarkm		goto fail;
2465109998Smarkm	}
2466109998Smarkm
2467109998Smarkm	device_printf(sc->sc_dev, "%s rf %s hwrev %s\n",
2468109998Smarkm	    (sc->sc_flags & URTW_RTL8187B) ? "rtl8187b" : "rtl8187l",
2469109998Smarkm	    ((data & 0xff) == URTW_EPROM_RFCHIPID_RTL8225U) ? "rtl8225u" :
2470109998Smarkm	    "rtl8225z2",
2471109998Smarkm	    (sc->sc_flags & URTW_RTL8187B) ? ((data8 == 0) ? "b" :
2472109998Smarkm		(data8 == 1) ? "d" : "e") : "none");
2473109998Smarkm
2474109998Smarkmfail:
2475109998Smarkm	return (error);
2476109998Smarkm}
2477109998Smarkm
2478109998Smarkm
2479109998Smarkmstatic usb_error_t
2480109998Smarkmurtw_led_init(struct urtw_softc *sc)
2481109998Smarkm{
2482111147Snectar	uint32_t rev;
2483109998Smarkm	usb_error_t error;
2484109998Smarkm
2485109998Smarkm	urtw_read8_m(sc, URTW_PSR, &sc->sc_psr);
2486109998Smarkm	error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
2487109998Smarkm	if (error != 0)
2488109998Smarkm		goto fail;
2489109998Smarkm
2490109998Smarkm	switch (rev & URTW_EPROM_CID_MASK) {
2491109998Smarkm	case URTW_EPROM_CID_ALPHA0:
2492109998Smarkm		sc->sc_strategy = URTW_SW_LED_MODE1;
2493109998Smarkm		break;
2494111147Snectar	case URTW_EPROM_CID_SERCOMM_PS:
2495109998Smarkm		sc->sc_strategy = URTW_SW_LED_MODE3;
2496109998Smarkm		break;
2497109998Smarkm	case URTW_EPROM_CID_HW_LED:
2498109998Smarkm		sc->sc_strategy = URTW_HW_LED;
2499109998Smarkm		break;
2500109998Smarkm	case URTW_EPROM_CID_RSVD0:
2501109998Smarkm	case URTW_EPROM_CID_RSVD1:
2502109998Smarkm	default:
2503109998Smarkm		sc->sc_strategy = URTW_SW_LED_MODE0;
2504109998Smarkm		break;
2505109998Smarkm	}
2506109998Smarkm
2507109998Smarkm	sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
2508111147Snectar
2509109998Smarkmfail:
2510109998Smarkm	return (error);
2511109998Smarkm}
2512109998Smarkm
2513109998Smarkm
2514109998Smarkmstatic usb_error_t
2515109998Smarkmurtw_8225_rf_init(struct urtw_softc *sc)
2516109998Smarkm{
2517109998Smarkm#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
2518109998Smarkm	int i;
2519109998Smarkm	uint16_t data;
2520109998Smarkm	usb_error_t error;
2521109998Smarkm
2522109998Smarkm	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
2523109998Smarkm	if (error)
2524109998Smarkm		goto fail;
2525109998Smarkm
2526109998Smarkm	error = urtw_8225_usb_init(sc);
2527109998Smarkm	if (error)
2528109998Smarkm		goto fail;
2529109998Smarkm
2530111147Snectar	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
2531111147Snectar	urtw_read16_m(sc, URTW_BRSR, &data);		/* XXX ??? */
2532109998Smarkm	urtw_write16_m(sc, URTW_BRSR, 0xffff);
2533109998Smarkm	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
2534109998Smarkm
2535109998Smarkm	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2536109998Smarkm	if (error)
2537109998Smarkm		goto fail;
2538109998Smarkm	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
2539109998Smarkm	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2540109998Smarkm	if (error)
2541109998Smarkm		goto fail;
2542109998Smarkm
2543109998Smarkm	error = urtw_8185_rf_pins_enable(sc);
2544109998Smarkm	if (error)
2545109998Smarkm		goto fail;
2546109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 1000);
2547109998Smarkm
2548109998Smarkm	for (i = 0; i < N(urtw_8225_rf_part1); i++) {
2549109998Smarkm		urtw_8225_write(sc, urtw_8225_rf_part1[i].reg,
2550109998Smarkm		    urtw_8225_rf_part1[i].val);
2551109998Smarkm		usb_pause_mtx(&sc->sc_mtx, 1);
2552160814Ssimon	}
2553109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 100);
2554111147Snectar	urtw_8225_write(sc,
2555109998Smarkm	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2556109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 200);
2557109998Smarkm	urtw_8225_write(sc,
2558109998Smarkm	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2559109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 200);
2560109998Smarkm	urtw_8225_write(sc,
2561109998Smarkm	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC3);
2562109998Smarkm
2563109998Smarkm	for (i = 0; i < 95; i++) {
2564109998Smarkm		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
2565109998Smarkm		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, urtw_8225_rxgain[i]);
2566109998Smarkm	}
2567109998Smarkm
2568109998Smarkm	urtw_8225_write(sc,
2569109998Smarkm	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC4);
2570109998Smarkm	urtw_8225_write(sc,
2571109998Smarkm	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC5);
2572111147Snectar
2573109998Smarkm	for (i = 0; i < 128; i++) {
2574109998Smarkm		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
2575109998Smarkm		usb_pause_mtx(&sc->sc_mtx, 1);
2576109998Smarkm		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
2577109998Smarkm		usb_pause_mtx(&sc->sc_mtx, 1);
2578109998Smarkm	}
2579109998Smarkm
2580109998Smarkm	for (i = 0; i < N(urtw_8225_rf_part2); i++) {
2581109998Smarkm		urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg,
2582109998Smarkm		    urtw_8225_rf_part2[i].val);
2583160814Ssimon		usb_pause_mtx(&sc->sc_mtx, 1);
2584109998Smarkm	}
2585109998Smarkm
2586109998Smarkm	error = urtw_8225_setgain(sc, 4);
2587109998Smarkm	if (error)
2588109998Smarkm		goto fail;
2589109998Smarkm
2590109998Smarkm	for (i = 0; i < N(urtw_8225_rf_part3); i++) {
2591109998Smarkm		urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg,
2592109998Smarkm		    urtw_8225_rf_part3[i].val);
2593109998Smarkm		usb_pause_mtx(&sc->sc_mtx, 1);
2594109998Smarkm	}
2595109998Smarkm
2596109998Smarkm	urtw_write8_m(sc, URTW_TESTR, 0x0d);
2597109998Smarkm
2598109998Smarkm	error = urtw_8225_set_txpwrlvl(sc, 1);
2599109998Smarkm	if (error)
2600109998Smarkm		goto fail;
2601109998Smarkm
2602109998Smarkm	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
2603109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 1);
2604109998Smarkm	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
2605111147Snectar	usb_pause_mtx(&sc->sc_mtx, 1);
2606109998Smarkm
2607160814Ssimon	/* TX ant A, 0x0 for B */
2608109998Smarkm	error = urtw_8185_tx_antenna(sc, 0x3);
2609109998Smarkm	if (error)
2610109998Smarkm		goto fail;
2611109998Smarkm	urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
2612109998Smarkm
2613111147Snectar	error = urtw_8225_rf_set_chan(sc, 1);
2614109998Smarkmfail:
2615109998Smarkm	return (error);
2616109998Smarkm#undef N
2617109998Smarkm}
2618109998Smarkm
2619109998Smarkmstatic usb_error_t
2620109998Smarkmurtw_8185_rf_pins_enable(struct urtw_softc *sc)
2621109998Smarkm{
2622109998Smarkm	usb_error_t error = 0;
2623109998Smarkm
2624109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7);
2625109998Smarkmfail:
2626109998Smarkm	return (error);
2627109998Smarkm}
2628109998Smarkm
2629109998Smarkmstatic usb_error_t
2630109998Smarkmurtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
2631109998Smarkm{
2632109998Smarkm	usb_error_t error;
2633109998Smarkm
2634109998Smarkm	urtw_write8_m(sc, URTW_TX_ANTENNA, ant);
2635109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 1);
2636109998Smarkmfail:
2637109998Smarkm	return (error);
2638109998Smarkm}
2639109998Smarkm
2640109998Smarkmstatic usb_error_t
2641109998Smarkmurtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2642109998Smarkm{
2643109998Smarkm
2644109998Smarkm	data = data & 0xff;
2645109998Smarkm	return urtw_8187_write_phy(sc, addr, data);
2646109998Smarkm}
2647109998Smarkm
2648109998Smarkmstatic usb_error_t
2649109998Smarkmurtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2650109998Smarkm{
2651109998Smarkm
2652109998Smarkm	data = data & 0xff;
2653109998Smarkm	return urtw_8187_write_phy(sc, addr, data | 0x10000);
2654109998Smarkm}
2655109998Smarkm
2656109998Smarkmstatic usb_error_t
2657109998Smarkmurtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
2658109998Smarkm{
2659109998Smarkm	uint32_t phyw;
2660109998Smarkm	usb_error_t error;
2661109998Smarkm
2662109998Smarkm	phyw = ((data << 8) | (addr | 0x80));
2663109998Smarkm	urtw_write8_m(sc, URTW_PHY_MAGIC4, ((phyw & 0xff000000) >> 24));
2664109998Smarkm	urtw_write8_m(sc, URTW_PHY_MAGIC3, ((phyw & 0x00ff0000) >> 16));
2665109998Smarkm	urtw_write8_m(sc, URTW_PHY_MAGIC2, ((phyw & 0x0000ff00) >> 8));
2666109998Smarkm	urtw_write8_m(sc, URTW_PHY_MAGIC1, ((phyw & 0x000000ff)));
2667109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 1);
2668109998Smarkmfail:
2669109998Smarkm	return (error);
2670109998Smarkm}
2671109998Smarkm
2672109998Smarkmstatic usb_error_t
2673109998Smarkmurtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
2674160814Ssimon{
2675109998Smarkm	usb_error_t error;
2676109998Smarkm
2677109998Smarkm	urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]);
2678109998Smarkm	urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]);
2679109998Smarkm	urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]);
2680109998Smarkm	urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]);
2681109998Smarkmfail:
2682109998Smarkm	return (error);
2683109998Smarkm}
2684109998Smarkm
2685109998Smarkmstatic usb_error_t
2686109998Smarkmurtw_8225_usb_init(struct urtw_softc *sc)
2687109998Smarkm{
2688109998Smarkm	uint8_t data;
2689109998Smarkm	usb_error_t error;
2690109998Smarkm
2691109998Smarkm	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0);
2692111147Snectar	urtw_write8_m(sc, URTW_GPIO, 0);
2693109998Smarkm	error = urtw_read8e(sc, 0x53, &data);
2694109998Smarkm	if (error)
2695109998Smarkm		goto fail;
2696109998Smarkm	error = urtw_write8e(sc, 0x53, data | (1 << 7));
2697109998Smarkm	if (error)
2698109998Smarkm		goto fail;
2699109998Smarkm	urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4);
2700109998Smarkm	urtw_write8_m(sc, URTW_GPIO, 0x20);
2701109998Smarkm	urtw_write8_m(sc, URTW_GP_ENABLE, 0);
2702109998Smarkm
2703109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80);
2704109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80);
2705109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80);
2706109998Smarkm
2707109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 500);
2708109998Smarkmfail:
2709109998Smarkm	return (error);
2710109998Smarkm}
2711109998Smarkm
2712109998Smarkmstatic usb_error_t
2713109998Smarkmurtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
2714109998Smarkm{
2715109998Smarkm	uint16_t d80, d82, d84;
2716111147Snectar	usb_error_t error;
2717109998Smarkm
2718109998Smarkm	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80);
2719109998Smarkm	d80 &= URTW_RF_PINS_MAGIC1;
2720109998Smarkm	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82);
2721109998Smarkm	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84);
2722109998Smarkm	d84 &= URTW_RF_PINS_MAGIC2;
2723109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | URTW_RF_PINS_MAGIC3);
2724109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | URTW_RF_PINS_MAGIC3);
2725109998Smarkm	DELAY(10);
2726109998Smarkm
2727109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2728111147Snectar	DELAY(2);
2729111147Snectar	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80);
2730109998Smarkm	DELAY(10);
2731109998Smarkm
2732109998Smarkm	error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
2733109998Smarkm	if (error != 0)
2734109998Smarkm		goto fail;
2735109998Smarkm
2736109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2737109998Smarkm	DELAY(10);
2738109998Smarkm	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
2739238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84);
2740238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 2);
2741109998Smarkmfail:
2742109998Smarkm	return (error);
2743111147Snectar}
2744109998Smarkm
2745109998Smarkmstatic usb_error_t
2746109998Smarkmurtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
2747109998Smarkm    uint16_t *data)
2748109998Smarkm{
2749109998Smarkm	uint8_t buf[2];
2750109998Smarkm	uint16_t data16;
2751109998Smarkm	struct usb_device_request req;
2752109998Smarkm	usb_error_t error = 0;
2753109998Smarkm
2754109998Smarkm	data16 = *data;
2755109998Smarkm
2756109998Smarkm	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2757109998Smarkm	req.bRequest = URTW_8187_SETREGS_REQ;
2758109998Smarkm	USETW(req.wValue, addr);
2759109998Smarkm	USETW(req.wIndex, index);
2760109998Smarkm	USETW(req.wLength, sizeof(uint16_t));
2761111147Snectar	buf[0] = (data16 & 0x00ff);
2762109998Smarkm	buf[1] = (data16 & 0xff00) >> 8;
2763109998Smarkm
2764109998Smarkm	error = urtw_do_request(sc, &req, buf);
2765109998Smarkm
2766109998Smarkm	return (error);
2767109998Smarkm}
2768109998Smarkm
2769160814Ssimonstatic usb_error_t
2770160814Ssimonurtw_8225_rf_set_chan(struct urtw_softc *sc, int chan)
2771109998Smarkm{
2772109998Smarkm	usb_error_t error;
2773109998Smarkm
2774109998Smarkm	error = urtw_8225_set_txpwrlvl(sc, chan);
2775109998Smarkm	if (error)
2776109998Smarkm		goto fail;
2777109998Smarkm	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
2778109998Smarkm	usb_pause_mtx(&sc->sc_mtx, 10);
2779160814Ssimonfail:
2780109998Smarkm	return (error);
2781109998Smarkm}
2782109998Smarkm
2783142425Snectarstatic usb_error_t
2784142425Snectarurtw_8225_rf_set_sens(struct urtw_softc *sc, int sens)
2785109998Smarkm{
2786142425Snectar	usb_error_t error;
2787109998Smarkm
2788109998Smarkm	if (sens < 0 || sens > 6)
2789109998Smarkm		return -1;
2790109998Smarkm
2791109998Smarkm	if (sens > 4)
2792109998Smarkm		urtw_8225_write(sc,
2793109998Smarkm		    URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC1);
2794109998Smarkm	else
2795109998Smarkm		urtw_8225_write(sc,
2796109998Smarkm		    URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC2);
2797109998Smarkm
2798109998Smarkm	sens = 6 - sens;
2799109998Smarkm	error = urtw_8225_setgain(sc, sens);
2800111147Snectar	if (error)
2801109998Smarkm		goto fail;
2802109998Smarkm
2803109998Smarkm	urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[sens]);
2804109998Smarkm
2805109998Smarkmfail:
2806109998Smarkm	return (error);
2807109998Smarkm}
2808120631Snectar
2809120631Snectarstatic usb_error_t
2810142425Snectarurtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
2811238405Sjkim{
2812238405Sjkim	int i, idx, set;
2813142425Snectar	uint8_t *cck_pwltable;
2814142425Snectar	uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
2815238405Sjkim	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
2816238405Sjkim	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
2817142425Snectar	usb_error_t error;
2818160814Ssimon
2819142425Snectar	cck_pwrlvl_max = 11;
2820142425Snectar	ofdm_pwrlvl_max = 25;	/* 12 -> 25  */
2821160814Ssimon	ofdm_pwrlvl_min = 10;
2822238405Sjkim
2823142425Snectar	/* CCK power setting */
2824238405Sjkim	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
2825238405Sjkim	idx = cck_pwrlvl % 6;
2826142425Snectar	set = cck_pwrlvl / 6;
2827238405Sjkim	cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
2828160814Ssimon	    urtw_8225_txpwr_cck;
2829142425Snectar
2830238405Sjkim	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
2831160814Ssimon	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2832238405Sjkim	for (i = 0; i < 8; i++) {
2833142425Snectar		urtw_8187_write_phy_cck(sc, 0x44 + i,
2834238405Sjkim		    cck_pwltable[idx * 8 + i]);
2835238405Sjkim	}
2836238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
2837238405Sjkim
2838238405Sjkim	/* OFDM power setting */
2839142425Snectar	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
2840160814Ssimon	    ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
2841142425Snectar	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
2842142425Snectar
2843238405Sjkim	idx = ofdm_pwrlvl % 6;
2844160814Ssimon	set = ofdm_pwrlvl / 6;
2845238405Sjkim
2846238405Sjkim	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
2847142425Snectar	if (error)
2848160814Ssimon		goto fail;
2849194206Ssimon	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
2850194206Ssimon	urtw_8187_write_phy_ofdm(sc, 6, 0);
2851194206Ssimon	urtw_8187_write_phy_ofdm(sc, 8, 0);
2852194206Ssimon
2853194206Ssimon	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
2854238405Sjkim	    urtw_8225_tx_gain_cck_ofdm[set] >> 1);
2855194206Ssimon	urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]);
2856238405Sjkim	urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]);
2857194206Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
2858194206Ssimonfail:
2859194206Ssimon	return (error);
2860194206Ssimon}
2861194206Ssimon
2862160814Ssimon
2863160814Ssimonstatic usb_error_t
2864160814Ssimonurtw_8225_rf_stop(struct urtw_softc *sc)
2865160814Ssimon{
2866160814Ssimon	uint8_t data;
2867160814Ssimon	usb_error_t error;
2868160814Ssimon
2869160814Ssimon	urtw_8225_write(sc, 0x4, 0x1f);
2870160814Ssimon
2871160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2872160814Ssimon	if (error)
2873160814Ssimon		goto fail;
2874160814Ssimon
2875238405Sjkim	urtw_read8_m(sc, URTW_CONFIG3, &data);
2876205128Ssimon	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
2877205128Ssimon	if (sc->sc_flags & URTW_RTL8187B) {
2878160814Ssimon		urtw_write32_m(sc, URTW_ANAPARAM2,
2879160814Ssimon		    URTW_8187B_8225_ANAPARAM2_OFF);
2880238405Sjkim		urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_OFF);
2881238405Sjkim		urtw_write32_m(sc, URTW_ANAPARAM3,
2882160814Ssimon		    URTW_8187B_8225_ANAPARAM3_OFF);
2883160814Ssimon	} else {
2884160814Ssimon		urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8225_ANAPARAM2_OFF);
2885160814Ssimon		urtw_write32_m(sc, URTW_ANAPARAM, URTW_8225_ANAPARAM_OFF);
2886160814Ssimon	}
2887160814Ssimon
2888160814Ssimon	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
2889194206Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2890160814Ssimon	if (error)
2891160814Ssimon		goto fail;
2892160814Ssimon
2893160814Ssimonfail:
2894160814Ssimon	return (error);
2895160814Ssimon}
2896160814Ssimon
2897160814Ssimonstatic usb_error_t
2898160814Ssimonurtw_8225v2_rf_init(struct urtw_softc *sc)
2899160814Ssimon{
2900238405Sjkim#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
2901238405Sjkim	int i;
2902160814Ssimon	uint16_t data;
2903160814Ssimon	uint32_t data32;
2904238405Sjkim	usb_error_t error;
2905238405Sjkim
2906160814Ssimon	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
2907160814Ssimon	if (error)
2908160814Ssimon		goto fail;
2909238405Sjkim
2910160814Ssimon	error = urtw_8225_usb_init(sc);
2911160814Ssimon	if (error)
2912160814Ssimon		goto fail;
2913238405Sjkim
2914238405Sjkim	urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
2915160814Ssimon	urtw_read16_m(sc, URTW_BRSR, &data);		/* XXX ??? */
2916160814Ssimon	urtw_write16_m(sc, URTW_BRSR, 0xffff);
2917160814Ssimon	urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
2918160814Ssimon
2919160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
2920160814Ssimon	if (error)
2921238405Sjkim		goto fail;
2922238405Sjkim	urtw_write8_m(sc, URTW_CONFIG3, 0x44);
2923160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
2924205128Ssimon	if (error)
2925160814Ssimon		goto fail;
2926160814Ssimon
2927238405Sjkim	error = urtw_8185_rf_pins_enable(sc);
2928238405Sjkim	if (error)
2929238405Sjkim		goto fail;
2930238405Sjkim
2931238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 500);
2932160814Ssimon
2933160814Ssimon	for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
2934160814Ssimon		urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg,
2935238405Sjkim		    urtw_8225v2_rf_part1[i].val);
2936238405Sjkim	}
2937160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 50);
2938160814Ssimon
2939160814Ssimon	urtw_8225_write(sc,
2940160814Ssimon	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC1);
2941160814Ssimon
2942160814Ssimon	for (i = 0; i < 95; i++) {
2943160814Ssimon		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
2944160814Ssimon		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
2945238405Sjkim		    urtw_8225v2_rxgain[i]);
2946238405Sjkim	}
2947160814Ssimon
2948160814Ssimon	urtw_8225_write(sc,
2949160814Ssimon	    URTW_8225_ADDR_3_MAGIC, URTW_8225_ADDR_3_DATA_MAGIC1);
2950238405Sjkim	urtw_8225_write(sc,
2951160814Ssimon	    URTW_8225_ADDR_5_MAGIC, URTW_8225_ADDR_5_DATA_MAGIC1);
2952238405Sjkim	urtw_8225_write(sc,
2953238405Sjkim	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC2);
2954160814Ssimon	urtw_8225_write(sc,
2955160814Ssimon	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2956238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 100);
2957160814Ssimon	urtw_8225_write(sc,
2958160814Ssimon	    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2959160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 100);
2960160814Ssimon
2961238405Sjkim	error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
2962238405Sjkim	if (error != 0)
2963238405Sjkim		goto fail;
2964160814Ssimon	if (data32 != URTW_8225_ADDR_6_DATA_MAGIC1)
2965160814Ssimon		device_printf(sc->sc_dev, "expect 0xe6!! (0x%x)\n", data32);
2966160814Ssimon	if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2)) {
2967160814Ssimon		urtw_8225_write(sc,
2968238405Sjkim		    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
2969160814Ssimon		usb_pause_mtx(&sc->sc_mtx, 100);
2970160814Ssimon		urtw_8225_write(sc,
2971160814Ssimon		    URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
2972238405Sjkim		usb_pause_mtx(&sc->sc_mtx, 50);
2973160814Ssimon		error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
2974160814Ssimon		if (error != 0)
2975238405Sjkim			goto fail;
2976160814Ssimon		if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2))
2977160814Ssimon			device_printf(sc->sc_dev, "RF calibration failed\n");
2978238405Sjkim	}
2979238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 100);
2980160814Ssimon
2981238405Sjkim	urtw_8225_write(sc,
2982160814Ssimon	    URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC6);
2983160814Ssimon	for (i = 0; i < 128; i++) {
2984160814Ssimon		urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
2985160814Ssimon		urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
2986160814Ssimon	}
2987238405Sjkim
2988160814Ssimon	for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
2989238405Sjkim		urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg,
2990160814Ssimon		    urtw_8225v2_rf_part2[i].val);
2991160814Ssimon	}
2992238405Sjkim
2993160814Ssimon	error = urtw_8225v2_setgain(sc, 4);
2994160814Ssimon	if (error)
2995238405Sjkim		goto fail;
2996238405Sjkim
2997160814Ssimon	for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
2998160814Ssimon		urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg,
2999238405Sjkim		    urtw_8225v2_rf_part3[i].val);
3000238405Sjkim	}
3001238405Sjkim
3002238405Sjkim	urtw_write8_m(sc, URTW_TESTR, 0x0d);
3003238405Sjkim
3004160814Ssimon	error = urtw_8225v2_set_txpwrlvl(sc, 1);
3005160814Ssimon	if (error)
3006238405Sjkim		goto fail;
3007160814Ssimon
3008160814Ssimon	urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
3009160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
3010238405Sjkim
3011238405Sjkim	/* TX ant A, 0x0 for B */
3012160814Ssimon	error = urtw_8185_tx_antenna(sc, 0x3);
3013160814Ssimon	if (error)
3014160814Ssimon		goto fail;
3015160814Ssimon	urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
3016160814Ssimon
3017160814Ssimon	error = urtw_8225_rf_set_chan(sc, 1);
3018160814Ssimonfail:
3019160814Ssimon	return (error);
3020160814Ssimon#undef N
3021238405Sjkim}
3022160814Ssimon
3023160814Ssimonstatic usb_error_t
3024160814Ssimonurtw_8225v2_rf_set_chan(struct urtw_softc *sc, int chan)
3025238405Sjkim{
3026160814Ssimon	usb_error_t error;
3027238405Sjkim
3028160814Ssimon	error = urtw_8225v2_set_txpwrlvl(sc, chan);
3029160814Ssimon	if (error)
3030160814Ssimon		goto fail;
3031160814Ssimon
3032160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
3033238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 10);
3034238405Sjkimfail:
3035160814Ssimon	return (error);
3036160814Ssimon}
3037238405Sjkim
3038238405Sjkimstatic usb_error_t
3039160814Ssimonurtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
3040160814Ssimon{
3041160814Ssimon	int i;
3042160814Ssimon	int16_t bit;
3043160814Ssimon	uint8_t rlen = 12, wlen = 6;
3044238405Sjkim	uint16_t o1, o2, o3, tmp;
3045238405Sjkim	uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
3046238405Sjkim	uint32_t mask = 0x80000000, value = 0;
3047160814Ssimon	usb_error_t error;
3048160814Ssimon
3049160814Ssimon	urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1);
3050160814Ssimon	urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2);
3051160814Ssimon	urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3);
3052238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | URTW_RF_PINS_MAGIC4);
3053238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | URTW_RF_PINS_MAGIC4);
3054160814Ssimon	o1 &= ~URTW_RF_PINS_MAGIC4;
3055160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN);
3056160814Ssimon	DELAY(5);
3057160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1);
3058160814Ssimon	DELAY(5);
3059238405Sjkim
3060238405Sjkim	for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
3061238405Sjkim		bit = ((d2w & mask) != 0) ? 1 : 0;
3062160814Ssimon
3063238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
3064238405Sjkim		DELAY(2);
3065238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3066160814Ssimon		    URTW_BB_HOST_BANG_CLK);
3067160814Ssimon		DELAY(2);
3068238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3069238405Sjkim		    URTW_BB_HOST_BANG_CLK);
3070238405Sjkim		DELAY(2);
3071238405Sjkim		mask = mask >> 1;
3072238405Sjkim		if (i == 2)
3073160814Ssimon			break;
3074160814Ssimon		bit = ((d2w & mask) != 0) ? 1 : 0;
3075238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3076238405Sjkim		    URTW_BB_HOST_BANG_CLK);
3077160814Ssimon		DELAY(2);
3078238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
3079238405Sjkim		    URTW_BB_HOST_BANG_CLK);
3080238405Sjkim		DELAY(2);
3081238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
3082238405Sjkim		DELAY(1);
3083160814Ssimon	}
3084238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW |
3085160814Ssimon	    URTW_BB_HOST_BANG_CLK);
3086238405Sjkim	DELAY(2);
3087160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW);
3088160814Ssimon	DELAY(2);
3089160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW);
3090160814Ssimon	DELAY(2);
3091160814Ssimon
3092160814Ssimon	mask = 0x800;
3093160814Ssimon	for (i = 0; i < rlen; i++, mask = mask >> 1) {
3094238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3095238405Sjkim		    o1 | URTW_BB_HOST_BANG_RW);
3096160814Ssimon		DELAY(2);
3097160814Ssimon		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3098238405Sjkim		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3099160814Ssimon		DELAY(2);
3100238405Sjkim		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3101160814Ssimon		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3102160814Ssimon		DELAY(2);
3103160814Ssimon		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3104160814Ssimon		    o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
3105160814Ssimon		DELAY(2);
3106160814Ssimon
3107238405Sjkim		urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp);
3108160814Ssimon		value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
3109160814Ssimon		urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
3110160814Ssimon		    o1 | URTW_BB_HOST_BANG_RW);
3111238405Sjkim		DELAY(2);
3112238405Sjkim	}
3113238405Sjkim
3114238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN |
3115160814Ssimon	    URTW_BB_HOST_BANG_RW);
3116160814Ssimon	DELAY(2);
3117160814Ssimon
3118238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2);
3119238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3);
3120238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_OUTPUT_MAGIC1);
3121238405Sjkim
3122238405Sjkim	if (data != NULL)
3123238405Sjkim		*data = value;
3124238405Sjkimfail:
3125160814Ssimon	return (error);
3126160814Ssimon}
3127238405Sjkim
3128160814Ssimon
3129238405Sjkimstatic usb_error_t
3130160814Ssimonurtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
3131160814Ssimon{
3132238405Sjkim	int i;
3133160814Ssimon	uint8_t *cck_pwrtable;
3134160814Ssimon	uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
3135205128Ssimon	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3136238405Sjkim	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3137238405Sjkim	usb_error_t error;
3138238405Sjkim
3139238405Sjkim	/* CCK power setting */
3140160814Ssimon	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
3141160814Ssimon	cck_pwrlvl += sc->sc_txpwr_cck_base;
3142160814Ssimon	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3143238405Sjkim	cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
3144238405Sjkim	    urtw_8225v2_txpwr_cck;
3145160814Ssimon
3146160814Ssimon	for (i = 0; i < 8; i++)
3147238405Sjkim		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3148238405Sjkim
3149160814Ssimon	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3150160814Ssimon	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]);
3151160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3152238405Sjkim
3153160814Ssimon	/* OFDM power setting */
3154160814Ssimon	ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
3155160814Ssimon		ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
3156160814Ssimon	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3157160814Ssimon	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3158160814Ssimon
3159238405Sjkim	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3160160814Ssimon	if (error)
3161238405Sjkim		goto fail;
3162160814Ssimon
3163238405Sjkim	urtw_8187_write_phy_ofdm(sc, 2, 0x42);
3164238405Sjkim	urtw_8187_write_phy_ofdm(sc, 5, 0x0);
3165160814Ssimon	urtw_8187_write_phy_ofdm(sc, 6, 0x40);
3166238405Sjkim	urtw_8187_write_phy_ofdm(sc, 7, 0x0);
3167160814Ssimon	urtw_8187_write_phy_ofdm(sc, 8, 0x40);
3168205128Ssimon
3169238405Sjkim	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3170238405Sjkim	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]);
3171238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
3172238405Sjkimfail:
3173160814Ssimon	return (error);
3174160814Ssimon}
3175160814Ssimon
3176238405Sjkimstatic usb_error_t
3177238405Sjkimurtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
3178160814Ssimon{
3179238405Sjkim	uint8_t *gainp;
3180238405Sjkim	usb_error_t error;
3181160814Ssimon
3182238405Sjkim	/* XXX for A?  */
3183238405Sjkim	gainp = urtw_8225v2_gain_bg;
3184160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]);
3185238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
3186238405Sjkim	urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]);
3187238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
3188238405Sjkim	urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]);
3189238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
3190238405Sjkim	urtw_8187_write_phy_ofdm(sc, 0x21, 0x17);
3191160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3192238405Sjkimfail:
3193238405Sjkim	return (error);
3194238405Sjkim}
3195238405Sjkim
3196160814Ssimonstatic usb_error_t
3197238405Sjkimurtw_8225_isv2(struct urtw_softc *sc, int *ret)
3198160814Ssimon{
3199160814Ssimon	uint32_t data;
3200160814Ssimon	usb_error_t error;
3201160814Ssimon
3202160814Ssimon	*ret = 1;
3203160814Ssimon
3204160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_MAGIC5);
3205238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_SELECT, URTW_RF_PINS_MAGIC5);
3206160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, URTW_RF_PINS_MAGIC5);
3207160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 500);
3208160814Ssimon
3209160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
3210160814Ssimon	    URTW_8225_ADDR_0_DATA_MAGIC1);
3211160814Ssimon
3212160814Ssimon	error = urtw_8225_read(sc, URTW_8225_ADDR_8_MAGIC, &data);
3213238405Sjkim	if (error != 0)
3214160814Ssimon		goto fail;
3215160814Ssimon	if (data != URTW_8225_ADDR_8_DATA_MAGIC1)
3216160814Ssimon		*ret = 0;
3217160814Ssimon	else {
3218238405Sjkim		error = urtw_8225_read(sc, URTW_8225_ADDR_9_MAGIC, &data);
3219238405Sjkim		if (error != 0)
3220160814Ssimon			goto fail;
3221238405Sjkim		if (data != URTW_8225_ADDR_9_DATA_MAGIC1)
3222160814Ssimon			*ret = 0;
3223238405Sjkim	}
3224238405Sjkim
3225160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
3226160814Ssimon	    URTW_8225_ADDR_0_DATA_MAGIC2);
3227205128Ssimonfail:
3228238405Sjkim	return (error);
3229160814Ssimon}
3230160814Ssimon
3231160814Ssimonstatic usb_error_t
3232238405Sjkimurtw_8225v2b_rf_init(struct urtw_softc *sc)
3233160814Ssimon{
3234238405Sjkim#define N(a)	((int)(sizeof(a) / sizeof((a)[0])))
3235160814Ssimon	int i;
3236160814Ssimon	uint8_t data8;
3237160814Ssimon	usb_error_t error;
3238160814Ssimon
3239238405Sjkim	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3240160814Ssimon	if (error)
3241160814Ssimon		goto fail;
3242238405Sjkim
3243160814Ssimon	/*
3244160814Ssimon	 * initialize extra registers on 8187
3245238405Sjkim	 */
3246160814Ssimon	urtw_write16_m(sc, URTW_BRSR_8187B, 0xfff);
3247160814Ssimon
3248238405Sjkim	/* retry limit */
3249160814Ssimon	urtw_read8_m(sc, URTW_CW_CONF, &data8);
3250160814Ssimon	data8 |= URTW_CW_CONF_PERPACKET_RETRY;
3251160814Ssimon	urtw_write8_m(sc, URTW_CW_CONF, data8);
3252160814Ssimon
3253160814Ssimon	/* TX AGC */
3254160814Ssimon	urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
3255160814Ssimon	data8 |= URTW_TX_AGC_CTL_PERPACKET_GAIN;
3256238405Sjkim	urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
3257238405Sjkim
3258160814Ssimon	/* Auto Rate Fallback Control */
3259160814Ssimon#define	URTW_ARFR	0x1e0
3260160814Ssimon	urtw_write16_m(sc, URTW_ARFR, 0xfff);
3261160814Ssimon	urtw_read8_m(sc, URTW_RATE_FALLBACK, &data8);
3262160814Ssimon	urtw_write8_m(sc, URTW_RATE_FALLBACK,
3263160814Ssimon	    data8 | URTW_RATE_FALLBACK_ENABLE);
3264160814Ssimon
3265160814Ssimon	urtw_read8_m(sc, URTW_MSR, &data8);
3266205128Ssimon	urtw_write8_m(sc, URTW_MSR, data8 & 0xf3);
3267238405Sjkim	urtw_read8_m(sc, URTW_MSR, &data8);
3268160814Ssimon	urtw_write8_m(sc, URTW_MSR, data8 | URTW_MSR_LINK_ENEDCA);
3269160814Ssimon	urtw_write8_m(sc, URTW_ACM_CONTROL, sc->sc_acmctl);
3270160814Ssimon
3271238405Sjkim	urtw_write16_m(sc, URTW_ATIM_WND, 2);
3272205128Ssimon	urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
3273160814Ssimon#define	URTW_FEMR_FOR_8187B	0x1d4
3274238405Sjkim	urtw_write16_m(sc, URTW_FEMR_FOR_8187B, 0xffff);
3275238405Sjkim
3276160814Ssimon	/* led type */
3277238405Sjkim	urtw_read8_m(sc, URTW_CONFIG1, &data8);
3278238405Sjkim	data8 = (data8 & 0x3f) | 0x80;
3279238405Sjkim	urtw_write8_m(sc, URTW_CONFIG1, data8);
3280160814Ssimon
3281160814Ssimon	/* applying MAC address again.  */
3282160814Ssimon	urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]);
3283160814Ssimon	urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff);
3284160814Ssimon
3285160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3286160814Ssimon	if (error)
3287160814Ssimon		goto fail;
3288160814Ssimon
3289238405Sjkim	urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
3290238405Sjkim
3291160814Ssimon	/*
3292160814Ssimon	 * MAC configuration
3293160814Ssimon	 */
3294160814Ssimon	for (i = 0; i < N(urtw_8225v2b_rf_part1); i++)
3295160814Ssimon		urtw_write8_m(sc, urtw_8225v2b_rf_part1[i].reg,
3296160814Ssimon		    urtw_8225v2b_rf_part1[i].val);
3297160814Ssimon	urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50);
3298160814Ssimon	urtw_write16_m(sc, URTW_INT_MIG, 0x0000);
3299238405Sjkim	urtw_write32_m(sc, 0x1f0, 0);
3300160814Ssimon	urtw_write32_m(sc, 0x1f4, 0);
3301160814Ssimon	urtw_write8_m(sc, 0x1f8, 0);
3302160814Ssimon	urtw_write32_m(sc, URTW_RF_TIMING, 0x4001);
3303160814Ssimon
3304160814Ssimon#define	URTW_RFSW_CTRL	0x272
3305160814Ssimon	urtw_write16_m(sc, URTW_RFSW_CTRL, 0x569a);
3306160814Ssimon
3307160814Ssimon	/*
3308160814Ssimon	 * initialize PHY
3309238405Sjkim	 */
3310160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3311160814Ssimon	if (error)
3312160814Ssimon		goto fail;
3313160814Ssimon	urtw_read8_m(sc, URTW_CONFIG3, &data8);
3314160814Ssimon	urtw_write8_m(sc, URTW_CONFIG3,
3315238405Sjkim	    data8 | URTW_CONFIG3_ANAPARAM_WRITE);
3316238405Sjkim
3317160814Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3318160814Ssimon	if (error)
3319160814Ssimon		goto fail;
3320160814Ssimon
3321160814Ssimon	/* setup RFE initial timing */
3322160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480);
3323238405Sjkim	urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488);
3324160814Ssimon	urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff);
3325160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1100);
3326160814Ssimon
3327160814Ssimon	for (i = 0; i < N(urtw_8225v2b_rf_part0); i++) {
3328238405Sjkim		urtw_8225_write(sc, urtw_8225v2b_rf_part0[i].reg,
3329160814Ssimon		    urtw_8225v2b_rf_part0[i].val);
3330160814Ssimon		usb_pause_mtx(&sc->sc_mtx, 1);
3331160814Ssimon	}
3332160814Ssimon	urtw_8225_write(sc, 0x00, 0x01b7);
3333160814Ssimon
3334160814Ssimon	for (i = 0; i < 95; i++) {
3335238405Sjkim		urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
3336238405Sjkim		usb_pause_mtx(&sc->sc_mtx, 1);
3337160814Ssimon		urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
3338205128Ssimon		    urtw_8225v2b_rxgain[i]);
3339238405Sjkim		usb_pause_mtx(&sc->sc_mtx, 1);
3340160814Ssimon	}
3341205128Ssimon
3342160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_3_MAGIC, 0x080);
3343160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3344238405Sjkim	urtw_8225_write(sc, URTW_8225_ADDR_5_MAGIC, 0x004);
3345238405Sjkim	usb_pause_mtx(&sc->sc_mtx, 1);
3346160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x0b7);
3347205128Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3348160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 3000);
3349238405Sjkim	urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0xc4d);
3350160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 2000);
3351160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0x44d);
3352160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3353160814Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x2bf);
3354160814Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3355160814Ssimon
3356160814Ssimon	urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03);
3357238405Sjkim	urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07);
3358238405Sjkim	urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03);
3359160814Ssimon
3360160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0x80, 0x12);
3361160814Ssimon	for (i = 0; i < 128; i++) {
3362160814Ssimon		uint32_t addr, data;
3363238405Sjkim
3364160814Ssimon		data = (urtw_8225z2_agc[i] << 8) | 0x0000008f;
3365160814Ssimon		addr = ((i + 0x80) << 8) | 0x0000008e;
3366160814Ssimon
3367160814Ssimon		urtw_8187_write_phy_ofdm(sc, data & 0x7f, (data >> 8) & 0xff);
3368160814Ssimon		urtw_8187_write_phy_ofdm(sc, addr & 0x7f, (addr >> 8) & 0xff);
3369160814Ssimon		urtw_8187_write_phy_ofdm(sc, 0x0e, 0x00);
3370160814Ssimon	}
3371238405Sjkim	urtw_8187_write_phy_ofdm(sc, 0x80, 0x10);
3372160814Ssimon
3373238405Sjkim	for (i = 0; i < N(urtw_8225v2b_rf_part2); i++)
3374160814Ssimon		urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2b_rf_part2[i].val);
3375160814Ssimon
3376160814Ssimon	urtw_write32_m(sc, URTW_8187B_AC_VO, (7 << 12) | (3 << 8) | 0x1c);
3377160814Ssimon	urtw_write32_m(sc, URTW_8187B_AC_VI, (7 << 12) | (3 << 8) | 0x1c);
3378160814Ssimon	urtw_write32_m(sc, URTW_8187B_AC_BE, (7 << 12) | (3 << 8) | 0x1c);
3379160814Ssimon	urtw_write32_m(sc, URTW_8187B_AC_BK, (7 << 12) | (3 << 8) | 0x1c);
3380160814Ssimon
3381160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0x97, 0x46);
3382160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6);
3383160814Ssimon	urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc);
3384160814Ssimon	urtw_8187_write_phy_cck(sc, 0xc1, 0x88);
3385160814Ssimon
3386160814Ssimonfail:
3387162911Ssimon	return (error);
3388162911Ssimon#undef N
3389162911Ssimon}
3390162911Ssimon
3391162911Ssimonstatic usb_error_t
3392238405Sjkimurtw_8225v2b_rf_set_chan(struct urtw_softc *sc, int chan)
3393162911Ssimon{
3394162911Ssimon	usb_error_t error;
3395162911Ssimon
3396162911Ssimon	error = urtw_8225v2b_set_txpwrlvl(sc, chan);
3397162911Ssimon	if (error)
3398162911Ssimon		goto fail;
3399162911Ssimon
3400162911Ssimon	urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
3401162911Ssimon	usb_pause_mtx(&sc->sc_mtx, 10);
3402162911Ssimonfail:
3403162911Ssimon	return (error);
3404162911Ssimon}
3405162911Ssimon
3406162911Ssimonstatic usb_error_t
3407162911Ssimonurtw_8225v2b_set_txpwrlvl(struct urtw_softc *sc, int chan)
3408162911Ssimon{
3409162911Ssimon	int i;
3410162911Ssimon	uint8_t *cck_pwrtable;
3411162911Ssimon	uint8_t cck_pwrlvl_max = 15;
3412162911Ssimon	uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
3413162911Ssimon	uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
3414162911Ssimon	usb_error_t error;
3415162911Ssimon
3416167612Ssimon	/* CCK power setting */
3417167612Ssimon	cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
3418167612Ssimon	    ((sc->sc_flags & URTW_RTL8187B_REV_B) ? cck_pwrlvl_max : 22) :
3419167612Ssimon	    (cck_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 0 : 7));
3420167612Ssimon	cck_pwrlvl += sc->sc_txpwr_cck_base;
3421167612Ssimon	cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
3422167612Ssimon	cck_pwrtable = (chan == 14) ? urtw_8225v2b_txpwr_cck_ch14 :
3423167612Ssimon	    urtw_8225v2b_txpwr_cck;
3424167612Ssimon
3425167612Ssimon	if (sc->sc_flags & URTW_RTL8187B_REV_B)
3426167612Ssimon		cck_pwrtable += (cck_pwrlvl <= 6) ? 0 :
3427167612Ssimon		    ((cck_pwrlvl <= 11) ? 8 : 16);
3428167612Ssimon	else
3429167612Ssimon		cck_pwrtable += (cck_pwrlvl <= 5) ? 0 :
3430167612Ssimon		    ((cck_pwrlvl <= 11) ? 8 : ((cck_pwrlvl <= 17) ? 16 : 24));
3431167612Ssimon
3432167612Ssimon	for (i = 0; i < 8; i++)
3433167612Ssimon		urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
3434167612Ssimon
3435167612Ssimon	urtw_write8_m(sc, URTW_TX_GAIN_CCK,
3436167612Ssimon	    urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1);
3437167612Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3438167612Ssimon
3439167612Ssimon	/* OFDM power setting */
3440167612Ssimon	ofdm_pwrlvl = (ofdm_pwrlvl > 15) ?
3441167612Ssimon	    ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 17 : 25) :
3442167612Ssimon	    (ofdm_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 2 : 10));
3443167612Ssimon	ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
3444167612Ssimon	ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
3445167612Ssimon
3446167612Ssimon	urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
3447167612Ssimon	    urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1);
3448167612Ssimon
3449167612Ssimon	if (sc->sc_flags & URTW_RTL8187B_REV_B) {
3450167612Ssimon		if (ofdm_pwrlvl <= 11) {
3451167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x87, 0x60);
3452167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x89, 0x60);
3453167612Ssimon		} else {
3454167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
3455167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
3456167612Ssimon		}
3457167612Ssimon	} else {
3458167612Ssimon		if (ofdm_pwrlvl <= 11) {
3459167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
3460167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
3461167612Ssimon		} else if (ofdm_pwrlvl <= 17) {
3462167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x87, 0x54);
3463167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x89, 0x54);
3464167612Ssimon		} else {
3465167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x87, 0x50);
3466167612Ssimon			urtw_8187_write_phy_ofdm(sc, 0x89, 0x50);
3467167612Ssimon		}
3468167612Ssimon	}
3469167612Ssimon	usb_pause_mtx(&sc->sc_mtx, 1);
3470167612Ssimonfail:
3471167612Ssimon	return (error);
3472167612Ssimon}
3473167612Ssimon
3474167612Ssimonstatic usb_error_t
3475167612Ssimonurtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
3476167612Ssimon{
3477167612Ssimon	struct usb_device_request req;
3478167612Ssimon	usb_error_t error;
3479167612Ssimon
3480167612Ssimon	req.bmRequestType = UT_READ_VENDOR_DEVICE;
3481167612Ssimon	req.bRequest = URTW_8187_GETREGS_REQ;
3482167612Ssimon	USETW(req.wValue, val | 0xfe00);
3483167612Ssimon	USETW(req.wIndex, 0);
3484167612Ssimon	USETW(req.wLength, sizeof(uint8_t));
3485167612Ssimon
3486167612Ssimon	error = urtw_do_request(sc, &req, data);
3487167612Ssimon	return (error);
3488167612Ssimon}
3489167612Ssimon
3490167612Ssimonstatic usb_error_t
3491167612Ssimonurtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
3492167612Ssimon{
3493167612Ssimon	struct usb_device_request req;
3494167612Ssimon
3495167612Ssimon	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
3496167612Ssimon	req.bRequest = URTW_8187_SETREGS_REQ;
3497167612Ssimon	USETW(req.wValue, val | 0xfe00);
3498167612Ssimon	USETW(req.wIndex, 0);
3499167612Ssimon	USETW(req.wLength, sizeof(uint8_t));
3500167612Ssimon
3501167612Ssimon	return (urtw_do_request(sc, &req, &data));
3502167612Ssimon}
3503167612Ssimon
3504167612Ssimonstatic usb_error_t
3505167612Ssimonurtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
3506167612Ssimon{
3507167612Ssimon	uint8_t data;
3508167612Ssimon	usb_error_t error;
3509167612Ssimon
3510167612Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3511167612Ssimon	if (error)
3512167612Ssimon		goto fail;
3513167612Ssimon
3514167612Ssimon	urtw_read8_m(sc, URTW_CONFIG3, &data);
3515167612Ssimon	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
3516167612Ssimon	urtw_write32_m(sc, URTW_ANAPARAM, val);
3517246772Sjkim	urtw_read8_m(sc, URTW_CONFIG3, &data);
3518264278Sjkim	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
3519194206Ssimon
3520194206Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3521194206Ssimon	if (error)
3522194206Ssimon		goto fail;
3523194206Ssimonfail:
3524194206Ssimon	return (error);
3525194206Ssimon}
3526194206Ssimon
3527194206Ssimonstatic usb_error_t
3528194206Ssimonurtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
3529194206Ssimon{
3530194206Ssimon	uint8_t data;
3531194206Ssimon	usb_error_t error;
3532194206Ssimon
3533194206Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
3534194206Ssimon	if (error)
3535194206Ssimon		goto fail;
3536194206Ssimon
3537194206Ssimon	urtw_read8_m(sc, URTW_CONFIG3, &data);
3538194206Ssimon	urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
3539194206Ssimon	urtw_write32_m(sc, URTW_ANAPARAM2, val);
3540194206Ssimon	urtw_read8_m(sc, URTW_CONFIG3, &data);
3541194206Ssimon	urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
3542194206Ssimon
3543194206Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
3544194206Ssimon	if (error)
3545194206Ssimon		goto fail;
3546194206Ssimonfail:
3547194206Ssimon	return (error);
3548298998Sjkim}
3549298998Sjkim
3550194206Ssimonstatic usb_error_t
3551194206Ssimonurtw_intr_enable(struct urtw_softc *sc)
3552194206Ssimon{
3553194206Ssimon	usb_error_t error;
3554194206Ssimon
3555194206Ssimon	urtw_write16_m(sc, URTW_INTR_MASK, 0xffff);
3556194206Ssimonfail:
3557194206Ssimon	return (error);
3558194206Ssimon}
3559194206Ssimon
3560194206Ssimonstatic usb_error_t
3561194206Ssimonurtw_intr_disable(struct urtw_softc *sc)
3562194206Ssimon{
3563194206Ssimon	usb_error_t error;
3564194206Ssimon
3565194206Ssimon	urtw_write16_m(sc, URTW_INTR_MASK, 0);
3566194206Ssimonfail:
3567194206Ssimon	return (error);
3568194206Ssimon}
3569194206Ssimon
3570194206Ssimonstatic usb_error_t
3571194206Ssimonurtw_reset(struct urtw_softc *sc)
3572194206Ssimon{
3573194206Ssimon	uint8_t data;
3574194206Ssimon	usb_error_t error;
3575194206Ssimon
3576194206Ssimon	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
3577194206Ssimon	if (error)
3578194206Ssimon		goto fail;
3579194206Ssimon	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3580194206Ssimon	if (error)
3581194206Ssimon		goto fail;
3582194206Ssimon
3583194206Ssimon	error = urtw_intr_disable(sc);
3584194206Ssimon	if (error)
3585194206Ssimon		goto fail;
3586194206Ssimon	usb_pause_mtx(&sc->sc_mtx, 100);
3587194206Ssimon
3588194206Ssimon	error = urtw_write8e(sc, 0x18, 0x10);
3589194206Ssimon	if (error != 0)
3590194206Ssimon		goto fail;
3591194206Ssimon	error = urtw_write8e(sc, 0x18, 0x11);
3592194206Ssimon	if (error != 0)
3593194206Ssimon		goto fail;
3594238405Sjkim	error = urtw_write8e(sc, 0x18, 0x00);
3595194206Ssimon	if (error != 0)
3596194206Ssimon		goto fail;
3597194206Ssimon	usb_pause_mtx(&sc->sc_mtx, 100);
3598194206Ssimon
3599194206Ssimon	urtw_read8_m(sc, URTW_CMD, &data);
3600194206Ssimon	data = (data & 0x2) | URTW_CMD_RST;
3601194206Ssimon	urtw_write8_m(sc, URTW_CMD, data);
3602194206Ssimon	usb_pause_mtx(&sc->sc_mtx, 100);
3603194206Ssimon
3604194206Ssimon	urtw_read8_m(sc, URTW_CMD, &data);
3605194206Ssimon	if (data & URTW_CMD_RST) {
3606194206Ssimon		device_printf(sc->sc_dev, "reset timeout\n");
3607194206Ssimon		goto fail;
3608194206Ssimon	}
3609194206Ssimon
3610194206Ssimon	error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
3611194206Ssimon	if (error)
3612194206Ssimon		goto fail;
3613194206Ssimon	usb_pause_mtx(&sc->sc_mtx, 100);
3614194206Ssimon
3615194206Ssimon	error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
3616194206Ssimon	if (error)
3617194206Ssimon		goto fail;
3618194206Ssimon	error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
3619194206Ssimon	if (error)
3620194206Ssimon		goto fail;
3621194206Ssimonfail:
3622194206Ssimon	return (error);
3623194206Ssimon}
3624194206Ssimon
3625194206Ssimonstatic usb_error_t
3626194206Ssimonurtw_led_ctl(struct urtw_softc *sc, int mode)
3627194206Ssimon{
3628194206Ssimon	usb_error_t error = 0;
3629194206Ssimon
3630194206Ssimon	switch (sc->sc_strategy) {
3631194206Ssimon	case URTW_SW_LED_MODE0:
3632194206Ssimon		error = urtw_led_mode0(sc, mode);
3633194206Ssimon		break;
3634194206Ssimon	case URTW_SW_LED_MODE1:
3635194206Ssimon		error = urtw_led_mode1(sc, mode);
3636194206Ssimon		break;
3637194206Ssimon	case URTW_SW_LED_MODE2:
3638194206Ssimon		error = urtw_led_mode2(sc, mode);
3639194206Ssimon		break;
3640194206Ssimon	case URTW_SW_LED_MODE3:
3641194206Ssimon		error = urtw_led_mode3(sc, mode);
3642194206Ssimon		break;
3643194206Ssimon	default:
3644194206Ssimon		DPRINTF(sc, URTW_DEBUG_STATE,
3645194206Ssimon		    "unsupported LED mode %d\n", sc->sc_strategy);
3646194206Ssimon		error = USB_ERR_INVAL;
3647194206Ssimon		break;
3648194206Ssimon	}
3649194206Ssimon
3650194206Ssimon	return (error);
3651194206Ssimon}
3652194206Ssimon
3653194206Ssimonstatic usb_error_t
3654194206Ssimonurtw_led_mode0(struct urtw_softc *sc, int mode)
3655194206Ssimon{
3656194206Ssimon
3657194206Ssimon	switch (mode) {
3658194206Ssimon	case URTW_LED_CTL_POWER_ON:
3659194206Ssimon		sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
3660194206Ssimon		break;
3661194206Ssimon	case URTW_LED_CTL_TX:
3662194206Ssimon		if (sc->sc_gpio_ledinprogress == 1)
3663194206Ssimon			return (0);
3664194206Ssimon
3665194206Ssimon		sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
3666238405Sjkim		sc->sc_gpio_blinktime = 2;
3667194206Ssimon		break;
3668238405Sjkim	case URTW_LED_CTL_LINK:
3669194206Ssimon		sc->sc_gpio_ledstate = URTW_LED_ON;
3670238405Sjkim		break;
3671238405Sjkim	default:
3672238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3673238405Sjkim		    "unsupported LED mode 0x%x", mode);
3674238405Sjkim		return (USB_ERR_INVAL);
3675238405Sjkim	}
3676238405Sjkim
3677238405Sjkim	switch (sc->sc_gpio_ledstate) {
3678194206Ssimon	case URTW_LED_ON:
3679194206Ssimon		if (sc->sc_gpio_ledinprogress != 0)
3680238405Sjkim			break;
3681238405Sjkim		urtw_led_on(sc, URTW_LED_GPIO);
3682238405Sjkim		break;
3683238405Sjkim	case URTW_LED_BLINK_NORMAL:
3684238405Sjkim		if (sc->sc_gpio_ledinprogress != 0)
3685238405Sjkim			break;
3686238405Sjkim		sc->sc_gpio_ledinprogress = 1;
3687238405Sjkim		sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
3688194206Ssimon			URTW_LED_OFF : URTW_LED_ON;
3689238405Sjkim		usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
3690238405Sjkim		break;
3691238405Sjkim	case URTW_LED_POWER_ON_BLINK:
3692238405Sjkim		urtw_led_on(sc, URTW_LED_GPIO);
3693238405Sjkim		usb_pause_mtx(&sc->sc_mtx, 100);
3694238405Sjkim		urtw_led_off(sc, URTW_LED_GPIO);
3695238405Sjkim		break;
3696246772Sjkim	default:
3697238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3698238405Sjkim		    "unknown LED status 0x%x", sc->sc_gpio_ledstate);
3699238405Sjkim		return (USB_ERR_INVAL);
3700238405Sjkim	}
3701238405Sjkim	return (0);
3702238405Sjkim}
3703238405Sjkim
3704194206Ssimonstatic usb_error_t
3705238405Sjkimurtw_led_mode1(struct urtw_softc *sc, int mode)
3706238405Sjkim{
3707238405Sjkim	return (USB_ERR_INVAL);
3708238405Sjkim}
3709238405Sjkim
3710194206Ssimonstatic usb_error_t
3711194206Ssimonurtw_led_mode2(struct urtw_softc *sc, int mode)
3712194206Ssimon{
3713194206Ssimon	return (USB_ERR_INVAL);
3714194206Ssimon}
3715194206Ssimon
3716194206Ssimonstatic usb_error_t
3717194206Ssimonurtw_led_mode3(struct urtw_softc *sc, int mode)
3718194206Ssimon{
3719194206Ssimon	return (USB_ERR_INVAL);
3720194206Ssimon}
3721194206Ssimon
3722194206Ssimonstatic usb_error_t
3723194206Ssimonurtw_led_on(struct urtw_softc *sc, int type)
3724194206Ssimon{
3725194206Ssimon	usb_error_t error;
3726194206Ssimon
3727194206Ssimon	if (type == URTW_LED_GPIO) {
3728194206Ssimon		switch (sc->sc_gpio_ledpin) {
3729194206Ssimon		case URTW_LED_PIN_GPIO0:
3730194206Ssimon			urtw_write8_m(sc, URTW_GPIO, 0x01);
3731194206Ssimon			urtw_write8_m(sc, URTW_GP_ENABLE, 0x00);
3732194206Ssimon			break;
3733205128Ssimon		default:
3734238405Sjkim			DPRINTF(sc, URTW_DEBUG_STATE,
3735238405Sjkim			    "unsupported LED PIN type 0x%x",
3736238405Sjkim			    sc->sc_gpio_ledpin);
3737238405Sjkim			error = USB_ERR_INVAL;
3738238405Sjkim			goto fail;
3739238405Sjkim		}
3740238405Sjkim	} else {
3741238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3742238405Sjkim		    "unsupported LED type 0x%x", type);
3743238405Sjkim		error = USB_ERR_INVAL;
3744238405Sjkim		goto fail;
3745238405Sjkim	}
3746238405Sjkim
3747238405Sjkim	sc->sc_gpio_ledon = 1;
3748238405Sjkimfail:
3749238405Sjkim	return (error);
3750238405Sjkim}
3751238405Sjkim
3752238405Sjkimstatic usb_error_t
3753238405Sjkimurtw_led_off(struct urtw_softc *sc, int type)
3754238405Sjkim{
3755238405Sjkim	usb_error_t error;
3756238405Sjkim
3757238405Sjkim	if (type == URTW_LED_GPIO) {
3758238405Sjkim		switch (sc->sc_gpio_ledpin) {
3759238405Sjkim		case URTW_LED_PIN_GPIO0:
3760238405Sjkim			urtw_write8_m(sc, URTW_GPIO, URTW_GPIO_DATA_MAGIC1);
3761238405Sjkim			urtw_write8_m(sc,
3762238405Sjkim			    URTW_GP_ENABLE, URTW_GP_ENABLE_DATA_MAGIC1);
3763238405Sjkim			break;
3764238405Sjkim		default:
3765238405Sjkim			DPRINTF(sc, URTW_DEBUG_STATE,
3766238405Sjkim			    "unsupported LED PIN type 0x%x",
3767238405Sjkim			    sc->sc_gpio_ledpin);
3768238405Sjkim			error = USB_ERR_INVAL;
3769238405Sjkim			goto fail;
3770238405Sjkim		}
3771238405Sjkim	} else {
3772238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3773238405Sjkim		    "unsupported LED type 0x%x", type);
3774238405Sjkim		error = USB_ERR_INVAL;
3775238405Sjkim		goto fail;
3776238405Sjkim	}
3777238405Sjkim
3778238405Sjkim	sc->sc_gpio_ledon = 0;
3779238405Sjkim
3780238405Sjkimfail:
3781238405Sjkim	return (error);
3782238405Sjkim}
3783238405Sjkim
3784238405Sjkimstatic void
3785238405Sjkimurtw_led_ch(void *arg)
3786238405Sjkim{
3787238405Sjkim	struct urtw_softc *sc = arg;
3788238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
3789238405Sjkim	struct ieee80211com *ic = ifp->if_l2com;
3790238405Sjkim
3791238405Sjkim	ieee80211_runtask(ic, &sc->sc_led_task);
3792238405Sjkim}
3793238405Sjkim
3794238405Sjkimstatic void
3795238405Sjkimurtw_ledtask(void *arg, int pending)
3796238405Sjkim{
3797238405Sjkim	struct urtw_softc *sc = arg;
3798238405Sjkim
3799238405Sjkim	if (sc->sc_strategy != URTW_SW_LED_MODE0) {
3800238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3801238405Sjkim		    "could not process a LED strategy 0x%x",
3802238405Sjkim		    sc->sc_strategy);
3803238405Sjkim		return;
3804238405Sjkim	}
3805238405Sjkim
3806238405Sjkim	URTW_LOCK(sc);
3807238405Sjkim	urtw_led_blink(sc);
3808238405Sjkim	URTW_UNLOCK(sc);
3809238405Sjkim}
3810238405Sjkim
3811238405Sjkimstatic usb_error_t
3812238405Sjkimurtw_led_blink(struct urtw_softc *sc)
3813238405Sjkim{
3814238405Sjkim	uint8_t ing = 0;
3815238405Sjkim	usb_error_t error;
3816238405Sjkim
3817238405Sjkim	if (sc->sc_gpio_blinkstate == URTW_LED_ON)
3818238405Sjkim		error = urtw_led_on(sc, URTW_LED_GPIO);
3819238405Sjkim	else
3820238405Sjkim		error = urtw_led_off(sc, URTW_LED_GPIO);
3821238405Sjkim	sc->sc_gpio_blinktime--;
3822238405Sjkim	if (sc->sc_gpio_blinktime == 0)
3823238405Sjkim		ing = 1;
3824238405Sjkim	else {
3825238405Sjkim		if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
3826238405Sjkim		    sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
3827238405Sjkim		    sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
3828238405Sjkim			ing = 1;
3829238405Sjkim	}
3830238405Sjkim	if (ing == 1) {
3831238405Sjkim		if (sc->sc_gpio_ledstate == URTW_LED_ON &&
3832238405Sjkim		    sc->sc_gpio_ledon == 0)
3833238405Sjkim			error = urtw_led_on(sc, URTW_LED_GPIO);
3834238405Sjkim		else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
3835238405Sjkim		    sc->sc_gpio_ledon == 1)
3836238405Sjkim			error = urtw_led_off(sc, URTW_LED_GPIO);
3837238405Sjkim
3838238405Sjkim		sc->sc_gpio_blinktime = 0;
3839238405Sjkim		sc->sc_gpio_ledinprogress = 0;
3840238405Sjkim		return (0);
3841238405Sjkim	}
3842238405Sjkim
3843238405Sjkim	sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
3844238405Sjkim	    URTW_LED_ON : URTW_LED_OFF;
3845238405Sjkim
3846238405Sjkim	switch (sc->sc_gpio_ledstate) {
3847238405Sjkim	case URTW_LED_BLINK_NORMAL:
3848238405Sjkim		usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
3849238405Sjkim		break;
3850238405Sjkim	default:
3851238405Sjkim		DPRINTF(sc, URTW_DEBUG_STATE,
3852238405Sjkim		    "unknown LED status 0x%x",
3853238405Sjkim		    sc->sc_gpio_ledstate);
3854238405Sjkim		return (USB_ERR_INVAL);
3855238405Sjkim	}
3856238405Sjkim	return (0);
3857238405Sjkim}
3858238405Sjkim
3859238405Sjkimstatic usb_error_t
3860238405Sjkimurtw_rx_enable(struct urtw_softc *sc)
3861238405Sjkim{
3862238405Sjkim	uint8_t data;
3863238405Sjkim	usb_error_t error;
3864238405Sjkim
3865238405Sjkim	usbd_transfer_start((sc->sc_flags & URTW_RTL8187B) ?
3866238405Sjkim	    sc->sc_xfer[URTW_8187B_BULK_RX] : sc->sc_xfer[URTW_8187L_BULK_RX]);
3867238405Sjkim
3868238405Sjkim	error = urtw_rx_setconf(sc);
3869238405Sjkim	if (error != 0)
3870238405Sjkim		goto fail;
3871238405Sjkim
3872238405Sjkim	if ((sc->sc_flags & URTW_RTL8187B) == 0) {
3873238405Sjkim		urtw_read8_m(sc, URTW_CMD, &data);
3874238405Sjkim		urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE);
3875238405Sjkim	}
3876238405Sjkimfail:
3877238405Sjkim	return (error);
3878238405Sjkim}
3879238405Sjkim
3880238405Sjkimstatic usb_error_t
3881238405Sjkimurtw_tx_enable(struct urtw_softc *sc)
3882238405Sjkim{
3883238405Sjkim	uint8_t data8;
3884238405Sjkim	uint32_t data;
3885238405Sjkim	usb_error_t error;
3886238405Sjkim
3887238405Sjkim	if (sc->sc_flags & URTW_RTL8187B) {
3888238405Sjkim		urtw_read32_m(sc, URTW_TX_CONF, &data);
3889238405Sjkim		data &= ~URTW_TX_LOOPBACK_MASK;
3890238405Sjkim		data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
3891238405Sjkim		data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
3892238405Sjkim		data &= ~URTW_TX_SWPLCPLEN;
3893238405Sjkim		data |= URTW_TX_HW_SEQNUM | URTW_TX_DISREQQSIZE |
3894238405Sjkim		    (7 << 8) |	/* short retry limit */
3895238405Sjkim		    (7 << 0) |	/* long retry limit */
3896238405Sjkim		    (7 << 21);	/* MAX TX DMA */
3897238405Sjkim		urtw_write32_m(sc, URTW_TX_CONF, data);
3898238405Sjkim
3899238405Sjkim		urtw_read8_m(sc, URTW_MSR, &data8);
3900238405Sjkim		data8 |= URTW_MSR_LINK_ENEDCA;
3901238405Sjkim		urtw_write8_m(sc, URTW_MSR, data8);
3902238405Sjkim		return (error);
3903238405Sjkim	}
3904238405Sjkim
3905238405Sjkim	urtw_read8_m(sc, URTW_CW_CONF, &data8);
3906238405Sjkim	data8 &= ~(URTW_CW_CONF_PERPACKET_CW | URTW_CW_CONF_PERPACKET_RETRY);
3907238405Sjkim	urtw_write8_m(sc, URTW_CW_CONF, data8);
3908238405Sjkim
3909238405Sjkim	urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
3910238405Sjkim	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
3911238405Sjkim	data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
3912238405Sjkim	data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
3913238405Sjkim	urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
3914238405Sjkim
3915238405Sjkim	urtw_read32_m(sc, URTW_TX_CONF, &data);
3916238405Sjkim	data &= ~URTW_TX_LOOPBACK_MASK;
3917238405Sjkim	data |= URTW_TX_LOOPBACK_NONE;
3918238405Sjkim	data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
3919238405Sjkim	data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
3920238405Sjkim	data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
3921238405Sjkim	data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
3922238405Sjkim	data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
3923238405Sjkim	data &= ~URTW_TX_SWPLCPLEN;
3924238405Sjkim	data |= URTW_TX_NOICV;
3925238405Sjkim	urtw_write32_m(sc, URTW_TX_CONF, data);
3926238405Sjkim
3927238405Sjkim	urtw_read8_m(sc, URTW_CMD, &data8);
3928238405Sjkim	urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
3929238405Sjkimfail:
3930238405Sjkim	return (error);
3931238405Sjkim}
3932238405Sjkim
3933238405Sjkimstatic usb_error_t
3934238405Sjkimurtw_rx_setconf(struct urtw_softc *sc)
3935238405Sjkim{
3936238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
3937238405Sjkim	struct ieee80211com *ic = ifp->if_l2com;
3938238405Sjkim	uint32_t data;
3939238405Sjkim	usb_error_t error;
3940238405Sjkim
3941238405Sjkim	urtw_read32_m(sc, URTW_RX, &data);
3942238405Sjkim	data = data &~ URTW_RX_FILTER_MASK;
3943238405Sjkim	if (sc->sc_flags & URTW_RTL8187B) {
3944238405Sjkim		data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA |
3945238405Sjkim		    URTW_RX_FILTER_MCAST | URTW_RX_FILTER_BCAST |
3946238405Sjkim		    URTW_RX_FILTER_NICMAC | URTW_RX_CHECK_BSSID |
3947238405Sjkim		    URTW_RX_FIFO_THRESHOLD_NONE |
3948238405Sjkim		    URTW_MAX_RX_DMA_2048 |
3949238405Sjkim		    URTW_RX_AUTORESETPHY | URTW_RCR_ONLYERLPKT;
3950238405Sjkim	} else {
3951238405Sjkim		data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
3952238405Sjkim		data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
3953238405Sjkim
3954238405Sjkim		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
3955238405Sjkim			data = data | URTW_RX_FILTER_ICVERR;
3956238405Sjkim			data = data | URTW_RX_FILTER_PWR;
3957238405Sjkim		}
3958238405Sjkim		if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
3959238405Sjkim			data = data | URTW_RX_FILTER_CRCERR;
3960238405Sjkim
3961238405Sjkim		if (ic->ic_opmode == IEEE80211_M_MONITOR ||
3962238405Sjkim		    (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) {
3963238405Sjkim			data = data | URTW_RX_FILTER_ALLMAC;
3964238405Sjkim		} else {
3965238405Sjkim			data = data | URTW_RX_FILTER_NICMAC;
3966238405Sjkim			data = data | URTW_RX_CHECK_BSSID;
3967238405Sjkim		}
3968238405Sjkim
3969238405Sjkim		data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
3970238405Sjkim		data = data | URTW_RX_FIFO_THRESHOLD_NONE |
3971238405Sjkim		    URTW_RX_AUTORESETPHY;
3972238405Sjkim		data = data &~ URTW_MAX_RX_DMA_MASK;
3973238405Sjkim		data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT;
3974238405Sjkim	}
3975238405Sjkim
3976238405Sjkim	urtw_write32_m(sc, URTW_RX, data);
3977238405Sjkimfail:
3978238405Sjkim	return (error);
3979238405Sjkim}
3980238405Sjkim
3981238405Sjkimstatic struct mbuf *
3982238405Sjkimurtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
3983238405Sjkim    int8_t *nf_p)
3984238405Sjkim{
3985238405Sjkim	int actlen, flen, rssi;
3986238405Sjkim	struct ieee80211_frame *wh;
3987238405Sjkim	struct mbuf *m, *mnew;
3988238405Sjkim	struct urtw_softc *sc = data->sc;
3989238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
3990238405Sjkim	struct ieee80211com *ic = ifp->if_l2com;
3991238405Sjkim	uint8_t noise = 0, rate;
3992238405Sjkim
3993238405Sjkim	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
3994238405Sjkim
3995238405Sjkim	if (actlen < (int)URTW_MIN_RXBUFSZ) {
3996238405Sjkim		ifp->if_ierrors++;
3997238405Sjkim		return (NULL);
3998238405Sjkim	}
3999238405Sjkim
4000238405Sjkim	if (sc->sc_flags & URTW_RTL8187B) {
4001238405Sjkim		struct urtw_8187b_rxhdr *rx;
4002238405Sjkim
4003238405Sjkim		rx = (struct urtw_8187b_rxhdr *)(data->buf +
4004238405Sjkim		    (actlen - (sizeof(struct urtw_8187b_rxhdr))));
4005238405Sjkim		flen = le32toh(rx->flag) & 0xfff;
4006238405Sjkim		if (flen > actlen) {
4007238405Sjkim			ifp->if_ierrors++;
4008238405Sjkim			return (NULL);
4009238405Sjkim		}
4010238405Sjkim		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
4011238405Sjkim		/* XXX correct? */
4012238405Sjkim		rssi = rx->rssi & URTW_RX_RSSI_MASK;
4013238405Sjkim		noise = rx->noise;
4014238405Sjkim	} else {
4015238405Sjkim		struct urtw_8187l_rxhdr *rx;
4016238405Sjkim
4017238405Sjkim		rx = (struct urtw_8187l_rxhdr *)(data->buf +
4018238405Sjkim		    (actlen - (sizeof(struct urtw_8187l_rxhdr))));
4019238405Sjkim		flen = le32toh(rx->flag) & 0xfff;
4020238405Sjkim		if (flen > actlen) {
4021238405Sjkim			ifp->if_ierrors++;
4022238405Sjkim			return (NULL);
4023238405Sjkim		}
4024238405Sjkim
4025238405Sjkim		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
4026238405Sjkim		/* XXX correct? */
4027238405Sjkim		rssi = rx->rssi & URTW_RX_8187L_RSSI_MASK;
4028238405Sjkim		noise = rx->noise;
4029238405Sjkim	}
4030238405Sjkim
4031238405Sjkim	mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
4032238405Sjkim	if (mnew == NULL) {
4033238405Sjkim		ifp->if_ierrors++;
4034238405Sjkim		return (NULL);
4035238405Sjkim	}
4036238405Sjkim
4037238405Sjkim	m = data->m;
4038238405Sjkim	data->m = mnew;
4039238405Sjkim	data->buf = mtod(mnew, uint8_t *);
4040238405Sjkim
4041238405Sjkim	/* finalize mbuf */
4042238405Sjkim	m->m_pkthdr.rcvif = ifp;
4043238405Sjkim	m->m_pkthdr.len = m->m_len = flen - IEEE80211_CRC_LEN;
4044238405Sjkim
4045238405Sjkim	if (ieee80211_radiotap_active(ic)) {
4046238405Sjkim		struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap;
4047238405Sjkim
4048238405Sjkim		/* XXX Are variables correct?  */
4049238405Sjkim		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
4050238405Sjkim		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
4051238405Sjkim		tap->wr_dbm_antsignal = (int8_t)rssi;
4052238405Sjkim	}
4053238405Sjkim
4054238405Sjkim	wh = mtod(m, struct ieee80211_frame *);
4055238405Sjkim	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
4056238405Sjkim		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
4057238405Sjkim
4058238405Sjkim	*rssi_p = rssi;
4059238405Sjkim	*nf_p = noise;		/* XXX correct? */
4060238405Sjkim
4061238405Sjkim	return (m);
4062238405Sjkim}
4063238405Sjkim
4064238405Sjkimstatic void
4065238405Sjkimurtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
4066238405Sjkim{
4067238405Sjkim	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4068238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
4069238405Sjkim	struct ieee80211com *ic = ifp->if_l2com;
4070238405Sjkim	struct ieee80211_frame *wh;
4071238405Sjkim	struct ieee80211_node *ni;
4072238405Sjkim	struct mbuf *m = NULL;
4073238405Sjkim	struct urtw_data *data;
4074238405Sjkim	int8_t nf = -95;
4075238405Sjkim	int rssi = 1;
4076238405Sjkim
4077238405Sjkim	URTW_ASSERT_LOCKED(sc);
4078238405Sjkim
4079238405Sjkim	switch (USB_GET_STATE(xfer)) {
4080238405Sjkim	case USB_ST_TRANSFERRED:
4081238405Sjkim		data = STAILQ_FIRST(&sc->sc_rx_active);
4082238405Sjkim		if (data == NULL)
4083238405Sjkim			goto setup;
4084238405Sjkim		STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
4085238405Sjkim		m = urtw_rxeof(xfer, data, &rssi, &nf);
4086238405Sjkim		STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
4087238405Sjkim		/* FALLTHROUGH */
4088238405Sjkim	case USB_ST_SETUP:
4089238405Sjkimsetup:
4090238405Sjkim		data = STAILQ_FIRST(&sc->sc_rx_inactive);
4091238405Sjkim		if (data == NULL) {
4092238405Sjkim			KASSERT(m == NULL, ("mbuf isn't NULL"));
4093238405Sjkim			return;
4094238405Sjkim		}
4095238405Sjkim		STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next);
4096238405Sjkim		STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next);
4097238405Sjkim		usbd_xfer_set_frame_data(xfer, 0, data->buf,
4098238405Sjkim		    usbd_xfer_max_len(xfer));
4099238405Sjkim		usbd_transfer_submit(xfer);
4100238405Sjkim
4101238405Sjkim		/*
4102238405Sjkim		 * To avoid LOR we should unlock our private mutex here to call
4103238405Sjkim		 * ieee80211_input() because here is at the end of a USB
4104238405Sjkim		 * callback and safe to unlock.
4105238405Sjkim		 */
4106238405Sjkim		URTW_UNLOCK(sc);
4107238405Sjkim		if (m != NULL) {
4108238405Sjkim			wh = mtod(m, struct ieee80211_frame *);
4109238405Sjkim			ni = ieee80211_find_rxnode(ic,
4110238405Sjkim			    (struct ieee80211_frame_min *)wh);
4111238405Sjkim			if (ni != NULL) {
4112238405Sjkim				(void) ieee80211_input(ni, m, rssi, nf);
4113238405Sjkim				/* node is no longer needed */
4114238405Sjkim				ieee80211_free_node(ni);
4115238405Sjkim			} else
4116238405Sjkim				(void) ieee80211_input_all(ic, m, rssi, nf);
4117238405Sjkim			m = NULL;
4118238405Sjkim		}
4119238405Sjkim		URTW_LOCK(sc);
4120238405Sjkim		break;
4121238405Sjkim	default:
4122238405Sjkim		/* needs it to the inactive queue due to a error.  */
4123238405Sjkim		data = STAILQ_FIRST(&sc->sc_rx_active);
4124238405Sjkim		if (data != NULL) {
4125238405Sjkim			STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
4126238405Sjkim			STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
4127238405Sjkim		}
4128238405Sjkim		if (error != USB_ERR_CANCELLED) {
4129238405Sjkim			usbd_xfer_set_stall(xfer);
4130238405Sjkim			ifp->if_ierrors++;
4131238405Sjkim			goto setup;
4132238405Sjkim		}
4133238405Sjkim		break;
4134238405Sjkim	}
4135238405Sjkim}
4136238405Sjkim
4137238405Sjkim#define	URTW_STATUS_TYPE_TXCLOSE	1
4138238405Sjkim#define	URTW_STATUS_TYPE_BEACON_INTR	0
4139238405Sjkim
4140238405Sjkimstatic void
4141238405Sjkimurtw_txstatus_eof(struct usb_xfer *xfer)
4142238405Sjkim{
4143238405Sjkim	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4144238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
4145238405Sjkim	int actlen, type, pktretry, seq;
4146238405Sjkim	uint64_t val;
4147238405Sjkim
4148238405Sjkim	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
4149238405Sjkim
4150238405Sjkim	if (actlen != sizeof(uint64_t))
4151238405Sjkim		return;
4152238405Sjkim
4153238405Sjkim	val = le64toh(sc->sc_txstatus);
4154238405Sjkim	type = (val >> 30) & 0x3;
4155238405Sjkim	if (type == URTW_STATUS_TYPE_TXCLOSE) {
4156238405Sjkim		pktretry = val & 0xff;
4157238405Sjkim		seq = (val >> 16) & 0xff;
4158238405Sjkim		if (pktretry == URTW_TX_MAXRETRY)
4159238405Sjkim			ifp->if_oerrors++;
4160238405Sjkim		DPRINTF(sc, URTW_DEBUG_TXSTATUS, "pktretry %d seq %#x\n",
4161238405Sjkim		    pktretry, seq);
4162238405Sjkim	}
4163238405Sjkim}
4164238405Sjkim
4165238405Sjkimstatic void
4166238405Sjkimurtw_bulk_tx_status_callback(struct usb_xfer *xfer, usb_error_t error)
4167238405Sjkim{
4168238405Sjkim	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4169238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
4170238405Sjkim	void *dma_buf = usbd_xfer_get_frame_buffer(xfer, 0);
4171238405Sjkim
4172238405Sjkim	URTW_ASSERT_LOCKED(sc);
4173238405Sjkim
4174238405Sjkim	switch (USB_GET_STATE(xfer)) {
4175238405Sjkim	case USB_ST_TRANSFERRED:
4176238405Sjkim		urtw_txstatus_eof(xfer);
4177238405Sjkim		/* FALLTHROUGH */
4178238405Sjkim	case USB_ST_SETUP:
4179238405Sjkimsetup:
4180238405Sjkim		memcpy(dma_buf, &sc->sc_txstatus, sizeof(uint64_t));
4181238405Sjkim		usbd_xfer_set_frame_len(xfer, 0, sizeof(uint64_t));
4182238405Sjkim		usbd_transfer_submit(xfer);
4183238405Sjkim		break;
4184238405Sjkim	default:
4185238405Sjkim		if (error != USB_ERR_CANCELLED) {
4186238405Sjkim			usbd_xfer_set_stall(xfer);
4187238405Sjkim			ifp->if_ierrors++;
4188238405Sjkim			goto setup;
4189238405Sjkim		}
4190238405Sjkim		break;
4191238405Sjkim	}
4192238405Sjkim}
4193238405Sjkim
4194238405Sjkimstatic void
4195238405Sjkimurtw_txeof(struct usb_xfer *xfer, struct urtw_data *data)
4196238405Sjkim{
4197238405Sjkim	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4198238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
4199238405Sjkim	struct mbuf *m;
4200238405Sjkim
4201238405Sjkim	URTW_ASSERT_LOCKED(sc);
4202238405Sjkim
4203238405Sjkim	/*
4204238405Sjkim	 * Do any tx complete callback.  Note this must be done before releasing
4205238405Sjkim	 * the node reference.
4206238405Sjkim	 */
4207238405Sjkim	if (data->m) {
4208238405Sjkim		m = data->m;
4209238405Sjkim		if (m->m_flags & M_TXCB) {
4210238405Sjkim			/* XXX status? */
4211238405Sjkim			ieee80211_process_callback(data->ni, m, 0);
4212238405Sjkim		}
4213238405Sjkim		m_freem(m);
4214238405Sjkim		data->m = NULL;
4215238405Sjkim	}
4216238405Sjkim	if (data->ni) {
4217238405Sjkim		ieee80211_free_node(data->ni);
4218238405Sjkim		data->ni = NULL;
4219238405Sjkim	}
4220238405Sjkim	sc->sc_txtimer = 0;
4221238405Sjkim	ifp->if_opackets++;
4222238405Sjkim	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
4223238405Sjkim}
4224238405Sjkim
4225238405Sjkimstatic void
4226238405Sjkimurtw_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
4227238405Sjkim{
4228238405Sjkim	struct urtw_softc *sc = usbd_xfer_softc(xfer);
4229238405Sjkim	struct ifnet *ifp = sc->sc_ifp;
4230238405Sjkim	struct urtw_data *data;
4231238405Sjkim
4232238405Sjkim	URTW_ASSERT_LOCKED(sc);
4233238405Sjkim
4234238405Sjkim	switch (USB_GET_STATE(xfer)) {
4235238405Sjkim	case USB_ST_TRANSFERRED:
4236238405Sjkim		data = STAILQ_FIRST(&sc->sc_tx_active);
4237238405Sjkim		if (data == NULL)
4238238405Sjkim			goto setup;
4239238405Sjkim		STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
4240238405Sjkim		urtw_txeof(xfer, data);
4241238405Sjkim		STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
4242238405Sjkim		/* FALLTHROUGH */
4243238405Sjkim	case USB_ST_SETUP:
4244238405Sjkimsetup:
4245238405Sjkim		data = STAILQ_FIRST(&sc->sc_tx_pending);
4246238405Sjkim		if (data == NULL) {
4247238405Sjkim			DPRINTF(sc, URTW_DEBUG_XMIT,
4248238405Sjkim			    "%s: empty pending queue\n", __func__);
4249238405Sjkim			return;
4250238405Sjkim		}
4251238405Sjkim		STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
4252238405Sjkim		STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
4253238405Sjkim
4254238405Sjkim		usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
4255238405Sjkim		usbd_transfer_submit(xfer);
4256238405Sjkim
4257238405Sjkim		URTW_UNLOCK(sc);
4258238405Sjkim		urtw_start(ifp);
4259238405Sjkim		URTW_LOCK(sc);
4260238405Sjkim		break;
4261238405Sjkim	default:
4262238405Sjkim		data = STAILQ_FIRST(&sc->sc_tx_active);
4263238405Sjkim		if (data == NULL)
4264238405Sjkim			goto setup;
4265238405Sjkim		if (data->ni != NULL) {
4266238405Sjkim			ieee80211_free_node(data->ni);
4267238405Sjkim			data->ni = NULL;
4268238405Sjkim			ifp->if_oerrors++;
4269238405Sjkim		}
4270238405Sjkim		if (error != USB_ERR_CANCELLED) {
4271238405Sjkim			usbd_xfer_set_stall(xfer);
4272238405Sjkim			goto setup;
4273238405Sjkim		}
4274238405Sjkim		break;
4275238405Sjkim	}
4276238405Sjkim}
4277238405Sjkim
4278238405Sjkimstatic struct urtw_data *
4279238405Sjkim_urtw_getbuf(struct urtw_softc *sc)
4280238405Sjkim{
4281238405Sjkim	struct urtw_data *bf;
4282238405Sjkim
4283238405Sjkim	bf = STAILQ_FIRST(&sc->sc_tx_inactive);
4284238405Sjkim	if (bf != NULL)
4285238405Sjkim		STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
4286238405Sjkim	else
4287290207Sjkim		bf = NULL;
4288238405Sjkim	if (bf == NULL)
4289238405Sjkim		DPRINTF(sc, URTW_DEBUG_XMIT, "%s: %s\n", __func__,
4290238405Sjkim		    "out of xmit buffers");
4291238405Sjkim	return (bf);
4292238405Sjkim}
4293238405Sjkim
4294238405Sjkimstatic struct urtw_data *
4295238405Sjkimurtw_getbuf(struct urtw_softc *sc)
4296238405Sjkim{
4297238405Sjkim	struct urtw_data *bf;
4298238405Sjkim
4299238405Sjkim	URTW_ASSERT_LOCKED(sc);
4300238405Sjkim
4301238405Sjkim	bf = _urtw_getbuf(sc);
4302238405Sjkim	if (bf == NULL) {
4303238405Sjkim		struct ifnet *ifp = sc->sc_ifp;
4304238405Sjkim
4305238405Sjkim		DPRINTF(sc, URTW_DEBUG_XMIT, "%s: stop queue\n", __func__);
4306238405Sjkim		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4307238405Sjkim	}
4308238405Sjkim	return (bf);
4309238405Sjkim}
4310238405Sjkim
4311238405Sjkimstatic int
4312238405Sjkimurtw_isbmode(uint16_t rate)
4313238405Sjkim{
4314238405Sjkim
4315238405Sjkim	return ((rate <= 22 && rate != 12 && rate != 18) ||
4316238405Sjkim	    rate == 44) ? (1) : (0);
4317238405Sjkim}
4318238405Sjkim
4319290207Sjkimstatic uint16_t
4320290207Sjkimurtw_rate2dbps(uint16_t rate)
4321290207Sjkim{
4322290207Sjkim
4323290207Sjkim	switch(rate) {
4324290207Sjkim	case 12:
4325290207Sjkim	case 18:
4326290207Sjkim	case 24:
4327290207Sjkim	case 36:
4328290207Sjkim	case 48:
4329290207Sjkim	case 72:
4330290207Sjkim	case 96:
4331290207Sjkim	case 108:
4332290207Sjkim		return (rate * 2);
4333290207Sjkim	default:
4334290207Sjkim		break;
4335290207Sjkim	}
4336290207Sjkim	return (24);
4337290207Sjkim}
4338290207Sjkim
4339290207Sjkimstatic int
4340290207Sjkimurtw_compute_txtime(uint16_t framelen, uint16_t rate,
4341290207Sjkim    uint8_t ismgt, uint8_t isshort)
4342290207Sjkim{
4343290207Sjkim	uint16_t     ceiling, frametime, n_dbps;
4344290207Sjkim
4345290207Sjkim	if (urtw_isbmode(rate)) {
4346290207Sjkim		if (ismgt || !isshort || rate == 2)
4347290207Sjkim			frametime = (uint16_t)(144 + 48 +
4348290207Sjkim			    (framelen * 8 / (rate / 2)));
4349290207Sjkim		else
4350290207Sjkim			frametime = (uint16_t)(72 + 24 +
4351290207Sjkim			    (framelen * 8 / (rate / 2)));
4352290207Sjkim		if ((framelen * 8 % (rate / 2)) != 0)
4353290207Sjkim			frametime++;
4354290207Sjkim	} else {
4355290207Sjkim		n_dbps = urtw_rate2dbps(rate);
4356290207Sjkim		ceiling = (16 + 8 * framelen + 6) / n_dbps
4357290207Sjkim		    + (((16 + 8 * framelen + 6) % n_dbps) ? 1 : 0);
4358290207Sjkim		frametime = (uint16_t)(16 + 4 + 4 * ceiling + 6);
4359290207Sjkim	}
4360290207Sjkim	return (frametime);
4361290207Sjkim}
4362290207Sjkim
4363290207Sjkim/*
4364290207Sjkim * Callback from the 802.11 layer to update the
4365290207Sjkim * slot time based on the current setting.
4366290207Sjkim */
4367290207Sjkimstatic void
4368290207Sjkimurtw_updateslot(struct ifnet *ifp)
4369290207Sjkim{
4370290207Sjkim	struct urtw_softc *sc = ifp->if_softc;
4371290207Sjkim	struct ieee80211com *ic = ifp->if_l2com;
4372290207Sjkim
4373325337Sjkim	ieee80211_runtask(ic, &sc->sc_updateslot_task);
4374290207Sjkim}
4375290207Sjkim
4376290207Sjkimstatic void
4377290207Sjkimurtw_updateslottask(void *arg, int pending)
4378290207Sjkim{
4379290207Sjkim	struct urtw_softc *sc = arg;
4380290207Sjkim	struct ifnet *ifp = sc->sc_ifp;
4381290207Sjkim	struct ieee80211com *ic = ifp->if_l2com;
4382290207Sjkim	int error;
4383290207Sjkim
4384290207Sjkim	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
4385290207Sjkim		return;
4386290207Sjkim
4387290207Sjkim	URTW_LOCK(sc);
4388290207Sjkim	if (sc->sc_flags & URTW_RTL8187B) {
4389290207Sjkim		urtw_write8_m(sc, URTW_SIFS, 0x22);
4390290207Sjkim		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
4391290207Sjkim			urtw_write8_m(sc, URTW_SLOT, 0x9);
4392290207Sjkim		else
4393290207Sjkim			urtw_write8_m(sc, URTW_SLOT, 0x14);
4394290207Sjkim		urtw_write8_m(sc, URTW_8187B_EIFS, 0x5b);
4395290207Sjkim		urtw_write8_m(sc, URTW_CARRIER_SCOUNT, 0x5b);
4396290207Sjkim	} else {
4397290207Sjkim		urtw_write8_m(sc, URTW_SIFS, 0x22);
4398290207Sjkim		if (sc->sc_state == IEEE80211_S_ASSOC &&
4399290207Sjkim		    ic->ic_flags & IEEE80211_F_SHSLOT)
4400290207Sjkim			urtw_write8_m(sc, URTW_SLOT, 0x9);
4401290207Sjkim		else
4402290207Sjkim			urtw_write8_m(sc, URTW_SLOT, 0x14);
4403290207Sjkim		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
4404290207Sjkim			urtw_write8_m(sc, URTW_DIFS, 0x14);
4405290207Sjkim			urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x14);
4406290207Sjkim			urtw_write8_m(sc, URTW_CW_VAL, 0x73);
4407290207Sjkim		} else {
4408290207Sjkim			urtw_write8_m(sc, URTW_DIFS, 0x24);
4409290207Sjkim			urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x24);
4410290207Sjkim			urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
4411290207Sjkim		}
4412290207Sjkim	}
4413290207Sjkimfail:
4414290207Sjkim	URTW_UNLOCK(sc);
4415290207Sjkim}
4416290207Sjkim
4417290207Sjkimstatic void
4418290207Sjkimurtw_sysctl_node(struct urtw_softc *sc)
4419325337Sjkim{
4420326663Sjkim#define	URTW_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
4421326663Sjkim	SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
4422325337Sjkim	struct sysctl_ctx_list *ctx;
4423325337Sjkim	struct sysctl_oid_list *child, *parent;
4424325337Sjkim	struct sysctl_oid *tree;
4425325337Sjkim	struct urtw_stats *stats = &sc->sc_stats;
4426325337Sjkim
4427325337Sjkim	ctx = device_get_sysctl_ctx(sc->sc_dev);
4428325337Sjkim	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev));
4429325337Sjkim
4430325337Sjkim	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
4431325337Sjkim	    NULL, "URTW statistics");
4432325337Sjkim	parent = SYSCTL_CHILDREN(tree);
4433325337Sjkim
4434340704Sjkim	/* Tx statistics. */
4435352193Sjkim	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
4436	    NULL, "Tx MAC statistics");
4437	child = SYSCTL_CHILDREN(tree);
4438	URTW_SYSCTL_STAT_ADD32(ctx, child, "1m", &stats->txrates[0],
4439	    "1 Mbit/s");
4440	URTW_SYSCTL_STAT_ADD32(ctx, child, "2m", &stats->txrates[1],
4441	    "2 Mbit/s");
4442	URTW_SYSCTL_STAT_ADD32(ctx, child, "5.5m", &stats->txrates[2],
4443	    "5.5 Mbit/s");
4444	URTW_SYSCTL_STAT_ADD32(ctx, child, "6m", &stats->txrates[4],
4445	    "6 Mbit/s");
4446	URTW_SYSCTL_STAT_ADD32(ctx, child, "9m", &stats->txrates[5],
4447	    "9 Mbit/s");
4448	URTW_SYSCTL_STAT_ADD32(ctx, child, "11m", &stats->txrates[3],
4449	    "11 Mbit/s");
4450	URTW_SYSCTL_STAT_ADD32(ctx, child, "12m", &stats->txrates[6],
4451	    "12 Mbit/s");
4452	URTW_SYSCTL_STAT_ADD32(ctx, child, "18m", &stats->txrates[7],
4453	    "18 Mbit/s");
4454	URTW_SYSCTL_STAT_ADD32(ctx, child, "24m", &stats->txrates[8],
4455	    "24 Mbit/s");
4456	URTW_SYSCTL_STAT_ADD32(ctx, child, "36m", &stats->txrates[9],
4457	    "36 Mbit/s");
4458	URTW_SYSCTL_STAT_ADD32(ctx, child, "48m", &stats->txrates[10],
4459	    "48 Mbit/s");
4460	URTW_SYSCTL_STAT_ADD32(ctx, child, "54m", &stats->txrates[11],
4461	    "54 Mbit/s");
4462#undef URTW_SYSCTL_STAT_ADD32
4463}
4464
4465static device_method_t urtw_methods[] = {
4466	DEVMETHOD(device_probe, urtw_match),
4467	DEVMETHOD(device_attach, urtw_attach),
4468	DEVMETHOD(device_detach, urtw_detach),
4469	DEVMETHOD_END
4470};
4471static driver_t urtw_driver = {
4472	.name = "urtw",
4473	.methods = urtw_methods,
4474	.size = sizeof(struct urtw_softc)
4475};
4476static devclass_t urtw_devclass;
4477
4478DRIVER_MODULE(urtw, uhub, urtw_driver, urtw_devclass, NULL, 0);
4479MODULE_DEPEND(urtw, wlan, 1, 1, 1);
4480MODULE_DEPEND(urtw, usb, 1, 1, 1);
4481MODULE_VERSION(urtw, 1);
4482