1*54fbbda3Sjsg /* $OpenBSD: if_urtw.c,v 1.74 2024/09/01 03:09:00 jsg Exp $ */ 2098d4431Smartynas 30e584c77Skevlo /*- 43d4b849eSmartynas * Copyright (c) 2009 Martynas Venckus <martynas@openbsd.org> 50187f01eSjsg * Copyright (c) 2008 Weongyo Jeong <weongyo@FreeBSD.org> 60e584c77Skevlo * 70187f01eSjsg * Permission to use, copy, modify, and distribute this software for any 80187f01eSjsg * purpose with or without fee is hereby granted, provided that the above 90187f01eSjsg * copyright notice and this permission notice appear in all copies. 100e584c77Skevlo * 110187f01eSjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 120187f01eSjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 130187f01eSjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 140187f01eSjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 150187f01eSjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 160187f01eSjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 170187f01eSjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 180e584c77Skevlo */ 190e584c77Skevlo 200e584c77Skevlo #include "bpfilter.h" 210e584c77Skevlo 220e584c77Skevlo #include <sys/param.h> 230e584c77Skevlo #include <sys/sockio.h> 240e584c77Skevlo #include <sys/mbuf.h> 250e584c77Skevlo #include <sys/systm.h> 260e584c77Skevlo #include <sys/timeout.h> 270e584c77Skevlo #include <sys/device.h> 289b18ffb8Sguenther #include <sys/endian.h> 290e584c77Skevlo 300e584c77Skevlo #if NBPFILTER > 0 310e584c77Skevlo #include <net/bpf.h> 320e584c77Skevlo #endif 330e584c77Skevlo #include <net/if.h> 340e584c77Skevlo #include <net/if_dl.h> 350e584c77Skevlo #include <net/if_media.h> 360e584c77Skevlo 370e584c77Skevlo #include <netinet/in.h> 380e584c77Skevlo #include <netinet/if_ether.h> 390e584c77Skevlo 400e584c77Skevlo #include <net80211/ieee80211_var.h> 410e584c77Skevlo #include <net80211/ieee80211_radiotap.h> 420e584c77Skevlo 430e584c77Skevlo #include <dev/usb/usb.h> 440e584c77Skevlo #include <dev/usb/usbdi.h> 450e584c77Skevlo #include <dev/usb/usbdi_util.h> 460e584c77Skevlo #include <dev/usb/usbdevs.h> 470e584c77Skevlo 480e584c77Skevlo #include <dev/usb/if_urtwreg.h> 490e584c77Skevlo 500e584c77Skevlo #ifdef URTW_DEBUG 51e5e1f14aSmartynas #define DPRINTF(x) do { if (urtw_debug) printf x; } while (0) 52e5e1f14aSmartynas #define DPRINTFN(n, x) do { if (urtw_debug >= (n)) printf x; } while (0) 530e584c77Skevlo int urtw_debug = 0; 540e584c77Skevlo #else 550e584c77Skevlo #define DPRINTF(x) 560e584c77Skevlo #define DPRINTFN(n, x) 570e584c77Skevlo #endif 580e584c77Skevlo 59c0e29f5aSmartynas /* 60c0e29f5aSmartynas * Recognized device vendors/products. 61c0e29f5aSmartynas */ 62c0e29f5aSmartynas static const struct urtw_type { 63c0e29f5aSmartynas struct usb_devno dev; 64c0e29f5aSmartynas uint8_t rev; 65c0e29f5aSmartynas } urtw_devs[] = { 66c0e29f5aSmartynas #define URTW_DEV_RTL8187(v, p) \ 67c0e29f5aSmartynas { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187 } 683d4b849eSmartynas #define URTW_DEV_RTL8187B(v, p) \ 693d4b849eSmartynas { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, URTW_HWREV_8187B } 70c0e29f5aSmartynas /* Realtek RTL8187 devices. */ 71c83881c7Smartynas URTW_DEV_RTL8187(ASUS, P5B_WIFI), 72c0e29f5aSmartynas URTW_DEV_RTL8187(DICKSMITH, RTL8187), 73c83881c7Smartynas URTW_DEV_RTL8187(LINKSYS4, WUSB54GCV2), 74c0e29f5aSmartynas URTW_DEV_RTL8187(LOGITEC, RTL8187), 75c0e29f5aSmartynas URTW_DEV_RTL8187(NETGEAR, WG111V2), 76c0e29f5aSmartynas URTW_DEV_RTL8187(REALTEK, RTL8187), 77f0bed7cbSmartynas URTW_DEV_RTL8187(SITECOMEU, WL168V1), 78c0e29f5aSmartynas URTW_DEV_RTL8187(SPHAIRON, RTL8187), 79c0e29f5aSmartynas URTW_DEV_RTL8187(SURECOM, EP9001G2A), 803d4b849eSmartynas /* Realtek RTL8187B devices. */ 813d4b849eSmartynas URTW_DEV_RTL8187B(BELKIN, F5D7050E), 823d4b849eSmartynas URTW_DEV_RTL8187B(NETGEAR, WG111V3), 833d4b849eSmartynas URTW_DEV_RTL8187B(REALTEK, RTL8187B_0), 843d4b849eSmartynas URTW_DEV_RTL8187B(REALTEK, RTL8187B_1), 853d4b849eSmartynas URTW_DEV_RTL8187B(REALTEK, RTL8187B_2), 86c83881c7Smartynas URTW_DEV_RTL8187B(SITECOMEU, WL168V4) 87c0e29f5aSmartynas #undef URTW_DEV_RTL8187 883d4b849eSmartynas #undef URTW_DEV_RTL8187B 890e584c77Skevlo }; 90c0e29f5aSmartynas #define urtw_lookup(v, p) \ 91c0e29f5aSmartynas ((const struct urtw_type *)usb_lookup(urtw_devs, v, p)) 920e584c77Skevlo 930ec995ceSmartynas /* 940ec995ceSmartynas * Helper read/write macros. 950ec995ceSmartynas */ 960e584c77Skevlo #define urtw_read8_m(sc, val, data) do { \ 970ec995ceSmartynas error = urtw_read8_c(sc, val, data, 0); \ 980ec995ceSmartynas if (error != 0) \ 990ec995ceSmartynas goto fail; \ 1000ec995ceSmartynas } while (0) 1010ec995ceSmartynas #define urtw_read8_idx_m(sc, val, data, idx) do { \ 1020ec995ceSmartynas error = urtw_read8_c(sc, val, data, idx); \ 1030e584c77Skevlo if (error != 0) \ 1040e584c77Skevlo goto fail; \ 1050e584c77Skevlo } while (0) 1060e584c77Skevlo #define urtw_write8_m(sc, val, data) do { \ 1070ec995ceSmartynas error = urtw_write8_c(sc, val, data, 0); \ 1080ec995ceSmartynas if (error != 0) \ 1090ec995ceSmartynas goto fail; \ 1100ec995ceSmartynas } while (0) 1110ec995ceSmartynas #define urtw_write8_idx_m(sc, val, data, idx) do { \ 1120ec995ceSmartynas error = urtw_write8_c(sc, val, data, idx); \ 1130e584c77Skevlo if (error != 0) \ 1140e584c77Skevlo goto fail; \ 1150e584c77Skevlo } while (0) 1160e584c77Skevlo #define urtw_read16_m(sc, val, data) do { \ 1170ec995ceSmartynas error = urtw_read16_c(sc, val, data, 0); \ 1180ec995ceSmartynas if (error != 0) \ 1190ec995ceSmartynas goto fail; \ 1200ec995ceSmartynas } while (0) 1210ec995ceSmartynas #define urtw_read16_idx_m(sc, val, data, idx) do { \ 1220ec995ceSmartynas error = urtw_read16_c(sc, val, data, idx); \ 1230e584c77Skevlo if (error != 0) \ 1240e584c77Skevlo goto fail; \ 1250e584c77Skevlo } while (0) 1260e584c77Skevlo #define urtw_write16_m(sc, val, data) do { \ 1270ec995ceSmartynas error = urtw_write16_c(sc, val, data, 0); \ 1280ec995ceSmartynas if (error != 0) \ 1290ec995ceSmartynas goto fail; \ 1300ec995ceSmartynas } while (0) 1310ec995ceSmartynas #define urtw_write16_idx_m(sc, val, data, idx) do { \ 1320ec995ceSmartynas error = urtw_write16_c(sc, val, data, idx); \ 1330e584c77Skevlo if (error != 0) \ 1340e584c77Skevlo goto fail; \ 1350e584c77Skevlo } while (0) 1360e584c77Skevlo #define urtw_read32_m(sc, val, data) do { \ 1370ec995ceSmartynas error = urtw_read32_c(sc, val, data, 0); \ 1380ec995ceSmartynas if (error != 0) \ 1390ec995ceSmartynas goto fail; \ 1400ec995ceSmartynas } while (0) 1410ec995ceSmartynas #define urtw_read32_idx_m(sc, val, data, idx) do { \ 1420ec995ceSmartynas error = urtw_read32_c(sc, val, data, idx); \ 1430e584c77Skevlo if (error != 0) \ 1440e584c77Skevlo goto fail; \ 1450e584c77Skevlo } while (0) 1460e584c77Skevlo #define urtw_write32_m(sc, val, data) do { \ 1470ec995ceSmartynas error = urtw_write32_c(sc, val, data, 0); \ 1480ec995ceSmartynas if (error != 0) \ 1490ec995ceSmartynas goto fail; \ 1500ec995ceSmartynas } while (0) 1510ec995ceSmartynas #define urtw_write32_idx_m(sc, val, data, idx) do { \ 1520ec995ceSmartynas error = urtw_write32_c(sc, val, data, idx); \ 1530e584c77Skevlo if (error != 0) \ 1540e584c77Skevlo goto fail; \ 1550e584c77Skevlo } while (0) 1560e584c77Skevlo #define urtw_8187_write_phy_ofdm(sc, val, data) do { \ 1570e584c77Skevlo error = urtw_8187_write_phy_ofdm_c(sc, val, data); \ 1580e584c77Skevlo if (error != 0) \ 1590e584c77Skevlo goto fail; \ 1600e584c77Skevlo } while (0) 1610e584c77Skevlo #define urtw_8187_write_phy_cck(sc, val, data) do { \ 1620e584c77Skevlo error = urtw_8187_write_phy_cck_c(sc, val, data); \ 1630e584c77Skevlo if (error != 0) \ 1640e584c77Skevlo goto fail; \ 1650e584c77Skevlo } while (0) 1660e584c77Skevlo #define urtw_8225_write(sc, val, data) do { \ 1670e584c77Skevlo error = urtw_8225_write_c(sc, val, data); \ 1680e584c77Skevlo if (error != 0) \ 1690e584c77Skevlo goto fail; \ 1700e584c77Skevlo } while (0) 1710e584c77Skevlo 1720e584c77Skevlo struct urtw_pair { 1730e584c77Skevlo uint32_t reg; 1740e584c77Skevlo uint32_t val; 1750e584c77Skevlo }; 1760e584c77Skevlo 1773d4b849eSmartynas struct urtw_pair_idx { 1783d4b849eSmartynas uint8_t reg; 1793d4b849eSmartynas uint8_t val; 1803d4b849eSmartynas uint8_t idx; 1813d4b849eSmartynas }; 1823d4b849eSmartynas 1833d4b849eSmartynas static struct urtw_pair_idx urtw_8187b_regtbl[] = { 1843d4b849eSmartynas { 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 }, 1853d4b849eSmartynas { 0xf3, 0x00, 0 }, { 0xf4, 0x32, 0 }, { 0xf5, 0x43, 0 }, 1863d4b849eSmartynas { 0xf6, 0x00, 0 }, { 0xf7, 0x00, 0 }, { 0xf8, 0x46, 0 }, 1873d4b849eSmartynas { 0xf9, 0xa4, 0 }, { 0xfa, 0x00, 0 }, { 0xfb, 0x00, 0 }, 1883d4b849eSmartynas { 0xfc, 0x96, 0 }, { 0xfd, 0xa4, 0 }, { 0xfe, 0x00, 0 }, 1893d4b849eSmartynas { 0xff, 0x00, 0 }, 1903d4b849eSmartynas 1913d4b849eSmartynas { 0x58, 0x4b, 1 }, { 0x59, 0x00, 1 }, { 0x5a, 0x4b, 1 }, 1923d4b849eSmartynas { 0x5b, 0x00, 1 }, { 0x60, 0x4b, 1 }, { 0x61, 0x09, 1 }, 1933d4b849eSmartynas { 0x62, 0x4b, 1 }, { 0x63, 0x09, 1 }, { 0xce, 0x0f, 1 }, 1943d4b849eSmartynas { 0xcf, 0x00, 1 }, { 0xe0, 0xff, 1 }, { 0xe1, 0x0f, 1 }, 1953d4b849eSmartynas { 0xe2, 0x00, 1 }, { 0xf0, 0x4e, 1 }, { 0xf1, 0x01, 1 }, 1963d4b849eSmartynas { 0xf2, 0x02, 1 }, { 0xf3, 0x03, 1 }, { 0xf4, 0x04, 1 }, 1973d4b849eSmartynas { 0xf5, 0x05, 1 }, { 0xf6, 0x06, 1 }, { 0xf7, 0x07, 1 }, 1983d4b849eSmartynas { 0xf8, 0x08, 1 }, 1993d4b849eSmartynas 2003d4b849eSmartynas { 0x4e, 0x00, 2 }, { 0x0c, 0x04, 2 }, { 0x21, 0x61, 2 }, 2013d4b849eSmartynas { 0x22, 0x68, 2 }, { 0x23, 0x6f, 2 }, { 0x24, 0x76, 2 }, 2023d4b849eSmartynas { 0x25, 0x7d, 2 }, { 0x26, 0x84, 2 }, { 0x27, 0x8d, 2 }, 2033d4b849eSmartynas { 0x4d, 0x08, 2 }, { 0x50, 0x05, 2 }, { 0x51, 0xf5, 2 }, 2043d4b849eSmartynas { 0x52, 0x04, 2 }, { 0x53, 0xa0, 2 }, { 0x54, 0x1f, 2 }, 2053d4b849eSmartynas { 0x55, 0x23, 2 }, { 0x56, 0x45, 2 }, { 0x57, 0x67, 2 }, 2063d4b849eSmartynas { 0x58, 0x08, 2 }, { 0x59, 0x08, 2 }, { 0x5a, 0x08, 2 }, 2073d4b849eSmartynas { 0x5b, 0x08, 2 }, { 0x60, 0x08, 2 }, { 0x61, 0x08, 2 }, 2083d4b849eSmartynas { 0x62, 0x08, 2 }, { 0x63, 0x08, 2 }, { 0x64, 0xcf, 2 }, 2093d4b849eSmartynas { 0x72, 0x56, 2 }, { 0x73, 0x9a, 2 }, 2103d4b849eSmartynas 2113d4b849eSmartynas { 0x34, 0xf0, 0 }, { 0x35, 0x0f, 0 }, { 0x5b, 0x40, 0 }, 2123d4b849eSmartynas { 0x84, 0x88, 0 }, { 0x85, 0x24, 0 }, { 0x88, 0x54, 0 }, 2133d4b849eSmartynas { 0x8b, 0xb8, 0 }, { 0x8c, 0x07, 0 }, { 0x8d, 0x00, 0 }, 2143d4b849eSmartynas { 0x94, 0x1b, 0 }, { 0x95, 0x12, 0 }, { 0x96, 0x00, 0 }, 2153d4b849eSmartynas { 0x97, 0x06, 0 }, { 0x9d, 0x1a, 0 }, { 0x9f, 0x10, 0 }, 2163d4b849eSmartynas { 0xb4, 0x22, 0 }, { 0xbe, 0x80, 0 }, { 0xdb, 0x00, 0 }, 2173d4b849eSmartynas { 0xee, 0x00, 0 }, { 0x91, 0x03, 0 }, 2183d4b849eSmartynas 2193d4b849eSmartynas { 0x4c, 0x00, 2 }, { 0x9f, 0x00, 3 }, { 0x8c, 0x01, 0 }, 2203d4b849eSmartynas { 0x8d, 0x10, 0 }, { 0x8e, 0x08, 0 }, { 0x8f, 0x00, 0 } 2213d4b849eSmartynas }; 2223d4b849eSmartynas 2230e584c77Skevlo static uint8_t urtw_8225_agc[] = { 2240e584c77Skevlo 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9c, 0x9b, 2250e584c77Skevlo 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 2260e584c77Skevlo 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 2270e584c77Skevlo 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 2280e584c77Skevlo 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 2290e584c77Skevlo 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 2300e584c77Skevlo 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 2310e584c77Skevlo 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 2320e584c77Skevlo 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 2330e584c77Skevlo 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 2340e584c77Skevlo 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 2350e584c77Skevlo 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 2360e584c77Skevlo }; 2370e584c77Skevlo 2380e584c77Skevlo static uint32_t urtw_8225_channel[] = { 2390e584c77Skevlo 0x0000, /* dummy channel 0 */ 2400e584c77Skevlo 0x085c, /* 1 */ 2410e584c77Skevlo 0x08dc, /* 2 */ 2420e584c77Skevlo 0x095c, /* 3 */ 2430e584c77Skevlo 0x09dc, /* 4 */ 2440e584c77Skevlo 0x0a5c, /* 5 */ 2450e584c77Skevlo 0x0adc, /* 6 */ 2460e584c77Skevlo 0x0b5c, /* 7 */ 2470e584c77Skevlo 0x0bdc, /* 8 */ 2480e584c77Skevlo 0x0c5c, /* 9 */ 2490e584c77Skevlo 0x0cdc, /* 10 */ 2500e584c77Skevlo 0x0d5c, /* 11 */ 2510e584c77Skevlo 0x0ddc, /* 12 */ 2520e584c77Skevlo 0x0e5c, /* 13 */ 2530e584c77Skevlo 0x0f72, /* 14 */ 2540e584c77Skevlo }; 2550e584c77Skevlo 2560e584c77Skevlo static uint8_t urtw_8225_gain[] = { 2570e584c77Skevlo 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ 2580e584c77Skevlo 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ 2590e584c77Skevlo 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ 2600e584c77Skevlo 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ 2610e584c77Skevlo 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ 2620e584c77Skevlo 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ 2630e584c77Skevlo 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ 2640e584c77Skevlo }; 2650e584c77Skevlo 2660e584c77Skevlo static struct urtw_pair urtw_8225_rf_part1[] = { 2670e584c77Skevlo { 0x00, 0x0067 }, { 0x01, 0x0fe0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 2680e584c77Skevlo { 0x04, 0x0486 }, { 0x05, 0x0bc0 }, { 0x06, 0x0ae6 }, { 0x07, 0x082a }, 2690e584c77Skevlo { 0x08, 0x001f }, { 0x09, 0x0334 }, { 0x0a, 0x0fd4 }, { 0x0b, 0x0391 }, 2703e951b55Smartynas { 0x0c, 0x0050 }, { 0x0d, 0x06db }, { 0x0e, 0x0029 }, { 0x0f, 0x0914 } 2710e584c77Skevlo }; 2720e584c77Skevlo 2730e584c77Skevlo static struct urtw_pair urtw_8225_rf_part2[] = { 2740e584c77Skevlo { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 }, 2750e584c77Skevlo { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 }, 2760e584c77Skevlo { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x09 }, { 0x0b, 0x80 }, 2770e584c77Skevlo { 0x0c, 0x01 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, { 0x10, 0x84 }, 2780e584c77Skevlo { 0x11, 0x06 }, { 0x12, 0x20 }, { 0x13, 0x20 }, { 0x14, 0x00 }, 2790e584c77Skevlo { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, { 0x18, 0xef }, 2800e584c77Skevlo { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x76 }, { 0x1c, 0x04 }, 2810e584c77Skevlo { 0x1e, 0x95 }, { 0x1f, 0x75 }, { 0x20, 0x1f }, { 0x21, 0x27 }, 2820e584c77Skevlo { 0x22, 0x16 }, { 0x24, 0x46 }, { 0x25, 0x20 }, { 0x26, 0x90 }, 2830e584c77Skevlo { 0x27, 0x88 } 2840e584c77Skevlo }; 2850e584c77Skevlo 2860e584c77Skevlo static struct urtw_pair urtw_8225_rf_part3[] = { 2870e584c77Skevlo { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 }, 2880e584c77Skevlo { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x10, 0x9b }, 2890e584c77Skevlo { 0x11, 0x88 }, { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, 2900e584c77Skevlo { 0x1a, 0xa0 }, { 0x1b, 0x08 }, { 0x40, 0x86 }, { 0x41, 0x8d }, 2910e584c77Skevlo { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x1f }, { 0x45, 0x1e }, 2920e584c77Skevlo { 0x46, 0x1a }, { 0x47, 0x15 }, { 0x48, 0x10 }, { 0x49, 0x0a }, 2930e584c77Skevlo { 0x4a, 0x05 }, { 0x4b, 0x02 }, { 0x4c, 0x05 } 2940e584c77Skevlo }; 2950e584c77Skevlo 2960e584c77Skevlo static uint16_t urtw_8225_rxgain[] = { 2970e584c77Skevlo 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, 2980e584c77Skevlo 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, 2990e584c77Skevlo 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, 3000e584c77Skevlo 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, 3010e584c77Skevlo 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, 3020e584c77Skevlo 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, 3030e584c77Skevlo 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, 3040e584c77Skevlo 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, 3050e584c77Skevlo 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, 3060e584c77Skevlo 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, 3070e584c77Skevlo 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, 3080e584c77Skevlo 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb 3090e584c77Skevlo }; 3100e584c77Skevlo 3110e584c77Skevlo static uint8_t urtw_8225_threshold[] = { 3123e951b55Smartynas 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd 3130e584c77Skevlo }; 3140e584c77Skevlo 3150e584c77Skevlo static uint8_t urtw_8225_tx_gain_cck_ofdm[] = { 3160e584c77Skevlo 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e 3170e584c77Skevlo }; 3180e584c77Skevlo 3190e584c77Skevlo static uint8_t urtw_8225_txpwr_cck[] = { 3200e584c77Skevlo 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, 3210e584c77Skevlo 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, 3220e584c77Skevlo 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, 3230e584c77Skevlo 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, 3240e584c77Skevlo 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, 3250e584c77Skevlo 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 3260e584c77Skevlo }; 3270e584c77Skevlo 3280e584c77Skevlo static uint8_t urtw_8225_txpwr_cck_ch14[] = { 3290e584c77Skevlo 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 3300e584c77Skevlo 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, 3310e584c77Skevlo 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, 3320e584c77Skevlo 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, 3330e584c77Skevlo 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 3340e584c77Skevlo 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 3350e584c77Skevlo }; 3360e584c77Skevlo 3370e584c77Skevlo static uint8_t urtw_8225_txpwr_ofdm[] = { 3380e584c77Skevlo 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 3390e584c77Skevlo }; 3400e584c77Skevlo 3413d4b849eSmartynas static uint8_t urtw_8225v2_agc[] = { 3423d4b849eSmartynas 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 3433d4b849eSmartynas 0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x47, 3443d4b849eSmartynas 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, 3453d4b849eSmartynas 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 3463d4b849eSmartynas 0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17, 3473d4b849eSmartynas 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, 3483d4b849eSmartynas 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 3493d4b849eSmartynas 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 3503d4b849eSmartynas 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 3513d4b849eSmartynas 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 3523d4b849eSmartynas 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a, 3533d4b849eSmartynas 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 3543d4b849eSmartynas 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 3553d4b849eSmartynas 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 3563d4b849eSmartynas 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 3573d4b849eSmartynas 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 3583d4b849eSmartynas }; 3593d4b849eSmartynas 3603d4b849eSmartynas static uint8_t urtw_8225v2_ofdm[] = { 3613d4b849eSmartynas 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, 3623d4b849eSmartynas 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 3633d4b849eSmartynas 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, 3643d4b849eSmartynas 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, 3653d4b849eSmartynas 0x0a, 0xe1, 0x2c, 0x8a, 0x86, 0x83, 0x34, 0x0f, 3663d4b849eSmartynas 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, 3673d4b849eSmartynas 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, 3683d4b849eSmartynas 0x6d, 0x3c, 0xfb, 0x07 3693d4b849eSmartynas }; 3703d4b849eSmartynas 3710e584c77Skevlo static uint8_t urtw_8225v2_gain_bg[] = { 3720e584c77Skevlo 0x23, 0x15, 0xa5, /* -82-1dbm */ 3730e584c77Skevlo 0x23, 0x15, 0xb5, /* -82-2dbm */ 3740e584c77Skevlo 0x23, 0x15, 0xc5, /* -82-3dbm */ 3750e584c77Skevlo 0x33, 0x15, 0xc5, /* -78dbm */ 3760e584c77Skevlo 0x43, 0x15, 0xc5, /* -74dbm */ 3770e584c77Skevlo 0x53, 0x15, 0xc5, /* -70dbm */ 3780e584c77Skevlo 0x63, 0x15, 0xc5, /* -66dbm */ 3790e584c77Skevlo }; 3800e584c77Skevlo 3810e584c77Skevlo static struct urtw_pair urtw_8225v2_rf_part1[] = { 3820e584c77Skevlo { 0x00, 0x02bf }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 3830e584c77Skevlo { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a }, 3840e584c77Skevlo { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb }, 3850e584c77Skevlo { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 } 3860e584c77Skevlo }; 3870e584c77Skevlo 3880e584c77Skevlo static struct urtw_pair urtw_8225v2_rf_part2[] = { 3890e584c77Skevlo { 0x00, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x42 }, { 0x03, 0x00 }, 3900e584c77Skevlo { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x40 }, { 0x07, 0x00 }, 3910e584c77Skevlo { 0x08, 0x40 }, { 0x09, 0xfe }, { 0x0a, 0x08 }, { 0x0b, 0x80 }, 3920e584c77Skevlo { 0x0c, 0x01 }, { 0x0d, 0x43 }, { 0x0e, 0xd3 }, { 0x0f, 0x38 }, 3930e584c77Skevlo { 0x10, 0x84 }, { 0x11, 0x07 }, { 0x12, 0x20 }, { 0x13, 0x20 }, 3940e584c77Skevlo { 0x14, 0x00 }, { 0x15, 0x40 }, { 0x16, 0x00 }, { 0x17, 0x40 }, 3950e584c77Skevlo { 0x18, 0xef }, { 0x19, 0x19 }, { 0x1a, 0x20 }, { 0x1b, 0x15 }, 3960e584c77Skevlo { 0x1c, 0x04 }, { 0x1d, 0xc5 }, { 0x1e, 0x95 }, { 0x1f, 0x75 }, 3970e584c77Skevlo { 0x20, 0x1f }, { 0x21, 0x17 }, { 0x22, 0x16 }, { 0x23, 0x80 }, 3980e584c77Skevlo { 0x24, 0x46 }, { 0x25, 0x00 }, { 0x26, 0x90 }, { 0x27, 0x88 } 3990e584c77Skevlo }; 4000e584c77Skevlo 4010e584c77Skevlo static struct urtw_pair urtw_8225v2_rf_part3[] = { 4020e584c77Skevlo { 0x00, 0x98 }, { 0x03, 0x20 }, { 0x04, 0x7e }, { 0x05, 0x12 }, 4030e584c77Skevlo { 0x06, 0xfc }, { 0x07, 0x78 }, { 0x08, 0x2e }, { 0x09, 0x11 }, 4040e584c77Skevlo { 0x0a, 0x17 }, { 0x0b, 0x11 }, { 0x10, 0x9b }, { 0x11, 0x88 }, 4050e584c77Skevlo { 0x12, 0x47 }, { 0x13, 0xd0 }, { 0x19, 0x00 }, { 0x1a, 0xa0 }, 4060e584c77Skevlo { 0x1b, 0x08 }, { 0x1d, 0x00 }, { 0x40, 0x86 }, { 0x41, 0x9d }, 4070e584c77Skevlo { 0x42, 0x15 }, { 0x43, 0x18 }, { 0x44, 0x36 }, { 0x45, 0x35 }, 4080e584c77Skevlo { 0x46, 0x2e }, { 0x47, 0x25 }, { 0x48, 0x1c }, { 0x49, 0x12 }, 4090e584c77Skevlo { 0x4a, 0x09 }, { 0x4b, 0x04 }, { 0x4c, 0x05 } 4100e584c77Skevlo }; 4110e584c77Skevlo 4120e584c77Skevlo static uint16_t urtw_8225v2_rxgain[] = { 4133d4b849eSmartynas 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, 4143d4b849eSmartynas 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, 4153d4b849eSmartynas 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, 4163d4b849eSmartynas 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, 4173d4b849eSmartynas 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, 4183d4b849eSmartynas 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, 4193d4b849eSmartynas 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, 4203d4b849eSmartynas 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, 4213d4b849eSmartynas 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, 4223d4b849eSmartynas 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, 4230e584c77Skevlo 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 4240e584c77Skevlo 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb 4250e584c77Skevlo }; 4260e584c77Skevlo 4270e584c77Skevlo static uint8_t urtw_8225v2_tx_gain_cck_ofdm[] = { 4280e584c77Skevlo 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 4290e584c77Skevlo 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 4300e584c77Skevlo 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 4310e584c77Skevlo 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 4320e584c77Skevlo 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 4333e951b55Smartynas 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 4340e584c77Skevlo }; 4350e584c77Skevlo 4360e584c77Skevlo static uint8_t urtw_8225v2_txpwr_cck[] = { 4373d4b849eSmartynas 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, 4383d4b849eSmartynas 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, 4393d4b849eSmartynas 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, 4403d4b849eSmartynas 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 4410e584c77Skevlo }; 4420e584c77Skevlo 4430e584c77Skevlo static uint8_t urtw_8225v2_txpwr_cck_ch14[] = { 4443d4b849eSmartynas 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, 4453d4b849eSmartynas 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, 4463d4b849eSmartynas 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, 4473d4b849eSmartynas 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 4483d4b849eSmartynas }; 4493d4b849eSmartynas 4503d4b849eSmartynas static struct urtw_pair urtw_8225v2_b_rf[] = { 4513d4b849eSmartynas { 0x00, 0x00b7 }, { 0x01, 0x0ee0 }, { 0x02, 0x044d }, { 0x03, 0x0441 }, 4523d4b849eSmartynas { 0x04, 0x08c3 }, { 0x05, 0x0c72 }, { 0x06, 0x00e6 }, { 0x07, 0x082a }, 4533d4b849eSmartynas { 0x08, 0x003f }, { 0x09, 0x0335 }, { 0x0a, 0x09d4 }, { 0x0b, 0x07bb }, 4543d4b849eSmartynas { 0x0c, 0x0850 }, { 0x0d, 0x0cdf }, { 0x0e, 0x002b }, { 0x0f, 0x0114 }, 4553d4b849eSmartynas { 0x00, 0x01b7 } 4560e584c77Skevlo }; 4570e584c77Skevlo 4580e584c77Skevlo static struct urtw_pair urtw_ratetable[] = { 4590e584c77Skevlo { 2, 0 }, { 4, 1 }, { 11, 2 }, { 12, 4 }, { 18, 5 }, 4600e584c77Skevlo { 22, 3 }, { 24, 6 }, { 36, 7 }, { 48, 8 }, { 72, 9 }, 4610e584c77Skevlo { 96, 10 }, { 108, 11 } 4620e584c77Skevlo }; 4630e584c77Skevlo 4640e584c77Skevlo int urtw_init(struct ifnet *); 4650e584c77Skevlo void urtw_stop(struct ifnet *, int); 4660e584c77Skevlo int urtw_ioctl(struct ifnet *, u_long, caddr_t); 4670e584c77Skevlo void urtw_start(struct ifnet *); 4680e584c77Skevlo int urtw_alloc_rx_data_list(struct urtw_softc *); 4690e584c77Skevlo void urtw_free_rx_data_list(struct urtw_softc *); 4700e584c77Skevlo int urtw_alloc_tx_data_list(struct urtw_softc *); 4710e584c77Skevlo void urtw_free_tx_data_list(struct urtw_softc *); 472ab0b1be7Smglocker void urtw_rxeof(struct usbd_xfer *, void *, 4730e584c77Skevlo usbd_status); 4740e584c77Skevlo int urtw_tx_start(struct urtw_softc *, 4750e584c77Skevlo struct ieee80211_node *, struct mbuf *, int); 476ab0b1be7Smglocker void urtw_txeof_low(struct usbd_xfer *, void *, 4770e584c77Skevlo usbd_status); 478ab0b1be7Smglocker void urtw_txeof_normal(struct usbd_xfer *, void *, 4790e584c77Skevlo usbd_status); 4800e584c77Skevlo void urtw_next_scan(void *); 4810e584c77Skevlo void urtw_task(void *); 4820e584c77Skevlo void urtw_ledusbtask(void *); 4830e584c77Skevlo void urtw_ledtask(void *); 4840e584c77Skevlo int urtw_media_change(struct ifnet *); 4850e584c77Skevlo int urtw_newstate(struct ieee80211com *, enum ieee80211_state, int); 4860e584c77Skevlo void urtw_watchdog(struct ifnet *); 4870e584c77Skevlo void urtw_set_multi(struct urtw_softc *); 4880e584c77Skevlo void urtw_set_chan(struct urtw_softc *, struct ieee80211_channel *); 4890e584c77Skevlo int urtw_isbmode(uint16_t); 4900e584c77Skevlo uint16_t urtw_rate2rtl(int rate); 4910e584c77Skevlo uint16_t urtw_rtl2rate(int); 4920e584c77Skevlo usbd_status urtw_set_rate(struct urtw_softc *); 4930e584c77Skevlo usbd_status urtw_update_msr(struct urtw_softc *); 4940ec995ceSmartynas usbd_status urtw_read8_c(struct urtw_softc *, int, uint8_t *, uint8_t); 4950ec995ceSmartynas usbd_status urtw_read16_c(struct urtw_softc *, int, uint16_t *, uint8_t); 4960ec995ceSmartynas usbd_status urtw_read32_c(struct urtw_softc *, int, uint32_t *, uint8_t); 4970ec995ceSmartynas usbd_status urtw_write8_c(struct urtw_softc *, int, uint8_t, uint8_t); 4980ec995ceSmartynas usbd_status urtw_write16_c(struct urtw_softc *, int, uint16_t, uint8_t); 4990ec995ceSmartynas usbd_status urtw_write32_c(struct urtw_softc *, int, uint32_t, uint8_t); 5000e584c77Skevlo usbd_status urtw_eprom_cs(struct urtw_softc *, int); 5010e584c77Skevlo usbd_status urtw_eprom_ck(struct urtw_softc *); 5020e584c77Skevlo usbd_status urtw_eprom_sendbits(struct urtw_softc *, int16_t *, 5030e584c77Skevlo int); 5040e584c77Skevlo usbd_status urtw_eprom_read32(struct urtw_softc *, uint32_t, 5050e584c77Skevlo uint32_t *); 5060e584c77Skevlo usbd_status urtw_eprom_readbit(struct urtw_softc *, int16_t *); 5070e584c77Skevlo usbd_status urtw_eprom_writebit(struct urtw_softc *, int16_t); 5080e584c77Skevlo usbd_status urtw_get_macaddr(struct urtw_softc *); 5090e584c77Skevlo usbd_status urtw_get_txpwr(struct urtw_softc *); 5100e584c77Skevlo usbd_status urtw_get_rfchip(struct urtw_softc *); 5110e584c77Skevlo usbd_status urtw_led_init(struct urtw_softc *); 5120e584c77Skevlo usbd_status urtw_8185_rf_pins_enable(struct urtw_softc *); 5130e584c77Skevlo usbd_status urtw_8185_tx_antenna(struct urtw_softc *, uint8_t); 5140e584c77Skevlo usbd_status urtw_8187_write_phy(struct urtw_softc *, uint8_t, uint32_t); 5150e584c77Skevlo usbd_status urtw_8187_write_phy_ofdm_c(struct urtw_softc *, uint8_t, 5160e584c77Skevlo uint32_t); 5170e584c77Skevlo usbd_status urtw_8187_write_phy_cck_c(struct urtw_softc *, uint8_t, 5180e584c77Skevlo uint32_t); 5190e584c77Skevlo usbd_status urtw_8225_setgain(struct urtw_softc *, int16_t); 5200e584c77Skevlo usbd_status urtw_8225_usb_init(struct urtw_softc *); 5210e584c77Skevlo usbd_status urtw_8225_write_c(struct urtw_softc *, uint8_t, uint16_t); 5220e584c77Skevlo usbd_status urtw_8225_write_s16(struct urtw_softc *, uint8_t, int, 523425512e4Smartynas uint16_t); 5240e584c77Skevlo usbd_status urtw_8225_read(struct urtw_softc *, uint8_t, uint32_t *); 525abcf0a78Smartynas usbd_status urtw_8225_rf_init(struct urtw_rf *); 526abcf0a78Smartynas usbd_status urtw_8225_rf_set_chan(struct urtw_rf *, int); 527abcf0a78Smartynas usbd_status urtw_8225_rf_set_sens(struct urtw_rf *); 5280e584c77Skevlo usbd_status urtw_8225_set_txpwrlvl(struct urtw_softc *, int); 529abcf0a78Smartynas usbd_status urtw_8225v2_rf_init(struct urtw_rf *); 530abcf0a78Smartynas usbd_status urtw_8225v2_rf_set_chan(struct urtw_rf *, int); 5310e584c77Skevlo usbd_status urtw_8225v2_set_txpwrlvl(struct urtw_softc *, int); 5320e584c77Skevlo usbd_status urtw_8225v2_setgain(struct urtw_softc *, int16_t); 5330e584c77Skevlo usbd_status urtw_8225_isv2(struct urtw_softc *, int *); 5340e584c77Skevlo usbd_status urtw_read8e(struct urtw_softc *, int, uint8_t *); 5350e584c77Skevlo usbd_status urtw_write8e(struct urtw_softc *, int, uint8_t); 5360e584c77Skevlo usbd_status urtw_8180_set_anaparam(struct urtw_softc *, uint32_t); 5370e584c77Skevlo usbd_status urtw_8185_set_anaparam2(struct urtw_softc *, uint32_t); 5380e584c77Skevlo usbd_status urtw_open_pipes(struct urtw_softc *); 5390e584c77Skevlo usbd_status urtw_close_pipes(struct urtw_softc *); 5400e584c77Skevlo usbd_status urtw_intr_enable(struct urtw_softc *); 5410e584c77Skevlo usbd_status urtw_intr_disable(struct urtw_softc *); 5420e584c77Skevlo usbd_status urtw_reset(struct urtw_softc *); 5430e584c77Skevlo usbd_status urtw_led_on(struct urtw_softc *, int); 5440e584c77Skevlo usbd_status urtw_led_ctl(struct urtw_softc *, int); 5450e584c77Skevlo usbd_status urtw_led_blink(struct urtw_softc *); 5460e584c77Skevlo usbd_status urtw_led_mode0(struct urtw_softc *, int); 5470e584c77Skevlo usbd_status urtw_led_mode1(struct urtw_softc *, int); 5480e584c77Skevlo usbd_status urtw_led_mode2(struct urtw_softc *, int); 5490e584c77Skevlo usbd_status urtw_led_mode3(struct urtw_softc *, int); 5500e584c77Skevlo usbd_status urtw_rx_setconf(struct urtw_softc *); 5510e584c77Skevlo usbd_status urtw_rx_enable(struct urtw_softc *); 552c0e29f5aSmartynas usbd_status urtw_tx_enable(struct urtw_softc *); 5533d4b849eSmartynas usbd_status urtw_8187b_update_wmm(struct urtw_softc *); 5543d4b849eSmartynas usbd_status urtw_8187b_reset(struct urtw_softc *); 5553d4b849eSmartynas int urtw_8187b_init(struct ifnet *); 5563d4b849eSmartynas usbd_status urtw_8225v2_b_config_mac(struct urtw_softc *); 5573d4b849eSmartynas usbd_status urtw_8225v2_b_init_rfe(struct urtw_softc *); 5583d4b849eSmartynas usbd_status urtw_8225v2_b_update_chan(struct urtw_softc *); 5593d4b849eSmartynas usbd_status urtw_8225v2_b_rf_init(struct urtw_rf *); 5603d4b849eSmartynas usbd_status urtw_8225v2_b_rf_set_chan(struct urtw_rf *, int); 5613d4b849eSmartynas usbd_status urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *, int); 56249b282e9Smiod int urtw_set_bssid(struct urtw_softc *, const uint8_t *); 56349b282e9Smiod int urtw_set_macaddr(struct urtw_softc *, const uint8_t *); 5640e584c77Skevlo 5650e584c77Skevlo int urtw_match(struct device *, void *, void *); 5660e584c77Skevlo void urtw_attach(struct device *, struct device *, void *); 5670e584c77Skevlo int urtw_detach(struct device *, int); 5680e584c77Skevlo 5690e584c77Skevlo struct cfdriver urtw_cd = { 5700e584c77Skevlo NULL, "urtw", DV_IFNET 5710e584c77Skevlo }; 5720e584c77Skevlo 5730e584c77Skevlo const struct cfattach urtw_ca = { 57453c6612dSmpi sizeof(struct urtw_softc), urtw_match, urtw_attach, urtw_detach 5750e584c77Skevlo }; 5760e584c77Skevlo 5770e584c77Skevlo int 5780e584c77Skevlo urtw_match(struct device *parent, void *match, void *aux) 5790e584c77Skevlo { 5800e584c77Skevlo struct usb_attach_arg *uaa = aux; 5810e584c77Skevlo 5827ebc5b51Smpi if (uaa->iface == NULL || uaa->configno != 1) 583c0e29f5aSmartynas return (UMATCH_NONE); 5840e584c77Skevlo 585c0e29f5aSmartynas return ((urtw_lookup(uaa->vendor, uaa->product) != NULL) ? 5867ebc5b51Smpi UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE); 5870e584c77Skevlo } 5880e584c77Skevlo 5890e584c77Skevlo void 5900e584c77Skevlo urtw_attach(struct device *parent, struct device *self, void *aux) 5910e584c77Skevlo { 5920e584c77Skevlo struct urtw_softc *sc = (struct urtw_softc *)self; 5930e584c77Skevlo struct usb_attach_arg *uaa = aux; 5940e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 5950e584c77Skevlo struct ifnet *ifp = &ic->ic_if; 5960e584c77Skevlo usbd_status error; 5973d4b849eSmartynas uint8_t data8; 5980e584c77Skevlo uint32_t data; 5990e584c77Skevlo int i; 6000e584c77Skevlo 6010e584c77Skevlo sc->sc_udev = uaa->device; 6027ebc5b51Smpi sc->sc_iface = uaa->iface; 60397f52115Smartynas sc->sc_hwrev = urtw_lookup(uaa->vendor, uaa->product)->rev; 60497f52115Smartynas 605c800ec2bSmartynas printf("%s: ", sc->sc_dev.dv_xname); 606c800ec2bSmartynas 60797f52115Smartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 60897f52115Smartynas urtw_read32_m(sc, URTW_TX_CONF, &data); 60997f52115Smartynas data &= URTW_TX_HWREV_MASK; 61097f52115Smartynas switch (data) { 61197f52115Smartynas case URTW_TX_HWREV_8187_D: 61297f52115Smartynas sc->sc_hwrev |= URTW_HWREV_8187_D; 613c800ec2bSmartynas printf("RTL8187 rev D"); 61497f52115Smartynas break; 61597f52115Smartynas case URTW_TX_HWREV_8187B_D: 61697f52115Smartynas /* 61797f52115Smartynas * Detect Realtek RTL8187B devices that use 61897f52115Smartynas * USB IDs of RTL8187. 61997f52115Smartynas */ 6203d4b849eSmartynas sc->sc_hwrev = URTW_HWREV_8187B | URTW_HWREV_8187B_B; 621c800ec2bSmartynas printf("RTL8187B rev B (early)"); 62297f52115Smartynas break; 62397f52115Smartynas default: 62497f52115Smartynas sc->sc_hwrev |= URTW_HWREV_8187_B; 625c800ec2bSmartynas printf("RTL8187 rev 0x%02x", data >> 25); 62697f52115Smartynas break; 62797f52115Smartynas } 62897f52115Smartynas } else { 6293d4b849eSmartynas /* RTL8187B hwrev register. */ 6303d4b849eSmartynas urtw_read8_m(sc, URTW_8187B_HWREV, &data8); 6313d4b849eSmartynas switch (data8) { 6323d4b849eSmartynas case URTW_8187B_HWREV_8187B_B: 6333d4b849eSmartynas sc->sc_hwrev |= URTW_HWREV_8187B_B; 634c800ec2bSmartynas printf("RTL8187B rev B"); 6353d4b849eSmartynas break; 6363d4b849eSmartynas case URTW_8187B_HWREV_8187B_D: 6373d4b849eSmartynas sc->sc_hwrev |= URTW_HWREV_8187B_D; 638c800ec2bSmartynas printf("RTL8187B rev D"); 6393d4b849eSmartynas break; 6403d4b849eSmartynas case URTW_8187B_HWREV_8187B_E: 6413d4b849eSmartynas sc->sc_hwrev |= URTW_HWREV_8187B_E; 642c800ec2bSmartynas printf("RTL8187B rev E"); 6433d4b849eSmartynas break; 6443d4b849eSmartynas default: 6453d4b849eSmartynas sc->sc_hwrev |= URTW_HWREV_8187B_B; 646c800ec2bSmartynas printf("RTL8187B rev 0x%02x", data8); 6473d4b849eSmartynas break; 6483d4b849eSmartynas } 64997f52115Smartynas } 65097f52115Smartynas 6510e584c77Skevlo urtw_read32_m(sc, URTW_RX, &data); 6520e584c77Skevlo sc->sc_epromtype = (data & URTW_RX_9356SEL) ? URTW_EEPROM_93C56 : 6530e584c77Skevlo URTW_EEPROM_93C46; 6540e584c77Skevlo 6550e584c77Skevlo error = urtw_get_rfchip(sc); 6560e584c77Skevlo if (error != 0) 6570e584c77Skevlo goto fail; 6580e584c77Skevlo error = urtw_get_macaddr(sc); 6590e584c77Skevlo if (error != 0) 6600e584c77Skevlo goto fail; 6610e584c77Skevlo error = urtw_get_txpwr(sc); 6620e584c77Skevlo if (error != 0) 6630e584c77Skevlo goto fail; 6644b1a56afSjsg error = urtw_led_init(sc); /* XXX incomplete */ 6650e584c77Skevlo if (error != 0) 6660e584c77Skevlo goto fail; 6670e584c77Skevlo 6680e584c77Skevlo sc->sc_rts_retry = URTW_DEFAULT_RTS_RETRY; 6690e584c77Skevlo sc->sc_tx_retry = URTW_DEFAULT_TX_RETRY; 6700e584c77Skevlo sc->sc_currate = 3; 6710e584c77Skevlo /* XXX for what? */ 6720e584c77Skevlo sc->sc_preamble_mode = 2; 6730e584c77Skevlo 674c33449aaSjakemsr usb_init_task(&sc->sc_task, urtw_task, sc, USB_TASK_TYPE_GENERIC); 675c33449aaSjakemsr usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc, 676c33449aaSjakemsr USB_TASK_TYPE_GENERIC); 6770e584c77Skevlo timeout_set(&sc->scan_to, urtw_next_scan, sc); 6780e584c77Skevlo timeout_set(&sc->sc_led_ch, urtw_ledtask, sc); 6790e584c77Skevlo 6800e584c77Skevlo ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 6810e584c77Skevlo ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 6820e584c77Skevlo ic->ic_state = IEEE80211_S_INIT; 6830e584c77Skevlo 6840e584c77Skevlo /* set device capabilities */ 6850e584c77Skevlo ic->ic_caps = 6860e584c77Skevlo IEEE80211_C_MONITOR | /* monitor mode supported */ 6870e584c77Skevlo IEEE80211_C_TXPMGT | /* tx power management */ 6880e584c77Skevlo IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 6890e584c77Skevlo IEEE80211_C_SHSLOT | /* short slot time supported */ 6900e584c77Skevlo IEEE80211_C_WEP | /* s/w WEP */ 6910e584c77Skevlo IEEE80211_C_RSN; /* WPA/RSN */ 6920e584c77Skevlo 6930e584c77Skevlo /* set supported .11b and .11g rates */ 6940e584c77Skevlo ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; 6950e584c77Skevlo ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; 6960e584c77Skevlo 6970e584c77Skevlo /* set supported .11b and .11g channels (1 through 14) */ 6980e584c77Skevlo for (i = 1; i <= 14; i++) { 6990e584c77Skevlo ic->ic_channels[i].ic_freq = 7000e584c77Skevlo ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 7010e584c77Skevlo ic->ic_channels[i].ic_flags = 7020e584c77Skevlo IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 7030e584c77Skevlo IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 7040e584c77Skevlo } 7050e584c77Skevlo 7060e584c77Skevlo ifp->if_softc = sc; 7070e584c77Skevlo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 7083d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 709f110151dSjsg sc->sc_init = urtw_init; 7103d4b849eSmartynas } else { 711f110151dSjsg sc->sc_init = urtw_8187b_init; 7123d4b849eSmartynas } 7130e584c77Skevlo ifp->if_ioctl = urtw_ioctl; 7140e584c77Skevlo ifp->if_start = urtw_start; 7150e584c77Skevlo ifp->if_watchdog = urtw_watchdog; 7160e584c77Skevlo memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 7170e584c77Skevlo 7180e584c77Skevlo if_attach(ifp); 7190e584c77Skevlo ieee80211_ifattach(ifp); 7200e584c77Skevlo 7210e584c77Skevlo /* override state transition machine */ 7220e584c77Skevlo sc->sc_newstate = ic->ic_newstate; 7230e584c77Skevlo ic->ic_newstate = urtw_newstate; 7240e584c77Skevlo ieee80211_media_init(ifp, urtw_media_change, ieee80211_media_status); 7250e584c77Skevlo 7260e584c77Skevlo #if NBPFILTER > 0 7270e584c77Skevlo bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO, 7280e584c77Skevlo sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN); 7290e584c77Skevlo 7300e584c77Skevlo sc->sc_rxtap_len = sizeof sc->sc_rxtapu; 7310e584c77Skevlo sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 7320e584c77Skevlo sc->sc_rxtap.wr_ihdr.it_present = htole32(URTW_RX_RADIOTAP_PRESENT); 7330e584c77Skevlo 7340e584c77Skevlo sc->sc_txtap_len = sizeof sc->sc_txtapu; 7350e584c77Skevlo sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 7360e584c77Skevlo sc->sc_txtap.wt_ihdr.it_present = htole32(URTW_TX_RADIOTAP_PRESENT); 7370e584c77Skevlo #endif 7380e584c77Skevlo 73997f52115Smartynas printf(", address %s\n", ether_sprintf(ic->ic_myaddr)); 7400e584c77Skevlo 7410e584c77Skevlo return; 7420e584c77Skevlo fail: 74397f52115Smartynas printf(": %s failed!\n", __func__); 7440e584c77Skevlo } 7450e584c77Skevlo 7460e584c77Skevlo int 7470e584c77Skevlo urtw_detach(struct device *self, int flags) 7480e584c77Skevlo { 7490e584c77Skevlo struct urtw_softc *sc = (struct urtw_softc *)self; 7500e584c77Skevlo struct ifnet *ifp = &sc->sc_ic.ic_if; 7510e584c77Skevlo int s; 7520e584c77Skevlo 7530e584c77Skevlo s = splusb(); 7540e584c77Skevlo 755c7438bddSjakemsr if (timeout_initialized(&sc->scan_to)) 7560e584c77Skevlo timeout_del(&sc->scan_to); 757c7438bddSjakemsr if (timeout_initialized(&sc->sc_led_ch)) 7580e584c77Skevlo timeout_del(&sc->sc_led_ch); 7590e584c77Skevlo 76012136ef5Sjakemsr usb_rem_wait_task(sc->sc_udev, &sc->sc_task); 76112136ef5Sjakemsr usb_rem_wait_task(sc->sc_udev, &sc->sc_ledtask); 76212136ef5Sjakemsr 76312136ef5Sjakemsr usbd_ref_wait(sc->sc_udev); 76412136ef5Sjakemsr 76512136ef5Sjakemsr if (ifp->if_softc != NULL) { 76612136ef5Sjakemsr ieee80211_ifdetach(ifp); /* free all nodes */ 76712136ef5Sjakemsr if_detach(ifp); 76812136ef5Sjakemsr } 76912136ef5Sjakemsr 7700e584c77Skevlo /* abort and free xfers */ 7710e584c77Skevlo urtw_free_tx_data_list(sc); 7720e584c77Skevlo urtw_free_rx_data_list(sc); 7730e584c77Skevlo urtw_close_pipes(sc); 7740e584c77Skevlo 7750e584c77Skevlo splx(s); 7760e584c77Skevlo 7770e584c77Skevlo return (0); 7780e584c77Skevlo } 7790e584c77Skevlo 7800e584c77Skevlo usbd_status 7810e584c77Skevlo urtw_close_pipes(struct urtw_softc *sc) 7820e584c77Skevlo { 7830e584c77Skevlo usbd_status error = 0; 7840e584c77Skevlo 7850e584c77Skevlo if (sc->sc_rxpipe != NULL) { 7860e584c77Skevlo error = usbd_close_pipe(sc->sc_rxpipe); 7870e584c77Skevlo if (error != 0) 7880e584c77Skevlo goto fail; 7890e584c77Skevlo sc->sc_rxpipe = NULL; 7900e584c77Skevlo } 7910e584c77Skevlo if (sc->sc_txpipe_low != NULL) { 7920e584c77Skevlo error = usbd_close_pipe(sc->sc_txpipe_low); 7930e584c77Skevlo if (error != 0) 7940e584c77Skevlo goto fail; 7950e584c77Skevlo sc->sc_txpipe_low = NULL; 7960e584c77Skevlo } 7970e584c77Skevlo if (sc->sc_txpipe_normal != NULL) { 7980e584c77Skevlo error = usbd_close_pipe(sc->sc_txpipe_normal); 7990e584c77Skevlo if (error != 0) 8000e584c77Skevlo goto fail; 8010e584c77Skevlo sc->sc_txpipe_normal = NULL; 8020e584c77Skevlo } 8030e584c77Skevlo fail: 8040e584c77Skevlo return (error); 8050e584c77Skevlo } 8060e584c77Skevlo 8070e584c77Skevlo usbd_status 8080e584c77Skevlo urtw_open_pipes(struct urtw_softc *sc) 8090e584c77Skevlo { 8100e584c77Skevlo usbd_status error; 8110e584c77Skevlo 8120e584c77Skevlo /* 8130e584c77Skevlo * NB: there is no way to distinguish each pipes so we need to hardcode 8140e584c77Skevlo * pipe numbers 8150e584c77Skevlo */ 8160e584c77Skevlo 8170e584c77Skevlo /* tx pipe - low priority packets */ 8183d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) 8193d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x2, 8203d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_txpipe_low); 8213d4b849eSmartynas else 8223d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x6, 8233d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_txpipe_low); 8240e584c77Skevlo if (error != 0) { 8250e584c77Skevlo printf("%s: could not open Tx low pipe: %s\n", 8260e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(error)); 8270e584c77Skevlo goto fail; 8280e584c77Skevlo } 8290e584c77Skevlo /* tx pipe - normal priority packets */ 8303d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) 8313d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x3, 8323d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_txpipe_normal); 8333d4b849eSmartynas else 8343d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x7, 8353d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_txpipe_normal); 8360e584c77Skevlo if (error != 0) { 8370e584c77Skevlo printf("%s: could not open Tx normal pipe: %s\n", 8380e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(error)); 8390e584c77Skevlo goto fail; 8400e584c77Skevlo } 8410e584c77Skevlo /* rx pipe */ 8423d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) 8433d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x81, 8443d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_rxpipe); 8453d4b849eSmartynas else 8463d4b849eSmartynas error = usbd_open_pipe(sc->sc_iface, 0x83, 8473d4b849eSmartynas USBD_EXCLUSIVE_USE, &sc->sc_rxpipe); 8480e584c77Skevlo if (error != 0) { 8490e584c77Skevlo printf("%s: could not open Rx pipe: %s\n", 8500e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(error)); 8510e584c77Skevlo goto fail; 8520e584c77Skevlo } 8530e584c77Skevlo 8540e584c77Skevlo return (0); 8550e584c77Skevlo fail: 8560e584c77Skevlo (void)urtw_close_pipes(sc); 8570e584c77Skevlo return (error); 8580e584c77Skevlo } 8590e584c77Skevlo 8600e584c77Skevlo int 86161a07a57Smartynas urtw_alloc_rx_data_list(struct urtw_softc *sc) 8620e584c77Skevlo { 8630e584c77Skevlo int i, error; 8640e584c77Skevlo 86561a07a57Smartynas for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) { 866366cafe1Smartynas struct urtw_rx_data *data = &sc->sc_rx_data[i]; 8670e584c77Skevlo 86861a07a57Smartynas data->sc = sc; 86961a07a57Smartynas 87061a07a57Smartynas data->xfer = usbd_alloc_xfer(sc->sc_udev); 87161a07a57Smartynas if (data->xfer == NULL) { 87261a07a57Smartynas printf("%s: could not allocate rx xfer\n", 8730e584c77Skevlo sc->sc_dev.dv_xname); 8740e584c77Skevlo error = ENOMEM; 8750e584c77Skevlo goto fail; 8760e584c77Skevlo } 87761a07a57Smartynas 878366cafe1Smartynas if (usbd_alloc_buffer(data->xfer, URTW_RX_MAXSIZE) == NULL) { 879366cafe1Smartynas printf("%s: could not allocate rx buffer\n", 880366cafe1Smartynas sc->sc_dev.dv_xname); 881366cafe1Smartynas error = ENOMEM; 882366cafe1Smartynas goto fail; 883366cafe1Smartynas } 884366cafe1Smartynas 88561a07a57Smartynas MGETHDR(data->m, M_DONTWAIT, MT_DATA); 88661a07a57Smartynas if (data->m == NULL) { 8870e584c77Skevlo printf("%s: could not allocate rx mbuf\n", 8880e584c77Skevlo sc->sc_dev.dv_xname); 8890e584c77Skevlo error = ENOMEM; 8900e584c77Skevlo goto fail; 8910e584c77Skevlo } 89261a07a57Smartynas MCLGET(data->m, M_DONTWAIT); 89361a07a57Smartynas if (!(data->m->m_flags & M_EXT)) { 89461a07a57Smartynas printf("%s: could not allocate rx mbuf cluster\n", 8950e584c77Skevlo sc->sc_dev.dv_xname); 8960e584c77Skevlo error = ENOMEM; 8970e584c77Skevlo goto fail; 8980e584c77Skevlo } 89961a07a57Smartynas data->buf = mtod(data->m, uint8_t *); 9000e584c77Skevlo } 9010e584c77Skevlo 9020e584c77Skevlo return (0); 9030e584c77Skevlo 90461a07a57Smartynas fail: 90561a07a57Smartynas urtw_free_rx_data_list(sc); 9060e584c77Skevlo return (error); 9070e584c77Skevlo } 9080e584c77Skevlo 9090e584c77Skevlo void 9100e584c77Skevlo urtw_free_rx_data_list(struct urtw_softc *sc) 9110e584c77Skevlo { 91261a07a57Smartynas int i; 9130e584c77Skevlo 91461a07a57Smartynas /* Make sure no transfers are pending. */ 91561a07a57Smartynas if (sc->sc_rxpipe != NULL) 91661a07a57Smartynas usbd_abort_pipe(sc->sc_rxpipe); 91761a07a57Smartynas 91861a07a57Smartynas for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) { 919366cafe1Smartynas struct urtw_rx_data *data = &sc->sc_rx_data[i]; 92061a07a57Smartynas 92161a07a57Smartynas if (data->xfer != NULL) { 92261a07a57Smartynas usbd_free_xfer(data->xfer); 92361a07a57Smartynas data->xfer = NULL; 92461a07a57Smartynas } 92561a07a57Smartynas if (data->m != NULL) { 92661a07a57Smartynas m_freem(data->m); 92761a07a57Smartynas data->m = NULL; 92861a07a57Smartynas } 92961a07a57Smartynas } 9300e584c77Skevlo } 9310e584c77Skevlo 9320e584c77Skevlo int 9330e584c77Skevlo urtw_alloc_tx_data_list(struct urtw_softc *sc) 9340e584c77Skevlo { 93561a07a57Smartynas int i, error; 9360e584c77Skevlo 93761a07a57Smartynas for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++) { 938366cafe1Smartynas struct urtw_tx_data *data = &sc->sc_tx_data[i]; 93961a07a57Smartynas 94061a07a57Smartynas data->sc = sc; 94161a07a57Smartynas data->ni = NULL; 94261a07a57Smartynas 94361a07a57Smartynas data->xfer = usbd_alloc_xfer(sc->sc_udev); 94461a07a57Smartynas if (data->xfer == NULL) { 94561a07a57Smartynas printf("%s: could not allocate tx xfer\n", 94661a07a57Smartynas sc->sc_dev.dv_xname); 94761a07a57Smartynas error = ENOMEM; 94861a07a57Smartynas goto fail; 94961a07a57Smartynas } 95061a07a57Smartynas 95161a07a57Smartynas data->buf = usbd_alloc_buffer(data->xfer, URTW_TX_MAXSIZE); 95261a07a57Smartynas if (data->buf == NULL) { 95361a07a57Smartynas printf("%s: could not allocate tx buffer\n", 95461a07a57Smartynas sc->sc_dev.dv_xname); 95561a07a57Smartynas error = ENOMEM; 95661a07a57Smartynas goto fail; 95761a07a57Smartynas } 95861a07a57Smartynas 95961a07a57Smartynas if (((unsigned long)data->buf) % 4) 96061a07a57Smartynas printf("%s: warn: unaligned buffer %p\n", 96161a07a57Smartynas sc->sc_dev.dv_xname, data->buf); 96261a07a57Smartynas } 96361a07a57Smartynas 96461a07a57Smartynas return (0); 96561a07a57Smartynas 96661a07a57Smartynas fail: 96761a07a57Smartynas urtw_free_tx_data_list(sc); 96861a07a57Smartynas return (error); 9690e584c77Skevlo } 9700e584c77Skevlo 9710e584c77Skevlo void 9720e584c77Skevlo urtw_free_tx_data_list(struct urtw_softc *sc) 9730e584c77Skevlo { 97461a07a57Smartynas struct ieee80211com *ic = &sc->sc_ic; 97561a07a57Smartynas int i; 9760e584c77Skevlo 97761a07a57Smartynas /* Make sure no transfers are pending. */ 97861a07a57Smartynas if (sc->sc_txpipe_low != NULL) 97961a07a57Smartynas usbd_abort_pipe(sc->sc_txpipe_low); 98061a07a57Smartynas if (sc->sc_txpipe_normal != NULL) 98161a07a57Smartynas usbd_abort_pipe(sc->sc_txpipe_normal); 98261a07a57Smartynas 98361a07a57Smartynas for (i = 0; i < URTW_TX_DATA_LIST_COUNT; i++) { 984366cafe1Smartynas struct urtw_tx_data *data = &sc->sc_tx_data[i]; 98561a07a57Smartynas 98661a07a57Smartynas if (data->xfer != NULL) { 98761a07a57Smartynas usbd_free_xfer(data->xfer); 98861a07a57Smartynas data->xfer = NULL; 98961a07a57Smartynas } 99061a07a57Smartynas if (data->ni != NULL) { 99161a07a57Smartynas ieee80211_release_node(ic, data->ni); 99261a07a57Smartynas data->ni = NULL; 99361a07a57Smartynas } 99461a07a57Smartynas } 9950e584c77Skevlo } 9960e584c77Skevlo 9970e584c77Skevlo int 9980e584c77Skevlo urtw_media_change(struct ifnet *ifp) 9990e584c77Skevlo { 1000f110151dSjsg struct urtw_softc *sc = ifp->if_softc; 10010e584c77Skevlo int error; 10020e584c77Skevlo 10030e584c77Skevlo error = ieee80211_media_change(ifp); 10040e584c77Skevlo if (error != ENETRESET) 10050e584c77Skevlo return (error); 10060e584c77Skevlo 100775cd1aa0Skevlo if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) 100875cd1aa0Skevlo error = sc->sc_init(ifp); 10090e584c77Skevlo 101075cd1aa0Skevlo return (error); 10110e584c77Skevlo } 10120e584c77Skevlo 10130e584c77Skevlo int 10140e584c77Skevlo urtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 10150e584c77Skevlo { 10160e584c77Skevlo struct urtw_softc *sc = ic->ic_if.if_softc; 10170e584c77Skevlo 10180e584c77Skevlo usb_rem_task(sc->sc_udev, &sc->sc_task); 10190e584c77Skevlo timeout_del(&sc->scan_to); 10200e584c77Skevlo 10210e584c77Skevlo /* do it in a process context */ 10220e584c77Skevlo sc->sc_state = nstate; 10230e584c77Skevlo sc->sc_arg = arg; 10240e584c77Skevlo usb_add_task(sc->sc_udev, &sc->sc_task); 10250e584c77Skevlo 10260e584c77Skevlo return (0); 10270e584c77Skevlo } 10280e584c77Skevlo 10290e584c77Skevlo usbd_status 10300e584c77Skevlo urtw_led_init(struct urtw_softc *sc) 10310e584c77Skevlo { 10320e584c77Skevlo uint32_t rev; 10330e584c77Skevlo usbd_status error; 10340e584c77Skevlo 10350e584c77Skevlo urtw_read8_m(sc, URTW_PSR, &sc->sc_psr); 10360e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_SWREV, &rev); 10370e584c77Skevlo if (error != 0) 10380e584c77Skevlo goto fail; 10390e584c77Skevlo 10400e584c77Skevlo switch (rev & URTW_EPROM_CID_MASK) { 10410e584c77Skevlo case URTW_EPROM_CID_ALPHA0: 10420e584c77Skevlo sc->sc_strategy = URTW_SW_LED_MODE1; 10430e584c77Skevlo break; 10440e584c77Skevlo case URTW_EPROM_CID_SERCOMM_PS: 10450e584c77Skevlo sc->sc_strategy = URTW_SW_LED_MODE3; 10460e584c77Skevlo break; 10470e584c77Skevlo case URTW_EPROM_CID_HW_LED: 10480e584c77Skevlo sc->sc_strategy = URTW_HW_LED; 10490e584c77Skevlo break; 10500e584c77Skevlo case URTW_EPROM_CID_RSVD0: 10510e584c77Skevlo case URTW_EPROM_CID_RSVD1: 10520e584c77Skevlo default: 10530e584c77Skevlo sc->sc_strategy = URTW_SW_LED_MODE0; 10540e584c77Skevlo break; 10550e584c77Skevlo } 10560e584c77Skevlo 10570e584c77Skevlo sc->sc_gpio_ledpin = URTW_LED_PIN_GPIO0; 10580e584c77Skevlo 10590e584c77Skevlo fail: 10600e584c77Skevlo return (error); 10610e584c77Skevlo } 10620e584c77Skevlo 10630e584c77Skevlo usbd_status 10640e584c77Skevlo urtw_8225_write_s16(struct urtw_softc *sc, uint8_t addr, int index, 1065425512e4Smartynas uint16_t data) 10660e584c77Skevlo { 1067425512e4Smartynas usb_device_request_t req; 10680e584c77Skevlo 1069425512e4Smartynas req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1070425512e4Smartynas req.bRequest = URTW_8187_SETREGS_REQ; 1071425512e4Smartynas USETW(req.wValue, addr); 1072425512e4Smartynas USETW(req.wIndex, index); 1073425512e4Smartynas USETW(req.wLength, sizeof(uint16_t)); 10740e584c77Skevlo 10759752fecbSstsp data = htole16(data); 1076425512e4Smartynas return (usbd_do_request(sc->sc_udev, &req, &data)); 10770e584c77Skevlo } 10780e584c77Skevlo 10790e584c77Skevlo usbd_status 10800e584c77Skevlo urtw_8225_read(struct urtw_softc *sc, uint8_t addr, uint32_t *data) 10810e584c77Skevlo { 10820e584c77Skevlo int i; 10830e584c77Skevlo int16_t bit; 10840e584c77Skevlo uint8_t rlen = 12, wlen = 6; 10850e584c77Skevlo uint16_t o1, o2, o3, tmp; 10860e584c77Skevlo uint32_t d2w = ((uint32_t)(addr & 0x1f)) << 27; 10870e584c77Skevlo uint32_t mask = 0x80000000, value = 0; 10880e584c77Skevlo usbd_status error; 10890e584c77Skevlo 10900e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &o1); 10910e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &o2); 10920e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_SELECT, &o3); 10930e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2 | 0xf); 10940e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3 | 0xf); 10950e584c77Skevlo o1 &= ~0xf; 10960e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN); 10970e584c77Skevlo DELAY(5); 10980e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1); 10990e584c77Skevlo DELAY(5); 11000e584c77Skevlo 11010e584c77Skevlo for (i = 0; i < (wlen / 2); i++, mask = mask >> 1) { 11020e584c77Skevlo bit = ((d2w & mask) != 0) ? 1 : 0; 11030e584c77Skevlo 11040e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1); 11050e584c77Skevlo DELAY(2); 11060e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 11070e584c77Skevlo URTW_BB_HOST_BANG_CLK); 11080e584c77Skevlo DELAY(2); 11090e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 11100e584c77Skevlo URTW_BB_HOST_BANG_CLK); 11110e584c77Skevlo DELAY(2); 11120e584c77Skevlo mask = mask >> 1; 11130e584c77Skevlo if (i == 2) 11140e584c77Skevlo break; 11150e584c77Skevlo bit = ((d2w & mask) != 0) ? 1 : 0; 11160e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 11170e584c77Skevlo URTW_BB_HOST_BANG_CLK); 11180e584c77Skevlo DELAY(2); 11190e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | 11200e584c77Skevlo URTW_BB_HOST_BANG_CLK); 11210e584c77Skevlo DELAY(2); 11220e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1); 11230e584c77Skevlo DELAY(1); 11240e584c77Skevlo } 11250e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW | 11260e584c77Skevlo URTW_BB_HOST_BANG_CLK); 11270e584c77Skevlo DELAY(2); 11280e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, bit | o1 | URTW_BB_HOST_BANG_RW); 11290e584c77Skevlo DELAY(2); 11300e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_RW); 11310e584c77Skevlo DELAY(2); 11320e584c77Skevlo 11330e584c77Skevlo mask = 0x800; 11340e584c77Skevlo for (i = 0; i < rlen; i++, mask = mask >> 1) { 11350e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 11360e584c77Skevlo o1 | URTW_BB_HOST_BANG_RW); 11370e584c77Skevlo DELAY(2); 11380e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 11390e584c77Skevlo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 11400e584c77Skevlo DELAY(2); 11410e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 11420e584c77Skevlo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 11430e584c77Skevlo DELAY(2); 11440e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 11450e584c77Skevlo o1 | URTW_BB_HOST_BANG_RW | URTW_BB_HOST_BANG_CLK); 11460e584c77Skevlo DELAY(2); 11470e584c77Skevlo 11480e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_INPUT, &tmp); 11490e584c77Skevlo value |= ((tmp & URTW_BB_HOST_BANG_CLK) ? mask : 0); 11500e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 11510e584c77Skevlo o1 | URTW_BB_HOST_BANG_RW); 11520e584c77Skevlo DELAY(2); 11530e584c77Skevlo } 11540e584c77Skevlo 11550e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, o1 | URTW_BB_HOST_BANG_EN | 11560e584c77Skevlo URTW_BB_HOST_BANG_RW); 11570e584c77Skevlo DELAY(2); 11580e584c77Skevlo 11590e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, o2); 11600e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, o3); 11610e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x3a0); 11620e584c77Skevlo 11630e584c77Skevlo if (data != NULL) 11640e584c77Skevlo *data = value; 11650e584c77Skevlo fail: 11660e584c77Skevlo return (error); 11670e584c77Skevlo } 11680e584c77Skevlo 11690e584c77Skevlo usbd_status 11700e584c77Skevlo urtw_8225_write_c(struct urtw_softc *sc, uint8_t addr, uint16_t data) 11710e584c77Skevlo { 11720e584c77Skevlo uint16_t d80, d82, d84; 11730e584c77Skevlo usbd_status error; 11740e584c77Skevlo 11750e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_OUTPUT, &d80); 11760e584c77Skevlo d80 &= 0xfff3; 11770e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_ENABLE, &d82); 11780e584c77Skevlo urtw_read16_m(sc, URTW_RF_PINS_SELECT, &d84); 11790e584c77Skevlo d84 &= 0xfff0; 11800e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, d82 | 0x0007); 11810e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84 | 0x0007); 11820e584c77Skevlo DELAY(10); 11830e584c77Skevlo 11840e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 11850e584c77Skevlo DELAY(2); 11860e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80); 11870e584c77Skevlo DELAY(10); 11880e584c77Skevlo 1189425512e4Smartynas error = urtw_8225_write_s16(sc, addr, 0x8225, data); 11900e584c77Skevlo if (error != 0) 11910e584c77Skevlo goto fail; 11920e584c77Skevlo 11930e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 11940e584c77Skevlo DELAY(10); 11950e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, d80 | URTW_BB_HOST_BANG_EN); 11960e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, d84); 11970e584c77Skevlo usbd_delay_ms(sc->sc_udev, 2); 11980e584c77Skevlo fail: 11990e584c77Skevlo return (error); 12000e584c77Skevlo } 12010e584c77Skevlo 12020e584c77Skevlo usbd_status 12030e584c77Skevlo urtw_8225_isv2(struct urtw_softc *sc, int *ret) 12040e584c77Skevlo { 12050e584c77Skevlo uint32_t data; 12060e584c77Skevlo usbd_status error; 12070e584c77Skevlo 12080e584c77Skevlo *ret = 1; 12090e584c77Skevlo 12100e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0080); 12110e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x0080); 12120e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x0080); 12136fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 500); 12140e584c77Skevlo 12150e584c77Skevlo urtw_8225_write(sc, 0x0, 0x1b7); 12160e584c77Skevlo 12170e584c77Skevlo error = urtw_8225_read(sc, 0x8, &data); 12180e584c77Skevlo if (error != 0) 12190e584c77Skevlo goto fail; 12200e584c77Skevlo if (data != 0x588) 12210e584c77Skevlo *ret = 0; 12220e584c77Skevlo else { 12230e584c77Skevlo error = urtw_8225_read(sc, 0x9, &data); 12240e584c77Skevlo if (error != 0) 12250e584c77Skevlo goto fail; 12260e584c77Skevlo if (data != 0x700) 12270e584c77Skevlo *ret = 0; 12280e584c77Skevlo } 12290e584c77Skevlo 12300e584c77Skevlo urtw_8225_write(sc, 0x0, 0xb7); 12310e584c77Skevlo fail: 12320e584c77Skevlo return (error); 12330e584c77Skevlo } 12340e584c77Skevlo 12350e584c77Skevlo usbd_status 12360e584c77Skevlo urtw_get_rfchip(struct urtw_softc *sc) 12370e584c77Skevlo { 1238abcf0a78Smartynas struct urtw_rf *rf = &sc->sc_rf; 12390e584c77Skevlo int ret; 12400e584c77Skevlo uint32_t data; 12410e584c77Skevlo usbd_status error; 12420e584c77Skevlo 1243abcf0a78Smartynas rf->rf_sc = sc; 1244abcf0a78Smartynas 12453d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 12460e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_RFCHIPID, &data); 12470e584c77Skevlo if (error != 0) 1248d32f9784Sstsp goto fail; 12490e584c77Skevlo switch (data & 0xff) { 12500e584c77Skevlo case URTW_EPROM_RFCHIPID_RTL8225U: 12510e584c77Skevlo error = urtw_8225_isv2(sc, &ret); 12520e584c77Skevlo if (error != 0) 12530e584c77Skevlo goto fail; 12540e584c77Skevlo if (ret == 0) { 1255abcf0a78Smartynas rf->init = urtw_8225_rf_init; 1256abcf0a78Smartynas rf->set_chan = urtw_8225_rf_set_chan; 12573d4b849eSmartynas rf->set_sens = urtw_8225_rf_set_sens; 1258c800ec2bSmartynas printf(", RFv1"); 12590e584c77Skevlo } else { 1260abcf0a78Smartynas rf->init = urtw_8225v2_rf_init; 1261abcf0a78Smartynas rf->set_chan = urtw_8225v2_rf_set_chan; 1262abcf0a78Smartynas rf->set_sens = NULL; 1263c800ec2bSmartynas printf(", RFv2"); 12640e584c77Skevlo } 12650e584c77Skevlo break; 12660e584c77Skevlo default: 12673d4b849eSmartynas goto fail; 12683d4b849eSmartynas } 12693d4b849eSmartynas } else { 12703d4b849eSmartynas rf->init = urtw_8225v2_b_rf_init; 12713d4b849eSmartynas rf->set_chan = urtw_8225v2_b_rf_set_chan; 12723d4b849eSmartynas rf->set_sens = NULL; 12730e584c77Skevlo } 12740e584c77Skevlo 12753d4b849eSmartynas rf->max_sens = URTW_8225_RF_MAX_SENS; 12763d4b849eSmartynas rf->sens = URTW_8225_RF_DEF_SENS; 12773d4b849eSmartynas 12783d4b849eSmartynas return (0); 12793d4b849eSmartynas 12800e584c77Skevlo fail: 1281d32f9784Sstsp printf("unsupported RF chip %d", data & 0xff); 1282d32f9784Sstsp return (error); 12830e584c77Skevlo } 12840e584c77Skevlo 12850e584c77Skevlo usbd_status 12860e584c77Skevlo urtw_get_txpwr(struct urtw_softc *sc) 12870e584c77Skevlo { 12880e584c77Skevlo int i, j; 12890e584c77Skevlo uint32_t data; 12900e584c77Skevlo usbd_status error; 12910e584c77Skevlo 12920e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW_BASE, &data); 12930e584c77Skevlo if (error != 0) 12940e584c77Skevlo goto fail; 12950e584c77Skevlo sc->sc_txpwr_cck_base = data & 0xf; 12960e584c77Skevlo sc->sc_txpwr_ofdm_base = (data >> 4) & 0xf; 12970e584c77Skevlo 12980e584c77Skevlo for (i = 1, j = 0; i < 6; i += 2, j++) { 12990e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW0 + j, &data); 13000e584c77Skevlo if (error != 0) 13010e584c77Skevlo goto fail; 13020e584c77Skevlo sc->sc_txpwr_cck[i] = data & 0xf; 13030e584c77Skevlo sc->sc_txpwr_cck[i + 1] = (data & 0xf00) >> 8; 13040e584c77Skevlo sc->sc_txpwr_ofdm[i] = (data & 0xf0) >> 4; 13050e584c77Skevlo sc->sc_txpwr_ofdm[i + 1] = (data & 0xf000) >> 12; 13060e584c77Skevlo } 13070e584c77Skevlo for (i = 1, j = 0; i < 4; i += 2, j++) { 13080e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_TXPW1 + j, &data); 13090e584c77Skevlo if (error != 0) 13100e584c77Skevlo goto fail; 13110e584c77Skevlo sc->sc_txpwr_cck[i + 6] = data & 0xf; 13120e584c77Skevlo sc->sc_txpwr_cck[i + 6 + 1] = (data & 0xf00) >> 8; 13130e584c77Skevlo sc->sc_txpwr_ofdm[i + 6] = (data & 0xf0) >> 4; 13140e584c77Skevlo sc->sc_txpwr_ofdm[i + 6 + 1] = (data & 0xf000) >> 12; 13150e584c77Skevlo } 13163d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 13170e584c77Skevlo for (i = 1, j = 0; i < 4; i += 2, j++) { 13183d4b849eSmartynas error = urtw_eprom_read32(sc, URTW_EPROM_TXPW2 + j, 13193d4b849eSmartynas &data); 13200e584c77Skevlo if (error != 0) 13210e584c77Skevlo goto fail; 13220e584c77Skevlo sc->sc_txpwr_cck[i + 6 + 4] = data & 0xf; 13230e584c77Skevlo sc->sc_txpwr_cck[i + 6 + 4 + 1] = (data & 0xf00) >> 8; 13240e584c77Skevlo sc->sc_txpwr_ofdm[i + 6 + 4] = (data & 0xf0) >> 4; 13253d4b849eSmartynas sc->sc_txpwr_ofdm[i + 6 + 4 + 1] = 13263d4b849eSmartynas (data & 0xf000) >> 12; 13273d4b849eSmartynas } 13283d4b849eSmartynas } else { 13293d4b849eSmartynas /* Channel 11. */ 13303d4b849eSmartynas error = urtw_eprom_read32(sc, 0x1b, &data); 13313d4b849eSmartynas if (error != 0) 13323d4b849eSmartynas goto fail; 13333d4b849eSmartynas sc->sc_txpwr_cck[11] = data & 0xf; 13343d4b849eSmartynas sc->sc_txpwr_ofdm[11] = (data & 0xf0) >> 4; 13353d4b849eSmartynas 13363d4b849eSmartynas /* Channel 12. */ 13373d4b849eSmartynas error = urtw_eprom_read32(sc, 0xa, &data); 13383d4b849eSmartynas if (error != 0) 13393d4b849eSmartynas goto fail; 13403d4b849eSmartynas sc->sc_txpwr_cck[12] = data & 0xf; 13413d4b849eSmartynas sc->sc_txpwr_ofdm[12] = (data & 0xf0) >> 4; 13423d4b849eSmartynas 13433d4b849eSmartynas /* Channel 13, 14. */ 13443d4b849eSmartynas error = urtw_eprom_read32(sc, 0x1c, &data); 13453d4b849eSmartynas if (error != 0) 13463d4b849eSmartynas goto fail; 13473d4b849eSmartynas sc->sc_txpwr_cck[13] = data & 0xf; 13483d4b849eSmartynas sc->sc_txpwr_ofdm[13] = (data & 0xf0) >> 4; 13493d4b849eSmartynas sc->sc_txpwr_cck[14] = (data & 0xf00) >> 8; 13503d4b849eSmartynas sc->sc_txpwr_ofdm[14] = (data & 0xf000) >> 12; 13510e584c77Skevlo } 13520e584c77Skevlo fail: 13530e584c77Skevlo return (error); 13540e584c77Skevlo } 13550e584c77Skevlo 13560e584c77Skevlo usbd_status 13570e584c77Skevlo urtw_get_macaddr(struct urtw_softc *sc) 13580e584c77Skevlo { 13590e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 13600e584c77Skevlo usbd_status error; 13610e584c77Skevlo uint32_t data; 13620e584c77Skevlo 13630e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR, &data); 13640e584c77Skevlo if (error != 0) 13650e584c77Skevlo goto fail; 13660e584c77Skevlo ic->ic_myaddr[0] = data & 0xff; 13670e584c77Skevlo ic->ic_myaddr[1] = (data & 0xff00) >> 8; 13680e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 1, &data); 13690e584c77Skevlo if (error != 0) 13700e584c77Skevlo goto fail; 13710e584c77Skevlo ic->ic_myaddr[2] = data & 0xff; 13720e584c77Skevlo ic->ic_myaddr[3] = (data & 0xff00) >> 8; 13730e584c77Skevlo error = urtw_eprom_read32(sc, URTW_EPROM_MACADDR + 2, &data); 13740e584c77Skevlo if (error != 0) 13750e584c77Skevlo goto fail; 13760e584c77Skevlo ic->ic_myaddr[4] = data & 0xff; 13770e584c77Skevlo ic->ic_myaddr[5] = (data & 0xff00) >> 8; 13780e584c77Skevlo fail: 13790e584c77Skevlo return (error); 13800e584c77Skevlo } 13810e584c77Skevlo 13820e584c77Skevlo usbd_status 13830e584c77Skevlo urtw_eprom_read32(struct urtw_softc *sc, uint32_t addr, uint32_t *data) 13840e584c77Skevlo { 13850e584c77Skevlo #define URTW_READCMD_LEN 3 13860e584c77Skevlo int addrlen, i; 13870e584c77Skevlo int16_t addrstr[8], data16, readcmd[] = { 1, 1, 0 }; 13880e584c77Skevlo usbd_status error; 13890e584c77Skevlo 13900e584c77Skevlo /* NB: make sure the buffer is initialized */ 13910e584c77Skevlo *data = 0; 13920e584c77Skevlo 13930e584c77Skevlo /* enable EPROM programming */ 13940e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_PROGRAM_MODE); 13950e584c77Skevlo DELAY(URTW_EPROM_DELAY); 13960e584c77Skevlo 13970e584c77Skevlo error = urtw_eprom_cs(sc, URTW_EPROM_ENABLE); 13980e584c77Skevlo if (error != 0) 13990e584c77Skevlo goto fail; 14000e584c77Skevlo error = urtw_eprom_ck(sc); 14010e584c77Skevlo if (error != 0) 14020e584c77Skevlo goto fail; 14030e584c77Skevlo error = urtw_eprom_sendbits(sc, readcmd, URTW_READCMD_LEN); 14040e584c77Skevlo if (error != 0) 14050e584c77Skevlo goto fail; 14060e584c77Skevlo if (sc->sc_epromtype == URTW_EEPROM_93C56) { 14070e584c77Skevlo addrlen = 8; 14080e584c77Skevlo addrstr[0] = addr & (1 << 7); 14090e584c77Skevlo addrstr[1] = addr & (1 << 6); 14100e584c77Skevlo addrstr[2] = addr & (1 << 5); 14110e584c77Skevlo addrstr[3] = addr & (1 << 4); 14120e584c77Skevlo addrstr[4] = addr & (1 << 3); 14130e584c77Skevlo addrstr[5] = addr & (1 << 2); 14140e584c77Skevlo addrstr[6] = addr & (1 << 1); 14150e584c77Skevlo addrstr[7] = addr & (1 << 0); 14160e584c77Skevlo } else { 14170e584c77Skevlo addrlen=6; 14180e584c77Skevlo addrstr[0] = addr & (1 << 5); 14190e584c77Skevlo addrstr[1] = addr & (1 << 4); 14200e584c77Skevlo addrstr[2] = addr & (1 << 3); 14210e584c77Skevlo addrstr[3] = addr & (1 << 2); 14220e584c77Skevlo addrstr[4] = addr & (1 << 1); 14230e584c77Skevlo addrstr[5] = addr & (1 << 0); 14240e584c77Skevlo } 14250e584c77Skevlo error = urtw_eprom_sendbits(sc, addrstr, addrlen); 14260e584c77Skevlo if (error != 0) 14270e584c77Skevlo goto fail; 14280e584c77Skevlo 14290e584c77Skevlo error = urtw_eprom_writebit(sc, 0); 14300e584c77Skevlo if (error != 0) 14310e584c77Skevlo goto fail; 14320e584c77Skevlo 14330e584c77Skevlo for (i = 0; i < 16; i++) { 14340e584c77Skevlo error = urtw_eprom_ck(sc); 14350e584c77Skevlo if (error != 0) 14360e584c77Skevlo goto fail; 14370e584c77Skevlo error = urtw_eprom_readbit(sc, &data16); 14380e584c77Skevlo if (error != 0) 14390e584c77Skevlo goto fail; 14400e584c77Skevlo 14410e584c77Skevlo (*data) |= (data16 << (15 - i)); 14420e584c77Skevlo } 14430e584c77Skevlo 14440e584c77Skevlo error = urtw_eprom_cs(sc, URTW_EPROM_DISABLE); 14450e584c77Skevlo if (error != 0) 14460e584c77Skevlo goto fail; 14470e584c77Skevlo error = urtw_eprom_ck(sc); 14480e584c77Skevlo if (error != 0) 14490e584c77Skevlo goto fail; 14500e584c77Skevlo 14510e584c77Skevlo /* now disable EPROM programming */ 14520e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, URTW_EPROM_CMD_NORMAL_MODE); 14530e584c77Skevlo fail: 14540e584c77Skevlo return (error); 14550e584c77Skevlo #undef URTW_READCMD_LEN 14560e584c77Skevlo } 14570e584c77Skevlo 14580e584c77Skevlo usbd_status 14590e584c77Skevlo urtw_eprom_readbit(struct urtw_softc *sc, int16_t *data) 14600e584c77Skevlo { 14610e584c77Skevlo uint8_t data8; 14620e584c77Skevlo usbd_status error; 14630e584c77Skevlo 14640e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data8); 14650e584c77Skevlo *data = (data8 & URTW_EPROM_READBIT) ? 1 : 0; 14660e584c77Skevlo DELAY(URTW_EPROM_DELAY); 14670e584c77Skevlo 14680e584c77Skevlo fail: 14690e584c77Skevlo return (error); 14700e584c77Skevlo } 14710e584c77Skevlo 14720e584c77Skevlo usbd_status 14730e584c77Skevlo urtw_eprom_sendbits(struct urtw_softc *sc, int16_t *buf, int buflen) 14740e584c77Skevlo { 14750e584c77Skevlo int i = 0; 14760e584c77Skevlo usbd_status error = 0; 14770e584c77Skevlo 14780e584c77Skevlo for (i = 0; i < buflen; i++) { 14790e584c77Skevlo error = urtw_eprom_writebit(sc, buf[i]); 14800e584c77Skevlo if (error != 0) 14810e584c77Skevlo goto fail; 14820e584c77Skevlo error = urtw_eprom_ck(sc); 14830e584c77Skevlo if (error != 0) 14840e584c77Skevlo goto fail; 14850e584c77Skevlo } 14860e584c77Skevlo fail: 14870e584c77Skevlo return (error); 14880e584c77Skevlo } 14890e584c77Skevlo 14900e584c77Skevlo usbd_status 14910e584c77Skevlo urtw_eprom_writebit(struct urtw_softc *sc, int16_t bit) 14920e584c77Skevlo { 14930e584c77Skevlo uint8_t data; 14940e584c77Skevlo usbd_status error; 14950e584c77Skevlo 14960e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data); 14970e584c77Skevlo if (bit != 0) 14980e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_WRITEBIT); 14990e584c77Skevlo else 15000e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_WRITEBIT); 15010e584c77Skevlo DELAY(URTW_EPROM_DELAY); 15020e584c77Skevlo fail: 15030e584c77Skevlo return (error); 15040e584c77Skevlo } 15050e584c77Skevlo 15060e584c77Skevlo usbd_status 15070e584c77Skevlo urtw_eprom_ck(struct urtw_softc *sc) 15080e584c77Skevlo { 15090e584c77Skevlo uint8_t data; 15100e584c77Skevlo usbd_status error; 15110e584c77Skevlo 15120e584c77Skevlo /* masking */ 15130e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data); 15140e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CK); 15150e584c77Skevlo DELAY(URTW_EPROM_DELAY); 15160e584c77Skevlo /* unmasking */ 15170e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data); 15180e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CK); 15190e584c77Skevlo DELAY(URTW_EPROM_DELAY); 15200e584c77Skevlo fail: 15210e584c77Skevlo return (error); 15220e584c77Skevlo } 15230e584c77Skevlo 15240e584c77Skevlo usbd_status 15250e584c77Skevlo urtw_eprom_cs(struct urtw_softc *sc, int able) 15260e584c77Skevlo { 15270e584c77Skevlo uint8_t data; 15280e584c77Skevlo usbd_status error; 15290e584c77Skevlo 15300e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data); 15310e584c77Skevlo if (able == URTW_EPROM_ENABLE) 15320e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data | URTW_EPROM_CS); 15330e584c77Skevlo else 15340e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data & ~URTW_EPROM_CS); 15350e584c77Skevlo DELAY(URTW_EPROM_DELAY); 15360e584c77Skevlo fail: 15370e584c77Skevlo return (error); 15380e584c77Skevlo } 15390e584c77Skevlo 15400e584c77Skevlo usbd_status 15410ec995ceSmartynas urtw_read8_c(struct urtw_softc *sc, int val, uint8_t *data, uint8_t idx) 15420e584c77Skevlo { 15430e584c77Skevlo usb_device_request_t req; 15440e584c77Skevlo usbd_status error; 15450e584c77Skevlo 15460e584c77Skevlo req.bmRequestType = UT_READ_VENDOR_DEVICE; 15470e584c77Skevlo req.bRequest = URTW_8187_GETREGS_REQ; 15480e584c77Skevlo USETW(req.wValue, val | 0xff00); 15490ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 15500e584c77Skevlo USETW(req.wLength, sizeof(uint8_t)); 15510e584c77Skevlo 15520e584c77Skevlo error = usbd_do_request(sc->sc_udev, &req, data); 15530e584c77Skevlo return (error); 15540e584c77Skevlo } 15550e584c77Skevlo 15560e584c77Skevlo usbd_status 15570e584c77Skevlo urtw_read8e(struct urtw_softc *sc, int val, uint8_t *data) 15580e584c77Skevlo { 15590e584c77Skevlo usb_device_request_t req; 15600e584c77Skevlo usbd_status error; 15610e584c77Skevlo 15620e584c77Skevlo req.bmRequestType = UT_READ_VENDOR_DEVICE; 15630e584c77Skevlo req.bRequest = URTW_8187_GETREGS_REQ; 15640e584c77Skevlo USETW(req.wValue, val | 0xfe00); 15650e584c77Skevlo USETW(req.wIndex, 0); 15660e584c77Skevlo USETW(req.wLength, sizeof(uint8_t)); 15670e584c77Skevlo 15680e584c77Skevlo error = usbd_do_request(sc->sc_udev, &req, data); 15690e584c77Skevlo return (error); 15700e584c77Skevlo } 15710e584c77Skevlo 15720e584c77Skevlo usbd_status 15730ec995ceSmartynas urtw_read16_c(struct urtw_softc *sc, int val, uint16_t *data, uint8_t idx) 15740e584c77Skevlo { 15750e584c77Skevlo usb_device_request_t req; 15760e584c77Skevlo usbd_status error; 15770e584c77Skevlo 15780e584c77Skevlo req.bmRequestType = UT_READ_VENDOR_DEVICE; 15790e584c77Skevlo req.bRequest = URTW_8187_GETREGS_REQ; 15800e584c77Skevlo USETW(req.wValue, val | 0xff00); 15810ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 15820e584c77Skevlo USETW(req.wLength, sizeof(uint16_t)); 15830e584c77Skevlo 15840e584c77Skevlo error = usbd_do_request(sc->sc_udev, &req, data); 15859752fecbSstsp *data = letoh16(*data); 15860e584c77Skevlo return (error); 15870e584c77Skevlo } 15880e584c77Skevlo 15890e584c77Skevlo usbd_status 15900ec995ceSmartynas urtw_read32_c(struct urtw_softc *sc, int val, uint32_t *data, uint8_t idx) 15910e584c77Skevlo { 15920e584c77Skevlo usb_device_request_t req; 15930e584c77Skevlo usbd_status error; 15940e584c77Skevlo 15950e584c77Skevlo req.bmRequestType = UT_READ_VENDOR_DEVICE; 15960e584c77Skevlo req.bRequest = URTW_8187_GETREGS_REQ; 15970e584c77Skevlo USETW(req.wValue, val | 0xff00); 15980ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 15990e584c77Skevlo USETW(req.wLength, sizeof(uint32_t)); 16000e584c77Skevlo 16010e584c77Skevlo error = usbd_do_request(sc->sc_udev, &req, data); 16029752fecbSstsp *data = letoh32(*data); 16030e584c77Skevlo return (error); 16040e584c77Skevlo } 16050e584c77Skevlo 16060e584c77Skevlo usbd_status 16070ec995ceSmartynas urtw_write8_c(struct urtw_softc *sc, int val, uint8_t data, uint8_t idx) 16080e584c77Skevlo { 16090e584c77Skevlo usb_device_request_t req; 16100e584c77Skevlo 16110e584c77Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 16120e584c77Skevlo req.bRequest = URTW_8187_SETREGS_REQ; 16130e584c77Skevlo USETW(req.wValue, val | 0xff00); 16140ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 16150e584c77Skevlo USETW(req.wLength, sizeof(uint8_t)); 16160e584c77Skevlo 16170e584c77Skevlo return (usbd_do_request(sc->sc_udev, &req, &data)); 16180e584c77Skevlo } 16190e584c77Skevlo 16200e584c77Skevlo usbd_status 16210e584c77Skevlo urtw_write8e(struct urtw_softc *sc, int val, uint8_t data) 16220e584c77Skevlo { 16230e584c77Skevlo usb_device_request_t req; 16240e584c77Skevlo 16250e584c77Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 16260e584c77Skevlo req.bRequest = URTW_8187_SETREGS_REQ; 16270e584c77Skevlo USETW(req.wValue, val | 0xfe00); 16280e584c77Skevlo USETW(req.wIndex, 0); 16290e584c77Skevlo USETW(req.wLength, sizeof(uint8_t)); 16300e584c77Skevlo 16310e584c77Skevlo return (usbd_do_request(sc->sc_udev, &req, &data)); 16320e584c77Skevlo } 16330e584c77Skevlo 16340e584c77Skevlo usbd_status 16350ec995ceSmartynas urtw_write16_c(struct urtw_softc *sc, int val, uint16_t data, uint8_t idx) 16360e584c77Skevlo { 16370e584c77Skevlo usb_device_request_t req; 16380e584c77Skevlo 16390e584c77Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 16400e584c77Skevlo req.bRequest = URTW_8187_SETREGS_REQ; 16410e584c77Skevlo USETW(req.wValue, val | 0xff00); 16420ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 16430e584c77Skevlo USETW(req.wLength, sizeof(uint16_t)); 16440e584c77Skevlo 16459752fecbSstsp data = htole16(data); 16460e584c77Skevlo return (usbd_do_request(sc->sc_udev, &req, &data)); 16470e584c77Skevlo } 16480e584c77Skevlo 16490e584c77Skevlo usbd_status 16500ec995ceSmartynas urtw_write32_c(struct urtw_softc *sc, int val, uint32_t data, uint8_t idx) 16510e584c77Skevlo { 16520e584c77Skevlo usb_device_request_t req; 16530e584c77Skevlo 16540e584c77Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 16550e584c77Skevlo req.bRequest = URTW_8187_SETREGS_REQ; 16560e584c77Skevlo USETW(req.wValue, val | 0xff00); 16570ec995ceSmartynas USETW(req.wIndex, idx & 0x03); 16580e584c77Skevlo USETW(req.wLength, sizeof(uint32_t)); 16590e584c77Skevlo 16609752fecbSstsp data = htole32(data); 16610e584c77Skevlo return (usbd_do_request(sc->sc_udev, &req, &data)); 16620e584c77Skevlo } 16630e584c77Skevlo 16640e584c77Skevlo static usbd_status 16650e584c77Skevlo urtw_set_mode(struct urtw_softc *sc, uint32_t mode) 16660e584c77Skevlo { 16670e584c77Skevlo uint8_t data; 16680e584c77Skevlo usbd_status error; 16690e584c77Skevlo 16700e584c77Skevlo urtw_read8_m(sc, URTW_EPROM_CMD, &data); 16710e584c77Skevlo data = (data & ~URTW_EPROM_CMD_MASK) | (mode << URTW_EPROM_CMD_SHIFT); 16720e584c77Skevlo data = data & ~(URTW_EPROM_CS | URTW_EPROM_CK); 16730e584c77Skevlo urtw_write8_m(sc, URTW_EPROM_CMD, data); 16740e584c77Skevlo fail: 16750e584c77Skevlo return (error); 16760e584c77Skevlo } 16770e584c77Skevlo 16780e584c77Skevlo usbd_status 16790e584c77Skevlo urtw_8180_set_anaparam(struct urtw_softc *sc, uint32_t val) 16800e584c77Skevlo { 16810e584c77Skevlo uint8_t data; 16820e584c77Skevlo usbd_status error; 16830e584c77Skevlo 16840e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 16850e584c77Skevlo if (error) 16860e584c77Skevlo goto fail; 16870e584c77Skevlo 16880e584c77Skevlo urtw_read8_m(sc, URTW_CONFIG3, &data); 16890e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 16900e584c77Skevlo urtw_write32_m(sc, URTW_ANAPARAM, val); 16910e584c77Skevlo urtw_read8_m(sc, URTW_CONFIG3, &data); 16920e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 16930e584c77Skevlo 16940e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 16950e584c77Skevlo if (error) 16960e584c77Skevlo goto fail; 16970e584c77Skevlo fail: 16980e584c77Skevlo return (error); 16990e584c77Skevlo } 17000e584c77Skevlo 17010e584c77Skevlo usbd_status 17020e584c77Skevlo urtw_8185_set_anaparam2(struct urtw_softc *sc, uint32_t val) 17030e584c77Skevlo { 17040e584c77Skevlo uint8_t data; 17050e584c77Skevlo usbd_status error; 17060e584c77Skevlo 17070e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 17080e584c77Skevlo if (error) 17090e584c77Skevlo goto fail; 17100e584c77Skevlo 17110e584c77Skevlo urtw_read8_m(sc, URTW_CONFIG3, &data); 17120e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 17130e584c77Skevlo urtw_write32_m(sc, URTW_ANAPARAM2, val); 17140e584c77Skevlo urtw_read8_m(sc, URTW_CONFIG3, &data); 17150e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 17160e584c77Skevlo 17170e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 17180e584c77Skevlo if (error) 17190e584c77Skevlo goto fail; 17200e584c77Skevlo fail: 17210e584c77Skevlo return (error); 17220e584c77Skevlo } 17230e584c77Skevlo 17240e584c77Skevlo usbd_status 17250e584c77Skevlo urtw_intr_disable(struct urtw_softc *sc) 17260e584c77Skevlo { 17270e584c77Skevlo usbd_status error; 17280e584c77Skevlo 17290e584c77Skevlo urtw_write16_m(sc, URTW_INTR_MASK, 0); 17300e584c77Skevlo fail: 17310e584c77Skevlo return (error); 17320e584c77Skevlo } 17330e584c77Skevlo 17340e584c77Skevlo usbd_status 17350e584c77Skevlo urtw_reset(struct urtw_softc *sc) 17360e584c77Skevlo { 17370e584c77Skevlo uint8_t data; 17380e584c77Skevlo usbd_status error; 17390e584c77Skevlo 1740896bfc84Smartynas error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON); 17410e584c77Skevlo if (error) 17420e584c77Skevlo goto fail; 1743896bfc84Smartynas error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON); 17440e584c77Skevlo if (error) 17450e584c77Skevlo goto fail; 17460e584c77Skevlo 17470e584c77Skevlo error = urtw_intr_disable(sc); 17480e584c77Skevlo if (error) 17490e584c77Skevlo goto fail; 17506fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 17510e584c77Skevlo 17520e584c77Skevlo error = urtw_write8e(sc, 0x18, 0x10); 17530e584c77Skevlo if (error != 0) 17540e584c77Skevlo goto fail; 17550e584c77Skevlo error = urtw_write8e(sc, 0x18, 0x11); 17560e584c77Skevlo if (error != 0) 17570e584c77Skevlo goto fail; 17580e584c77Skevlo error = urtw_write8e(sc, 0x18, 0x00); 17590e584c77Skevlo if (error != 0) 17600e584c77Skevlo goto fail; 17616fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 17620e584c77Skevlo 17630e584c77Skevlo urtw_read8_m(sc, URTW_CMD, &data); 17640e584c77Skevlo data = (data & 2) | URTW_CMD_RST; 17650e584c77Skevlo urtw_write8_m(sc, URTW_CMD, data); 17666fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 17670e584c77Skevlo 17680e584c77Skevlo urtw_read8_m(sc, URTW_CMD, &data); 17690e584c77Skevlo if (data & URTW_CMD_RST) { 17700e584c77Skevlo printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 17710e584c77Skevlo goto fail; 17720e584c77Skevlo } 17730e584c77Skevlo 17740e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_LOAD); 17750e584c77Skevlo if (error) 17760e584c77Skevlo goto fail; 17776fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 17780e584c77Skevlo 1779896bfc84Smartynas error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON); 17800e584c77Skevlo if (error) 17810e584c77Skevlo goto fail; 1782896bfc84Smartynas error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON); 17830e584c77Skevlo if (error) 17840e584c77Skevlo goto fail; 17850e584c77Skevlo fail: 17860e584c77Skevlo return (error); 17870e584c77Skevlo } 17880e584c77Skevlo 17890e584c77Skevlo usbd_status 17900e584c77Skevlo urtw_led_on(struct urtw_softc *sc, int type) 17910e584c77Skevlo { 1792d32f9784Sstsp usbd_status error = 0; 17930e584c77Skevlo 17940e584c77Skevlo if (type == URTW_LED_GPIO) { 17950e584c77Skevlo switch (sc->sc_gpio_ledpin) { 17960e584c77Skevlo case URTW_LED_PIN_GPIO0: 17970e584c77Skevlo urtw_write8_m(sc, URTW_GPIO, 0x01); 17980e584c77Skevlo urtw_write8_m(sc, URTW_GP_ENABLE, 0x00); 17990e584c77Skevlo break; 18000e584c77Skevlo default: 1801d32f9784Sstsp break; 18020e584c77Skevlo } 18030e584c77Skevlo } 18040e584c77Skevlo 18050e584c77Skevlo sc->sc_gpio_ledon = 1; 18060e584c77Skevlo fail: 18070e584c77Skevlo return (error); 18080e584c77Skevlo } 18090e584c77Skevlo 18100e584c77Skevlo static usbd_status 18110e584c77Skevlo urtw_led_off(struct urtw_softc *sc, int type) 18120e584c77Skevlo { 1813d32f9784Sstsp usbd_status error = 0; 18140e584c77Skevlo 18150e584c77Skevlo if (type == URTW_LED_GPIO) { 18160e584c77Skevlo switch (sc->sc_gpio_ledpin) { 18170e584c77Skevlo case URTW_LED_PIN_GPIO0: 18180e584c77Skevlo urtw_write8_m(sc, URTW_GPIO, 0x01); 18190e584c77Skevlo urtw_write8_m(sc, URTW_GP_ENABLE, 0x01); 18200e584c77Skevlo break; 18210e584c77Skevlo default: 1822d32f9784Sstsp break; 18230e584c77Skevlo } 18240e584c77Skevlo } 18250e584c77Skevlo 18260e584c77Skevlo sc->sc_gpio_ledon = 0; 18270e584c77Skevlo 18280e584c77Skevlo fail: 18290e584c77Skevlo return (error); 18300e584c77Skevlo } 18310e584c77Skevlo 18320e584c77Skevlo usbd_status 18330e584c77Skevlo urtw_led_mode0(struct urtw_softc *sc, int mode) 18340e584c77Skevlo { 18350e584c77Skevlo switch (mode) { 18360e584c77Skevlo case URTW_LED_CTL_POWER_ON: 18370e584c77Skevlo sc->sc_gpio_ledstate = URTW_LED_POWER_ON_BLINK; 18380e584c77Skevlo break; 18390e584c77Skevlo case URTW_LED_CTL_TX: 18400e584c77Skevlo if (sc->sc_gpio_ledinprogress == 1) 18410e584c77Skevlo return (0); 18420e584c77Skevlo 18430e584c77Skevlo sc->sc_gpio_ledstate = URTW_LED_BLINK_NORMAL; 18440e584c77Skevlo sc->sc_gpio_blinktime = 2; 18450e584c77Skevlo break; 18460e584c77Skevlo case URTW_LED_CTL_LINK: 18470e584c77Skevlo sc->sc_gpio_ledstate = URTW_LED_ON; 18480e584c77Skevlo break; 18490e584c77Skevlo default: 1850d32f9784Sstsp break; 18510e584c77Skevlo } 18520e584c77Skevlo 18530e584c77Skevlo switch (sc->sc_gpio_ledstate) { 18540e584c77Skevlo case URTW_LED_ON: 18550e584c77Skevlo if (sc->sc_gpio_ledinprogress != 0) 18560e584c77Skevlo break; 18570e584c77Skevlo urtw_led_on(sc, URTW_LED_GPIO); 18580e584c77Skevlo break; 18590e584c77Skevlo case URTW_LED_BLINK_NORMAL: 18600e584c77Skevlo if (sc->sc_gpio_ledinprogress != 0) 18610e584c77Skevlo break; 18620e584c77Skevlo sc->sc_gpio_ledinprogress = 1; 18630e584c77Skevlo sc->sc_gpio_blinkstate = (sc->sc_gpio_ledon != 0) ? 18640e584c77Skevlo URTW_LED_OFF : URTW_LED_ON; 186512136ef5Sjakemsr if (!usbd_is_dying(sc->sc_udev)) 1866ed2f6cd3Skn timeout_add_msec(&sc->sc_led_ch, 100); 18670e584c77Skevlo break; 18680e584c77Skevlo case URTW_LED_POWER_ON_BLINK: 18690e584c77Skevlo urtw_led_on(sc, URTW_LED_GPIO); 18700e584c77Skevlo usbd_delay_ms(sc->sc_udev, 100); 18710e584c77Skevlo urtw_led_off(sc, URTW_LED_GPIO); 18720e584c77Skevlo break; 18730e584c77Skevlo default: 1874d32f9784Sstsp break; 18750e584c77Skevlo } 18760e584c77Skevlo return (0); 18770e584c77Skevlo } 18780e584c77Skevlo 18790e584c77Skevlo usbd_status 18800e584c77Skevlo urtw_led_mode1(struct urtw_softc *sc, int mode) 18810e584c77Skevlo { 18820e584c77Skevlo return (USBD_INVAL); 18830e584c77Skevlo } 18840e584c77Skevlo 18850e584c77Skevlo usbd_status 18860e584c77Skevlo urtw_led_mode2(struct urtw_softc *sc, int mode) 18870e584c77Skevlo { 18880e584c77Skevlo return (USBD_INVAL); 18890e584c77Skevlo } 18900e584c77Skevlo 18910e584c77Skevlo usbd_status 18920e584c77Skevlo urtw_led_mode3(struct urtw_softc *sc, int mode) 18930e584c77Skevlo { 18940e584c77Skevlo return (USBD_INVAL); 18950e584c77Skevlo } 18960e584c77Skevlo 18970e584c77Skevlo void 18980e584c77Skevlo urtw_ledusbtask(void *arg) 18990e584c77Skevlo { 19000e584c77Skevlo struct urtw_softc *sc = arg; 19010e584c77Skevlo 19020e584c77Skevlo if (sc->sc_strategy != URTW_SW_LED_MODE0) 1903d32f9784Sstsp return; 19040e584c77Skevlo 19050e584c77Skevlo urtw_led_blink(sc); 19060e584c77Skevlo } 19070e584c77Skevlo 19080e584c77Skevlo void 19090e584c77Skevlo urtw_ledtask(void *arg) 19100e584c77Skevlo { 19110e584c77Skevlo struct urtw_softc *sc = arg; 19120e584c77Skevlo 19130e584c77Skevlo /* 19140e584c77Skevlo * NB: to change a status of the led we need at least a sleep so we 19150e584c77Skevlo * can't do it here 19160e584c77Skevlo */ 19170e584c77Skevlo usb_add_task(sc->sc_udev, &sc->sc_ledtask); 19180e584c77Skevlo } 19190e584c77Skevlo 19200e584c77Skevlo usbd_status 19210e584c77Skevlo urtw_led_ctl(struct urtw_softc *sc, int mode) 19220e584c77Skevlo { 19230e584c77Skevlo usbd_status error = 0; 19240e584c77Skevlo 19250e584c77Skevlo switch (sc->sc_strategy) { 19260e584c77Skevlo case URTW_SW_LED_MODE0: 19270e584c77Skevlo error = urtw_led_mode0(sc, mode); 19280e584c77Skevlo break; 19290e584c77Skevlo case URTW_SW_LED_MODE1: 19300e584c77Skevlo error = urtw_led_mode1(sc, mode); 19310e584c77Skevlo break; 19320e584c77Skevlo case URTW_SW_LED_MODE2: 19330e584c77Skevlo error = urtw_led_mode2(sc, mode); 19340e584c77Skevlo break; 19350e584c77Skevlo case URTW_SW_LED_MODE3: 19360e584c77Skevlo error = urtw_led_mode3(sc, mode); 19370e584c77Skevlo break; 19380e584c77Skevlo default: 1939d32f9784Sstsp break; 19400e584c77Skevlo } 19410e584c77Skevlo 19420e584c77Skevlo return (error); 19430e584c77Skevlo } 19440e584c77Skevlo 19450e584c77Skevlo usbd_status 19460e584c77Skevlo urtw_led_blink(struct urtw_softc *sc) 19470e584c77Skevlo { 19480e584c77Skevlo uint8_t ing = 0; 19490e584c77Skevlo usbd_status error; 19500e584c77Skevlo 19510e584c77Skevlo if (sc->sc_gpio_blinkstate == URTW_LED_ON) 19520e584c77Skevlo error = urtw_led_on(sc, URTW_LED_GPIO); 19530e584c77Skevlo else 19540e584c77Skevlo error = urtw_led_off(sc, URTW_LED_GPIO); 19550e584c77Skevlo sc->sc_gpio_blinktime--; 19560e584c77Skevlo if (sc->sc_gpio_blinktime == 0) 19570e584c77Skevlo ing = 1; 19580e584c77Skevlo else { 19590e584c77Skevlo if (sc->sc_gpio_ledstate != URTW_LED_BLINK_NORMAL && 19600e584c77Skevlo sc->sc_gpio_ledstate != URTW_LED_BLINK_SLOWLY && 19610e584c77Skevlo sc->sc_gpio_ledstate != URTW_LED_BLINK_CM3) 19620e584c77Skevlo ing = 1; 19630e584c77Skevlo } 19640e584c77Skevlo if (ing == 1) { 19650e584c77Skevlo if (sc->sc_gpio_ledstate == URTW_LED_ON && 19660e584c77Skevlo sc->sc_gpio_ledon == 0) 19670e584c77Skevlo error = urtw_led_on(sc, URTW_LED_GPIO); 19680e584c77Skevlo else if (sc->sc_gpio_ledstate == URTW_LED_OFF && 19690e584c77Skevlo sc->sc_gpio_ledon == 1) 19700e584c77Skevlo error = urtw_led_off(sc, URTW_LED_GPIO); 19710e584c77Skevlo 19720e584c77Skevlo sc->sc_gpio_blinktime = 0; 19730e584c77Skevlo sc->sc_gpio_ledinprogress = 0; 19740e584c77Skevlo return (0); 19750e584c77Skevlo } 19760e584c77Skevlo 19770e584c77Skevlo sc->sc_gpio_blinkstate = (sc->sc_gpio_blinkstate != URTW_LED_ON) ? 19780e584c77Skevlo URTW_LED_ON : URTW_LED_OFF; 19790e584c77Skevlo 19800e584c77Skevlo switch (sc->sc_gpio_ledstate) { 19810e584c77Skevlo case URTW_LED_BLINK_NORMAL: 198212136ef5Sjakemsr if (!usbd_is_dying(sc->sc_udev)) 1983ed2f6cd3Skn timeout_add_msec(&sc->sc_led_ch, 100); 19840e584c77Skevlo break; 19850e584c77Skevlo default: 1986d32f9784Sstsp break; 19870e584c77Skevlo } 19880e584c77Skevlo return (0); 19890e584c77Skevlo } 19900e584c77Skevlo 19910e584c77Skevlo usbd_status 19920e584c77Skevlo urtw_update_msr(struct urtw_softc *sc) 19930e584c77Skevlo { 19940e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 19950e584c77Skevlo uint8_t data; 19960e584c77Skevlo usbd_status error; 19970e584c77Skevlo 19980e584c77Skevlo urtw_read8_m(sc, URTW_MSR, &data); 19990e584c77Skevlo data &= ~URTW_MSR_LINK_MASK; 20000e584c77Skevlo 20013d4b849eSmartynas /* Should always be set. */ 20023d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187B) 20033d4b849eSmartynas data |= URTW_MSR_LINK_ENEDCA; 20043d4b849eSmartynas 20050e584c77Skevlo if (sc->sc_state == IEEE80211_S_RUN) { 20060e584c77Skevlo switch (ic->ic_opmode) { 20070e584c77Skevlo case IEEE80211_M_STA: 20080e584c77Skevlo case IEEE80211_M_MONITOR: 20090e584c77Skevlo data |= URTW_MSR_LINK_STA; 20100e584c77Skevlo break; 20110e584c77Skevlo default: 2012d32f9784Sstsp break; 20130e584c77Skevlo } 20140e584c77Skevlo } else 20150e584c77Skevlo data |= URTW_MSR_LINK_NONE; 20160e584c77Skevlo 20170e584c77Skevlo urtw_write8_m(sc, URTW_MSR, data); 20180e584c77Skevlo fail: 20190e584c77Skevlo return (error); 20200e584c77Skevlo } 20210e584c77Skevlo 20220e584c77Skevlo uint16_t 20230e584c77Skevlo urtw_rate2rtl(int rate) 20240e584c77Skevlo { 20250e584c77Skevlo int i; 20260e584c77Skevlo 202716f0c350Skevlo for (i = 0; i < nitems(urtw_ratetable); i++) { 20280e584c77Skevlo if (rate == urtw_ratetable[i].reg) 2029217395cbSmartynas return (urtw_ratetable[i].val); 20300e584c77Skevlo } 20310e584c77Skevlo 20320e584c77Skevlo return (3); 20330e584c77Skevlo } 20340e584c77Skevlo 20350e584c77Skevlo uint16_t 20360e584c77Skevlo urtw_rtl2rate(int rate) 20370e584c77Skevlo { 20380e584c77Skevlo int i; 20390e584c77Skevlo 204016f0c350Skevlo for (i = 0; i < nitems(urtw_ratetable); i++) { 20410e584c77Skevlo if (rate == urtw_ratetable[i].val) 2042217395cbSmartynas return (urtw_ratetable[i].reg); 20430e584c77Skevlo } 20440e584c77Skevlo 20450e584c77Skevlo return (0); 20460e584c77Skevlo } 20470e584c77Skevlo 20480e584c77Skevlo usbd_status 20490e584c77Skevlo urtw_set_rate(struct urtw_softc *sc) 20500e584c77Skevlo { 20510e584c77Skevlo int i, basic_rate, min_rr_rate, max_rr_rate; 20520e584c77Skevlo uint16_t data; 20530e584c77Skevlo usbd_status error; 20540e584c77Skevlo 20550e584c77Skevlo basic_rate = urtw_rate2rtl(48); 20560e584c77Skevlo min_rr_rate = urtw_rate2rtl(12); 20570e584c77Skevlo max_rr_rate = urtw_rate2rtl(48); 20580e584c77Skevlo 20590e584c77Skevlo urtw_write8_m(sc, URTW_RESP_RATE, 20600e584c77Skevlo max_rr_rate << URTW_RESP_MAX_RATE_SHIFT | 20610e584c77Skevlo min_rr_rate << URTW_RESP_MIN_RATE_SHIFT); 20620e584c77Skevlo 2063ac7c6af9Smartynas urtw_read16_m(sc, URTW_8187_BRSR, &data); 20640e584c77Skevlo data &= ~URTW_BRSR_MBR_8185; 20650e584c77Skevlo 20660e584c77Skevlo for (i = 0; i <= basic_rate; i++) 20670e584c77Skevlo data |= (1 << i); 20680e584c77Skevlo 2069ac7c6af9Smartynas urtw_write16_m(sc, URTW_8187_BRSR, data); 20700e584c77Skevlo fail: 20710e584c77Skevlo return (error); 20720e584c77Skevlo } 20730e584c77Skevlo 20740e584c77Skevlo usbd_status 20750e584c77Skevlo urtw_intr_enable(struct urtw_softc *sc) 20760e584c77Skevlo { 20770e584c77Skevlo usbd_status error; 20780e584c77Skevlo 20790e584c77Skevlo urtw_write16_m(sc, URTW_INTR_MASK, 0xffff); 20800e584c77Skevlo fail: 20810e584c77Skevlo return (error); 20820e584c77Skevlo } 20830e584c77Skevlo 20840e584c77Skevlo usbd_status 20850e584c77Skevlo urtw_rx_setconf(struct urtw_softc *sc) 20860e584c77Skevlo { 20870e584c77Skevlo struct ifnet *ifp = &sc->sc_ic.ic_if; 20880e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 20890e584c77Skevlo uint32_t data; 20900e584c77Skevlo usbd_status error; 20910e584c77Skevlo 20920e584c77Skevlo urtw_read32_m(sc, URTW_RX, &data); 20930e584c77Skevlo data = data &~ URTW_RX_FILTER_MASK; 20940e584c77Skevlo #if 0 20950e584c77Skevlo data = data | URTW_RX_FILTER_CTL; 20960e584c77Skevlo #endif 20970e584c77Skevlo data = data | URTW_RX_FILTER_MNG | URTW_RX_FILTER_DATA; 20980e584c77Skevlo data = data | URTW_RX_FILTER_BCAST | URTW_RX_FILTER_MCAST; 20990e584c77Skevlo 21000e584c77Skevlo if (ic->ic_opmode == IEEE80211_M_MONITOR) { 21010e584c77Skevlo data = data | URTW_RX_FILTER_ICVERR; 21020e584c77Skevlo data = data | URTW_RX_FILTER_PWR; 21030e584c77Skevlo } 21040e584c77Skevlo if (sc->sc_crcmon == 1 && ic->ic_opmode == IEEE80211_M_MONITOR) 21050e584c77Skevlo data = data | URTW_RX_FILTER_CRCERR; 21060e584c77Skevlo 21070e584c77Skevlo if (ic->ic_opmode == IEEE80211_M_MONITOR || 21080e584c77Skevlo (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC))) { 21090e584c77Skevlo data = data | URTW_RX_FILTER_ALLMAC; 21100e584c77Skevlo } else { 21110e584c77Skevlo data = data | URTW_RX_FILTER_NICMAC; 21120e584c77Skevlo data = data | URTW_RX_CHECK_BSSID; 21130e584c77Skevlo } 21140e584c77Skevlo 21150e584c77Skevlo data = data &~ URTW_RX_FIFO_THRESHOLD_MASK; 21160e584c77Skevlo data = data | URTW_RX_FIFO_THRESHOLD_NONE | URTW_RX_AUTORESETPHY; 21170e584c77Skevlo data = data &~ URTW_MAX_RX_DMA_MASK; 21180e584c77Skevlo data = data | URTW_MAX_RX_DMA_2048 | URTW_RCR_ONLYERLPKT; 21190e584c77Skevlo 21200e584c77Skevlo urtw_write32_m(sc, URTW_RX, data); 21210e584c77Skevlo fail: 21220e584c77Skevlo return (error); 21230e584c77Skevlo } 21240e584c77Skevlo 21250e584c77Skevlo usbd_status 21260e584c77Skevlo urtw_rx_enable(struct urtw_softc *sc) 21270e584c77Skevlo { 21280e584c77Skevlo int i; 2129366cafe1Smartynas struct urtw_rx_data *rx_data; 21300e584c77Skevlo uint8_t data; 21310e584c77Skevlo usbd_status error; 21320e584c77Skevlo 21330e584c77Skevlo /* 21340e584c77Skevlo * Start up the receive pipe. 21350e584c77Skevlo */ 21360e584c77Skevlo for (i = 0; i < URTW_RX_DATA_LIST_COUNT; i++) { 2137366cafe1Smartynas rx_data = &sc->sc_rx_data[i]; 21380e584c77Skevlo 2139366cafe1Smartynas usbd_setup_xfer(rx_data->xfer, sc->sc_rxpipe, rx_data, 2140366cafe1Smartynas rx_data->buf, MCLBYTES, USBD_SHORT_XFER_OK, 2141366cafe1Smartynas USBD_NO_TIMEOUT, urtw_rxeof); 2142366cafe1Smartynas error = usbd_transfer(rx_data->xfer); 21430e584c77Skevlo if (error != USBD_IN_PROGRESS && error != 0) { 21440e584c77Skevlo printf("%s: could not queue Rx transfer\n", 21450e584c77Skevlo sc->sc_dev.dv_xname); 21460e584c77Skevlo goto fail; 21470e584c77Skevlo } 21480e584c77Skevlo } 21490e584c77Skevlo 21500e584c77Skevlo error = urtw_rx_setconf(sc); 21510e584c77Skevlo if (error != 0) 21520e584c77Skevlo goto fail; 21530e584c77Skevlo 21540e584c77Skevlo urtw_read8_m(sc, URTW_CMD, &data); 21550e584c77Skevlo urtw_write8_m(sc, URTW_CMD, data | URTW_CMD_RX_ENABLE); 21560e584c77Skevlo fail: 21570e584c77Skevlo return (error); 21580e584c77Skevlo } 21590e584c77Skevlo 21600e584c77Skevlo usbd_status 21610e584c77Skevlo urtw_tx_enable(struct urtw_softc *sc) 21620e584c77Skevlo { 21630e584c77Skevlo uint8_t data8; 21640e584c77Skevlo uint32_t data; 21650e584c77Skevlo usbd_status error; 21660e584c77Skevlo 21673d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 21680e584c77Skevlo urtw_read8_m(sc, URTW_CW_CONF, &data8); 21693d4b849eSmartynas data8 &= ~(URTW_CW_CONF_PERPACKET_CW | 21703d4b849eSmartynas URTW_CW_CONF_PERPACKET_RETRY); 21710e584c77Skevlo urtw_write8_m(sc, URTW_CW_CONF, data8); 21720e584c77Skevlo 21730e584c77Skevlo urtw_read8_m(sc, URTW_TX_AGC_CTL, &data8); 21740e584c77Skevlo data8 &= ~URTW_TX_AGC_CTL_PERPACKET_GAIN; 21750e584c77Skevlo data8 &= ~URTW_TX_AGC_CTL_PERPACKET_ANTSEL; 21760e584c77Skevlo data8 &= ~URTW_TX_AGC_CTL_FEEDBACK_ANT; 21770e584c77Skevlo urtw_write8_m(sc, URTW_TX_AGC_CTL, data8); 21780e584c77Skevlo 21790e584c77Skevlo urtw_read32_m(sc, URTW_TX_CONF, &data); 21800e584c77Skevlo data &= ~URTW_TX_LOOPBACK_MASK; 21810e584c77Skevlo data |= URTW_TX_LOOPBACK_NONE; 21820e584c77Skevlo data &= ~(URTW_TX_DPRETRY_MASK | URTW_TX_RTSRETRY_MASK); 21830e584c77Skevlo data |= sc->sc_tx_retry << URTW_TX_DPRETRY_SHIFT; 21840e584c77Skevlo data |= sc->sc_rts_retry << URTW_TX_RTSRETRY_SHIFT; 21850e584c77Skevlo data &= ~(URTW_TX_NOCRC | URTW_TX_MXDMA_MASK); 21860e584c77Skevlo data |= URTW_TX_MXDMA_2048 | URTW_TX_CWMIN | URTW_TX_DISCW; 21870e584c77Skevlo data &= ~URTW_TX_SWPLCPLEN; 21880e584c77Skevlo data |= URTW_TX_NOICV; 21890e584c77Skevlo urtw_write32_m(sc, URTW_TX_CONF, data); 21903d4b849eSmartynas } else { 21913d4b849eSmartynas data = URTW_TX_DURPROCMODE | URTW_TX_DISREQQSIZE | 21923d4b849eSmartynas URTW_TX_MXDMA_2048 | URTW_TX_SHORTRETRY | 21933d4b849eSmartynas URTW_TX_LONGRETRY; 21943d4b849eSmartynas urtw_write32_m(sc, URTW_TX_CONF, data); 21953d4b849eSmartynas } 21960e584c77Skevlo 21970e584c77Skevlo urtw_read8_m(sc, URTW_CMD, &data8); 21980e584c77Skevlo urtw_write8_m(sc, URTW_CMD, data8 | URTW_CMD_TX_ENABLE); 21990e584c77Skevlo fail: 22000e584c77Skevlo return (error); 22010e584c77Skevlo } 22020e584c77Skevlo 22030e584c77Skevlo int 22040e584c77Skevlo urtw_init(struct ifnet *ifp) 22050e584c77Skevlo { 22060e584c77Skevlo struct urtw_softc *sc = ifp->if_softc; 2207abcf0a78Smartynas struct urtw_rf *rf = &sc->sc_rf; 22080e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 22090e584c77Skevlo usbd_status error; 22100e584c77Skevlo 22116fb8d30bSkevlo urtw_stop(ifp, 0); 22126fb8d30bSkevlo 22130e584c77Skevlo error = urtw_reset(sc); 22140e584c77Skevlo if (error) 22150e584c77Skevlo goto fail; 22160e584c77Skevlo 22170e584c77Skevlo urtw_write8_m(sc, 0x85, 0); 22180e584c77Skevlo urtw_write8_m(sc, URTW_GPIO, 0); 22190e584c77Skevlo 22200e584c77Skevlo /* for led */ 22210e584c77Skevlo urtw_write8_m(sc, 0x85, 4); 22220e584c77Skevlo error = urtw_led_ctl(sc, URTW_LED_CTL_POWER_ON); 22230e584c77Skevlo if (error != 0) 22240e584c77Skevlo goto fail; 22250e584c77Skevlo 22260e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 22270e584c77Skevlo if (error) 22280e584c77Skevlo goto fail; 22290e584c77Skevlo 22300e584c77Skevlo /* applying MAC address again. */ 22310e584c77Skevlo IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); 223249b282e9Smiod error = urtw_set_macaddr(sc, ic->ic_myaddr); 223349b282e9Smiod if (error) 223449b282e9Smiod goto fail; 22350e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 22360e584c77Skevlo if (error) 22370e584c77Skevlo goto fail; 22380e584c77Skevlo 22390e584c77Skevlo error = urtw_update_msr(sc); 22400e584c77Skevlo if (error) 22410e584c77Skevlo goto fail; 22420e584c77Skevlo 22430e584c77Skevlo urtw_write32_m(sc, URTW_INT_TIMEOUT, 0); 22440e584c77Skevlo urtw_write8_m(sc, URTW_WPA_CONFIG, 0); 22450e584c77Skevlo urtw_write8_m(sc, URTW_RATE_FALLBACK, 0x81); 22460e584c77Skevlo error = urtw_set_rate(sc); 22470e584c77Skevlo if (error != 0) 22480e584c77Skevlo goto fail; 22490e584c77Skevlo 2250abcf0a78Smartynas error = rf->init(rf); 22510e584c77Skevlo if (error != 0) 22520e584c77Skevlo goto fail; 2253abcf0a78Smartynas if (rf->set_sens != NULL) 2254abcf0a78Smartynas rf->set_sens(rf); 22550e584c77Skevlo 22560e584c77Skevlo urtw_write16_m(sc, 0x5e, 1); 22570e584c77Skevlo urtw_write16_m(sc, 0xfe, 0x10); 22580e584c77Skevlo urtw_write8_m(sc, URTW_TALLY_SEL, 0x80); 22590e584c77Skevlo urtw_write8_m(sc, 0xff, 0x60); 22600e584c77Skevlo urtw_write16_m(sc, 0x5e, 0); 22610e584c77Skevlo urtw_write8_m(sc, 0x85, 4); 22620e584c77Skevlo 22630e584c77Skevlo error = urtw_intr_enable(sc); 22640e584c77Skevlo if (error != 0) 22650e584c77Skevlo goto fail; 22660e584c77Skevlo 22670e584c77Skevlo /* reset softc variables */ 22680e584c77Skevlo sc->sc_txidx = sc->sc_tx_low_queued = sc->sc_tx_normal_queued = 0; 22690e584c77Skevlo sc->sc_txtimer = 0; 22700e584c77Skevlo 22710e584c77Skevlo if (!(sc->sc_flags & URTW_INIT_ONCE)) { 22720e584c77Skevlo error = urtw_open_pipes(sc); 22730e584c77Skevlo if (error != 0) 22740e584c77Skevlo goto fail; 227575cd1aa0Skevlo error = urtw_alloc_rx_data_list(sc); 22760e584c77Skevlo if (error != 0) 22770e584c77Skevlo goto fail; 227875cd1aa0Skevlo error = urtw_alloc_tx_data_list(sc); 22790e584c77Skevlo if (error != 0) 22800e584c77Skevlo goto fail; 22810e584c77Skevlo sc->sc_flags |= URTW_INIT_ONCE; 22820e584c77Skevlo } 22830e584c77Skevlo 22840e584c77Skevlo error = urtw_rx_enable(sc); 22850e584c77Skevlo if (error != 0) 22860e584c77Skevlo goto fail; 22870e584c77Skevlo error = urtw_tx_enable(sc); 22880e584c77Skevlo if (error != 0) 22890e584c77Skevlo goto fail; 22900e584c77Skevlo 2291de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 22920e584c77Skevlo ifp->if_flags |= IFF_RUNNING; 22930e584c77Skevlo 22940e584c77Skevlo ifp->if_timer = 1; 22950e584c77Skevlo 22960e584c77Skevlo if (ic->ic_opmode == IEEE80211_M_MONITOR) 22970e584c77Skevlo ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 22980e584c77Skevlo else 22990e584c77Skevlo ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 23000e584c77Skevlo 23010e584c77Skevlo return (0); 23020e584c77Skevlo fail: 23030e584c77Skevlo return (error); 23040e584c77Skevlo } 23050e584c77Skevlo 23060e584c77Skevlo void 23070e584c77Skevlo urtw_set_multi(struct urtw_softc *sc) 23080e584c77Skevlo { 23090e584c77Skevlo struct arpcom *ac = &sc->sc_ic.ic_ac; 23100e584c77Skevlo struct ifnet *ifp = &ac->ac_if; 23110e584c77Skevlo 23120e584c77Skevlo /* 23130e584c77Skevlo * XXX don't know how to set a device. Lack of docs. Just try to set 23140e584c77Skevlo * IFF_ALLMULTI flag here. 23150e584c77Skevlo */ 23160e584c77Skevlo ifp->if_flags |= IFF_ALLMULTI; 23170e584c77Skevlo } 23180e584c77Skevlo 23190e584c77Skevlo int 23200e584c77Skevlo urtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 23210e584c77Skevlo { 23220e584c77Skevlo struct urtw_softc *sc = ifp->if_softc; 23230e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 23240e584c77Skevlo struct ifreq *ifr; 23250e584c77Skevlo int s, error = 0; 23260e584c77Skevlo 232712136ef5Sjakemsr if (usbd_is_dying(sc->sc_udev)) 232812136ef5Sjakemsr return (ENXIO); 232912136ef5Sjakemsr 233012136ef5Sjakemsr usbd_ref_incr(sc->sc_udev); 233112136ef5Sjakemsr 23320e584c77Skevlo s = splnet(); 23330e584c77Skevlo 23340e584c77Skevlo switch (cmd) { 23350e584c77Skevlo case SIOCSIFADDR: 23360e584c77Skevlo ifp->if_flags |= IFF_UP; 23370e584c77Skevlo /* FALLTHROUGH */ 23380e584c77Skevlo case SIOCSIFFLAGS: 23390e584c77Skevlo if (ifp->if_flags & IFF_UP) { 23400e584c77Skevlo /* 23410e584c77Skevlo * If only the PROMISC or ALLMULTI flag changes, then 23420e584c77Skevlo * don't do a full re-init of the chip, just update 23430e584c77Skevlo * the Rx filter. 23440e584c77Skevlo */ 23450e584c77Skevlo if ((ifp->if_flags & IFF_RUNNING) && 23460e584c77Skevlo ((ifp->if_flags ^ sc->sc_if_flags) & 23470e584c77Skevlo (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 23480e584c77Skevlo urtw_set_multi(sc); 23490e584c77Skevlo } else { 23500e584c77Skevlo if (!(ifp->if_flags & IFF_RUNNING)) 2351f110151dSjsg sc->sc_init(ifp); 23520e584c77Skevlo } 23530e584c77Skevlo } else { 23540e584c77Skevlo if (ifp->if_flags & IFF_RUNNING) 23550e584c77Skevlo urtw_stop(ifp, 1); 23560e584c77Skevlo } 23570e584c77Skevlo sc->sc_if_flags = ifp->if_flags; 23580e584c77Skevlo break; 23590e584c77Skevlo 23600e584c77Skevlo case SIOCADDMULTI: 23610e584c77Skevlo case SIOCDELMULTI: 23620e584c77Skevlo ifr = (struct ifreq *)data; 23630e584c77Skevlo error = (cmd == SIOCADDMULTI) ? 23640e584c77Skevlo ether_addmulti(ifr, &ic->ic_ac) : 23650e584c77Skevlo ether_delmulti(ifr, &ic->ic_ac); 23660e584c77Skevlo if (error == ENETRESET) { 23670e584c77Skevlo if (ifp->if_flags & IFF_RUNNING) 23680e584c77Skevlo urtw_set_multi(sc); 23690e584c77Skevlo error = 0; 23700e584c77Skevlo } 23710e584c77Skevlo break; 23720e584c77Skevlo 23730e584c77Skevlo case SIOCS80211CHANNEL: 23740e584c77Skevlo /* 23750e584c77Skevlo * This allows for fast channel switching in monitor mode 23760e584c77Skevlo * (used by kismet). In IBSS mode, we must explicitly reset 23770e584c77Skevlo * the interface to generate a new beacon frame. 23780e584c77Skevlo */ 23790e584c77Skevlo error = ieee80211_ioctl(ifp, cmd, data); 23800e584c77Skevlo if (error == ENETRESET && 23810e584c77Skevlo ic->ic_opmode == IEEE80211_M_MONITOR) { 23820e584c77Skevlo urtw_set_chan(sc, ic->ic_ibss_chan); 23830e584c77Skevlo error = 0; 23840e584c77Skevlo } 23850e584c77Skevlo break; 23860e584c77Skevlo 23870e584c77Skevlo default: 23880e584c77Skevlo error = ieee80211_ioctl(ifp, cmd, data); 23890e584c77Skevlo } 23900e584c77Skevlo 23910e584c77Skevlo if (error == ENETRESET) { 23920e584c77Skevlo if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == 23930e584c77Skevlo (IFF_RUNNING | IFF_UP)) 2394f110151dSjsg sc->sc_init(ifp); 23950e584c77Skevlo error = 0; 23960e584c77Skevlo } 23970e584c77Skevlo 23980e584c77Skevlo splx(s); 23990e584c77Skevlo 240012136ef5Sjakemsr usbd_ref_decr(sc->sc_udev); 240112136ef5Sjakemsr 24020e584c77Skevlo return (error); 24030e584c77Skevlo } 24040e584c77Skevlo 24050e584c77Skevlo void 24060e584c77Skevlo urtw_start(struct ifnet *ifp) 24070e584c77Skevlo { 24080e584c77Skevlo struct urtw_softc *sc = ifp->if_softc; 24090e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 24100e584c77Skevlo struct ieee80211_node *ni; 24110e584c77Skevlo struct mbuf *m0; 24120e584c77Skevlo 24130e584c77Skevlo /* 24140e584c77Skevlo * net80211 may still try to send management frames even if the 24150e584c77Skevlo * IFF_RUNNING flag is not set... 24160e584c77Skevlo */ 2417de6cd8fbSdlg if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) 24180e584c77Skevlo return; 24190e584c77Skevlo 24200e584c77Skevlo for (;;) { 24210e584c77Skevlo if (sc->sc_tx_low_queued >= URTW_TX_DATA_LIST_COUNT || 242232a12f8bSmpi sc->sc_tx_normal_queued >= URTW_TX_DATA_LIST_COUNT) { 2423de6cd8fbSdlg ifq_set_oactive(&ifp->if_snd); 24240e584c77Skevlo break; 24250e584c77Skevlo } 242632a12f8bSmpi 242732a12f8bSmpi m0 = mq_dequeue(&ic->ic_mgtq); 242832a12f8bSmpi if (m0 != NULL) { 24296da4b19dSmpi ni = m0->m_pkthdr.ph_cookie; 24300e584c77Skevlo #if NBPFILTER > 0 24310e584c77Skevlo if (ic->ic_rawbpf != NULL) 24320e584c77Skevlo bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT); 24330e584c77Skevlo #endif 24340e584c77Skevlo if (urtw_tx_start(sc, ni, m0, URTW_PRIORITY_NORMAL) 24350e584c77Skevlo != 0) 24360e584c77Skevlo break; 24370e584c77Skevlo } else { 24380e584c77Skevlo if (ic->ic_state != IEEE80211_S_RUN) 24390e584c77Skevlo break; 244063bcfa73Spatrick m0 = ifq_dequeue(&ifp->if_snd); 24410e584c77Skevlo if (m0 == NULL) 24420e584c77Skevlo break; 24430e584c77Skevlo #if NBPFILTER > 0 24440e584c77Skevlo if (ifp->if_bpf != NULL) 24450e584c77Skevlo bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); 24460e584c77Skevlo #endif 24470e584c77Skevlo m0 = ieee80211_encap(ifp, m0, &ni); 24480e584c77Skevlo if (m0 == NULL) 24490e584c77Skevlo continue; 24500e584c77Skevlo #if NBPFILTER > 0 24510e584c77Skevlo if (ic->ic_rawbpf != NULL) 24520e584c77Skevlo bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT); 24530e584c77Skevlo #endif 24540e584c77Skevlo if (urtw_tx_start(sc, ni, m0, URTW_PRIORITY_NORMAL) 24550e584c77Skevlo != 0) { 24560e584c77Skevlo if (ni != NULL) 24570e584c77Skevlo ieee80211_release_node(ic, ni); 24580e584c77Skevlo ifp->if_oerrors++; 24590e584c77Skevlo break; 24600e584c77Skevlo } 24610e584c77Skevlo } 24620e584c77Skevlo sc->sc_txtimer = 5; 24630e584c77Skevlo } 24640e584c77Skevlo } 24650e584c77Skevlo 24660e584c77Skevlo void 24670e584c77Skevlo urtw_watchdog(struct ifnet *ifp) 24680e584c77Skevlo { 24690e584c77Skevlo struct urtw_softc *sc = ifp->if_softc; 24700e584c77Skevlo 24710e584c77Skevlo ifp->if_timer = 0; 24720e584c77Skevlo 24730e584c77Skevlo if (sc->sc_txtimer > 0) { 24740e584c77Skevlo if (--sc->sc_txtimer == 0) { 24750e584c77Skevlo printf("%s: device timeout\n", sc->sc_dev.dv_xname); 24760e584c77Skevlo ifp->if_oerrors++; 24770e584c77Skevlo return; 24780e584c77Skevlo } 24790e584c77Skevlo ifp->if_timer = 1; 24800e584c77Skevlo } 24810e584c77Skevlo 24820e584c77Skevlo ieee80211_watchdog(ifp); 24830e584c77Skevlo } 24840e584c77Skevlo 24850e584c77Skevlo void 2486ab0b1be7Smglocker urtw_txeof_low(struct usbd_xfer *xfer, void *priv, 24870e584c77Skevlo usbd_status status) 24880e584c77Skevlo { 248961a07a57Smartynas struct urtw_tx_data *data = priv; 24900e584c77Skevlo struct urtw_softc *sc = data->sc; 24910e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 24920e584c77Skevlo struct ifnet *ifp = &ic->ic_if; 24930e584c77Skevlo int s; 24940e584c77Skevlo 24950e584c77Skevlo if (status != USBD_NORMAL_COMPLETION) { 24960e584c77Skevlo if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 24970e584c77Skevlo return; 24980e584c77Skevlo 24990e584c77Skevlo printf("%s: could not transmit buffer: %s\n", 25000e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(status)); 25010e584c77Skevlo 25020e584c77Skevlo if (status == USBD_STALLED) 25030e584c77Skevlo usbd_clear_endpoint_stall_async(sc->sc_txpipe_low); 25040e584c77Skevlo 25050e584c77Skevlo ifp->if_oerrors++; 25060e584c77Skevlo return; 25070e584c77Skevlo } 25080e584c77Skevlo 25090e584c77Skevlo s = splnet(); 25100e584c77Skevlo 25110e584c77Skevlo ieee80211_release_node(ic, data->ni); 25120e584c77Skevlo data->ni = NULL; 25130e584c77Skevlo 25140e584c77Skevlo sc->sc_txtimer = 0; 25150e584c77Skevlo 25160e584c77Skevlo sc->sc_tx_low_queued--; 2517de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 25180e584c77Skevlo urtw_start(ifp); 25190e584c77Skevlo 25200e584c77Skevlo splx(s); 25210e584c77Skevlo } 25220e584c77Skevlo 25230e584c77Skevlo void 2524ab0b1be7Smglocker urtw_txeof_normal(struct usbd_xfer *xfer, void *priv, 25250e584c77Skevlo usbd_status status) 25260e584c77Skevlo { 252761a07a57Smartynas struct urtw_tx_data *data = priv; 25280e584c77Skevlo struct urtw_softc *sc = data->sc; 25290e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 25300e584c77Skevlo struct ifnet *ifp = &ic->ic_if; 25310e584c77Skevlo int s; 25320e584c77Skevlo 25330e584c77Skevlo if (status != USBD_NORMAL_COMPLETION) { 25340e584c77Skevlo if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 25350e584c77Skevlo return; 25360e584c77Skevlo 25370e584c77Skevlo printf("%s: could not transmit buffer: %s\n", 25380e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(status)); 25390e584c77Skevlo 25400e584c77Skevlo if (status == USBD_STALLED) 25410e584c77Skevlo usbd_clear_endpoint_stall_async(sc->sc_txpipe_normal); 25420e584c77Skevlo 25430e584c77Skevlo ifp->if_oerrors++; 25440e584c77Skevlo return; 25450e584c77Skevlo } 25460e584c77Skevlo 25470e584c77Skevlo s = splnet(); 25480e584c77Skevlo 25490e584c77Skevlo ieee80211_release_node(ic, data->ni); 25500e584c77Skevlo data->ni = NULL; 25510e584c77Skevlo 25520e584c77Skevlo sc->sc_txtimer = 0; 25530e584c77Skevlo 25540e584c77Skevlo sc->sc_tx_normal_queued--; 2555de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 25560e584c77Skevlo urtw_start(ifp); 25570e584c77Skevlo 25580e584c77Skevlo splx(s); 25590e584c77Skevlo } 25600e584c77Skevlo 25610e584c77Skevlo int 25620e584c77Skevlo urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, 25630e584c77Skevlo int prior) 25640e584c77Skevlo { 25650e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 256661a07a57Smartynas struct urtw_tx_data *data; 25670e584c77Skevlo struct ieee80211_frame *wh; 25680e584c77Skevlo struct ieee80211_key *k; 25690e584c77Skevlo usbd_status error; 25700e584c77Skevlo int xferlen; 25710e584c77Skevlo 25720e584c77Skevlo wh = mtod(m0, struct ieee80211_frame *); 25730e584c77Skevlo 25740e584c77Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 25750e584c77Skevlo k = ieee80211_get_txkey(ic, wh, ni); 25760e584c77Skevlo 25770e584c77Skevlo if ((m0 = ieee80211_encrypt(ic, m0, k)) == NULL) 25780e584c77Skevlo return (ENOBUFS); 25790e584c77Skevlo 25800e584c77Skevlo /* packet header may have moved, reset our local pointer */ 25810e584c77Skevlo wh = mtod(m0, struct ieee80211_frame *); 25820e584c77Skevlo } 25830e584c77Skevlo 25840e584c77Skevlo #if NBPFILTER > 0 25850e584c77Skevlo if (sc->sc_drvbpf != NULL) { 25860e584c77Skevlo struct mbuf mb; 25870e584c77Skevlo struct urtw_tx_radiotap_header *tap = &sc->sc_txtap; 25880e584c77Skevlo 25890e584c77Skevlo tap->wt_flags = 0; 25900e584c77Skevlo tap->wt_rate = 0; 25910e584c77Skevlo tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq); 25920e584c77Skevlo tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags); 25930e584c77Skevlo 25940e584c77Skevlo mb.m_data = (caddr_t)tap; 25950e584c77Skevlo mb.m_len = sc->sc_txtap_len; 25960e584c77Skevlo mb.m_next = m0; 25970e584c77Skevlo mb.m_nextpkt = NULL; 25980e584c77Skevlo mb.m_type = 0; 25990e584c77Skevlo mb.m_flags = 0; 26000e584c77Skevlo bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT); 26010e584c77Skevlo } 26020e584c77Skevlo #endif 26030e584c77Skevlo 26043d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) 26050e584c77Skevlo xferlen = m0->m_pkthdr.len + 4 * 3; 26063d4b849eSmartynas else 26073d4b849eSmartynas xferlen = m0->m_pkthdr.len + 4 * 8; 26083d4b849eSmartynas 26090e584c77Skevlo if ((0 == xferlen % 64) || (0 == xferlen % 512)) 26100e584c77Skevlo xferlen += 1; 26110e584c77Skevlo 2612366cafe1Smartynas data = &sc->sc_tx_data[sc->sc_txidx]; 26130e584c77Skevlo sc->sc_txidx = (sc->sc_txidx + 1) % URTW_TX_DATA_LIST_COUNT; 26140e584c77Skevlo 26150e584c77Skevlo bzero(data->buf, URTW_TX_MAXSIZE); 26160e584c77Skevlo data->buf[0] = m0->m_pkthdr.len & 0xff; 26170e584c77Skevlo data->buf[1] = (m0->m_pkthdr.len & 0x0f00) >> 8; 26180e584c77Skevlo data->buf[1] |= (1 << 7); 26190e584c77Skevlo 26200e584c77Skevlo /* XXX sc_preamble_mode is always 2. */ 26210e584c77Skevlo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 26220e584c77Skevlo (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) && 26230e584c77Skevlo (sc->sc_preamble_mode == 1) && (sc->sc_currate != 0)) 26240e584c77Skevlo data->buf[2] |= 1; 26250e584c77Skevlo if ((m0->m_pkthdr.len > ic->ic_rtsthreshold) && 26260e584c77Skevlo prior == URTW_PRIORITY_LOW) 2627d32f9784Sstsp return ENOTSUP; /* TODO */ 26280e584c77Skevlo if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) 26290e584c77Skevlo data->buf[2] |= (1 << 1); 26300e584c77Skevlo /* RTS rate - 10 means we use a basic rate. */ 26310e584c77Skevlo data->buf[2] |= (urtw_rate2rtl(2) << 3); 26320e584c77Skevlo /* 26330e584c77Skevlo * XXX currently TX rate control depends on the rate value of 26340e584c77Skevlo * RX descriptor because I don't know how to we can control TX rate 26350e584c77Skevlo * in more smart way. Please fix me you find a thing. 26360e584c77Skevlo */ 26370e584c77Skevlo data->buf[3] = sc->sc_currate; 26380e584c77Skevlo if (prior == URTW_PRIORITY_NORMAL) { 26390e584c77Skevlo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 26400e584c77Skevlo data->buf[3] = urtw_rate2rtl(ni->ni_rates.rs_rates[0]); 26410e584c77Skevlo else if (ic->ic_fixed_rate != -1) 26420e584c77Skevlo data->buf[3] = urtw_rate2rtl(ic->ic_fixed_rate); 26430e584c77Skevlo } 26443d4b849eSmartynas 26453d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 26460e584c77Skevlo data->buf[8] = 3; /* CW minimum */ 26470e584c77Skevlo data->buf[8] |= (7 << 4); /* CW maximum */ 26480e584c77Skevlo data->buf[9] |= 11; /* retry limitation */ 26495c7fed39Sdlg m_copydata(m0, 0, m0->m_pkthdr.len, &data->buf[12]); 26503d4b849eSmartynas } else { 26513d4b849eSmartynas data->buf[21] |= 11; /* retry limitation */ 26525c7fed39Sdlg m_copydata(m0, 0, m0->m_pkthdr.len, &data->buf[32]); 26533d4b849eSmartynas } 26543d4b849eSmartynas 26550e584c77Skevlo data->ni = ni; 2656522a965bSmartynas 2657522a965bSmartynas /* mbuf is no longer needed. */ 2658522a965bSmartynas m_freem(m0); 26590e584c77Skevlo 26600e584c77Skevlo usbd_setup_xfer(data->xfer, 26610e584c77Skevlo (prior == URTW_PRIORITY_LOW) ? sc->sc_txpipe_low : 26620e584c77Skevlo sc->sc_txpipe_normal, data, data->buf, xferlen, 26630e584c77Skevlo USBD_FORCE_SHORT_XFER | USBD_NO_COPY, URTW_DATA_TIMEOUT, 26640e584c77Skevlo (prior == URTW_PRIORITY_LOW) ? urtw_txeof_low : urtw_txeof_normal); 26650e584c77Skevlo error = usbd_transfer(data->xfer); 26660e584c77Skevlo if (error != USBD_IN_PROGRESS && error != USBD_NORMAL_COMPLETION) { 26670e584c77Skevlo printf("%s: could not send frame: %s\n", 26680e584c77Skevlo sc->sc_dev.dv_xname, usbd_errstr(error)); 26690e584c77Skevlo return (EIO); 26700e584c77Skevlo } 26710e584c77Skevlo 26720e584c77Skevlo error = urtw_led_ctl(sc, URTW_LED_CTL_TX); 26730e584c77Skevlo if (error != 0) 26740e584c77Skevlo printf("%s: could not control LED (%d)\n", 26750e584c77Skevlo sc->sc_dev.dv_xname, error); 26760e584c77Skevlo 26770e584c77Skevlo if (prior == URTW_PRIORITY_LOW) 26780e584c77Skevlo sc->sc_tx_low_queued++; 26790e584c77Skevlo else 26800e584c77Skevlo sc->sc_tx_normal_queued++; 26810e584c77Skevlo 26820e584c77Skevlo return (0); 26830e584c77Skevlo } 26840e584c77Skevlo 26850e584c77Skevlo usbd_status 26860e584c77Skevlo urtw_8225_usb_init(struct urtw_softc *sc) 26870e584c77Skevlo { 26880e584c77Skevlo uint8_t data; 26890e584c77Skevlo usbd_status error; 26900e584c77Skevlo 26910e584c77Skevlo urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 0); 26920e584c77Skevlo urtw_write8_m(sc, URTW_GPIO, 0); 26930e584c77Skevlo error = urtw_read8e(sc, 0x53, &data); 26940e584c77Skevlo if (error) 26950e584c77Skevlo goto fail; 26960e584c77Skevlo error = urtw_write8e(sc, 0x53, data | (1 << 7)); 26970e584c77Skevlo if (error) 26980e584c77Skevlo goto fail; 26990e584c77Skevlo urtw_write8_m(sc, URTW_RF_PINS_SELECT + 1, 4); 27000e584c77Skevlo urtw_write8_m(sc, URTW_GPIO, 0x20); 27010e584c77Skevlo urtw_write8_m(sc, URTW_GP_ENABLE, 0); 27020e584c77Skevlo 27030e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x80); 27040e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x80); 27050e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x80); 27060e584c77Skevlo 27076fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 500); 27080e584c77Skevlo fail: 27090e584c77Skevlo return (error); 27100e584c77Skevlo } 27110e584c77Skevlo 27120e584c77Skevlo usbd_status 27130e584c77Skevlo urtw_8185_rf_pins_enable(struct urtw_softc *sc) 27140e584c77Skevlo { 27150e584c77Skevlo usbd_status error = 0; 27160e584c77Skevlo 27170e584c77Skevlo urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1ff7); 27180e584c77Skevlo fail: 27190e584c77Skevlo return (error); 27200e584c77Skevlo } 27210e584c77Skevlo 27220e584c77Skevlo usbd_status 27230e584c77Skevlo urtw_8187_write_phy(struct urtw_softc *sc, uint8_t addr, uint32_t data) 27240e584c77Skevlo { 27250e584c77Skevlo uint32_t phyw; 27260e584c77Skevlo usbd_status error; 27270e584c77Skevlo 27280e584c77Skevlo phyw = ((data << 8) | (addr | 0x80)); 27290e584c77Skevlo urtw_write8_m(sc, 0x7f, ((phyw & 0xff000000) >> 24)); 27300e584c77Skevlo urtw_write8_m(sc, 0x7e, ((phyw & 0x00ff0000) >> 16)); 27310e584c77Skevlo urtw_write8_m(sc, 0x7d, ((phyw & 0x0000ff00) >> 8)); 27320e584c77Skevlo urtw_write8_m(sc, 0x7c, ((phyw & 0x000000ff))); 27333d4b849eSmartynas /* 27343d4b849eSmartynas * Delay removed from 8185 to 8187. 27353d4b849eSmartynas * usbd_delay_ms(sc->sc_udev, 1); 27363d4b849eSmartynas */ 27370e584c77Skevlo fail: 27380e584c77Skevlo return (error); 27390e584c77Skevlo } 27400e584c77Skevlo 27410e584c77Skevlo usbd_status 27420e584c77Skevlo urtw_8187_write_phy_ofdm_c(struct urtw_softc *sc, uint8_t addr, uint32_t data) 27430e584c77Skevlo { 27440e584c77Skevlo data = data & 0xff; 27450e584c77Skevlo return (urtw_8187_write_phy(sc, addr, data)); 27460e584c77Skevlo } 27470e584c77Skevlo 27480e584c77Skevlo usbd_status 27490e584c77Skevlo urtw_8187_write_phy_cck_c(struct urtw_softc *sc, uint8_t addr, uint32_t data) 27500e584c77Skevlo { 27510e584c77Skevlo data = data & 0xff; 27520e584c77Skevlo return (urtw_8187_write_phy(sc, addr, data | 0x10000)); 27530e584c77Skevlo } 27540e584c77Skevlo 27550e584c77Skevlo usbd_status 27560e584c77Skevlo urtw_8225_setgain(struct urtw_softc *sc, int16_t gain) 27570e584c77Skevlo { 27580e584c77Skevlo usbd_status error; 27590e584c77Skevlo 27600e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x0d, urtw_8225_gain[gain * 4]); 27610e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x1b, urtw_8225_gain[gain * 4 + 2]); 27620e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x1d, urtw_8225_gain[gain * 4 + 3]); 27630e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x23, urtw_8225_gain[gain * 4 + 1]); 27640e584c77Skevlo fail: 27650e584c77Skevlo return (error); 27660e584c77Skevlo } 27670e584c77Skevlo 27680e584c77Skevlo usbd_status 27690e584c77Skevlo urtw_8225_set_txpwrlvl(struct urtw_softc *sc, int chan) 27700e584c77Skevlo { 27710e584c77Skevlo int i, idx, set; 27720e584c77Skevlo uint8_t *cck_pwltable; 27730e584c77Skevlo uint8_t cck_pwrlvl_max, ofdm_pwrlvl_min, ofdm_pwrlvl_max; 27740e584c77Skevlo uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 27750e584c77Skevlo uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 27760e584c77Skevlo usbd_status error; 27770e584c77Skevlo 27780e584c77Skevlo cck_pwrlvl_max = 11; 27790e584c77Skevlo ofdm_pwrlvl_max = 25; /* 12 -> 25 */ 27800e584c77Skevlo ofdm_pwrlvl_min = 10; 27810e584c77Skevlo 27820e584c77Skevlo /* CCK power setting */ 27830e584c77Skevlo cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl; 27840e584c77Skevlo idx = cck_pwrlvl % 6; 27850e584c77Skevlo set = cck_pwrlvl / 6; 27860e584c77Skevlo cck_pwltable = (chan == 14) ? urtw_8225_txpwr_cck_ch14 : 27870e584c77Skevlo urtw_8225_txpwr_cck; 27880e584c77Skevlo 27890e584c77Skevlo urtw_write8_m(sc, URTW_TX_GAIN_CCK, 27900e584c77Skevlo urtw_8225_tx_gain_cck_ofdm[set] >> 1); 27910e584c77Skevlo for (i = 0; i < 8; i++) { 27920e584c77Skevlo urtw_8187_write_phy_cck(sc, 0x44 + i, 27930e584c77Skevlo cck_pwltable[idx * 8 + i]); 27940e584c77Skevlo } 27950e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 27960e584c77Skevlo 27970e584c77Skevlo /* OFDM power setting */ 27980e584c77Skevlo ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ? 27990e584c77Skevlo ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min; 28000e584c77Skevlo ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 28010e584c77Skevlo 28020e584c77Skevlo idx = ofdm_pwrlvl % 6; 28030e584c77Skevlo set = ofdm_pwrlvl / 6; 28040e584c77Skevlo 2805896bfc84Smartynas error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON); 28060e584c77Skevlo if (error) 28070e584c77Skevlo goto fail; 28080e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 2, 0x42); 28090e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 6, 0); 28100e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 8, 0); 28110e584c77Skevlo 28120e584c77Skevlo urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 28130e584c77Skevlo urtw_8225_tx_gain_cck_ofdm[set] >> 1); 28140e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x5, urtw_8225_txpwr_ofdm[idx]); 28150e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x7, urtw_8225_txpwr_ofdm[idx]); 28160e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 28170e584c77Skevlo fail: 28180e584c77Skevlo return (error); 28190e584c77Skevlo } 28200e584c77Skevlo 28210e584c77Skevlo usbd_status 28220e584c77Skevlo urtw_8185_tx_antenna(struct urtw_softc *sc, uint8_t ant) 28230e584c77Skevlo { 28240e584c77Skevlo usbd_status error; 28250e584c77Skevlo 28260e584c77Skevlo urtw_write8_m(sc, URTW_TX_ANTENNA, ant); 28270e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 28280e584c77Skevlo fail: 28290e584c77Skevlo return (error); 28300e584c77Skevlo } 28310e584c77Skevlo 28320e584c77Skevlo usbd_status 2833abcf0a78Smartynas urtw_8225_rf_init(struct urtw_rf *rf) 28340e584c77Skevlo { 2835abcf0a78Smartynas struct urtw_softc *sc = rf->rf_sc; 28360e584c77Skevlo int i; 28370e584c77Skevlo uint16_t data; 28380e584c77Skevlo usbd_status error; 28390e584c77Skevlo 2840896bfc84Smartynas error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON); 28410e584c77Skevlo if (error) 28420e584c77Skevlo goto fail; 28430e584c77Skevlo 28440e584c77Skevlo error = urtw_8225_usb_init(sc); 28450e584c77Skevlo if (error) 28460e584c77Skevlo goto fail; 28470e584c77Skevlo 28480e584c77Skevlo urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008); 2849ac7c6af9Smartynas urtw_read16_m(sc, URTW_8187_BRSR, &data); /* XXX ??? */ 2850ac7c6af9Smartynas urtw_write16_m(sc, URTW_8187_BRSR, 0xffff); 28510e584c77Skevlo urtw_write32_m(sc, URTW_RF_PARA, 0x100044); 28520e584c77Skevlo 28530e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 28540e584c77Skevlo if (error) 28550e584c77Skevlo goto fail; 28560e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, 0x44); 28570e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 28580e584c77Skevlo if (error) 28590e584c77Skevlo goto fail; 28600e584c77Skevlo 28610e584c77Skevlo error = urtw_8185_rf_pins_enable(sc); 28620e584c77Skevlo if (error) 28630e584c77Skevlo goto fail; 28643e951b55Smartynas 28656fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 500); 28660e584c77Skevlo 286716f0c350Skevlo for (i = 0; i < nitems(urtw_8225_rf_part1); i++) { 28680e584c77Skevlo urtw_8225_write(sc, urtw_8225_rf_part1[i].reg, 28690e584c77Skevlo urtw_8225_rf_part1[i].val); 28700e584c77Skevlo } 28716fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 50); 28720e584c77Skevlo urtw_8225_write(sc, 0x2, 0xc4d); 28730e584c77Skevlo usbd_delay_ms(sc->sc_udev, 200); 28740e584c77Skevlo urtw_8225_write(sc, 0x2, 0x44d); 28750e584c77Skevlo usbd_delay_ms(sc->sc_udev, 200); 28760e584c77Skevlo urtw_8225_write(sc, 0x0, 0x127); 28770e584c77Skevlo 2878217395cbSmartynas for (i = 0; i < nitems(urtw_8225_rxgain); i++) { 28790e584c77Skevlo urtw_8225_write(sc, 0x1, (uint8_t)(i + 1)); 28800e584c77Skevlo urtw_8225_write(sc, 0x2, urtw_8225_rxgain[i]); 28810e584c77Skevlo } 28820e584c77Skevlo 28830e584c77Skevlo urtw_8225_write(sc, 0x0, 0x27); 28840e584c77Skevlo urtw_8225_write(sc, 0x0, 0x22f); 28850e584c77Skevlo 2886217395cbSmartynas for (i = 0; i < nitems(urtw_8225_agc); i++) { 28870e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]); 28880e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80); 28890e584c77Skevlo } 28900e584c77Skevlo 289116f0c350Skevlo for (i = 0; i < nitems(urtw_8225_rf_part2); i++) { 28920e584c77Skevlo urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg, 28930e584c77Skevlo urtw_8225_rf_part2[i].val); 28940e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 28950e584c77Skevlo } 28960e584c77Skevlo 28970e584c77Skevlo error = urtw_8225_setgain(sc, 4); 28980e584c77Skevlo if (error) 28990e584c77Skevlo goto fail; 29000e584c77Skevlo 290116f0c350Skevlo for (i = 0; i < nitems(urtw_8225_rf_part3); i++) { 29020e584c77Skevlo urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg, 29030e584c77Skevlo urtw_8225_rf_part3[i].val); 29040e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 29050e584c77Skevlo } 29060e584c77Skevlo 29070e584c77Skevlo urtw_write8_m(sc, 0x5b, 0x0d); 29080e584c77Skevlo 29090e584c77Skevlo error = urtw_8225_set_txpwrlvl(sc, 1); 29100e584c77Skevlo if (error) 29110e584c77Skevlo goto fail; 29120e584c77Skevlo 29130e584c77Skevlo urtw_8187_write_phy_cck(sc, 0x10, 0x9b); 29140e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 29150e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x26, 0x90); 29160e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 29170e584c77Skevlo 29180e584c77Skevlo /* TX ant A, 0x0 for B */ 29190e584c77Skevlo error = urtw_8185_tx_antenna(sc, 0x3); 29200e584c77Skevlo if (error) 29210e584c77Skevlo goto fail; 29220e584c77Skevlo urtw_write32_m(sc, 0x94, 0x3dc00002); 29230e584c77Skevlo 2924abcf0a78Smartynas error = urtw_8225_rf_set_chan(rf, 1); 29250e584c77Skevlo fail: 29260e584c77Skevlo return (error); 29270e584c77Skevlo } 29280e584c77Skevlo 29290e584c77Skevlo usbd_status 2930abcf0a78Smartynas urtw_8225_rf_set_chan(struct urtw_rf *rf, int chan) 29310e584c77Skevlo { 2932abcf0a78Smartynas struct urtw_softc *sc = rf->rf_sc; 29330e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 29340e584c77Skevlo struct ieee80211_channel *c = ic->ic_ibss_chan; 29350e584c77Skevlo usbd_status error; 29360e584c77Skevlo 29370e584c77Skevlo error = urtw_8225_set_txpwrlvl(sc, chan); 29380e584c77Skevlo if (error) 29390e584c77Skevlo goto fail; 29400e584c77Skevlo urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]); 29410e584c77Skevlo usbd_delay_ms(sc->sc_udev, 10); 29420e584c77Skevlo 29430e584c77Skevlo urtw_write8_m(sc, URTW_SIFS, 0x22); 29440e584c77Skevlo 29450e584c77Skevlo if (sc->sc_state == IEEE80211_S_ASSOC && 29460e584c77Skevlo ic->ic_flags & IEEE80211_F_SHSLOT) 29478443256dSkevlo urtw_write8_m(sc, URTW_SLOT, IEEE80211_DUR_DS_SHSLOT); 29480e584c77Skevlo else 29498443256dSkevlo urtw_write8_m(sc, URTW_SLOT, IEEE80211_DUR_DS_SLOT); 29500e584c77Skevlo 29510e584c77Skevlo if (IEEE80211_IS_CHAN_G(c)) { 29520e584c77Skevlo urtw_write8_m(sc, URTW_DIFS, 0x14); 2953ac7c6af9Smartynas urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x14); 29540e584c77Skevlo urtw_write8_m(sc, URTW_CW_VAL, 0x73); 29550e584c77Skevlo } else { 29560e584c77Skevlo urtw_write8_m(sc, URTW_DIFS, 0x24); 2957ac7c6af9Smartynas urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x24); 29580e584c77Skevlo urtw_write8_m(sc, URTW_CW_VAL, 0xa5); 29590e584c77Skevlo } 29600e584c77Skevlo 29610e584c77Skevlo fail: 29620e584c77Skevlo return (error); 29630e584c77Skevlo } 29640e584c77Skevlo 29650e584c77Skevlo usbd_status 2966abcf0a78Smartynas urtw_8225_rf_set_sens(struct urtw_rf *rf) 29670e584c77Skevlo { 2968abcf0a78Smartynas struct urtw_softc *sc = rf->rf_sc; 29690e584c77Skevlo usbd_status error; 29700e584c77Skevlo 297196134ebdSbrad if (rf->sens > 6) 2972217395cbSmartynas return (-1); 29730e584c77Skevlo 2974abcf0a78Smartynas if (rf->sens > 4) 29750e584c77Skevlo urtw_8225_write(sc, 0x0c, 0x850); 29760e584c77Skevlo else 29770e584c77Skevlo urtw_8225_write(sc, 0x0c, 0x50); 29780e584c77Skevlo 2979abcf0a78Smartynas rf->sens = 6 - rf->sens; 2980abcf0a78Smartynas error = urtw_8225_setgain(sc, rf->sens); 29810e584c77Skevlo if (error) 29820e584c77Skevlo goto fail; 29830e584c77Skevlo 2984abcf0a78Smartynas urtw_8187_write_phy_cck(sc, 0x41, urtw_8225_threshold[rf->sens]); 29850e584c77Skevlo 29860e584c77Skevlo fail: 29870e584c77Skevlo return (error); 29880e584c77Skevlo } 29890e584c77Skevlo 29900e584c77Skevlo void 29910e584c77Skevlo urtw_stop(struct ifnet *ifp, int disable) 29920e584c77Skevlo { 29930e584c77Skevlo struct urtw_softc *sc = ifp->if_softc; 29943d4b849eSmartynas struct ieee80211com *ic = &sc->sc_ic; 29953d4b849eSmartynas uint8_t data; 29963d4b849eSmartynas usbd_status error; 29970e584c77Skevlo 2998de6cd8fbSdlg ifp->if_flags &= ~IFF_RUNNING; 2999de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 30000e584c77Skevlo 30013d4b849eSmartynas ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 30023d4b849eSmartynas 30030e584c77Skevlo timeout_del(&sc->scan_to); 30040e584c77Skevlo timeout_del(&sc->sc_led_ch); 30050e584c77Skevlo 30063d4b849eSmartynas urtw_intr_disable(sc); 30073d4b849eSmartynas urtw_read8_m(sc, URTW_CMD, &data); 30083d4b849eSmartynas data &= ~URTW_CMD_TX_ENABLE; 30093d4b849eSmartynas data &= ~URTW_CMD_RX_ENABLE; 30103d4b849eSmartynas urtw_write8_m(sc, URTW_CMD, data); 30113d4b849eSmartynas 30120e584c77Skevlo if (sc->sc_rxpipe != NULL) 30130e584c77Skevlo usbd_abort_pipe(sc->sc_rxpipe); 30140e584c77Skevlo if (sc->sc_txpipe_low != NULL) 30150e584c77Skevlo usbd_abort_pipe(sc->sc_txpipe_low); 30160e584c77Skevlo if (sc->sc_txpipe_normal != NULL) 30170e584c77Skevlo usbd_abort_pipe(sc->sc_txpipe_normal); 30183d4b849eSmartynas 30193d4b849eSmartynas fail: 30203d4b849eSmartynas return; 30210e584c77Skevlo } 30220e584c77Skevlo 30230e584c77Skevlo int 30240e584c77Skevlo urtw_isbmode(uint16_t rate) 30250e584c77Skevlo { 30260e584c77Skevlo rate = urtw_rtl2rate(rate); 30270e584c77Skevlo 3028217395cbSmartynas return (((rate <= 22 && rate != 12 && rate != 18) || 3029217395cbSmartynas rate == 44) ? (1) : (0)); 30300e584c77Skevlo } 30310e584c77Skevlo 30320e584c77Skevlo void 3033ab0b1be7Smglocker urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 30340e584c77Skevlo { 303561a07a57Smartynas struct urtw_rx_data *data = priv; 30360e584c77Skevlo struct urtw_softc *sc = data->sc; 30370e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 30380e584c77Skevlo struct ifnet *ifp = &ic->ic_if; 30390e584c77Skevlo struct ieee80211_frame *wh; 30400e584c77Skevlo struct ieee80211_node *ni; 30410e584c77Skevlo struct ieee80211_rxinfo rxi; 30420e584c77Skevlo struct mbuf *m, *mnew; 30430e584c77Skevlo uint8_t *desc, quality, rate; 30440e584c77Skevlo int actlen, flen, len, nf, rssi, s; 30450e584c77Skevlo 30460e584c77Skevlo if (status != USBD_NORMAL_COMPLETION) { 30470e584c77Skevlo if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 30480e584c77Skevlo return; 30490e584c77Skevlo 30500e584c77Skevlo if (status == USBD_STALLED) 30510e584c77Skevlo usbd_clear_endpoint_stall_async(sc->sc_rxpipe); 30520e584c77Skevlo ifp->if_ierrors++; 30530e584c77Skevlo goto skip; 30540e584c77Skevlo } 30550e584c77Skevlo 30560e584c77Skevlo usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL); 30570e584c77Skevlo if (actlen < URTW_MIN_RXBUFSZ) { 30580e584c77Skevlo ifp->if_ierrors++; 30590e584c77Skevlo goto skip; 30600e584c77Skevlo } 30610e584c77Skevlo 30623d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) 30630e584c77Skevlo /* 4 dword and 4 byte CRC */ 30640e584c77Skevlo len = actlen - (4 * 4); 30653d4b849eSmartynas else 30663d4b849eSmartynas /* 5 dword and 4 byte CRC */ 30673d4b849eSmartynas len = actlen - (4 * 5); 30683d4b849eSmartynas 30690e584c77Skevlo desc = data->buf + len; 30700e584c77Skevlo flen = ((desc[1] & 0x0f) << 8) + (desc[0] & 0xff); 30710e584c77Skevlo if (flen > actlen) { 30720e584c77Skevlo ifp->if_ierrors++; 30730e584c77Skevlo goto skip; 30740e584c77Skevlo } 30750e584c77Skevlo 30760e584c77Skevlo rate = (desc[2] & 0xf0) >> 4; 30773d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187) { 30780e584c77Skevlo quality = desc[4] & 0xff; 30790e584c77Skevlo rssi = (desc[6] & 0xfe) >> 1; 30803d4b849eSmartynas 30813d4b849eSmartynas /* XXX correct? */ 30820e584c77Skevlo if (!urtw_isbmode(rate)) { 30830e584c77Skevlo rssi = (rssi > 90) ? 90 : ((rssi < 25) ? 25 : rssi); 30840e584c77Skevlo rssi = ((90 - rssi) * 100) / 65; 30850e584c77Skevlo } else { 30860e584c77Skevlo rssi = (rssi > 90) ? 95 : ((rssi < 30) ? 30 : rssi); 30870e584c77Skevlo rssi = ((95 - rssi) * 100) / 65; 30880e584c77Skevlo } 30893d4b849eSmartynas } else { 30903d4b849eSmartynas quality = desc[12]; 30913d4b849eSmartynas rssi = 14 - desc[14] / 2; 30923d4b849eSmartynas } 30930e584c77Skevlo 30940e584c77Skevlo MGETHDR(mnew, M_DONTWAIT, MT_DATA); 30950e584c77Skevlo if (mnew == NULL) { 30960e584c77Skevlo printf("%s: could not allocate rx mbuf\n", 30970e584c77Skevlo sc->sc_dev.dv_xname); 30980e584c77Skevlo ifp->if_ierrors++; 30990e584c77Skevlo goto skip; 31000e584c77Skevlo } 31010e584c77Skevlo MCLGET(mnew, M_DONTWAIT); 31020e584c77Skevlo if (!(mnew->m_flags & M_EXT)) { 31030e584c77Skevlo printf("%s: could not allocate rx mbuf cluster\n", 31040e584c77Skevlo sc->sc_dev.dv_xname); 31050e584c77Skevlo m_freem(mnew); 31060e584c77Skevlo ifp->if_ierrors++; 31070e584c77Skevlo goto skip; 31080e584c77Skevlo } 31090e584c77Skevlo 31100e584c77Skevlo m = data->m; 31110e584c77Skevlo data->m = mnew; 31120e584c77Skevlo data->buf = mtod(mnew, uint8_t *); 31130e584c77Skevlo 31140e584c77Skevlo /* finalize mbuf */ 31150e584c77Skevlo m->m_pkthdr.len = m->m_len = flen - 4; 31160e584c77Skevlo 31170e584c77Skevlo s = splnet(); 31180e584c77Skevlo 31190e584c77Skevlo #if NBPFILTER > 0 31200e584c77Skevlo if (sc->sc_drvbpf != NULL) { 31210e584c77Skevlo struct mbuf mb; 31220e584c77Skevlo struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap; 31230e584c77Skevlo 31240e584c77Skevlo /* XXX Are variables correct? */ 312563be937aSdamien tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq); 312663be937aSdamien tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags); 31270e584c77Skevlo tap->wr_dbm_antsignal = (int8_t)rssi; 31280e584c77Skevlo 31290e584c77Skevlo mb.m_data = (caddr_t)tap; 31300e584c77Skevlo mb.m_len = sc->sc_rxtap_len; 31310e584c77Skevlo mb.m_next = m; 31320e584c77Skevlo mb.m_nextpkt = NULL; 31330e584c77Skevlo mb.m_type = 0; 31340e584c77Skevlo mb.m_flags = 0; 31350e584c77Skevlo bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN); 31360e584c77Skevlo } 31370e584c77Skevlo #endif 31380e584c77Skevlo wh = mtod(m, struct ieee80211_frame *); 31390e584c77Skevlo if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) 31400e584c77Skevlo sc->sc_currate = (rate > 0) ? rate : sc->sc_currate; 31410e584c77Skevlo ni = ieee80211_find_rxnode(ic, wh); 31420e584c77Skevlo 31430e584c77Skevlo /* XXX correct? */ 31443d4b849eSmartynas if (!urtw_isbmode(rate)) { 31453d4b849eSmartynas if (quality > 127) 31463d4b849eSmartynas quality = 0; 31473d4b849eSmartynas else if (quality < 27) 31483d4b849eSmartynas quality = 100; 31493d4b849eSmartynas else 31503d4b849eSmartynas quality = 127 - quality; 31513d4b849eSmartynas } else 31523d4b849eSmartynas quality = (quality > 64) ? 0 : ((64 - quality) * 100) / 64; 31533d4b849eSmartynas 31543d4b849eSmartynas nf = quality; 31550e584c77Skevlo 31560e584c77Skevlo /* send the frame to the 802.11 layer */ 315752a13037Sstsp memset(&rxi, 0, sizeof(rxi)); 31580e584c77Skevlo rxi.rxi_rssi = rssi; 31590e584c77Skevlo ieee80211_input(ifp, m, ni, &rxi); 31600e584c77Skevlo 31610e584c77Skevlo /* node is no longer needed */ 31620e584c77Skevlo ieee80211_release_node(ic, ni); 31630e584c77Skevlo 31640e584c77Skevlo splx(s); 31650e584c77Skevlo 31660e584c77Skevlo skip: /* setup a new transfer */ 31670e584c77Skevlo usbd_setup_xfer(xfer, sc->sc_rxpipe, data, data->buf, MCLBYTES, 31680e584c77Skevlo USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, urtw_rxeof); 31690e584c77Skevlo (void)usbd_transfer(xfer); 31700e584c77Skevlo } 31710e584c77Skevlo 31720e584c77Skevlo usbd_status 31730e584c77Skevlo urtw_8225v2_setgain(struct urtw_softc *sc, int16_t gain) 31740e584c77Skevlo { 31750e584c77Skevlo uint8_t *gainp; 31760e584c77Skevlo usbd_status error; 31770e584c77Skevlo 31780e584c77Skevlo /* XXX for A? */ 31790e584c77Skevlo gainp = urtw_8225v2_gain_bg; 31800e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x0d, gainp[gain * 3]); 31810e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 31820e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x1b, gainp[gain * 3 + 1]); 31830e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 31840e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x1d, gainp[gain * 3 + 2]); 31850e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 31860e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x21, 0x17); 31870e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 31880e584c77Skevlo fail: 31890e584c77Skevlo return (error); 31900e584c77Skevlo } 31910e584c77Skevlo 31920e584c77Skevlo usbd_status 31930e584c77Skevlo urtw_8225v2_set_txpwrlvl(struct urtw_softc *sc, int chan) 31940e584c77Skevlo { 31950e584c77Skevlo int i; 31960e584c77Skevlo uint8_t *cck_pwrtable; 31970e584c77Skevlo uint8_t cck_pwrlvl_max = 15, ofdm_pwrlvl_max = 25, ofdm_pwrlvl_min = 10; 31980e584c77Skevlo uint8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 31990e584c77Skevlo uint8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 32000e584c77Skevlo usbd_status error; 32010e584c77Skevlo 32020e584c77Skevlo /* CCK power setting */ 32030e584c77Skevlo cck_pwrlvl = (cck_pwrlvl > cck_pwrlvl_max) ? cck_pwrlvl_max : cck_pwrlvl; 32040e584c77Skevlo cck_pwrlvl += sc->sc_txpwr_cck_base; 32050e584c77Skevlo cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl; 32060e584c77Skevlo cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 : 32070e584c77Skevlo urtw_8225v2_txpwr_cck; 32080e584c77Skevlo 32090e584c77Skevlo for (i = 0; i < 8; i++) { 32100e584c77Skevlo urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]); 32110e584c77Skevlo } 32120e584c77Skevlo urtw_write8_m(sc, URTW_TX_GAIN_CCK, 32130e584c77Skevlo urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl]); 32140e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 32150e584c77Skevlo 32160e584c77Skevlo /* OFDM power setting */ 32170e584c77Skevlo ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ? 32180e584c77Skevlo ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min; 32190e584c77Skevlo ofdm_pwrlvl += sc->sc_txpwr_ofdm_base; 32200e584c77Skevlo ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 32210e584c77Skevlo 3222896bfc84Smartynas error = urtw_8185_set_anaparam2(sc, URTW_8187_8225_ANAPARAM2_ON); 32230e584c77Skevlo if (error) 32240e584c77Skevlo goto fail; 32250e584c77Skevlo 32260e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 2, 0x42); 32270e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 5, 0x0); 32280e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 6, 0x40); 32290e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 7, 0x0); 32300e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 8, 0x40); 32310e584c77Skevlo 32320e584c77Skevlo urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 32330e584c77Skevlo urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl]); 32340e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 32350e584c77Skevlo fail: 32360e584c77Skevlo return (error); 32370e584c77Skevlo } 32380e584c77Skevlo 32390e584c77Skevlo usbd_status 3240abcf0a78Smartynas urtw_8225v2_rf_init(struct urtw_rf *rf) 32410e584c77Skevlo { 3242abcf0a78Smartynas struct urtw_softc *sc = rf->rf_sc; 32430e584c77Skevlo int i; 32440e584c77Skevlo uint16_t data; 32450e584c77Skevlo uint32_t data32; 32460e584c77Skevlo usbd_status error; 32470e584c77Skevlo 3248896bfc84Smartynas error = urtw_8180_set_anaparam(sc, URTW_8187_8225_ANAPARAM_ON); 32490e584c77Skevlo if (error) 32500e584c77Skevlo goto fail; 32510e584c77Skevlo 32520e584c77Skevlo error = urtw_8225_usb_init(sc); 32530e584c77Skevlo if (error) 32540e584c77Skevlo goto fail; 32550e584c77Skevlo 32560e584c77Skevlo urtw_write32_m(sc, URTW_RF_TIMING, 0x000a8008); 3257ac7c6af9Smartynas urtw_read16_m(sc, URTW_8187_BRSR, &data); /* XXX ??? */ 3258ac7c6af9Smartynas urtw_write16_m(sc, URTW_8187_BRSR, 0xffff); 32590e584c77Skevlo urtw_write32_m(sc, URTW_RF_PARA, 0x100044); 32600e584c77Skevlo 32610e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 32620e584c77Skevlo if (error) 32630e584c77Skevlo goto fail; 32640e584c77Skevlo urtw_write8_m(sc, URTW_CONFIG3, 0x44); 32650e584c77Skevlo error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 32660e584c77Skevlo if (error) 32670e584c77Skevlo goto fail; 32680e584c77Skevlo 32690e584c77Skevlo error = urtw_8185_rf_pins_enable(sc); 32700e584c77Skevlo if (error) 32710e584c77Skevlo goto fail; 32720e584c77Skevlo 32730e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1000); 32740e584c77Skevlo 327516f0c350Skevlo for (i = 0; i < nitems(urtw_8225v2_rf_part1); i++) { 32760e584c77Skevlo urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg, 32770e584c77Skevlo urtw_8225v2_rf_part1[i].val); 32780e584c77Skevlo usbd_delay_ms(sc->sc_udev, 1); 32790e584c77Skevlo } 32806fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 50); 32810e584c77Skevlo 32820e584c77Skevlo urtw_8225_write(sc, 0x0, 0x1b7); 32830e584c77Skevlo 3284217395cbSmartynas for (i = 0; i < nitems(urtw_8225v2_rxgain); i++) { 32850e584c77Skevlo urtw_8225_write(sc, 0x1, (uint8_t)(i + 1)); 32860e584c77Skevlo urtw_8225_write(sc, 0x2, urtw_8225v2_rxgain[i]); 32870e584c77Skevlo } 32880e584c77Skevlo 32890e584c77Skevlo urtw_8225_write(sc, 0x3, 0x2); 32900e584c77Skevlo urtw_8225_write(sc, 0x5, 0x4); 32910e584c77Skevlo urtw_8225_write(sc, 0x0, 0xb7); 32920e584c77Skevlo urtw_8225_write(sc, 0x2, 0xc4d); 32936fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 32940e584c77Skevlo urtw_8225_write(sc, 0x2, 0x44d); 32956fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 32960e584c77Skevlo 32970e584c77Skevlo error = urtw_8225_read(sc, 0x6, &data32); 32980e584c77Skevlo if (error != 0) 32990e584c77Skevlo goto fail; 33000e584c77Skevlo if (data32 != 0xe6) 33010e584c77Skevlo printf("%s: expect 0xe6!! (0x%x)\n", sc->sc_dev.dv_xname, 33020e584c77Skevlo data32); 33030e584c77Skevlo if (!(data32 & 0x80)) { 33040e584c77Skevlo urtw_8225_write(sc, 0x02, 0x0c4d); 33050e584c77Skevlo usbd_delay_ms(sc->sc_udev, 200); 33060e584c77Skevlo urtw_8225_write(sc, 0x02, 0x044d); 33070e584c77Skevlo usbd_delay_ms(sc->sc_udev, 100); 33080e584c77Skevlo error = urtw_8225_read(sc, 0x6, &data32); 33090e584c77Skevlo if (error != 0) 33100e584c77Skevlo goto fail; 33110e584c77Skevlo if (!(data32 & 0x80)) 33120e584c77Skevlo printf("%s: RF calibration failed\n", 33130e584c77Skevlo sc->sc_dev.dv_xname); 33140e584c77Skevlo } 33156fb8d30bSkevlo usbd_delay_ms(sc->sc_udev, 100); 33160e584c77Skevlo 33170e584c77Skevlo urtw_8225_write(sc, 0x0, 0x2bf); 3318217395cbSmartynas for (i = 0; i < nitems(urtw_8225_agc); i++) { 33190e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0xb, urtw_8225_agc[i]); 33200e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80); 33210e584c77Skevlo } 33220e584c77Skevlo 332316f0c350Skevlo for (i = 0; i < nitems(urtw_8225v2_rf_part2); i++) { 33240e584c77Skevlo urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg, 33250e584c77Skevlo urtw_8225v2_rf_part2[i].val); 33260e584c77Skevlo } 33270e584c77Skevlo 33280e584c77Skevlo error = urtw_8225v2_setgain(sc, 4); 33290e584c77Skevlo if (error) 33300e584c77Skevlo goto fail; 33310e584c77Skevlo 333216f0c350Skevlo for (i = 0; i < nitems(urtw_8225v2_rf_part3); i++) { 33330e584c77Skevlo urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg, 33340e584c77Skevlo urtw_8225v2_rf_part3[i].val); 33350e584c77Skevlo } 33360e584c77Skevlo 33370e584c77Skevlo urtw_write8_m(sc, 0x5b, 0x0d); 33380e584c77Skevlo 33390e584c77Skevlo error = urtw_8225v2_set_txpwrlvl(sc, 1); 33400e584c77Skevlo if (error) 33410e584c77Skevlo goto fail; 33420e584c77Skevlo 33430e584c77Skevlo urtw_8187_write_phy_cck(sc, 0x10, 0x9b); 33440e584c77Skevlo urtw_8187_write_phy_ofdm(sc, 0x26, 0x90); 33450e584c77Skevlo 33460e584c77Skevlo /* TX ant A, 0x0 for B */ 33470e584c77Skevlo error = urtw_8185_tx_antenna(sc, 0x3); 33480e584c77Skevlo if (error) 33490e584c77Skevlo goto fail; 33500e584c77Skevlo urtw_write32_m(sc, 0x94, 0x3dc00002); 33510e584c77Skevlo 3352abcf0a78Smartynas error = urtw_8225_rf_set_chan(rf, 1); 33530e584c77Skevlo fail: 33540e584c77Skevlo return (error); 33550e584c77Skevlo } 33560e584c77Skevlo 33570e584c77Skevlo usbd_status 3358abcf0a78Smartynas urtw_8225v2_rf_set_chan(struct urtw_rf *rf, int chan) 33590e584c77Skevlo { 3360abcf0a78Smartynas struct urtw_softc *sc = rf->rf_sc; 33610e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 33620e584c77Skevlo struct ieee80211_channel *c = ic->ic_ibss_chan; 33630e584c77Skevlo usbd_status error; 33640e584c77Skevlo 33650e584c77Skevlo error = urtw_8225v2_set_txpwrlvl(sc, chan); 33660e584c77Skevlo if (error) 33670e584c77Skevlo goto fail; 33680e584c77Skevlo 33690e584c77Skevlo urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]); 33700e584c77Skevlo usbd_delay_ms(sc->sc_udev, 10); 33710e584c77Skevlo 33720e584c77Skevlo urtw_write8_m(sc, URTW_SIFS, 0x22); 33730e584c77Skevlo 33740e584c77Skevlo if(sc->sc_state == IEEE80211_S_ASSOC && 33750e584c77Skevlo ic->ic_flags & IEEE80211_F_SHSLOT) 33768443256dSkevlo urtw_write8_m(sc, URTW_SLOT, IEEE80211_DUR_DS_SHSLOT); 33770e584c77Skevlo else 33788443256dSkevlo urtw_write8_m(sc, URTW_SLOT, IEEE80211_DUR_DS_SLOT); 33790e584c77Skevlo 33800e584c77Skevlo if (IEEE80211_IS_CHAN_G(c)) { 33810e584c77Skevlo urtw_write8_m(sc, URTW_DIFS, 0x14); 3382ac7c6af9Smartynas urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x14); 33830e584c77Skevlo urtw_write8_m(sc, URTW_CW_VAL, 0x73); 33840e584c77Skevlo } else { 33850e584c77Skevlo urtw_write8_m(sc, URTW_DIFS, 0x24); 3386ac7c6af9Smartynas urtw_write8_m(sc, URTW_8187_EIFS, 0x5b - 0x24); 33870e584c77Skevlo urtw_write8_m(sc, URTW_CW_VAL, 0xa5); 33880e584c77Skevlo } 33890e584c77Skevlo 33900e584c77Skevlo fail: 33910e584c77Skevlo return (error); 33920e584c77Skevlo } 33930e584c77Skevlo 33940e584c77Skevlo void 33950e584c77Skevlo urtw_set_chan(struct urtw_softc *sc, struct ieee80211_channel *c) 33960e584c77Skevlo { 3397abcf0a78Smartynas struct urtw_rf *rf = &sc->sc_rf; 33980e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 33990e584c77Skevlo usbd_status error = 0; 34000e584c77Skevlo uint32_t data; 34010e584c77Skevlo u_int chan; 34020e584c77Skevlo 34030e584c77Skevlo chan = ieee80211_chan2ieee(ic, c); 34040e584c77Skevlo if (chan == 0 || chan == IEEE80211_CHAN_ANY) 34050e584c77Skevlo return; 34060e584c77Skevlo /* 3407896bfc84Smartynas * During changing the channel we need to temporary disable 34080e584c77Skevlo * TX. 34090e584c77Skevlo */ 34100e584c77Skevlo urtw_read32_m(sc, URTW_TX_CONF, &data); 34110e584c77Skevlo data &= ~URTW_TX_LOOPBACK_MASK; 34120e584c77Skevlo urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_MAC); 3413abcf0a78Smartynas error = rf->set_chan(rf, chan); 34140e584c77Skevlo if (error != 0) { 34150e584c77Skevlo printf("%s could not change the channel\n", 34160e584c77Skevlo sc->sc_dev.dv_xname); 34170e584c77Skevlo return; 34180e584c77Skevlo } 34190e584c77Skevlo usbd_delay_ms(sc->sc_udev, 10); 34200e584c77Skevlo urtw_write32_m(sc, URTW_TX_CONF, data | URTW_TX_LOOPBACK_NONE); 34210e584c77Skevlo 34220e584c77Skevlo fail: return; 34230e584c77Skevlo 34240e584c77Skevlo } 34250e584c77Skevlo 34260e584c77Skevlo void 34270e584c77Skevlo urtw_next_scan(void *arg) 34280e584c77Skevlo { 34290e584c77Skevlo struct urtw_softc *sc = arg; 34300e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 34310e584c77Skevlo struct ifnet *ifp = &ic->ic_if; 34320e584c77Skevlo 343312136ef5Sjakemsr if (usbd_is_dying(sc->sc_udev)) 343412136ef5Sjakemsr return; 343512136ef5Sjakemsr 343612136ef5Sjakemsr usbd_ref_incr(sc->sc_udev); 343712136ef5Sjakemsr 34380e584c77Skevlo if (ic->ic_state == IEEE80211_S_SCAN) 34390e584c77Skevlo ieee80211_next_scan(ifp); 344012136ef5Sjakemsr 344112136ef5Sjakemsr usbd_ref_decr(sc->sc_udev); 34420e584c77Skevlo } 34430e584c77Skevlo 34440e584c77Skevlo void 34450e584c77Skevlo urtw_task(void *arg) 34460e584c77Skevlo { 34470e584c77Skevlo struct urtw_softc *sc = arg; 34480e584c77Skevlo struct ieee80211com *ic = &sc->sc_ic; 34490e584c77Skevlo struct ieee80211_node *ni; 34500e584c77Skevlo enum ieee80211_state ostate; 34510e584c77Skevlo usbd_status error = 0; 34520e584c77Skevlo 345312136ef5Sjakemsr if (usbd_is_dying(sc->sc_udev)) 345412136ef5Sjakemsr return; 345512136ef5Sjakemsr 34560e584c77Skevlo ostate = ic->ic_state; 34570e584c77Skevlo 34580e584c77Skevlo switch (sc->sc_state) { 34590e584c77Skevlo case IEEE80211_S_INIT: 34600e584c77Skevlo if (ostate == IEEE80211_S_RUN) { 34610e584c77Skevlo /* turn link LED off */ 34620e584c77Skevlo (void)urtw_led_off(sc, URTW_LED_GPIO); 34630e584c77Skevlo } 34640e584c77Skevlo break; 34650e584c77Skevlo 34660e584c77Skevlo case IEEE80211_S_SCAN: 34670e584c77Skevlo urtw_set_chan(sc, ic->ic_bss->ni_chan); 346812136ef5Sjakemsr if (!usbd_is_dying(sc->sc_udev)) 34696fe37b1cSblambert timeout_add_msec(&sc->scan_to, 200); 34700e584c77Skevlo break; 34710e584c77Skevlo 34720e584c77Skevlo case IEEE80211_S_AUTH: 34730e584c77Skevlo case IEEE80211_S_ASSOC: 34740e584c77Skevlo urtw_set_chan(sc, ic->ic_bss->ni_chan); 34750e584c77Skevlo break; 34760e584c77Skevlo 34770e584c77Skevlo case IEEE80211_S_RUN: 34780e584c77Skevlo ni = ic->ic_bss; 34790e584c77Skevlo 34800e584c77Skevlo /* setting bssid. */ 348149b282e9Smiod error = urtw_set_bssid(sc, ni->ni_bssid); 348249b282e9Smiod if (error != 0) 348349b282e9Smiod goto fail; 34840e584c77Skevlo urtw_update_msr(sc); 34850e584c77Skevlo /* XXX maybe the below would be incorrect. */ 34860e584c77Skevlo urtw_write16_m(sc, URTW_ATIM_WND, 2); 34870e584c77Skevlo urtw_write16_m(sc, URTW_ATIM_TR_ITV, 100); 34880e584c77Skevlo urtw_write16_m(sc, URTW_BEACON_INTERVAL, 0x64); 34893d4b849eSmartynas urtw_write16_m(sc, URTW_BEACON_INTERVAL_TIME, 0x3ff); 34900e584c77Skevlo error = urtw_led_ctl(sc, URTW_LED_CTL_LINK); 34910e584c77Skevlo if (error != 0) 34920e584c77Skevlo printf("%s: could not control LED (%d)\n", 34930e584c77Skevlo sc->sc_dev.dv_xname, error); 34940e584c77Skevlo break; 34950e584c77Skevlo } 34960e584c77Skevlo 34970e584c77Skevlo sc->sc_newstate(ic, sc->sc_state, sc->sc_arg); 34980e584c77Skevlo 34990e584c77Skevlo fail: 35000e584c77Skevlo if (error != 0) 3501*54fbbda3Sjsg DPRINTF(("%s: error processing RUN state.", 35020e584c77Skevlo sc->sc_dev.dv_xname)); 35030e584c77Skevlo } 3504d63cd6d5Smartynas 35053d4b849eSmartynas usbd_status 35063d4b849eSmartynas urtw_8187b_update_wmm(struct urtw_softc *sc) 35073d4b849eSmartynas { 35083d4b849eSmartynas struct ieee80211com *ic = &sc->sc_ic; 35093d4b849eSmartynas struct ieee80211_channel *c = ic->ic_ibss_chan; 35103d4b849eSmartynas uint32_t data; 35113d4b849eSmartynas uint8_t aifs, sifs, slot, ecwmin, ecwmax; 35123d4b849eSmartynas usbd_status error; 35133d4b849eSmartynas 35143d4b849eSmartynas sifs = 0xa; 35153d4b849eSmartynas if (IEEE80211_IS_CHAN_G(c)) 35163d4b849eSmartynas slot = 0x9; 35173d4b849eSmartynas else 35183d4b849eSmartynas slot = 0x14; 35193d4b849eSmartynas 35203d4b849eSmartynas aifs = (2 * slot) + sifs; 35213d4b849eSmartynas ecwmin = 3; 35223d4b849eSmartynas ecwmax = 7; 35233d4b849eSmartynas 35243d4b849eSmartynas data = ((uint32_t)aifs << 0) | /* AIFS, offset 0 */ 35253d4b849eSmartynas ((uint32_t)ecwmin << 8) | /* ECW minimum, offset 8 */ 35263d4b849eSmartynas ((uint32_t)ecwmax << 12); /* ECW maximum, offset 16 */ 35273d4b849eSmartynas 35283d4b849eSmartynas urtw_write32_m(sc, URTW_AC_VO, data); 35293d4b849eSmartynas urtw_write32_m(sc, URTW_AC_VI, data); 35303d4b849eSmartynas urtw_write32_m(sc, URTW_AC_BE, data); 35313d4b849eSmartynas urtw_write32_m(sc, URTW_AC_BK, data); 35323d4b849eSmartynas 35333d4b849eSmartynas fail: 35343d4b849eSmartynas return (error); 35353d4b849eSmartynas } 35363d4b849eSmartynas 35373d4b849eSmartynas usbd_status 35383d4b849eSmartynas urtw_8187b_reset(struct urtw_softc *sc) 35393d4b849eSmartynas { 35403d4b849eSmartynas uint8_t data; 35413d4b849eSmartynas usbd_status error; 35423d4b849eSmartynas 35433d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 35443d4b849eSmartynas if (error) 35453d4b849eSmartynas goto fail; 35463d4b849eSmartynas 35473d4b849eSmartynas urtw_read8_m(sc, URTW_CONFIG3, &data); 35483d4b849eSmartynas urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE | 35493d4b849eSmartynas URTW_CONFIG3_GNT_SELECT); 35503d4b849eSmartynas 35513d4b849eSmartynas urtw_write32_m(sc, URTW_ANAPARAM2, URTW_8187B_8225_ANAPARAM2_ON); 35523d4b849eSmartynas urtw_write32_m(sc, URTW_ANAPARAM, URTW_8187B_8225_ANAPARAM_ON); 35533d4b849eSmartynas urtw_write8_m(sc, URTW_ANAPARAM3, URTW_8187B_8225_ANAPARAM3_ON); 35543d4b849eSmartynas 35553d4b849eSmartynas urtw_write8_m(sc, 0x61, 0x10); 35563d4b849eSmartynas urtw_read8_m(sc, 0x62, &data); 35573d4b849eSmartynas urtw_write8_m(sc, 0x62, data & ~(1 << 5)); 35583d4b849eSmartynas urtw_write8_m(sc, 0x62, data | (1 << 5)); 35593d4b849eSmartynas 35603d4b849eSmartynas urtw_read8_m(sc, URTW_CONFIG3, &data); 35613d4b849eSmartynas urtw_write8_m(sc, URTW_CONFIG3, data & ~URTW_CONFIG3_ANAPARAM_WRITE); 35623d4b849eSmartynas 35633d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 35643d4b849eSmartynas if (error) 35653d4b849eSmartynas goto fail; 35663d4b849eSmartynas 35673d4b849eSmartynas urtw_read8_m(sc, URTW_CMD, &data); 35683d4b849eSmartynas data = (data & 2) | URTW_CMD_RST; 35693d4b849eSmartynas urtw_write8_m(sc, URTW_CMD, data); 35703d4b849eSmartynas usbd_delay_ms(sc->sc_udev, 100); 35713d4b849eSmartynas 35723d4b849eSmartynas urtw_read8_m(sc, URTW_CMD, &data); 35733d4b849eSmartynas if (data & URTW_CMD_RST) { 35743d4b849eSmartynas printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 35753d4b849eSmartynas goto fail; 35763d4b849eSmartynas } 35773d4b849eSmartynas 35783d4b849eSmartynas fail: 35793d4b849eSmartynas return (error); 35803d4b849eSmartynas } 35813d4b849eSmartynas 35823d4b849eSmartynas int 35833d4b849eSmartynas urtw_8187b_init(struct ifnet *ifp) 35843d4b849eSmartynas { 35853d4b849eSmartynas struct urtw_softc *sc = ifp->if_softc; 35863d4b849eSmartynas struct urtw_rf *rf = &sc->sc_rf; 35873d4b849eSmartynas struct ieee80211com *ic = &sc->sc_ic; 35883d4b849eSmartynas uint8_t data; 35893d4b849eSmartynas usbd_status error; 35903d4b849eSmartynas 35913d4b849eSmartynas urtw_stop(ifp, 0); 35923d4b849eSmartynas 35933d4b849eSmartynas error = urtw_8187b_update_wmm(sc); 35943d4b849eSmartynas if (error != 0) 35953d4b849eSmartynas goto fail; 35963d4b849eSmartynas error = urtw_8187b_reset(sc); 35973d4b849eSmartynas if (error) 35983d4b849eSmartynas goto fail; 35993d4b849eSmartynas 36003d4b849eSmartynas /* Applying MAC address again. */ 36013d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 36023d4b849eSmartynas if (error) 36033d4b849eSmartynas goto fail; 36043d4b849eSmartynas IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); 360549b282e9Smiod error = urtw_set_macaddr(sc, ic->ic_myaddr); 360649b282e9Smiod if (error) 360749b282e9Smiod goto fail; 36083d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 36093d4b849eSmartynas if (error) 36103d4b849eSmartynas goto fail; 36113d4b849eSmartynas 36123d4b849eSmartynas error = urtw_update_msr(sc); 36133d4b849eSmartynas if (error) 36143d4b849eSmartynas goto fail; 36153d4b849eSmartynas 36163d4b849eSmartynas error = rf->init(rf); 36173d4b849eSmartynas if (error != 0) 36183d4b849eSmartynas goto fail; 36193d4b849eSmartynas 36203d4b849eSmartynas urtw_write8_m(sc, URTW_CMD, URTW_CMD_TX_ENABLE | 36213d4b849eSmartynas URTW_CMD_RX_ENABLE); 36223d4b849eSmartynas error = urtw_intr_enable(sc); 36233d4b849eSmartynas if (error != 0) 36243d4b849eSmartynas goto fail; 36253d4b849eSmartynas 36263d4b849eSmartynas error = urtw_write8e(sc, 0x41, 0xf4); 36273d4b849eSmartynas if (error != 0) 36283d4b849eSmartynas goto fail; 36293d4b849eSmartynas error = urtw_write8e(sc, 0x40, 0x00); 36303d4b849eSmartynas if (error != 0) 36313d4b849eSmartynas goto fail; 36323d4b849eSmartynas error = urtw_write8e(sc, 0x42, 0x00); 36333d4b849eSmartynas if (error != 0) 36343d4b849eSmartynas goto fail; 36353d4b849eSmartynas error = urtw_write8e(sc, 0x42, 0x01); 36363d4b849eSmartynas if (error != 0) 36373d4b849eSmartynas goto fail; 36383d4b849eSmartynas error = urtw_write8e(sc, 0x40, 0x0f); 36393d4b849eSmartynas if (error != 0) 36403d4b849eSmartynas goto fail; 36413d4b849eSmartynas error = urtw_write8e(sc, 0x42, 0x00); 36423d4b849eSmartynas if (error != 0) 36433d4b849eSmartynas goto fail; 36443d4b849eSmartynas error = urtw_write8e(sc, 0x42, 0x01); 36453d4b849eSmartynas if (error != 0) 36463d4b849eSmartynas goto fail; 36473d4b849eSmartynas 36483d4b849eSmartynas urtw_read8_m(sc, 0xdb, &data); 36493d4b849eSmartynas urtw_write8_m(sc, 0xdb, data | (1 << 2)); 36503d4b849eSmartynas urtw_write16_idx_m(sc, 0x72, 0x59fa, 3); 36513d4b849eSmartynas urtw_write16_idx_m(sc, 0x74, 0x59d2, 3); 36523d4b849eSmartynas urtw_write16_idx_m(sc, 0x76, 0x59d2, 3); 36533d4b849eSmartynas urtw_write16_idx_m(sc, 0x78, 0x19fa, 3); 36543d4b849eSmartynas urtw_write16_idx_m(sc, 0x7a, 0x19fa, 3); 36553d4b849eSmartynas urtw_write16_idx_m(sc, 0x7c, 0x00d0, 3); 36563d4b849eSmartynas urtw_write8_m(sc, 0x61, 0); 36573d4b849eSmartynas urtw_write8_idx_m(sc, 0x80, 0x0f, 1); 36583d4b849eSmartynas urtw_write8_idx_m(sc, 0x83, 0x03, 1); 36593d4b849eSmartynas urtw_write8_m(sc, 0xda, 0x10); 36603d4b849eSmartynas urtw_write8_idx_m(sc, 0x4d, 0x08, 2); 36613d4b849eSmartynas 36623d4b849eSmartynas urtw_write32_m(sc, URTW_HSSI_PARA, 0x0600321b); 36633d4b849eSmartynas 36643d4b849eSmartynas urtw_write16_idx_m(sc, 0xec, 0x0800, 1); 36653d4b849eSmartynas 36663d4b849eSmartynas urtw_write8_m(sc, URTW_ACM_CONTROL, 0); 36673d4b849eSmartynas 36683d4b849eSmartynas /* Reset softc variables. */ 36693d4b849eSmartynas sc->sc_txidx = sc->sc_tx_low_queued = sc->sc_tx_normal_queued = 0; 36703d4b849eSmartynas sc->sc_txtimer = 0; 36713d4b849eSmartynas 36723d4b849eSmartynas if (!(sc->sc_flags & URTW_INIT_ONCE)) { 36733d4b849eSmartynas error = urtw_open_pipes(sc); 36743d4b849eSmartynas if (error != 0) 36753d4b849eSmartynas goto fail; 36765c36bcedSkevlo error = urtw_alloc_rx_data_list(sc); 36773d4b849eSmartynas if (error != 0) 36783d4b849eSmartynas goto fail; 36795c36bcedSkevlo error = urtw_alloc_tx_data_list(sc); 36803d4b849eSmartynas if (error != 0) 36813d4b849eSmartynas goto fail; 36823d4b849eSmartynas sc->sc_flags |= URTW_INIT_ONCE; 36833d4b849eSmartynas } 36843d4b849eSmartynas 36853d4b849eSmartynas error = urtw_rx_enable(sc); 36863d4b849eSmartynas if (error != 0) 36873d4b849eSmartynas goto fail; 36883d4b849eSmartynas error = urtw_tx_enable(sc); 36893d4b849eSmartynas if (error != 0) 36903d4b849eSmartynas goto fail; 36913d4b849eSmartynas 36923d4b849eSmartynas ifp->if_flags |= IFF_RUNNING; 3693de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 36943d4b849eSmartynas 36953d4b849eSmartynas ifp->if_timer = 1; 36963d4b849eSmartynas 36973d4b849eSmartynas if (ic->ic_opmode == IEEE80211_M_MONITOR) 36983d4b849eSmartynas ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 36993d4b849eSmartynas else 37003d4b849eSmartynas ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 37013d4b849eSmartynas 37023d4b849eSmartynas fail: 37033d4b849eSmartynas return (error); 37043d4b849eSmartynas } 37053d4b849eSmartynas 37063d4b849eSmartynas usbd_status 37073d4b849eSmartynas urtw_8225v2_b_config_mac(struct urtw_softc *sc) 37083d4b849eSmartynas { 37093d4b849eSmartynas int i; 37103d4b849eSmartynas usbd_status error; 37113d4b849eSmartynas 37123d4b849eSmartynas for (i = 0; i < nitems(urtw_8187b_regtbl); i++) { 37133d4b849eSmartynas urtw_write8_idx_m(sc, urtw_8187b_regtbl[i].reg, 37143d4b849eSmartynas urtw_8187b_regtbl[i].val, urtw_8187b_regtbl[i].idx); 37153d4b849eSmartynas } 37163d4b849eSmartynas 37173d4b849eSmartynas urtw_write16_m(sc, URTW_TID_AC_MAP, 0xfa50); 37183d4b849eSmartynas urtw_write16_m(sc, URTW_INT_MIG, 0); 37193d4b849eSmartynas 37203d4b849eSmartynas urtw_write32_idx_m(sc, 0xf0, 0, 1); 37213d4b849eSmartynas urtw_write32_idx_m(sc, 0xf4, 0, 1); 37223d4b849eSmartynas urtw_write8_idx_m(sc, 0xf8, 0, 1); 37233d4b849eSmartynas 37243d4b849eSmartynas urtw_write32_m(sc, URTW_RF_TIMING, 0x00004001); 37253d4b849eSmartynas 37263d4b849eSmartynas fail: 37273d4b849eSmartynas return (error); 37283d4b849eSmartynas } 37293d4b849eSmartynas 37303d4b849eSmartynas usbd_status 37313d4b849eSmartynas urtw_8225v2_b_init_rfe(struct urtw_softc *sc) 37323d4b849eSmartynas { 37333d4b849eSmartynas usbd_status error; 37343d4b849eSmartynas 37353d4b849eSmartynas urtw_write16_m(sc, URTW_RF_PINS_OUTPUT, 0x0480); 37363d4b849eSmartynas urtw_write16_m(sc, URTW_RF_PINS_SELECT, 0x2488); 37373d4b849eSmartynas urtw_write16_m(sc, URTW_RF_PINS_ENABLE, 0x1fff); 37383d4b849eSmartynas usbd_delay_ms(sc->sc_udev, 100); 37393d4b849eSmartynas 37403d4b849eSmartynas fail: 37413d4b849eSmartynas return (error); 37423d4b849eSmartynas } 37433d4b849eSmartynas 37443d4b849eSmartynas usbd_status 37453d4b849eSmartynas urtw_8225v2_b_update_chan(struct urtw_softc *sc) 37463d4b849eSmartynas { 37473d4b849eSmartynas struct ieee80211com *ic = &sc->sc_ic; 37483d4b849eSmartynas struct ieee80211_channel *c = ic->ic_ibss_chan; 37493d4b849eSmartynas uint8_t aifs, difs, eifs, sifs, slot; 37503d4b849eSmartynas usbd_status error; 37513d4b849eSmartynas 37523d4b849eSmartynas urtw_write8_m(sc, URTW_SIFS, 0x22); 37533d4b849eSmartynas 37543d4b849eSmartynas sifs = 0xa; 37553d4b849eSmartynas if (IEEE80211_IS_CHAN_G(c)) { 37563d4b849eSmartynas slot = 0x9; 37573d4b849eSmartynas difs = 0x1c; 37583d4b849eSmartynas eifs = 0x5b; 37593d4b849eSmartynas } else { 37603d4b849eSmartynas slot = 0x14; 37613d4b849eSmartynas difs = 0x32; 37623d4b849eSmartynas eifs = 0x5b; 37633d4b849eSmartynas } 37643d4b849eSmartynas aifs = (2 * slot) + sifs; 37653d4b849eSmartynas 37663d4b849eSmartynas urtw_write8_m(sc, URTW_SLOT, slot); 37673d4b849eSmartynas 37683d4b849eSmartynas urtw_write8_m(sc, URTW_AC_VO, aifs); 37693d4b849eSmartynas urtw_write8_m(sc, URTW_AC_VI, aifs); 37703d4b849eSmartynas urtw_write8_m(sc, URTW_AC_BE, aifs); 37713d4b849eSmartynas urtw_write8_m(sc, URTW_AC_BK, aifs); 37723d4b849eSmartynas 37733d4b849eSmartynas urtw_write8_m(sc, URTW_DIFS, difs); 37743d4b849eSmartynas urtw_write8_m(sc, URTW_8187B_EIFS, eifs); 37753d4b849eSmartynas 37763d4b849eSmartynas fail: 37773d4b849eSmartynas return (error); 37783d4b849eSmartynas } 37793d4b849eSmartynas 37803d4b849eSmartynas usbd_status 37813d4b849eSmartynas urtw_8225v2_b_rf_init(struct urtw_rf *rf) 37823d4b849eSmartynas { 37833d4b849eSmartynas struct urtw_softc *sc = rf->rf_sc; 37843d4b849eSmartynas int i; 37853d4b849eSmartynas uint8_t data; 37863d4b849eSmartynas usbd_status error; 37873d4b849eSmartynas 37883d4b849eSmartynas /* Set up ACK rate, retry limit, TX AGC, TX antenna. */ 37893d4b849eSmartynas urtw_write16_m(sc, URTW_8187B_BRSR, 0x0fff); 37903d4b849eSmartynas urtw_read8_m(sc, URTW_CW_CONF, &data); 37913d4b849eSmartynas urtw_write8_m(sc, URTW_CW_CONF, data | 37923d4b849eSmartynas URTW_CW_CONF_PERPACKET_RETRY); 37933d4b849eSmartynas urtw_read8_m(sc, URTW_TX_AGC_CTL, &data); 37943d4b849eSmartynas urtw_write8_m(sc, URTW_TX_AGC_CTL, data | 37953d4b849eSmartynas URTW_TX_AGC_CTL_PERPACKET_GAIN | 37963d4b849eSmartynas URTW_TX_AGC_CTL_PERPACKET_ANTSEL); 37973d4b849eSmartynas 37983d4b849eSmartynas /* Auto rate fallback control. */ 37993d4b849eSmartynas urtw_write16_idx_m(sc, URTW_ARFR, 0x0fff, 1); /* 1M ~ 54M */ 38003d4b849eSmartynas urtw_read8_m(sc, URTW_RATE_FALLBACK, &data); 38013d4b849eSmartynas urtw_write8_m(sc, URTW_RATE_FALLBACK, data | 38023d4b849eSmartynas URTW_RATE_FALLBACK_ENABLE); 38033d4b849eSmartynas 38043d4b849eSmartynas urtw_write16_m(sc, URTW_BEACON_INTERVAL, 100); 38053d4b849eSmartynas urtw_write16_m(sc, URTW_ATIM_WND, 2); 38063d4b849eSmartynas urtw_write16_idx_m(sc, URTW_FEMR, 0xffff, 1); 38073d4b849eSmartynas 38083d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 38093d4b849eSmartynas if (error) 38103d4b849eSmartynas goto fail; 38113d4b849eSmartynas urtw_read8_m(sc, URTW_CONFIG1, &data); 38123d4b849eSmartynas urtw_write8_m(sc, URTW_CONFIG1, (data & 0x3f) | 0x80); 38133d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 38143d4b849eSmartynas if (error) 38153d4b849eSmartynas goto fail; 38163d4b849eSmartynas 38173d4b849eSmartynas urtw_write8_m(sc, URTW_WPA_CONFIG, 0); 38183d4b849eSmartynas urtw_8225v2_b_config_mac(sc); 38193d4b849eSmartynas urtw_write16_idx_m(sc, URTW_RFSW_CTRL, 0x569a, 2); 38203d4b849eSmartynas 38213d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_CONFIG); 38223d4b849eSmartynas if (error) 38233d4b849eSmartynas goto fail; 38243d4b849eSmartynas urtw_read8_m(sc, URTW_CONFIG3, &data); 38253d4b849eSmartynas urtw_write8_m(sc, URTW_CONFIG3, data | URTW_CONFIG3_ANAPARAM_WRITE); 38263d4b849eSmartynas error = urtw_set_mode(sc, URTW_EPROM_CMD_NORMAL); 38273d4b849eSmartynas if (error) 38283d4b849eSmartynas goto fail; 38293d4b849eSmartynas 38303d4b849eSmartynas urtw_8225v2_b_init_rfe(sc); 38313d4b849eSmartynas 38323d4b849eSmartynas for (i = 0; i < nitems(urtw_8225v2_b_rf); i++) { 38333d4b849eSmartynas urtw_8225_write(sc, urtw_8225v2_b_rf[i].reg, 38343d4b849eSmartynas urtw_8225v2_b_rf[i].val); 38353d4b849eSmartynas } 38363d4b849eSmartynas 38373d4b849eSmartynas for (i = 0; i < nitems(urtw_8225v2_rxgain); i++) { 38383d4b849eSmartynas urtw_8225_write(sc, 0x1, (uint8_t)(i + 1)); 38393d4b849eSmartynas urtw_8225_write(sc, 0x2, urtw_8225v2_rxgain[i]); 38403d4b849eSmartynas } 38413d4b849eSmartynas 38423d4b849eSmartynas urtw_8225_write(sc, 0x03, 0x080); 38433d4b849eSmartynas urtw_8225_write(sc, 0x05, 0x004); 38443d4b849eSmartynas urtw_8225_write(sc, 0x00, 0x0b7); 38453d4b849eSmartynas urtw_8225_write(sc, 0x02, 0xc4d); 38463d4b849eSmartynas urtw_8225_write(sc, 0x02, 0x44d); 38473d4b849eSmartynas urtw_8225_write(sc, 0x00, 0x2bf); 38483d4b849eSmartynas 38493d4b849eSmartynas urtw_write8_m(sc, URTW_TX_GAIN_CCK, 0x03); 38503d4b849eSmartynas urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 0x07); 38513d4b849eSmartynas urtw_write8_m(sc, URTW_TX_ANTENNA, 0x03); 38523d4b849eSmartynas 38533d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x80, 0x12); 38543d4b849eSmartynas for (i = 0; i < nitems(urtw_8225v2_agc); i++) { 38553d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x0f, urtw_8225v2_agc[i]); 38563d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x0e, (uint8_t)i + 0x80); 38573d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x0e, 0); 38583d4b849eSmartynas } 38593d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x80, 0x10); 38603d4b849eSmartynas 38613d4b849eSmartynas for (i = 0; i < nitems(urtw_8225v2_ofdm); i++) 38623d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, i, urtw_8225v2_ofdm[i]); 38633d4b849eSmartynas 38643d4b849eSmartynas urtw_8225v2_b_update_chan(sc); 38653d4b849eSmartynas 38663d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x97, 0x46); 38673d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0xa4, 0xb6); 38683d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x85, 0xfc); 38693d4b849eSmartynas urtw_8187_write_phy_cck(sc, 0xc1, 0x88); 38703d4b849eSmartynas 38713d4b849eSmartynas error = urtw_8225v2_b_rf_set_chan(rf, 1); 38723d4b849eSmartynas fail: 38733d4b849eSmartynas return (error); 38743d4b849eSmartynas } 38753d4b849eSmartynas 38763d4b849eSmartynas usbd_status 38773d4b849eSmartynas urtw_8225v2_b_rf_set_chan(struct urtw_rf *rf, int chan) 38783d4b849eSmartynas { 38793d4b849eSmartynas struct urtw_softc *sc = rf->rf_sc; 38803d4b849eSmartynas usbd_status error; 38813d4b849eSmartynas 38823d4b849eSmartynas error = urtw_8225v2_b_set_txpwrlvl(sc, chan); 38833d4b849eSmartynas if (error) 38843d4b849eSmartynas goto fail; 38853d4b849eSmartynas 38863d4b849eSmartynas urtw_8225_write(sc, 0x7, urtw_8225_channel[chan]); 38873d4b849eSmartynas /* 38883d4b849eSmartynas * Delay removed from 8185 to 8187. 38893d4b849eSmartynas * usbd_delay_ms(sc->sc_udev, 10); 38903d4b849eSmartynas */ 38913d4b849eSmartynas 38923d4b849eSmartynas urtw_write16_m(sc, URTW_AC_VO, 0x5114); 38933d4b849eSmartynas urtw_write16_m(sc, URTW_AC_VI, 0x5114); 38943d4b849eSmartynas urtw_write16_m(sc, URTW_AC_BE, 0x5114); 38953d4b849eSmartynas urtw_write16_m(sc, URTW_AC_BK, 0x5114); 38963d4b849eSmartynas 38973d4b849eSmartynas fail: 38983d4b849eSmartynas return (error); 38993d4b849eSmartynas } 39003d4b849eSmartynas 39013d4b849eSmartynas usbd_status 39023d4b849eSmartynas urtw_8225v2_b_set_txpwrlvl(struct urtw_softc *sc, int chan) 39033d4b849eSmartynas { 39043d4b849eSmartynas int i; 39053d4b849eSmartynas uint8_t *cck_pwrtable; 39063d4b849eSmartynas uint8_t cck_pwrlvl_min, cck_pwrlvl_max, ofdm_pwrlvl_min, 39073d4b849eSmartynas ofdm_pwrlvl_max; 39083d4b849eSmartynas int8_t cck_pwrlvl = sc->sc_txpwr_cck[chan] & 0xff; 39093d4b849eSmartynas int8_t ofdm_pwrlvl = sc->sc_txpwr_ofdm[chan] & 0xff; 39103d4b849eSmartynas usbd_status error; 39113d4b849eSmartynas 39123d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187B_B) { 39133d4b849eSmartynas cck_pwrlvl_min = 0; 39143d4b849eSmartynas cck_pwrlvl_max = 15; 39153d4b849eSmartynas ofdm_pwrlvl_min = 2; 39163d4b849eSmartynas ofdm_pwrlvl_max = 17; 39173d4b849eSmartynas } else { 39183d4b849eSmartynas cck_pwrlvl_min = 7; 39193d4b849eSmartynas cck_pwrlvl_max = 22; 39203d4b849eSmartynas ofdm_pwrlvl_min = 10; 39213d4b849eSmartynas ofdm_pwrlvl_max = 25; 39223d4b849eSmartynas } 39233d4b849eSmartynas 39243d4b849eSmartynas /* CCK power setting */ 39253d4b849eSmartynas cck_pwrlvl = (cck_pwrlvl > (cck_pwrlvl_max - cck_pwrlvl_min)) ? 39263d4b849eSmartynas cck_pwrlvl_max : (cck_pwrlvl + cck_pwrlvl_min); 39273d4b849eSmartynas 39283d4b849eSmartynas cck_pwrlvl += sc->sc_txpwr_cck_base; 39293d4b849eSmartynas cck_pwrlvl = (cck_pwrlvl > 35) ? 35 : cck_pwrlvl; 39303d4b849eSmartynas cck_pwrlvl = (cck_pwrlvl < 0) ? 0 : cck_pwrlvl; 39313d4b849eSmartynas 39323d4b849eSmartynas cck_pwrtable = (chan == 14) ? urtw_8225v2_txpwr_cck_ch14 : 39333d4b849eSmartynas urtw_8225v2_txpwr_cck; 39343d4b849eSmartynas 39353d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187B_B) { 39363d4b849eSmartynas if (cck_pwrlvl <= 6) 39373d4b849eSmartynas ; /* do nothing */ 39383d4b849eSmartynas else if (cck_pwrlvl <= 11) 39393d4b849eSmartynas cck_pwrtable += 8; 39403d4b849eSmartynas else 39413d4b849eSmartynas cck_pwrtable += 16; 39423d4b849eSmartynas } else { 39433d4b849eSmartynas if (cck_pwrlvl <= 5) 39443d4b849eSmartynas ; /* do nothing */ 39453d4b849eSmartynas else if (cck_pwrlvl <= 11) 39463d4b849eSmartynas cck_pwrtable += 8; 39473d4b849eSmartynas else if (cck_pwrlvl <= 17) 39483d4b849eSmartynas cck_pwrtable += 16; 39493d4b849eSmartynas else 39503d4b849eSmartynas cck_pwrtable += 24; 39513d4b849eSmartynas } 39523d4b849eSmartynas 39533d4b849eSmartynas for (i = 0; i < 8; i++) { 39543d4b849eSmartynas urtw_8187_write_phy_cck(sc, 0x44 + i, cck_pwrtable[i]); 39553d4b849eSmartynas } 39563d4b849eSmartynas 39573d4b849eSmartynas urtw_write8_m(sc, URTW_TX_GAIN_CCK, 39583d4b849eSmartynas urtw_8225v2_tx_gain_cck_ofdm[cck_pwrlvl] << 1); 39593d4b849eSmartynas /* 39603d4b849eSmartynas * Delay removed from 8185 to 8187. 39613d4b849eSmartynas * usbd_delay_ms(sc->sc_udev, 1); 39623d4b849eSmartynas */ 39633d4b849eSmartynas 39643d4b849eSmartynas /* OFDM power setting */ 39653d4b849eSmartynas ofdm_pwrlvl = (ofdm_pwrlvl > (ofdm_pwrlvl_max - ofdm_pwrlvl_min)) ? 39663d4b849eSmartynas ofdm_pwrlvl_max : ofdm_pwrlvl + ofdm_pwrlvl_min; 39673d4b849eSmartynas 39683d4b849eSmartynas ofdm_pwrlvl += sc->sc_txpwr_ofdm_base; 39693d4b849eSmartynas ofdm_pwrlvl = (ofdm_pwrlvl > 35) ? 35 : ofdm_pwrlvl; 39703d4b849eSmartynas ofdm_pwrlvl = (ofdm_pwrlvl < 0) ? 0 : ofdm_pwrlvl; 39713d4b849eSmartynas 39723d4b849eSmartynas urtw_write8_m(sc, URTW_TX_GAIN_OFDM, 39733d4b849eSmartynas urtw_8225v2_tx_gain_cck_ofdm[ofdm_pwrlvl] << 1); 39743d4b849eSmartynas 39753d4b849eSmartynas if (sc->sc_hwrev & URTW_HWREV_8187B_B) { 39763d4b849eSmartynas if (ofdm_pwrlvl <= 11) { 39773d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x87, 0x60); 39783d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x89, 0x60); 39793d4b849eSmartynas } else { 39803d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c); 39813d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c); 39823d4b849eSmartynas } 39833d4b849eSmartynas } else { 39843d4b849eSmartynas if (ofdm_pwrlvl <= 11) { 39853d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x87, 0x5c); 39863d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x89, 0x5c); 39873d4b849eSmartynas } else if (ofdm_pwrlvl <= 17) { 39883d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x87, 0x54); 39893d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x89, 0x54); 39903d4b849eSmartynas } else { 39913d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x87, 0x50); 39923d4b849eSmartynas urtw_8187_write_phy_ofdm(sc, 0x89, 0x50); 39933d4b849eSmartynas } 39943d4b849eSmartynas } 39953d4b849eSmartynas 39963d4b849eSmartynas /* 39973d4b849eSmartynas * Delay removed from 8185 to 8187. 39983d4b849eSmartynas * usbd_delay_ms(sc->sc_udev, 1); 39993d4b849eSmartynas */ 40003d4b849eSmartynas fail: 40013d4b849eSmartynas return (error); 40023d4b849eSmartynas } 40033d4b849eSmartynas 400449b282e9Smiod int 400549b282e9Smiod urtw_set_bssid(struct urtw_softc *sc, const uint8_t *bssid) 400649b282e9Smiod { 400749b282e9Smiod int error; 400849b282e9Smiod 400949b282e9Smiod urtw_write32_m(sc, URTW_BSSID, 401049b282e9Smiod bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 401149b282e9Smiod urtw_write16_m(sc, URTW_BSSID + 4, 401249b282e9Smiod bssid[4] | bssid[5] << 8); 401349b282e9Smiod 401449b282e9Smiod return 0; 401549b282e9Smiod 401649b282e9Smiod fail: 401749b282e9Smiod return error; 401849b282e9Smiod } 401949b282e9Smiod 402049b282e9Smiod int 402149b282e9Smiod urtw_set_macaddr(struct urtw_softc *sc, const uint8_t *addr) 402249b282e9Smiod { 402349b282e9Smiod int error; 402449b282e9Smiod 402549b282e9Smiod urtw_write32_m(sc, URTW_MAC0, 402649b282e9Smiod addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 402749b282e9Smiod urtw_write16_m(sc, URTW_MAC4, 402849b282e9Smiod addr[4] | addr[5] << 8); 402949b282e9Smiod 403049b282e9Smiod return 0; 403149b282e9Smiod 403249b282e9Smiod fail: 403349b282e9Smiod return error; 403449b282e9Smiod } 4035