summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorweongyo <weongyo@FreeBSD.org>2009-05-27 03:57:38 +0000
committerweongyo <weongyo@FreeBSD.org>2009-05-27 03:57:38 +0000
commitc6ef0a3a393e76e0e3c3043a8144919064f5a854 (patch)
tree5fe0d8a2ed5e63101d8743bd72258f12ddbd0243 /sys/dev
parent8e9cac6f75099387d986f926f4cd0a0e25c4ad6c (diff)
downloadFreeBSD-src-c6ef0a3a393e76e0e3c3043a8144919064f5a854.zip
FreeBSD-src-c6ef0a3a393e76e0e3c3043a8144919064f5a854.tar.gz
ports urtw(4) for USB2. Additionally it supports a 8187B chipset weakly
that it needs more stabilization.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/wlan/if_urtw.c4241
-rw-r--r--sys/dev/usb/wlan/if_urtwreg.h303
-rw-r--r--sys/dev/usb/wlan/if_urtwvar.h174
3 files changed, 4718 insertions, 0 deletions
diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c
new file mode 100644
index 0000000..0124023
--- /dev/null
+++ b/sys/dev/usb/wlan/if_urtw.c
@@ -0,0 +1,4241 @@
+/*-
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kdb.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_error.h>
+#include <dev/usb/usb_lookup.h>
+#include <dev/usb/usb_request.h>
+#include <dev/usb/usb_util.h>
+#include "usbdevs.h"
+
+#include <dev/usb/wlan/if_urtwreg.h>
+#include <dev/usb/wlan/if_urtwvar.h>
+
+SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L");
+#ifdef URTW_DEBUG
+int urtw_debug = 0;
+SYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW, &urtw_debug, 0,
+ "control debugging printfs");
+TUNABLE_INT("hw.usb.urtw.debug", &urtw_debug);
+enum {
+ URTW_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
+ URTW_DEBUG_RECV = 0x00000002, /* basic recv operation */
+ URTW_DEBUG_RESET = 0x00000004, /* reset processing */
+ URTW_DEBUG_TX_PROC = 0x00000008, /* tx ISR proc */
+ URTW_DEBUG_RX_PROC = 0x00000010, /* rx ISR proc */
+ URTW_DEBUG_STATE = 0x00000020, /* 802.11 state transitions */
+ URTW_DEBUG_STAT = 0x00000040, /* statistic */
+ URTW_DEBUG_INIT = 0x00000080, /* initialization of dev */
+ URTW_DEBUG_ANY = 0xffffffff
+};
+#define DPRINTF(sc, m, fmt, ...) do { \
+ if (sc->sc_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, m, fmt, ...) do { \
+ (void) sc; \
+} while (0)
+#endif
+int urtw_preamble_mode = URTW_PREAMBLE_MODE_LONG;
+SYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW,
+ &urtw_preamble_mode, 0, "set the preable mode (long or short)");
+TUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode);
+
+/* recognized device vendors/products */
+#define urtw_lookup(v, p) \
+ ((const struct urtw_type *)usb_lookup(urtw_devs, v, p))
+#define URTW_DEV_B(v,p) \
+ { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187B) }
+#define URTW_DEV_L(v,p) \
+ { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) }
+#define URTW_REV_RTL8187B 0
+#define URTW_REV_RTL8187L 1
+static const struct usb2_device_id urtw_devs[] = {
+ { USB_VPI(USB_VENDOR_BELKIN, 0x705e, URTW_REV_RTL8187B) },
+ { USB_VPI(USB_VENDOR_REALTEK, 0x8189, URTW_REV_RTL8187B) },
+ { USB_VPI(USB_VENDOR_REALTEK, 0x8197, URTW_REV_RTL8187B) },
+ { USB_VPI(USB_VENDOR_REALTEK, 0x8198, URTW_REV_RTL8187B) },
+ { USB_VPI(USB_VENDOR_NETGEAR, 0x4260, URTW_REV_RTL8187B) },
+ { USB_VPI(0x1b75, 0x8187, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_ASUS, 0x171d, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_NETGEAR, 0x6100, URTW_REV_RTL8187L) },
+ URTW_DEV_L(NETGEAR, WG111V2),
+ URTW_DEV_L(REALTEK, RTL8187),
+ { USB_VPI(USB_VENDOR_SITECOMEU, 0x000d, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_SPHAIRON, 0x0150, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_SURECOM, 0x11f2, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_QCOM, 0x6232, URTW_REV_RTL8187L) },
+#undef URTW_DEV_L
+#undef URTW_DEV_B
+};
+
+#define urtw_read8_m(sc, val, data) do { \
+ error = urtw_read8_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_write8_m(sc, val, data) do { \
+ error = urtw_write8_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_read16_m(sc, val, data) do { \
+ error = urtw_read16_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_write16_m(sc, val, data) do { \
+ error = urtw_write16_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_read32_m(sc, val, data) do { \
+ error = urtw_read32_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_write32_m(sc, val, data) do { \
+ error = urtw_write32_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_8187_write_phy_ofdm(sc, val, data) do { \
+ error = urtw_8187_write_phy_ofdm_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_8187_write_phy_cck(sc, val, data) do { \
+ error = urtw_8187_write_phy_cck_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+#define urtw_8225_write(sc, val, data) do { \
+ error = urtw_8225_write_c(sc, val, data); \
+ if (error != 0) \
+ goto fail; \
+} while (0)
+
+struct urtw_pair {
+ uint32_t reg;
+ uint32_t val;
+};
+
+static uint8_t urtw_8225_agc[] = {
+ 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b,
+ 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+ 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85,
+ 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a,
+ 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f,
+ 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
+ 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19,
+ 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+ 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static uint8_t urtw_8225z2_agc[] = {
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51,
+ 0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b,
+ 0x39, 0x37, 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25,
+ 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f,
+ 0x0d, 0x0b, 0x09, 0x07, 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
+ 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
+ 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31,
+ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
+};
+
+static uint32_t urtw_8225_channel[] = {
+ 0x0000, /* dummy channel 0 */
+ 0x085c, /* 1 */
+ 0x08dc, /* 2 */
+ 0x095c, /* 3 */
+ 0x09dc, /* 4 */
+ 0x0a5c, /* 5 */
+ 0x0adc, /* 6 */
+ 0x0b5c, /* 7 */
+ 0x0bdc, /* 8 */
+ 0x0c5c, /* 9 */
+ 0x0cdc, /* 10 */
+ 0x0d5c, /* 11 */
+ 0x0ddc, /* 12 */
+ 0x0e5c, /* 13 */
+ 0x0f72, /* 14 */
+};
+
+static uint8_t urtw_8225_gain[] = {
+ 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */
+ 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */
+ 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */
+ 0x33, 0x80, 0x79, 0xc5, /* -78dbm */
+ 0x43, 0x78, 0x76, 0xc5, /* -74dbm */
+ 0x53, 0x60, 0x73, 0xc5, /* -70dbm */
+ 0x63, 0x58, 0x70, 0xc5, /* -66dbm */
+};
+
+static struct urtw_pair urtw_8225_rf_part1[] = {
+ { 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
+ { 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a },
+ { 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 },
+ { 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 },
+};
+
+static struct urtw_pair urtw_8225_rf_part2[] = {
+ { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
+ { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
+ { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 },
+ { 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 },
+ { 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 },
+ { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef },
+ { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 },
+ { 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 },
+ { 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 },
+ { 0x27, 0x88 }
+};
+
+static struct urtw_pair urtw_8225_rf_part3[] = {
+ { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
+ { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b },
+ { 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 },
+ { 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d },
+ { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e },
+ { 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a },
+ { 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 }
+};
+
+static uint16_t urtw_8225_rxgain[] = {
+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+ 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+ 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static uint8_t urtw_8225_threshold[] = {
+ 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd,
+};
+
+static uint8_t urtw_8225_tx_gain_cck_ofdm[] = {
+ 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static uint8_t urtw_8225_txpwr_cck[] = {
+ 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+ 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+ 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+ 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static uint8_t urtw_8225_txpwr_cck_ch14[] = {
+ 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static uint8_t urtw_8225_txpwr_ofdm[]={
+ 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static uint8_t urtw_8225v2_gain_bg[]={
+ 0x23, 0x15, 0xa5, /* -82-1dbm */
+ 0x23, 0x15, 0xb5, /* -82-2dbm */
+ 0x23, 0x15, 0xc5, /* -82-3dbm */
+ 0x33, 0x15, 0xc5, /* -78dbm */
+ 0x43, 0x15, 0xc5, /* -74dbm */
+ 0x53, 0x15, 0xc5, /* -70dbm */
+ 0x63, 0x15, 0xc5, /* -66dbm */
+};
+
+static struct urtw_pair urtw_8225v2_rf_part1[] = {
+ { 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
+ { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
+ { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
+ { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
+};
+
+static struct urtw_pair urtw_8225v2b_rf_part1[] = {
+ { 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 },
+ { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a },
+ { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb },
+ { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }
+};
+
+static struct urtw_pair urtw_8225v2_rf_part2[] = {
+ { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 },
+ { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 },
+ { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 },
+ { 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 },
+ { 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 },
+ { 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 },
+ { 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 },
+ { 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 },
+ { 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 },
+ { 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 }
+};
+
+static struct urtw_pair urtw_8225v2b_rf_part2[] = {
+ { 0x00, 0x10 }, { 0x01, 0x0d }, { 0x02, 0x01 }, { 0x03, 0x00 },
+ { 0x04, 0x14 }, { 0x05, 0xfb }, { 0x06, 0xfb }, { 0x07, 0x60 },
+ { 0x08, 0x00 }, { 0x09, 0x60 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x0c, 0x00 }, { 0x0d, 0x5c }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
+ { 0x10, 0x40 }, { 0x11, 0x00 }, { 0x12, 0x40 }, { 0x13, 0x00 },
+ { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0xa8 }, { 0x17, 0x26 },
+ { 0x18, 0x32 }, { 0x19, 0x33 }, { 0x1a, 0x07 }, { 0x1b, 0xa5 },
+ { 0x1c, 0x6f }, { 0x1d, 0x55 }, { 0x1e, 0xc8 }, { 0x1f, 0xb3 },
+ { 0x20, 0x0a }, { 0x21, 0xe1 }, { 0x22, 0x2C }, { 0x23, 0x8a },
+ { 0x24, 0x86 }, { 0x25, 0x83 }, { 0x26, 0x34 }, { 0x27, 0x0f },
+ { 0x28, 0x4f }, { 0x29, 0x24 }, { 0x2a, 0x6f }, { 0x2b, 0xc2 },
+ { 0x2c, 0x6b }, { 0x2d, 0x40 }, { 0x2e, 0x80 }, { 0x2f, 0x00 },
+ { 0x30, 0xc0 }, { 0x31, 0xc1 }, { 0x32, 0x58 }, { 0x33, 0xf1 },
+ { 0x34, 0x00 }, { 0x35, 0xe4 }, { 0x36, 0x90 }, { 0x37, 0x3e },
+ { 0x38, 0x6d }, { 0x39, 0x3c }, { 0x3a, 0xfb }, { 0x3b, 0x07 }
+};
+
+static struct urtw_pair urtw_8225v2_rf_part3[] = {
+ { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 },
+ { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 },
+ { 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 },
+ { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 },
+ { 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d },
+ { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 },
+ { 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 },
+ { 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 }
+};
+
+static uint16_t urtw_8225v2_rxgain[] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
+ 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
+ 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
+ 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
+ 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
+ 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
+ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
+ 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
+ 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
+ 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
+ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static uint16_t urtw_8225v2b_rxgain[] = {
+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+};
+
+static uint8_t urtw_8225v2_txpwr_cck[] = {
+ 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static uint8_t urtw_8225v2_txpwr_cck_ch14[] = {
+ 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static uint8_t urtw_8225v2b_txpwr_cck[] = {
+ 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
+ 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
+ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
+ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
+};
+
+static uint8_t urtw_8225v2b_txpwr_cck_ch14[] = {
+ 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static struct urtw_pair urtw_ratetable[] = {
+ { 2, 0 }, { 4, 1 }, { 11, 2 }, { 12, 4 }, { 18, 5 },
+ { 22, 3 }, { 24, 6 }, { 36, 7 }, { 48, 8 }, { 72, 9 },
+ { 96, 10 }, { 108, 11 }
+};
+
+static const uint8_t urtw_8187b_reg_table[][3] = {
+ { 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 },
+ { 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 },
+ { 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 },
+ { 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 },
+ { 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 },
+ { 0xff, 0x00, 0 }, { 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 },
+ { 0x5a, 0x4b, 1 }, { 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 },
+ { 0x61, 0x09, 1 }, { 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 },
+ { 0xce, 0x0f, 1 }, { 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 },
+ { 0xe1, 0x0f, 1 }, { 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 },
+ { 0xf1, 0x01, 1 }, { 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 },
+ { 0xf4, 0x04, 1 }, { 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 },
+ { 0xf7, 0x07, 1 }, { 0xf8, 0x08, 1 }, { 0x4e, 0x00, 2 },
+ { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 }, { 0x22, 0x68, 2 },
+ { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 }, { 0x25, 0x7d, 2 },
+ { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 }, { 0x4d, 0x08, 2 },
+ { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 }, { 0x52, 0x04, 2 },
+ { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 }, { 0x55, 0x23, 2 },
+ { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 }, { 0x58, 0x08, 2 },
+ { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 }, { 0x5b, 0x08, 2 },
+ { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 }, { 0x62, 0x08, 2 },
+ { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 }, { 0x72, 0x56, 2 },
+ { 0x73, 0x9a, 2 }, { 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 },
+ { 0x5b, 0x40, 0 }, { 0x84, 0x88, 0 }, { 0x85, 0x24, 0 },
+ { 0x88, 0x54, 0 }, { 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 },
+ { 0x8d, 0x00, 0 }, { 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 },
+ { 0x96, 0x00, 0 }, { 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 },
+ { 0x9f, 0x10, 0 }, { 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 },
+ { 0xdb, 0x00, 0 }, { 0xee, 0x00, 0 }, { 0x91, 0x03, 0 },
+ { 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 },
+ { 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 }
+};
+
+static usb2_callback_t urtw_bulk_rx_callback;
+static usb2_callback_t urtw_bulk_tx_callback;
+
+static const struct usb2_config urtw_8187b_usbconfig[URTW_8187B_N_XFERS] = {
+ [URTW_8187B_BULK_RX] = {
+ .type = UE_BULK,
+ .endpoint = 0x83,
+ .direction = UE_DIR_IN,
+ .bufsize = MCLBYTES,
+ .flags = {
+ .ext_buffer = 1,
+ .pipe_bof = 1,
+ .short_xfer_ok = 1
+ },
+ .callback = urtw_bulk_rx_callback
+ },
+ [URTW_8187B_BULK_TX_BE] = {
+ .type = UE_BULK,
+ .endpoint = URTW_8187B_TXPIPE_BE,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+ [URTW_8187B_BULK_TX_BK] = {
+ .type = UE_BULK,
+ .endpoint = URTW_8187B_TXPIPE_BK,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+ [URTW_8187B_BULK_TX_VI] = {
+ .type = UE_BULK,
+ .endpoint = URTW_8187B_TXPIPE_VI,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+ [URTW_8187B_BULK_TX_VO] = {
+ .type = UE_BULK,
+ .endpoint = URTW_8187B_TXPIPE_VO,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+ [URTW_8187B_BULK_TX_EP12] = {
+ .type = UE_BULK,
+ .endpoint = 0xc,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ }
+};
+
+static const struct usb2_config urtw_8187l_usbconfig[URTW_8187L_N_XFERS] = {
+ [URTW_8187L_BULK_RX] = {
+ .type = UE_BULK,
+ .endpoint = 0x81,
+ .direction = UE_DIR_IN,
+ .bufsize = MCLBYTES,
+ .flags = {
+ .ext_buffer = 1,
+ .pipe_bof = 1,
+ .short_xfer_ok = 1
+ },
+ .callback = urtw_bulk_rx_callback
+ },
+ [URTW_8187L_BULK_TX_LOW] = {
+ .type = UE_BULK,
+ .endpoint = 0x2,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+ [URTW_8187L_BULK_TX_NORMAL] = {
+ .type = UE_BULK,
+ .endpoint = 0x3,
+ .direction = UE_DIR_OUT,
+ .bufsize = URTW_TX_MAXSIZE,
+ .flags = {
+ .ext_buffer = 1,
+ .force_short_xfer = 1,
+ .pipe_bof = 1,
+ },
+ .callback = urtw_bulk_tx_callback,
+ .timeout = URTW_DATA_TIMEOUT
+ },
+};
+
+static struct ieee80211vap *urtw_vap_create(struct ieee80211com *,
+ const char name[IFNAMSIZ], int unit, int opmode,
+ int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void urtw_vap_delete(struct ieee80211vap *);
+static void urtw_init(void *);
+static void urtw_stop(struct ifnet *, int);
+static void urtw_stop_locked(struct ifnet *, int);
+static int urtw_ioctl(struct ifnet *, u_long, caddr_t);
+static void urtw_start(struct ifnet *);
+static int urtw_alloc_rx_data_list(struct urtw_softc *);
+static int urtw_alloc_tx_data_list(struct urtw_softc *);
+static int urtw_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+static void urtw_scan_start(struct ieee80211com *);
+static void urtw_scan_end(struct ieee80211com *);
+static void urtw_set_channel(struct ieee80211com *);
+static void urtw_update_mcast(struct ifnet *);
+static int urtw_tx_start(struct urtw_softc *,
+ struct ieee80211_node *, struct mbuf *,
+ struct urtw_data *, int);
+static int urtw_newstate(struct ieee80211vap *,
+ enum ieee80211_state, int);
+static void urtw_led_ch(void *);
+static void urtw_ledtask(void *, int);
+static void urtw_watchdog(void *);
+static void urtw_set_multi(void *);
+static int urtw_isbmode(uint16_t);
+static uint16_t urtw_rate2rtl(int);
+static uint16_t urtw_rtl2rate(int);
+static usb2_error_t urtw_set_rate(struct urtw_softc *);
+static usb2_error_t urtw_update_msr(struct urtw_softc *);
+static usb2_error_t urtw_read8_c(struct urtw_softc *, int, uint8_t *);
+static usb2_error_t urtw_read16_c(struct urtw_softc *, int, uint16_t *);
+static usb2_error_t urtw_read32_c(struct urtw_softc *, int, uint32_t *);
+static usb2_error_t urtw_write8_c(struct urtw_softc *, int, uint8_t);
+static usb2_error_t urtw_write16_c(struct urtw_softc *, int, uint16_t);
+static usb2_error_t urtw_write32_c(struct urtw_softc *, int, uint32_t);
+static usb2_error_t urtw_eprom_cs(struct urtw_softc *, int);
+static usb2_error_t urtw_eprom_ck(struct urtw_softc *);
+static usb2_error_t urtw_eprom_sendbits(struct urtw_softc *, int16_t *,
+ int);
+static usb2_error_t urtw_eprom_read32(struct urtw_softc *, uint32_t,
+ uint32_t *);
+static usb2_error_t urtw_eprom_readbit(struct urtw_softc *, int16_t *);
+static usb2_error_t urtw_eprom_writebit(struct urtw_softc *, int16_t);
+static usb2_error_t urtw_get_macaddr(struct urtw_softc *);
+static usb2_error_t urtw_get_txpwr(struct urtw_softc *);
+static usb2_error_t urtw_get_rfchip(struct urtw_softc *);
+static usb2_error_t urtw_led_init(struct urtw_softc *);
+static usb2_error_t urtw_8185_rf_pins_enable(struct urtw_softc *);
+static usb2_error_t urtw_8185_tx_antenna(struct urtw_softc *, uint8_t);
+static usb2_error_t urtw_8187_write_phy(struct urtw_softc *, uint8_t,
+ uint32_t);
+static usb2_error_t urtw_8187_write_phy_ofdm_c(struct urtw_softc *,
+ uint8_t, uint32_t);
+static usb2_error_t urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t,
+ uint32_t);
+static usb2_error_t urtw_8225_setgain(struct urtw_softc *, int16_t);
+static usb2_error_t urtw_8225_usb_init(struct urtw_softc *);
+static usb2_error_t urtw_8225_write_c(struct urtw_softc *, uint8_t,
+ uint16_t);
+static usb2_error_t urtw_8225_write_s16(struct urtw_softc *, uint8_t, int,
+ uint16_t *);
+static usb2_error_t urtw_8225_read(struct urtw_softc *, uint8_t,
+ uint32_t *);
+static usb2_error_t urtw_8225_rf_init(struct urtw_softc *);
+static usb2_error_t urtw_8225_rf_set_chan(struct urtw_softc *, int);
+static usb2_error_t urtw_8225_rf_set_sens(struct urtw_softc *, int);
+static usb2_error_t urtw_8225_set_txpwrlvl(struct urtw_softc *, int);
+static usb2_error_t urtw_8225_rf_stop(struct urtw_softc *);
+static usb2_error_t urtw_8225v2_rf_init(struct urtw_softc *);
+static usb2_error_t urtw_8225v2_rf_set_chan(struct urtw_softc *, int);
+static usb2_error_t urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int);
+static usb2_error_t urtw_8225v2_setgain(struct urtw_softc *, int16_t);
+static usb2_error_t urtw_8225_isv2(struct urtw_softc *, int *);
+static usb2_error_t urtw_8225v2b_rf_init(struct urtw_softc *);
+static usb2_error_t urtw_8225v2b_rf_set_chan(struct urtw_softc *, int);
+static usb2_error_t urtw_read8e(struct urtw_softc *, int, uint8_t *);
+static usb2_error_t urtw_write8e(struct urtw_softc *, int, uint8_t);
+static usb2_error_t urtw_8180_set_anaparam(struct urtw_softc *, uint32_t);
+static usb2_error_t urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t);
+static usb2_error_t urtw_intr_enable(struct urtw_softc *);
+static usb2_error_t urtw_intr_disable(struct urtw_softc *);
+static usb2_error_t urtw_reset(struct urtw_softc *);
+static usb2_error_t urtw_led_on(struct urtw_softc *, int);
+static usb2_error_t urtw_led_ctl(struct urtw_softc *, int);
+static usb2_error_t urtw_led_blink(struct urtw_softc *);
+static usb2_error_t urtw_led_mode0(struct urtw_softc *, int);
+static usb2_error_t urtw_led_mode1(struct urtw_softc *, int);
+static usb2_error_t urtw_led_mode2(struct urtw_softc *, int);
+static usb2_error_t urtw_led_mode3(struct urtw_softc *, int);
+static usb2_error_t urtw_rx_setconf(struct urtw_softc *);
+static usb2_error_t urtw_rx_enable(struct urtw_softc *);
+static usb2_error_t urtw_tx_enable(struct urtw_softc *sc);
+static void urtw_free_tx_data_list(struct urtw_softc *);
+static void urtw_free_rx_data_list(struct urtw_softc *);
+static void urtw_free_data_list(struct urtw_softc *,
+ struct urtw_data data[], int, int);
+static usb2_error_t urtw_adapter_start(struct urtw_softc *);
+static usb2_error_t urtw_adapter_start_b(struct urtw_softc *);
+static usb2_error_t urtw_set_mode(struct urtw_softc *, uint32_t);
+static usb2_error_t urtw_8187b_cmd_reset(struct urtw_softc *);
+static usb2_error_t urtw_write16_i(struct urtw_softc *, int, uint16_t, int);
+static usb2_error_t urtw_write8_i(struct urtw_softc *, int, uint8_t, int);
+static usb2_error_t urtw_write32_i(struct urtw_softc *, int, uint32_t, int);
+static usb2_error_t urtw_do_request(struct urtw_softc *,
+ struct usb2_device_request *, void *);
+static usb2_error_t urtw_8225v2b_set_txpwrlvl(struct urtw_softc *, int);
+static usb2_error_t urtw_led_off(struct urtw_softc *, int);
+static void urtw_abort_xfers(struct urtw_softc *);
+static struct urtw_data *
+ urtw_getbuf(struct urtw_softc *sc);
+
+static int
+urtw_match(device_t dev)
+{
+ struct usb2_attach_arg *uaa = device_get_ivars(dev);
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+ if (uaa->info.bConfigIndex != URTW_CONFIG_INDEX)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != URTW_IFACE_INDEX)
+ return (ENXIO);
+
+ return (usb2_lookup_id_by_uaa(urtw_devs, sizeof(urtw_devs), uaa));
+}
+
+static int
+urtw_attach(device_t dev)
+{
+ const struct usb2_config *setup_start;
+ int ret = ENXIO;
+ struct urtw_softc *sc = device_get_softc(dev);
+ struct usb2_attach_arg *uaa = device_get_ivars(dev);
+ struct ieee80211com *ic;
+ struct ifnet *ifp;
+ uint8_t bands, iface_index = URTW_IFACE_INDEX; /* XXX */
+ uint16_t n_setup;
+ uint32_t data;
+ usb2_error_t error;
+
+ device_set_usb2_desc(dev);
+
+ sc->sc_dev = dev;
+ sc->sc_udev = uaa->device;
+ if (USB_GET_DRIVER_INFO(uaa) == URTW_REV_RTL8187B)
+ sc->sc_flags |= URTW_RTL8187B;
+#ifdef URTW_DEBUG
+ sc->sc_debug = urtw_debug;
+#endif
+
+ mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ usb2_callout_init_mtx(&sc->sc_led_ch, &sc->sc_mtx, 0);
+ TASK_INIT(&sc->sc_led_task, 0, urtw_ledtask, sc);
+ callout_init(&sc->sc_watchdog_ch, 0);
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ setup_start = urtw_8187b_usbconfig;
+ n_setup = URTW_8187B_N_XFERS;
+ } else {
+ setup_start = urtw_8187l_usbconfig;
+ n_setup = URTW_8187L_N_XFERS;
+ }
+
+ error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
+ setup_start, n_setup, sc, &sc->sc_mtx);
+ if (error) {
+ device_printf(dev, "could not allocate USB transfers, "
+ "err=%s\n", usb2_errstr(error));
+ ret = ENXIO;
+ goto fail0;
+ }
+
+ URTW_LOCK(sc);
+
+ urtw_read32_m(sc, URTW_RX, &data);
+ sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 :
+ URTW_EEPROM_93C46;
+
+ error = urtw_get_rfchip(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_get_macaddr(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_get_txpwr(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_led_init(sc);
+ if (error != 0)
+ goto fail;
+
+ URTW_UNLOCK(sc);
+
+ sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY;
+ sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY;
+ sc->sc_currate = 3;
+ sc->sc_preamble_mode = urtw_preamble_mode;
+
+ ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+ if (ifp == NULL) {
+ device_printf(sc->sc_dev, "can not allocate ifnet\n");
+ ret = ENOMEM;
+ goto fail1;
+ }
+
+ ifp->if_softc = sc;
+ if_initname(ifp, "urtw", device_get_unit(sc->sc_dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = urtw_init;
+ ifp->if_ioctl = urtw_ioctl;
+ ifp->if_start = urtw_start;
+ /* XXX URTW_TX_DATA_LIST_COUNT */
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ic = ifp->if_l2com;
+ ic->ic_ifp = ifp;
+ ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+
+ /* set device capabilities */
+ ic->ic_caps =
+ IEEE80211_C_STA | /* station mode */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
+ IEEE80211_C_TXPMGT | /* tx power management */
+ IEEE80211_C_SHPREAMBLE | /* short preamble supported */
+ IEEE80211_C_SHSLOT | /* short slot time supported */
+ IEEE80211_C_BGSCAN | /* capable of bg scanning */
+ IEEE80211_C_WPA; /* 802.11i */
+
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ ieee80211_init_channels(ic, NULL, &bands);
+
+ ieee80211_ifattach(ic, sc->sc_bssid);
+ ic->ic_raw_xmit = urtw_raw_xmit;
+ ic->ic_scan_start = urtw_scan_start;
+ ic->ic_scan_end = urtw_scan_end;
+ ic->ic_set_channel = urtw_set_channel;
+
+ ic->ic_vap_create = urtw_vap_create;
+ ic->ic_vap_delete = urtw_vap_delete;
+ ic->ic_update_mcast = urtw_update_mcast;
+
+ ieee80211_radiotap_attach(ic,
+ &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
+ URTW_TX_RADIOTAP_PRESENT,
+ &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
+ URTW_RX_RADIOTAP_PRESENT);
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+ return (0);
+
+fail: URTW_UNLOCK(sc);
+fail1: usb2_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ?
+ URTW_8187B_N_XFERS : URTW_8187L_N_XFERS);
+fail0:
+ return (ret);
+}
+
+static int
+urtw_detach(device_t dev)
+{
+ struct urtw_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if (!device_is_attached(dev))
+ return (0);
+
+ urtw_stop(ifp, 1);
+ ieee80211_draintask(ic, &sc->sc_led_task);
+
+ usb2_callout_drain(&sc->sc_led_ch);
+ callout_drain(&sc->sc_watchdog_ch);
+
+ usb2_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ?
+ URTW_8187B_N_XFERS : URTW_8187L_N_XFERS);
+ ieee80211_ifdetach(ic);
+
+ urtw_free_tx_data_list(sc);
+ urtw_free_rx_data_list(sc);
+
+ if_free(ifp);
+ mtx_destroy(&sc->sc_mtx);
+
+ return (0);
+}
+
+static void
+urtw_free_tx_data_list(struct urtw_softc *sc)
+{
+
+ urtw_free_data_list(sc, sc->sc_tx, URTW_TX_DATA_LIST_COUNT, 0);
+}
+
+static void
+urtw_free_rx_data_list(struct urtw_softc *sc)
+{
+
+ urtw_free_data_list(sc, sc->sc_rx, URTW_RX_DATA_LIST_COUNT, 1);
+}
+
+static void
+urtw_free_data_list(struct urtw_softc *sc, struct urtw_data data[], int ndata,
+ int fillmbuf)
+{
+ int i;
+
+ for (i = 0; i < ndata; i++) {
+ struct urtw_data *dp = &data[i];
+
+ if (fillmbuf == 1) {
+ if (dp->m != NULL) {
+ m_freem(dp->m);
+ dp->m = NULL;
+ dp->buf = NULL;
+ }
+ } else {
+ if (dp->buf != NULL) {
+ free(dp->buf, M_USBDEV);
+ dp->buf = NULL;
+ }
+ }
+ if (dp->ni != NULL) {
+ ieee80211_free_node(dp->ni);
+ dp->ni = NULL;
+ }
+ }
+}
+
+static struct ieee80211vap *
+urtw_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct urtw_vap *uvp;
+ struct ieee80211vap *vap;
+
+ if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
+ return (NULL);
+ uvp = (struct urtw_vap *) malloc(sizeof(struct urtw_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (uvp == NULL)
+ return (NULL);
+ vap = &uvp->vap;
+ /* enable s/w bmiss handling for sta mode */
+ ieee80211_vap_setup(ic, vap, name, unit, opmode,
+ flags | IEEE80211_CLONE_NOBEACONS, bssid, mac);
+
+ /* override state transition machine */
+ uvp->newstate = vap->iv_newstate;
+ vap->iv_newstate = urtw_newstate;
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, ieee80211_media_change,
+ ieee80211_media_status);
+ ic->ic_opmode = opmode;
+ return (vap);
+}
+
+static void
+urtw_vap_delete(struct ieee80211vap *vap)
+{
+ struct urtw_vap *uvp = URTW_VAP(vap);
+
+ ieee80211_vap_detach(vap);
+ free(uvp, M_80211_VAP);
+}
+
+static void
+urtw_init_locked(void *arg)
+{
+ int ret;
+ struct urtw_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ usb2_error_t error;
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ urtw_stop_locked(ifp, 0);
+
+ error = (sc->sc_flags & URTW_RTL8187B) ? urtw_adapter_start_b(sc) :
+ urtw_adapter_start(sc);
+ if (error != 0)
+ goto fail;
+
+ /* reset softc variables */
+ sc->sc_txtimer = 0;
+
+ if (!(sc->sc_flags & URTW_INIT_ONCE)) {
+ ret = urtw_alloc_rx_data_list(sc);
+ if (error != 0)
+ goto fail;
+ ret = urtw_alloc_tx_data_list(sc);
+ if (error != 0)
+ goto fail;
+ sc->sc_flags |= URTW_INIT_ONCE;
+ }
+
+ error = urtw_rx_enable(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_tx_enable(sc);
+ if (error != 0)
+ goto fail;
+
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+ callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
+fail:
+ return;
+}
+
+static void
+urtw_init(void *arg)
+{
+ struct urtw_softc *sc = arg;
+
+ URTW_LOCK(sc);
+ urtw_init_locked(arg);
+ URTW_UNLOCK(sc);
+}
+
+static usb2_error_t
+urtw_adapter_start_b(struct urtw_softc *sc)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+ uint8_t data8;
+ usb2_error_t error;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_CONFIG3, &data8);
+ urtw_write8_m(sc, URTW_CONFIG3,
+ data8 | URTW_CONFIG3_ANAPARAM_WRITE | URTW_CONFIG3_GNT_SELECT);
+ urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON);
+ urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON);
+ urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON);
+
+ urtw_write8_m(sc, 0x61, 0x10);
+ urtw_read8_m(sc, 0x62, &data8);
+ urtw_write8_m(sc, 0x62, data8 & ~(1 << 5));
+ urtw_write8_m(sc, 0x62, data8 | (1 << 5));
+
+ urtw_read8_m(sc, URTW_CONFIG3, &data8);
+ data8 &= ~URTW_CONFIG3_ANAPARAM_WRITE;
+ urtw_write8_m(sc, URTW_CONFIG3, data8);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ error = urtw_8187b_cmd_reset(sc);
+ if (error)
+ goto fail;
+
+ urtw_write16_m(sc, 0x2d, 0xfff);
+ urtw_read8_m(sc, URTW_CW_CONF, &data8);
+ urtw_write8_m(sc, URTW_CW_CONF, data8 | URTW_CW_CONF_PERPACKET_RETRY);
+ urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
+ data8 |= URTW_TX_AGC_CTL_PERPACKET_GAIN |
+ URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
+ urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
+
+ error = urtw_write16_i(sc, 0xe0, 0xfff, 1);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_RATE_FALLBACK, &data8);
+ urtw_write8_m(sc, URTW_RATE_FALLBACK, data8 | URTW_RATE_FALLBACK_ENABLE);
+
+ urtw_write16_m(sc, URTW_ATIM_WND, 2);
+ urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
+ error = urtw_write16_i(sc, 0xd4, 0xffff, 1);
+ if (error)
+ goto fail;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ urtw_read8_m(sc, URTW_CONFIG1, &data8);
+ urtw_write8_m(sc, URTW_CONFIG1, (data8 & 0x3f) | 0x80);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
+ for (i = 0; i < N(urtw_8187b_reg_table); i++) {
+ error = urtw_write8_i(sc, urtw_8187b_reg_table[i][0],
+ urtw_8187b_reg_table[i][1], urtw_8187b_reg_table[i][2]);
+ if (error)
+ goto fail;
+ }
+
+ urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50);
+ urtw_write16_m(sc, URTW_INT_MIG, 0);
+
+ error = urtw_write32_i(sc, 0xf0, 0, 1);
+ if (error)
+ goto fail;
+ error = urtw_write32_i(sc, 0xf4, 0, 1);
+ if (error)
+ goto fail;
+ error = urtw_write8_i(sc, 0xf8, 0, 1);
+ if (error)
+ goto fail;
+
+ urtw_write32_m(sc, URTW_RF_TIMING, 0x00004001);
+
+ error = urtw_write16_i(sc, 0x72, 0x569a, 2);
+ if (error)
+ goto fail;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ urtw_read8_m(sc, URTW_CONFIG3, &data8);
+ urtw_write8_m(sc, URTW_CONFIG3, data8 | URTW_CONFIG3_ANAPARAM_WRITE);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488);
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ error = sc->sc_rf_init(sc);
+ if (error != 0)
+ goto fail;
+
+ error = urtw_intr_enable(sc);
+ if (error)
+ goto fail;
+
+ error = urtw_write8e(sc, 0x41, 0xf4);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x40, 0x00);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x42, 0x00);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x42, 0x01);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x40, 0x0f);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x42, 0x00);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x42, 0x01);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, 0xdb, &data8);
+ urtw_write8_m(sc, 0xdb, data8 | (1 << 2));
+ error = urtw_write16_i(sc, 0x72, 0x59fa, 3);
+ if (error)
+ goto fail;
+ error = urtw_write16_i(sc, 0x74, 0x59d2, 3);
+ if (error)
+ goto fail;
+ error = urtw_write16_i(sc, 0x76, 0x59d2, 3);
+ if (error)
+ goto fail;
+ error = urtw_write16_i(sc, 0x78, 0x19fa, 3);
+ if (error)
+ goto fail;
+ error = urtw_write16_i(sc, 0x7a, 0x19fa, 3);
+ if (error)
+ goto fail;
+ error = urtw_write16_i(sc, 0x7c, 0x00d0, 3);
+ if (error)
+ goto fail;
+ urtw_write8_m(sc, 0x61, 0);
+ error = urtw_write8_i(sc, 0x80, 0x0f, 1);
+ if (error)
+ goto fail;
+ error = urtw_write8_i(sc, 0x83, 0x03, 1);
+ if (error)
+ goto fail;
+ urtw_write8_m(sc, 0xda, 0x10);
+ error = urtw_write8_i(sc, 0x4d, 0x08, 2);
+ if (error)
+ goto fail;
+
+ urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321B);
+
+ error = urtw_write16_i(sc, 0xec, 0x800, 1);
+ if (error)
+ goto fail;
+
+fail:
+ return (error);
+#undef N
+}
+
+static usb2_error_t
+urtw_adapter_start(struct urtw_softc *sc)
+{
+ usb2_error_t error;
+
+ error = urtw_reset(sc);
+ if (error)
+ goto fail;
+
+ urtw_write8_m(sc, URTW_ADDR_MAGIC1, 0);
+ urtw_write8_m(sc, URTW_GPIO, 0);
+
+ /* for led */
+ urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
+ error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON);
+ if (error != 0)
+ goto fail;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ /* applying MAC address again. */
+ urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]);
+ urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ error = urtw_update_msr(sc);
+ if (error)
+ goto fail;
+
+ urtw_write32_m(sc, URTW_INT_TIMEOUT, 0);
+ urtw_write8_m(sc, URTW_WPA_CONFIG, 0);
+ urtw_write8_m(sc, URTW_RATE_FALLBACK, URTW_RATE_FALLBACK_ENABLE | 0x1);
+ error = urtw_set_rate(sc);
+ if (error != 0)
+ goto fail;
+
+ error = sc->sc_rf_init(sc);
+ if (error != 0)
+ goto fail;
+ if (sc->sc_rf_set_sens != NULL)
+ sc->sc_rf_set_sens(sc, sc->sc_sens);
+
+ /* XXX correct? to call write16 */
+ urtw_write16_m(sc, URTW_PSR, 1);
+ urtw_write16_m(sc, URTW_ADDR_MAGIC2, 0x10);
+ urtw_write8_m(sc, URTW_TALLY_SEL, 0x80);
+ urtw_write8_m(sc, URTW_ADDR_MAGIC3, 0x60);
+ /* XXX correct? to call write16 */
+ urtw_write16_m(sc, URTW_PSR, 0);
+ urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4);
+
+ error = urtw_intr_enable(sc);
+ if (error != 0)
+ goto fail;
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_set_mode(struct urtw_softc *sc, uint32_t mode)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data);
+ data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT);
+ data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK);
+ urtw_write8_m(sc, URTW_EPROM_CMD, data);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8187b_cmd_reset(struct urtw_softc *sc)
+{
+ int i;
+ uint8_t data8;
+ usb2_error_t error;
+
+ /* XXX the code can be duplicate with urtw_reset(). */
+ urtw_read8_m(sc, URTW_CMD, &data8);
+ data8 = (data8 & 0x2) | URTW_CMD_RST;
+ urtw_write8_m(sc, URTW_CMD, data8);
+
+ for (i = 0; i < 20; i++) {
+ usb2_pause_mtx(&sc->sc_mtx, 2);
+ urtw_read8_m(sc, URTW_CMD, &data8);
+ if (!(data8 & URTW_CMD_RST))
+ break;
+ }
+ if (i >= 20) {
+ device_printf(sc->sc_dev, "reset timeout\n");
+ goto fail;
+ }
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
+ if (error)
+ goto fail;
+
+ for (i = 0; i < 20; i++) {
+ usb2_pause_mtx(&sc->sc_mtx, 4);
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data8);
+ if (!(data8 & URTW_EPROM_CMD_CONFIG))
+ break;
+ }
+ if (i >= 20) {
+ device_printf(sc->sc_dev, "eeprom reset timeout\n");
+ goto fail;
+ }
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_write16_i(struct urtw_softc *sc, int val, uint16_t data, int idx)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, idx & 0x3);
+ USETW(req.wLength, sizeof(uint16_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_do_request(struct urtw_softc *sc,
+ struct usb2_device_request *req, void *data)
+{
+ usb2_error_t err;
+ int ntries = 10;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ while (ntries--) {
+ err = usb2_do_request_flags(sc->sc_udev, &sc->sc_mtx,
+ req, data, 0, NULL, 250 /* ms */);
+ if (err == 0)
+ break;
+
+ DPRINTF(sc, URTW_DEBUG_INIT,
+ "Control request failed, %s (retrying)\n",
+ usb2_errstr(err));
+ usb2_pause_mtx(&sc->sc_mtx, hz / 100);
+ }
+ return (err);
+}
+
+static usb2_error_t
+urtw_write8_i(struct urtw_softc *sc, int val, uint8_t data, int idx)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, idx & 0x3);
+ USETW(req.wLength, sizeof(uint8_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_write32_i(struct urtw_softc *sc, int val, uint32_t data, int idx)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, idx & 0x3);
+ USETW(req.wLength, sizeof(uint32_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static void
+urtw_stop_locked(struct ifnet *ifp, int disable)
+{
+ struct urtw_softc *sc = ifp->if_softc;
+ uint8_t data8;
+ usb2_error_t error;
+
+ (void)disable;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ error = urtw_intr_disable(sc);
+ if (error)
+ goto fail;
+ urtw_read8_m(sc, URTW_CMD, &data8);
+ data8 &= ~(URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE);
+ urtw_write8_m(sc, URTW_CMD, data8);
+
+ error = sc->sc_rf_stop(sc);
+ if (error != 0)
+ goto fail;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ urtw_read8_m(sc, URTW_CONFIG4, &data8);
+ urtw_write8_m(sc, URTW_CONFIG4, data8 | URTW_CONFIG4_VCOOFF);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+fail:
+ if (error)
+ device_printf(sc->sc_dev, "failed to stop (%s)\n",
+ usb2_errstr(error));
+
+ usb2_callout_stop(&sc->sc_led_ch);
+ callout_stop(&sc->sc_watchdog_ch);
+
+ urtw_abort_xfers(sc);
+}
+
+static void
+urtw_stop(struct ifnet *ifp, int disable)
+{
+ struct urtw_softc *sc = ifp->if_softc;
+
+ URTW_LOCK(sc);
+ urtw_stop_locked(ifp, disable);
+ URTW_UNLOCK(sc);
+}
+
+static void
+urtw_abort_xfers(struct urtw_softc *sc)
+{
+ int i, max;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ max = (sc->sc_flags & URTW_RTL8187B) ? URTW_8187B_N_XFERS :
+ URTW_8187L_N_XFERS;
+
+ /* abort any pending transfers */
+ for (i = 0; i < max; i++)
+ usb2_transfer_stop(sc->sc_xfer[i]);
+}
+
+static int
+urtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct urtw_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0, startall = 0;
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->sc_if_flags) &
+ (IFF_ALLMULTI | IFF_PROMISC))
+ urtw_set_multi(sc);
+ } else {
+ urtw_init(ifp->if_softc);
+ startall = 1;
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ urtw_stop(ifp, 1);
+ }
+ sc->sc_if_flags = ifp->if_flags;
+ if (startall)
+ ieee80211_start_all(ic);
+ break;
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
+ break;
+ case SIOCGIFADDR:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
+static void
+urtw_start(struct ifnet *ifp)
+{
+ struct urtw_data *bf;
+ struct urtw_softc *sc = ifp->if_softc;
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ URTW_LOCK(sc);
+ for (;;) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+ bf = urtw_getbuf(sc);
+ if (bf == NULL) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ break;
+ }
+
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+
+ if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_NORMAL) != 0) {
+ ifp->if_oerrors++;
+ STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
+ ieee80211_free_node(ni);
+ break;
+ }
+
+ sc->sc_txtimer = 5;
+ }
+ URTW_UNLOCK(sc);
+}
+
+static int
+urtw_alloc_data_list(struct urtw_softc *sc, struct urtw_data data[],
+ int ndata, int maxsz, int fillmbuf)
+{
+ int i, error;
+
+ for (i = 0; i < ndata; i++) {
+ struct urtw_data *dp = &data[i];
+
+ dp->sc = sc;
+ if (fillmbuf) {
+ dp->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (dp->m == NULL) {
+ device_printf(sc->sc_dev,
+ "could not allocate rx mbuf\n");
+ error = ENOMEM;
+ goto fail;
+ }
+ dp->buf = mtod(dp->m, uint8_t *);
+ } else {
+ dp->m = NULL;
+ dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
+ if (dp->buf == NULL) {
+ device_printf(sc->sc_dev,
+ "could not allocate buffer\n");
+ error = ENOMEM;
+ goto fail;
+ }
+ if (((unsigned long)dp->buf) % 4)
+ device_printf(sc->sc_dev,
+ "warn: unaligned buffer %p\n", dp->buf);
+ }
+ dp->ni = NULL;
+ }
+
+ return 0;
+
+fail: urtw_free_data_list(sc, data, ndata, fillmbuf);
+ return error;
+}
+
+static int
+urtw_alloc_rx_data_list(struct urtw_softc *sc)
+{
+ int error, i;
+
+ error = urtw_alloc_data_list(sc,
+ sc->sc_rx, URTW_RX_DATA_LIST_COUNT, MCLBYTES, 1 /* mbufs */);
+ if (error != 0)
+ return (error);
+
+ STAILQ_INIT(&sc->sc_rx_active);
+ STAILQ_INIT(&sc->sc_rx_inactive);
+
+ for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++)
+ STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next);
+
+ return (0);
+}
+
+static int
+urtw_alloc_tx_data_list(struct urtw_softc *sc)
+{
+ int error, i;
+
+ error = urtw_alloc_data_list(sc,
+ sc->sc_tx, URTW_TX_DATA_LIST_COUNT, URTW_TX_MAXSIZE,
+ 0 /* no mbufs */);
+ if (error != 0)
+ return (error);
+
+ STAILQ_INIT(&sc->sc_tx_active);
+ STAILQ_INIT(&sc->sc_tx_inactive);
+ STAILQ_INIT(&sc->sc_tx_pending);
+
+ for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++)
+ STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i],
+ next);
+
+ return (0);
+}
+
+static int
+urtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct urtw_data *bf;
+ struct urtw_softc *sc = ifp->if_softc;
+
+ /* prevent management frames from being sent if we're not ready */
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ m_freem(m);
+ ieee80211_free_node(ni);
+ return ENETDOWN;
+ }
+ URTW_LOCK(sc);
+ bf = urtw_getbuf(sc);
+ if (bf == NULL) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ URTW_UNLOCK(sc);
+ return (ENOBUFS); /* XXX */
+ }
+
+ ifp->if_opackets++;
+ if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_LOW) != 0) {
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
+ STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
+ URTW_UNLOCK(sc);
+ return (EIO);
+ }
+ URTW_UNLOCK(sc);
+
+ sc->sc_txtimer = 5;
+ return (0);
+}
+
+static void
+urtw_scan_start(struct ieee80211com *ic)
+{
+
+ /* XXX do nothing? */
+}
+
+static void
+urtw_scan_end(struct ieee80211com *ic)
+{
+
+ /* XXX do nothing? */
+}
+
+static void
+urtw_set_channel(struct ieee80211com *ic)
+{
+ struct urtw_softc *sc = ic->ic_ifp->if_softc;
+ struct ifnet *ifp = sc->sc_ifp;
+ uint32_t data, orig;
+ usb2_error_t error;
+
+ /*
+ * if the user set a channel explicitly using ifconfig(8) this function
+ * can be called earlier than we're expected that in some cases the
+ * initialization would be failed if setting a channel is called before
+ * the init have done.
+ */
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return;
+
+ if (sc->sc_curchan != NULL && sc->sc_curchan == ic->ic_curchan)
+ return;
+
+ URTW_LOCK(sc);
+
+ /*
+ * during changing th channel we need to temporarily be disable
+ * TX.
+ */
+ urtw_read32_m(sc, URTW_TX_CONF, &orig);
+ data = orig & ~URTW_TX_LOOPBACK_MASK;
+ urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC);
+
+ error = sc->sc_rf_set_chan(sc, ieee80211_chan2ieee(ic, ic->ic_curchan));
+ if (error != 0)
+ goto fail;
+ usb2_pause_mtx(&sc->sc_mtx, 10);
+ urtw_write32_m(sc, URTW_TX_CONF, orig);
+
+ urtw_write16_m(sc, URTW_ATIM_WND, 2);
+ urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
+ urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100);
+ urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
+
+fail:
+ URTW_UNLOCK(sc);
+
+ sc->sc_curchan = ic->ic_curchan;
+
+ if (error != 0)
+ device_printf(sc->sc_dev, "could not change the channel\n");
+}
+
+static void
+urtw_update_mcast(struct ifnet *ifp)
+{
+
+ /* XXX do nothing? */
+}
+
+static int
+urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0,
+ struct urtw_data *data, int prior)
+{
+ int xferlen;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
+ struct ieee80211_key *k;
+ const struct ieee80211_txparam *tp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct urtw_8187b_txhdr *hdr;
+ struct usb2_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = {
+ sc->sc_xfer[URTW_8187B_BULK_TX_BE],
+ sc->sc_xfer[URTW_8187B_BULK_TX_BK],
+ sc->sc_xfer[URTW_8187B_BULK_TX_VI],
+ sc->sc_xfer[URTW_8187B_BULK_TX_VO]
+ };
+ struct usb2_xfer *xfer;
+ usb2_error_t error;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ /*
+ * Software crypto.
+ */
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ k = ieee80211_crypto_encap(ni, m0);
+ if (k == NULL) {
+ device_printf(sc->sc_dev,
+ "ieee80211_crypto_encap returns NULL.\n");
+ /* XXX we don't expect the fragmented frames */
+ m_freem(m0);
+ return (ENOBUFS);
+ }
+
+ /* in case packet header moved, reset pointer */
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
+
+ if (ieee80211_radiotap_active_vap(vap)) {
+ struct urtw_tx_radiotap_header *tap = &sc->sc_txtap;
+
+ /* XXX Are variables correct? */
+ tap->wt_flags = 0;
+ tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
+
+ ieee80211_radiotap_tx(vap, m0);
+ }
+
+ xferlen = m0->m_pkthdr.len;
+ xferlen += (sc->sc_flags & URTW_RTL8187B) ? (4 * 8) : (4 * 3);
+ if ((0 == xferlen % 64) || (0 == xferlen % 512))
+ xferlen += 1;
+
+ bzero(data->buf, URTW_TX_MAXSIZE);
+ data->buf[0] = m0->m_pkthdr.len & 0xff;
+ data->buf[1] = (m0->m_pkthdr.len & 0x0f00) >> 8;
+ data->buf[1] |= (1 << 7);
+
+ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) &&
+ (sc->sc_preamble_mode == URTW_PREAMBLE_MODE_SHORT) &&
+ (sc->sc_currate != 0))
+ data->buf[2] |= 1;
+ if ((m0->m_pkthdr.len > vap->iv_rtsthreshold) &&
+ prior == URTW_PRIORITY_LOW) {
+ device_printf(sc->sc_dev, "TODO tx.\n");
+ return (EIO);
+ }
+ if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
+ data->buf[2] |= (1 << 1);
+ /* RTS rate - 10 means we use a basic rate. */
+ data->buf[2] |= (urtw_rate2rtl(2) << 3);
+ /*
+ * XXX currently TX rate control depends on the rate value of
+ * RX descriptor because I don't know how to we can control TX rate
+ * in more smart way. Please fix me you find a thing.
+ */
+ data->buf[3] = sc->sc_currate;
+ if (prior == URTW_PRIORITY_NORMAL) {
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+ data->buf[3] = urtw_rate2rtl(tp->mcastrate);
+ else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+ data->buf[3] = urtw_rate2rtl(tp->ucastrate);
+ }
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ hdr = (struct urtw_8187b_txhdr *)data->buf;
+ hdr->rts_duration = 0;
+ hdr->len = 0;
+ hdr->retry = 3 | (7 << 4) | 11;
+ hdr->tx_duration = ieee80211_compute_duration(ic->ic_rt,
+ m0->m_pkthdr.len + IEEE80211_CRC_LEN,
+ urtw_rtl2rate(data->buf[3]),
+ (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0);
+ /* XXX MUST fill another variables like rts_duration, tx_.. */
+ m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)&data->buf[32]);
+ } else {
+ data->buf[8] = 3; /* CW minimum */
+ data->buf[8] |= (7 << 4); /* CW maximum */
+ data->buf[9] |= 11; /* retry limitation */
+ m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)&data->buf[12]);
+ }
+
+ data->buflen = xferlen;
+ data->ni = ni;
+ data->m = m0;
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+ case IEEE80211_FC0_TYPE_CTL:
+ case IEEE80211_FC0_TYPE_MGT:
+ xfer = sc->sc_xfer[URTW_8187B_BULK_TX_EP12];
+ break;
+ default:
+ KASSERT(M_WME_GETAC(m0) < URTW_8187B_TXPIPE_MAX,
+ ("unsupported WME pipe %d", M_WME_GETAC(m0)));
+ xfer = rtl8187b_pipes[M_WME_GETAC(m0)];
+ break;
+ }
+ } else
+ xfer = (prior == URTW_PRIORITY_LOW) ?
+ sc->sc_xfer[URTW_8187L_BULK_TX_LOW] :
+ sc->sc_xfer[URTW_8187L_BULK_TX_NORMAL];
+
+ STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
+ usb2_transfer_start(xfer);
+
+ error = urtw_led_ctl(sc, URTW_LED_CTL_TX);
+ if (error != 0)
+ device_printf(sc->sc_dev, "could not control LED (%d)\n",
+ error);
+ return (0);
+}
+
+static int
+urtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ struct ieee80211_node *ni = vap->iv_bss;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct urtw_softc *sc = ic->ic_ifp->if_softc;
+ struct urtw_vap *uvp = URTW_VAP(vap);
+ usb2_error_t error = 0;
+
+ DPRINTF(sc, URTW_DEBUG_STATE, "%s: %s -> %s\n", __func__,
+ ieee80211_state_name[vap->iv_state],
+ ieee80211_state_name[nstate]);
+
+ sc->sc_state = nstate;
+
+ IEEE80211_UNLOCK(ic);
+ URTW_LOCK(sc);
+ usb2_callout_stop(&sc->sc_led_ch);
+ callout_stop(&sc->sc_watchdog_ch);
+
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ case IEEE80211_S_SCAN:
+ case IEEE80211_S_AUTH:
+ case IEEE80211_S_ASSOC:
+ break;
+ case IEEE80211_S_RUN:
+ /* setting bssid. */
+ urtw_write32_m(sc, URTW_BSSID, ((uint32_t *)ni->ni_bssid)[0]);
+ urtw_write16_m(sc, URTW_BSSID + 4,
+ ((uint16_t *)ni->ni_bssid)[2]);
+ urtw_update_msr(sc);
+ /* XXX maybe the below would be incorrect. */
+ urtw_write16_m(sc, URTW_ATIM_WND, 2);
+ urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100);
+ urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64);
+ urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100);
+ error = urtw_led_ctl(sc, URTW_LED_CTL_LINK);
+ if (error != 0)
+ device_printf(sc->sc_dev,
+ "could not control LED (%d)\n", error);
+ break;
+ default:
+ break;
+ }
+fail:
+ URTW_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ return (uvp->newstate(vap, nstate, arg));
+}
+
+static void
+urtw_watchdog(void *arg)
+{
+ struct urtw_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if (sc->sc_txtimer > 0) {
+ if (--sc->sc_txtimer == 0) {
+ device_printf(sc->sc_dev, "device timeout\n");
+ ifp->if_oerrors++;
+ return;
+ }
+ callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc);
+ }
+}
+
+static void
+urtw_set_multi(void *arg)
+{
+ struct urtw_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if (!(ifp->if_flags & IFF_UP))
+ return;
+
+ /*
+ * XXX don't know how to set a device. Lack of docs. Just try to set
+ * IFF_ALLMULTI flag here.
+ */
+ IF_ADDR_LOCK(ifp);
+ ifp->if_flags |= IFF_ALLMULTI;
+ IF_ADDR_UNLOCK(ifp);
+}
+
+static usb2_error_t
+urtw_set_rate(struct urtw_softc *sc)
+{
+ int i, basic_rate, min_rr_rate, max_rr_rate;
+ uint16_t data;
+ usb2_error_t error;
+
+ basic_rate = urtw_rate2rtl(48);
+ min_rr_rate = urtw_rate2rtl(12);
+ max_rr_rate = urtw_rate2rtl(48);
+
+ urtw_write8_m(sc, URTW_RESP_RATE,
+ max_rr_rate << URTW_RESP_MAX_RATE_SHIFT |
+ min_rr_rate << URTW_RESP_MIN_RATE_SHIFT);
+
+ urtw_read16_m(sc, URTW_BRSR, &data);
+ data &= ~URTW_BRSR_MBR_8185;
+
+ for (i = 0; i <= basic_rate; i++)
+ data |= (1 << i);
+
+ urtw_write16_m(sc, URTW_BRSR, data);
+fail:
+ return (error);
+}
+
+static uint16_t
+urtw_rate2rtl(int rate)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+
+ for (i = 0; i < N(urtw_ratetable); i++) {
+ if (rate == urtw_ratetable[i].reg)
+ return urtw_ratetable[i].val;
+ }
+
+ return (3);
+#undef N
+}
+
+static uint16_t
+urtw_rtl2rate(int rate)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+
+ for (i = 0; i < N(urtw_ratetable); i++) {
+ if (rate == urtw_ratetable[i].val)
+ return urtw_ratetable[i].reg;
+ }
+
+ return (0);
+#undef N
+}
+
+static usb2_error_t
+urtw_update_msr(struct urtw_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_MSR, &data);
+ data &= ~URTW_MSR_LINK_MASK;
+
+ if (sc->sc_state == IEEE80211_S_RUN) {
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ case IEEE80211_M_MONITOR:
+ data |= URTW_MSR_LINK_STA;
+ if (sc->sc_flags & URTW_RTL8187B)
+ data |= URTW_MSR_LINK_ENEDCA;
+ break;
+ case IEEE80211_M_IBSS:
+ data |= URTW_MSR_LINK_ADHOC;
+ break;
+ case IEEE80211_M_HOSTAP:
+ data |= URTW_MSR_LINK_HOSTAP;
+ break;
+ default:
+ panic("unsupported operation mode 0x%x\n",
+ ic->ic_opmode);
+ /* never reach */
+ }
+ } else
+ data |= URTW_MSR_LINK_NONE;
+
+ urtw_write8_m(sc, URTW_MSR, data);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data)
+{
+ struct usb2_device_request req;
+ usb2_error_t error;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_GETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint8_t));
+
+ error = urtw_do_request(sc, &req, data);
+ return (error);
+}
+
+static usb2_error_t
+urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data)
+{
+ struct usb2_device_request req;
+ usb2_error_t error;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_GETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint16_t));
+
+ error = urtw_do_request(sc, &req, data);
+ return (error);
+}
+
+static usb2_error_t
+urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data)
+{
+ struct usb2_device_request req;
+ usb2_error_t error;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_GETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint32_t));
+
+ error = urtw_do_request(sc, &req, data);
+ return (error);
+}
+
+static usb2_error_t
+urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data)
+{
+ struct usb2_device_request req;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint8_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data)
+{
+ struct usb2_device_request req;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint16_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data)
+{
+ struct usb2_device_request req;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xff00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint32_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_get_macaddr(struct urtw_softc *sc)
+{
+ uint32_t data;
+ usb2_error_t error;
+
+ error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_bssid[0] = data & 0xff;
+ sc->sc_bssid[1] = (data & 0xff00) >> 8;
+ error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_bssid[2] = data & 0xff;
+ sc->sc_bssid[3] = (data & 0xff00) >> 8;
+ error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_bssid[4] = data & 0xff;
+ sc->sc_bssid[5] = (data & 0xff00) >> 8;
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data)
+{
+#define URTW_READCMD_LEN 3
+ int addrlen, i;
+ int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 };
+ usb2_error_t error;
+
+ /* NB: make sure the buffer is initialized */
+ *data = 0;
+
+ /* enable EPROM programming */
+ urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE);
+ DELAY(URTW_EPROM_DELAY);
+
+ error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE);
+ if (error != 0)
+ goto fail;
+ error = urtw_eprom_ck(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN);
+ if (error != 0)
+ goto fail;
+ if (sc->sc_epromtype == URTW_EEPROM_93C56) {
+ addrlen = 8;
+ addrstr[0] = addr & (1 << 7);
+ addrstr[1] = addr & (1 << 6);
+ addrstr[2] = addr & (1 << 5);
+ addrstr[3] = addr & (1 << 4);
+ addrstr[4] = addr & (1 << 3);
+ addrstr[5] = addr & (1 << 2);
+ addrstr[6] = addr & (1 << 1);
+ addrstr[7] = addr & (1 << 0);
+ } else {
+ addrlen=6;
+ addrstr[0] = addr & (1 << 5);
+ addrstr[1] = addr & (1 << 4);
+ addrstr[2] = addr & (1 << 3);
+ addrstr[3] = addr & (1 << 2);
+ addrstr[4] = addr & (1 << 1);
+ addrstr[5] = addr & (1 << 0);
+ }
+ error = urtw_eprom_sendbits(sc, addrstr, addrlen);
+ if (error != 0)
+ goto fail;
+
+ error = urtw_eprom_writebit(sc, 0);
+ if (error != 0)
+ goto fail;
+
+ for (i = 0; i < 16; i++) {
+ error = urtw_eprom_ck(sc);
+ if (error != 0)
+ goto fail;
+ error = urtw_eprom_readbit(sc, &data16);
+ if (error != 0)
+ goto fail;
+
+ (*data) |= (data16 << (15 - i));
+ }
+
+ error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE);
+ if (error != 0)
+ goto fail;
+ error = urtw_eprom_ck(sc);
+ if (error != 0)
+ goto fail;
+
+ /* now disable EPROM programming */
+ urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE);
+fail:
+ return (error);
+#undef URTW_READCMD_LEN
+}
+
+static usb2_error_t
+urtw_eprom_cs(struct urtw_softc *sc, int able)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data);
+ if (able == URTW_EPROM_ENABLE)
+ urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS);
+ else
+ urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS);
+ DELAY(URTW_EPROM_DELAY);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_eprom_ck(struct urtw_softc *sc)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ /* masking */
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data);
+ urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK);
+ DELAY(URTW_EPROM_DELAY);
+ /* unmasking */
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data);
+ urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK);
+ DELAY(URTW_EPROM_DELAY);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data)
+{
+ uint8_t data8;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data8);
+ *data = (data8 & URTW_EPROM_READBIT) ? 1 : 0;
+ DELAY(URTW_EPROM_DELAY);
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_EPROM_CMD, &data);
+ if (bit != 0)
+ urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT);
+ else
+ urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT);
+ DELAY(URTW_EPROM_DELAY);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen)
+{
+ int i = 0;
+ usb2_error_t error = 0;
+
+ for (i = 0; i < buflen; i++) {
+ error = urtw_eprom_writebit(sc, buf[i]);
+ if (error != 0)
+ goto fail;
+ error = urtw_eprom_ck(sc);
+ if (error != 0)
+ goto fail;
+ }
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_get_txpwr(struct urtw_softc *sc)
+{
+ int i, j;
+ uint32_t data;
+ usb2_error_t error;
+
+ error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck_base = data & 0xf;
+ sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf;
+
+ for (i = 1, j = 0; i < 6; i += 2, j++) {
+ error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[i] = data & 0xf;
+ sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8;
+ sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4;
+ sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12;
+ }
+ for (i = 1, j = 0; i < 4; i += 2, j++) {
+ error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[i + 6] = data & 0xf;
+ sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8;
+ sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4;
+ sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12;
+ }
+ if (sc->sc_flags & URTW_RTL8187B) {
+ error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[1 + 6 + 4] = data & 0xf;
+ sc->sc_txpwr_ofdm[1 + 6 + 4] = (data & 0xf0) >> 4;
+ error = urtw_eprom_read32(sc, 0x0a, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[2 + 6 + 4] = data & 0xf;
+ sc->sc_txpwr_ofdm[2 + 6 + 4] = (data & 0xf0) >> 4;
+ error = urtw_eprom_read32(sc, 0x1c, &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[3 + 6 + 4] = data & 0xf;
+ sc->sc_txpwr_cck[3 + 6 + 4 + 1] = (data & 0xf00) >> 8;
+ sc->sc_txpwr_ofdm[3 + 6 + 4] = (data & 0xf0) >> 4;
+ sc->sc_txpwr_ofdm[3 + 6 + 4 + 1] = (data & 0xf000) >> 12;
+ } else {
+ for (i = 1, j = 0; i < 4; i += 2, j++) {
+ error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j,
+ &data);
+ if (error != 0)
+ goto fail;
+ sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf;
+ sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8;
+ sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4;
+ sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = (data & 0xf000) >> 12;
+ }
+ }
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_get_rfchip(struct urtw_softc *sc)
+{
+ int ret;
+ uint8_t data8;
+ uint32_t data;
+ usb2_error_t error;
+
+ error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data);
+ if (error != 0)
+ goto fail;
+ switch (data & 0xff) {
+ case URTW_EPROM_RFCHIPID_RTL8225U:
+ error = urtw_8225_isv2(sc, &ret);
+ if (error != 0)
+ goto fail;
+ if (ret == 0) {
+ sc->sc_rf_init = urtw_8225_rf_init;
+ sc->sc_rf_set_sens = urtw_8225_rf_set_sens;
+ sc->sc_rf_set_chan = urtw_8225_rf_set_chan;
+ sc->sc_rf_stop = urtw_8225_rf_stop;
+ } else {
+ sc->sc_rf_init = urtw_8225v2_rf_init;
+ sc->sc_rf_set_chan = urtw_8225v2_rf_set_chan;
+ sc->sc_rf_stop = urtw_8225_rf_stop;
+ }
+ sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
+ sc->sc_sens = URTW_8225_RF_DEF_SENS;
+ break;
+ case URTW_EPROM_RFCHIPID_RTL8225Z2:
+ sc->sc_rf_init = urtw_8225v2b_rf_init;
+ sc->sc_rf_set_chan = urtw_8225v2b_rf_set_chan;
+ sc->sc_max_sens = URTW_8225_RF_MAX_SENS;
+ sc->sc_sens = URTW_8225_RF_DEF_SENS;
+ sc->sc_rf_stop = urtw_8225_rf_stop;
+ break;
+ default:
+ panic("unsupported RF chip %d\n", data & 0xff);
+ /* never reach */
+ }
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ urtw_read8_m(sc, 0xe1, &data8);
+ sc->sc_flags |= (data8 == 0) ? URTW_RTL8187B_REV_B :
+ (data8 == 1) ? URTW_RTL8187B_REV_D : URTW_RTL8187B_REV_E;
+ }
+
+ device_printf(sc->sc_dev, "%s rf %s hwrev %s\n",
+ (sc->sc_flags & URTW_RTL8187B) ? "rtl8187b" : "rtl8187l",
+ ((data & 0xff) == URTW_EPROM_RFCHIPID_RTL8225U) ? "rtl8225u" :
+ "rtl8225z2",
+ (sc->sc_flags & URTW_RTL8187B) ? ((data8 == 0) ? "b" :
+ (data8 == 1) ? "d" : "e") : "none");
+
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_led_init(struct urtw_softc *sc)
+{
+ uint32_t rev;
+ usb2_error_t error;
+
+ urtw_read8_m(sc, URTW_PSR, &sc->sc_psr);
+ error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev);
+ if (error != 0)
+ goto fail;
+
+ switch (rev & URTW_EPROM_CID_MASK) {
+ case URTW_EPROM_CID_ALPHA0:
+ sc->sc_strategy = URTW_SW_LED_MODE1;
+ break;
+ case URTW_EPROM_CID_SERCOMM_PS:
+ sc->sc_strategy = URTW_SW_LED_MODE3;
+ break;
+ case URTW_EPROM_CID_HW_LED:
+ sc->sc_strategy = URTW_HW_LED;
+ break;
+ case URTW_EPROM_CID_RSVD0:
+ case URTW_EPROM_CID_RSVD1:
+ default:
+ sc->sc_strategy = URTW_SW_LED_MODE0;
+ break;
+ }
+
+ sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0;
+
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_8225_rf_init(struct urtw_softc *sc)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+ uint16_t data;
+ usb2_error_t error;
+
+ error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
+ if (error)
+ goto fail;
+
+ error = urtw_8225_usb_init(sc);
+ if (error)
+ goto fail;
+
+ urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
+ urtw_read16_m(sc, URTW_BRSR, &data); /* XXX ??? */
+ urtw_write16_m(sc, URTW_BRSR, 0xffff);
+ urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ urtw_write8_m(sc, URTW_CONFIG3, 0x44);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ error = urtw_8185_rf_pins_enable(sc);
+ if (error)
+ goto fail;
+ usb2_pause_mtx(&sc->sc_mtx, 1000);
+
+ for (i = 0; i < N(urtw_8225_rf_part1); i++) {
+ urtw_8225_write(sc, urtw_8225_rf_part1[i].reg,
+ urtw_8225_rf_part1[i].val);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ }
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
+ usb2_pause_mtx(&sc->sc_mtx, 200);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
+ usb2_pause_mtx(&sc->sc_mtx, 200);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC3);
+
+ for (i = 0; i < 95; i++) {
+ urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
+ urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, urtw_8225_rxgain[i]);
+ }
+
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC4);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC5);
+
+ for (i = 0; i < 128; i++) {
+ urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ }
+
+ for (i = 0; i < N(urtw_8225_rf_part2); i++) {
+ urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg,
+ urtw_8225_rf_part2[i].val);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ }
+
+ error = urtw_8225_setgain(sc, 4);
+ if (error)
+ goto fail;
+
+ for (i = 0; i < N(urtw_8225_rf_part3); i++) {
+ urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg,
+ urtw_8225_rf_part3[i].val);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ }
+
+ urtw_write8_m(sc, URTW_TESTR, 0x0d);
+
+ error = urtw_8225_set_txpwrlvl(sc, 1);
+ if (error)
+ goto fail;
+
+ urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+
+ /* TX ant A, 0x0 for B */
+ error = urtw_8185_tx_antenna(sc, 0x3);
+ if (error)
+ goto fail;
+ urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
+
+ error = urtw_8225_rf_set_chan(sc, 1);
+fail:
+ return (error);
+#undef N
+}
+
+static usb2_error_t
+urtw_8185_rf_pins_enable(struct urtw_softc *sc)
+{
+ usb2_error_t error = 0;
+
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant)
+{
+ usb2_error_t error;
+
+ urtw_write8_m(sc, URTW_TX_ANTENNA, ant);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
+{
+
+ data = data & 0xff;
+ return urtw_8187_write_phy(sc, addr, data);
+}
+
+static usb2_error_t
+urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data)
+{
+
+ data = data & 0xff;
+ return urtw_8187_write_phy(sc, addr, data | 0x10000);
+}
+
+static usb2_error_t
+urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data)
+{
+ uint32_t phyw;
+ usb2_error_t error;
+
+ phyw = ((data << 8) | (addr | 0x80));
+ urtw_write8_m(sc, URTW_PHY_MAGIC4, ((phyw & 0xff000000) >> 24));
+ urtw_write8_m(sc, URTW_PHY_MAGIC3, ((phyw & 0x00ff0000) >> 16));
+ urtw_write8_m(sc, URTW_PHY_MAGIC2, ((phyw & 0x0000ff00) >> 8));
+ urtw_write8_m(sc, URTW_PHY_MAGIC1, ((phyw & 0x000000ff)));
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_setgain(struct urtw_softc *sc, int16_t gain)
+{
+ usb2_error_t error;
+
+ urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]);
+ urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]);
+ urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]);
+ urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_usb_init(struct urtw_softc *sc)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0);
+ urtw_write8_m(sc, URTW_GPIO, 0);
+ error = urtw_read8e(sc, 0x53, &data);
+ if (error)
+ goto fail;
+ error = urtw_write8e(sc, 0x53, data | (1 << 7));
+ if (error)
+ goto fail;
+ urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4);
+ urtw_write8_m(sc, URTW_GPIO, 0x20);
+ urtw_write8_m(sc, URTW_GP_ENABLE, 0);
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80);
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80);
+
+ usb2_pause_mtx(&sc->sc_mtx, 500);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data)
+{
+ uint16_t d80, d82, d84;
+ usb2_error_t error;
+
+ urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80);
+ d80 &= URTW_RF_PINS_MAGIC1;
+ urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82);
+ urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84);
+ d84 &= URTW_RF_PINS_MAGIC2;
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | URTW_RF_PINS_MAGIC3);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | URTW_RF_PINS_MAGIC3);
+ DELAY(10);
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80);
+ DELAY(10);
+
+ error = urtw_8225_write_s16(sc, addr, 0x8225, &data);
+ if (error != 0)
+ goto fail;
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
+ DELAY(10);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84);
+ usb2_pause_mtx(&sc->sc_mtx, 2);
+fail:
+ return (error);
+}
+
+/* XXX why we should allocalte memory buffer instead of using memory stack? */
+static usb2_error_t
+urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index,
+ uint16_t *data)
+{
+ uint8_t *buf;
+ uint16_t data16;
+ struct usb2_device_request *req;
+ usb2_error_t error = 0;
+
+ data16 = *data;
+ req = (usb_device_request_t *)malloc(sizeof(usb_device_request_t),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (req == NULL) {
+ device_printf(sc->sc_dev, "could not allocate a memory\n");
+ goto fail0;
+ }
+ buf = (uint8_t *)malloc(2, M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (req == NULL) {
+ device_printf(sc->sc_dev, "could not allocate a memory\n");
+ goto fail1;
+ }
+
+ req->bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req->bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req->wValue, addr);
+ USETW(req->wIndex, index);
+ USETW(req->wLength, sizeof(uint16_t));
+ buf[0] = (data16 & 0x00ff);
+ buf[1] = (data16 & 0xff00) >> 8;
+
+ error = urtw_do_request(sc, req, buf);
+
+ free(buf, M_80211_VAP);
+fail1: free(req, M_80211_VAP);
+fail0: return (error);
+}
+
+static usb2_error_t
+urtw_8225_rf_set_chan(struct urtw_softc *sc, int chan)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_channel *c = ic->ic_curchan;
+ usb2_error_t error;
+
+ error = urtw_8225_set_txpwrlvl(sc, chan);
+ if (error)
+ goto fail;
+ urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
+ usb2_pause_mtx(&sc->sc_mtx, 10);
+
+ urtw_write8_m(sc, URTW_SIFS, 0x22);
+
+ if (sc->sc_state == IEEE80211_S_ASSOC &&
+ ic->ic_flags & IEEE80211_F_SHSLOT)
+ urtw_write8_m(sc, URTW_SLOT, 0x9);
+ else
+ urtw_write8_m(sc, URTW_SLOT, 0x14);
+
+ if (IEEE80211_IS_CHAN_G(c)) {
+ /* for G */
+ urtw_write8_m(sc, URTW_DIFS, 0x14);
+ urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x14);
+ urtw_write8_m(sc, URTW_CW_VAL, 0x73);
+ } else {
+ /* for B */
+ urtw_write8_m(sc, URTW_DIFS, 0x24);
+ urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x24);
+ urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
+ }
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_rf_set_sens(struct urtw_softc *sc, int sens)
+{
+ usb2_error_t error;
+
+ if (sens < 0 || sens > 6)
+ return -1;
+
+ if (sens > 4)
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC1);
+ else
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC2);
+
+ sens = 6 - sens;
+ error = urtw_8225_setgain(sc, sens);
+ if (error)
+ goto fail;
+
+ urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[sens]);
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan)
+{
+ int i, idx, set;
+ uint8_t *cck_pwltable;
+ uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max;
+ uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
+ uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
+ usb2_error_t error;
+
+ cck_pwrlvl_max = 11;
+ ofdm_pwrlvl_max = 25; /* 12 -> 25 */
+ ofdm_pwrlvl_min = 10;
+
+ /* CCK power setting */
+ cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
+ idx = cck_pwrlvl % 6;
+ set = cck_pwrlvl / 6;
+ cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 :
+ urtw_8225_txpwr_cck;
+
+ urtw_write8_m(sc, URTW_TX_GAIN_CCK,
+ urtw_8225_tx_gain_cck_ofdm[set] >> 1);
+ for (i = 0; i < 8; i++) {
+ urtw_8187_write_phy_cck(sc, 0x44 + i,
+ cck_pwltable[idx * 8 + i]);
+ }
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+
+ /* OFDM power setting */
+ ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
+ ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
+ ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
+
+ idx = ofdm_pwrlvl % 6;
+ set = ofdm_pwrlvl / 6;
+
+ error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
+ if (error)
+ goto fail;
+ urtw_8187_write_phy_ofdm(sc, 2, 0x42);
+ urtw_8187_write_phy_ofdm(sc, 6, 0);
+ urtw_8187_write_phy_ofdm(sc, 8, 0);
+
+ urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
+ urtw_8225_tx_gain_cck_ofdm[set] >> 1);
+ urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]);
+ urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_8225_rf_stop(struct urtw_softc *sc)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ urtw_8225_write(sc, 0x4, 0x1f);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_CONFIG3, &data);
+ urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
+ if (sc->sc_flags & URTW_RTL8187B) {
+ urtw_write32_m(sc, URTW_ANAPARAM2,
+ URTW_8187B_8225_ANAPARAM2_OFF);
+ urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_OFF);
+ urtw_write32_m(sc, URTW_ANAPARAM3,
+ URTW_8187B_8225_ANAPARAM3_OFF);
+ } else {
+ urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8225_ANAPARAM2_OFF);
+ urtw_write32_m(sc, URTW_ANAPARAM, URTW_8225_ANAPARAM_OFF);
+ }
+
+ urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225v2_rf_init(struct urtw_softc *sc)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+ uint16_t data;
+ uint32_t data32;
+ usb2_error_t error;
+
+ error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
+ if (error)
+ goto fail;
+
+ error = urtw_8225_usb_init(sc);
+ if (error)
+ goto fail;
+
+ urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008);
+ urtw_read16_m(sc, URTW_BRSR, &data); /* XXX ??? */
+ urtw_write16_m(sc, URTW_BRSR, 0xffff);
+ urtw_write32_m(sc, URTW_RF_PARA, 0x100044);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+ urtw_write8_m(sc, URTW_CONFIG3, 0x44);
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+
+ error = urtw_8185_rf_pins_enable(sc);
+ if (error)
+ goto fail;
+
+ usb2_pause_mtx(&sc->sc_mtx, 500);
+
+ for (i = 0; i < N(urtw_8225v2_rf_part1); i++) {
+ urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg,
+ urtw_8225v2_rf_part1[i].val);
+ }
+ usb2_pause_mtx(&sc->sc_mtx, 50);
+
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC1);
+
+ for (i = 0; i < 95; i++) {
+ urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
+ urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
+ urtw_8225v2_rxgain[i]);
+ }
+
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_3_MAGIC, URTW_8225_ADDR_3_DATA_MAGIC1);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_5_MAGIC, URTW_8225_ADDR_5_DATA_MAGIC1);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC2);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
+ if (error != 0)
+ goto fail;
+ if (data32 != URTW_8225_ADDR_6_DATA_MAGIC1)
+ device_printf(sc->sc_dev, "expect 0xe6!! (0x%x)\n", data32);
+ if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2)) {
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2);
+ usb2_pause_mtx(&sc->sc_mtx, 50);
+ error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32);
+ if (error != 0)
+ goto fail;
+ if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2))
+ device_printf(sc->sc_dev, "RF calibration failed\n");
+ }
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC6);
+ for (i = 0; i < 128; i++) {
+ urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]);
+ urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80);
+ }
+
+ for (i = 0; i < N(urtw_8225v2_rf_part2); i++) {
+ urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg,
+ urtw_8225v2_rf_part2[i].val);
+ }
+
+ error = urtw_8225v2_setgain(sc, 4);
+ if (error)
+ goto fail;
+
+ for (i = 0; i < N(urtw_8225v2_rf_part3); i++) {
+ urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg,
+ urtw_8225v2_rf_part3[i].val);
+ }
+
+ urtw_write8_m(sc, URTW_TESTR, 0x0d);
+
+ error = urtw_8225v2_set_txpwrlvl(sc, 1);
+ if (error)
+ goto fail;
+
+ urtw_8187_write_phy_cck(sc, 0x10, 0x9b);
+ urtw_8187_write_phy_ofdm(sc, 0x26, 0x90);
+
+ /* TX ant A, 0x0 for B */
+ error = urtw_8185_tx_antenna(sc, 0x3);
+ if (error)
+ goto fail;
+ urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002);
+
+ error = urtw_8225_rf_set_chan(sc, 1);
+fail:
+ return (error);
+#undef N
+}
+
+static usb2_error_t
+urtw_8225v2_rf_set_chan(struct urtw_softc *sc, int chan)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_channel *c = ic->ic_curchan;
+ usb2_error_t error;
+
+ error = urtw_8225v2_set_txpwrlvl(sc, chan);
+ if (error)
+ goto fail;
+
+ urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
+ usb2_pause_mtx(&sc->sc_mtx, 10);
+
+ urtw_write8_m(sc, URTW_SIFS, 0x22);
+
+ if(sc->sc_state == IEEE80211_S_ASSOC &&
+ ic->ic_flags & IEEE80211_F_SHSLOT)
+ urtw_write8_m(sc, URTW_SLOT, 0x9);
+ else
+ urtw_write8_m(sc, URTW_SLOT, 0x14);
+
+ if (IEEE80211_IS_CHAN_G(c)) {
+ /* for G */
+ urtw_write8_m(sc, URTW_DIFS, 0x14);
+ urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x14);
+ urtw_write8_m(sc, URTW_CW_VAL, 0x73);
+ } else {
+ /* for B */
+ urtw_write8_m(sc, URTW_DIFS, 0x24);
+ urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x24);
+ urtw_write8_m(sc, URTW_CW_VAL, 0xa5);
+ }
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data)
+{
+ int i;
+ int16_t bit;
+ uint8_t rlen = 12, wlen = 6;
+ uint16_t o1, o2, o3, tmp;
+ uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27;
+ uint32_t mask = 0x80000000, value = 0;
+ usb2_error_t error;
+
+ urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1);
+ urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2);
+ urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3);
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | URTW_RF_PINS_MAGIC4);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | URTW_RF_PINS_MAGIC4);
+ o1 &= ~URTW_RF_PINS_MAGIC4;
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN);
+ DELAY(5);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1);
+ DELAY(5);
+
+ for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) {
+ bit = ((d2w & mask) != 0) ? 1 : 0;
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
+ URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
+ URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ mask = mask >> 1;
+ if (i == 2)
+ break;
+ bit = ((d2w & mask) != 0) ? 1 : 0;
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
+ URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 |
+ URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1);
+ DELAY(1);
+ }
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW |
+ URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW);
+ DELAY(2);
+
+ mask = 0x800;
+ for (i = 0; i < rlen; i++, mask = mask >> 1) {
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
+ o1 | URTW_BB_HOST_BANG_RW);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
+ o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
+ o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
+ o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK);
+ DELAY(2);
+
+ urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp);
+ value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT,
+ o1 | URTW_BB_HOST_BANG_RW);
+ DELAY(2);
+ }
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN |
+ URTW_BB_HOST_BANG_RW);
+ DELAY(2);
+
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3);
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_OUTPUT_MAGIC1);
+
+ if (data != NULL)
+ *data = value;
+fail:
+ return (error);
+}
+
+
+static usb2_error_t
+urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan)
+{
+ int i;
+ uint8_t *cck_pwrtable;
+ uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10;
+ uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
+ uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
+ usb2_error_t error;
+
+ /* CCK power setting */
+ cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl;
+ cck_pwrlvl += sc->sc_txpwr_cck_base;
+ cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
+ cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 :
+ urtw_8225v2_txpwr_cck;
+
+ for (i = 0; i < 8; i++)
+ urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
+
+ urtw_write8_m(sc, URTW_TX_GAIN_CCK,
+ urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+
+ /* OFDM power setting */
+ ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ?
+ ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min;
+ ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
+ ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
+
+ error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
+ if (error)
+ goto fail;
+
+ urtw_8187_write_phy_ofdm(sc, 2, 0x42);
+ urtw_8187_write_phy_ofdm(sc, 5, 0x0);
+ urtw_8187_write_phy_ofdm(sc, 6, 0x40);
+ urtw_8187_write_phy_ofdm(sc, 7, 0x0);
+ urtw_8187_write_phy_ofdm(sc, 8, 0x40);
+
+ urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
+ urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain)
+{
+ uint8_t *gainp;
+ usb2_error_t error;
+
+ /* XXX for A? */
+ gainp = urtw_8225v2_gain_bg;
+ urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+ urtw_8187_write_phy_ofdm(sc, 0x21, 0x17);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225_isv2(struct urtw_softc *sc, int *ret)
+{
+ uint32_t data;
+ usb2_error_t error;
+
+ *ret = 1;
+
+ urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_MAGIC5);
+ urtw_write16_m(sc, URTW_RF_PINS_SELECT, URTW_RF_PINS_MAGIC5);
+ urtw_write16_m(sc, URTW_RF_PINS_ENABLE, URTW_RF_PINS_MAGIC5);
+ usb2_pause_mtx(&sc->sc_mtx, 500);
+
+ urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
+ URTW_8225_ADDR_0_DATA_MAGIC1);
+
+ error = urtw_8225_read(sc, URTW_8225_ADDR_8_MAGIC, &data);
+ if (error != 0)
+ goto fail;
+ if (data != URTW_8225_ADDR_8_DATA_MAGIC1)
+ *ret = 0;
+ else {
+ error = urtw_8225_read(sc, URTW_8225_ADDR_9_MAGIC, &data);
+ if (error != 0)
+ goto fail;
+ if (data != URTW_8225_ADDR_9_DATA_MAGIC1)
+ *ret = 0;
+ }
+
+ urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC,
+ URTW_8225_ADDR_0_DATA_MAGIC2);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225v2b_rf_init(struct urtw_softc *sc)
+{
+#define N(a) (sizeof(a) / sizeof((a)[0]))
+ int i;
+ usb2_error_t error;
+
+ for (i = 0; i < N(urtw_8225v2b_rf_part1); i++)
+ urtw_8225_write(sc, urtw_8225v2b_rf_part1[i].reg,
+ urtw_8225v2b_rf_part1[i].val);
+
+ urtw_8225_write(sc,
+ URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC1);
+
+ for (i = 0; i < N(urtw_8225v2b_rxgain); i++) {
+ urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1));
+ urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC,
+ urtw_8225v2b_rxgain[i]);
+ }
+
+ urtw_8225_write(sc, URTW_8225_ADDR_3_MAGIC, 0x080);
+ urtw_8225_write(sc, URTW_8225_ADDR_5_MAGIC, 0x004);
+ urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x0b7);
+ urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0xc4d);
+ urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0x44d);
+ urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x2bf);
+
+ urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03);
+ urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07);
+ urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03);
+
+ urtw_8187_write_phy_ofdm(sc, 0x80, 0x12);
+ for (i = 0; i < N(urtw_8225z2_agc); i++) {
+ urtw_8187_write_phy_ofdm(sc, 0xf, urtw_8225z2_agc[i]);
+ urtw_8187_write_phy_ofdm(sc, 0xe, 0x80 + i);
+ urtw_8187_write_phy_ofdm(sc, 0xe, 0);
+ }
+ urtw_8187_write_phy_ofdm(sc, 0x80, 0x10);
+
+ for (i = 0; i < N(urtw_8225v2b_rf_part2); i++)
+ urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2b_rf_part2[i].val);
+
+ urtw_write32_m(sc, 0xf0, (7 << 12) | (3 << 8) | 0x1c);
+ urtw_write32_m(sc, 0xf4, (7 << 12) | (3 << 8) | 0x1c);
+ urtw_write32_m(sc, 0xf8, (7 << 12) | (3 << 8) | 0x1c);
+ urtw_write32_m(sc, 0xfc, (7 << 12) | (3 << 8) | 0x1c);
+ urtw_write8_m(sc, URTW_ACM_CONTROL, 0);
+
+ urtw_8187_write_phy_ofdm(sc, 0x97, 0x46);
+ urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6);
+ urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc);
+ urtw_8187_write_phy_cck(sc, 0xc1, 0x88);
+fail:
+ return (error);
+#undef N
+}
+
+static usb2_error_t
+urtw_8225v2b_rf_set_chan(struct urtw_softc *sc, int chan)
+{
+ int ack;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ usb2_error_t error;
+
+ error = urtw_8225v2b_set_txpwrlvl(sc, chan);
+ if (error)
+ goto fail;
+
+ urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]);
+ usb2_pause_mtx(&sc->sc_mtx, 10);
+
+ urtw_write8_m(sc, URTW_SIFS, 0xa);
+ if (ic->ic_flags & IEEE80211_F_SHSLOT) {
+ urtw_write8_m(sc, URTW_SLOT, 0x9);
+ urtw_write8_m(sc, URTW_DIFS, 0x1c);
+ /* In 8187B, BRSR + 1 ==> EIFS register */
+ urtw_write8_m(sc, URTW_BRSR + 1, 0x53);
+
+ ack = 112 + 48 + 0x1c;
+ ack += (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ?
+ 72 : 144;
+ urtw_write8_m(sc, URTW_CARRIER_SCOUNT,
+ roundup2(ack, 4));
+ } else {
+ urtw_write8_m(sc, URTW_SLOT, 0x14);
+ urtw_write8_m(sc, URTW_DIFS, 0x32);
+ /* In 8187B, BRSR + 1 ==> EIFS register */
+ urtw_write8_m(sc, URTW_BRSR + 1, 0x5b);
+
+ ack = 112 + 48 + 0x32;
+ ack += (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ?
+ 72 : 144;
+ urtw_write8_m(sc, URTW_CARRIER_SCOUNT,
+ roundup2(ack, 4));
+
+ }
+
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8225v2b_set_txpwrlvl(struct urtw_softc *sc, int chan)
+{
+ int i;
+ uint8_t *cck_pwrtable;
+ uint8_t cck_pwrlvl_max = 15;
+ uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff;
+ uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff;
+ usb2_error_t error;
+
+ /* CCK power setting */
+ cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ?
+ ((sc->sc_flags & URTW_RTL8187B_REV_B) ? cck_pwrlvl_max : 22) :
+ (cck_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 0 : 7));
+ cck_pwrlvl += sc->sc_txpwr_cck_base;
+ cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl;
+ cck_pwrtable = (chan == 14) ? urtw_8225v2b_txpwr_cck_ch14 :
+ urtw_8225v2b_txpwr_cck;
+
+ if (sc->sc_flags & URTW_RTL8187B_REV_B)
+ cck_pwrtable += (cck_pwrlvl <= 6) ? 0 :
+ ((cck_pwrlvl <= 11) ? 8 : 16);
+ else
+ cck_pwrtable += (cck_pwrlvl <= 5) ? 0 :
+ ((cck_pwrlvl <= 11) ? 8 : ((cck_pwrlvl <= 17) ? 16 : 24));
+
+ for (i = 0; i < 8; i++)
+ urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]);
+
+ urtw_write8_m(sc, URTW_TX_GAIN_CCK,
+ urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1);
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+
+ /* OFDM power setting */
+ ofdm_pwrlvl = (ofdm_pwrlvl > 15) ?
+ ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 17 : 25) :
+ (ofdm_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 2 : 10));
+ ofdm_pwrlvl += sc->sc_txpwr_ofdm_base;
+ ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl;
+
+ urtw_write8_m(sc, URTW_TX_GAIN_OFDM,
+ urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1);
+
+ if (sc->sc_flags & URTW_RTL8187B_REV_B) {
+ if (ofdm_pwrlvl <= 11) {
+ urtw_8187_write_phy_ofdm(sc, 0x87, 0x60);
+ urtw_8187_write_phy_ofdm(sc, 0x89, 0x60);
+ } else {
+ urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
+ urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
+ }
+ } else {
+ if (ofdm_pwrlvl <= 11) {
+ urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c);
+ urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c);
+ } else if (ofdm_pwrlvl <= 17) {
+ urtw_8187_write_phy_ofdm(sc, 0x87, 0x54);
+ urtw_8187_write_phy_ofdm(sc, 0x89, 0x54);
+ } else {
+ urtw_8187_write_phy_ofdm(sc, 0x87, 0x50);
+ urtw_8187_write_phy_ofdm(sc, 0x89, 0x50);
+ }
+ }
+ usb2_pause_mtx(&sc->sc_mtx, 1);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data)
+{
+ struct usb2_device_request req;
+ usb2_error_t error;
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_GETREGS_REQ;
+ USETW(req.wValue, val | 0xfe00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint8_t));
+
+ error = urtw_do_request(sc, &req, data);
+ return (error);
+}
+
+static usb2_error_t
+urtw_write8e(struct urtw_softc *sc, int val, uint8_t data)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URTW_8187_SETREGS_REQ;
+ USETW(req.wValue, val | 0xfe00);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(uint8_t));
+
+ return (urtw_do_request(sc, &req, &data));
+}
+
+static usb2_error_t
+urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_CONFIG3, &data);
+ urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
+ urtw_write32_m(sc, URTW_ANAPARAM, val);
+ urtw_read8_m(sc, URTW_CONFIG3, &data);
+ urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG);
+ if (error)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_CONFIG3, &data);
+ urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE);
+ urtw_write32_m(sc, URTW_ANAPARAM2, val);
+ urtw_read8_m(sc, URTW_CONFIG3, &data);
+ urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE);
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL);
+ if (error)
+ goto fail;
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_intr_enable(struct urtw_softc *sc)
+{
+ usb2_error_t error;
+
+ urtw_write16_m(sc, URTW_INTR_MASK, 0xffff);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_intr_disable(struct urtw_softc *sc)
+{
+ usb2_error_t error;
+
+ urtw_write16_m(sc, URTW_INTR_MASK, 0);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_reset(struct urtw_softc *sc)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
+ if (error)
+ goto fail;
+ error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
+ if (error)
+ goto fail;
+
+ error = urtw_intr_disable(sc);
+ if (error)
+ goto fail;
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ error = urtw_write8e(sc, 0x18, 0x10);
+ if (error != 0)
+ goto fail;
+ error = urtw_write8e(sc, 0x18, 0x11);
+ if (error != 0)
+ goto fail;
+ error = urtw_write8e(sc, 0x18, 0x00);
+ if (error != 0)
+ goto fail;
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ urtw_read8_m(sc, URTW_CMD, &data);
+ data = (data & 0x2) | URTW_CMD_RST;
+ urtw_write8_m(sc, URTW_CMD, data);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ urtw_read8_m(sc, URTW_CMD, &data);
+ if (data & URTW_CMD_RST) {
+ device_printf(sc->sc_dev, "reset timeout\n");
+ goto fail;
+ }
+
+ error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD);
+ if (error)
+ goto fail;
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+
+ error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON);
+ if (error)
+ goto fail;
+ error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON);
+ if (error)
+ goto fail;
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_led_ctl(struct urtw_softc *sc, int mode)
+{
+ usb2_error_t error = 0;
+
+ switch (sc->sc_strategy) {
+ case URTW_SW_LED_MODE0:
+ error = urtw_led_mode0(sc, mode);
+ break;
+ case URTW_SW_LED_MODE1:
+ error = urtw_led_mode1(sc, mode);
+ break;
+ case URTW_SW_LED_MODE2:
+ error = urtw_led_mode2(sc, mode);
+ break;
+ case URTW_SW_LED_MODE3:
+ error = urtw_led_mode3(sc, mode);
+ break;
+ default:
+ panic("unsupported LED mode %d\n", sc->sc_strategy);
+ /* never reach */
+ }
+
+ return (error);
+}
+
+static usb2_error_t
+urtw_led_mode0(struct urtw_softc *sc, int mode)
+{
+
+ switch (mode) {
+ case URTW_LED_CTL_POWER_ON:
+ sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK;
+ break;
+ case URTW_LED_CTL_TX:
+ if (sc->sc_gpio_ledinprogress == 1)
+ return (0);
+
+ sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL;
+ sc->sc_gpio_blinktime = 2;
+ break;
+ case URTW_LED_CTL_LINK:
+ sc->sc_gpio_ledstate = URTW_LED_ON;
+ break;
+ default:
+ panic("unsupported LED mode 0x%x", mode);
+ /* never reach */
+ }
+
+ switch (sc->sc_gpio_ledstate) {
+ case URTW_LED_ON:
+ if (sc->sc_gpio_ledinprogress != 0)
+ break;
+ urtw_led_on(sc, URTW_LED_GPIO);
+ break;
+ case URTW_LED_BLINK_NORMAL:
+ if (sc->sc_gpio_ledinprogress != 0)
+ break;
+ sc->sc_gpio_ledinprogress = 1;
+ sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ?
+ URTW_LED_OFF : URTW_LED_ON;
+ usb2_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
+ break;
+ case URTW_LED_POWER_ON_BLINK:
+ urtw_led_on(sc, URTW_LED_GPIO);
+ usb2_pause_mtx(&sc->sc_mtx, 100);
+ urtw_led_off(sc, URTW_LED_GPIO);
+ break;
+ default:
+ panic("unknown LED status 0x%x", sc->sc_gpio_ledstate);
+ /* never reach */
+ }
+ return (0);
+}
+
+static usb2_error_t
+urtw_led_mode1(struct urtw_softc *sc, int mode)
+{
+
+ return (USB_ERR_INVAL);
+}
+
+static usb2_error_t
+urtw_led_mode2(struct urtw_softc *sc, int mode)
+{
+
+ return (USB_ERR_INVAL);
+}
+
+static usb2_error_t
+urtw_led_mode3(struct urtw_softc *sc, int mode)
+{
+
+ return (USB_ERR_INVAL);
+}
+
+static usb2_error_t
+urtw_led_on(struct urtw_softc *sc, int type)
+{
+ usb2_error_t error;
+
+ if (type == URTW_LED_GPIO) {
+ switch (sc->sc_gpio_ledpin) {
+ case URTW_LED_PIN_GPIO0:
+ urtw_write8_m(sc, URTW_GPIO, 0x01);
+ urtw_write8_m(sc, URTW_GP_ENABLE, 0x00);
+ break;
+ default:
+ panic("unsupported LED PIN type 0x%x",
+ sc->sc_gpio_ledpin);
+ /* never reach */
+ }
+ } else {
+ panic("unsupported LED type 0x%x", type);
+ /* never reach */
+ }
+
+ sc->sc_gpio_ledon = 1;
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_led_off(struct urtw_softc *sc, int type)
+{
+ usb2_error_t error;
+
+ if (type == URTW_LED_GPIO) {
+ switch (sc->sc_gpio_ledpin) {
+ case URTW_LED_PIN_GPIO0:
+ urtw_write8_m(sc, URTW_GPIO, URTW_GPIO_DATA_MAGIC1);
+ urtw_write8_m(sc,
+ URTW_GP_ENABLE, URTW_GP_ENABLE_DATA_MAGIC1);
+ break;
+ default:
+ panic("unsupported LED PIN type 0x%x",
+ sc->sc_gpio_ledpin);
+ /* never reach */
+ }
+ } else {
+ panic("unsupported LED type 0x%x", type);
+ /* never reach */
+ }
+
+ sc->sc_gpio_ledon = 0;
+
+fail:
+ return (error);
+}
+
+static void
+urtw_led_ch(void *arg)
+{
+ struct urtw_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ ieee80211_runtask(ic, &sc->sc_led_task);
+}
+
+static void
+urtw_ledtask(void *arg, int pending)
+{
+ struct urtw_softc *sc = arg;
+
+ if (sc->sc_strategy != URTW_SW_LED_MODE0)
+ panic("could not process a LED strategy 0x%x", sc->sc_strategy);
+
+ URTW_LOCK(sc);
+ urtw_led_blink(sc);
+ URTW_UNLOCK(sc);
+}
+
+static usb2_error_t
+urtw_led_blink(struct urtw_softc *sc)
+{
+ uint8_t ing = 0;
+ usb2_error_t error;
+
+ if (sc->sc_gpio_blinkstate == URTW_LED_ON)
+ error = urtw_led_on(sc, URTW_LED_GPIO);
+ else
+ error = urtw_led_off(sc, URTW_LED_GPIO);
+ sc->sc_gpio_blinktime--;
+ if (sc->sc_gpio_blinktime == 0)
+ ing = 1;
+ else {
+ if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL &&
+ sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY &&
+ sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3)
+ ing = 1;
+ }
+ if (ing == 1) {
+ if (sc->sc_gpio_ledstate == URTW_LED_ON &&
+ sc->sc_gpio_ledon == 0)
+ error = urtw_led_on(sc, URTW_LED_GPIO);
+ else if (sc->sc_gpio_ledstate == URTW_LED_OFF &&
+ sc->sc_gpio_ledon == 1)
+ error = urtw_led_off(sc, URTW_LED_GPIO);
+
+ sc->sc_gpio_blinktime = 0;
+ sc->sc_gpio_ledinprogress = 0;
+ return (0);
+ }
+
+ sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ?
+ URTW_LED_ON : URTW_LED_OFF;
+
+ switch (sc->sc_gpio_ledstate) {
+ case URTW_LED_BLINK_NORMAL:
+ usb2_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc);
+ break;
+ default:
+ panic("unknown LED status 0x%x", sc->sc_gpio_ledstate);
+ /* never reach */
+ }
+ return (0);
+}
+
+static usb2_error_t
+urtw_rx_enable(struct urtw_softc *sc)
+{
+ uint8_t data;
+ usb2_error_t error;
+
+ usb2_transfer_start((sc->sc_flags & URTW_RTL8187B) ?
+ sc->sc_xfer[URTW_8187B_BULK_RX] : sc->sc_xfer[URTW_8187L_BULK_RX]);
+
+ error = urtw_rx_setconf(sc);
+ if (error != 0)
+ goto fail;
+
+ urtw_read8_m(sc, URTW_CMD, &data);
+ urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_tx_enable(struct urtw_softc *sc)
+{
+ uint8_t data8;
+ uint32_t data;
+ usb2_error_t error;
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ urtw_read32_m(sc, URTW_TX_CONF, &data);
+ data &= ~URTW_TX_LOOPBACK_MASK;
+ data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
+ data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
+ data &= ~URTW_TX_SWPLCPLEN;
+ data |= URTW_TX_HW_SEQNUM | URTW_TX_DISREQQSIZE |
+ (7 << 8) | /* short retry limit */
+ (7 << 0) | /* long retry limit */
+ (7 << 21); /* MAX TX DMA */
+ urtw_write32_m(sc, URTW_TX_CONF, data);
+
+ urtw_read8_m(sc, URTW_CMD, &data8);
+ urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
+ return (error);
+ }
+
+ urtw_read8_m(sc, URTW_CW_CONF, &data8);
+ data8 &= ~(URTW_CW_CONF_PERPACKET_CW | URTW_CW_CONF_PERPACKET_RETRY);
+ urtw_write8_m(sc, URTW_CW_CONF, data8);
+
+ urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8);
+ data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN;
+ data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL;
+ data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT;
+ urtw_write8_m(sc, URTW_TX_AGC_CTL, data8);
+
+ urtw_read32_m(sc, URTW_TX_CONF, &data);
+ data &= ~URTW_TX_LOOPBACK_MASK;
+ data |= URTW_TX_LOOPBACK_NONE;
+ data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK);
+ data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT;
+ data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT;
+ data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK);
+ data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW;
+ data &= ~URTW_TX_SWPLCPLEN;
+ data |= URTW_TX_NOICV;
+ urtw_write32_m(sc, URTW_TX_CONF, data);
+
+ urtw_read8_m(sc, URTW_CMD, &data8);
+ urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE);
+fail:
+ return (error);
+}
+
+static usb2_error_t
+urtw_rx_setconf(struct urtw_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t data;
+ usb2_error_t error;
+
+ urtw_read32_m(sc, URTW_RX, &data);
+ data = data &~ URTW_RX_FILTER_MASK;
+ if (sc->sc_flags & URTW_RTL8187B) {
+ data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA |
+ URTW_RX_FILTER_MCAST | URTW_RX_FILTER_BCAST |
+ URTW_RX_FILTER_NICMAC | URTW_RX_CHECK_BSSID |
+ URTW_RX_FIFO_THRESHOLD_NONE |
+ URTW_MAX_RX_DMA_2048 |
+ URTW_RX_AUTORESETPHY | URTW_RCR_ONLYERLPKT;
+ } else {
+ data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA;
+ data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST;
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ data = data | URTW_RX_FILTER_ICVERR;
+ data = data | URTW_RX_FILTER_PWR;
+ }
+ if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR)
+ data = data | URTW_RX_FILTER_CRCERR;
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR ||
+ (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) {
+ data = data | URTW_RX_FILTER_ALLMAC;
+ } else {
+ data = data | URTW_RX_FILTER_NICMAC;
+ data = data | URTW_RX_CHECK_BSSID;
+ }
+
+ data = data &~ URTW_RX_FIFO_THRESHOLD_MASK;
+ data = data | URTW_RX_FIFO_THRESHOLD_NONE |
+ URTW_RX_AUTORESETPHY;
+ data = data &~ URTW_MAX_RX_DMA_MASK;
+ data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT;
+ }
+
+ urtw_write32_m(sc, URTW_RX, data);
+fail:
+ return (error);
+}
+
+static struct mbuf *
+urtw_rxeof(struct usb2_xfer *xfer, struct urtw_data *data, int *rssi_p,
+ int8_t *nf_p)
+{
+ int actlen, flen, len, nf = -95, rssi;
+ struct ieee80211_frame *wh;
+ struct mbuf *m, *mnew;
+ struct urtw_8187b_rxhdr *bhdr;
+ struct urtw_softc *sc = data->sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint8_t *desc, quality = 0, rate;
+
+ actlen = xfer->actlen;
+ if (actlen < URTW_MIN_RXBUFSZ) {
+ ifp->if_ierrors++;
+ return (NULL);
+ }
+
+ if (sc->sc_flags & URTW_RTL8187B) {
+ len = actlen - (sizeof(struct urtw_8187b_rxhdr));
+ bhdr = (struct urtw_8187b_rxhdr *)(data->buf + len);
+ desc = data->buf + len;
+ flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
+ if (flen > actlen) {
+ ifp->if_ierrors++;
+ return (NULL);
+ }
+ rate = (le32toh(bhdr->flags) >> 20) & 0xf;
+ rssi = 14 + (bhdr->rssi / 2);
+ if (rssi > 95)
+ rssi = 95;
+ } else {
+ /* 4 dword and 4 byte CRC */
+ len = actlen - (4 * 4);
+ desc = data->buf + len;
+ flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff);
+ if (flen > actlen) {
+ ifp->if_ierrors++;
+ return (NULL);
+ }
+
+ rate = (desc[2] & 0xf0) >> 4;
+ quality = desc[4] & 0xff;
+ /* XXX correct? */
+ rssi = (desc[6] & 0xfe) >> 1;
+ if (!urtw_isbmode(rate)) {
+ rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi);
+ rssi = ((90 - rssi) * 100) / 65;
+ } else {
+ rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi);
+ rssi = ((95 - rssi) * 100) / 65;
+ }
+ }
+
+ mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (mnew == NULL) {
+ ifp->if_ierrors++;
+ return (NULL);
+ }
+
+ m = data->m;
+ data->m = mnew;
+ data->buf = mtod(mnew, uint8_t *);
+
+ /* finalize mbuf */
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = flen - 4;
+
+ if (ieee80211_radiotap_active(ic)) {
+ struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+ /* XXX Are variables correct? */
+ tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
+ tap->wr_dbm_antsignal = (int8_t)rssi;
+ }
+
+ wh = mtod(m, struct ieee80211_frame *);
+ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
+ sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
+ /* XXX correct? */
+ if ((sc->sc_flags & URTW_RTL8187B) == 0)
+ nf = (quality > 64) ? 0 : ((64 - quality) * 100) / 64;
+
+ *rssi_p = rssi;
+ *nf_p = nf;
+
+ return (m);
+}
+
+static void
+urtw_bulk_rx_callback(struct usb2_xfer *xfer)
+{
+ struct urtw_softc *sc = xfer->priv_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct mbuf *m = NULL;
+ struct urtw_data *data;
+ int8_t nf = -95;
+ int rssi = 1;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ data = STAILQ_FIRST(&sc->sc_rx_active);
+ if (data == NULL)
+ goto setup;
+ STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
+ m = urtw_rxeof(xfer, data, &rssi, &nf);
+ STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
+ /* FALLTHROUGH */
+ case USB_ST_SETUP:
+setup:
+ data = STAILQ_FIRST(&sc->sc_rx_inactive);
+ if (data == NULL) {
+ KASSERT(m == NULL, ("mbuf isn't NULL"));
+ return;
+ }
+ STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next);
+ STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next);
+ usb2_set_frame_data(xfer, data->buf, 0);
+ xfer->frlengths[0] = xfer->max_data_length;
+ usb2_start_hardware(xfer);
+
+ /*
+ * To avoid LOR we should unlock our private mutex here to call
+ * ieee80211_input() because here is at the end of a USB
+ * callback and safe to unlock.
+ */
+ URTW_UNLOCK(sc);
+ if (m != NULL) {
+ wh = mtod(m, struct ieee80211_frame *);
+ ni = ieee80211_find_rxnode(ic,
+ (struct ieee80211_frame_min *)wh);
+ if (ni != NULL) {
+ (void) ieee80211_input(ni, m, rssi, nf);
+ /* node is no longer needed */
+ ieee80211_free_node(ni);
+ } else
+ (void) ieee80211_input_all(ic, m, rssi, nf);
+ m = NULL;
+ }
+ URTW_LOCK(sc);
+ break;
+ default:
+ /* needs it to the inactive queue due to a error. */
+ data = STAILQ_FIRST(&sc->sc_rx_active);
+ if (data != NULL) {
+ STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
+ STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
+ }
+ if (xfer->error != USB_ERR_CANCELLED) {
+ xfer->flags.stall_pipe = 1;
+ ifp->if_ierrors++;
+ goto setup;
+ }
+ break;
+ }
+}
+
+static void
+urtw_txeof(struct usb2_xfer *xfer, struct urtw_data *data)
+{
+ struct urtw_softc *sc = xfer->priv_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ /*
+ * Do any tx complete callback. Note this must be done before releasing
+ * the node reference.
+ */
+ if (data->m) {
+ m = data->m;
+ if (m->m_flags & M_TXCB) {
+ /* XXX status? */
+ ieee80211_process_callback(data->ni, m, 0);
+ }
+ m_freem(m);
+ data->m = NULL;
+ }
+ if (data->ni) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+ sc->sc_txtimer = 0;
+ ifp->if_opackets++;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+}
+
+static void
+urtw_bulk_tx_callback(struct usb2_xfer *xfer)
+{
+ struct urtw_softc *sc = xfer->priv_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct urtw_data *data;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ data = STAILQ_FIRST(&sc->sc_tx_active);
+ if (data == NULL)
+ goto setup;
+ STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
+ urtw_txeof(xfer, data);
+ STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
+ /* FALLTHROUGH */
+ case USB_ST_SETUP:
+setup:
+ data = STAILQ_FIRST(&sc->sc_tx_pending);
+ if (data == NULL) {
+ DPRINTF(sc, URTW_DEBUG_XMIT,
+ "%s: empty pending queue\n", __func__);
+ return;
+ }
+ STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
+ STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
+
+ usb2_set_frame_data(xfer, data->buf, 0);
+ xfer->frlengths[0] = data->buflen;
+ usb2_start_hardware(xfer);
+
+ URTW_UNLOCK(sc);
+ urtw_start(ifp);
+ URTW_LOCK(sc);
+ break;
+ default:
+ data = STAILQ_FIRST(&sc->sc_tx_active);
+ if (data == NULL)
+ goto setup;
+ if (data->ni != NULL) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ ifp->if_oerrors++;
+ }
+ if (xfer->error != USB_ERR_CANCELLED) {
+ xfer->flags.stall_pipe = 1;
+ goto setup;
+ }
+ break;
+ }
+}
+
+static struct urtw_data *
+_urtw_getbuf(struct urtw_softc *sc)
+{
+ struct urtw_data *bf;
+
+ bf = STAILQ_FIRST(&sc->sc_tx_inactive);
+ if (bf != NULL)
+ STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
+ else
+ bf = NULL;
+ if (bf == NULL)
+ DPRINTF(sc, URTW_DEBUG_XMIT, "%s: %s\n", __func__,
+ "out of xmit buffers");
+ return (bf);
+}
+
+static struct urtw_data *
+urtw_getbuf(struct urtw_softc *sc)
+{
+ struct urtw_data *bf;
+
+ URTW_ASSERT_LOCKED(sc);
+
+ bf = _urtw_getbuf(sc);
+ if (bf == NULL) {
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF(sc, URTW_DEBUG_XMIT, "%s: stop queue\n", __func__);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ }
+ return (bf);
+}
+
+static int
+urtw_isbmode(uint16_t rate)
+{
+
+ rate = urtw_rtl2rate(rate);
+
+ return ((rate <= 22 && rate != 12 && rate != 18) ||
+ rate == 44) ? (1) : (0);
+}
+
+static device_method_t urtw_methods[] = {
+ DEVMETHOD(device_probe, urtw_match),
+ DEVMETHOD(device_attach, urtw_attach),
+ DEVMETHOD(device_detach, urtw_detach),
+ { 0, 0 }
+};
+static driver_t urtw_driver = {
+ "urtw",
+ urtw_methods,
+ sizeof(struct urtw_softc)
+};
+static devclass_t urtw_devclass;
+
+DRIVER_MODULE(urtw, uhub, urtw_driver, urtw_devclass, NULL, 0);
+MODULE_DEPEND(urtw, wlan, 1, 1, 1);
+MODULE_DEPEND(urtw, usb, 1, 1, 1);
diff --git a/sys/dev/usb/wlan/if_urtwreg.h b/sys/dev/usb/wlan/if_urtwreg.h
new file mode 100644
index 0000000..d3399b7
--- /dev/null
+++ b/sys/dev/usb/wlan/if_urtwreg.h
@@ -0,0 +1,303 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define URTW_CONFIG_INDEX 0
+#define URTW_IFACE_INDEX 0
+
+/* for 8187 */
+#define URTW_MAC0 0x0000 /* 1 byte */
+#define URTW_MAC1 0x0001 /* 1 byte */
+#define URTW_MAC2 0x0002 /* 1 byte */
+#define URTW_MAC3 0x0003 /* 1 byte */
+#define URTW_MAC4 0x0004 /* 1 byte */
+#define URTW_MAC5 0x0005 /* 1 byte */
+#define URTW_BRSR 0x002c /* 2 byte */
+#define URTW_BRSR_MBR_8185 (0x0fff)
+#define URTW_BSSID 0x002e /* 6 byte */
+#define URTW_RESP_RATE 0x0034 /* 1 byte */
+#define URTW_RESP_MAX_RATE_SHIFT (4)
+#define URTW_RESP_MIN_RATE_SHIFT (0)
+#define URTW_EIFS 0x0035 /* 1 byte */
+#define URTW_INTR_MASK 0x003c /* 2 byte */
+#define URTW_CMD 0x0037 /* 1 byte */
+#define URTW_CMD_TX_ENABLE (0x4)
+#define URTW_CMD_RX_ENABLE (0x8)
+#define URTW_CMD_RST (0x10)
+#define URTW_TX_CONF 0x0040 /* 4 byte */
+#define URTW_TX_LOOPBACK_SHIFT (17)
+#define URTW_TX_LOOPBACK_NONE (0 << URTW_TX_LOOPBACK_SHIFT)
+#define URTW_TX_LOOPBACK_MAC (1 << URTW_TX_LOOPBACK_SHIFT)
+#define URTW_TX_LOOPBACK_BASEBAND (2 << URTW_TX_LOOPBACK_SHIFT)
+#define URTW_TX_LOOPBACK_CONTINUE (3 << URTW_TX_LOOPBACK_SHIFT)
+#define URTW_TX_LOOPBACK_MASK (0x60000)
+#define URTW_TX_DPRETRY_MASK (0xff00)
+#define URTW_TX_RTSRETRY_MASK (0xff)
+#define URTW_TX_DPRETRY_SHIFT (0)
+#define URTW_TX_RTSRETRY_SHIFT (8)
+#define URTW_TX_NOCRC (0x10000)
+#define URTW_TX_MXDMA_MASK (0xe00000)
+#define URTW_TX_MXDMA_1024 (6 << URTW_TX_MXDMA_SHIFT)
+#define URTW_TX_MXDMA_2048 (7 << URTW_TX_MXDMA_SHIFT)
+#define URTW_TX_MXDMA_SHIFT (21)
+#define URTW_TX_DISCW (1 << 20)
+#define URTW_TX_SWPLCPLEN (1 << 24)
+#define URTW_TX_DISREQQSIZE (1 << 28)
+#define URTW_TX_HW_SEQNUM (1 << 30)
+#define URTW_TX_CWMIN (1 << 31)
+#define URTW_TX_NOICV (0x80000)
+#define URTW_RX 0x0044 /* 4 byte */
+#define URTW_RX_9356SEL (1 << 6)
+#define URTW_RX_FILTER_MASK \
+ (URTW_RX_FILTER_ALLMAC | URTW_RX_FILTER_NICMAC | URTW_RX_FILTER_MCAST | \
+ URTW_RX_FILTER_BCAST | URTW_RX_FILTER_CRCERR | URTW_RX_FILTER_ICVERR | \
+ URTW_RX_FILTER_DATA | URTW_RX_FILTER_CTL | URTW_RX_FILTER_MNG | \
+ (1 << 21) | \
+ URTW_RX_FILTER_PWR | URTW_RX_CHECK_BSSID)
+#define URTW_RX_FILTER_ALLMAC (0x00000001)
+#define URTW_RX_FILTER_NICMAC (0x00000002)
+#define URTW_RX_FILTER_MCAST (0x00000004)
+#define URTW_RX_FILTER_BCAST (0x00000008)
+#define URTW_RX_FILTER_CRCERR (0x00000020)
+#define URTW_RX_FILTER_ICVERR (0x00001000)
+#define URTW_RX_FILTER_DATA (0x00040000)
+#define URTW_RX_FILTER_CTL (0x00080000)
+#define URTW_RX_FILTER_MNG (0x00100000)
+#define URTW_RX_FILTER_PWR (0x00400000)
+#define URTW_RX_CHECK_BSSID (0x00800000)
+#define URTW_RX_FIFO_THRESHOLD_MASK ((1 << 13) | (1 << 14) | (1 << 15))
+#define URTW_RX_FIFO_THRESHOLD_SHIFT (13)
+#define URTW_RX_FIFO_THRESHOLD_128 (3)
+#define URTW_RX_FIFO_THRESHOLD_256 (4)
+#define URTW_RX_FIFO_THRESHOLD_512 (5)
+#define URTW_RX_FIFO_THRESHOLD_1024 (6)
+#define URTW_RX_FIFO_THRESHOLD_NONE (7 << URTW_RX_FIFO_THRESHOLD_SHIFT)
+#define URTW_RX_AUTORESETPHY (1 << URTW_RX_AUTORESETPHY_SHIFT)
+#define URTW_RX_AUTORESETPHY_SHIFT (28)
+#define URTW_MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10))
+#define URTW_MAX_RX_DMA_2048 (7 << URTW_MAX_RX_DMA_SHIFT)
+#define URTW_MAX_RX_DMA_1024 (6)
+#define URTW_MAX_RX_DMA_SHIFT (10)
+#define URTW_RCR_ONLYERLPKT (1 << 31)
+#define URTW_INT_TIMEOUT 0x0048 /* 4 byte */
+#define URTW_EPROM_CMD 0x0050 /* 1 byte */
+#define URTW_EPROM_CMD_NORMAL (0x0)
+#define URTW_EPROM_CMD_NORMAL_MODE \
+ (URTW_EPROM_CMD_NORMAL << URTW_EPROM_CMD_SHIFT)
+#define URTW_EPROM_CMD_LOAD (0x1)
+#define URTW_EPROM_CMD_PROGRAM (0x2)
+#define URTW_EPROM_CMD_PROGRAM_MODE \
+ (URTW_EPROM_CMD_PROGRAM << URTW_EPROM_CMD_SHIFT)
+#define URTW_EPROM_CMD_CONFIG (0x3)
+#define URTW_EPROM_CMD_SHIFT (6)
+#define URTW_EPROM_CMD_MASK ((1 << 7) | (1 << 6))
+#define URTW_EPROM_READBIT (0x1)
+#define URTW_EPROM_WRITEBIT (0x2)
+#define URTW_EPROM_CK (0x4)
+#define URTW_EPROM_CS (0x8)
+#define URTW_CONFIG1 0x0052 /* 1 byte */
+#define URTW_CONFIG2 0x0053 /* 1 byte */
+#define URTW_ANAPARAM 0x0054 /* 4 byte */
+#define URTW_8225_ANAPARAM_ON (0xa0000a59)
+#define URTW_8225_ANAPARAM_OFF (0xa00beb59)
+#define URTW_8187B_8225_ANAPARAM_ON (0x45090658)
+#define URTW_8187B_8225_ANAPARAM_OFF (0x55480658)
+#define URTW_MSR 0x0058 /* 1 byte */
+#define URTW_MSR_LINK_MASK ((1 << 2) | (1 << 3))
+#define URTW_MSR_LINK_SHIFT (2)
+#define URTW_MSR_LINK_NONE (0 << URTW_MSR_LINK_SHIFT)
+#define URTW_MSR_LINK_ADHOC (1 << URTW_MSR_LINK_SHIFT)
+#define URTW_MSR_LINK_STA (2 << URTW_MSR_LINK_SHIFT)
+#define URTW_MSR_LINK_HOSTAP (3 << URTW_MSR_LINK_SHIFT)
+#define URTW_MSR_LINK_ENEDCA (1 << 4)
+#define URTW_CONFIG3 0x0059 /* 1 byte */
+#define URTW_CONFIG3_ANAPARAM_WRITE (0x40)
+#define URTW_CONFIG3_GNT_SELECT (0x80)
+#define URTW_CONFIG3_ANAPARAM_W_SHIFT (6)
+#define URTW_CONFIG4 0x005a /* 1 byte */
+#define URTW_CONFIG4_VCOOFF (1 << 7)
+#define URTW_TESTR 0x005b /* 1 byte */
+#define URTW_PSR 0x005e /* 1 byte */
+#define URTW_ANAPARAM2 0x0060 /* 4 byte */
+#define URTW_8225_ANAPARAM2_ON (0x860c7312)
+#define URTW_8225_ANAPARAM2_OFF (0x840dec11)
+#define URTW_8187B_8225_ANAPARAM2_ON (0x727f3f52)
+#define URTW_8187B_8225_ANAPARAM2_OFF (0x72003f50)
+#define URTW_BEACON_INTERVAL 0x0070 /* 2 byte */
+#define URTW_ATIM_WND 0x0072 /* 2 byte */
+#define URTW_BEACON_INTERVAL_TIME 0x0074 /* 2 byte */
+#define URTW_ATIM_TR_ITV 0x0076 /* 2 byte */
+#define URTW_CARRIER_SCOUNT 0x0079 /* 1 byte */
+#define URTW_PHY_MAGIC1 0x007c /* 1 byte */
+#define URTW_PHY_MAGIC2 0x007d /* 1 byte */
+#define URTW_PHY_MAGIC3 0x007e /* 1 byte */
+#define URTW_PHY_MAGIC4 0x007f /* 1 byte */
+#define URTW_RF_PINS_OUTPUT 0x0080 /* 2 byte */
+#define URTW_RF_PINS_OUTPUT_MAGIC1 (0x3a0)
+#define URTW_BB_HOST_BANG_CLK (1 << 1)
+#define URTW_BB_HOST_BANG_EN (1 << 2)
+#define URTW_BB_HOST_BANG_RW (1 << 3)
+#define URTW_RF_PINS_ENABLE 0x0082 /* 2 byte */
+#define URTW_RF_PINS_SELECT 0x0084 /* 2 byte */
+#define URTW_ADDR_MAGIC1 0x0085 /* broken? */
+#define URTW_RF_PINS_INPUT 0x0086 /* 2 byte */
+#define URTW_RF_PINS_MAGIC1 (0xfff3)
+#define URTW_RF_PINS_MAGIC2 (0xfff0)
+#define URTW_RF_PINS_MAGIC3 (0x0007)
+#define URTW_RF_PINS_MAGIC4 (0xf)
+#define URTW_RF_PINS_MAGIC5 (0x0080)
+#define URTW_RF_PARA 0x0088 /* 4 byte */
+#define URTW_RF_TIMING 0x008c /* 4 byte */
+#define URTW_GP_ENABLE 0x0090 /* 1 byte */
+#define URTW_GP_ENABLE_DATA_MAGIC1 (0x1)
+#define URTW_GPIO 0x0091 /* 1 byte */
+#define URTW_GPIO_DATA_MAGIC1 (0x1)
+#define URTW_HSSI_PARA 0x0094 /* 4 byte */
+#define URTW_TX_AGC_CTL 0x009c /* 1 byte */
+#define URTW_TX_AGC_CTL_PERPACKET_GAIN (0x1)
+#define URTW_TX_AGC_CTL_PERPACKET_ANTSEL (0x2)
+#define URTW_TX_AGC_CTL_FEEDBACK_ANT (0x4)
+#define URTW_TX_GAIN_CCK 0x009d /* 1 byte */
+#define URTW_TX_GAIN_OFDM 0x009e /* 1 byte */
+#define URTW_TX_ANTENNA 0x009f /* 1 byte */
+#define URTW_WPA_CONFIG 0x00b0 /* 1 byte */
+#define URTW_SIFS 0x00b4 /* 1 byte */
+#define URTW_DIFS 0x00b5 /* 1 byte */
+#define URTW_SLOT 0x00b6 /* 1 byte */
+#define URTW_CW_CONF 0x00bc /* 1 byte */
+#define URTW_CW_CONF_PERPACKET_RETRY (0x2)
+#define URTW_CW_CONF_PERPACKET_CW (0x1)
+#define URTW_CW_VAL 0x00bd /* 1 byte */
+#define URTW_RATE_FALLBACK 0x00be /* 1 byte */
+#define URTW_RATE_FALLBACK_ENABLE (0x80)
+#define URTW_ACM_CONTROL 0x00bf /* 1 byte */
+#define URTW_INT_MIG 0x00e2 /* 2 byte */
+#define URTW_TID_AC_MAP 0x00e8 /* 2 byte */
+#define URTW_ANAPARAM3 0x00ee /* 1 byte */
+#define URTW_8187B_8225_ANAPARAM3_ON (0x0)
+#define URTW_8187B_8225_ANAPARAM3_OFF (0x0)
+
+#define URTW_TALLY_SEL 0x00fc /* 1 byte */
+#define URTW_ADDR_MAGIC2 0x00fe /* 2 byte */
+#define URTW_ADDR_MAGIC3 0x00ff /* 1 byte */
+
+/* for 8225 */
+#define URTW_8225_ADDR_0_MAGIC 0x0
+#define URTW_8225_ADDR_0_DATA_MAGIC1 (0x1b7)
+#define URTW_8225_ADDR_0_DATA_MAGIC2 (0x0b7)
+#define URTW_8225_ADDR_0_DATA_MAGIC3 (0x127)
+#define URTW_8225_ADDR_0_DATA_MAGIC4 (0x027)
+#define URTW_8225_ADDR_0_DATA_MAGIC5 (0x22f)
+#define URTW_8225_ADDR_0_DATA_MAGIC6 (0x2bf)
+#define URTW_8225_ADDR_1_MAGIC 0x1
+#define URTW_8225_ADDR_2_MAGIC 0x2
+#define URTW_8225_ADDR_2_DATA_MAGIC1 (0xc4d)
+#define URTW_8225_ADDR_2_DATA_MAGIC2 (0x44d)
+#define URTW_8225_ADDR_3_MAGIC 0x3
+#define URTW_8225_ADDR_3_DATA_MAGIC1 (0x2)
+#define URTW_8225_ADDR_5_MAGIC 0x5
+#define URTW_8225_ADDR_5_DATA_MAGIC1 (0x4)
+#define URTW_8225_ADDR_6_MAGIC 0x6
+#define URTW_8225_ADDR_6_DATA_MAGIC1 (0xe6)
+#define URTW_8225_ADDR_6_DATA_MAGIC2 (0x80)
+#define URTW_8225_ADDR_7_MAGIC 0x7
+#define URTW_8225_ADDR_8_MAGIC 0x8
+#define URTW_8225_ADDR_8_DATA_MAGIC1 (0x588)
+#define URTW_8225_ADDR_9_MAGIC 0x9
+#define URTW_8225_ADDR_9_DATA_MAGIC1 (0x700)
+#define URTW_8225_ADDR_C_MAGIC 0xc
+#define URTW_8225_ADDR_C_DATA_MAGIC1 (0x850)
+#define URTW_8225_ADDR_C_DATA_MAGIC2 (0x050)
+
+/* for EEPROM */
+#define URTW_EPROM_TXPW_BASE 0x05
+#define URTW_EPROM_RFCHIPID 0x06
+#define URTW_EPROM_RFCHIPID_RTL8225U (5)
+#define URTW_EPROM_RFCHIPID_RTL8225Z2 (6)
+#define URTW_EPROM_MACADDR 0x07
+#define URTW_EPROM_TXPW0 0x16
+#define URTW_EPROM_TXPW2 0x1b
+#define URTW_EPROM_TXPW1 0x3d
+#define URTW_EPROM_SWREV 0x3f
+#define URTW_EPROM_CID_MASK (0xff)
+#define URTW_EPROM_CID_RSVD0 (0x00)
+#define URTW_EPROM_CID_RSVD1 (0xff)
+#define URTW_EPROM_CID_ALPHA0 (0x01)
+#define URTW_EPROM_CID_SERCOMM_PS (0x02)
+#define URTW_EPROM_CID_HW_LED (0x03)
+
+/* LED */
+#define URTW_CID_DEFAULT 0
+#define URTW_CID_8187_ALPHA0 1
+#define URTW_CID_8187_SERCOMM_PS 2
+#define URTW_CID_8187_HW_LED 3
+#define URTW_SW_LED_MODE0 0
+#define URTW_SW_LED_MODE1 1
+#define URTW_SW_LED_MODE2 2
+#define URTW_SW_LED_MODE3 3
+#define URTW_HW_LED 4
+#define URTW_LED_CTL_POWER_ON 0
+#define URTW_LED_CTL_LINK 2
+#define URTW_LED_CTL_TX 4
+#define URTW_LED_PIN_GPIO0 0
+#define URTW_LED_PIN_LED0 1
+#define URTW_LED_PIN_LED1 2
+#define URTW_LED_UNKNOWN 0
+#define URTW_LED_ON 1
+#define URTW_LED_OFF 2
+#define URTW_LED_BLINK_NORMAL 3
+#define URTW_LED_BLINK_SLOWLY 4
+#define URTW_LED_POWER_ON_BLINK 5
+#define URTW_LED_SCAN_BLINK 6
+#define URTW_LED_NO_LINK_BLINK 7
+#define URTW_LED_BLINK_CM3 8
+
+/* for extra area */
+#define URTW_EPROM_DISABLE 0
+#define URTW_EPROM_ENABLE 1
+#define URTW_EPROM_DELAY 10
+#define URTW_8187_GETREGS_REQ 5
+#define URTW_8187_SETREGS_REQ 5
+#define URTW_8225_RF_MAX_SENS 6
+#define URTW_8225_RF_DEF_SENS 4
+#define URTW_DEFAULT_RTS_RETRY 7
+#define URTW_DEFAULT_TX_RETRY 7
+#define URTW_DEFAULT_RTS_THRESHOLD 2342U
+
+struct urtw_8187b_rxhdr {
+ uint32_t flags;
+ uint64_t mactime;
+ uint8_t sq;
+ uint8_t rssi;
+ uint8_t agc;
+ uint8_t flags2;
+ uint16_t unknown;
+ int8_t pwdb;
+ uint8_t fot;
+} __packed;
+
+struct urtw_8187b_txhdr {
+ uint32_t flags;
+ uint16_t rts_duration;
+ uint16_t len;
+ uint32_t unknown1;
+ uint16_t unknown2;
+ uint16_t tx_duration;
+ uint32_t unknown3;
+ uint32_t retry;
+ uint32_t unknown4[2];
+} __packed;
diff --git a/sys/dev/usb/wlan/if_urtwvar.h b/sys/dev/usb/wlan/if_urtwvar.h
new file mode 100644
index 0000000..0835659
--- /dev/null
+++ b/sys/dev/usb/wlan/if_urtwvar.h
@@ -0,0 +1,174 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+enum {
+ URTW_8187B_BULK_RX,
+ URTW_8187B_BULK_TX_BE,
+ URTW_8187B_BULK_TX_BK,
+ URTW_8187B_BULK_TX_VI,
+ URTW_8187B_BULK_TX_VO,
+ URTW_8187B_BULK_TX_EP12,
+ URTW_8187B_N_XFERS = 6
+};
+
+enum {
+ URTW_8187L_BULK_RX,
+ URTW_8187L_BULK_TX_LOW,
+ URTW_8187L_BULK_TX_NORMAL,
+ URTW_8187L_N_XFERS = 3
+};
+
+/* XXX no definition at net80211? */
+#define URTW_MAX_CHANNELS 15
+
+struct urtw_data {
+ struct urtw_softc *sc;
+ uint8_t *buf;
+ uint16_t buflen;
+ struct mbuf *m;
+ struct ieee80211_node *ni; /* NB: tx only */
+ STAILQ_ENTRY(urtw_data) next;
+};
+typedef STAILQ_HEAD(, urtw_data) urtw_datahead;
+
+/* XXX not correct.. */
+#define URTW_MIN_RXBUFSZ \
+ (sizeof(struct ieee80211_frame_min))
+
+#define URTW_RX_DATA_LIST_COUNT 4
+#define URTW_TX_DATA_LIST_COUNT 16
+#define URTW_RX_MAXSIZE 0x9c4
+#define URTW_TX_MAXSIZE 0x9c4
+
+struct urtw_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ uint8_t wr_flags;
+ uint16_t wr_chan_freq;
+ uint16_t wr_chan_flags;
+ int8_t wr_dbm_antsignal;
+} __packed;
+
+#define URTW_RX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL))
+
+struct urtw_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ uint8_t wt_flags;
+ uint16_t wt_chan_freq;
+ uint16_t wt_chan_flags;
+} __packed;
+
+#define URTW_TX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL))
+
+struct urtw_vap {
+ struct ieee80211vap vap;
+ int (*newstate)(struct ieee80211vap *,
+ enum ieee80211_state, int);
+};
+#define URTW_VAP(vap) ((struct urtw_vap *)(vap))
+
+struct urtw_softc {
+ struct ifnet *sc_ifp;
+ device_t sc_dev;
+ struct usb2_device *sc_udev;
+ struct mtx sc_mtx;
+
+ int sc_debug;
+ int sc_if_flags;
+ int sc_flags;
+#define URTW_INIT_ONCE (1 << 1)
+#define URTW_RTL8187B (1 << 2)
+#define URTW_RTL8187B_REV_B (1 << 3)
+#define URTW_RTL8187B_REV_D (1 << 4)
+#define URTW_RTL8187B_REV_E (1 << 5)
+ enum ieee80211_state sc_state;
+
+ int sc_epromtype;
+#define URTW_EEPROM_93C46 0
+#define URTW_EEPROM_93C56 1
+ uint8_t sc_crcmon;
+ uint8_t sc_bssid[IEEE80211_ADDR_LEN];
+
+ struct ieee80211_channel *sc_curchan;
+
+ /* for RF */
+ usb2_error_t (*sc_rf_init)(struct urtw_softc *);
+ usb2_error_t (*sc_rf_set_chan)(struct urtw_softc *,
+ int);
+ usb2_error_t (*sc_rf_set_sens)(struct urtw_softc *,
+ int);
+ usb2_error_t (*sc_rf_stop)(struct urtw_softc *);
+ uint8_t sc_rfchip;
+ uint32_t sc_max_sens;
+ uint32_t sc_sens;
+ /* for LED */
+ struct usb2_callout sc_led_ch;
+ struct task sc_led_task;
+ uint8_t sc_psr;
+ uint8_t sc_strategy;
+#define URTW_LED_GPIO 1
+ uint8_t sc_gpio_ledon;
+ uint8_t sc_gpio_ledinprogress;
+ uint8_t sc_gpio_ledstate;
+ uint8_t sc_gpio_ledpin;
+ uint8_t sc_gpio_blinktime;
+ uint8_t sc_gpio_blinkstate;
+ /* RX/TX */
+ struct usb2_xfer *sc_xfer[URTW_8187B_N_XFERS];
+#define URTW_PRIORITY_LOW 0
+#define URTW_PRIORITY_NORMAL 1
+#define URTW_DATA_TIMEOUT 10000 /* 10 sec */
+#define URTW_8187B_TXPIPE_BE 0x6 /* best effort */
+#define URTW_8187B_TXPIPE_BK 0x7 /* background */
+#define URTW_8187B_TXPIPE_VI 0x5 /* video */
+#define URTW_8187B_TXPIPE_VO 0x4 /* voice */
+#define URTW_8187B_TXPIPE_MAX 4
+ struct urtw_data sc_rx[URTW_RX_DATA_LIST_COUNT];
+ urtw_datahead sc_rx_active;
+ urtw_datahead sc_rx_inactive;
+ struct urtw_data sc_tx[URTW_TX_DATA_LIST_COUNT];
+ urtw_datahead sc_tx_active;
+ urtw_datahead sc_tx_inactive;
+ urtw_datahead sc_tx_pending;
+ uint8_t sc_rts_retry;
+ uint8_t sc_tx_retry;
+ uint8_t sc_preamble_mode;
+#define URTW_PREAMBLE_MODE_SHORT 1
+#define URTW_PREAMBLE_MODE_LONG 2
+ struct callout sc_watchdog_ch;
+ int sc_txtimer;
+ int sc_currate;
+ /* TX power */
+ uint8_t sc_txpwr_cck[URTW_MAX_CHANNELS];
+ uint8_t sc_txpwr_cck_base;
+ uint8_t sc_txpwr_ofdm[URTW_MAX_CHANNELS];
+ uint8_t sc_txpwr_ofdm_base;
+
+ struct urtw_rx_radiotap_header sc_rxtap;
+ int sc_rxtap_len;
+ struct urtw_tx_radiotap_header sc_txtap;
+ int sc_txtap_len;
+};
+
+#define URTW_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define URTW_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define URTW_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
OpenPOWER on IntegriCloud