1192873Sweongyo/*- 2192873Sweongyo * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org> 3192873Sweongyo * 4192873Sweongyo * Permission to use, copy, modify, and distribute this software for any 5192873Sweongyo * purpose with or without fee is hereby granted, provided that the above 6192873Sweongyo * copyright notice and this permission notice appear in all copies. 7192873Sweongyo * 8192873Sweongyo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9192873Sweongyo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10192873Sweongyo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11192873Sweongyo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12192873Sweongyo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13192873Sweongyo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14192873Sweongyo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15192873Sweongyo */ 16192873Sweongyo 17192873Sweongyo#include <sys/cdefs.h> 18192873Sweongyo__FBSDID("$FreeBSD$"); 19192873Sweongyo#include <sys/param.h> 20192873Sweongyo#include <sys/sockio.h> 21192873Sweongyo#include <sys/sysctl.h> 22192873Sweongyo#include <sys/lock.h> 23192873Sweongyo#include <sys/mutex.h> 24192873Sweongyo#include <sys/mbuf.h> 25192873Sweongyo#include <sys/kernel.h> 26192873Sweongyo#include <sys/socket.h> 27192873Sweongyo#include <sys/systm.h> 28192873Sweongyo#include <sys/malloc.h> 29192873Sweongyo#include <sys/module.h> 30192873Sweongyo#include <sys/bus.h> 31192873Sweongyo#include <sys/endian.h> 32192873Sweongyo#include <sys/kdb.h> 33192873Sweongyo 34192873Sweongyo#include <machine/bus.h> 35192873Sweongyo#include <machine/resource.h> 36192873Sweongyo#include <sys/rman.h> 37192873Sweongyo 38192873Sweongyo#include <net/if.h> 39192873Sweongyo#include <net/if_arp.h> 40192873Sweongyo#include <net/ethernet.h> 41192873Sweongyo#include <net/if_dl.h> 42192873Sweongyo#include <net/if_media.h> 43192873Sweongyo#include <net/if_types.h> 44192873Sweongyo 45192873Sweongyo#ifdef INET 46192873Sweongyo#include <netinet/in.h> 47192873Sweongyo#include <netinet/in_systm.h> 48192873Sweongyo#include <netinet/in_var.h> 49192873Sweongyo#include <netinet/if_ether.h> 50192873Sweongyo#include <netinet/ip.h> 51192873Sweongyo#endif 52192873Sweongyo 53192873Sweongyo#include <net80211/ieee80211_var.h> 54192873Sweongyo#include <net80211/ieee80211_regdomain.h> 55192873Sweongyo#include <net80211/ieee80211_radiotap.h> 56192873Sweongyo 57192873Sweongyo#include <dev/usb/usb.h> 58194677Sthompsa#include <dev/usb/usbdi.h> 59192873Sweongyo#include "usbdevs.h" 60192873Sweongyo 61192873Sweongyo#include <dev/usb/wlan/if_urtwreg.h> 62192873Sweongyo#include <dev/usb/wlan/if_urtwvar.h> 63192873Sweongyo 64248085Smariusstatic SYSCTL_NODE(_hw_usb, OID_AUTO, urtw, CTLFLAG_RW, 0, "USB Realtek 8187L"); 65192873Sweongyo#ifdef URTW_DEBUG 66192873Sweongyoint urtw_debug = 0; 67242775ShselaskySYSCTL_INT(_hw_usb_urtw, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &urtw_debug, 0, 68192873Sweongyo "control debugging printfs"); 69192873SweongyoTUNABLE_INT("hw.usb.urtw.debug", &urtw_debug); 70192873Sweongyoenum { 71192873Sweongyo URTW_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ 72192873Sweongyo URTW_DEBUG_RECV = 0x00000002, /* basic recv operation */ 73192873Sweongyo URTW_DEBUG_RESET = 0x00000004, /* reset processing */ 74192873Sweongyo URTW_DEBUG_TX_PROC = 0x00000008, /* tx ISR proc */ 75192873Sweongyo URTW_DEBUG_RX_PROC = 0x00000010, /* rx ISR proc */ 76192873Sweongyo URTW_DEBUG_STATE = 0x00000020, /* 802.11 state transitions */ 77192873Sweongyo URTW_DEBUG_STAT = 0x00000040, /* statistic */ 78192873Sweongyo URTW_DEBUG_INIT = 0x00000080, /* initialization of dev */ 79198194Sweongyo URTW_DEBUG_TXSTATUS = 0x00000100, /* tx status */ 80192873Sweongyo URTW_DEBUG_ANY = 0xffffffff 81192873Sweongyo}; 82192873Sweongyo#define DPRINTF(sc, m, fmt, ...) do { \ 83192873Sweongyo if (sc->sc_debug & (m)) \ 84192873Sweongyo printf(fmt, __VA_ARGS__); \ 85192873Sweongyo} while (0) 86192873Sweongyo#else 87192873Sweongyo#define DPRINTF(sc, m, fmt, ...) do { \ 88192873Sweongyo (void) sc; \ 89192873Sweongyo} while (0) 90192873Sweongyo#endif 91194099Sthompsastatic int urtw_preamble_mode = URTW_PREAMBLE_MODE_LONG; 92242775ShselaskySYSCTL_INT(_hw_usb_urtw, OID_AUTO, preamble_mode, CTLFLAG_RW | CTLFLAG_TUN, 93192873Sweongyo &urtw_preamble_mode, 0, "set the preable mode (long or short)"); 94192873SweongyoTUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode); 95192873Sweongyo 96192873Sweongyo/* recognized device vendors/products */ 97192873Sweongyo#define urtw_lookup(v, p) \ 98192873Sweongyo ((const struct urtw_type *)usb_lookup(urtw_devs, v, p)) 99192873Sweongyo#define URTW_DEV_B(v,p) \ 100192873Sweongyo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187B) } 101192873Sweongyo#define URTW_DEV_L(v,p) \ 102192873Sweongyo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) } 103192873Sweongyo#define URTW_REV_RTL8187B 0 104192873Sweongyo#define URTW_REV_RTL8187L 1 105223486Shselaskystatic const STRUCT_USB_HOST_ID urtw_devs[] = { 106197761Sweongyo URTW_DEV_B(NETGEAR, WG111V3), 107197761Sweongyo URTW_DEV_B(REALTEK, RTL8187B_0), 108197761Sweongyo URTW_DEV_B(REALTEK, RTL8187B_1), 109197761Sweongyo URTW_DEV_B(REALTEK, RTL8187B_2), 110197761Sweongyo URTW_DEV_B(SITECOMEU, WL168V4), 111197761Sweongyo URTW_DEV_L(ASUS, P5B_WIFI), 112197761Sweongyo URTW_DEV_L(BELKIN, F5D7050E), 113197761Sweongyo URTW_DEV_L(LINKSYS4, WUSB54GCV2), 114197761Sweongyo URTW_DEV_L(NETGEAR, WG111V2), 115197761Sweongyo URTW_DEV_L(REALTEK, RTL8187), 116197761Sweongyo URTW_DEV_L(SITECOMEU, WL168V1), 117197761Sweongyo URTW_DEV_L(SURECOM, EP9001G2A), 118223446Sgavin { USB_VPI(USB_VENDOR_OVISLINK, 0x8187, URTW_REV_RTL8187L) }, 119192873Sweongyo { USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) }, 120192873Sweongyo { USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) }, 121192873Sweongyo { USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) }, 122192873Sweongyo { USB_VPI(USB_VENDOR_NETGEAR, 0x6100, URTW_REV_RTL8187L) }, 123192873Sweongyo { USB_VPI(USB_VENDOR_SPHAIRON, 0x0150, URTW_REV_RTL8187L) }, 124192873Sweongyo { USB_VPI(USB_VENDOR_QCOM, 0x6232, URTW_REV_RTL8187L) }, 125192873Sweongyo#undef URTW_DEV_L 126192873Sweongyo#undef URTW_DEV_B 127192873Sweongyo}; 128192873Sweongyo 129192873Sweongyo#define urtw_read8_m(sc, val, data) do { \ 130192873Sweongyo error = urtw_read8_c(sc, val, data); \ 131192873Sweongyo if (error != 0) \ 132192873Sweongyo goto fail; \ 133192873Sweongyo} while (0) 134192873Sweongyo#define urtw_write8_m(sc, val, data) do { \ 135192873Sweongyo error = urtw_write8_c(sc, val, data); \ 136192873Sweongyo if (error != 0) \ 137192873Sweongyo goto fail; \ 138192873Sweongyo} while (0) 139192873Sweongyo#define urtw_read16_m(sc, val, data) do { \ 140192873Sweongyo error = urtw_read16_c(sc, val, data); \ 141192873Sweongyo if (error != 0) \ 142192873Sweongyo goto fail; \ 143192873Sweongyo} while (0) 144192873Sweongyo#define urtw_write16_m(sc, val, data) do { \ 145192873Sweongyo error = urtw_write16_c(sc, val, data); \ 146192873Sweongyo if (error != 0) \ 147192873Sweongyo goto fail; \ 148192873Sweongyo} while (0) 149192873Sweongyo#define urtw_read32_m(sc, val, data) do { \ 150192873Sweongyo error = urtw_read32_c(sc, val, data); \ 151192873Sweongyo if (error != 0) \ 152192873Sweongyo goto fail; \ 153192873Sweongyo} while (0) 154192873Sweongyo#define urtw_write32_m(sc, val, data) do { \ 155192873Sweongyo error = urtw_write32_c(sc, val, data); \ 156192873Sweongyo if (error != 0) \ 157192873Sweongyo goto fail; \ 158192873Sweongyo} while (0) 159192873Sweongyo#define urtw_8187_write_phy_ofdm(sc, val, data) do { \ 160192873Sweongyo error = urtw_8187_write_phy_ofdm_c(sc, val, data); \ 161192873Sweongyo if (error != 0) \ 162192873Sweongyo goto fail; \ 163192873Sweongyo} while (0) 164192873Sweongyo#define urtw_8187_write_phy_cck(sc, val, data) do { \ 165192873Sweongyo error = urtw_8187_write_phy_cck_c(sc, val, data); \ 166192873Sweongyo if (error != 0) \ 167192873Sweongyo goto fail; \ 168192873Sweongyo} while (0) 169192873Sweongyo#define urtw_8225_write(sc, val, data) do { \ 170192873Sweongyo error = urtw_8225_write_c(sc, val, data); \ 171192873Sweongyo if (error != 0) \ 172192873Sweongyo goto fail; \ 173192873Sweongyo} while (0) 174192873Sweongyo 175192873Sweongyostruct urtw_pair { 176192873Sweongyo uint32_t reg; 177192873Sweongyo uint32_t val; 178192873Sweongyo}; 179192873Sweongyo 180192873Sweongyostatic uint8_t urtw_8225_agc[] = { 181192873Sweongyo 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b, 182192873Sweongyo 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 183192873Sweongyo 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 184192873Sweongyo 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 185192873Sweongyo 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 186192873Sweongyo 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 187192873Sweongyo 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 188192873Sweongyo 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 189192873Sweongyo 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 190192873Sweongyo 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 191192873Sweongyo 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 192192873Sweongyo 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 193192873Sweongyo}; 194192873Sweongyo 195196970Sphkstatic uint8_t urtw_8225z2_agc[] = { 196196970Sphk 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 197196970Sphk 0x4f, 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 198196970Sphk 0x39, 0x37, 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 199196970Sphk 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 200196970Sphk 0x0d, 0x0b, 0x09, 0x07, 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 201196970Sphk 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 202196970Sphk 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x20, 0x21, 0x22, 0x23, 203196970Sphk 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a, 204196970Sphk 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 205196970Sphk 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 206196970Sphk 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 207196970Sphk 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 208196970Sphk}; 209196970Sphk 210192873Sweongyostatic uint32_t urtw_8225_channel[] = { 211192873Sweongyo 0x0000, /* dummy channel 0 */ 212192873Sweongyo 0x085c, /* 1 */ 213192873Sweongyo 0x08dc, /* 2 */ 214192873Sweongyo 0x095c, /* 3 */ 215192873Sweongyo 0x09dc, /* 4 */ 216192873Sweongyo 0x0a5c, /* 5 */ 217192873Sweongyo 0x0adc, /* 6 */ 218192873Sweongyo 0x0b5c, /* 7 */ 219192873Sweongyo 0x0bdc, /* 8 */ 220192873Sweongyo 0x0c5c, /* 9 */ 221192873Sweongyo 0x0cdc, /* 10 */ 222192873Sweongyo 0x0d5c, /* 11 */ 223192873Sweongyo 0x0ddc, /* 12 */ 224192873Sweongyo 0x0e5c, /* 13 */ 225192873Sweongyo 0x0f72, /* 14 */ 226192873Sweongyo}; 227192873Sweongyo 228192873Sweongyostatic uint8_t urtw_8225_gain[] = { 229192873Sweongyo 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ 230192873Sweongyo 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ 231192873Sweongyo 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ 232192873Sweongyo 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ 233192873Sweongyo 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ 234192873Sweongyo 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ 235192873Sweongyo 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ 236192873Sweongyo}; 237192873Sweongyo 238192873Sweongyostatic struct urtw_pair urtw_8225_rf_part1[] = { 239192873Sweongyo { 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 240192873Sweongyo { 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a }, 241192873Sweongyo { 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 }, 242196970Sphk { 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 }, 243192873Sweongyo}; 244192873Sweongyo 245192873Sweongyostatic struct urtw_pair urtw_8225_rf_part2[] = { 246192873Sweongyo { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 }, 247192873Sweongyo { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 }, 248192873Sweongyo { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 }, 249192873Sweongyo { 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 }, 250192873Sweongyo { 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 }, 251192873Sweongyo { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef }, 252192873Sweongyo { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 }, 253192873Sweongyo { 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 }, 254192873Sweongyo { 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 }, 255192873Sweongyo { 0x27, 0x88 } 256192873Sweongyo}; 257192873Sweongyo 258192873Sweongyostatic struct urtw_pair urtw_8225_rf_part3[] = { 259192873Sweongyo { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 }, 260192873Sweongyo { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b }, 261192873Sweongyo { 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, 262192873Sweongyo { 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d }, 263192873Sweongyo { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e }, 264192873Sweongyo { 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a }, 265192873Sweongyo { 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 } 266192873Sweongyo}; 267192873Sweongyo 268192873Sweongyostatic uint16_t urtw_8225_rxgain[] = { 269192873Sweongyo 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, 270192873Sweongyo 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, 271192873Sweongyo 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, 272192873Sweongyo 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, 273192873Sweongyo 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, 274192873Sweongyo 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, 275192873Sweongyo 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, 276192873Sweongyo 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, 277192873Sweongyo 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, 278192873Sweongyo 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, 279192873Sweongyo 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, 280192873Sweongyo 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb 281192873Sweongyo}; 282192873Sweongyo 283192873Sweongyostatic uint8_t urtw_8225_threshold[] = { 284196970Sphk 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd, 285192873Sweongyo}; 286192873Sweongyo 287192873Sweongyostatic uint8_t urtw_8225_tx_gain_cck_ofdm[] = { 288192873Sweongyo 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e 289192873Sweongyo}; 290192873Sweongyo 291192873Sweongyostatic uint8_t urtw_8225_txpwr_cck[] = { 292192873Sweongyo 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, 293192873Sweongyo 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, 294192873Sweongyo 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, 295192873Sweongyo 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, 296192873Sweongyo 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, 297192873Sweongyo 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 298192873Sweongyo}; 299192873Sweongyo 300192873Sweongyostatic uint8_t urtw_8225_txpwr_cck_ch14[] = { 301192873Sweongyo 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 302192873Sweongyo 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 303192873Sweongyo 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, 304192873Sweongyo 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, 305192873Sweongyo 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 306192873Sweongyo 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 307192873Sweongyo}; 308192873Sweongyo 309196970Sphkstatic uint8_t urtw_8225_txpwr_ofdm[]={ 310192873Sweongyo 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 311192873Sweongyo}; 312192873Sweongyo 313192873Sweongyostatic uint8_t urtw_8225v2_gain_bg[]={ 314192873Sweongyo 0x23, 0x15, 0xa5, /* -82-1dbm */ 315192873Sweongyo 0x23, 0x15, 0xb5, /* -82-2dbm */ 316192873Sweongyo 0x23, 0x15, 0xc5, /* -82-3dbm */ 317192873Sweongyo 0x33, 0x15, 0xc5, /* -78dbm */ 318192873Sweongyo 0x43, 0x15, 0xc5, /* -74dbm */ 319192873Sweongyo 0x53, 0x15, 0xc5, /* -70dbm */ 320192873Sweongyo 0x63, 0x15, 0xc5, /* -66dbm */ 321192873Sweongyo}; 322192873Sweongyo 323192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part1[] = { 324192873Sweongyo { 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 325192873Sweongyo { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a }, 326192873Sweongyo { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb }, 327192873Sweongyo { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 } 328192873Sweongyo}; 329192873Sweongyo 330198194Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part0[] = { 331192873Sweongyo { 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 332192873Sweongyo { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a }, 333192873Sweongyo { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb }, 334192873Sweongyo { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 } 335192873Sweongyo}; 336192873Sweongyo 337198194Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part1[] = { 338198194Sweongyo {0x0f0, 0x32}, {0x0f1, 0x32}, {0x0f2, 0x00}, 339198194Sweongyo {0x0f3, 0x00}, {0x0f4, 0x32}, {0x0f5, 0x43}, 340198194Sweongyo {0x0f6, 0x00}, {0x0f7, 0x00}, {0x0f8, 0x46}, 341198194Sweongyo {0x0f9, 0xa4}, {0x0fa, 0x00}, {0x0fb, 0x00}, 342198194Sweongyo {0x0fc, 0x96}, {0x0fd, 0xa4}, {0x0fe, 0x00}, 343198194Sweongyo {0x0ff, 0x00}, {0x158, 0x4b}, {0x159, 0x00}, 344198194Sweongyo {0x15a, 0x4b}, {0x15b, 0x00}, {0x160, 0x4b}, 345198194Sweongyo {0x161, 0x09}, {0x162, 0x4b}, {0x163, 0x09}, 346198194Sweongyo {0x1ce, 0x0f}, {0x1cf, 0x00}, {0x1e0, 0xff}, 347198194Sweongyo {0x1e1, 0x0f}, {0x1e2, 0x00}, {0x1f0, 0x4e}, 348198194Sweongyo {0x1f1, 0x01}, {0x1f2, 0x02}, {0x1f3, 0x03}, 349198194Sweongyo {0x1f4, 0x04}, {0x1f5, 0x05}, {0x1f6, 0x06}, 350198194Sweongyo {0x1f7, 0x07}, {0x1f8, 0x08}, {0x24e, 0x00}, 351198194Sweongyo {0x20c, 0x04}, {0x221, 0x61}, {0x222, 0x68}, 352198194Sweongyo {0x223, 0x6f}, {0x224, 0x76}, {0x225, 0x7d}, 353198194Sweongyo {0x226, 0x84}, {0x227, 0x8d}, {0x24d, 0x08}, 354198194Sweongyo {0x250, 0x05}, {0x251, 0xf5}, {0x252, 0x04}, 355198194Sweongyo {0x253, 0xa0}, {0x254, 0x1f}, {0x255, 0x23}, 356198194Sweongyo {0x256, 0x45}, {0x257, 0x67}, {0x258, 0x08}, 357198194Sweongyo {0x259, 0x08}, {0x25a, 0x08}, {0x25b, 0x08}, 358198194Sweongyo {0x260, 0x08}, {0x261, 0x08}, {0x262, 0x08}, 359198194Sweongyo {0x263, 0x08}, {0x264, 0xcf}, {0x272, 0x56}, 360198194Sweongyo {0x273, 0x9a}, {0x034, 0xf0}, {0x035, 0x0f}, 361198194Sweongyo {0x05b, 0x40}, {0x084, 0x88}, {0x085, 0x24}, 362198194Sweongyo {0x088, 0x54}, {0x08b, 0xb8}, {0x08c, 0x07}, 363198194Sweongyo {0x08d, 0x00}, {0x094, 0x1b}, {0x095, 0x12}, 364198194Sweongyo {0x096, 0x00}, {0x097, 0x06}, {0x09d, 0x1a}, 365198194Sweongyo {0x09f, 0x10}, {0x0b4, 0x22}, {0x0be, 0x80}, 366198194Sweongyo {0x0db, 0x00}, {0x0ee, 0x00}, {0x091, 0x03}, 367198194Sweongyo {0x24c, 0x00}, {0x39f, 0x00}, {0x08c, 0x01}, 368198194Sweongyo {0x08d, 0x10}, {0x08e, 0x08}, {0x08f, 0x00} 369198194Sweongyo}; 370198194Sweongyo 371192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part2[] = { 372192873Sweongyo { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 }, 373192873Sweongyo { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 }, 374192873Sweongyo { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 }, 375192873Sweongyo { 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, 376192873Sweongyo { 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 }, 377192873Sweongyo { 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, 378192873Sweongyo { 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 }, 379192873Sweongyo { 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 }, 380192873Sweongyo { 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 }, 381192873Sweongyo { 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 } 382192873Sweongyo}; 383192873Sweongyo 384192873Sweongyostatic struct urtw_pair urtw_8225v2b_rf_part2[] = { 385192873Sweongyo { 0x00, 0x10 }, { 0x01, 0x0d }, { 0x02, 0x01 }, { 0x03, 0x00 }, 386192873Sweongyo { 0x04, 0x14 }, { 0x05, 0xfb }, { 0x06, 0xfb }, { 0x07, 0x60 }, 387192873Sweongyo { 0x08, 0x00 }, { 0x09, 0x60 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, 388192873Sweongyo { 0x0c, 0x00 }, { 0x0d, 0x5c }, { 0x0e, 0x00 }, { 0x0f, 0x00 }, 389192873Sweongyo { 0x10, 0x40 }, { 0x11, 0x00 }, { 0x12, 0x40 }, { 0x13, 0x00 }, 390192873Sweongyo { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0xa8 }, { 0x17, 0x26 }, 391192873Sweongyo { 0x18, 0x32 }, { 0x19, 0x33 }, { 0x1a, 0x07 }, { 0x1b, 0xa5 }, 392192873Sweongyo { 0x1c, 0x6f }, { 0x1d, 0x55 }, { 0x1e, 0xc8 }, { 0x1f, 0xb3 }, 393192873Sweongyo { 0x20, 0x0a }, { 0x21, 0xe1 }, { 0x22, 0x2C }, { 0x23, 0x8a }, 394192873Sweongyo { 0x24, 0x86 }, { 0x25, 0x83 }, { 0x26, 0x34 }, { 0x27, 0x0f }, 395192873Sweongyo { 0x28, 0x4f }, { 0x29, 0x24 }, { 0x2a, 0x6f }, { 0x2b, 0xc2 }, 396192873Sweongyo { 0x2c, 0x6b }, { 0x2d, 0x40 }, { 0x2e, 0x80 }, { 0x2f, 0x00 }, 397192873Sweongyo { 0x30, 0xc0 }, { 0x31, 0xc1 }, { 0x32, 0x58 }, { 0x33, 0xf1 }, 398192873Sweongyo { 0x34, 0x00 }, { 0x35, 0xe4 }, { 0x36, 0x90 }, { 0x37, 0x3e }, 399192873Sweongyo { 0x38, 0x6d }, { 0x39, 0x3c }, { 0x3a, 0xfb }, { 0x3b, 0x07 } 400192873Sweongyo}; 401192873Sweongyo 402192873Sweongyostatic struct urtw_pair urtw_8225v2_rf_part3[] = { 403192873Sweongyo { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 }, 404192873Sweongyo { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 }, 405192873Sweongyo { 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 }, 406192873Sweongyo { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 }, 407192873Sweongyo { 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d }, 408192873Sweongyo { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 }, 409192873Sweongyo { 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 }, 410192873Sweongyo { 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 } 411192873Sweongyo}; 412192873Sweongyo 413192873Sweongyostatic uint16_t urtw_8225v2_rxgain[] = { 414192873Sweongyo 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, 415192873Sweongyo 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, 416192873Sweongyo 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, 417192873Sweongyo 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, 418192873Sweongyo 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, 419192873Sweongyo 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, 420192873Sweongyo 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, 421192873Sweongyo 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, 422192873Sweongyo 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 423192873Sweongyo 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, 424192873Sweongyo 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 425192873Sweongyo 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb 426192873Sweongyo}; 427192873Sweongyo 428192873Sweongyostatic uint16_t urtw_8225v2b_rxgain[] = { 429192873Sweongyo 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, 430192873Sweongyo 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, 431192873Sweongyo 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, 432192873Sweongyo 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, 433192873Sweongyo 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, 434192873Sweongyo 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, 435192873Sweongyo 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, 436192873Sweongyo 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, 437192873Sweongyo 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, 438192873Sweongyo 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, 439192873Sweongyo 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 440192873Sweongyo 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb 441192873Sweongyo}; 442192873Sweongyo 443192873Sweongyostatic uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = { 444192873Sweongyo 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 445192873Sweongyo 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 446192873Sweongyo 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 447192873Sweongyo 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 448192873Sweongyo 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 449196970Sphk 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 450192873Sweongyo}; 451192873Sweongyo 452196970Sphkstatic uint8_t urtw_8225v2_txpwr_cck[] = { 453196970Sphk 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 454196970Sphk}; 455196970Sphk 456192873Sweongyostatic uint8_t urtw_8225v2_txpwr_cck_ch14[] = { 457192873Sweongyo 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 458192873Sweongyo}; 459192873Sweongyo 460192873Sweongyostatic uint8_t urtw_8225v2b_txpwr_cck[] = { 461192873Sweongyo 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, 462192873Sweongyo 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, 463192873Sweongyo 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, 464192873Sweongyo 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 465192873Sweongyo}; 466192873Sweongyo 467192873Sweongyostatic uint8_t urtw_8225v2b_txpwr_cck_ch14[] = { 468192873Sweongyo 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, 469192873Sweongyo 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, 470192873Sweongyo 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, 471192873Sweongyo 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 472192873Sweongyo}; 473192873Sweongyo 474192873Sweongyostatic struct urtw_pair urtw_ratetable[] = { 475192873Sweongyo { 2, 0 }, { 4, 1 }, { 11, 2 }, { 12, 4 }, { 18, 5 }, 476192873Sweongyo { 22, 3 }, { 24, 6 }, { 36, 7 }, { 48, 8 }, { 72, 9 }, 477192873Sweongyo { 96, 10 }, { 108, 11 } 478192873Sweongyo}; 479192873Sweongyo 480260284Sdim#if 0 481196970Sphkstatic const uint8_t urtw_8187b_reg_table[][3] = { 482196970Sphk { 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 }, 483196970Sphk { 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 }, 484196970Sphk { 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 }, 485196970Sphk { 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 }, 486196970Sphk { 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 }, 487196970Sphk { 0xff, 0x00, 0 }, { 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 }, 488196970Sphk { 0x5a, 0x4b, 1 }, { 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 }, 489196970Sphk { 0x61, 0x09, 1 }, { 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 }, 490196970Sphk { 0xce, 0x0f, 1 }, { 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 }, 491196970Sphk { 0xe1, 0x0f, 1 }, { 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 }, 492196970Sphk { 0xf1, 0x01, 1 }, { 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 }, 493196970Sphk { 0xf4, 0x04, 1 }, { 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 }, 494196970Sphk { 0xf7, 0x07, 1 }, { 0xf8, 0x08, 1 }, { 0x4e, 0x00, 2 }, 495196970Sphk { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 }, { 0x22, 0x68, 2 }, 496196970Sphk { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 }, { 0x25, 0x7d, 2 }, 497196970Sphk { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 }, { 0x4d, 0x08, 2 }, 498196970Sphk { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 }, { 0x52, 0x04, 2 }, 499196970Sphk { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 }, { 0x55, 0x23, 2 }, 500196970Sphk { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 }, { 0x58, 0x08, 2 }, 501196970Sphk { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 }, { 0x5b, 0x08, 2 }, 502196970Sphk { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 }, { 0x62, 0x08, 2 }, 503196970Sphk { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 }, { 0x72, 0x56, 2 }, 504196970Sphk { 0x73, 0x9a, 2 }, { 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 }, 505196970Sphk { 0x5b, 0x40, 0 }, { 0x84, 0x88, 0 }, { 0x85, 0x24, 0 }, 506196970Sphk { 0x88, 0x54, 0 }, { 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 }, 507196970Sphk { 0x8d, 0x00, 0 }, { 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 }, 508196970Sphk { 0x96, 0x00, 0 }, { 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 }, 509196970Sphk { 0x9f, 0x10, 0 }, { 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 }, 510196970Sphk { 0xdb, 0x00, 0 }, { 0xee, 0x00, 0 }, { 0x91, 0x03, 0 }, 511196970Sphk { 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 }, 512196970Sphk { 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 } 513196970Sphk}; 514260284Sdim#endif 515196970Sphk 516193045Sthompsastatic usb_callback_t urtw_bulk_rx_callback; 517193045Sthompsastatic usb_callback_t urtw_bulk_tx_callback; 518198194Sweongyostatic usb_callback_t urtw_bulk_tx_status_callback; 519192873Sweongyo 520192984Sthompsastatic const struct usb_config urtw_8187b_usbconfig[URTW_8187B_N_XFERS] = { 521192873Sweongyo [URTW_8187B_BULK_RX] = { 522192873Sweongyo .type = UE_BULK, 523192873Sweongyo .endpoint = 0x83, 524192873Sweongyo .direction = UE_DIR_IN, 525192873Sweongyo .bufsize = MCLBYTES, 526192873Sweongyo .flags = { 527192873Sweongyo .ext_buffer = 1, 528192873Sweongyo .pipe_bof = 1, 529192873Sweongyo .short_xfer_ok = 1 530192873Sweongyo }, 531192873Sweongyo .callback = urtw_bulk_rx_callback 532192873Sweongyo }, 533198194Sweongyo [URTW_8187B_BULK_TX_STATUS] = { 534198194Sweongyo .type = UE_BULK, 535198194Sweongyo .endpoint = 0x89, 536198194Sweongyo .direction = UE_DIR_IN, 537259454Shselasky .bufsize = sizeof(uint64_t), 538198194Sweongyo .flags = { 539198194Sweongyo .pipe_bof = 1, 540198194Sweongyo .short_xfer_ok = 1 541198194Sweongyo }, 542198194Sweongyo .callback = urtw_bulk_tx_status_callback 543198194Sweongyo }, 544192873Sweongyo [URTW_8187B_BULK_TX_BE] = { 545192873Sweongyo .type = UE_BULK, 546192873Sweongyo .endpoint = URTW_8187B_TXPIPE_BE, 547192873Sweongyo .direction = UE_DIR_OUT, 548259454Shselasky .bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT, 549192873Sweongyo .flags = { 550192873Sweongyo .force_short_xfer = 1, 551192873Sweongyo .pipe_bof = 1, 552192873Sweongyo }, 553192873Sweongyo .callback = urtw_bulk_tx_callback, 554192873Sweongyo .timeout = URTW_DATA_TIMEOUT 555192873Sweongyo }, 556192873Sweongyo [URTW_8187B_BULK_TX_BK] = { 557192873Sweongyo .type = UE_BULK, 558192873Sweongyo .endpoint = URTW_8187B_TXPIPE_BK, 559192873Sweongyo .direction = UE_DIR_OUT, 560192873Sweongyo .bufsize = URTW_TX_MAXSIZE, 561192873Sweongyo .flags = { 562192873Sweongyo .ext_buffer = 1, 563192873Sweongyo .force_short_xfer = 1, 564192873Sweongyo .pipe_bof = 1, 565192873Sweongyo }, 566192873Sweongyo .callback = urtw_bulk_tx_callback, 567192873Sweongyo .timeout = URTW_DATA_TIMEOUT 568192873Sweongyo }, 569192873Sweongyo [URTW_8187B_BULK_TX_VI] = { 570192873Sweongyo .type = UE_BULK, 571192873Sweongyo .endpoint = URTW_8187B_TXPIPE_VI, 572192873Sweongyo .direction = UE_DIR_OUT, 573192873Sweongyo .bufsize = URTW_TX_MAXSIZE, 574192873Sweongyo .flags = { 575192873Sweongyo .ext_buffer = 1, 576192873Sweongyo .force_short_xfer = 1, 577192873Sweongyo .pipe_bof = 1, 578192873Sweongyo }, 579192873Sweongyo .callback = urtw_bulk_tx_callback, 580192873Sweongyo .timeout = URTW_DATA_TIMEOUT 581192873Sweongyo }, 582192873Sweongyo [URTW_8187B_BULK_TX_VO] = { 583192873Sweongyo .type = UE_BULK, 584192873Sweongyo .endpoint = URTW_8187B_TXPIPE_VO, 585192873Sweongyo .direction = UE_DIR_OUT, 586192873Sweongyo .bufsize = URTW_TX_MAXSIZE, 587192873Sweongyo .flags = { 588192873Sweongyo .ext_buffer = 1, 589192873Sweongyo .force_short_xfer = 1, 590192873Sweongyo .pipe_bof = 1, 591192873Sweongyo }, 592192873Sweongyo .callback = urtw_bulk_tx_callback, 593192873Sweongyo .timeout = URTW_DATA_TIMEOUT 594192873Sweongyo }, 595192873Sweongyo [URTW_8187B_BULK_TX_EP12] = { 596192873Sweongyo .type = UE_BULK, 597192873Sweongyo .endpoint = 0xc, 598192873Sweongyo .direction = UE_DIR_OUT, 599192873Sweongyo .bufsize = URTW_TX_MAXSIZE, 600192873Sweongyo .flags = { 601192873Sweongyo .ext_buffer = 1, 602192873Sweongyo .force_short_xfer = 1, 603192873Sweongyo .pipe_bof = 1, 604192873Sweongyo }, 605192873Sweongyo .callback = urtw_bulk_tx_callback, 606192873Sweongyo .timeout = URTW_DATA_TIMEOUT 607192873Sweongyo } 608192873Sweongyo}; 609192873Sweongyo 610192984Sthompsastatic const struct usb_config urtw_8187l_usbconfig[URTW_8187L_N_XFERS] = { 611192873Sweongyo [URTW_8187L_BULK_RX] = { 612192873Sweongyo .type = UE_BULK, 613192873Sweongyo .endpoint = 0x81, 614192873Sweongyo .direction = UE_DIR_IN, 615192873Sweongyo .bufsize = MCLBYTES, 616192873Sweongyo .flags = { 617192873Sweongyo .ext_buffer = 1, 618192873Sweongyo .pipe_bof = 1, 619192873Sweongyo .short_xfer_ok = 1 620192873Sweongyo }, 621192873Sweongyo .callback = urtw_bulk_rx_callback 622192873Sweongyo }, 623192873Sweongyo [URTW_8187L_BULK_TX_LOW] = { 624192873Sweongyo .type = UE_BULK, 625192873Sweongyo .endpoint = 0x2, 626192873Sweongyo .direction = UE_DIR_OUT, 627259454Shselasky .bufsize = URTW_TX_MAXSIZE * URTW_TX_DATA_LIST_COUNT, 628192873Sweongyo .flags = { 629192873Sweongyo .force_short_xfer = 1, 630192873Sweongyo .pipe_bof = 1, 631192873Sweongyo }, 632192873Sweongyo .callback = urtw_bulk_tx_callback, 633192873Sweongyo .timeout = URTW_DATA_TIMEOUT 634192873Sweongyo }, 635192873Sweongyo [URTW_8187L_BULK_TX_NORMAL] = { 636192873Sweongyo .type = UE_BULK, 637192873Sweongyo .endpoint = 0x3, 638192873Sweongyo .direction = UE_DIR_OUT, 639192873Sweongyo .bufsize = URTW_TX_MAXSIZE, 640192873Sweongyo .flags = { 641192873Sweongyo .ext_buffer = 1, 642192873Sweongyo .force_short_xfer = 1, 643192873Sweongyo .pipe_bof = 1, 644192873Sweongyo }, 645192873Sweongyo .callback = urtw_bulk_tx_callback, 646192873Sweongyo .timeout = URTW_DATA_TIMEOUT 647192873Sweongyo }, 648192873Sweongyo}; 649192873Sweongyo 650192873Sweongyostatic struct ieee80211vap *urtw_vap_create(struct ieee80211com *, 651234753Sdim const char [IFNAMSIZ], int, enum ieee80211_opmode, 652234753Sdim int, const uint8_t [IEEE80211_ADDR_LEN], 653234753Sdim const uint8_t [IEEE80211_ADDR_LEN]); 654192873Sweongyostatic void urtw_vap_delete(struct ieee80211vap *); 655192873Sweongyostatic void urtw_init(void *); 656259456Shselaskystatic void urtw_stop(struct ifnet *); 657259456Shselaskystatic void urtw_stop_locked(struct ifnet *); 658192873Sweongyostatic int urtw_ioctl(struct ifnet *, u_long, caddr_t); 659192873Sweongyostatic void urtw_start(struct ifnet *); 660192873Sweongyostatic int urtw_alloc_rx_data_list(struct urtw_softc *); 661192873Sweongyostatic int urtw_alloc_tx_data_list(struct urtw_softc *); 662192873Sweongyostatic int urtw_raw_xmit(struct ieee80211_node *, struct mbuf *, 663192873Sweongyo const struct ieee80211_bpf_params *); 664192873Sweongyostatic void urtw_scan_start(struct ieee80211com *); 665192873Sweongyostatic void urtw_scan_end(struct ieee80211com *); 666192873Sweongyostatic void urtw_set_channel(struct ieee80211com *); 667192873Sweongyostatic void urtw_update_mcast(struct ifnet *); 668192873Sweongyostatic int urtw_tx_start(struct urtw_softc *, 669192873Sweongyo struct ieee80211_node *, struct mbuf *, 670192873Sweongyo struct urtw_data *, int); 671192873Sweongyostatic int urtw_newstate(struct ieee80211vap *, 672192873Sweongyo enum ieee80211_state, int); 673192873Sweongyostatic void urtw_led_ch(void *); 674192873Sweongyostatic void urtw_ledtask(void *, int); 675192873Sweongyostatic void urtw_watchdog(void *); 676192873Sweongyostatic void urtw_set_multi(void *); 677192873Sweongyostatic int urtw_isbmode(uint16_t); 678235000Shselaskystatic uint16_t urtw_rate2rtl(uint32_t); 679235000Shselaskystatic uint16_t urtw_rtl2rate(uint32_t); 680193045Sthompsastatic usb_error_t urtw_set_rate(struct urtw_softc *); 681193045Sthompsastatic usb_error_t urtw_update_msr(struct urtw_softc *); 682193045Sthompsastatic usb_error_t urtw_read8_c(struct urtw_softc *, int, uint8_t *); 683193045Sthompsastatic usb_error_t urtw_read16_c(struct urtw_softc *, int, uint16_t *); 684193045Sthompsastatic usb_error_t urtw_read32_c(struct urtw_softc *, int, uint32_t *); 685193045Sthompsastatic usb_error_t urtw_write8_c(struct urtw_softc *, int, uint8_t); 686193045Sthompsastatic usb_error_t urtw_write16_c(struct urtw_softc *, int, uint16_t); 687193045Sthompsastatic usb_error_t urtw_write32_c(struct urtw_softc *, int, uint32_t); 688193045Sthompsastatic usb_error_t urtw_eprom_cs(struct urtw_softc *, int); 689193045Sthompsastatic usb_error_t urtw_eprom_ck(struct urtw_softc *); 690193045Sthompsastatic usb_error_t urtw_eprom_sendbits(struct urtw_softc *, int16_t *, 691192873Sweongyo int); 692193045Sthompsastatic usb_error_t urtw_eprom_read32(struct urtw_softc *, uint32_t, 693192873Sweongyo uint32_t *); 694193045Sthompsastatic usb_error_t urtw_eprom_readbit(struct urtw_softc *, int16_t *); 695193045Sthompsastatic usb_error_t urtw_eprom_writebit(struct urtw_softc *, int16_t); 696193045Sthompsastatic usb_error_t urtw_get_macaddr(struct urtw_softc *); 697193045Sthompsastatic usb_error_t urtw_get_txpwr(struct urtw_softc *); 698193045Sthompsastatic usb_error_t urtw_get_rfchip(struct urtw_softc *); 699193045Sthompsastatic usb_error_t urtw_led_init(struct urtw_softc *); 700193045Sthompsastatic usb_error_t urtw_8185_rf_pins_enable(struct urtw_softc *); 701193045Sthompsastatic usb_error_t urtw_8185_tx_antenna(struct urtw_softc *, uint8_t); 702193045Sthompsastatic usb_error_t urtw_8187_write_phy(struct urtw_softc *, uint8_t, 703192873Sweongyo uint32_t); 704193045Sthompsastatic usb_error_t urtw_8187_write_phy_ofdm_c(struct urtw_softc *, 705192873Sweongyo uint8_t, uint32_t); 706193045Sthompsastatic usb_error_t urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t, 707192873Sweongyo uint32_t); 708193045Sthompsastatic usb_error_t urtw_8225_setgain(struct urtw_softc *, int16_t); 709193045Sthompsastatic usb_error_t urtw_8225_usb_init(struct urtw_softc *); 710193045Sthompsastatic usb_error_t urtw_8225_write_c(struct urtw_softc *, uint8_t, 711192873Sweongyo uint16_t); 712193045Sthompsastatic usb_error_t urtw_8225_write_s16(struct urtw_softc *, uint8_t, int, 713192873Sweongyo uint16_t *); 714193045Sthompsastatic usb_error_t urtw_8225_read(struct urtw_softc *, uint8_t, 715192873Sweongyo uint32_t *); 716193045Sthompsastatic usb_error_t urtw_8225_rf_init(struct urtw_softc *); 717193045Sthompsastatic usb_error_t urtw_8225_rf_set_chan(struct urtw_softc *, int); 718193045Sthompsastatic usb_error_t urtw_8225_rf_set_sens(struct urtw_softc *, int); 719193045Sthompsastatic usb_error_t urtw_8225_set_txpwrlvl(struct urtw_softc *, int); 720193045Sthompsastatic usb_error_t urtw_8225_rf_stop(struct urtw_softc *); 721193045Sthompsastatic usb_error_t urtw_8225v2_rf_init(struct urtw_softc *); 722193045Sthompsastatic usb_error_t urtw_8225v2_rf_set_chan(struct urtw_softc *, int); 723193045Sthompsastatic usb_error_t urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int); 724193045Sthompsastatic usb_error_t urtw_8225v2_setgain(struct urtw_softc *, int16_t); 725193045Sthompsastatic usb_error_t urtw_8225_isv2(struct urtw_softc *, int *); 726193045Sthompsastatic usb_error_t urtw_8225v2b_rf_init(struct urtw_softc *); 727193045Sthompsastatic usb_error_t urtw_8225v2b_rf_set_chan(struct urtw_softc *, int); 728193045Sthompsastatic usb_error_t urtw_read8e(struct urtw_softc *, int, uint8_t *); 729193045Sthompsastatic usb_error_t urtw_write8e(struct urtw_softc *, int, uint8_t); 730193045Sthompsastatic usb_error_t urtw_8180_set_anaparam(struct urtw_softc *, uint32_t); 731193045Sthompsastatic usb_error_t urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t); 732193045Sthompsastatic usb_error_t urtw_intr_enable(struct urtw_softc *); 733193045Sthompsastatic usb_error_t urtw_intr_disable(struct urtw_softc *); 734193045Sthompsastatic usb_error_t urtw_reset(struct urtw_softc *); 735193045Sthompsastatic usb_error_t urtw_led_on(struct urtw_softc *, int); 736193045Sthompsastatic usb_error_t urtw_led_ctl(struct urtw_softc *, int); 737193045Sthompsastatic usb_error_t urtw_led_blink(struct urtw_softc *); 738193045Sthompsastatic usb_error_t urtw_led_mode0(struct urtw_softc *, int); 739193045Sthompsastatic usb_error_t urtw_led_mode1(struct urtw_softc *, int); 740193045Sthompsastatic usb_error_t urtw_led_mode2(struct urtw_softc *, int); 741193045Sthompsastatic usb_error_t urtw_led_mode3(struct urtw_softc *, int); 742193045Sthompsastatic usb_error_t urtw_rx_setconf(struct urtw_softc *); 743193045Sthompsastatic usb_error_t urtw_rx_enable(struct urtw_softc *); 744193045Sthompsastatic usb_error_t urtw_tx_enable(struct urtw_softc *sc); 745192873Sweongyostatic void urtw_free_tx_data_list(struct urtw_softc *); 746192873Sweongyostatic void urtw_free_rx_data_list(struct urtw_softc *); 747192873Sweongyostatic void urtw_free_data_list(struct urtw_softc *, 748192873Sweongyo struct urtw_data data[], int, int); 749193045Sthompsastatic usb_error_t urtw_adapter_start(struct urtw_softc *); 750193045Sthompsastatic usb_error_t urtw_adapter_start_b(struct urtw_softc *); 751193045Sthompsastatic usb_error_t urtw_set_mode(struct urtw_softc *, uint32_t); 752193045Sthompsastatic usb_error_t urtw_8187b_cmd_reset(struct urtw_softc *); 753193045Sthompsastatic usb_error_t urtw_do_request(struct urtw_softc *, 754192984Sthompsa struct usb_device_request *, void *); 755193045Sthompsastatic usb_error_t urtw_8225v2b_set_txpwrlvl(struct urtw_softc *, int); 756193045Sthompsastatic usb_error_t urtw_led_off(struct urtw_softc *, int); 757192873Sweongyostatic void urtw_abort_xfers(struct urtw_softc *); 758192873Sweongyostatic struct urtw_data * 759192873Sweongyo urtw_getbuf(struct urtw_softc *sc); 760198194Sweongyostatic int urtw_compute_txtime(uint16_t, uint16_t, uint8_t, 761198194Sweongyo uint8_t); 762198194Sweongyostatic void urtw_updateslot(struct ifnet *); 763198194Sweongyostatic void urtw_updateslottask(void *, int); 764203087Sweongyostatic void urtw_sysctl_node(struct urtw_softc *); 765192873Sweongyo 766192873Sweongyostatic int 767192873Sweongyourtw_match(device_t dev) 768192873Sweongyo{ 769192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 770192873Sweongyo 771192873Sweongyo if (uaa->usb_mode != USB_MODE_HOST) 772192873Sweongyo return (ENXIO); 773192873Sweongyo if (uaa->info.bConfigIndex != URTW_CONFIG_INDEX) 774192873Sweongyo return (ENXIO); 775192873Sweongyo if (uaa->info.bIfaceIndex != URTW_IFACE_INDEX) 776192873Sweongyo return (ENXIO); 777192873Sweongyo 778194228Sthompsa return (usbd_lookup_id_by_uaa(urtw_devs, sizeof(urtw_devs), uaa)); 779192873Sweongyo} 780192873Sweongyo 781192873Sweongyostatic int 782192873Sweongyourtw_attach(device_t dev) 783192873Sweongyo{ 784192984Sthompsa const struct usb_config *setup_start; 785192873Sweongyo int ret = ENXIO; 786192873Sweongyo struct urtw_softc *sc = device_get_softc(dev); 787192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 788192873Sweongyo struct ieee80211com *ic; 789192873Sweongyo struct ifnet *ifp; 790192873Sweongyo uint8_t bands, iface_index = URTW_IFACE_INDEX; /* XXX */ 791192873Sweongyo uint16_t n_setup; 792192873Sweongyo uint32_t data; 793193045Sthompsa usb_error_t error; 794192873Sweongyo 795194228Sthompsa device_set_usb_desc(dev); 796192873Sweongyo 797192873Sweongyo sc->sc_dev = dev; 798192873Sweongyo sc->sc_udev = uaa->device; 799192873Sweongyo if (USB_GET_DRIVER_INFO(uaa) == URTW_REV_RTL8187B) 800192873Sweongyo sc->sc_flags |= URTW_RTL8187B; 801192873Sweongyo#ifdef URTW_DEBUG 802192873Sweongyo sc->sc_debug = urtw_debug; 803192873Sweongyo#endif 804192873Sweongyo 805192873Sweongyo mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, 806192873Sweongyo MTX_DEF); 807194228Sthompsa usb_callout_init_mtx(&sc->sc_led_ch, &sc->sc_mtx, 0); 808192873Sweongyo TASK_INIT(&sc->sc_led_task, 0, urtw_ledtask, sc); 809198194Sweongyo TASK_INIT(&sc->sc_updateslot_task, 0, urtw_updateslottask, sc); 810192873Sweongyo callout_init(&sc->sc_watchdog_ch, 0); 811192873Sweongyo 812192873Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 813192873Sweongyo setup_start = urtw_8187b_usbconfig; 814192873Sweongyo n_setup = URTW_8187B_N_XFERS; 815192873Sweongyo } else { 816192873Sweongyo setup_start = urtw_8187l_usbconfig; 817192873Sweongyo n_setup = URTW_8187L_N_XFERS; 818192873Sweongyo } 819192873Sweongyo 820194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 821192873Sweongyo setup_start, n_setup, sc, &sc->sc_mtx); 822192873Sweongyo if (error) { 823192873Sweongyo device_printf(dev, "could not allocate USB transfers, " 824194228Sthompsa "err=%s\n", usbd_errstr(error)); 825192873Sweongyo ret = ENXIO; 826192873Sweongyo goto fail0; 827192873Sweongyo } 828192873Sweongyo 829259454Shselasky if (sc->sc_flags & URTW_RTL8187B) { 830259454Shselasky sc->sc_tx_dma_buf = 831259454Shselasky usbd_xfer_get_frame_buffer(sc->sc_xfer[ 832259454Shselasky URTW_8187B_BULK_TX_BE], 0); 833259454Shselasky } else { 834259454Shselasky sc->sc_tx_dma_buf = 835259454Shselasky usbd_xfer_get_frame_buffer(sc->sc_xfer[ 836259454Shselasky URTW_8187L_BULK_TX_LOW], 0); 837259454Shselasky } 838259454Shselasky 839192873Sweongyo URTW_LOCK(sc); 840192873Sweongyo 841192873Sweongyo urtw_read32_m(sc, URTW_RX, &data); 842192873Sweongyo sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 : 843192873Sweongyo URTW_EEPROM_93C46; 844192873Sweongyo 845192873Sweongyo error = urtw_get_rfchip(sc); 846192873Sweongyo if (error != 0) 847192873Sweongyo goto fail; 848192873Sweongyo error = urtw_get_macaddr(sc); 849192873Sweongyo if (error != 0) 850192873Sweongyo goto fail; 851192873Sweongyo error = urtw_get_txpwr(sc); 852192873Sweongyo if (error != 0) 853192873Sweongyo goto fail; 854192873Sweongyo error = urtw_led_init(sc); 855192873Sweongyo if (error != 0) 856192873Sweongyo goto fail; 857192873Sweongyo 858192873Sweongyo URTW_UNLOCK(sc); 859192873Sweongyo 860192873Sweongyo sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY; 861192873Sweongyo sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY; 862192873Sweongyo sc->sc_currate = 3; 863192873Sweongyo sc->sc_preamble_mode = urtw_preamble_mode; 864192873Sweongyo 865192873Sweongyo ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 866192873Sweongyo if (ifp == NULL) { 867192873Sweongyo device_printf(sc->sc_dev, "can not allocate ifnet\n"); 868192873Sweongyo ret = ENOMEM; 869192873Sweongyo goto fail1; 870192873Sweongyo } 871192873Sweongyo 872192873Sweongyo ifp->if_softc = sc; 873192873Sweongyo if_initname(ifp, "urtw", device_get_unit(sc->sc_dev)); 874192873Sweongyo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 875192873Sweongyo ifp->if_init = urtw_init; 876192873Sweongyo ifp->if_ioctl = urtw_ioctl; 877192873Sweongyo ifp->if_start = urtw_start; 878192873Sweongyo /* XXX URTW_TX_DATA_LIST_COUNT */ 879207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 880207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 881192873Sweongyo IFQ_SET_READY(&ifp->if_snd); 882192873Sweongyo 883192873Sweongyo ic = ifp->if_l2com; 884192873Sweongyo ic->ic_ifp = ifp; 885192873Sweongyo ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 886192873Sweongyo ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 887192873Sweongyo 888192873Sweongyo /* set device capabilities */ 889192873Sweongyo ic->ic_caps = 890192873Sweongyo IEEE80211_C_STA | /* station mode */ 891192873Sweongyo IEEE80211_C_MONITOR | /* monitor mode supported */ 892192873Sweongyo IEEE80211_C_TXPMGT | /* tx power management */ 893192873Sweongyo IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 894192873Sweongyo IEEE80211_C_SHSLOT | /* short slot time supported */ 895192873Sweongyo IEEE80211_C_BGSCAN | /* capable of bg scanning */ 896192873Sweongyo IEEE80211_C_WPA; /* 802.11i */ 897192873Sweongyo 898192873Sweongyo bands = 0; 899192873Sweongyo setbit(&bands, IEEE80211_MODE_11B); 900192873Sweongyo setbit(&bands, IEEE80211_MODE_11G); 901192873Sweongyo ieee80211_init_channels(ic, NULL, &bands); 902192873Sweongyo 903192873Sweongyo ieee80211_ifattach(ic, sc->sc_bssid); 904192873Sweongyo ic->ic_raw_xmit = urtw_raw_xmit; 905192873Sweongyo ic->ic_scan_start = urtw_scan_start; 906192873Sweongyo ic->ic_scan_end = urtw_scan_end; 907192873Sweongyo ic->ic_set_channel = urtw_set_channel; 908198194Sweongyo ic->ic_updateslot = urtw_updateslot; 909192873Sweongyo ic->ic_vap_create = urtw_vap_create; 910192873Sweongyo ic->ic_vap_delete = urtw_vap_delete; 911192873Sweongyo ic->ic_update_mcast = urtw_update_mcast; 912192873Sweongyo 913192873Sweongyo ieee80211_radiotap_attach(ic, 914192873Sweongyo &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 915192873Sweongyo URTW_TX_RADIOTAP_PRESENT, 916192873Sweongyo &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 917192873Sweongyo URTW_RX_RADIOTAP_PRESENT); 918192873Sweongyo 919203087Sweongyo urtw_sysctl_node(sc); 920203087Sweongyo 921192873Sweongyo if (bootverbose) 922192873Sweongyo ieee80211_announce(ic); 923192873Sweongyo return (0); 924192873Sweongyo 925192873Sweongyofail: URTW_UNLOCK(sc); 926194228Sthompsafail1: usbd_transfer_unsetup(sc->sc_xfer, (sc->sc_flags & URTW_RTL8187B) ? 927192873Sweongyo URTW_8187B_N_XFERS : URTW_8187L_N_XFERS); 928192873Sweongyofail0: 929192873Sweongyo return (ret); 930192873Sweongyo} 931192873Sweongyo 932192873Sweongyostatic int 933192873Sweongyourtw_detach(device_t dev) 934192873Sweongyo{ 935192873Sweongyo struct urtw_softc *sc = device_get_softc(dev); 936192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 937192873Sweongyo struct ieee80211com *ic = ifp->if_l2com; 938259456Shselasky unsigned int x; 939259456Shselasky unsigned int n_xfers; 940192873Sweongyo 941259456Shselasky /* Prevent further ioctls */ 942259456Shselasky URTW_LOCK(sc); 943259456Shselasky sc->sc_flags |= URTW_DETACHED; 944259456Shselasky URTW_UNLOCK(sc); 945192873Sweongyo 946259456Shselasky urtw_stop(ifp); 947259456Shselasky 948198194Sweongyo ieee80211_draintask(ic, &sc->sc_updateslot_task); 949192873Sweongyo ieee80211_draintask(ic, &sc->sc_led_task); 950192873Sweongyo 951194228Sthompsa usb_callout_drain(&sc->sc_led_ch); 952192873Sweongyo callout_drain(&sc->sc_watchdog_ch); 953192873Sweongyo 954259456Shselasky n_xfers = (sc->sc_flags & URTW_RTL8187B) ? 955259456Shselasky URTW_8187B_N_XFERS : URTW_8187L_N_XFERS; 956259454Shselasky 957259456Shselasky /* prevent further allocations from RX/TX data lists */ 958259456Shselasky URTW_LOCK(sc); 959259456Shselasky STAILQ_INIT(&sc->sc_tx_active); 960259456Shselasky STAILQ_INIT(&sc->sc_tx_inactive); 961259456Shselasky STAILQ_INIT(&sc->sc_tx_pending); 962192873Sweongyo 963259456Shselasky STAILQ_INIT(&sc->sc_rx_active); 964259456Shselasky STAILQ_INIT(&sc->sc_rx_inactive); 965259456Shselasky URTW_UNLOCK(sc); 966259456Shselasky 967259456Shselasky /* drain USB transfers */ 968259456Shselasky for (x = 0; x != n_xfers; x++) 969259456Shselasky usbd_transfer_drain(sc->sc_xfer[x]); 970259456Shselasky 971259456Shselasky /* free data buffers */ 972259456Shselasky URTW_LOCK(sc); 973192873Sweongyo urtw_free_tx_data_list(sc); 974192873Sweongyo urtw_free_rx_data_list(sc); 975259456Shselasky URTW_UNLOCK(sc); 976192873Sweongyo 977259456Shselasky /* free USB transfers and some data buffers */ 978259456Shselasky usbd_transfer_unsetup(sc->sc_xfer, n_xfers); 979259456Shselasky 980259456Shselasky ieee80211_ifdetach(ic); 981192873Sweongyo if_free(ifp); 982192873Sweongyo mtx_destroy(&sc->sc_mtx); 983192873Sweongyo return (0); 984192873Sweongyo} 985192873Sweongyo 986192873Sweongyostatic void 987192873Sweongyourtw_free_tx_data_list(struct urtw_softc *sc) 988192873Sweongyo{ 989192873Sweongyo urtw_free_data_list(sc, sc->sc_tx, URTW_TX_DATA_LIST_COUNT, 0); 990192873Sweongyo} 991192873Sweongyo 992192873Sweongyostatic void 993192873Sweongyourtw_free_rx_data_list(struct urtw_softc *sc) 994192873Sweongyo{ 995192873Sweongyo urtw_free_data_list(sc, sc->sc_rx, URTW_RX_DATA_LIST_COUNT, 1); 996192873Sweongyo} 997192873Sweongyo 998192873Sweongyostatic void 999192873Sweongyourtw_free_data_list(struct urtw_softc *sc, struct urtw_data data[], int ndata, 1000192873Sweongyo int fillmbuf) 1001192873Sweongyo{ 1002192873Sweongyo int i; 1003192873Sweongyo 1004192873Sweongyo for (i = 0; i < ndata; i++) { 1005192873Sweongyo struct urtw_data *dp = &data[i]; 1006192873Sweongyo 1007192873Sweongyo if (fillmbuf == 1) { 1008192873Sweongyo if (dp->m != NULL) { 1009192873Sweongyo m_freem(dp->m); 1010192873Sweongyo dp->m = NULL; 1011192873Sweongyo dp->buf = NULL; 1012192873Sweongyo } 1013192873Sweongyo } else { 1014259454Shselasky dp->buf = NULL; 1015192873Sweongyo } 1016192873Sweongyo if (dp->ni != NULL) { 1017192873Sweongyo ieee80211_free_node(dp->ni); 1018192873Sweongyo dp->ni = NULL; 1019192873Sweongyo } 1020192873Sweongyo } 1021192873Sweongyo} 1022192873Sweongyo 1023192873Sweongyostatic struct ieee80211vap * 1024234753Sdimurtw_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 1025234753Sdim enum ieee80211_opmode opmode, int flags, 1026234753Sdim const uint8_t bssid[IEEE80211_ADDR_LEN], 1027234753Sdim const uint8_t mac[IEEE80211_ADDR_LEN]) 1028192873Sweongyo{ 1029192873Sweongyo struct urtw_vap *uvp; 1030192873Sweongyo struct ieee80211vap *vap; 1031192873Sweongyo 1032192873Sweongyo if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 1033192873Sweongyo return (NULL); 1034192873Sweongyo uvp = (struct urtw_vap *) malloc(sizeof(struct urtw_vap), 1035192873Sweongyo M_80211_VAP, M_NOWAIT | M_ZERO); 1036192873Sweongyo if (uvp == NULL) 1037192873Sweongyo return (NULL); 1038192873Sweongyo vap = &uvp->vap; 1039192873Sweongyo /* enable s/w bmiss handling for sta mode */ 1040192873Sweongyo 1041259457Shselasky if (ieee80211_vap_setup(ic, vap, name, unit, opmode, 1042259457Shselasky flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) { 1043259457Shselasky /* out of memory */ 1044259457Shselasky free(uvp, M_80211_VAP); 1045259457Shselasky return (NULL); 1046259457Shselasky } 1047259457Shselasky 1048192873Sweongyo /* override state transition machine */ 1049192873Sweongyo uvp->newstate = vap->iv_newstate; 1050192873Sweongyo vap->iv_newstate = urtw_newstate; 1051192873Sweongyo 1052192873Sweongyo /* complete setup */ 1053192873Sweongyo ieee80211_vap_attach(vap, ieee80211_media_change, 1054192873Sweongyo ieee80211_media_status); 1055192873Sweongyo ic->ic_opmode = opmode; 1056192873Sweongyo return (vap); 1057192873Sweongyo} 1058192873Sweongyo 1059192873Sweongyostatic void 1060192873Sweongyourtw_vap_delete(struct ieee80211vap *vap) 1061192873Sweongyo{ 1062192873Sweongyo struct urtw_vap *uvp = URTW_VAP(vap); 1063192873Sweongyo 1064192873Sweongyo ieee80211_vap_detach(vap); 1065192873Sweongyo free(uvp, M_80211_VAP); 1066192873Sweongyo} 1067192873Sweongyo 1068192873Sweongyostatic void 1069192873Sweongyourtw_init_locked(void *arg) 1070192873Sweongyo{ 1071192873Sweongyo int ret; 1072192873Sweongyo struct urtw_softc *sc = arg; 1073192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 1074193045Sthompsa usb_error_t error; 1075192873Sweongyo 1076192873Sweongyo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1077259456Shselasky urtw_stop_locked(ifp); 1078192873Sweongyo 1079192873Sweongyo error = (sc->sc_flags & URTW_RTL8187B) ? urtw_adapter_start_b(sc) : 1080192873Sweongyo urtw_adapter_start(sc); 1081192873Sweongyo if (error != 0) 1082192873Sweongyo goto fail; 1083192873Sweongyo 1084192873Sweongyo /* reset softc variables */ 1085192873Sweongyo sc->sc_txtimer = 0; 1086192873Sweongyo 1087192873Sweongyo if (!(sc->sc_flags & URTW_INIT_ONCE)) { 1088192873Sweongyo ret = urtw_alloc_rx_data_list(sc); 1089229121Shselasky if (ret != 0) 1090192873Sweongyo goto fail; 1091192873Sweongyo ret = urtw_alloc_tx_data_list(sc); 1092229121Shselasky if (ret != 0) 1093192873Sweongyo goto fail; 1094192873Sweongyo sc->sc_flags |= URTW_INIT_ONCE; 1095192873Sweongyo } 1096192873Sweongyo 1097192873Sweongyo error = urtw_rx_enable(sc); 1098192873Sweongyo if (error != 0) 1099192873Sweongyo goto fail; 1100192873Sweongyo error = urtw_tx_enable(sc); 1101192873Sweongyo if (error != 0) 1102192873Sweongyo goto fail; 1103192873Sweongyo 1104198194Sweongyo if (sc->sc_flags & URTW_RTL8187B) 1105198194Sweongyo usbd_transfer_start(sc->sc_xfer[URTW_8187B_BULK_TX_STATUS]); 1106198194Sweongyo 1107192873Sweongyo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1108192873Sweongyo ifp->if_drv_flags |= IFF_DRV_RUNNING; 1109192873Sweongyo 1110192873Sweongyo callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc); 1111192873Sweongyofail: 1112192873Sweongyo return; 1113192873Sweongyo} 1114192873Sweongyo 1115192873Sweongyostatic void 1116192873Sweongyourtw_init(void *arg) 1117192873Sweongyo{ 1118192873Sweongyo struct urtw_softc *sc = arg; 1119192873Sweongyo 1120192873Sweongyo URTW_LOCK(sc); 1121192873Sweongyo urtw_init_locked(arg); 1122192873Sweongyo URTW_UNLOCK(sc); 1123192873Sweongyo} 1124192873Sweongyo 1125193045Sthompsastatic usb_error_t 1126192873Sweongyourtw_adapter_start_b(struct urtw_softc *sc) 1127192873Sweongyo{ 1128235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 1129192873Sweongyo uint8_t data8; 1130193045Sthompsa usb_error_t error; 1131192873Sweongyo 1132192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 1133192873Sweongyo if (error) 1134192873Sweongyo goto fail; 1135192873Sweongyo 1136192873Sweongyo urtw_read8_m(sc, URTW_CONFIG3, &data8); 1137192873Sweongyo urtw_write8_m(sc, URTW_CONFIG3, 1138192873Sweongyo data8 | URTW_CONFIG3_ANAPARAM_WRITE | URTW_CONFIG3_GNT_SELECT); 1139192873Sweongyo urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON); 1140192873Sweongyo urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON); 1141192873Sweongyo urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON); 1142192873Sweongyo 1143192873Sweongyo urtw_write8_m(sc, 0x61, 0x10); 1144192873Sweongyo urtw_read8_m(sc, 0x62, &data8); 1145192873Sweongyo urtw_write8_m(sc, 0x62, data8 & ~(1 << 5)); 1146192873Sweongyo urtw_write8_m(sc, 0x62, data8 | (1 << 5)); 1147192873Sweongyo 1148192873Sweongyo urtw_read8_m(sc, URTW_CONFIG3, &data8); 1149192873Sweongyo data8 &= ~URTW_CONFIG3_ANAPARAM_WRITE; 1150192873Sweongyo urtw_write8_m(sc, URTW_CONFIG3, data8); 1151192873Sweongyo 1152192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 1153192873Sweongyo if (error) 1154192873Sweongyo goto fail; 1155192873Sweongyo 1156192873Sweongyo error = urtw_8187b_cmd_reset(sc); 1157192873Sweongyo if (error) 1158192873Sweongyo goto fail; 1159192873Sweongyo 1160192873Sweongyo error = sc->sc_rf_init(sc); 1161192873Sweongyo if (error != 0) 1162192873Sweongyo goto fail; 1163198194Sweongyo urtw_write8_m(sc, URTW_CMD, URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE); 1164192873Sweongyo 1165198194Sweongyo /* fix RTL8187B RX stall */ 1166192873Sweongyo error = urtw_intr_enable(sc); 1167192873Sweongyo if (error) 1168192873Sweongyo goto fail; 1169192873Sweongyo 1170192873Sweongyo error = urtw_write8e(sc, 0x41, 0xf4); 1171192873Sweongyo if (error) 1172192873Sweongyo goto fail; 1173192873Sweongyo error = urtw_write8e(sc, 0x40, 0x00); 1174192873Sweongyo if (error) 1175192873Sweongyo goto fail; 1176192873Sweongyo error = urtw_write8e(sc, 0x42, 0x00); 1177192873Sweongyo if (error) 1178192873Sweongyo goto fail; 1179192873Sweongyo error = urtw_write8e(sc, 0x42, 0x01); 1180192873Sweongyo if (error) 1181192873Sweongyo goto fail; 1182192873Sweongyo error = urtw_write8e(sc, 0x40, 0x0f); 1183192873Sweongyo if (error) 1184192873Sweongyo goto fail; 1185192873Sweongyo error = urtw_write8e(sc, 0x42, 0x00); 1186192873Sweongyo if (error) 1187192873Sweongyo goto fail; 1188192873Sweongyo error = urtw_write8e(sc, 0x42, 0x01); 1189192873Sweongyo if (error) 1190192873Sweongyo goto fail; 1191192873Sweongyo 1192192873Sweongyo urtw_read8_m(sc, 0xdb, &data8); 1193192873Sweongyo urtw_write8_m(sc, 0xdb, data8 | (1 << 2)); 1194198194Sweongyo urtw_write16_m(sc, 0x372, 0x59fa); 1195198194Sweongyo urtw_write16_m(sc, 0x374, 0x59d2); 1196198194Sweongyo urtw_write16_m(sc, 0x376, 0x59d2); 1197198194Sweongyo urtw_write16_m(sc, 0x378, 0x19fa); 1198198194Sweongyo urtw_write16_m(sc, 0x37a, 0x19fa); 1199198194Sweongyo urtw_write16_m(sc, 0x37c, 0x00d0); 1200192873Sweongyo urtw_write8_m(sc, 0x61, 0); 1201198194Sweongyo 1202198194Sweongyo urtw_write8_m(sc, 0x180, 0x0f); 1203198194Sweongyo urtw_write8_m(sc, 0x183, 0x03); 1204192873Sweongyo urtw_write8_m(sc, 0xda, 0x10); 1205198194Sweongyo urtw_write8_m(sc, 0x24d, 0x08); 1206198194Sweongyo urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321b); 1207192873Sweongyo 1208198194Sweongyo urtw_write16_m(sc, 0x1ec, 0x800); /* RX MAX SIZE */ 1209192873Sweongyofail: 1210192873Sweongyo return (error); 1211196970Sphk#undef N 1212192873Sweongyo} 1213192873Sweongyo 1214193045Sthompsastatic usb_error_t 1215192873Sweongyourtw_adapter_start(struct urtw_softc *sc) 1216192873Sweongyo{ 1217193045Sthompsa usb_error_t error; 1218192873Sweongyo 1219192873Sweongyo error = urtw_reset(sc); 1220192873Sweongyo if (error) 1221192873Sweongyo goto fail; 1222192873Sweongyo 1223192873Sweongyo urtw_write8_m(sc, URTW_ADDR_MAGIC1, 0); 1224192873Sweongyo urtw_write8_m(sc, URTW_GPIO, 0); 1225192873Sweongyo 1226192873Sweongyo /* for led */ 1227192873Sweongyo urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4); 1228192873Sweongyo error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON); 1229192873Sweongyo if (error != 0) 1230192873Sweongyo goto fail; 1231192873Sweongyo 1232192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 1233192873Sweongyo if (error) 1234192873Sweongyo goto fail; 1235192873Sweongyo /* applying MAC address again. */ 1236192873Sweongyo urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]); 1237192873Sweongyo urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff); 1238192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 1239192873Sweongyo if (error) 1240192873Sweongyo goto fail; 1241192873Sweongyo 1242192873Sweongyo error = urtw_update_msr(sc); 1243192873Sweongyo if (error) 1244192873Sweongyo goto fail; 1245192873Sweongyo 1246192873Sweongyo urtw_write32_m(sc, URTW_INT_TIMEOUT, 0); 1247192873Sweongyo urtw_write8_m(sc, URTW_WPA_CONFIG, 0); 1248192873Sweongyo urtw_write8_m(sc, URTW_RATE_FALLBACK, URTW_RATE_FALLBACK_ENABLE | 0x1); 1249192873Sweongyo error = urtw_set_rate(sc); 1250192873Sweongyo if (error != 0) 1251192873Sweongyo goto fail; 1252192873Sweongyo 1253192873Sweongyo error = sc->sc_rf_init(sc); 1254192873Sweongyo if (error != 0) 1255192873Sweongyo goto fail; 1256192873Sweongyo if (sc->sc_rf_set_sens != NULL) 1257192873Sweongyo sc->sc_rf_set_sens(sc, sc->sc_sens); 1258192873Sweongyo 1259192873Sweongyo /* XXX correct? to call write16 */ 1260192873Sweongyo urtw_write16_m(sc, URTW_PSR, 1); 1261192873Sweongyo urtw_write16_m(sc, URTW_ADDR_MAGIC2, 0x10); 1262192873Sweongyo urtw_write8_m(sc, URTW_TALLY_SEL, 0x80); 1263192873Sweongyo urtw_write8_m(sc, URTW_ADDR_MAGIC3, 0x60); 1264192873Sweongyo /* XXX correct? to call write16 */ 1265192873Sweongyo urtw_write16_m(sc, URTW_PSR, 0); 1266192873Sweongyo urtw_write8_m(sc, URTW_ADDR_MAGIC1, 4); 1267192873Sweongyo 1268192873Sweongyo error = urtw_intr_enable(sc); 1269192873Sweongyo if (error != 0) 1270192873Sweongyo goto fail; 1271192873Sweongyo 1272192873Sweongyofail: 1273192873Sweongyo return (error); 1274192873Sweongyo} 1275192873Sweongyo 1276196970Sphkstatic usb_error_t 1277196970Sphkurtw_set_mode(struct urtw_softc *sc, uint32_t mode) 1278196970Sphk{ 1279196970Sphk uint8_t data; 1280196970Sphk usb_error_t error; 1281192873Sweongyo 1282196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data); 1283196970Sphk data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT); 1284196970Sphk data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK); 1285196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data); 1286196970Sphkfail: 1287196970Sphk return (error); 1288196970Sphk} 1289196970Sphk 1290193045Sthompsastatic usb_error_t 1291192873Sweongyourtw_8187b_cmd_reset(struct urtw_softc *sc) 1292192873Sweongyo{ 1293192873Sweongyo int i; 1294192873Sweongyo uint8_t data8; 1295193045Sthompsa usb_error_t error; 1296192873Sweongyo 1297192873Sweongyo /* XXX the code can be duplicate with urtw_reset(). */ 1298192873Sweongyo urtw_read8_m(sc, URTW_CMD, &data8); 1299192873Sweongyo data8 = (data8 & 0x2) | URTW_CMD_RST; 1300192873Sweongyo urtw_write8_m(sc, URTW_CMD, data8); 1301192873Sweongyo 1302192873Sweongyo for (i = 0; i < 20; i++) { 1303194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 2); 1304192873Sweongyo urtw_read8_m(sc, URTW_CMD, &data8); 1305192873Sweongyo if (!(data8 & URTW_CMD_RST)) 1306192873Sweongyo break; 1307192873Sweongyo } 1308192873Sweongyo if (i >= 20) { 1309192873Sweongyo device_printf(sc->sc_dev, "reset timeout\n"); 1310192873Sweongyo goto fail; 1311192873Sweongyo } 1312192873Sweongyofail: 1313192873Sweongyo return (error); 1314192873Sweongyo} 1315192873Sweongyo 1316193045Sthompsastatic usb_error_t 1317192873Sweongyourtw_do_request(struct urtw_softc *sc, 1318192984Sthompsa struct usb_device_request *req, void *data) 1319192873Sweongyo{ 1320193045Sthompsa usb_error_t err; 1321192873Sweongyo int ntries = 10; 1322192873Sweongyo 1323192873Sweongyo URTW_ASSERT_LOCKED(sc); 1324192873Sweongyo 1325192873Sweongyo while (ntries--) { 1326194228Sthompsa err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 1327192873Sweongyo req, data, 0, NULL, 250 /* ms */); 1328192873Sweongyo if (err == 0) 1329192873Sweongyo break; 1330192873Sweongyo 1331192873Sweongyo DPRINTF(sc, URTW_DEBUG_INIT, 1332192873Sweongyo "Control request failed, %s (retrying)\n", 1333194228Sthompsa usbd_errstr(err)); 1334194228Sthompsa usb_pause_mtx(&sc->sc_mtx, hz / 100); 1335192873Sweongyo } 1336192873Sweongyo return (err); 1337192873Sweongyo} 1338192873Sweongyo 1339192873Sweongyostatic void 1340259456Shselaskyurtw_stop_locked(struct ifnet *ifp) 1341196970Sphk{ 1342196970Sphk struct urtw_softc *sc = ifp->if_softc; 1343196970Sphk uint8_t data8; 1344196970Sphk usb_error_t error; 1345196970Sphk 1346196970Sphk ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1347196970Sphk 1348196970Sphk error = urtw_intr_disable(sc); 1349196970Sphk if (error) 1350196970Sphk goto fail; 1351196970Sphk urtw_read8_m(sc, URTW_CMD, &data8); 1352196970Sphk data8 &= ~(URTW_CMD_RX_ENABLE | URTW_CMD_TX_ENABLE); 1353196970Sphk urtw_write8_m(sc, URTW_CMD, data8); 1354196970Sphk 1355196970Sphk error = sc->sc_rf_stop(sc); 1356196970Sphk if (error != 0) 1357196970Sphk goto fail; 1358196970Sphk 1359196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 1360196970Sphk if (error) 1361196970Sphk goto fail; 1362196970Sphk urtw_read8_m(sc, URTW_CONFIG4, &data8); 1363196970Sphk urtw_write8_m(sc, URTW_CONFIG4, data8 | URTW_CONFIG4_VCOOFF); 1364196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 1365196970Sphk if (error) 1366196970Sphk goto fail; 1367196970Sphkfail: 1368196970Sphk if (error) 1369196970Sphk device_printf(sc->sc_dev, "failed to stop (%s)\n", 1370196970Sphk usbd_errstr(error)); 1371196970Sphk 1372196970Sphk usb_callout_stop(&sc->sc_led_ch); 1373196970Sphk callout_stop(&sc->sc_watchdog_ch); 1374196970Sphk 1375196970Sphk urtw_abort_xfers(sc); 1376196970Sphk} 1377196970Sphk 1378196970Sphkstatic void 1379259456Shselaskyurtw_stop(struct ifnet *ifp) 1380196970Sphk{ 1381196970Sphk struct urtw_softc *sc = ifp->if_softc; 1382196970Sphk 1383196970Sphk URTW_LOCK(sc); 1384259456Shselasky urtw_stop_locked(ifp); 1385196970Sphk URTW_UNLOCK(sc); 1386196970Sphk} 1387196970Sphk 1388196970Sphkstatic void 1389192873Sweongyourtw_abort_xfers(struct urtw_softc *sc) 1390192873Sweongyo{ 1391192873Sweongyo int i, max; 1392192873Sweongyo 1393192873Sweongyo URTW_ASSERT_LOCKED(sc); 1394192873Sweongyo 1395192873Sweongyo max = (sc->sc_flags & URTW_RTL8187B) ? URTW_8187B_N_XFERS : 1396192873Sweongyo URTW_8187L_N_XFERS; 1397192873Sweongyo 1398192873Sweongyo /* abort any pending transfers */ 1399192873Sweongyo for (i = 0; i < max; i++) 1400194228Sthompsa usbd_transfer_stop(sc->sc_xfer[i]); 1401192873Sweongyo} 1402192873Sweongyo 1403192873Sweongyostatic int 1404192873Sweongyourtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1405192873Sweongyo{ 1406192873Sweongyo struct urtw_softc *sc = ifp->if_softc; 1407192873Sweongyo struct ieee80211com *ic = ifp->if_l2com; 1408192873Sweongyo struct ifreq *ifr = (struct ifreq *) data; 1409259456Shselasky int error; 1410259456Shselasky int startall = 0; 1411192873Sweongyo 1412259456Shselasky URTW_LOCK(sc); 1413259456Shselasky error = (sc->sc_flags & URTW_DETACHED) ? ENXIO : 0; 1414259456Shselasky URTW_UNLOCK(sc); 1415259456Shselasky if (error) 1416259456Shselasky return (error); 1417259456Shselasky 1418192873Sweongyo switch (cmd) { 1419192873Sweongyo case SIOCSIFFLAGS: 1420192873Sweongyo if (ifp->if_flags & IFF_UP) { 1421192873Sweongyo if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1422192873Sweongyo if ((ifp->if_flags ^ sc->sc_if_flags) & 1423192873Sweongyo (IFF_ALLMULTI | IFF_PROMISC)) 1424192873Sweongyo urtw_set_multi(sc); 1425192873Sweongyo } else { 1426192873Sweongyo urtw_init(ifp->if_softc); 1427192873Sweongyo startall = 1; 1428192873Sweongyo } 1429192873Sweongyo } else { 1430192873Sweongyo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1431259456Shselasky urtw_stop(ifp); 1432192873Sweongyo } 1433192873Sweongyo sc->sc_if_flags = ifp->if_flags; 1434192873Sweongyo if (startall) 1435192873Sweongyo ieee80211_start_all(ic); 1436192873Sweongyo break; 1437192873Sweongyo case SIOCGIFMEDIA: 1438192873Sweongyo error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 1439192873Sweongyo break; 1440192873Sweongyo case SIOCGIFADDR: 1441192873Sweongyo error = ether_ioctl(ifp, cmd, data); 1442192873Sweongyo break; 1443192873Sweongyo default: 1444192873Sweongyo error = EINVAL; 1445192873Sweongyo break; 1446192873Sweongyo } 1447192873Sweongyo return (error); 1448192873Sweongyo} 1449192873Sweongyo 1450192873Sweongyostatic void 1451192873Sweongyourtw_start(struct ifnet *ifp) 1452192873Sweongyo{ 1453192873Sweongyo struct urtw_data *bf; 1454192873Sweongyo struct urtw_softc *sc = ifp->if_softc; 1455192873Sweongyo struct ieee80211_node *ni; 1456192873Sweongyo struct mbuf *m; 1457192873Sweongyo 1458192873Sweongyo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1459192873Sweongyo return; 1460192873Sweongyo 1461192873Sweongyo URTW_LOCK(sc); 1462192873Sweongyo for (;;) { 1463192873Sweongyo IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1464192873Sweongyo if (m == NULL) 1465192873Sweongyo break; 1466192873Sweongyo bf = urtw_getbuf(sc); 1467192873Sweongyo if (bf == NULL) { 1468192873Sweongyo IFQ_DRV_PREPEND(&ifp->if_snd, m); 1469192873Sweongyo break; 1470192873Sweongyo } 1471192873Sweongyo 1472192873Sweongyo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 1473192873Sweongyo m->m_pkthdr.rcvif = NULL; 1474192873Sweongyo 1475192873Sweongyo if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_NORMAL) != 0) { 1476192873Sweongyo ifp->if_oerrors++; 1477192873Sweongyo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 1478192873Sweongyo ieee80211_free_node(ni); 1479192873Sweongyo break; 1480192873Sweongyo } 1481192873Sweongyo 1482192873Sweongyo sc->sc_txtimer = 5; 1483198194Sweongyo callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc); 1484192873Sweongyo } 1485192873Sweongyo URTW_UNLOCK(sc); 1486192873Sweongyo} 1487192873Sweongyo 1488192873Sweongyostatic int 1489192873Sweongyourtw_alloc_data_list(struct urtw_softc *sc, struct urtw_data data[], 1490259454Shselasky int ndata, int maxsz, void *dma_buf) 1491192873Sweongyo{ 1492192873Sweongyo int i, error; 1493192873Sweongyo 1494192873Sweongyo for (i = 0; i < ndata; i++) { 1495192873Sweongyo struct urtw_data *dp = &data[i]; 1496192873Sweongyo 1497192873Sweongyo dp->sc = sc; 1498259454Shselasky if (dma_buf == NULL) { 1499248078Smarius dp->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1500192873Sweongyo if (dp->m == NULL) { 1501192873Sweongyo device_printf(sc->sc_dev, 1502192873Sweongyo "could not allocate rx mbuf\n"); 1503192873Sweongyo error = ENOMEM; 1504192873Sweongyo goto fail; 1505192873Sweongyo } 1506192873Sweongyo dp->buf = mtod(dp->m, uint8_t *); 1507192873Sweongyo } else { 1508192873Sweongyo dp->m = NULL; 1509259454Shselasky dp->buf = ((uint8_t *)dma_buf) + 1510259454Shselasky (i * maxsz); 1511192873Sweongyo } 1512192873Sweongyo dp->ni = NULL; 1513192873Sweongyo } 1514259454Shselasky return (0); 1515192873Sweongyo 1516259454Shselaskyfail: urtw_free_data_list(sc, data, ndata, 1); 1517259454Shselasky return (error); 1518192873Sweongyo} 1519192873Sweongyo 1520192873Sweongyostatic int 1521192873Sweongyourtw_alloc_rx_data_list(struct urtw_softc *sc) 1522192873Sweongyo{ 1523192873Sweongyo int error, i; 1524192873Sweongyo 1525192873Sweongyo error = urtw_alloc_data_list(sc, 1526259454Shselasky sc->sc_rx, URTW_RX_DATA_LIST_COUNT, 1527259454Shselasky MCLBYTES, NULL /* mbufs */); 1528192873Sweongyo if (error != 0) 1529192873Sweongyo return (error); 1530192873Sweongyo 1531192873Sweongyo STAILQ_INIT(&sc->sc_rx_active); 1532192873Sweongyo STAILQ_INIT(&sc->sc_rx_inactive); 1533192873Sweongyo 1534192873Sweongyo for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) 1535192873Sweongyo STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); 1536192873Sweongyo 1537192873Sweongyo return (0); 1538192873Sweongyo} 1539192873Sweongyo 1540192873Sweongyostatic int 1541192873Sweongyourtw_alloc_tx_data_list(struct urtw_softc *sc) 1542192873Sweongyo{ 1543192873Sweongyo int error, i; 1544192873Sweongyo 1545192873Sweongyo error = urtw_alloc_data_list(sc, 1546192873Sweongyo sc->sc_tx, URTW_TX_DATA_LIST_COUNT, URTW_TX_MAXSIZE, 1547259454Shselasky sc->sc_tx_dma_buf /* no mbufs */); 1548192873Sweongyo if (error != 0) 1549192873Sweongyo return (error); 1550192873Sweongyo 1551192873Sweongyo STAILQ_INIT(&sc->sc_tx_active); 1552192873Sweongyo STAILQ_INIT(&sc->sc_tx_inactive); 1553192873Sweongyo STAILQ_INIT(&sc->sc_tx_pending); 1554192873Sweongyo 1555192873Sweongyo for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++) 1556192873Sweongyo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], 1557192873Sweongyo next); 1558192873Sweongyo 1559192873Sweongyo return (0); 1560192873Sweongyo} 1561192873Sweongyo 1562192873Sweongyostatic int 1563192873Sweongyourtw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 1564192873Sweongyo const struct ieee80211_bpf_params *params) 1565192873Sweongyo{ 1566192873Sweongyo struct ieee80211com *ic = ni->ni_ic; 1567192873Sweongyo struct ifnet *ifp = ic->ic_ifp; 1568192873Sweongyo struct urtw_data *bf; 1569192873Sweongyo struct urtw_softc *sc = ifp->if_softc; 1570192873Sweongyo 1571192873Sweongyo /* prevent management frames from being sent if we're not ready */ 1572192873Sweongyo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1573192873Sweongyo m_freem(m); 1574192873Sweongyo ieee80211_free_node(ni); 1575192873Sweongyo return ENETDOWN; 1576192873Sweongyo } 1577192873Sweongyo URTW_LOCK(sc); 1578192873Sweongyo bf = urtw_getbuf(sc); 1579192873Sweongyo if (bf == NULL) { 1580192873Sweongyo ieee80211_free_node(ni); 1581192873Sweongyo m_freem(m); 1582192873Sweongyo URTW_UNLOCK(sc); 1583192873Sweongyo return (ENOBUFS); /* XXX */ 1584192873Sweongyo } 1585192873Sweongyo 1586192873Sweongyo ifp->if_opackets++; 1587192873Sweongyo if (urtw_tx_start(sc, ni, m, bf, URTW_PRIORITY_LOW) != 0) { 1588192873Sweongyo ieee80211_free_node(ni); 1589192873Sweongyo ifp->if_oerrors++; 1590192873Sweongyo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 1591192873Sweongyo URTW_UNLOCK(sc); 1592192873Sweongyo return (EIO); 1593192873Sweongyo } 1594192873Sweongyo URTW_UNLOCK(sc); 1595192873Sweongyo 1596192873Sweongyo sc->sc_txtimer = 5; 1597192873Sweongyo return (0); 1598192873Sweongyo} 1599192873Sweongyo 1600192873Sweongyostatic void 1601192873Sweongyourtw_scan_start(struct ieee80211com *ic) 1602192873Sweongyo{ 1603192873Sweongyo 1604192873Sweongyo /* XXX do nothing? */ 1605192873Sweongyo} 1606192873Sweongyo 1607192873Sweongyostatic void 1608192873Sweongyourtw_scan_end(struct ieee80211com *ic) 1609192873Sweongyo{ 1610192873Sweongyo 1611192873Sweongyo /* XXX do nothing? */ 1612192873Sweongyo} 1613192873Sweongyo 1614192873Sweongyostatic void 1615192873Sweongyourtw_set_channel(struct ieee80211com *ic) 1616192873Sweongyo{ 1617192873Sweongyo struct urtw_softc *sc = ic->ic_ifp->if_softc; 1618192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 1619192873Sweongyo uint32_t data, orig; 1620193045Sthompsa usb_error_t error; 1621192873Sweongyo 1622192873Sweongyo /* 1623192873Sweongyo * if the user set a channel explicitly using ifconfig(8) this function 1624192873Sweongyo * can be called earlier than we're expected that in some cases the 1625192873Sweongyo * initialization would be failed if setting a channel is called before 1626192873Sweongyo * the init have done. 1627192873Sweongyo */ 1628192873Sweongyo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1629192873Sweongyo return; 1630192873Sweongyo 1631192873Sweongyo if (sc->sc_curchan != NULL && sc->sc_curchan == ic->ic_curchan) 1632192873Sweongyo return; 1633192873Sweongyo 1634192873Sweongyo URTW_LOCK(sc); 1635192873Sweongyo 1636192873Sweongyo /* 1637192873Sweongyo * during changing th channel we need to temporarily be disable 1638192873Sweongyo * TX. 1639192873Sweongyo */ 1640192873Sweongyo urtw_read32_m(sc, URTW_TX_CONF, &orig); 1641192873Sweongyo data = orig & ~URTW_TX_LOOPBACK_MASK; 1642192873Sweongyo urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC); 1643192873Sweongyo 1644192873Sweongyo error = sc->sc_rf_set_chan(sc, ieee80211_chan2ieee(ic, ic->ic_curchan)); 1645192873Sweongyo if (error != 0) 1646192873Sweongyo goto fail; 1647194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 10); 1648192873Sweongyo urtw_write32_m(sc, URTW_TX_CONF, orig); 1649192873Sweongyo 1650192873Sweongyo urtw_write16_m(sc, URTW_ATIM_WND, 2); 1651192873Sweongyo urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100); 1652192873Sweongyo urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100); 1653192873Sweongyo urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100); 1654192873Sweongyo 1655192873Sweongyofail: 1656192873Sweongyo URTW_UNLOCK(sc); 1657192873Sweongyo 1658192873Sweongyo sc->sc_curchan = ic->ic_curchan; 1659192873Sweongyo 1660192873Sweongyo if (error != 0) 1661192873Sweongyo device_printf(sc->sc_dev, "could not change the channel\n"); 1662192873Sweongyo} 1663192873Sweongyo 1664192873Sweongyostatic void 1665192873Sweongyourtw_update_mcast(struct ifnet *ifp) 1666192873Sweongyo{ 1667192873Sweongyo 1668192873Sweongyo /* XXX do nothing? */ 1669192873Sweongyo} 1670192873Sweongyo 1671192873Sweongyostatic int 1672192873Sweongyourtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, 1673192873Sweongyo struct urtw_data *data, int prior) 1674192873Sweongyo{ 1675192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 1676192873Sweongyo struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); 1677192873Sweongyo struct ieee80211_key *k; 1678192873Sweongyo const struct ieee80211_txparam *tp; 1679192873Sweongyo struct ieee80211com *ic = ifp->if_l2com; 1680192873Sweongyo struct ieee80211vap *vap = ni->ni_vap; 1681192984Sthompsa struct usb_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = { 1682192873Sweongyo sc->sc_xfer[URTW_8187B_BULK_TX_BE], 1683192873Sweongyo sc->sc_xfer[URTW_8187B_BULK_TX_BK], 1684192873Sweongyo sc->sc_xfer[URTW_8187B_BULK_TX_VI], 1685192873Sweongyo sc->sc_xfer[URTW_8187B_BULK_TX_VO] 1686192873Sweongyo }; 1687192984Sthompsa struct usb_xfer *xfer; 1688198194Sweongyo int dur = 0, rtsdur = 0, rtsenable = 0, ctsenable = 0, rate, 1689198194Sweongyo pkttime = 0, txdur = 0, isshort = 0, xferlen; 1690198194Sweongyo uint16_t acktime, rtstime, ctstime; 1691198194Sweongyo uint32_t flags; 1692193045Sthompsa usb_error_t error; 1693192873Sweongyo 1694192873Sweongyo URTW_ASSERT_LOCKED(sc); 1695192873Sweongyo 1696192873Sweongyo /* 1697192873Sweongyo * Software crypto. 1698192873Sweongyo */ 1699192873Sweongyo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1700192873Sweongyo k = ieee80211_crypto_encap(ni, m0); 1701192873Sweongyo if (k == NULL) { 1702192873Sweongyo device_printf(sc->sc_dev, 1703192873Sweongyo "ieee80211_crypto_encap returns NULL.\n"); 1704192873Sweongyo /* XXX we don't expect the fragmented frames */ 1705192873Sweongyo m_freem(m0); 1706192873Sweongyo return (ENOBUFS); 1707192873Sweongyo } 1708192873Sweongyo 1709192873Sweongyo /* in case packet header moved, reset pointer */ 1710192873Sweongyo wh = mtod(m0, struct ieee80211_frame *); 1711192873Sweongyo } 1712192873Sweongyo 1713192873Sweongyo if (ieee80211_radiotap_active_vap(vap)) { 1714192873Sweongyo struct urtw_tx_radiotap_header *tap = &sc->sc_txtap; 1715192873Sweongyo 1716192873Sweongyo /* XXX Are variables correct? */ 1717192873Sweongyo tap->wt_flags = 0; 1718192873Sweongyo tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1719192873Sweongyo tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1720192873Sweongyo 1721192873Sweongyo ieee80211_radiotap_tx(vap, m0); 1722192873Sweongyo } 1723192873Sweongyo 1724198862Sweongyo if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT || 1725198194Sweongyo (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) { 1726198194Sweongyo tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1727198194Sweongyo rate = tp->mgmtrate; 1728198194Sweongyo } else { 1729198194Sweongyo tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1730198194Sweongyo /* for data frames */ 1731198194Sweongyo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 1732198194Sweongyo rate = tp->mcastrate; 1733198194Sweongyo else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 1734198194Sweongyo rate = tp->ucastrate; 1735198194Sweongyo else 1736198194Sweongyo rate = urtw_rtl2rate(sc->sc_currate); 1737198194Sweongyo } 1738198194Sweongyo 1739203087Sweongyo sc->sc_stats.txrates[sc->sc_currate]++; 1740203087Sweongyo 1741198194Sweongyo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 1742198194Sweongyo txdur = pkttime = urtw_compute_txtime(m0->m_pkthdr.len + 1743198194Sweongyo IEEE80211_CRC_LEN, rate, 0, 0); 1744198194Sweongyo else { 1745198194Sweongyo acktime = urtw_compute_txtime(14, 2,0, 0); 1746198194Sweongyo if ((m0->m_pkthdr.len + 4) > vap->iv_rtsthreshold) { 1747198194Sweongyo rtsenable = 1; 1748198194Sweongyo ctsenable = 0; 1749198194Sweongyo rtstime = urtw_compute_txtime(URTW_ACKCTS_LEN, 2, 0, 0); 1750198194Sweongyo ctstime = urtw_compute_txtime(14, 2, 0, 0); 1751198194Sweongyo pkttime = urtw_compute_txtime(m0->m_pkthdr.len + 1752198194Sweongyo IEEE80211_CRC_LEN, rate, 0, isshort); 1753198194Sweongyo rtsdur = ctstime + pkttime + acktime + 1754198194Sweongyo 3 * URTW_ASIFS_TIME; 1755198194Sweongyo txdur = rtstime + rtsdur; 1756198194Sweongyo } else { 1757198194Sweongyo rtsenable = ctsenable = rtsdur = 0; 1758198194Sweongyo pkttime = urtw_compute_txtime(m0->m_pkthdr.len + 1759198194Sweongyo IEEE80211_CRC_LEN, rate, 0, isshort); 1760198194Sweongyo txdur = pkttime + URTW_ASIFS_TIME + acktime; 1761198194Sweongyo } 1762198194Sweongyo 1763198194Sweongyo if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) 1764198194Sweongyo dur = urtw_compute_txtime(m0->m_pkthdr.len + 1765198194Sweongyo IEEE80211_CRC_LEN, rate, 0, isshort) + 1766198194Sweongyo 3 * URTW_ASIFS_TIME + 1767198194Sweongyo 2 * acktime; 1768198194Sweongyo else 1769198194Sweongyo dur = URTW_ASIFS_TIME + acktime; 1770198194Sweongyo } 1771259457Shselasky USETW(wh->i_dur, dur); 1772198194Sweongyo 1773192873Sweongyo xferlen = m0->m_pkthdr.len; 1774192873Sweongyo xferlen += (sc->sc_flags & URTW_RTL8187B) ? (4 * 8) : (4 * 3); 1775192873Sweongyo if ((0 == xferlen % 64) || (0 == xferlen % 512)) 1776192873Sweongyo xferlen += 1; 1777192873Sweongyo 1778229080Shselasky memset(data->buf, 0, URTW_TX_MAXSIZE); 1779198194Sweongyo flags = m0->m_pkthdr.len & 0xfff; 1780198194Sweongyo flags |= URTW_TX_FLAG_NO_ENC; 1781192873Sweongyo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1782192873Sweongyo (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) && 1783192873Sweongyo (sc->sc_preamble_mode == URTW_PREAMBLE_MODE_SHORT) && 1784192873Sweongyo (sc->sc_currate != 0)) 1785198194Sweongyo flags |= URTW_TX_FLAG_SPLCP; 1786192873Sweongyo if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) 1787198194Sweongyo flags |= URTW_TX_FLAG_MOREFRAG; 1788192873Sweongyo 1789198194Sweongyo flags |= (sc->sc_currate & 0xf) << URTW_TX_FLAG_TXRATE_SHIFT; 1790198194Sweongyo 1791192873Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 1792198194Sweongyo struct urtw_8187b_txhdr *tx; 1793198194Sweongyo 1794198194Sweongyo tx = (struct urtw_8187b_txhdr *)data->buf; 1795198194Sweongyo if (ctsenable) 1796198194Sweongyo flags |= URTW_TX_FLAG_CTS; 1797198194Sweongyo if (rtsenable) { 1798198194Sweongyo flags |= URTW_TX_FLAG_RTS; 1799198194Sweongyo flags |= (urtw_rate2rtl(11) & 0xf) << 1800198194Sweongyo URTW_TX_FLAG_RTSRATE_SHIFT; 1801198194Sweongyo tx->rtsdur = rtsdur; 1802198194Sweongyo } 1803198194Sweongyo tx->flag = htole32(flags); 1804198194Sweongyo tx->txdur = txdur; 1805198194Sweongyo if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1806198194Sweongyo IEEE80211_FC0_TYPE_MGT && 1807198194Sweongyo (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1808198194Sweongyo IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1809198194Sweongyo tx->retry = 1; 1810198194Sweongyo else 1811198194Sweongyo tx->retry = URTW_TX_MAXRETRY; 1812198194Sweongyo m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1)); 1813192873Sweongyo } else { 1814198194Sweongyo struct urtw_8187l_txhdr *tx; 1815198194Sweongyo 1816198194Sweongyo tx = (struct urtw_8187l_txhdr *)data->buf; 1817198194Sweongyo if (rtsenable) { 1818198194Sweongyo flags |= URTW_TX_FLAG_RTS; 1819198194Sweongyo tx->rtsdur = rtsdur; 1820198194Sweongyo } 1821198194Sweongyo flags |= (urtw_rate2rtl(11) & 0xf) << URTW_TX_FLAG_RTSRATE_SHIFT; 1822198194Sweongyo tx->flag = htole32(flags); 1823198194Sweongyo tx->retry = 3; /* CW minimum */ 1824198194Sweongyo tx->retry = 7 << 4; /* CW maximum */ 1825198194Sweongyo tx->retry = URTW_TX_MAXRETRY << 8; /* retry limitation */ 1826198194Sweongyo m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(tx + 1)); 1827192873Sweongyo } 1828192873Sweongyo 1829192873Sweongyo data->buflen = xferlen; 1830192873Sweongyo data->ni = ni; 1831192873Sweongyo data->m = m0; 1832192873Sweongyo 1833192873Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 1834192873Sweongyo switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 1835192873Sweongyo case IEEE80211_FC0_TYPE_CTL: 1836192873Sweongyo case IEEE80211_FC0_TYPE_MGT: 1837192873Sweongyo xfer = sc->sc_xfer[URTW_8187B_BULK_TX_EP12]; 1838192873Sweongyo break; 1839192873Sweongyo default: 1840192873Sweongyo KASSERT(M_WME_GETAC(m0) < URTW_8187B_TXPIPE_MAX, 1841192873Sweongyo ("unsupported WME pipe %d", M_WME_GETAC(m0))); 1842192873Sweongyo xfer = rtl8187b_pipes[M_WME_GETAC(m0)]; 1843192873Sweongyo break; 1844192873Sweongyo } 1845192873Sweongyo } else 1846192873Sweongyo xfer = (prior == URTW_PRIORITY_LOW) ? 1847192873Sweongyo sc->sc_xfer[URTW_8187L_BULK_TX_LOW] : 1848192873Sweongyo sc->sc_xfer[URTW_8187L_BULK_TX_NORMAL]; 1849192873Sweongyo 1850192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 1851194228Sthompsa usbd_transfer_start(xfer); 1852192873Sweongyo 1853192873Sweongyo error = urtw_led_ctl(sc, URTW_LED_CTL_TX); 1854192873Sweongyo if (error != 0) 1855192873Sweongyo device_printf(sc->sc_dev, "could not control LED (%d)\n", 1856192873Sweongyo error); 1857192873Sweongyo return (0); 1858192873Sweongyo} 1859192873Sweongyo 1860192873Sweongyostatic int 1861192873Sweongyourtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1862192873Sweongyo{ 1863192873Sweongyo struct ieee80211com *ic = vap->iv_ic; 1864192873Sweongyo struct urtw_softc *sc = ic->ic_ifp->if_softc; 1865192873Sweongyo struct urtw_vap *uvp = URTW_VAP(vap); 1866212131Sthompsa struct ieee80211_node *ni; 1867193045Sthompsa usb_error_t error = 0; 1868192873Sweongyo 1869192873Sweongyo DPRINTF(sc, URTW_DEBUG_STATE, "%s: %s -> %s\n", __func__, 1870192873Sweongyo ieee80211_state_name[vap->iv_state], 1871192873Sweongyo ieee80211_state_name[nstate]); 1872192873Sweongyo 1873192873Sweongyo sc->sc_state = nstate; 1874192873Sweongyo 1875192873Sweongyo IEEE80211_UNLOCK(ic); 1876192873Sweongyo URTW_LOCK(sc); 1877194228Sthompsa usb_callout_stop(&sc->sc_led_ch); 1878192873Sweongyo callout_stop(&sc->sc_watchdog_ch); 1879192873Sweongyo 1880192873Sweongyo switch (nstate) { 1881192873Sweongyo case IEEE80211_S_INIT: 1882192873Sweongyo case IEEE80211_S_SCAN: 1883192873Sweongyo case IEEE80211_S_AUTH: 1884192873Sweongyo case IEEE80211_S_ASSOC: 1885192873Sweongyo break; 1886192873Sweongyo case IEEE80211_S_RUN: 1887212127Sthompsa ni = ieee80211_ref_node(vap->iv_bss); 1888192873Sweongyo /* setting bssid. */ 1889192873Sweongyo urtw_write32_m(sc, URTW_BSSID, ((uint32_t *)ni->ni_bssid)[0]); 1890192873Sweongyo urtw_write16_m(sc, URTW_BSSID + 4, 1891192873Sweongyo ((uint16_t *)ni->ni_bssid)[2]); 1892192873Sweongyo urtw_update_msr(sc); 1893192873Sweongyo /* XXX maybe the below would be incorrect. */ 1894192873Sweongyo urtw_write16_m(sc, URTW_ATIM_WND, 2); 1895192873Sweongyo urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100); 1896192873Sweongyo urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64); 1897192873Sweongyo urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 100); 1898192873Sweongyo error = urtw_led_ctl(sc, URTW_LED_CTL_LINK); 1899192873Sweongyo if (error != 0) 1900192873Sweongyo device_printf(sc->sc_dev, 1901192873Sweongyo "could not control LED (%d)\n", error); 1902212127Sthompsa ieee80211_free_node(ni); 1903192873Sweongyo break; 1904192873Sweongyo default: 1905192873Sweongyo break; 1906192873Sweongyo } 1907192873Sweongyofail: 1908192873Sweongyo URTW_UNLOCK(sc); 1909192873Sweongyo IEEE80211_LOCK(ic); 1910192873Sweongyo return (uvp->newstate(vap, nstate, arg)); 1911192873Sweongyo} 1912192873Sweongyo 1913192873Sweongyostatic void 1914192873Sweongyourtw_watchdog(void *arg) 1915192873Sweongyo{ 1916192873Sweongyo struct urtw_softc *sc = arg; 1917192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 1918192873Sweongyo 1919192873Sweongyo if (sc->sc_txtimer > 0) { 1920192873Sweongyo if (--sc->sc_txtimer == 0) { 1921192873Sweongyo device_printf(sc->sc_dev, "device timeout\n"); 1922192873Sweongyo ifp->if_oerrors++; 1923192873Sweongyo return; 1924192873Sweongyo } 1925192873Sweongyo callout_reset(&sc->sc_watchdog_ch, hz, urtw_watchdog, sc); 1926192873Sweongyo } 1927192873Sweongyo} 1928192873Sweongyo 1929192873Sweongyostatic void 1930192873Sweongyourtw_set_multi(void *arg) 1931192873Sweongyo{ 1932192873Sweongyo struct urtw_softc *sc = arg; 1933192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 1934192873Sweongyo 1935192873Sweongyo if (!(ifp->if_flags & IFF_UP)) 1936192873Sweongyo return; 1937192873Sweongyo 1938192873Sweongyo /* 1939192873Sweongyo * XXX don't know how to set a device. Lack of docs. Just try to set 1940192873Sweongyo * IFF_ALLMULTI flag here. 1941192873Sweongyo */ 1942192873Sweongyo ifp->if_flags |= IFF_ALLMULTI; 1943192873Sweongyo} 1944192873Sweongyo 1945193045Sthompsastatic usb_error_t 1946196970Sphkurtw_set_rate(struct urtw_softc *sc) 1947192873Sweongyo{ 1948196970Sphk int i, basic_rate, min_rr_rate, max_rr_rate; 1949196970Sphk uint16_t data; 1950193045Sthompsa usb_error_t error; 1951192873Sweongyo 1952196970Sphk basic_rate = urtw_rate2rtl(48); 1953196970Sphk min_rr_rate = urtw_rate2rtl(12); 1954196970Sphk max_rr_rate = urtw_rate2rtl(48); 1955192873Sweongyo 1956196970Sphk urtw_write8_m(sc, URTW_RESP_RATE, 1957196970Sphk max_rr_rate << URTW_RESP_MAX_RATE_SHIFT | 1958196970Sphk min_rr_rate << URTW_RESP_MIN_RATE_SHIFT); 1959192873Sweongyo 1960196970Sphk urtw_read16_m(sc, URTW_BRSR, &data); 1961196970Sphk data &= ~URTW_BRSR_MBR_8185; 1962192873Sweongyo 1963196970Sphk for (i = 0; i <= basic_rate; i++) 1964196970Sphk data |= (1 << i); 1965192873Sweongyo 1966196970Sphk urtw_write16_m(sc, URTW_BRSR, data); 1967192873Sweongyofail: 1968192873Sweongyo return (error); 1969192873Sweongyo} 1970192873Sweongyo 1971196970Sphkstatic uint16_t 1972235000Shselaskyurtw_rate2rtl(uint32_t rate) 1973192873Sweongyo{ 1974235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 1975196970Sphk int i; 1976192873Sweongyo 1977196970Sphk for (i = 0; i < N(urtw_ratetable); i++) { 1978196970Sphk if (rate == urtw_ratetable[i].reg) 1979196970Sphk return urtw_ratetable[i].val; 1980196970Sphk } 1981192873Sweongyo 1982196970Sphk return (3); 1983196970Sphk#undef N 1984192873Sweongyo} 1985192873Sweongyo 1986196970Sphkstatic uint16_t 1987235000Shselaskyurtw_rtl2rate(uint32_t rate) 1988192873Sweongyo{ 1989235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 1990196970Sphk int i; 1991192873Sweongyo 1992196970Sphk for (i = 0; i < N(urtw_ratetable); i++) { 1993196970Sphk if (rate == urtw_ratetable[i].val) 1994196970Sphk return urtw_ratetable[i].reg; 1995192873Sweongyo } 1996192873Sweongyo 1997196970Sphk return (0); 1998196970Sphk#undef N 1999192873Sweongyo} 2000192873Sweongyo 2001193045Sthompsastatic usb_error_t 2002196970Sphkurtw_update_msr(struct urtw_softc *sc) 2003192873Sweongyo{ 2004196970Sphk struct ifnet *ifp = sc->sc_ifp; 2005196970Sphk struct ieee80211com *ic = ifp->if_l2com; 2006192873Sweongyo uint8_t data; 2007193045Sthompsa usb_error_t error; 2008192873Sweongyo 2009196970Sphk urtw_read8_m(sc, URTW_MSR, &data); 2010196970Sphk data &= ~URTW_MSR_LINK_MASK; 2011192873Sweongyo 2012196970Sphk if (sc->sc_state == IEEE80211_S_RUN) { 2013196970Sphk switch (ic->ic_opmode) { 2014196970Sphk case IEEE80211_M_STA: 2015196970Sphk case IEEE80211_M_MONITOR: 2016196970Sphk data |= URTW_MSR_LINK_STA; 2017196970Sphk if (sc->sc_flags & URTW_RTL8187B) 2018196970Sphk data |= URTW_MSR_LINK_ENEDCA; 2019196970Sphk break; 2020196970Sphk case IEEE80211_M_IBSS: 2021196970Sphk data |= URTW_MSR_LINK_ADHOC; 2022196970Sphk break; 2023196970Sphk case IEEE80211_M_HOSTAP: 2024196970Sphk data |= URTW_MSR_LINK_HOSTAP; 2025196970Sphk break; 2026196970Sphk default: 2027259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 2028259456Shselasky "unsupported operation mode 0x%x\n", 2029196970Sphk ic->ic_opmode); 2030259456Shselasky error = USB_ERR_INVAL; 2031259456Shselasky goto fail; 2032196970Sphk } 2033196970Sphk } else 2034196970Sphk data |= URTW_MSR_LINK_NONE; 2035192873Sweongyo 2036196970Sphk urtw_write8_m(sc, URTW_MSR, data); 2037192873Sweongyofail: 2038192873Sweongyo return (error); 2039192873Sweongyo} 2040192873Sweongyo 2041193045Sthompsastatic usb_error_t 2042192873Sweongyourtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data) 2043192873Sweongyo{ 2044192984Sthompsa struct usb_device_request req; 2045193045Sthompsa usb_error_t error; 2046192873Sweongyo 2047192873Sweongyo URTW_ASSERT_LOCKED(sc); 2048192873Sweongyo 2049192873Sweongyo req.bmRequestType = UT_READ_VENDOR_DEVICE; 2050192873Sweongyo req.bRequest = URTW_8187_GETREGS_REQ; 2051198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2052198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2053192873Sweongyo USETW(req.wLength, sizeof(uint8_t)); 2054192873Sweongyo 2055192873Sweongyo error = urtw_do_request(sc, &req, data); 2056192873Sweongyo return (error); 2057192873Sweongyo} 2058192873Sweongyo 2059193045Sthompsastatic usb_error_t 2060192873Sweongyourtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data) 2061192873Sweongyo{ 2062192984Sthompsa struct usb_device_request req; 2063193045Sthompsa usb_error_t error; 2064192873Sweongyo 2065192873Sweongyo URTW_ASSERT_LOCKED(sc); 2066192873Sweongyo 2067192873Sweongyo req.bmRequestType = UT_READ_VENDOR_DEVICE; 2068192873Sweongyo req.bRequest = URTW_8187_GETREGS_REQ; 2069198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2070198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2071192873Sweongyo USETW(req.wLength, sizeof(uint16_t)); 2072192873Sweongyo 2073192873Sweongyo error = urtw_do_request(sc, &req, data); 2074192873Sweongyo return (error); 2075192873Sweongyo} 2076192873Sweongyo 2077193045Sthompsastatic usb_error_t 2078192873Sweongyourtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data) 2079192873Sweongyo{ 2080192984Sthompsa struct usb_device_request req; 2081193045Sthompsa usb_error_t error; 2082192873Sweongyo 2083192873Sweongyo URTW_ASSERT_LOCKED(sc); 2084192873Sweongyo 2085192873Sweongyo req.bmRequestType = UT_READ_VENDOR_DEVICE; 2086192873Sweongyo req.bRequest = URTW_8187_GETREGS_REQ; 2087198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2088198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2089192873Sweongyo USETW(req.wLength, sizeof(uint32_t)); 2090192873Sweongyo 2091192873Sweongyo error = urtw_do_request(sc, &req, data); 2092192873Sweongyo return (error); 2093192873Sweongyo} 2094192873Sweongyo 2095193045Sthompsastatic usb_error_t 2096192873Sweongyourtw_write8_c(struct urtw_softc *sc, int val, uint8_t data) 2097192873Sweongyo{ 2098192984Sthompsa struct usb_device_request req; 2099192873Sweongyo 2100192873Sweongyo URTW_ASSERT_LOCKED(sc); 2101192873Sweongyo 2102192873Sweongyo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 2103192873Sweongyo req.bRequest = URTW_8187_SETREGS_REQ; 2104198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2105198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2106192873Sweongyo USETW(req.wLength, sizeof(uint8_t)); 2107192873Sweongyo 2108192873Sweongyo return (urtw_do_request(sc, &req, &data)); 2109192873Sweongyo} 2110192873Sweongyo 2111193045Sthompsastatic usb_error_t 2112192873Sweongyourtw_write16_c(struct urtw_softc *sc, int val, uint16_t data) 2113192873Sweongyo{ 2114192984Sthompsa struct usb_device_request req; 2115192873Sweongyo 2116192873Sweongyo URTW_ASSERT_LOCKED(sc); 2117192873Sweongyo 2118192873Sweongyo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 2119192873Sweongyo req.bRequest = URTW_8187_SETREGS_REQ; 2120198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2121198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2122192873Sweongyo USETW(req.wLength, sizeof(uint16_t)); 2123192873Sweongyo 2124192873Sweongyo return (urtw_do_request(sc, &req, &data)); 2125192873Sweongyo} 2126192873Sweongyo 2127193045Sthompsastatic usb_error_t 2128192873Sweongyourtw_write32_c(struct urtw_softc *sc, int val, uint32_t data) 2129192873Sweongyo{ 2130192984Sthompsa struct usb_device_request req; 2131192873Sweongyo 2132192873Sweongyo URTW_ASSERT_LOCKED(sc); 2133192873Sweongyo 2134192873Sweongyo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 2135192873Sweongyo req.bRequest = URTW_8187_SETREGS_REQ; 2136198194Sweongyo USETW(req.wValue, (val & 0xff) | 0xff00); 2137198194Sweongyo USETW(req.wIndex, (val >> 8) & 0x3); 2138192873Sweongyo USETW(req.wLength, sizeof(uint32_t)); 2139192873Sweongyo 2140192873Sweongyo return (urtw_do_request(sc, &req, &data)); 2141192873Sweongyo} 2142192873Sweongyo 2143193045Sthompsastatic usb_error_t 2144196970Sphkurtw_get_macaddr(struct urtw_softc *sc) 2145192873Sweongyo{ 2146196970Sphk uint32_t data; 2147193045Sthompsa usb_error_t error; 2148192873Sweongyo 2149196970Sphk error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data); 2150196970Sphk if (error != 0) 2151192873Sweongyo goto fail; 2152196970Sphk sc->sc_bssid[0] = data & 0xff; 2153196970Sphk sc->sc_bssid[1] = (data & 0xff00) >> 8; 2154196970Sphk error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data); 2155196970Sphk if (error != 0) 2156192873Sweongyo goto fail; 2157196970Sphk sc->sc_bssid[2] = data & 0xff; 2158196970Sphk sc->sc_bssid[3] = (data & 0xff00) >> 8; 2159196970Sphk error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data); 2160196970Sphk if (error != 0) 2161192873Sweongyo goto fail; 2162196970Sphk sc->sc_bssid[4] = data & 0xff; 2163196970Sphk sc->sc_bssid[5] = (data & 0xff00) >> 8; 2164192873Sweongyofail: 2165192873Sweongyo return (error); 2166192873Sweongyo} 2167192873Sweongyo 2168193045Sthompsastatic usb_error_t 2169196970Sphkurtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data) 2170192873Sweongyo{ 2171196970Sphk#define URTW_READCMD_LEN 3 2172196970Sphk int addrlen, i; 2173196970Sphk int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 }; 2174193045Sthompsa usb_error_t error; 2175192873Sweongyo 2176196970Sphk /* NB: make sure the buffer is initialized */ 2177196970Sphk *data = 0; 2178192873Sweongyo 2179196970Sphk /* enable EPROM programming */ 2180196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE); 2181196970Sphk DELAY(URTW_EPROM_DELAY); 2182192873Sweongyo 2183196970Sphk error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE); 2184196970Sphk if (error != 0) 2185192873Sweongyo goto fail; 2186196970Sphk error = urtw_eprom_ck(sc); 2187196970Sphk if (error != 0) 2188192873Sweongyo goto fail; 2189196970Sphk error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN); 2190192873Sweongyo if (error != 0) 2191192873Sweongyo goto fail; 2192196970Sphk if (sc->sc_epromtype == URTW_EEPROM_93C56) { 2193196970Sphk addrlen = 8; 2194196970Sphk addrstr[0] = addr & (1 << 7); 2195196970Sphk addrstr[1] = addr & (1 << 6); 2196196970Sphk addrstr[2] = addr & (1 << 5); 2197196970Sphk addrstr[3] = addr & (1 << 4); 2198196970Sphk addrstr[4] = addr & (1 << 3); 2199196970Sphk addrstr[5] = addr & (1 << 2); 2200196970Sphk addrstr[6] = addr & (1 << 1); 2201196970Sphk addrstr[7] = addr & (1 << 0); 2202196970Sphk } else { 2203196970Sphk addrlen=6; 2204196970Sphk addrstr[0] = addr & (1 << 5); 2205196970Sphk addrstr[1] = addr & (1 << 4); 2206196970Sphk addrstr[2] = addr & (1 << 3); 2207196970Sphk addrstr[3] = addr & (1 << 2); 2208196970Sphk addrstr[4] = addr & (1 << 1); 2209196970Sphk addrstr[5] = addr & (1 << 0); 2210196970Sphk } 2211196970Sphk error = urtw_eprom_sendbits(sc, addrstr, addrlen); 2212192873Sweongyo if (error != 0) 2213192873Sweongyo goto fail; 2214196970Sphk 2215196970Sphk error = urtw_eprom_writebit(sc, 0); 2216192873Sweongyo if (error != 0) 2217192873Sweongyo goto fail; 2218192873Sweongyo 2219196970Sphk for (i = 0; i < 16; i++) { 2220196970Sphk error = urtw_eprom_ck(sc); 2221196970Sphk if (error != 0) 2222196970Sphk goto fail; 2223196970Sphk error = urtw_eprom_readbit(sc, &data16); 2224196970Sphk if (error != 0) 2225196970Sphk goto fail; 2226192873Sweongyo 2227196970Sphk (*data) |= (data16 << (15 - i)); 2228192873Sweongyo } 2229192873Sweongyo 2230196970Sphk error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE); 2231196970Sphk if (error != 0) 2232192873Sweongyo goto fail; 2233196970Sphk error = urtw_eprom_ck(sc); 2234196970Sphk if (error != 0) 2235192873Sweongyo goto fail; 2236192873Sweongyo 2237196970Sphk /* now disable EPROM programming */ 2238196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE); 2239192873Sweongyofail: 2240192873Sweongyo return (error); 2241196970Sphk#undef URTW_READCMD_LEN 2242192873Sweongyo} 2243192873Sweongyo 2244193045Sthompsastatic usb_error_t 2245196970Sphkurtw_eprom_cs(struct urtw_softc *sc, int able) 2246192873Sweongyo{ 2247196970Sphk uint8_t data; 2248193045Sthompsa usb_error_t error; 2249192873Sweongyo 2250196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data); 2251196970Sphk if (able == URTW_EPROM_ENABLE) 2252196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS); 2253196970Sphk else 2254196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS); 2255196970Sphk DELAY(URTW_EPROM_DELAY); 2256192873Sweongyofail: 2257192873Sweongyo return (error); 2258192873Sweongyo} 2259192873Sweongyo 2260193045Sthompsastatic usb_error_t 2261196970Sphkurtw_eprom_ck(struct urtw_softc *sc) 2262192873Sweongyo{ 2263192873Sweongyo uint8_t data; 2264193045Sthompsa usb_error_t error; 2265192873Sweongyo 2266196970Sphk /* masking */ 2267196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data); 2268196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK); 2269196970Sphk DELAY(URTW_EPROM_DELAY); 2270196970Sphk /* unmasking */ 2271196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data); 2272196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK); 2273196970Sphk DELAY(URTW_EPROM_DELAY); 2274192873Sweongyofail: 2275192873Sweongyo return (error); 2276192873Sweongyo} 2277192873Sweongyo 2278193045Sthompsastatic usb_error_t 2279196970Sphkurtw_eprom_readbit(struct urtw_softc *sc, int16_t *data) 2280192873Sweongyo{ 2281196970Sphk uint8_t data8; 2282193045Sthompsa usb_error_t error; 2283192873Sweongyo 2284196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data8); 2285196970Sphk *data = (data8 & URTW_EPROM_READBIT) ? 1 : 0; 2286196970Sphk DELAY(URTW_EPROM_DELAY); 2287192873Sweongyo 2288192873Sweongyofail: 2289192873Sweongyo return (error); 2290192873Sweongyo} 2291192873Sweongyo 2292193045Sthompsastatic usb_error_t 2293196970Sphkurtw_eprom_writebit(struct urtw_softc *sc, int16_t bit) 2294192873Sweongyo{ 2295192873Sweongyo uint8_t data; 2296193045Sthompsa usb_error_t error; 2297192873Sweongyo 2298196970Sphk urtw_read8_m(sc, URTW_EPROM_CMD, &data); 2299196970Sphk if (bit != 0) 2300196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT); 2301196970Sphk else 2302196970Sphk urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT); 2303196970Sphk DELAY(URTW_EPROM_DELAY); 2304192873Sweongyofail: 2305192873Sweongyo return (error); 2306192873Sweongyo} 2307192873Sweongyo 2308193045Sthompsastatic usb_error_t 2309196970Sphkurtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen) 2310192873Sweongyo{ 2311196970Sphk int i = 0; 2312196970Sphk usb_error_t error = 0; 2313192873Sweongyo 2314196970Sphk for (i = 0; i < buflen; i++) { 2315196970Sphk error = urtw_eprom_writebit(sc, buf[i]); 2316196970Sphk if (error != 0) 2317196970Sphk goto fail; 2318196970Sphk error = urtw_eprom_ck(sc); 2319196970Sphk if (error != 0) 2320196970Sphk goto fail; 2321192873Sweongyo } 2322192873Sweongyofail: 2323192873Sweongyo return (error); 2324192873Sweongyo} 2325192873Sweongyo 2326192873Sweongyo 2327193045Sthompsastatic usb_error_t 2328192873Sweongyourtw_get_txpwr(struct urtw_softc *sc) 2329192873Sweongyo{ 2330192873Sweongyo int i, j; 2331192873Sweongyo uint32_t data; 2332193045Sthompsa usb_error_t error; 2333192873Sweongyo 2334192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data); 2335192873Sweongyo if (error != 0) 2336192873Sweongyo goto fail; 2337192873Sweongyo sc->sc_txpwr_cck_base = data & 0xf; 2338192873Sweongyo sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf; 2339192873Sweongyo 2340192873Sweongyo for (i = 1, j = 0; i < 6; i += 2, j++) { 2341192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data); 2342192873Sweongyo if (error != 0) 2343192873Sweongyo goto fail; 2344192873Sweongyo sc->sc_txpwr_cck[i] = data & 0xf; 2345192873Sweongyo sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8; 2346192873Sweongyo sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4; 2347192873Sweongyo sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12; 2348192873Sweongyo } 2349192873Sweongyo for (i = 1, j = 0; i < 4; i += 2, j++) { 2350192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data); 2351192873Sweongyo if (error != 0) 2352192873Sweongyo goto fail; 2353192873Sweongyo sc->sc_txpwr_cck[i + 6] = data & 0xf; 2354192873Sweongyo sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8; 2355192873Sweongyo sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4; 2356192873Sweongyo sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12; 2357192873Sweongyo } 2358192873Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 2359192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2, &data); 2360192873Sweongyo if (error != 0) 2361192873Sweongyo goto fail; 2362192873Sweongyo sc->sc_txpwr_cck[1 + 6 + 4] = data & 0xf; 2363192873Sweongyo sc->sc_txpwr_ofdm[1 + 6 + 4] = (data & 0xf0) >> 4; 2364192873Sweongyo error = urtw_eprom_read32(sc, 0x0a, &data); 2365192873Sweongyo if (error != 0) 2366192873Sweongyo goto fail; 2367192873Sweongyo sc->sc_txpwr_cck[2 + 6 + 4] = data & 0xf; 2368192873Sweongyo sc->sc_txpwr_ofdm[2 + 6 + 4] = (data & 0xf0) >> 4; 2369192873Sweongyo error = urtw_eprom_read32(sc, 0x1c, &data); 2370192873Sweongyo if (error != 0) 2371192873Sweongyo goto fail; 2372192873Sweongyo sc->sc_txpwr_cck[3 + 6 + 4] = data & 0xf; 2373192873Sweongyo sc->sc_txpwr_cck[3 + 6 + 4 + 1] = (data & 0xf00) >> 8; 2374192873Sweongyo sc->sc_txpwr_ofdm[3 + 6 + 4] = (data & 0xf0) >> 4; 2375192873Sweongyo sc->sc_txpwr_ofdm[3 + 6 + 4 + 1] = (data & 0xf000) >> 12; 2376192873Sweongyo } else { 2377192873Sweongyo for (i = 1, j = 0; i < 4; i += 2, j++) { 2378192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j, 2379192873Sweongyo &data); 2380192873Sweongyo if (error != 0) 2381192873Sweongyo goto fail; 2382192873Sweongyo sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf; 2383192873Sweongyo sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8; 2384192873Sweongyo sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4; 2385192873Sweongyo sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = (data & 0xf000) >> 12; 2386192873Sweongyo } 2387192873Sweongyo } 2388192873Sweongyofail: 2389192873Sweongyo return (error); 2390192873Sweongyo} 2391192873Sweongyo 2392192873Sweongyo 2393193045Sthompsastatic usb_error_t 2394192873Sweongyourtw_get_rfchip(struct urtw_softc *sc) 2395192873Sweongyo{ 2396192873Sweongyo int ret; 2397192873Sweongyo uint8_t data8; 2398192873Sweongyo uint32_t data; 2399193045Sthompsa usb_error_t error; 2400192873Sweongyo 2401198194Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 2402198194Sweongyo urtw_read8_m(sc, 0xe1, &data8); 2403198194Sweongyo switch (data8) { 2404198194Sweongyo case 0: 2405198194Sweongyo sc->sc_flags |= URTW_RTL8187B_REV_B; 2406198194Sweongyo break; 2407198194Sweongyo case 1: 2408198194Sweongyo sc->sc_flags |= URTW_RTL8187B_REV_D; 2409198194Sweongyo break; 2410198194Sweongyo case 2: 2411198194Sweongyo sc->sc_flags |= URTW_RTL8187B_REV_E; 2412198194Sweongyo break; 2413198194Sweongyo default: 2414198194Sweongyo device_printf(sc->sc_dev, "unknown type: %#x\n", data8); 2415198194Sweongyo sc->sc_flags |= URTW_RTL8187B_REV_B; 2416198194Sweongyo break; 2417198194Sweongyo } 2418198194Sweongyo } else { 2419198194Sweongyo urtw_read32_m(sc, URTW_TX_CONF, &data); 2420198194Sweongyo switch (data & URTW_TX_HWMASK) { 2421198194Sweongyo case URTW_TX_R8187vD_B: 2422198194Sweongyo sc->sc_flags |= URTW_RTL8187B; 2423198194Sweongyo break; 2424198194Sweongyo case URTW_TX_R8187vD: 2425198194Sweongyo break; 2426198194Sweongyo default: 2427198194Sweongyo device_printf(sc->sc_dev, "unknown RTL8187L type: %#x\n", 2428198194Sweongyo data & URTW_TX_HWMASK); 2429198194Sweongyo break; 2430198194Sweongyo } 2431198194Sweongyo } 2432198194Sweongyo 2433192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data); 2434192873Sweongyo if (error != 0) 2435192873Sweongyo goto fail; 2436192873Sweongyo switch (data & 0xff) { 2437192873Sweongyo case URTW_EPROM_RFCHIPID_RTL8225U: 2438192873Sweongyo error = urtw_8225_isv2(sc, &ret); 2439192873Sweongyo if (error != 0) 2440192873Sweongyo goto fail; 2441192873Sweongyo if (ret == 0) { 2442192873Sweongyo sc->sc_rf_init = urtw_8225_rf_init; 2443192873Sweongyo sc->sc_rf_set_sens = urtw_8225_rf_set_sens; 2444192873Sweongyo sc->sc_rf_set_chan = urtw_8225_rf_set_chan; 2445192873Sweongyo sc->sc_rf_stop = urtw_8225_rf_stop; 2446192873Sweongyo } else { 2447192873Sweongyo sc->sc_rf_init = urtw_8225v2_rf_init; 2448192873Sweongyo sc->sc_rf_set_chan = urtw_8225v2_rf_set_chan; 2449192873Sweongyo sc->sc_rf_stop = urtw_8225_rf_stop; 2450192873Sweongyo } 2451192873Sweongyo sc->sc_max_sens = URTW_8225_RF_MAX_SENS; 2452192873Sweongyo sc->sc_sens = URTW_8225_RF_DEF_SENS; 2453192873Sweongyo break; 2454192873Sweongyo case URTW_EPROM_RFCHIPID_RTL8225Z2: 2455192873Sweongyo sc->sc_rf_init = urtw_8225v2b_rf_init; 2456192873Sweongyo sc->sc_rf_set_chan = urtw_8225v2b_rf_set_chan; 2457192873Sweongyo sc->sc_max_sens = URTW_8225_RF_MAX_SENS; 2458192873Sweongyo sc->sc_sens = URTW_8225_RF_DEF_SENS; 2459192873Sweongyo sc->sc_rf_stop = urtw_8225_rf_stop; 2460192873Sweongyo break; 2461192873Sweongyo default: 2462259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 2463259456Shselasky "unsupported RF chip %d\n", data & 0xff); 2464259456Shselasky error = USB_ERR_INVAL; 2465259456Shselasky goto fail; 2466192873Sweongyo } 2467192873Sweongyo 2468192873Sweongyo device_printf(sc->sc_dev, "%s rf %s hwrev %s\n", 2469192873Sweongyo (sc->sc_flags & URTW_RTL8187B) ? "rtl8187b" : "rtl8187l", 2470192873Sweongyo ((data & 0xff) == URTW_EPROM_RFCHIPID_RTL8225U) ? "rtl8225u" : 2471192873Sweongyo "rtl8225z2", 2472192873Sweongyo (sc->sc_flags & URTW_RTL8187B) ? ((data8 == 0) ? "b" : 2473192873Sweongyo (data8 == 1) ? "d" : "e") : "none"); 2474192873Sweongyo 2475192873Sweongyofail: 2476192873Sweongyo return (error); 2477192873Sweongyo} 2478192873Sweongyo 2479192873Sweongyo 2480193045Sthompsastatic usb_error_t 2481192873Sweongyourtw_led_init(struct urtw_softc *sc) 2482192873Sweongyo{ 2483192873Sweongyo uint32_t rev; 2484193045Sthompsa usb_error_t error; 2485192873Sweongyo 2486192873Sweongyo urtw_read8_m(sc, URTW_PSR, &sc->sc_psr); 2487192873Sweongyo error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev); 2488192873Sweongyo if (error != 0) 2489192873Sweongyo goto fail; 2490192873Sweongyo 2491192873Sweongyo switch (rev & URTW_EPROM_CID_MASK) { 2492192873Sweongyo case URTW_EPROM_CID_ALPHA0: 2493192873Sweongyo sc->sc_strategy = URTW_SW_LED_MODE1; 2494192873Sweongyo break; 2495192873Sweongyo case URTW_EPROM_CID_SERCOMM_PS: 2496192873Sweongyo sc->sc_strategy = URTW_SW_LED_MODE3; 2497192873Sweongyo break; 2498192873Sweongyo case URTW_EPROM_CID_HW_LED: 2499192873Sweongyo sc->sc_strategy = URTW_HW_LED; 2500192873Sweongyo break; 2501192873Sweongyo case URTW_EPROM_CID_RSVD0: 2502192873Sweongyo case URTW_EPROM_CID_RSVD1: 2503192873Sweongyo default: 2504192873Sweongyo sc->sc_strategy = URTW_SW_LED_MODE0; 2505192873Sweongyo break; 2506192873Sweongyo } 2507192873Sweongyo 2508192873Sweongyo sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0; 2509192873Sweongyo 2510192873Sweongyofail: 2511192873Sweongyo return (error); 2512192873Sweongyo} 2513192873Sweongyo 2514196970Sphk 2515193045Sthompsastatic usb_error_t 2516196970Sphkurtw_8225_rf_init(struct urtw_softc *sc) 2517196970Sphk{ 2518235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 2519196970Sphk int i; 2520196970Sphk uint16_t data; 2521196970Sphk usb_error_t error; 2522196970Sphk 2523196970Sphk error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON); 2524196970Sphk if (error) 2525196970Sphk goto fail; 2526196970Sphk 2527196970Sphk error = urtw_8225_usb_init(sc); 2528196970Sphk if (error) 2529196970Sphk goto fail; 2530196970Sphk 2531196970Sphk urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008); 2532196970Sphk urtw_read16_m(sc, URTW_BRSR, &data); /* XXX ??? */ 2533196970Sphk urtw_write16_m(sc, URTW_BRSR, 0xffff); 2534196970Sphk urtw_write32_m(sc, URTW_RF_PARA, 0x100044); 2535196970Sphk 2536196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 2537196970Sphk if (error) 2538196970Sphk goto fail; 2539196970Sphk urtw_write8_m(sc, URTW_CONFIG3, 0x44); 2540196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 2541196970Sphk if (error) 2542196970Sphk goto fail; 2543196970Sphk 2544196970Sphk error = urtw_8185_rf_pins_enable(sc); 2545196970Sphk if (error) 2546196970Sphk goto fail; 2547196970Sphk usb_pause_mtx(&sc->sc_mtx, 1000); 2548196970Sphk 2549196970Sphk for (i = 0; i < N(urtw_8225_rf_part1); i++) { 2550196970Sphk urtw_8225_write(sc, urtw_8225_rf_part1[i].reg, 2551196970Sphk urtw_8225_rf_part1[i].val); 2552196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2553196970Sphk } 2554196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 2555196970Sphk urtw_8225_write(sc, 2556196970Sphk URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1); 2557196970Sphk usb_pause_mtx(&sc->sc_mtx, 200); 2558196970Sphk urtw_8225_write(sc, 2559196970Sphk URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2); 2560196970Sphk usb_pause_mtx(&sc->sc_mtx, 200); 2561196970Sphk urtw_8225_write(sc, 2562196970Sphk URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC3); 2563196970Sphk 2564196970Sphk for (i = 0; i < 95; i++) { 2565196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1)); 2566196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, urtw_8225_rxgain[i]); 2567196970Sphk } 2568196970Sphk 2569196970Sphk urtw_8225_write(sc, 2570196970Sphk URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC4); 2571196970Sphk urtw_8225_write(sc, 2572196970Sphk URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC5); 2573196970Sphk 2574196970Sphk for (i = 0; i < 128; i++) { 2575196970Sphk urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]); 2576196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2577196970Sphk urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80); 2578196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2579196970Sphk } 2580196970Sphk 2581196970Sphk for (i = 0; i < N(urtw_8225_rf_part2); i++) { 2582196970Sphk urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg, 2583196970Sphk urtw_8225_rf_part2[i].val); 2584196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2585196970Sphk } 2586196970Sphk 2587196970Sphk error = urtw_8225_setgain(sc, 4); 2588196970Sphk if (error) 2589196970Sphk goto fail; 2590196970Sphk 2591196970Sphk for (i = 0; i < N(urtw_8225_rf_part3); i++) { 2592196970Sphk urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg, 2593196970Sphk urtw_8225_rf_part3[i].val); 2594196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2595196970Sphk } 2596196970Sphk 2597196970Sphk urtw_write8_m(sc, URTW_TESTR, 0x0d); 2598196970Sphk 2599196970Sphk error = urtw_8225_set_txpwrlvl(sc, 1); 2600196970Sphk if (error) 2601196970Sphk goto fail; 2602196970Sphk 2603196970Sphk urtw_8187_write_phy_cck(sc, 0x10, 0x9b); 2604196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2605196970Sphk urtw_8187_write_phy_ofdm(sc, 0x26, 0x90); 2606196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2607196970Sphk 2608196970Sphk /* TX ant A, 0x0 for B */ 2609196970Sphk error = urtw_8185_tx_antenna(sc, 0x3); 2610196970Sphk if (error) 2611196970Sphk goto fail; 2612196970Sphk urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002); 2613196970Sphk 2614196970Sphk error = urtw_8225_rf_set_chan(sc, 1); 2615196970Sphkfail: 2616196970Sphk return (error); 2617196970Sphk#undef N 2618196970Sphk} 2619196970Sphk 2620196970Sphkstatic usb_error_t 2621192873Sweongyourtw_8185_rf_pins_enable(struct urtw_softc *sc) 2622192873Sweongyo{ 2623193045Sthompsa usb_error_t error = 0; 2624192873Sweongyo 2625192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7); 2626192873Sweongyofail: 2627192873Sweongyo return (error); 2628192873Sweongyo} 2629192873Sweongyo 2630193045Sthompsastatic usb_error_t 2631192873Sweongyourtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant) 2632192873Sweongyo{ 2633193045Sthompsa usb_error_t error; 2634192873Sweongyo 2635192873Sweongyo urtw_write8_m(sc, URTW_TX_ANTENNA, ant); 2636194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 1); 2637192873Sweongyofail: 2638192873Sweongyo return (error); 2639192873Sweongyo} 2640192873Sweongyo 2641193045Sthompsastatic usb_error_t 2642192873Sweongyourtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data) 2643192873Sweongyo{ 2644192873Sweongyo 2645192873Sweongyo data = data & 0xff; 2646192873Sweongyo return urtw_8187_write_phy(sc, addr, data); 2647192873Sweongyo} 2648192873Sweongyo 2649193045Sthompsastatic usb_error_t 2650192873Sweongyourtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data) 2651192873Sweongyo{ 2652192873Sweongyo 2653192873Sweongyo data = data & 0xff; 2654192873Sweongyo return urtw_8187_write_phy(sc, addr, data | 0x10000); 2655192873Sweongyo} 2656192873Sweongyo 2657193045Sthompsastatic usb_error_t 2658192873Sweongyourtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data) 2659192873Sweongyo{ 2660192873Sweongyo uint32_t phyw; 2661193045Sthompsa usb_error_t error; 2662192873Sweongyo 2663192873Sweongyo phyw = ((data << 8) | (addr | 0x80)); 2664192873Sweongyo urtw_write8_m(sc, URTW_PHY_MAGIC4, ((phyw & 0xff000000) >> 24)); 2665192873Sweongyo urtw_write8_m(sc, URTW_PHY_MAGIC3, ((phyw & 0x00ff0000) >> 16)); 2666192873Sweongyo urtw_write8_m(sc, URTW_PHY_MAGIC2, ((phyw & 0x0000ff00) >> 8)); 2667192873Sweongyo urtw_write8_m(sc, URTW_PHY_MAGIC1, ((phyw & 0x000000ff))); 2668194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 1); 2669192873Sweongyofail: 2670192873Sweongyo return (error); 2671192873Sweongyo} 2672192873Sweongyo 2673193045Sthompsastatic usb_error_t 2674192873Sweongyourtw_8225_setgain(struct urtw_softc *sc, int16_t gain) 2675192873Sweongyo{ 2676193045Sthompsa usb_error_t error; 2677192873Sweongyo 2678192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]); 2679192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]); 2680192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]); 2681192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]); 2682192873Sweongyofail: 2683192873Sweongyo return (error); 2684192873Sweongyo} 2685192873Sweongyo 2686193045Sthompsastatic usb_error_t 2687192873Sweongyourtw_8225_usb_init(struct urtw_softc *sc) 2688192873Sweongyo{ 2689192873Sweongyo uint8_t data; 2690193045Sthompsa usb_error_t error; 2691192873Sweongyo 2692192873Sweongyo urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0); 2693192873Sweongyo urtw_write8_m(sc, URTW_GPIO, 0); 2694192873Sweongyo error = urtw_read8e(sc, 0x53, &data); 2695192873Sweongyo if (error) 2696192873Sweongyo goto fail; 2697192873Sweongyo error = urtw_write8e(sc, 0x53, data | (1 << 7)); 2698192873Sweongyo if (error) 2699192873Sweongyo goto fail; 2700192873Sweongyo urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4); 2701192873Sweongyo urtw_write8_m(sc, URTW_GPIO, 0x20); 2702192873Sweongyo urtw_write8_m(sc, URTW_GP_ENABLE, 0); 2703192873Sweongyo 2704192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80); 2705192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80); 2706192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80); 2707192873Sweongyo 2708194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 500); 2709192873Sweongyofail: 2710192873Sweongyo return (error); 2711192873Sweongyo} 2712192873Sweongyo 2713193045Sthompsastatic usb_error_t 2714192873Sweongyourtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data) 2715192873Sweongyo{ 2716192873Sweongyo uint16_t d80, d82, d84; 2717193045Sthompsa usb_error_t error; 2718192873Sweongyo 2719192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80); 2720192873Sweongyo d80 &= URTW_RF_PINS_MAGIC1; 2721192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82); 2722192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84); 2723192873Sweongyo d84 &= URTW_RF_PINS_MAGIC2; 2724192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | URTW_RF_PINS_MAGIC3); 2725192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | URTW_RF_PINS_MAGIC3); 2726192873Sweongyo DELAY(10); 2727192873Sweongyo 2728192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 2729192873Sweongyo DELAY(2); 2730192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80); 2731192873Sweongyo DELAY(10); 2732192873Sweongyo 2733192873Sweongyo error = urtw_8225_write_s16(sc, addr, 0x8225, &data); 2734192873Sweongyo if (error != 0) 2735192873Sweongyo goto fail; 2736192873Sweongyo 2737192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 2738192873Sweongyo DELAY(10); 2739192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 2740192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84); 2741194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 2); 2742192873Sweongyofail: 2743192873Sweongyo return (error); 2744192873Sweongyo} 2745192873Sweongyo 2746193045Sthompsastatic usb_error_t 2747192873Sweongyourtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index, 2748192873Sweongyo uint16_t *data) 2749192873Sweongyo{ 2750259454Shselasky uint8_t buf[2]; 2751192873Sweongyo uint16_t data16; 2752259454Shselasky struct usb_device_request req; 2753193045Sthompsa usb_error_t error = 0; 2754192873Sweongyo 2755192873Sweongyo data16 = *data; 2756192873Sweongyo 2757259454Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 2758259454Shselasky req.bRequest = URTW_8187_SETREGS_REQ; 2759259454Shselasky USETW(req.wValue, addr); 2760259454Shselasky USETW(req.wIndex, index); 2761259454Shselasky USETW(req.wLength, sizeof(uint16_t)); 2762192873Sweongyo buf[0] = (data16 & 0x00ff); 2763192873Sweongyo buf[1] = (data16 & 0xff00) >> 8; 2764192873Sweongyo 2765259454Shselasky error = urtw_do_request(sc, &req, buf); 2766192873Sweongyo 2767259454Shselasky return (error); 2768192873Sweongyo} 2769192873Sweongyo 2770193045Sthompsastatic usb_error_t 2771192873Sweongyourtw_8225_rf_set_chan(struct urtw_softc *sc, int chan) 2772192873Sweongyo{ 2773193045Sthompsa usb_error_t error; 2774192873Sweongyo 2775192873Sweongyo error = urtw_8225_set_txpwrlvl(sc, chan); 2776192873Sweongyo if (error) 2777192873Sweongyo goto fail; 2778192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]); 2779194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 10); 2780192873Sweongyofail: 2781192873Sweongyo return (error); 2782192873Sweongyo} 2783192873Sweongyo 2784193045Sthompsastatic usb_error_t 2785192873Sweongyourtw_8225_rf_set_sens(struct urtw_softc *sc, int sens) 2786192873Sweongyo{ 2787193045Sthompsa usb_error_t error; 2788192873Sweongyo 2789192873Sweongyo if (sens < 0 || sens > 6) 2790192873Sweongyo return -1; 2791192873Sweongyo 2792192873Sweongyo if (sens > 4) 2793192873Sweongyo urtw_8225_write(sc, 2794192873Sweongyo URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC1); 2795192873Sweongyo else 2796192873Sweongyo urtw_8225_write(sc, 2797192873Sweongyo URTW_8225_ADDR_C_MAGIC, URTW_8225_ADDR_C_DATA_MAGIC2); 2798192873Sweongyo 2799192873Sweongyo sens = 6 - sens; 2800192873Sweongyo error = urtw_8225_setgain(sc, sens); 2801192873Sweongyo if (error) 2802192873Sweongyo goto fail; 2803192873Sweongyo 2804192873Sweongyo urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[sens]); 2805192873Sweongyo 2806192873Sweongyofail: 2807192873Sweongyo return (error); 2808192873Sweongyo} 2809192873Sweongyo 2810196970Sphkstatic usb_error_t 2811196970Sphkurtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan) 2812192873Sweongyo{ 2813196970Sphk int i, idx, set; 2814196970Sphk uint8_t *cck_pwltable; 2815196970Sphk uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max; 2816196970Sphk uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 2817196970Sphk uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 2818193045Sthompsa usb_error_t error; 2819192873Sweongyo 2820196970Sphk cck_pwrlvl_max = 11; 2821196970Sphk ofdm_pwrlvl_max = 25; /* 12 -> 25 */ 2822196970Sphk ofdm_pwrlvl_min = 10; 2823192873Sweongyo 2824196970Sphk /* CCK power setting */ 2825196970Sphk cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl; 2826196970Sphk idx = cck_pwrlvl % 6; 2827196970Sphk set = cck_pwrlvl / 6; 2828196970Sphk cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 : 2829196970Sphk urtw_8225_txpwr_cck; 2830192873Sweongyo 2831196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_CCK, 2832196970Sphk urtw_8225_tx_gain_cck_ofdm[set] >> 1); 2833196970Sphk for (i = 0; i < 8; i++) { 2834196970Sphk urtw_8187_write_phy_cck(sc, 0x44 + i, 2835196970Sphk cck_pwltable[idx * 8 + i]); 2836192873Sweongyo } 2837196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 2838192873Sweongyo 2839196970Sphk /* OFDM power setting */ 2840196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ? 2841196970Sphk ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min; 2842196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 2843192873Sweongyo 2844196970Sphk idx = ofdm_pwrlvl % 6; 2845196970Sphk set = ofdm_pwrlvl / 6; 2846192873Sweongyo 2847196970Sphk error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON); 2848196970Sphk if (error) 2849196970Sphk goto fail; 2850196970Sphk urtw_8187_write_phy_ofdm(sc, 2, 0x42); 2851196970Sphk urtw_8187_write_phy_ofdm(sc, 6, 0); 2852196970Sphk urtw_8187_write_phy_ofdm(sc, 8, 0); 2853192873Sweongyo 2854196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 2855196970Sphk urtw_8225_tx_gain_cck_ofdm[set] >> 1); 2856196970Sphk urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]); 2857196970Sphk urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]); 2858194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 1); 2859192873Sweongyofail: 2860192873Sweongyo return (error); 2861192873Sweongyo} 2862192873Sweongyo 2863196970Sphk 2864193045Sthompsastatic usb_error_t 2865196970Sphkurtw_8225_rf_stop(struct urtw_softc *sc) 2866192873Sweongyo{ 2867196970Sphk uint8_t data; 2868193045Sthompsa usb_error_t error; 2869192873Sweongyo 2870196970Sphk urtw_8225_write(sc, 0x4, 0x1f); 2871192873Sweongyo 2872196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 2873196970Sphk if (error) 2874196970Sphk goto fail; 2875192873Sweongyo 2876196970Sphk urtw_read8_m(sc, URTW_CONFIG3, &data); 2877196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 2878196970Sphk if (sc->sc_flags & URTW_RTL8187B) { 2879196970Sphk urtw_write32_m(sc, URTW_ANAPARAM2, 2880196970Sphk URTW_8187B_8225_ANAPARAM2_OFF); 2881196970Sphk urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_OFF); 2882196970Sphk urtw_write32_m(sc, URTW_ANAPARAM3, 2883196970Sphk URTW_8187B_8225_ANAPARAM3_OFF); 2884196970Sphk } else { 2885196970Sphk urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8225_ANAPARAM2_OFF); 2886196970Sphk urtw_write32_m(sc, URTW_ANAPARAM, URTW_8225_ANAPARAM_OFF); 2887196970Sphk } 2888192873Sweongyo 2889196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 2890196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 2891192873Sweongyo if (error) 2892192873Sweongyo goto fail; 2893192873Sweongyo 2894192873Sweongyofail: 2895192873Sweongyo return (error); 2896192873Sweongyo} 2897192873Sweongyo 2898193045Sthompsastatic usb_error_t 2899192873Sweongyourtw_8225v2_rf_init(struct urtw_softc *sc) 2900192873Sweongyo{ 2901235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 2902192873Sweongyo int i; 2903192873Sweongyo uint16_t data; 2904192873Sweongyo uint32_t data32; 2905193045Sthompsa usb_error_t error; 2906192873Sweongyo 2907192873Sweongyo error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON); 2908192873Sweongyo if (error) 2909192873Sweongyo goto fail; 2910192873Sweongyo 2911192873Sweongyo error = urtw_8225_usb_init(sc); 2912192873Sweongyo if (error) 2913192873Sweongyo goto fail; 2914192873Sweongyo 2915192873Sweongyo urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008); 2916192873Sweongyo urtw_read16_m(sc, URTW_BRSR, &data); /* XXX ??? */ 2917192873Sweongyo urtw_write16_m(sc, URTW_BRSR, 0xffff); 2918192873Sweongyo urtw_write32_m(sc, URTW_RF_PARA, 0x100044); 2919192873Sweongyo 2920192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 2921192873Sweongyo if (error) 2922192873Sweongyo goto fail; 2923192873Sweongyo urtw_write8_m(sc, URTW_CONFIG3, 0x44); 2924192873Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 2925192873Sweongyo if (error) 2926192873Sweongyo goto fail; 2927192873Sweongyo 2928192873Sweongyo error = urtw_8185_rf_pins_enable(sc); 2929192873Sweongyo if (error) 2930192873Sweongyo goto fail; 2931192873Sweongyo 2932194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 500); 2933192873Sweongyo 2934196970Sphk for (i = 0; i < N(urtw_8225v2_rf_part1); i++) { 2935192873Sweongyo urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg, 2936192873Sweongyo urtw_8225v2_rf_part1[i].val); 2937192873Sweongyo } 2938194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 50); 2939192873Sweongyo 2940192873Sweongyo urtw_8225_write(sc, 2941192873Sweongyo URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC1); 2942192873Sweongyo 2943192873Sweongyo for (i = 0; i < 95; i++) { 2944192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1)); 2945192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 2946192873Sweongyo urtw_8225v2_rxgain[i]); 2947192873Sweongyo } 2948192873Sweongyo 2949192873Sweongyo urtw_8225_write(sc, 2950192873Sweongyo URTW_8225_ADDR_3_MAGIC, URTW_8225_ADDR_3_DATA_MAGIC1); 2951192873Sweongyo urtw_8225_write(sc, 2952192873Sweongyo URTW_8225_ADDR_5_MAGIC, URTW_8225_ADDR_5_DATA_MAGIC1); 2953192873Sweongyo urtw_8225_write(sc, 2954192873Sweongyo URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC2); 2955192873Sweongyo urtw_8225_write(sc, 2956192873Sweongyo URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1); 2957194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 100); 2958192873Sweongyo urtw_8225_write(sc, 2959192873Sweongyo URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2); 2960194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 100); 2961192873Sweongyo 2962192873Sweongyo error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32); 2963192873Sweongyo if (error != 0) 2964192873Sweongyo goto fail; 2965192873Sweongyo if (data32 != URTW_8225_ADDR_6_DATA_MAGIC1) 2966192873Sweongyo device_printf(sc->sc_dev, "expect 0xe6!! (0x%x)\n", data32); 2967192873Sweongyo if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2)) { 2968192873Sweongyo urtw_8225_write(sc, 2969192873Sweongyo URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC1); 2970194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 100); 2971192873Sweongyo urtw_8225_write(sc, 2972192873Sweongyo URTW_8225_ADDR_2_MAGIC, URTW_8225_ADDR_2_DATA_MAGIC2); 2973194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 50); 2974192873Sweongyo error = urtw_8225_read(sc, URTW_8225_ADDR_6_MAGIC, &data32); 2975192873Sweongyo if (error != 0) 2976192873Sweongyo goto fail; 2977192873Sweongyo if (!(data32 & URTW_8225_ADDR_6_DATA_MAGIC2)) 2978192873Sweongyo device_printf(sc->sc_dev, "RF calibration failed\n"); 2979192873Sweongyo } 2980194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 100); 2981192873Sweongyo 2982192873Sweongyo urtw_8225_write(sc, 2983192873Sweongyo URTW_8225_ADDR_0_MAGIC, URTW_8225_ADDR_0_DATA_MAGIC6); 2984192873Sweongyo for (i = 0; i < 128; i++) { 2985192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]); 2986192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80); 2987192873Sweongyo } 2988192873Sweongyo 2989196970Sphk for (i = 0; i < N(urtw_8225v2_rf_part2); i++) { 2990192873Sweongyo urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg, 2991192873Sweongyo urtw_8225v2_rf_part2[i].val); 2992192873Sweongyo } 2993192873Sweongyo 2994192873Sweongyo error = urtw_8225v2_setgain(sc, 4); 2995192873Sweongyo if (error) 2996192873Sweongyo goto fail; 2997192873Sweongyo 2998196970Sphk for (i = 0; i < N(urtw_8225v2_rf_part3); i++) { 2999192873Sweongyo urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg, 3000192873Sweongyo urtw_8225v2_rf_part3[i].val); 3001192873Sweongyo } 3002192873Sweongyo 3003192873Sweongyo urtw_write8_m(sc, URTW_TESTR, 0x0d); 3004192873Sweongyo 3005192873Sweongyo error = urtw_8225v2_set_txpwrlvl(sc, 1); 3006192873Sweongyo if (error) 3007192873Sweongyo goto fail; 3008192873Sweongyo 3009192873Sweongyo urtw_8187_write_phy_cck(sc, 0x10, 0x9b); 3010192873Sweongyo urtw_8187_write_phy_ofdm(sc, 0x26, 0x90); 3011192873Sweongyo 3012192873Sweongyo /* TX ant A, 0x0 for B */ 3013192873Sweongyo error = urtw_8185_tx_antenna(sc, 0x3); 3014192873Sweongyo if (error) 3015192873Sweongyo goto fail; 3016192873Sweongyo urtw_write32_m(sc, URTW_HSSI_PARA, 0x3dc00002); 3017192873Sweongyo 3018192873Sweongyo error = urtw_8225_rf_set_chan(sc, 1); 3019192873Sweongyofail: 3020192873Sweongyo return (error); 3021196970Sphk#undef N 3022192873Sweongyo} 3023192873Sweongyo 3024193045Sthompsastatic usb_error_t 3025192873Sweongyourtw_8225v2_rf_set_chan(struct urtw_softc *sc, int chan) 3026192873Sweongyo{ 3027193045Sthompsa usb_error_t error; 3028192873Sweongyo 3029192873Sweongyo error = urtw_8225v2_set_txpwrlvl(sc, chan); 3030192873Sweongyo if (error) 3031192873Sweongyo goto fail; 3032192873Sweongyo 3033192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]); 3034194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 10); 3035192873Sweongyofail: 3036192873Sweongyo return (error); 3037192873Sweongyo} 3038192873Sweongyo 3039193045Sthompsastatic usb_error_t 3040192873Sweongyourtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data) 3041192873Sweongyo{ 3042192873Sweongyo int i; 3043192873Sweongyo int16_t bit; 3044192873Sweongyo uint8_t rlen = 12, wlen = 6; 3045192873Sweongyo uint16_t o1, o2, o3, tmp; 3046192873Sweongyo uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27; 3047192873Sweongyo uint32_t mask = 0x80000000, value = 0; 3048193045Sthompsa usb_error_t error; 3049192873Sweongyo 3050192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1); 3051192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2); 3052192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3); 3053192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | URTW_RF_PINS_MAGIC4); 3054192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | URTW_RF_PINS_MAGIC4); 3055192873Sweongyo o1 &= ~URTW_RF_PINS_MAGIC4; 3056192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN); 3057192873Sweongyo DELAY(5); 3058192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1); 3059192873Sweongyo DELAY(5); 3060192873Sweongyo 3061192873Sweongyo for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) { 3062192873Sweongyo bit = ((d2w & mask) != 0) ? 1 : 0; 3063192873Sweongyo 3064192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1); 3065192873Sweongyo DELAY(2); 3066192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 3067192873Sweongyo URTW_BB_HOST_BANG_CLK); 3068192873Sweongyo DELAY(2); 3069192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 3070192873Sweongyo URTW_BB_HOST_BANG_CLK); 3071192873Sweongyo DELAY(2); 3072192873Sweongyo mask = mask >> 1; 3073192873Sweongyo if (i == 2) 3074192873Sweongyo break; 3075192873Sweongyo bit = ((d2w & mask) != 0) ? 1 : 0; 3076192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 3077192873Sweongyo URTW_BB_HOST_BANG_CLK); 3078192873Sweongyo DELAY(2); 3079192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 3080192873Sweongyo URTW_BB_HOST_BANG_CLK); 3081192873Sweongyo DELAY(2); 3082192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1); 3083192873Sweongyo DELAY(1); 3084192873Sweongyo } 3085192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW | 3086192873Sweongyo URTW_BB_HOST_BANG_CLK); 3087192873Sweongyo DELAY(2); 3088192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW); 3089192873Sweongyo DELAY(2); 3090192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW); 3091192873Sweongyo DELAY(2); 3092192873Sweongyo 3093192873Sweongyo mask = 0x800; 3094192873Sweongyo for (i = 0; i < rlen; i++, mask = mask >> 1) { 3095192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 3096192873Sweongyo o1 | URTW_BB_HOST_BANG_RW); 3097192873Sweongyo DELAY(2); 3098192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 3099192873Sweongyo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 3100192873Sweongyo DELAY(2); 3101192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 3102192873Sweongyo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 3103192873Sweongyo DELAY(2); 3104192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 3105192873Sweongyo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 3106192873Sweongyo DELAY(2); 3107192873Sweongyo 3108192873Sweongyo urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp); 3109192873Sweongyo value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0); 3110192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 3111192873Sweongyo o1 | URTW_BB_HOST_BANG_RW); 3112192873Sweongyo DELAY(2); 3113192873Sweongyo } 3114192873Sweongyo 3115192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN | 3116192873Sweongyo URTW_BB_HOST_BANG_RW); 3117192873Sweongyo DELAY(2); 3118192873Sweongyo 3119192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2); 3120192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3); 3121192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_OUTPUT_MAGIC1); 3122192873Sweongyo 3123192873Sweongyo if (data != NULL) 3124192873Sweongyo *data = value; 3125192873Sweongyofail: 3126192873Sweongyo return (error); 3127192873Sweongyo} 3128192873Sweongyo 3129192873Sweongyo 3130193045Sthompsastatic usb_error_t 3131196970Sphkurtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan) 3132196970Sphk{ 3133196970Sphk int i; 3134196970Sphk uint8_t *cck_pwrtable; 3135196970Sphk uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10; 3136196970Sphk uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 3137196970Sphk uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 3138196970Sphk usb_error_t error; 3139196970Sphk 3140196970Sphk /* CCK power setting */ 3141196970Sphk cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl; 3142196970Sphk cck_pwrlvl += sc->sc_txpwr_cck_base; 3143196970Sphk cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl; 3144196970Sphk cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 : 3145196970Sphk urtw_8225v2_txpwr_cck; 3146196970Sphk 3147196970Sphk for (i = 0; i < 8; i++) 3148196970Sphk urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]); 3149196970Sphk 3150196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_CCK, 3151196970Sphk urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]); 3152196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3153196970Sphk 3154196970Sphk /* OFDM power setting */ 3155196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ? 3156196970Sphk ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min; 3157196970Sphk ofdm_pwrlvl += sc->sc_txpwr_ofdm_base; 3158196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 3159196970Sphk 3160196970Sphk error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON); 3161196970Sphk if (error) 3162196970Sphk goto fail; 3163196970Sphk 3164196970Sphk urtw_8187_write_phy_ofdm(sc, 2, 0x42); 3165196970Sphk urtw_8187_write_phy_ofdm(sc, 5, 0x0); 3166196970Sphk urtw_8187_write_phy_ofdm(sc, 6, 0x40); 3167196970Sphk urtw_8187_write_phy_ofdm(sc, 7, 0x0); 3168196970Sphk urtw_8187_write_phy_ofdm(sc, 8, 0x40); 3169196970Sphk 3170196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 3171196970Sphk urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]); 3172196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3173196970Sphkfail: 3174196970Sphk return (error); 3175196970Sphk} 3176196970Sphk 3177196970Sphkstatic usb_error_t 3178196970Sphkurtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain) 3179196970Sphk{ 3180196970Sphk uint8_t *gainp; 3181196970Sphk usb_error_t error; 3182196970Sphk 3183196970Sphk /* XXX for A? */ 3184196970Sphk gainp = urtw_8225v2_gain_bg; 3185196970Sphk urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]); 3186196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3187196970Sphk urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]); 3188196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3189196970Sphk urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]); 3190196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3191196970Sphk urtw_8187_write_phy_ofdm(sc, 0x21, 0x17); 3192196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3193196970Sphkfail: 3194196970Sphk return (error); 3195196970Sphk} 3196196970Sphk 3197196970Sphkstatic usb_error_t 3198192873Sweongyourtw_8225_isv2(struct urtw_softc *sc, int *ret) 3199192873Sweongyo{ 3200192873Sweongyo uint32_t data; 3201193045Sthompsa usb_error_t error; 3202192873Sweongyo 3203192873Sweongyo *ret = 1; 3204192873Sweongyo 3205192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, URTW_RF_PINS_MAGIC5); 3206192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, URTW_RF_PINS_MAGIC5); 3207192873Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, URTW_RF_PINS_MAGIC5); 3208194228Sthompsa usb_pause_mtx(&sc->sc_mtx, 500); 3209192873Sweongyo 3210192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 3211192873Sweongyo URTW_8225_ADDR_0_DATA_MAGIC1); 3212192873Sweongyo 3213192873Sweongyo error = urtw_8225_read(sc, URTW_8225_ADDR_8_MAGIC, &data); 3214192873Sweongyo if (error != 0) 3215192873Sweongyo goto fail; 3216192873Sweongyo if (data != URTW_8225_ADDR_8_DATA_MAGIC1) 3217192873Sweongyo *ret = 0; 3218192873Sweongyo else { 3219192873Sweongyo error = urtw_8225_read(sc, URTW_8225_ADDR_9_MAGIC, &data); 3220192873Sweongyo if (error != 0) 3221192873Sweongyo goto fail; 3222192873Sweongyo if (data != URTW_8225_ADDR_9_DATA_MAGIC1) 3223192873Sweongyo *ret = 0; 3224192873Sweongyo } 3225192873Sweongyo 3226192873Sweongyo urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 3227192873Sweongyo URTW_8225_ADDR_0_DATA_MAGIC2); 3228192873Sweongyofail: 3229192873Sweongyo return (error); 3230192873Sweongyo} 3231196970Sphk 3232196970Sphkstatic usb_error_t 3233196970Sphkurtw_8225v2b_rf_init(struct urtw_softc *sc) 3234196970Sphk{ 3235235000Shselasky#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) 3236196970Sphk int i; 3237198194Sweongyo uint8_t data8; 3238196970Sphk usb_error_t error; 3239196970Sphk 3240198194Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 3241198194Sweongyo if (error) 3242198194Sweongyo goto fail; 3243198194Sweongyo 3244198194Sweongyo /* 3245198194Sweongyo * initialize extra registers on 8187 3246198194Sweongyo */ 3247198194Sweongyo urtw_write16_m(sc, URTW_BRSR_8187B, 0xfff); 3248198194Sweongyo 3249198194Sweongyo /* retry limit */ 3250198194Sweongyo urtw_read8_m(sc, URTW_CW_CONF, &data8); 3251198194Sweongyo data8 |= URTW_CW_CONF_PERPACKET_RETRY; 3252198194Sweongyo urtw_write8_m(sc, URTW_CW_CONF, data8); 3253198194Sweongyo 3254198194Sweongyo /* TX AGC */ 3255198194Sweongyo urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8); 3256198194Sweongyo data8 |= URTW_TX_AGC_CTL_PERPACKET_GAIN; 3257198194Sweongyo urtw_write8_m(sc, URTW_TX_AGC_CTL, data8); 3258198194Sweongyo 3259198194Sweongyo /* Auto Rate Fallback Control */ 3260198194Sweongyo#define URTW_ARFR 0x1e0 3261198194Sweongyo urtw_write16_m(sc, URTW_ARFR, 0xfff); 3262198194Sweongyo urtw_read8_m(sc, URTW_RATE_FALLBACK, &data8); 3263198194Sweongyo urtw_write8_m(sc, URTW_RATE_FALLBACK, 3264198194Sweongyo data8 | URTW_RATE_FALLBACK_ENABLE); 3265198194Sweongyo 3266198194Sweongyo urtw_read8_m(sc, URTW_MSR, &data8); 3267198194Sweongyo urtw_write8_m(sc, URTW_MSR, data8 & 0xf3); 3268198194Sweongyo urtw_read8_m(sc, URTW_MSR, &data8); 3269198194Sweongyo urtw_write8_m(sc, URTW_MSR, data8 | URTW_MSR_LINK_ENEDCA); 3270198194Sweongyo urtw_write8_m(sc, URTW_ACM_CONTROL, sc->sc_acmctl); 3271198194Sweongyo 3272198194Sweongyo urtw_write16_m(sc, URTW_ATIM_WND, 2); 3273198194Sweongyo urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100); 3274198194Sweongyo#define URTW_FEMR_FOR_8187B 0x1d4 3275198194Sweongyo urtw_write16_m(sc, URTW_FEMR_FOR_8187B, 0xffff); 3276198194Sweongyo 3277198194Sweongyo /* led type */ 3278198194Sweongyo urtw_read8_m(sc, URTW_CONFIG1, &data8); 3279198194Sweongyo data8 = (data8 & 0x3f) | 0x80; 3280198194Sweongyo urtw_write8_m(sc, URTW_CONFIG1, data8); 3281198194Sweongyo 3282198194Sweongyo /* applying MAC address again. */ 3283198194Sweongyo urtw_write32_m(sc, URTW_MAC0, ((uint32_t *)sc->sc_bssid)[0]); 3284198194Sweongyo urtw_write16_m(sc, URTW_MAC4, ((uint32_t *)sc->sc_bssid)[1] & 0xffff); 3285198194Sweongyo 3286198194Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 3287198194Sweongyo if (error) 3288198194Sweongyo goto fail; 3289198194Sweongyo 3290198194Sweongyo urtw_write8_m(sc, URTW_WPA_CONFIG, 0); 3291198194Sweongyo 3292198194Sweongyo /* 3293198194Sweongyo * MAC configuration 3294198194Sweongyo */ 3295196970Sphk for (i = 0; i < N(urtw_8225v2b_rf_part1); i++) 3296198194Sweongyo urtw_write8_m(sc, urtw_8225v2b_rf_part1[i].reg, 3297196970Sphk urtw_8225v2b_rf_part1[i].val); 3298198194Sweongyo urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50); 3299198194Sweongyo urtw_write16_m(sc, URTW_INT_MIG, 0x0000); 3300198194Sweongyo urtw_write32_m(sc, 0x1f0, 0); 3301198194Sweongyo urtw_write32_m(sc, 0x1f4, 0); 3302198194Sweongyo urtw_write8_m(sc, 0x1f8, 0); 3303198194Sweongyo urtw_write32_m(sc, URTW_RF_TIMING, 0x4001); 3304196970Sphk 3305198194Sweongyo#define URTW_RFSW_CTRL 0x272 3306198194Sweongyo urtw_write16_m(sc, URTW_RFSW_CTRL, 0x569a); 3307196970Sphk 3308198194Sweongyo /* 3309198194Sweongyo * initialize PHY 3310198194Sweongyo */ 3311198194Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 3312198194Sweongyo if (error) 3313198194Sweongyo goto fail; 3314198194Sweongyo urtw_read8_m(sc, URTW_CONFIG3, &data8); 3315198194Sweongyo urtw_write8_m(sc, URTW_CONFIG3, 3316198194Sweongyo data8 | URTW_CONFIG3_ANAPARAM_WRITE); 3317198194Sweongyo 3318198194Sweongyo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 3319198194Sweongyo if (error) 3320198194Sweongyo goto fail; 3321198194Sweongyo 3322198194Sweongyo /* setup RFE initial timing */ 3323198194Sweongyo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480); 3324198194Sweongyo urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488); 3325198194Sweongyo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff); 3326198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1100); 3327198194Sweongyo 3328198194Sweongyo for (i = 0; i < N(urtw_8225v2b_rf_part0); i++) { 3329198194Sweongyo urtw_8225_write(sc, urtw_8225v2b_rf_part0[i].reg, 3330198194Sweongyo urtw_8225v2b_rf_part0[i].val); 3331198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3332198194Sweongyo } 3333198194Sweongyo urtw_8225_write(sc, 0x00, 0x01b7); 3334198194Sweongyo 3335198194Sweongyo for (i = 0; i < 95; i++) { 3336196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_1_MAGIC, (uint8_t)(i + 1)); 3337198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3338196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 3339196970Sphk urtw_8225v2b_rxgain[i]); 3340198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3341196970Sphk } 3342196970Sphk 3343196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_3_MAGIC, 0x080); 3344198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3345196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_5_MAGIC, 0x004); 3346198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3347196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x0b7); 3348198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3349198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 3000); 3350196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0xc4d); 3351198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 2000); 3352196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_2_MAGIC, 0x44d); 3353198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3354196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_0_MAGIC, 0x2bf); 3355198194Sweongyo usb_pause_mtx(&sc->sc_mtx, 1); 3356196970Sphk 3357196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03); 3358196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07); 3359196970Sphk urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03); 3360196970Sphk 3361196970Sphk urtw_8187_write_phy_ofdm(sc, 0x80, 0x12); 3362198194Sweongyo for (i = 0; i < 128; i++) { 3363198194Sweongyo uint32_t addr, data; 3364198194Sweongyo 3365198194Sweongyo data = (urtw_8225z2_agc[i] << 8) | 0x0000008f; 3366198194Sweongyo addr = ((i + 0x80) << 8) | 0x0000008e; 3367198194Sweongyo 3368198194Sweongyo urtw_8187_write_phy_ofdm(sc, data & 0x7f, (data >> 8) & 0xff); 3369198194Sweongyo urtw_8187_write_phy_ofdm(sc, addr & 0x7f, (addr >> 8) & 0xff); 3370198194Sweongyo urtw_8187_write_phy_ofdm(sc, 0x0e, 0x00); 3371196970Sphk } 3372196970Sphk urtw_8187_write_phy_ofdm(sc, 0x80, 0x10); 3373196970Sphk 3374196970Sphk for (i = 0; i < N(urtw_8225v2b_rf_part2); i++) 3375196970Sphk urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2b_rf_part2[i].val); 3376196970Sphk 3377198194Sweongyo urtw_write32_m(sc, URTW_8187B_AC_VO, (7 << 12) | (3 << 8) | 0x1c); 3378198194Sweongyo urtw_write32_m(sc, URTW_8187B_AC_VI, (7 << 12) | (3 << 8) | 0x1c); 3379198194Sweongyo urtw_write32_m(sc, URTW_8187B_AC_BE, (7 << 12) | (3 << 8) | 0x1c); 3380198194Sweongyo urtw_write32_m(sc, URTW_8187B_AC_BK, (7 << 12) | (3 << 8) | 0x1c); 3381196970Sphk 3382196970Sphk urtw_8187_write_phy_ofdm(sc, 0x97, 0x46); 3383196970Sphk urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6); 3384196970Sphk urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc); 3385196970Sphk urtw_8187_write_phy_cck(sc, 0xc1, 0x88); 3386198194Sweongyo 3387196970Sphkfail: 3388196970Sphk return (error); 3389196970Sphk#undef N 3390196970Sphk} 3391196970Sphk 3392196970Sphkstatic usb_error_t 3393196970Sphkurtw_8225v2b_rf_set_chan(struct urtw_softc *sc, int chan) 3394196970Sphk{ 3395196970Sphk usb_error_t error; 3396196970Sphk 3397196970Sphk error = urtw_8225v2b_set_txpwrlvl(sc, chan); 3398196970Sphk if (error) 3399196970Sphk goto fail; 3400196970Sphk 3401196970Sphk urtw_8225_write(sc, URTW_8225_ADDR_7_MAGIC, urtw_8225_channel[chan]); 3402196970Sphk usb_pause_mtx(&sc->sc_mtx, 10); 3403196970Sphkfail: 3404196970Sphk return (error); 3405196970Sphk} 3406196970Sphk 3407196970Sphkstatic usb_error_t 3408196970Sphkurtw_8225v2b_set_txpwrlvl(struct urtw_softc *sc, int chan) 3409196970Sphk{ 3410196970Sphk int i; 3411196970Sphk uint8_t *cck_pwrtable; 3412196970Sphk uint8_t cck_pwrlvl_max = 15; 3413196970Sphk uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 3414196970Sphk uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 3415196970Sphk usb_error_t error; 3416196970Sphk 3417196970Sphk /* CCK power setting */ 3418196970Sphk cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? 3419196970Sphk ((sc->sc_flags & URTW_RTL8187B_REV_B) ? cck_pwrlvl_max : 22) : 3420196970Sphk (cck_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 0 : 7)); 3421196970Sphk cck_pwrlvl += sc->sc_txpwr_cck_base; 3422196970Sphk cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl; 3423196970Sphk cck_pwrtable = (chan == 14) ? urtw_8225v2b_txpwr_cck_ch14 : 3424196970Sphk urtw_8225v2b_txpwr_cck; 3425196970Sphk 3426196970Sphk if (sc->sc_flags & URTW_RTL8187B_REV_B) 3427196970Sphk cck_pwrtable += (cck_pwrlvl <= 6) ? 0 : 3428196970Sphk ((cck_pwrlvl <= 11) ? 8 : 16); 3429196970Sphk else 3430196970Sphk cck_pwrtable += (cck_pwrlvl <= 5) ? 0 : 3431196970Sphk ((cck_pwrlvl <= 11) ? 8 : ((cck_pwrlvl <= 17) ? 16 : 24)); 3432196970Sphk 3433196970Sphk for (i = 0; i < 8; i++) 3434196970Sphk urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]); 3435196970Sphk 3436196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_CCK, 3437196970Sphk urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1); 3438196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3439196970Sphk 3440196970Sphk /* OFDM power setting */ 3441196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > 15) ? 3442196970Sphk ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 17 : 25) : 3443196970Sphk (ofdm_pwrlvl + ((sc->sc_flags & URTW_RTL8187B_REV_B) ? 2 : 10)); 3444196970Sphk ofdm_pwrlvl += sc->sc_txpwr_ofdm_base; 3445196970Sphk ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 3446196970Sphk 3447196970Sphk urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 3448196970Sphk urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1); 3449196970Sphk 3450196970Sphk if (sc->sc_flags & URTW_RTL8187B_REV_B) { 3451196970Sphk if (ofdm_pwrlvl <= 11) { 3452196970Sphk urtw_8187_write_phy_ofdm(sc, 0x87, 0x60); 3453196970Sphk urtw_8187_write_phy_ofdm(sc, 0x89, 0x60); 3454196970Sphk } else { 3455196970Sphk urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c); 3456196970Sphk urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c); 3457196970Sphk } 3458196970Sphk } else { 3459196970Sphk if (ofdm_pwrlvl <= 11) { 3460196970Sphk urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c); 3461196970Sphk urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c); 3462196970Sphk } else if (ofdm_pwrlvl <= 17) { 3463196970Sphk urtw_8187_write_phy_ofdm(sc, 0x87, 0x54); 3464196970Sphk urtw_8187_write_phy_ofdm(sc, 0x89, 0x54); 3465196970Sphk } else { 3466196970Sphk urtw_8187_write_phy_ofdm(sc, 0x87, 0x50); 3467196970Sphk urtw_8187_write_phy_ofdm(sc, 0x89, 0x50); 3468196970Sphk } 3469196970Sphk } 3470196970Sphk usb_pause_mtx(&sc->sc_mtx, 1); 3471196970Sphkfail: 3472196970Sphk return (error); 3473196970Sphk} 3474196970Sphk 3475196970Sphkstatic usb_error_t 3476196970Sphkurtw_read8e(struct urtw_softc *sc, int val, uint8_t *data) 3477196970Sphk{ 3478196970Sphk struct usb_device_request req; 3479196970Sphk usb_error_t error; 3480196970Sphk 3481196970Sphk req.bmRequestType = UT_READ_VENDOR_DEVICE; 3482196970Sphk req.bRequest = URTW_8187_GETREGS_REQ; 3483196970Sphk USETW(req.wValue, val | 0xfe00); 3484196970Sphk USETW(req.wIndex, 0); 3485196970Sphk USETW(req.wLength, sizeof(uint8_t)); 3486196970Sphk 3487196970Sphk error = urtw_do_request(sc, &req, data); 3488196970Sphk return (error); 3489196970Sphk} 3490196970Sphk 3491196970Sphkstatic usb_error_t 3492196970Sphkurtw_write8e(struct urtw_softc *sc, int val, uint8_t data) 3493196970Sphk{ 3494196970Sphk struct usb_device_request req; 3495196970Sphk 3496196970Sphk req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 3497196970Sphk req.bRequest = URTW_8187_SETREGS_REQ; 3498196970Sphk USETW(req.wValue, val | 0xfe00); 3499196970Sphk USETW(req.wIndex, 0); 3500196970Sphk USETW(req.wLength, sizeof(uint8_t)); 3501196970Sphk 3502196970Sphk return (urtw_do_request(sc, &req, &data)); 3503196970Sphk} 3504196970Sphk 3505196970Sphkstatic usb_error_t 3506196970Sphkurtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val) 3507196970Sphk{ 3508196970Sphk uint8_t data; 3509196970Sphk usb_error_t error; 3510196970Sphk 3511196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 3512196970Sphk if (error) 3513196970Sphk goto fail; 3514196970Sphk 3515196970Sphk urtw_read8_m(sc, URTW_CONFIG3, &data); 3516196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 3517196970Sphk urtw_write32_m(sc, URTW_ANAPARAM, val); 3518196970Sphk urtw_read8_m(sc, URTW_CONFIG3, &data); 3519196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 3520196970Sphk 3521196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 3522196970Sphk if (error) 3523196970Sphk goto fail; 3524196970Sphkfail: 3525196970Sphk return (error); 3526196970Sphk} 3527196970Sphk 3528196970Sphkstatic usb_error_t 3529196970Sphkurtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val) 3530196970Sphk{ 3531196970Sphk uint8_t data; 3532196970Sphk usb_error_t error; 3533196970Sphk 3534196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 3535196970Sphk if (error) 3536196970Sphk goto fail; 3537196970Sphk 3538196970Sphk urtw_read8_m(sc, URTW_CONFIG3, &data); 3539196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 3540196970Sphk urtw_write32_m(sc, URTW_ANAPARAM2, val); 3541196970Sphk urtw_read8_m(sc, URTW_CONFIG3, &data); 3542196970Sphk urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 3543196970Sphk 3544196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 3545196970Sphk if (error) 3546196970Sphk goto fail; 3547196970Sphkfail: 3548196970Sphk return (error); 3549196970Sphk} 3550196970Sphk 3551196970Sphkstatic usb_error_t 3552196970Sphkurtw_intr_enable(struct urtw_softc *sc) 3553196970Sphk{ 3554196970Sphk usb_error_t error; 3555196970Sphk 3556196970Sphk urtw_write16_m(sc, URTW_INTR_MASK, 0xffff); 3557196970Sphkfail: 3558196970Sphk return (error); 3559196970Sphk} 3560196970Sphk 3561196970Sphkstatic usb_error_t 3562196970Sphkurtw_intr_disable(struct urtw_softc *sc) 3563196970Sphk{ 3564196970Sphk usb_error_t error; 3565196970Sphk 3566196970Sphk urtw_write16_m(sc, URTW_INTR_MASK, 0); 3567196970Sphkfail: 3568196970Sphk return (error); 3569196970Sphk} 3570196970Sphk 3571196970Sphkstatic usb_error_t 3572196970Sphkurtw_reset(struct urtw_softc *sc) 3573196970Sphk{ 3574196970Sphk uint8_t data; 3575196970Sphk usb_error_t error; 3576196970Sphk 3577196970Sphk error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON); 3578196970Sphk if (error) 3579196970Sphk goto fail; 3580196970Sphk error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON); 3581196970Sphk if (error) 3582196970Sphk goto fail; 3583196970Sphk 3584196970Sphk error = urtw_intr_disable(sc); 3585196970Sphk if (error) 3586196970Sphk goto fail; 3587196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 3588196970Sphk 3589196970Sphk error = urtw_write8e(sc, 0x18, 0x10); 3590196970Sphk if (error != 0) 3591196970Sphk goto fail; 3592196970Sphk error = urtw_write8e(sc, 0x18, 0x11); 3593196970Sphk if (error != 0) 3594196970Sphk goto fail; 3595196970Sphk error = urtw_write8e(sc, 0x18, 0x00); 3596196970Sphk if (error != 0) 3597196970Sphk goto fail; 3598196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 3599196970Sphk 3600196970Sphk urtw_read8_m(sc, URTW_CMD, &data); 3601196970Sphk data = (data & 0x2) | URTW_CMD_RST; 3602196970Sphk urtw_write8_m(sc, URTW_CMD, data); 3603196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 3604196970Sphk 3605196970Sphk urtw_read8_m(sc, URTW_CMD, &data); 3606196970Sphk if (data & URTW_CMD_RST) { 3607196970Sphk device_printf(sc->sc_dev, "reset timeout\n"); 3608196970Sphk goto fail; 3609196970Sphk } 3610196970Sphk 3611196970Sphk error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD); 3612196970Sphk if (error) 3613196970Sphk goto fail; 3614196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 3615196970Sphk 3616196970Sphk error = urtw_8180_set_anaparam(sc, URTW_8225_ANAPARAM_ON); 3617196970Sphk if (error) 3618196970Sphk goto fail; 3619196970Sphk error = urtw_8185_set_anaparam2(sc, URTW_8225_ANAPARAM2_ON); 3620196970Sphk if (error) 3621196970Sphk goto fail; 3622196970Sphkfail: 3623196970Sphk return (error); 3624196970Sphk} 3625196970Sphk 3626196970Sphkstatic usb_error_t 3627196970Sphkurtw_led_ctl(struct urtw_softc *sc, int mode) 3628196970Sphk{ 3629196970Sphk usb_error_t error = 0; 3630196970Sphk 3631196970Sphk switch (sc->sc_strategy) { 3632196970Sphk case URTW_SW_LED_MODE0: 3633196970Sphk error = urtw_led_mode0(sc, mode); 3634196970Sphk break; 3635196970Sphk case URTW_SW_LED_MODE1: 3636196970Sphk error = urtw_led_mode1(sc, mode); 3637196970Sphk break; 3638196970Sphk case URTW_SW_LED_MODE2: 3639196970Sphk error = urtw_led_mode2(sc, mode); 3640196970Sphk break; 3641196970Sphk case URTW_SW_LED_MODE3: 3642196970Sphk error = urtw_led_mode3(sc, mode); 3643196970Sphk break; 3644196970Sphk default: 3645259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3646259456Shselasky "unsupported LED mode %d\n", sc->sc_strategy); 3647259456Shselasky error = USB_ERR_INVAL; 3648259456Shselasky break; 3649196970Sphk } 3650196970Sphk 3651196970Sphk return (error); 3652196970Sphk} 3653196970Sphk 3654196970Sphkstatic usb_error_t 3655196970Sphkurtw_led_mode0(struct urtw_softc *sc, int mode) 3656196970Sphk{ 3657196970Sphk 3658196970Sphk switch (mode) { 3659196970Sphk case URTW_LED_CTL_POWER_ON: 3660196970Sphk sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK; 3661196970Sphk break; 3662196970Sphk case URTW_LED_CTL_TX: 3663196970Sphk if (sc->sc_gpio_ledinprogress == 1) 3664196970Sphk return (0); 3665196970Sphk 3666196970Sphk sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL; 3667196970Sphk sc->sc_gpio_blinktime = 2; 3668196970Sphk break; 3669196970Sphk case URTW_LED_CTL_LINK: 3670196970Sphk sc->sc_gpio_ledstate = URTW_LED_ON; 3671196970Sphk break; 3672196970Sphk default: 3673259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3674259456Shselasky "unsupported LED mode 0x%x", mode); 3675259456Shselasky return (USB_ERR_INVAL); 3676196970Sphk } 3677196970Sphk 3678196970Sphk switch (sc->sc_gpio_ledstate) { 3679196970Sphk case URTW_LED_ON: 3680196970Sphk if (sc->sc_gpio_ledinprogress != 0) 3681196970Sphk break; 3682196970Sphk urtw_led_on(sc, URTW_LED_GPIO); 3683196970Sphk break; 3684196970Sphk case URTW_LED_BLINK_NORMAL: 3685196970Sphk if (sc->sc_gpio_ledinprogress != 0) 3686196970Sphk break; 3687196970Sphk sc->sc_gpio_ledinprogress = 1; 3688196970Sphk sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ? 3689196970Sphk URTW_LED_OFF : URTW_LED_ON; 3690196970Sphk usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc); 3691196970Sphk break; 3692196970Sphk case URTW_LED_POWER_ON_BLINK: 3693196970Sphk urtw_led_on(sc, URTW_LED_GPIO); 3694196970Sphk usb_pause_mtx(&sc->sc_mtx, 100); 3695196970Sphk urtw_led_off(sc, URTW_LED_GPIO); 3696196970Sphk break; 3697196970Sphk default: 3698259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3699259456Shselasky "unknown LED status 0x%x", sc->sc_gpio_ledstate); 3700259456Shselasky return (USB_ERR_INVAL); 3701196970Sphk } 3702196970Sphk return (0); 3703196970Sphk} 3704196970Sphk 3705196970Sphkstatic usb_error_t 3706196970Sphkurtw_led_mode1(struct urtw_softc *sc, int mode) 3707196970Sphk{ 3708196970Sphk return (USB_ERR_INVAL); 3709196970Sphk} 3710196970Sphk 3711196970Sphkstatic usb_error_t 3712196970Sphkurtw_led_mode2(struct urtw_softc *sc, int mode) 3713196970Sphk{ 3714196970Sphk return (USB_ERR_INVAL); 3715196970Sphk} 3716196970Sphk 3717196970Sphkstatic usb_error_t 3718196970Sphkurtw_led_mode3(struct urtw_softc *sc, int mode) 3719196970Sphk{ 3720196970Sphk return (USB_ERR_INVAL); 3721196970Sphk} 3722196970Sphk 3723196970Sphkstatic usb_error_t 3724196970Sphkurtw_led_on(struct urtw_softc *sc, int type) 3725196970Sphk{ 3726196970Sphk usb_error_t error; 3727196970Sphk 3728196970Sphk if (type == URTW_LED_GPIO) { 3729196970Sphk switch (sc->sc_gpio_ledpin) { 3730196970Sphk case URTW_LED_PIN_GPIO0: 3731196970Sphk urtw_write8_m(sc, URTW_GPIO, 0x01); 3732196970Sphk urtw_write8_m(sc, URTW_GP_ENABLE, 0x00); 3733196970Sphk break; 3734196970Sphk default: 3735259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3736259456Shselasky "unsupported LED PIN type 0x%x", 3737196970Sphk sc->sc_gpio_ledpin); 3738259456Shselasky error = USB_ERR_INVAL; 3739259456Shselasky goto fail; 3740196970Sphk } 3741196970Sphk } else { 3742259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3743259456Shselasky "unsupported LED type 0x%x", type); 3744259456Shselasky error = USB_ERR_INVAL; 3745259456Shselasky goto fail; 3746196970Sphk } 3747196970Sphk 3748196970Sphk sc->sc_gpio_ledon = 1; 3749196970Sphkfail: 3750196970Sphk return (error); 3751196970Sphk} 3752196970Sphk 3753196970Sphkstatic usb_error_t 3754196970Sphkurtw_led_off(struct urtw_softc *sc, int type) 3755196970Sphk{ 3756196970Sphk usb_error_t error; 3757196970Sphk 3758196970Sphk if (type == URTW_LED_GPIO) { 3759196970Sphk switch (sc->sc_gpio_ledpin) { 3760196970Sphk case URTW_LED_PIN_GPIO0: 3761196970Sphk urtw_write8_m(sc, URTW_GPIO, URTW_GPIO_DATA_MAGIC1); 3762196970Sphk urtw_write8_m(sc, 3763196970Sphk URTW_GP_ENABLE, URTW_GP_ENABLE_DATA_MAGIC1); 3764196970Sphk break; 3765196970Sphk default: 3766259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3767259456Shselasky "unsupported LED PIN type 0x%x", 3768196970Sphk sc->sc_gpio_ledpin); 3769259456Shselasky error = USB_ERR_INVAL; 3770259456Shselasky goto fail; 3771196970Sphk } 3772196970Sphk } else { 3773259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3774259456Shselasky "unsupported LED type 0x%x", type); 3775259456Shselasky error = USB_ERR_INVAL; 3776259456Shselasky goto fail; 3777196970Sphk } 3778196970Sphk 3779196970Sphk sc->sc_gpio_ledon = 0; 3780196970Sphk 3781196970Sphkfail: 3782196970Sphk return (error); 3783196970Sphk} 3784196970Sphk 3785192873Sweongyostatic void 3786192873Sweongyourtw_led_ch(void *arg) 3787192873Sweongyo{ 3788192873Sweongyo struct urtw_softc *sc = arg; 3789192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 3790192873Sweongyo struct ieee80211com *ic = ifp->if_l2com; 3791192873Sweongyo 3792192873Sweongyo ieee80211_runtask(ic, &sc->sc_led_task); 3793192873Sweongyo} 3794196970Sphk 3795192873Sweongyostatic void 3796196970Sphkurtw_ledtask(void *arg, int pending) 3797196970Sphk{ 3798196970Sphk struct urtw_softc *sc = arg; 3799196970Sphk 3800259456Shselasky if (sc->sc_strategy != URTW_SW_LED_MODE0) { 3801259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3802259456Shselasky "could not process a LED strategy 0x%x", 3803259456Shselasky sc->sc_strategy); 3804259456Shselasky return; 3805259456Shselasky } 3806196970Sphk 3807196970Sphk URTW_LOCK(sc); 3808196970Sphk urtw_led_blink(sc); 3809196970Sphk URTW_UNLOCK(sc); 3810196970Sphk} 3811196970Sphk 3812196970Sphkstatic usb_error_t 3813196970Sphkurtw_led_blink(struct urtw_softc *sc) 3814196970Sphk{ 3815196970Sphk uint8_t ing = 0; 3816196970Sphk usb_error_t error; 3817196970Sphk 3818196970Sphk if (sc->sc_gpio_blinkstate == URTW_LED_ON) 3819196970Sphk error = urtw_led_on(sc, URTW_LED_GPIO); 3820196970Sphk else 3821196970Sphk error = urtw_led_off(sc, URTW_LED_GPIO); 3822196970Sphk sc->sc_gpio_blinktime--; 3823196970Sphk if (sc->sc_gpio_blinktime == 0) 3824196970Sphk ing = 1; 3825196970Sphk else { 3826196970Sphk if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL && 3827196970Sphk sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY && 3828196970Sphk sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3) 3829196970Sphk ing = 1; 3830196970Sphk } 3831196970Sphk if (ing == 1) { 3832196970Sphk if (sc->sc_gpio_ledstate == URTW_LED_ON && 3833196970Sphk sc->sc_gpio_ledon == 0) 3834196970Sphk error = urtw_led_on(sc, URTW_LED_GPIO); 3835196970Sphk else if (sc->sc_gpio_ledstate == URTW_LED_OFF && 3836196970Sphk sc->sc_gpio_ledon == 1) 3837196970Sphk error = urtw_led_off(sc, URTW_LED_GPIO); 3838196970Sphk 3839196970Sphk sc->sc_gpio_blinktime = 0; 3840196970Sphk sc->sc_gpio_ledinprogress = 0; 3841196970Sphk return (0); 3842196970Sphk } 3843196970Sphk 3844196970Sphk sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ? 3845196970Sphk URTW_LED_ON : URTW_LED_OFF; 3846196970Sphk 3847196970Sphk switch (sc->sc_gpio_ledstate) { 3848196970Sphk case URTW_LED_BLINK_NORMAL: 3849196970Sphk usb_callout_reset(&sc->sc_led_ch, hz, urtw_led_ch, sc); 3850196970Sphk break; 3851196970Sphk default: 3852259456Shselasky DPRINTF(sc, URTW_DEBUG_STATE, 3853259456Shselasky "unknown LED status 0x%x", 3854259456Shselasky sc->sc_gpio_ledstate); 3855259456Shselasky return (USB_ERR_INVAL); 3856196970Sphk } 3857196970Sphk return (0); 3858196970Sphk} 3859196970Sphk 3860196970Sphkstatic usb_error_t 3861196970Sphkurtw_rx_enable(struct urtw_softc *sc) 3862196970Sphk{ 3863196970Sphk uint8_t data; 3864196970Sphk usb_error_t error; 3865196970Sphk 3866196970Sphk usbd_transfer_start((sc->sc_flags & URTW_RTL8187B) ? 3867196970Sphk sc->sc_xfer[URTW_8187B_BULK_RX] : sc->sc_xfer[URTW_8187L_BULK_RX]); 3868196970Sphk 3869196970Sphk error = urtw_rx_setconf(sc); 3870196970Sphk if (error != 0) 3871196970Sphk goto fail; 3872196970Sphk 3873198194Sweongyo if ((sc->sc_flags & URTW_RTL8187B) == 0) { 3874198194Sweongyo urtw_read8_m(sc, URTW_CMD, &data); 3875198194Sweongyo urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE); 3876198194Sweongyo } 3877196970Sphkfail: 3878196970Sphk return (error); 3879196970Sphk} 3880196970Sphk 3881196970Sphkstatic usb_error_t 3882196970Sphkurtw_tx_enable(struct urtw_softc *sc) 3883196970Sphk{ 3884196970Sphk uint8_t data8; 3885196970Sphk uint32_t data; 3886196970Sphk usb_error_t error; 3887196970Sphk 3888196970Sphk if (sc->sc_flags & URTW_RTL8187B) { 3889196970Sphk urtw_read32_m(sc, URTW_TX_CONF, &data); 3890196970Sphk data &= ~URTW_TX_LOOPBACK_MASK; 3891196970Sphk data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK); 3892196970Sphk data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK); 3893196970Sphk data &= ~URTW_TX_SWPLCPLEN; 3894196970Sphk data |= URTW_TX_HW_SEQNUM | URTW_TX_DISREQQSIZE | 3895196970Sphk (7 << 8) | /* short retry limit */ 3896196970Sphk (7 << 0) | /* long retry limit */ 3897196970Sphk (7 << 21); /* MAX TX DMA */ 3898196970Sphk urtw_write32_m(sc, URTW_TX_CONF, data); 3899196970Sphk 3900198194Sweongyo urtw_read8_m(sc, URTW_MSR, &data8); 3901198194Sweongyo data8 |= URTW_MSR_LINK_ENEDCA; 3902198194Sweongyo urtw_write8_m(sc, URTW_MSR, data8); 3903196970Sphk return (error); 3904196970Sphk } 3905196970Sphk 3906196970Sphk urtw_read8_m(sc, URTW_CW_CONF, &data8); 3907196970Sphk data8 &= ~(URTW_CW_CONF_PERPACKET_CW | URTW_CW_CONF_PERPACKET_RETRY); 3908196970Sphk urtw_write8_m(sc, URTW_CW_CONF, data8); 3909196970Sphk 3910196970Sphk urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8); 3911196970Sphk data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN; 3912196970Sphk data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL; 3913196970Sphk data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT; 3914196970Sphk urtw_write8_m(sc, URTW_TX_AGC_CTL, data8); 3915196970Sphk 3916196970Sphk urtw_read32_m(sc, URTW_TX_CONF, &data); 3917196970Sphk data &= ~URTW_TX_LOOPBACK_MASK; 3918196970Sphk data |= URTW_TX_LOOPBACK_NONE; 3919196970Sphk data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK); 3920196970Sphk data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT; 3921196970Sphk data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT; 3922196970Sphk data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK); 3923196970Sphk data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW; 3924196970Sphk data &= ~URTW_TX_SWPLCPLEN; 3925196970Sphk data |= URTW_TX_NOICV; 3926196970Sphk urtw_write32_m(sc, URTW_TX_CONF, data); 3927196970Sphk 3928196970Sphk urtw_read8_m(sc, URTW_CMD, &data8); 3929196970Sphk urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE); 3930196970Sphkfail: 3931196970Sphk return (error); 3932196970Sphk} 3933196970Sphk 3934196970Sphkstatic usb_error_t 3935196970Sphkurtw_rx_setconf(struct urtw_softc *sc) 3936196970Sphk{ 3937196970Sphk struct ifnet *ifp = sc->sc_ifp; 3938196970Sphk struct ieee80211com *ic = ifp->if_l2com; 3939196970Sphk uint32_t data; 3940196970Sphk usb_error_t error; 3941196970Sphk 3942196970Sphk urtw_read32_m(sc, URTW_RX, &data); 3943196970Sphk data = data &~ URTW_RX_FILTER_MASK; 3944196970Sphk if (sc->sc_flags & URTW_RTL8187B) { 3945196970Sphk data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA | 3946196970Sphk URTW_RX_FILTER_MCAST | URTW_RX_FILTER_BCAST | 3947196970Sphk URTW_RX_FILTER_NICMAC | URTW_RX_CHECK_BSSID | 3948196970Sphk URTW_RX_FIFO_THRESHOLD_NONE | 3949196970Sphk URTW_MAX_RX_DMA_2048 | 3950196970Sphk URTW_RX_AUTORESETPHY | URTW_RCR_ONLYERLPKT; 3951196970Sphk } else { 3952196970Sphk data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA; 3953196970Sphk data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST; 3954196970Sphk 3955196970Sphk if (ic->ic_opmode == IEEE80211_M_MONITOR) { 3956196970Sphk data = data | URTW_RX_FILTER_ICVERR; 3957196970Sphk data = data | URTW_RX_FILTER_PWR; 3958196970Sphk } 3959196970Sphk if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR) 3960196970Sphk data = data | URTW_RX_FILTER_CRCERR; 3961196970Sphk 3962196970Sphk if (ic->ic_opmode == IEEE80211_M_MONITOR || 3963196970Sphk (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { 3964196970Sphk data = data | URTW_RX_FILTER_ALLMAC; 3965196970Sphk } else { 3966196970Sphk data = data | URTW_RX_FILTER_NICMAC; 3967196970Sphk data = data | URTW_RX_CHECK_BSSID; 3968196970Sphk } 3969196970Sphk 3970196970Sphk data = data &~ URTW_RX_FIFO_THRESHOLD_MASK; 3971196970Sphk data = data | URTW_RX_FIFO_THRESHOLD_NONE | 3972196970Sphk URTW_RX_AUTORESETPHY; 3973196970Sphk data = data &~ URTW_MAX_RX_DMA_MASK; 3974196970Sphk data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT; 3975196970Sphk } 3976196970Sphk 3977196970Sphk urtw_write32_m(sc, URTW_RX, data); 3978196970Sphkfail: 3979196970Sphk return (error); 3980196970Sphk} 3981196970Sphk 3982196970Sphkstatic struct mbuf * 3983196970Sphkurtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p, 3984196970Sphk int8_t *nf_p) 3985196970Sphk{ 3986198194Sweongyo int actlen, flen, rssi; 3987196970Sphk struct ieee80211_frame *wh; 3988196970Sphk struct mbuf *m, *mnew; 3989196970Sphk struct urtw_softc *sc = data->sc; 3990196970Sphk struct ifnet *ifp = sc->sc_ifp; 3991196970Sphk struct ieee80211com *ic = ifp->if_l2com; 3992198194Sweongyo uint8_t noise = 0, rate; 3993196970Sphk 3994196970Sphk usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 3995196970Sphk 3996235000Shselasky if (actlen < (int)URTW_MIN_RXBUFSZ) { 3997196970Sphk ifp->if_ierrors++; 3998196970Sphk return (NULL); 3999196970Sphk } 4000196970Sphk 4001196970Sphk if (sc->sc_flags & URTW_RTL8187B) { 4002198194Sweongyo struct urtw_8187b_rxhdr *rx; 4003198194Sweongyo 4004198194Sweongyo rx = (struct urtw_8187b_rxhdr *)(data->buf + 4005198194Sweongyo (actlen - (sizeof(struct urtw_8187b_rxhdr)))); 4006198194Sweongyo flen = le32toh(rx->flag) & 0xfff; 4007196970Sphk if (flen > actlen) { 4008196970Sphk ifp->if_ierrors++; 4009196970Sphk return (NULL); 4010196970Sphk } 4011198194Sweongyo rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf; 4012198194Sweongyo /* XXX correct? */ 4013198194Sweongyo rssi = rx->rssi & URTW_RX_RSSI_MASK; 4014198194Sweongyo noise = rx->noise; 4015196970Sphk } else { 4016198194Sweongyo struct urtw_8187l_rxhdr *rx; 4017198194Sweongyo 4018198194Sweongyo rx = (struct urtw_8187l_rxhdr *)(data->buf + 4019198194Sweongyo (actlen - (sizeof(struct urtw_8187l_rxhdr)))); 4020198194Sweongyo flen = le32toh(rx->flag) & 0xfff; 4021196970Sphk if (flen > actlen) { 4022196970Sphk ifp->if_ierrors++; 4023196970Sphk return (NULL); 4024196970Sphk } 4025196970Sphk 4026198194Sweongyo rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf; 4027198194Sweongyo /* XXX correct? */ 4028198194Sweongyo rssi = rx->rssi & URTW_RX_8187L_RSSI_MASK; 4029198194Sweongyo noise = rx->noise; 4030196970Sphk } 4031196970Sphk 4032248078Smarius mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 4033196970Sphk if (mnew == NULL) { 4034196970Sphk ifp->if_ierrors++; 4035196970Sphk return (NULL); 4036196970Sphk } 4037196970Sphk 4038196970Sphk m = data->m; 4039196970Sphk data->m = mnew; 4040196970Sphk data->buf = mtod(mnew, uint8_t *); 4041196970Sphk 4042196970Sphk /* finalize mbuf */ 4043196970Sphk m->m_pkthdr.rcvif = ifp; 4044198194Sweongyo m->m_pkthdr.len = m->m_len = flen - IEEE80211_CRC_LEN; 4045196970Sphk 4046196970Sphk if (ieee80211_radiotap_active(ic)) { 4047196970Sphk struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap; 4048196970Sphk 4049196970Sphk /* XXX Are variables correct? */ 4050196970Sphk tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 4051196970Sphk tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 4052196970Sphk tap->wr_dbm_antsignal = (int8_t)rssi; 4053196970Sphk } 4054196970Sphk 4055196970Sphk wh = mtod(m, struct ieee80211_frame *); 4056196970Sphk if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) 4057196970Sphk sc->sc_currate = (rate > 0) ? rate : sc->sc_currate; 4058196970Sphk 4059196970Sphk *rssi_p = rssi; 4060198194Sweongyo *nf_p = noise; /* XXX correct? */ 4061196970Sphk 4062196970Sphk return (m); 4063196970Sphk} 4064196970Sphk 4065196970Sphkstatic void 4066194677Sthompsaurtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 4067192873Sweongyo{ 4068194677Sthompsa struct urtw_softc *sc = usbd_xfer_softc(xfer); 4069192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 4070192873Sweongyo struct ieee80211com *ic = ifp->if_l2com; 4071192873Sweongyo struct ieee80211_frame *wh; 4072192873Sweongyo struct ieee80211_node *ni; 4073192873Sweongyo struct mbuf *m = NULL; 4074192873Sweongyo struct urtw_data *data; 4075192873Sweongyo int8_t nf = -95; 4076192873Sweongyo int rssi = 1; 4077192873Sweongyo 4078192873Sweongyo URTW_ASSERT_LOCKED(sc); 4079192873Sweongyo 4080192873Sweongyo switch (USB_GET_STATE(xfer)) { 4081192873Sweongyo case USB_ST_TRANSFERRED: 4082192873Sweongyo data = STAILQ_FIRST(&sc->sc_rx_active); 4083192873Sweongyo if (data == NULL) 4084192873Sweongyo goto setup; 4085192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 4086192873Sweongyo m = urtw_rxeof(xfer, data, &rssi, &nf); 4087192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 4088192873Sweongyo /* FALLTHROUGH */ 4089192873Sweongyo case USB_ST_SETUP: 4090192873Sweongyosetup: 4091192873Sweongyo data = STAILQ_FIRST(&sc->sc_rx_inactive); 4092192873Sweongyo if (data == NULL) { 4093192873Sweongyo KASSERT(m == NULL, ("mbuf isn't NULL")); 4094192873Sweongyo return; 4095192873Sweongyo } 4096192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); 4097192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); 4098194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, data->buf, 4099194677Sthompsa usbd_xfer_max_len(xfer)); 4100194228Sthompsa usbd_transfer_submit(xfer); 4101192873Sweongyo 4102192873Sweongyo /* 4103192873Sweongyo * To avoid LOR we should unlock our private mutex here to call 4104192873Sweongyo * ieee80211_input() because here is at the end of a USB 4105192873Sweongyo * callback and safe to unlock. 4106192873Sweongyo */ 4107192873Sweongyo URTW_UNLOCK(sc); 4108192873Sweongyo if (m != NULL) { 4109192873Sweongyo wh = mtod(m, struct ieee80211_frame *); 4110192873Sweongyo ni = ieee80211_find_rxnode(ic, 4111192873Sweongyo (struct ieee80211_frame_min *)wh); 4112192873Sweongyo if (ni != NULL) { 4113192873Sweongyo (void) ieee80211_input(ni, m, rssi, nf); 4114192873Sweongyo /* node is no longer needed */ 4115192873Sweongyo ieee80211_free_node(ni); 4116192873Sweongyo } else 4117192873Sweongyo (void) ieee80211_input_all(ic, m, rssi, nf); 4118192873Sweongyo m = NULL; 4119192873Sweongyo } 4120192873Sweongyo URTW_LOCK(sc); 4121192873Sweongyo break; 4122192873Sweongyo default: 4123192873Sweongyo /* needs it to the inactive queue due to a error. */ 4124192873Sweongyo data = STAILQ_FIRST(&sc->sc_rx_active); 4125192873Sweongyo if (data != NULL) { 4126192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 4127192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 4128192873Sweongyo } 4129194677Sthompsa if (error != USB_ERR_CANCELLED) { 4130194677Sthompsa usbd_xfer_set_stall(xfer); 4131192873Sweongyo ifp->if_ierrors++; 4132192873Sweongyo goto setup; 4133192873Sweongyo } 4134192873Sweongyo break; 4135192873Sweongyo } 4136192873Sweongyo} 4137192873Sweongyo 4138198194Sweongyo#define URTW_STATUS_TYPE_TXCLOSE 1 4139198194Sweongyo#define URTW_STATUS_TYPE_BEACON_INTR 0 4140198194Sweongyo 4141192873Sweongyostatic void 4142198194Sweongyourtw_txstatus_eof(struct usb_xfer *xfer) 4143198194Sweongyo{ 4144198194Sweongyo struct urtw_softc *sc = usbd_xfer_softc(xfer); 4145198194Sweongyo struct ifnet *ifp = sc->sc_ifp; 4146198194Sweongyo int actlen, type, pktretry, seq; 4147198194Sweongyo uint64_t val; 4148198194Sweongyo 4149198194Sweongyo usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 4150198194Sweongyo 4151198194Sweongyo if (actlen != sizeof(uint64_t)) 4152198194Sweongyo return; 4153198194Sweongyo 4154198194Sweongyo val = le64toh(sc->sc_txstatus); 4155198194Sweongyo type = (val >> 30) & 0x3; 4156198194Sweongyo if (type == URTW_STATUS_TYPE_TXCLOSE) { 4157198194Sweongyo pktretry = val & 0xff; 4158198194Sweongyo seq = (val >> 16) & 0xff; 4159198194Sweongyo if (pktretry == URTW_TX_MAXRETRY) 4160198194Sweongyo ifp->if_oerrors++; 4161198194Sweongyo DPRINTF(sc, URTW_DEBUG_TXSTATUS, "pktretry %d seq %#x\n", 4162198194Sweongyo pktretry, seq); 4163198194Sweongyo } 4164198194Sweongyo} 4165198194Sweongyo 4166198194Sweongyostatic void 4167198194Sweongyourtw_bulk_tx_status_callback(struct usb_xfer *xfer, usb_error_t error) 4168198194Sweongyo{ 4169198194Sweongyo struct urtw_softc *sc = usbd_xfer_softc(xfer); 4170198194Sweongyo struct ifnet *ifp = sc->sc_ifp; 4171259454Shselasky void *dma_buf = usbd_xfer_get_frame_buffer(xfer, 0); 4172198194Sweongyo 4173198194Sweongyo URTW_ASSERT_LOCKED(sc); 4174198194Sweongyo 4175198194Sweongyo switch (USB_GET_STATE(xfer)) { 4176198194Sweongyo case USB_ST_TRANSFERRED: 4177198194Sweongyo urtw_txstatus_eof(xfer); 4178198194Sweongyo /* FALLTHROUGH */ 4179198194Sweongyo case USB_ST_SETUP: 4180198194Sweongyosetup: 4181259454Shselasky memcpy(dma_buf, &sc->sc_txstatus, sizeof(uint64_t)); 4182260575Shselasky usbd_xfer_set_frame_len(xfer, 0, sizeof(uint64_t)); 4183198194Sweongyo usbd_transfer_submit(xfer); 4184198194Sweongyo break; 4185198194Sweongyo default: 4186198194Sweongyo if (error != USB_ERR_CANCELLED) { 4187198194Sweongyo usbd_xfer_set_stall(xfer); 4188198194Sweongyo ifp->if_ierrors++; 4189198194Sweongyo goto setup; 4190198194Sweongyo } 4191198194Sweongyo break; 4192198194Sweongyo } 4193198194Sweongyo} 4194198194Sweongyo 4195198194Sweongyostatic void 4196192984Sthompsaurtw_txeof(struct usb_xfer *xfer, struct urtw_data *data) 4197192873Sweongyo{ 4198194677Sthompsa struct urtw_softc *sc = usbd_xfer_softc(xfer); 4199192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 4200192873Sweongyo struct mbuf *m; 4201192873Sweongyo 4202192873Sweongyo URTW_ASSERT_LOCKED(sc); 4203192873Sweongyo 4204192873Sweongyo /* 4205192873Sweongyo * Do any tx complete callback. Note this must be done before releasing 4206192873Sweongyo * the node reference. 4207192873Sweongyo */ 4208192873Sweongyo if (data->m) { 4209192873Sweongyo m = data->m; 4210192873Sweongyo if (m->m_flags & M_TXCB) { 4211192873Sweongyo /* XXX status? */ 4212192873Sweongyo ieee80211_process_callback(data->ni, m, 0); 4213192873Sweongyo } 4214192873Sweongyo m_freem(m); 4215192873Sweongyo data->m = NULL; 4216192873Sweongyo } 4217192873Sweongyo if (data->ni) { 4218192873Sweongyo ieee80211_free_node(data->ni); 4219192873Sweongyo data->ni = NULL; 4220192873Sweongyo } 4221192873Sweongyo sc->sc_txtimer = 0; 4222192873Sweongyo ifp->if_opackets++; 4223192873Sweongyo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4224192873Sweongyo} 4225192873Sweongyo 4226192873Sweongyostatic void 4227194677Sthompsaurtw_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 4228192873Sweongyo{ 4229194677Sthompsa struct urtw_softc *sc = usbd_xfer_softc(xfer); 4230192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 4231192873Sweongyo struct urtw_data *data; 4232192873Sweongyo 4233192873Sweongyo URTW_ASSERT_LOCKED(sc); 4234192873Sweongyo 4235192873Sweongyo switch (USB_GET_STATE(xfer)) { 4236192873Sweongyo case USB_ST_TRANSFERRED: 4237192873Sweongyo data = STAILQ_FIRST(&sc->sc_tx_active); 4238192873Sweongyo if (data == NULL) 4239192873Sweongyo goto setup; 4240192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 4241192873Sweongyo urtw_txeof(xfer, data); 4242192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); 4243192873Sweongyo /* FALLTHROUGH */ 4244192873Sweongyo case USB_ST_SETUP: 4245192873Sweongyosetup: 4246192873Sweongyo data = STAILQ_FIRST(&sc->sc_tx_pending); 4247192873Sweongyo if (data == NULL) { 4248192873Sweongyo DPRINTF(sc, URTW_DEBUG_XMIT, 4249192873Sweongyo "%s: empty pending queue\n", __func__); 4250192873Sweongyo return; 4251192873Sweongyo } 4252192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); 4253192873Sweongyo STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); 4254192873Sweongyo 4255194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 4256194228Sthompsa usbd_transfer_submit(xfer); 4257192873Sweongyo 4258192873Sweongyo URTW_UNLOCK(sc); 4259192873Sweongyo urtw_start(ifp); 4260192873Sweongyo URTW_LOCK(sc); 4261192873Sweongyo break; 4262192873Sweongyo default: 4263192873Sweongyo data = STAILQ_FIRST(&sc->sc_tx_active); 4264192873Sweongyo if (data == NULL) 4265192873Sweongyo goto setup; 4266192873Sweongyo if (data->ni != NULL) { 4267192873Sweongyo ieee80211_free_node(data->ni); 4268192873Sweongyo data->ni = NULL; 4269192873Sweongyo ifp->if_oerrors++; 4270192873Sweongyo } 4271194677Sthompsa if (error != USB_ERR_CANCELLED) { 4272194677Sthompsa usbd_xfer_set_stall(xfer); 4273192873Sweongyo goto setup; 4274192873Sweongyo } 4275192873Sweongyo break; 4276192873Sweongyo } 4277192873Sweongyo} 4278192873Sweongyo 4279192873Sweongyostatic struct urtw_data * 4280192873Sweongyo_urtw_getbuf(struct urtw_softc *sc) 4281192873Sweongyo{ 4282192873Sweongyo struct urtw_data *bf; 4283192873Sweongyo 4284192873Sweongyo bf = STAILQ_FIRST(&sc->sc_tx_inactive); 4285192873Sweongyo if (bf != NULL) 4286192873Sweongyo STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); 4287192873Sweongyo else 4288192873Sweongyo bf = NULL; 4289192873Sweongyo if (bf == NULL) 4290192873Sweongyo DPRINTF(sc, URTW_DEBUG_XMIT, "%s: %s\n", __func__, 4291192873Sweongyo "out of xmit buffers"); 4292192873Sweongyo return (bf); 4293192873Sweongyo} 4294192873Sweongyo 4295192873Sweongyostatic struct urtw_data * 4296192873Sweongyourtw_getbuf(struct urtw_softc *sc) 4297192873Sweongyo{ 4298192873Sweongyo struct urtw_data *bf; 4299192873Sweongyo 4300192873Sweongyo URTW_ASSERT_LOCKED(sc); 4301192873Sweongyo 4302192873Sweongyo bf = _urtw_getbuf(sc); 4303192873Sweongyo if (bf == NULL) { 4304192873Sweongyo struct ifnet *ifp = sc->sc_ifp; 4305192873Sweongyo 4306192873Sweongyo DPRINTF(sc, URTW_DEBUG_XMIT, "%s: stop queue\n", __func__); 4307192873Sweongyo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 4308192873Sweongyo } 4309192873Sweongyo return (bf); 4310192873Sweongyo} 4311192873Sweongyo 4312196970Sphkstatic int 4313196970Sphkurtw_isbmode(uint16_t rate) 4314192873Sweongyo{ 4315192873Sweongyo 4316196970Sphk return ((rate <= 22 && rate != 12 && rate != 18) || 4317196970Sphk rate == 44) ? (1) : (0); 4318192873Sweongyo} 4319192873Sweongyo 4320198194Sweongyostatic uint16_t 4321198194Sweongyourtw_rate2dbps(uint16_t rate) 4322198194Sweongyo{ 4323198194Sweongyo 4324198194Sweongyo switch(rate) { 4325198194Sweongyo case 12: 4326198194Sweongyo case 18: 4327198194Sweongyo case 24: 4328198194Sweongyo case 36: 4329198194Sweongyo case 48: 4330198194Sweongyo case 72: 4331198194Sweongyo case 96: 4332198194Sweongyo case 108: 4333198194Sweongyo return (rate * 2); 4334198194Sweongyo default: 4335198194Sweongyo break; 4336198194Sweongyo } 4337198194Sweongyo return (24); 4338198194Sweongyo} 4339198194Sweongyo 4340198194Sweongyostatic int 4341198194Sweongyourtw_compute_txtime(uint16_t framelen, uint16_t rate, 4342198194Sweongyo uint8_t ismgt, uint8_t isshort) 4343198194Sweongyo{ 4344198194Sweongyo uint16_t ceiling, frametime, n_dbps; 4345198194Sweongyo 4346198194Sweongyo if (urtw_isbmode(rate)) { 4347198194Sweongyo if (ismgt || !isshort || rate == 2) 4348198194Sweongyo frametime = (uint16_t)(144 + 48 + 4349198194Sweongyo (framelen * 8 / (rate / 2))); 4350198194Sweongyo else 4351198194Sweongyo frametime = (uint16_t)(72 + 24 + 4352198194Sweongyo (framelen * 8 / (rate / 2))); 4353198194Sweongyo if ((framelen * 8 % (rate / 2)) != 0) 4354198194Sweongyo frametime++; 4355198194Sweongyo } else { 4356198194Sweongyo n_dbps = urtw_rate2dbps(rate); 4357198194Sweongyo ceiling = (16 + 8 * framelen + 6) / n_dbps 4358198194Sweongyo + (((16 + 8 * framelen + 6) % n_dbps) ? 1 : 0); 4359198194Sweongyo frametime = (uint16_t)(16 + 4 + 4 * ceiling + 6); 4360198194Sweongyo } 4361198194Sweongyo return (frametime); 4362198194Sweongyo} 4363198194Sweongyo 4364198194Sweongyo/* 4365198194Sweongyo * Callback from the 802.11 layer to update the 4366198194Sweongyo * slot time based on the current setting. 4367198194Sweongyo */ 4368198194Sweongyostatic void 4369198194Sweongyourtw_updateslot(struct ifnet *ifp) 4370198194Sweongyo{ 4371198194Sweongyo struct urtw_softc *sc = ifp->if_softc; 4372198194Sweongyo struct ieee80211com *ic = ifp->if_l2com; 4373198194Sweongyo 4374198194Sweongyo ieee80211_runtask(ic, &sc->sc_updateslot_task); 4375198194Sweongyo} 4376198194Sweongyo 4377198194Sweongyostatic void 4378198194Sweongyourtw_updateslottask(void *arg, int pending) 4379198194Sweongyo{ 4380198194Sweongyo struct urtw_softc *sc = arg; 4381198194Sweongyo struct ifnet *ifp = sc->sc_ifp; 4382198194Sweongyo struct ieee80211com *ic = ifp->if_l2com; 4383198194Sweongyo int error; 4384198194Sweongyo 4385198194Sweongyo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 4386198194Sweongyo return; 4387198194Sweongyo 4388198194Sweongyo URTW_LOCK(sc); 4389198194Sweongyo if (sc->sc_flags & URTW_RTL8187B) { 4390198194Sweongyo urtw_write8_m(sc, URTW_SIFS, 0x22); 4391198194Sweongyo if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) 4392198194Sweongyo urtw_write8_m(sc, URTW_SLOT, 0x9); 4393198194Sweongyo else 4394198194Sweongyo urtw_write8_m(sc, URTW_SLOT, 0x14); 4395198194Sweongyo urtw_write8_m(sc, URTW_8187B_EIFS, 0x5b); 4396198194Sweongyo urtw_write8_m(sc, URTW_CARRIER_SCOUNT, 0x5b); 4397198194Sweongyo } else { 4398198194Sweongyo urtw_write8_m(sc, URTW_SIFS, 0x22); 4399198194Sweongyo if (sc->sc_state == IEEE80211_S_ASSOC && 4400198194Sweongyo ic->ic_flags & IEEE80211_F_SHSLOT) 4401198194Sweongyo urtw_write8_m(sc, URTW_SLOT, 0x9); 4402198194Sweongyo else 4403198194Sweongyo urtw_write8_m(sc, URTW_SLOT, 0x14); 4404198194Sweongyo if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) { 4405198194Sweongyo urtw_write8_m(sc, URTW_DIFS, 0x14); 4406198194Sweongyo urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x14); 4407198194Sweongyo urtw_write8_m(sc, URTW_CW_VAL, 0x73); 4408198194Sweongyo } else { 4409198194Sweongyo urtw_write8_m(sc, URTW_DIFS, 0x24); 4410198194Sweongyo urtw_write8_m(sc, URTW_EIFS, 0x5b - 0x24); 4411198194Sweongyo urtw_write8_m(sc, URTW_CW_VAL, 0xa5); 4412198194Sweongyo } 4413198194Sweongyo } 4414198194Sweongyofail: 4415198194Sweongyo URTW_UNLOCK(sc); 4416198194Sweongyo} 4417198194Sweongyo 4418203087Sweongyostatic void 4419203087Sweongyourtw_sysctl_node(struct urtw_softc *sc) 4420203087Sweongyo{ 4421203087Sweongyo#define URTW_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 4422203087Sweongyo SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 4423203087Sweongyo struct sysctl_ctx_list *ctx; 4424203087Sweongyo struct sysctl_oid_list *child, *parent; 4425203087Sweongyo struct sysctl_oid *tree; 4426203087Sweongyo struct urtw_stats *stats = &sc->sc_stats; 4427203087Sweongyo 4428203087Sweongyo ctx = device_get_sysctl_ctx(sc->sc_dev); 4429203087Sweongyo child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); 4430203087Sweongyo 4431203087Sweongyo tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 4432203087Sweongyo NULL, "URTW statistics"); 4433203087Sweongyo parent = SYSCTL_CHILDREN(tree); 4434203087Sweongyo 4435203087Sweongyo /* Tx statistics. */ 4436203087Sweongyo tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 4437203087Sweongyo NULL, "Tx MAC statistics"); 4438203087Sweongyo child = SYSCTL_CHILDREN(tree); 4439203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "1m", &stats->txrates[0], 4440203087Sweongyo "1 Mbit/s"); 4441203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "2m", &stats->txrates[1], 4442203087Sweongyo "2 Mbit/s"); 4443203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "5.5m", &stats->txrates[2], 4444203087Sweongyo "5.5 Mbit/s"); 4445203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "6m", &stats->txrates[4], 4446203087Sweongyo "6 Mbit/s"); 4447203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "9m", &stats->txrates[5], 4448203087Sweongyo "9 Mbit/s"); 4449203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "11m", &stats->txrates[3], 4450203087Sweongyo "11 Mbit/s"); 4451203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "12m", &stats->txrates[6], 4452203087Sweongyo "12 Mbit/s"); 4453203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "18m", &stats->txrates[7], 4454203087Sweongyo "18 Mbit/s"); 4455203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "24m", &stats->txrates[8], 4456203087Sweongyo "24 Mbit/s"); 4457203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "36m", &stats->txrates[9], 4458203087Sweongyo "36 Mbit/s"); 4459203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "48m", &stats->txrates[10], 4460203087Sweongyo "48 Mbit/s"); 4461203087Sweongyo URTW_SYSCTL_STAT_ADD32(ctx, child, "54m", &stats->txrates[11], 4462203087Sweongyo "54 Mbit/s"); 4463203087Sweongyo#undef URTW_SYSCTL_STAT_ADD32 4464203087Sweongyo} 4465203087Sweongyo 4466192873Sweongyostatic device_method_t urtw_methods[] = { 4467192873Sweongyo DEVMETHOD(device_probe, urtw_match), 4468192873Sweongyo DEVMETHOD(device_attach, urtw_attach), 4469192873Sweongyo DEVMETHOD(device_detach, urtw_detach), 4470259454Shselasky DEVMETHOD_END 4471192873Sweongyo}; 4472192873Sweongyostatic driver_t urtw_driver = { 4473235000Shselasky .name = "urtw", 4474235000Shselasky .methods = urtw_methods, 4475235000Shselasky .size = sizeof(struct urtw_softc) 4476192873Sweongyo}; 4477192873Sweongyostatic devclass_t urtw_devclass; 4478192873Sweongyo 4479192873SweongyoDRIVER_MODULE(urtw, uhub, urtw_driver, urtw_devclass, NULL, 0); 4480192873SweongyoMODULE_DEPEND(urtw, wlan, 1, 1, 1); 4481192873SweongyoMODULE_DEPEND(urtw, usb, 1, 1, 1); 4482212122SthompsaMODULE_VERSION(urtw, 1); 4483