| File: | dev/usb/if_urtwn.c |
| Warning: | line 605, column 11 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: if_urtwn.c,v 1.108 2023/06/12 11:27:30 jsg Exp $ */ | |||
| 2 | ||||
| 3 | /*- | |||
| 4 | * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> | |||
| 5 | * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> | |||
| 6 | * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> | |||
| 7 | * | |||
| 8 | * Permission to use, copy, modify, and distribute this software for any | |||
| 9 | * purpose with or without fee is hereby granted, provided that the above | |||
| 10 | * copyright notice and this permission notice appear in all copies. | |||
| 11 | * | |||
| 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 19 | */ | |||
| 20 | ||||
| 21 | /* | |||
| 22 | * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188FTV/RTL8188RU/ | |||
| 23 | * RTL8192CU/RTL8192EU. | |||
| 24 | */ | |||
| 25 | ||||
| 26 | #include "bpfilter.h" | |||
| 27 | ||||
| 28 | #include <sys/param.h> | |||
| 29 | #include <sys/sockio.h> | |||
| 30 | #include <sys/mbuf.h> | |||
| 31 | #include <sys/kernel.h> | |||
| 32 | #include <sys/socket.h> | |||
| 33 | #include <sys/systm.h> | |||
| 34 | #include <sys/timeout.h> | |||
| 35 | #include <sys/conf.h> | |||
| 36 | #include <sys/device.h> | |||
| 37 | #include <sys/endian.h> | |||
| 38 | ||||
| 39 | #include <machine/bus.h> | |||
| 40 | #include <machine/intr.h> | |||
| 41 | ||||
| 42 | #if NBPFILTER1 > 0 | |||
| 43 | #include <net/bpf.h> | |||
| 44 | #endif | |||
| 45 | #include <net/if.h> | |||
| 46 | #include <net/if_dl.h> | |||
| 47 | #include <net/if_media.h> | |||
| 48 | ||||
| 49 | #include <netinet/in.h> | |||
| 50 | #include <netinet/if_ether.h> | |||
| 51 | ||||
| 52 | #include <net80211/ieee80211_var.h> | |||
| 53 | #include <net80211/ieee80211_amrr.h> | |||
| 54 | #include <net80211/ieee80211_radiotap.h> | |||
| 55 | ||||
| 56 | #include <dev/usb/usb.h> | |||
| 57 | #include <dev/usb/usbdi.h> | |||
| 58 | #include <dev/usb/usbdivar.h> | |||
| 59 | #include <dev/usb/usbdi_util.h> | |||
| 60 | #include <dev/usb/usbdevs.h> | |||
| 61 | ||||
| 62 | #include <dev/ic/r92creg.h> | |||
| 63 | #include <dev/ic/rtwnvar.h> | |||
| 64 | ||||
| 65 | /* Maximum number of output pipes is 3. */ | |||
| 66 | #define R92C_MAX_EPOUT3 3 | |||
| 67 | ||||
| 68 | #define R92C_HQ_NPAGES12 12 | |||
| 69 | #define R92C_LQ_NPAGES2 2 | |||
| 70 | #define R92C_NQ_NPAGES2 2 | |||
| 71 | #define R92C_TXPKTBUF_COUNT256 256 | |||
| 72 | #define R92C_TX_PAGE_COUNT248 248 | |||
| 73 | #define R92C_MAX_RX_DMA_SIZE0x2800 0x2800 | |||
| 74 | ||||
| 75 | #define R88E_HQ_NPAGES0 0 | |||
| 76 | #define R88E_LQ_NPAGES9 9 | |||
| 77 | #define R88E_NQ_NPAGES0 0 | |||
| 78 | #define R88E_TXPKTBUF_COUNT177 177 | |||
| 79 | #define R88E_TX_PAGE_COUNT168 168 | |||
| 80 | #define R88E_MAX_RX_DMA_SIZE0x2400 0x2400 | |||
| 81 | ||||
| 82 | #define R88F_HQ_NPAGES12 12 | |||
| 83 | #define R88F_LQ_NPAGES2 2 | |||
| 84 | #define R88F_NQ_NPAGES2 2 | |||
| 85 | #define R88F_TXPKTBUF_COUNT177 177 | |||
| 86 | #define R88F_TX_PAGE_COUNT247 247 | |||
| 87 | #define R88F_MAX_RX_DMA_SIZE0x3f80 0x3f80 | |||
| 88 | ||||
| 89 | #define R92E_HQ_NPAGES16 16 | |||
| 90 | #define R92E_LQ_NPAGES16 16 | |||
| 91 | #define R92E_NQ_NPAGES16 16 | |||
| 92 | #define R92E_TX_PAGE_COUNT248 248 | |||
| 93 | #define R92E_MAX_RX_DMA_SIZE0x3fc0 0x3fc0 | |||
| 94 | ||||
| 95 | #define R92C_TXDESC_SUMSIZE32 32 | |||
| 96 | #define R92C_TXDESC_SUMOFFSET14 14 | |||
| 97 | ||||
| 98 | /* USB Requests. */ | |||
| 99 | #define R92C_REQ_REGS0x05 0x05 | |||
| 100 | ||||
| 101 | /* | |||
| 102 | * Driver definitions. | |||
| 103 | */ | |||
| 104 | #define URTWN_RX_LIST_COUNT1 1 | |||
| 105 | #define URTWN_TX_LIST_COUNT8 8 | |||
| 106 | #define URTWN_HOST_CMD_RING_COUNT32 32 | |||
| 107 | ||||
| 108 | #define URTWN_RXBUFSZ(16 * 1024) (16 * 1024) | |||
| 109 | #define URTWN_TXBUFSZ(sizeof(struct r92e_tx_desc_usb) + (2300 + 4 + (3 + 1 + 4))) (sizeof(struct r92e_tx_desc_usb) + IEEE80211_MAX_LEN(2300 + 4 + (3 + 1 + 4))) | |||
| 110 | ||||
| 111 | #define URTWN_RIDX_COUNT28 28 | |||
| 112 | ||||
| 113 | #define URTWN_TX_TIMEOUT5000 5000 /* ms */ | |||
| 114 | ||||
| 115 | #define URTWN_LED_LINK0 0 | |||
| 116 | #define URTWN_LED_DATA1 1 | |||
| 117 | ||||
| 118 | struct urtwn_rx_radiotap_header { | |||
| 119 | struct ieee80211_radiotap_header wr_ihdr; | |||
| 120 | uint8_t wr_flags; | |||
| 121 | uint8_t wr_rate; | |||
| 122 | uint16_t wr_chan_freq; | |||
| 123 | uint16_t wr_chan_flags; | |||
| 124 | uint8_t wr_dbm_antsignal; | |||
| 125 | } __packed__attribute__((__packed__)); | |||
| 126 | ||||
| 127 | #define URTWN_RX_RADIOTAP_PRESENT(1 << IEEE80211_RADIOTAP_FLAGS | 1 << IEEE80211_RADIOTAP_RATE | 1 << IEEE80211_RADIOTAP_CHANNEL | 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL ) \ | |||
| 128 | (1 << IEEE80211_RADIOTAP_FLAGS | \ | |||
| 129 | 1 << IEEE80211_RADIOTAP_RATE | \ | |||
| 130 | 1 << IEEE80211_RADIOTAP_CHANNEL | \ | |||
| 131 | 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | |||
| 132 | ||||
| 133 | struct urtwn_tx_radiotap_header { | |||
| 134 | struct ieee80211_radiotap_header wt_ihdr; | |||
| 135 | uint8_t wt_flags; | |||
| 136 | uint16_t wt_chan_freq; | |||
| 137 | uint16_t wt_chan_flags; | |||
| 138 | } __packed__attribute__((__packed__)); | |||
| 139 | ||||
| 140 | #define URTWN_TX_RADIOTAP_PRESENT(1 << IEEE80211_RADIOTAP_FLAGS | 1 << IEEE80211_RADIOTAP_CHANNEL ) \ | |||
| 141 | (1 << IEEE80211_RADIOTAP_FLAGS | \ | |||
| 142 | 1 << IEEE80211_RADIOTAP_CHANNEL) | |||
| 143 | ||||
| 144 | struct urtwn_softc; | |||
| 145 | ||||
| 146 | struct urtwn_rx_data { | |||
| 147 | struct urtwn_softc *sc; | |||
| 148 | struct usbd_xfer *xfer; | |||
| 149 | uint8_t *buf; | |||
| 150 | }; | |||
| 151 | ||||
| 152 | struct urtwn_tx_data { | |||
| 153 | struct urtwn_softc *sc; | |||
| 154 | struct usbd_pipe *pipe; | |||
| 155 | struct usbd_xfer *xfer; | |||
| 156 | uint8_t *buf; | |||
| 157 | TAILQ_ENTRY(urtwn_tx_data)struct { struct urtwn_tx_data *tqe_next; struct urtwn_tx_data **tqe_prev; } next; | |||
| 158 | }; | |||
| 159 | ||||
| 160 | struct urtwn_host_cmd { | |||
| 161 | void (*cb)(struct urtwn_softc *, void *); | |||
| 162 | uint8_t data[256]; | |||
| 163 | }; | |||
| 164 | ||||
| 165 | struct urtwn_cmd_newstate { | |||
| 166 | enum ieee80211_state state; | |||
| 167 | int arg; | |||
| 168 | }; | |||
| 169 | ||||
| 170 | struct urtwn_cmd_key { | |||
| 171 | struct ieee80211_key key; | |||
| 172 | struct ieee80211_node *ni; | |||
| 173 | }; | |||
| 174 | ||||
| 175 | struct urtwn_host_cmd_ring { | |||
| 176 | struct urtwn_host_cmd cmd[URTWN_HOST_CMD_RING_COUNT32]; | |||
| 177 | int cur; | |||
| 178 | int next; | |||
| 179 | int queued; | |||
| 180 | }; | |||
| 181 | ||||
| 182 | struct urtwn_softc { | |||
| 183 | struct device sc_dev; | |||
| 184 | struct rtwn_softc sc_sc; | |||
| 185 | ||||
| 186 | struct usbd_device *sc_udev; | |||
| 187 | struct usbd_interface *sc_iface; | |||
| 188 | struct usb_task sc_task; | |||
| 189 | ||||
| 190 | struct timeout scan_to; | |||
| 191 | struct timeout calib_to; | |||
| 192 | ||||
| 193 | int ntx; | |||
| 194 | struct usbd_pipe *rx_pipe; | |||
| 195 | struct usbd_pipe *tx_pipe[R92C_MAX_EPOUT3]; | |||
| 196 | int ac2idx[EDCA_NUM_AC4]; | |||
| 197 | ||||
| 198 | struct urtwn_host_cmd_ring cmdq; | |||
| 199 | struct urtwn_rx_data rx_data[URTWN_RX_LIST_COUNT1]; | |||
| 200 | struct urtwn_tx_data tx_data[URTWN_TX_LIST_COUNT8]; | |||
| 201 | TAILQ_HEAD(, urtwn_tx_data)struct { struct urtwn_tx_data *tqh_first; struct urtwn_tx_data **tqh_last; } tx_free_list; | |||
| 202 | ||||
| 203 | struct ieee80211_amrr amrr; | |||
| 204 | struct ieee80211_amrr_node amn; | |||
| 205 | ||||
| 206 | #if NBPFILTER1 > 0 | |||
| 207 | caddr_t sc_drvbpf; | |||
| 208 | ||||
| 209 | union { | |||
| 210 | struct urtwn_rx_radiotap_header th; | |||
| 211 | uint8_t pad[64]; | |||
| 212 | } sc_rxtapu; | |||
| 213 | #define sc_rxtapsc_rxtapu.th sc_rxtapu.th | |||
| 214 | int sc_rxtap_len; | |||
| 215 | ||||
| 216 | union { | |||
| 217 | struct urtwn_tx_radiotap_header th; | |||
| 218 | uint8_t pad[64]; | |||
| 219 | } sc_txtapu; | |||
| 220 | #define sc_txtapsc_txtapu.th sc_txtapu.th | |||
| 221 | int sc_txtap_len; | |||
| 222 | #endif | |||
| 223 | int sc_key_tasks; | |||
| 224 | }; | |||
| 225 | ||||
| 226 | #ifdef URTWN_DEBUG | |||
| 227 | #define DPRINTF(x) do { if (urtwn_debug) printf x; } while (0) | |||
| 228 | #define DPRINTFN(n, x) do { if (urtwn_debug >= (n)) printf x; } while (0) | |||
| 229 | int urtwn_debug = 4; | |||
| 230 | #else | |||
| 231 | #define DPRINTF(x) | |||
| 232 | #define DPRINTFN(n, x) | |||
| 233 | #endif | |||
| 234 | ||||
| 235 | /* | |||
| 236 | * Various supported device vendors/products. | |||
| 237 | */ | |||
| 238 | #define URTWN_DEV(v, p, f){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (f) | 0x80000000 } \ | |||
| 239 | { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) | RTWN_CHIP_USB0x80000000 } | |||
| 240 | #define URTWN_DEV_8192CU(v, p){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000001 | 0x00000010 ) | 0x80000000 } URTWN_DEV(v, p, RTWN_CHIP_92C | RTWN_CHIP_88C){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000001 | 0x00000010 ) | 0x80000000 } | |||
| 241 | #define URTWN_DEV_8192EU(v, p){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000040) | 0x80000000 } URTWN_DEV(v, p, RTWN_CHIP_92E){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000040) | 0x80000000 } | |||
| 242 | #define URTWN_DEV_8188EU(v, p){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000020) | 0x80000000 } URTWN_DEV(v, p, RTWN_CHIP_88E){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000020) | 0x80000000 } | |||
| 243 | #define URTWN_DEV_8188F(v, p){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000200) | 0x80000000 } URTWN_DEV(v, p, RTWN_CHIP_88F){ { USB_VENDOR_v, USB_PRODUCT_v_p }, (0x00000200) | 0x80000000 } | |||
| 244 | static const struct urtwn_type { | |||
| 245 | struct usb_devno dev; | |||
| 246 | uint32_t chip; | |||
| 247 | } urtwn_devs[] = { | |||
| 248 | URTWN_DEV_8192CU(ABOCOM, RTL8188CU_1){ { 0x07b8, 0x8188 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 249 | URTWN_DEV_8192CU(ABOCOM, RTL8188CU_1){ { 0x07b8, 0x8188 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 250 | URTWN_DEV_8192CU(ABOCOM, RTL8188CU_2){ { 0x07b8, 0x8189 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 251 | URTWN_DEV_8192CU(ABOCOM, RTL8192CU){ { 0x07b8, 0x8178 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 252 | URTWN_DEV_8192CU(ASUS, RTL8192CU){ { 0x0b05, 0x17ab }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 253 | URTWN_DEV_8192CU(ASUS, RTL8192CU_2){ { 0x0b05, 0x17ba }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 254 | URTWN_DEV_8192CU(ASUS, RTL8192CU_3){ { 0x0b05, 0x17c0 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 255 | URTWN_DEV_8192CU(AZUREWAVE, RTL8188CE_1){ { 0x13d3, 0x3358 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 256 | URTWN_DEV_8192CU(AZUREWAVE, RTL8188CE_2){ { 0x13d3, 0x3359 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 257 | URTWN_DEV_8192CU(AZUREWAVE, RTL8188CU){ { 0x13d3, 0x3357 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 258 | URTWN_DEV_8192CU(BELKIN, F7D2102){ { 0x050d, 0x2103 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 259 | URTWN_DEV_8192CU(BELKIN, F9L1004V1){ { 0x050d, 0x1004 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 260 | URTWN_DEV_8192CU(BELKIN, RTL8188CU){ { 0x050d, 0x1102 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 261 | URTWN_DEV_8192CU(BELKIN, RTL8188CUS){ { 0x050d, 0x11f2 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 262 | URTWN_DEV_8192CU(BELKIN, RTL8192CU){ { 0x050d, 0x2102 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 263 | URTWN_DEV_8192CU(BELKIN, RTL8192CU_1){ { 0x050d, 0x21f2 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 264 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_1){ { 0x04f2, 0xaff7 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 265 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_2){ { 0x04f2, 0xaff8 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 266 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_3){ { 0x04f2, 0xaff9 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 267 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_4){ { 0x04f2, 0xaffa }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 268 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_5){ { 0x04f2, 0xaffb }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 269 | URTWN_DEV_8192CU(CHICONY, RTL8188CUS_6){ { 0x04f2, 0xaffc }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 270 | URTWN_DEV_8192CU(COMPARE, RTL8192CU){ { 0xcdab, 0x8010 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 271 | URTWN_DEV_8192CU(COREGA, RTL8192CU){ { 0x07aa, 0x0056 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 272 | URTWN_DEV_8192CU(DLINK, DWA131B){ { 0x2001, 0x330d }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 273 | URTWN_DEV_8192CU(DLINK, RTL8188CU){ { 0x2001, 0x3308 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 274 | URTWN_DEV_8192CU(DLINK, RTL8192CU_1){ { 0x2001, 0x3307 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 275 | URTWN_DEV_8192CU(DLINK, RTL8192CU_2){ { 0x2001, 0x3309 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 276 | URTWN_DEV_8192CU(DLINK, RTL8192CU_3){ { 0x2001, 0x330a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 277 | URTWN_DEV_8192CU(DLINK, RTL8192CU_4){ { 0x2001, 0x330b }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 278 | URTWN_DEV_8192CU(EDIMAX, EW7811UN){ { 0x7392, 0x7811 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 279 | URTWN_DEV_8192CU(EDIMAX, RTL8192CU){ { 0x7392, 0x7822 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 280 | URTWN_DEV_8192CU(FEIXUN, RTL8188CU){ { 0x4855, 0x0090 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 281 | URTWN_DEV_8192CU(FEIXUN, RTL8192CU){ { 0x4855, 0x0091 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 282 | URTWN_DEV_8192CU(GUILLEMOT, HWNUP150){ { 0x06f8, 0xe033 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 283 | URTWN_DEV_8192CU(GUILLEMOT, RTL8192CU){ { 0x06f8, 0xe035 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 284 | URTWN_DEV_8192CU(HAWKING, RTL8192CU){ { 0x0e66, 0x0019 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 285 | URTWN_DEV_8192CU(HAWKING, RTL8192CU_2){ { 0x0e66, 0x0020 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 286 | URTWN_DEV_8192CU(HP3, RTL8188CU){ { 0x103c, 0x1629 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 287 | URTWN_DEV_8192CU(IODATA, WNG150UM){ { 0x04bb, 0x094c }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 288 | URTWN_DEV_8192CU(IODATA, RTL8192CU){ { 0x04bb, 0x0950 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 289 | URTWN_DEV_8192CU(NETGEAR, N300MA){ { 0x0846, 0xf001 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 290 | URTWN_DEV_8192CU(NETGEAR, WNA1000M){ { 0x0846, 0x9041 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 291 | URTWN_DEV_8192CU(NETGEAR, WNA1000MV2){ { 0x0846, 0x9043 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 292 | URTWN_DEV_8192CU(NETGEAR, RTL8192CU){ { 0x0846, 0x9021 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 293 | URTWN_DEV_8192CU(NETGEAR4, RTL8188CU){ { 0x9846, 0x9041 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 294 | URTWN_DEV_8192CU(NETWEEN, RTL8192CU){ { 0x4856, 0x0091 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 295 | URTWN_DEV_8192CU(NOVATECH, RTL8188CU){ { 0x0eb0, 0x9071 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 296 | URTWN_DEV_8192CU(PLANEX2, RTL8188CU_1){ { 0x2019, 0xab2a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 297 | URTWN_DEV_8192CU(PLANEX2, RTL8188CU_2){ { 0x2019, 0xed17 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 298 | URTWN_DEV_8192CU(PLANEX2, RTL8188CU_3){ { 0x2019, 0x4902 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 299 | URTWN_DEV_8192CU(PLANEX2, RTL8188CU_4){ { 0x2019, 0xab2e }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 300 | URTWN_DEV_8192CU(PLANEX2, RTL8188CUS){ { 0x2019, 0x1201 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 301 | URTWN_DEV_8192CU(PLANEX2, RTL8192CU){ { 0x2019, 0xab2b }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 302 | URTWN_DEV_8192CU(REALTEK, RTL8188CE_0){ { 0x0bda, 0x8170 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 303 | URTWN_DEV_8192CU(REALTEK, RTL8188CE_1){ { 0x0bda, 0x817e }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 304 | URTWN_DEV_8192CU(REALTEK, RTL8188CTV){ { 0x0bda, 0x018a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 305 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_0){ { 0x0bda, 0x8176 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 306 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_1){ { 0x0bda, 0x817a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 307 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_2){ { 0x0bda, 0x817b }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 308 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_3){ { 0x0bda, 0x8191 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 309 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_4){ { 0x0bda, 0x5088 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 310 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_5){ { 0x0bda, 0x819a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 311 | URTWN_DEV_8192CU(REALTEK, RTL8188CU_COMBO){ { 0x0bda, 0x8754 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 312 | URTWN_DEV_8192CU(REALTEK, RTL8188CUS){ { 0x0bda, 0x818a }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 313 | URTWN_DEV_8192CU(REALTEK, RTL8188RU){ { 0x0bda, 0x817d }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 314 | URTWN_DEV_8192CU(REALTEK, RTL8188RU_2){ { 0x0bda, 0x317f }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 315 | URTWN_DEV_8192CU(REALTEK, RTL8188RU_3){ { 0x0bda, 0x817f }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 316 | URTWN_DEV_8192CU(REALTEK, RTL8191CU){ { 0x0bda, 0x8177 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 317 | URTWN_DEV_8192CU(REALTEK, RTL8192CE){ { 0x0bda, 0x817c }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 318 | URTWN_DEV_8192CU(REALTEK, RTL8192CE_VAU){ { 0x0bda, 0x8186 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 319 | URTWN_DEV_8192CU(REALTEK, RTL8192CU){ { 0x0bda, 0x8178 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 320 | URTWN_DEV_8192CU(SITECOMEU, RTL8188CU){ { 0x0df6, 0x0052 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 321 | URTWN_DEV_8192CU(SITECOMEU, RTL8188CU_2){ { 0x0df6, 0x005c }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 322 | URTWN_DEV_8192CU(SITECOMEU, RTL8192CU){ { 0x0df6, 0x0061 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 323 | URTWN_DEV_8192CU(SITECOMEU, RTL8192CU_2){ { 0x0df6, 0x0070 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 324 | URTWN_DEV_8192CU(SITECOMEU, WLA2100V2){ { 0x0df6, 0x0077 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 325 | URTWN_DEV_8192CU(TPLINK, RTL8192CU){ { 0x2357, 0x0100 }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 326 | URTWN_DEV_8192CU(TRENDNET, RTL8188CU){ { 0x20f4, 0x648b }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 327 | URTWN_DEV_8192CU(TRENDNET, RTL8192CU){ { 0x20f4, 0x624d }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 328 | URTWN_DEV_8192CU(ZYXEL, RTL8192CU){ { 0x0586, 0x341f }, (0x00000001 | 0x00000010) | 0x80000000 }, | |||
| 329 | /* URTWN_RTL8188E */ | |||
| 330 | URTWN_DEV_8188EU(ABOCOM, RTL8188EU){ { 0x07b8, 0x8179 }, (0x00000020) | 0x80000000 }, | |||
| 331 | URTWN_DEV_8188EU(DLINK, DWA121B1){ { 0x2001, 0x331b }, (0x00000020) | 0x80000000 }, | |||
| 332 | URTWN_DEV_8188EU(DLINK, DWA123D1){ { 0x2001, 0x3310 }, (0x00000020) | 0x80000000 }, | |||
| 333 | URTWN_DEV_8188EU(DLINK, DWA125D1){ { 0x2001, 0x330f }, (0x00000020) | 0x80000000 }, | |||
| 334 | URTWN_DEV_8188EU(EDIMAX, EW7811UNV2){ { 0x7392, 0xb811 }, (0x00000020) | 0x80000000 }, | |||
| 335 | URTWN_DEV_8188EU(ELECOM, WDC150SU2M){ { 0x056e, 0x4008 }, (0x00000020) | 0x80000000 }, | |||
| 336 | URTWN_DEV_8188EU(MERCUSYS, MW150USV2){ { 0x2c4e, 0x0102 }, (0x00000020) | 0x80000000 }, | |||
| 337 | URTWN_DEV_8188EU(REALTEK, RTL8188ETV){ { 0x0bda, 0x0179 }, (0x00000020) | 0x80000000 }, | |||
| 338 | URTWN_DEV_8188EU(REALTEK, RTL8188EU){ { 0x0bda, 0x8179 }, (0x00000020) | 0x80000000 }, | |||
| 339 | URTWN_DEV_8188EU(TPLINK, RTL8188EUS){ { 0x2357, 0x010c }, (0x00000020) | 0x80000000 }, | |||
| 340 | URTWN_DEV_8188EU(ASUS, RTL8188EUS){ { 0x0b05, 0x18f0 }, (0x00000020) | 0x80000000 }, | |||
| 341 | /* URTWN_RTL8188FTV */ | |||
| 342 | URTWN_DEV_8188F(REALTEK, RTL8188FTV){ { 0x0bda, 0xf179 }, (0x00000200) | 0x80000000 }, | |||
| 343 | ||||
| 344 | /* URTWN_RTL8192EU */ | |||
| 345 | URTWN_DEV_8192EU(DLINK, DWA131E1){ { 0x2001, 0x3319 }, (0x00000040) | 0x80000000 }, | |||
| 346 | URTWN_DEV_8192EU(REALTEK, RTL8192EU){ { 0x0bda, 0x818b }, (0x00000040) | 0x80000000 }, | |||
| 347 | URTWN_DEV_8192EU(TPLINK, RTL8192EU){ { 0x2357, 0x0107 }, (0x00000040) | 0x80000000 }, | |||
| 348 | URTWN_DEV_8192EU(TPLINK, RTL8192EU_2){ { 0x2357, 0x0108 }, (0x00000040) | 0x80000000 }, | |||
| 349 | URTWN_DEV_8192EU(TPLINK, RTL8192EU_3){ { 0x2357, 0x0109 }, (0x00000040) | 0x80000000 } | |||
| 350 | }; | |||
| 351 | ||||
| 352 | #define urtwn_lookup(v, p)((const struct urtwn_type *)usbd_match_device((const struct usb_devno *)(urtwn_devs), sizeof (urtwn_devs) / sizeof ((urtwn_devs)[0 ]), sizeof ((urtwn_devs)[0]), (v), (p))) \ | |||
| 353 | ((const struct urtwn_type *)usb_lookup(urtwn_devs, v, p)usbd_match_device((const struct usb_devno *)(urtwn_devs), sizeof (urtwn_devs) / sizeof ((urtwn_devs)[0]), sizeof ((urtwn_devs )[0]), (v), (p))) | |||
| 354 | ||||
| 355 | int urtwn_match(struct device *, void *, void *); | |||
| 356 | void urtwn_attach(struct device *, struct device *, void *); | |||
| 357 | int urtwn_detach(struct device *, int); | |||
| 358 | int urtwn_open_pipes(struct urtwn_softc *); | |||
| 359 | void urtwn_close_pipes(struct urtwn_softc *); | |||
| 360 | int urtwn_alloc_rx_list(struct urtwn_softc *); | |||
| 361 | void urtwn_free_rx_list(struct urtwn_softc *); | |||
| 362 | int urtwn_alloc_tx_list(struct urtwn_softc *); | |||
| 363 | void urtwn_free_tx_list(struct urtwn_softc *); | |||
| 364 | void urtwn_task(void *); | |||
| 365 | void urtwn_do_async(struct urtwn_softc *, | |||
| 366 | void (*)(struct urtwn_softc *, void *), void *, int); | |||
| 367 | void urtwn_wait_async(void *); | |||
| 368 | int urtwn_write_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | |||
| 369 | int); | |||
| 370 | void urtwn_write_1(void *, uint16_t, uint8_t); | |||
| 371 | void urtwn_write_2(void *, uint16_t, uint16_t); | |||
| 372 | void urtwn_write_4(void *, uint16_t, uint32_t); | |||
| 373 | int urtwn_read_region_1(struct urtwn_softc *, uint16_t, uint8_t *, | |||
| 374 | int); | |||
| 375 | uint8_t urtwn_read_1(void *, uint16_t); | |||
| 376 | uint16_t urtwn_read_2(void *, uint16_t); | |||
| 377 | uint32_t urtwn_read_4(void *, uint16_t); | |||
| 378 | int urtwn_llt_write(struct urtwn_softc *, uint32_t, uint32_t); | |||
| 379 | void urtwn_calib_to(void *); | |||
| 380 | void urtwn_calib_cb(struct urtwn_softc *, void *); | |||
| 381 | void urtwn_scan_to(void *); | |||
| 382 | void urtwn_next_scan(void *); | |||
| 383 | void urtwn_cancel_scan(void *); | |||
| 384 | int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, | |||
| 385 | int); | |||
| 386 | void urtwn_newstate_cb(struct urtwn_softc *, void *); | |||
| 387 | void urtwn_updateslot(struct ieee80211com *); | |||
| 388 | void urtwn_updateslot_cb(struct urtwn_softc *, void *); | |||
| 389 | void urtwn_updateedca(struct ieee80211com *); | |||
| 390 | void urtwn_updateedca_cb(struct urtwn_softc *, void *); | |||
| 391 | int urtwn_set_key(struct ieee80211com *, struct ieee80211_node *, | |||
| 392 | struct ieee80211_key *); | |||
| 393 | void urtwn_set_key_cb(struct urtwn_softc *, void *); | |||
| 394 | void urtwn_delete_key(struct ieee80211com *, | |||
| 395 | struct ieee80211_node *, struct ieee80211_key *); | |||
| 396 | void urtwn_delete_key_cb(struct urtwn_softc *, void *); | |||
| 397 | void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, | |||
| 398 | struct mbuf_list *); | |||
| 399 | void urtwn_rxeof(struct usbd_xfer *, void *, | |||
| 400 | usbd_status); | |||
| 401 | void urtwn_txeof(struct usbd_xfer *, void *, | |||
| 402 | usbd_status); | |||
| 403 | int urtwn_tx(void *, struct mbuf *, struct ieee80211_node *); | |||
| 404 | int urtwn_ioctl(struct ifnet *, u_long, caddr_t); | |||
| 405 | int urtwn_power_on(void *); | |||
| 406 | int urtwn_alloc_buffers(void *); | |||
| 407 | int urtwn_r92c_power_on(struct urtwn_softc *); | |||
| 408 | int urtwn_r92e_power_on(struct urtwn_softc *); | |||
| 409 | int urtwn_r88e_power_on(struct urtwn_softc *); | |||
| 410 | int urtwn_r88f_power_on(struct urtwn_softc *); | |||
| 411 | int urtwn_llt_init(struct urtwn_softc *, int); | |||
| 412 | int urtwn_fw_loadpage(void *, int, uint8_t *, int); | |||
| 413 | int urtwn_load_firmware(void *, u_char **, size_t *); | |||
| 414 | int urtwn_dma_init(void *); | |||
| 415 | void urtwn_aggr_init(void *); | |||
| 416 | void urtwn_mac_init(void *); | |||
| 417 | void urtwn_bb_init(void *); | |||
| 418 | void urtwn_burstlen_init(struct urtwn_softc *); | |||
| 419 | int urtwn_init(void *); | |||
| 420 | void urtwn_stop(void *); | |||
| 421 | int urtwn_is_oactive(void *); | |||
| 422 | void urtwn_next_calib(void *); | |||
| 423 | void urtwn_cancel_calib(void *); | |||
| 424 | ||||
| 425 | /* Aliases. */ | |||
| 426 | #define urtwn_bb_writeurtwn_write_4 urtwn_write_4 | |||
| 427 | #define urtwn_bb_readurtwn_read_4 urtwn_read_4 | |||
| 428 | ||||
| 429 | struct cfdriver urtwn_cd = { | |||
| 430 | NULL((void *)0), "urtwn", DV_IFNET | |||
| 431 | }; | |||
| 432 | ||||
| 433 | const struct cfattach urtwn_ca = { | |||
| 434 | sizeof(struct urtwn_softc), urtwn_match, urtwn_attach, urtwn_detach | |||
| 435 | }; | |||
| 436 | ||||
| 437 | int | |||
| 438 | urtwn_match(struct device *parent, void *match, void *aux) | |||
| 439 | { | |||
| 440 | struct usb_attach_arg *uaa = aux; | |||
| 441 | ||||
| 442 | if (uaa->iface == NULL((void *)0) || uaa->configno != 1) | |||
| 443 | return (UMATCH_NONE0); | |||
| 444 | ||||
| 445 | return ((urtwn_lookup(uaa->vendor, uaa->product)((const struct urtwn_type *)usbd_match_device((const struct usb_devno *)(urtwn_devs), sizeof (urtwn_devs) / sizeof ((urtwn_devs)[0 ]), sizeof ((urtwn_devs)[0]), (uaa->vendor), (uaa->product ))) != NULL((void *)0)) ? | |||
| 446 | UMATCH_VENDOR_PRODUCT_CONF_IFACE8 : UMATCH_NONE0); | |||
| 447 | } | |||
| 448 | ||||
| 449 | void | |||
| 450 | urtwn_attach(struct device *parent, struct device *self, void *aux) | |||
| 451 | { | |||
| 452 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 453 | struct usb_attach_arg *uaa = aux; | |||
| 454 | struct ifnet *ifp; | |||
| 455 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 456 | ||||
| 457 | sc->sc_udev = uaa->device; | |||
| 458 | sc->sc_iface = uaa->iface; | |||
| 459 | ||||
| 460 | sc->sc_sc.chip = urtwn_lookup(uaa->vendor, uaa->product)((const struct urtwn_type *)usbd_match_device((const struct usb_devno *)(urtwn_devs), sizeof (urtwn_devs) / sizeof ((urtwn_devs)[0 ]), sizeof ((urtwn_devs)[0]), (uaa->vendor), (uaa->product )))->chip; | |||
| 461 | ||||
| 462 | usb_init_task(&sc->sc_task, urtwn_task, sc, USB_TASK_TYPE_GENERIC)((&sc->sc_task)->fun = (urtwn_task), (&sc->sc_task )->arg = (sc), (&sc->sc_task)->type = (0), (& sc->sc_task)->state = 0x0); | |||
| 463 | timeout_set(&sc->scan_to, urtwn_scan_to, sc); | |||
| 464 | timeout_set(&sc->calib_to, urtwn_calib_to, sc); | |||
| 465 | if (urtwn_open_pipes(sc) != 0) | |||
| ||||
| 466 | return; | |||
| 467 | ||||
| 468 | sc->amrr.amrr_min_success_threshold = 1; | |||
| 469 | sc->amrr.amrr_max_success_threshold = 10; | |||
| 470 | ||||
| 471 | /* Attach the bus-agnostic driver. */ | |||
| 472 | sc->sc_sc.sc_ops.cookie = sc; | |||
| 473 | sc->sc_sc.sc_ops.write_1 = urtwn_write_1; | |||
| 474 | sc->sc_sc.sc_ops.write_2 = urtwn_write_2; | |||
| 475 | sc->sc_sc.sc_ops.write_4 = urtwn_write_4; | |||
| 476 | sc->sc_sc.sc_ops.read_1 = urtwn_read_1; | |||
| 477 | sc->sc_sc.sc_ops.read_2 = urtwn_read_2; | |||
| 478 | sc->sc_sc.sc_ops.read_4 = urtwn_read_4; | |||
| 479 | sc->sc_sc.sc_ops.tx = urtwn_tx; | |||
| 480 | sc->sc_sc.sc_ops.power_on = urtwn_power_on; | |||
| 481 | sc->sc_sc.sc_ops.dma_init = urtwn_dma_init; | |||
| 482 | sc->sc_sc.sc_ops.fw_loadpage = urtwn_fw_loadpage; | |||
| 483 | sc->sc_sc.sc_ops.load_firmware = urtwn_load_firmware; | |||
| 484 | sc->sc_sc.sc_ops.aggr_init = urtwn_aggr_init; | |||
| 485 | sc->sc_sc.sc_ops.mac_init = urtwn_mac_init; | |||
| 486 | sc->sc_sc.sc_ops.bb_init = urtwn_bb_init; | |||
| 487 | sc->sc_sc.sc_ops.alloc_buffers = urtwn_alloc_buffers; | |||
| 488 | sc->sc_sc.sc_ops.init = urtwn_init; | |||
| 489 | sc->sc_sc.sc_ops.stop = urtwn_stop; | |||
| 490 | sc->sc_sc.sc_ops.is_oactive = urtwn_is_oactive; | |||
| 491 | sc->sc_sc.sc_ops.next_calib = urtwn_next_calib; | |||
| 492 | sc->sc_sc.sc_ops.cancel_calib = urtwn_cancel_calib; | |||
| 493 | sc->sc_sc.sc_ops.next_scan = urtwn_next_scan; | |||
| 494 | sc->sc_sc.sc_ops.cancel_scan = urtwn_cancel_scan; | |||
| 495 | sc->sc_sc.sc_ops.wait_async = urtwn_wait_async; | |||
| 496 | if (rtwn_attach(&sc->sc_dev, &sc->sc_sc) != 0) { | |||
| 497 | urtwn_close_pipes(sc); | |||
| 498 | return; | |||
| 499 | } | |||
| 500 | ||||
| 501 | /* ifp is now valid */ | |||
| 502 | ifp = &sc->sc_sc.sc_ic.ic_ific_ac.ac_if; | |||
| 503 | ifp->if_ioctl = urtwn_ioctl; | |||
| 504 | ||||
| 505 | ic->ic_updateslot = urtwn_updateslot; | |||
| 506 | ic->ic_updateedca = urtwn_updateedca; | |||
| 507 | ic->ic_set_key = urtwn_set_key; | |||
| 508 | ic->ic_delete_key = urtwn_delete_key; | |||
| 509 | /* Override state transition machine. */ | |||
| 510 | ic->ic_newstate = urtwn_newstate; | |||
| 511 | ||||
| 512 | #if NBPFILTER1 > 0 | |||
| 513 | bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO127, | |||
| 514 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN64); | |||
| 515 | ||||
| 516 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); | |||
| 517 | sc->sc_rxtapsc_rxtapu.th.wr_ihdr.it_len = htole16(sc->sc_rxtap_len)((__uint16_t)(sc->sc_rxtap_len)); | |||
| 518 | sc->sc_rxtapsc_rxtapu.th.wr_ihdr.it_present = htole32(URTWN_RX_RADIOTAP_PRESENT)((__uint32_t)((1 << IEEE80211_RADIOTAP_FLAGS | 1 << IEEE80211_RADIOTAP_RATE | 1 << IEEE80211_RADIOTAP_CHANNEL | 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL))); | |||
| 519 | ||||
| 520 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); | |||
| 521 | sc->sc_txtapsc_txtapu.th.wt_ihdr.it_len = htole16(sc->sc_txtap_len)((__uint16_t)(sc->sc_txtap_len)); | |||
| 522 | sc->sc_txtapsc_txtapu.th.wt_ihdr.it_present = htole32(URTWN_TX_RADIOTAP_PRESENT)((__uint32_t)((1 << IEEE80211_RADIOTAP_FLAGS | 1 << IEEE80211_RADIOTAP_CHANNEL))); | |||
| 523 | #endif | |||
| 524 | } | |||
| 525 | ||||
| 526 | int | |||
| 527 | urtwn_detach(struct device *self, int flags) | |||
| 528 | { | |||
| 529 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 530 | int s; | |||
| 531 | ||||
| 532 | s = splusb()splraise(0x2); | |||
| 533 | ||||
| 534 | if (timeout_initialized(&sc->scan_to)((&sc->scan_to)->to_flags & 0x04)) | |||
| 535 | timeout_del(&sc->scan_to); | |||
| 536 | if (timeout_initialized(&sc->calib_to)((&sc->calib_to)->to_flags & 0x04)) | |||
| 537 | timeout_del(&sc->calib_to); | |||
| 538 | ||||
| 539 | /* Wait for all async commands to complete. */ | |||
| 540 | usb_rem_wait_task(sc->sc_udev, &sc->sc_task); | |||
| 541 | ||||
| 542 | usbd_ref_wait(sc->sc_udev); | |||
| 543 | ||||
| 544 | rtwn_detach(&sc->sc_sc, flags); | |||
| 545 | ||||
| 546 | /* Abort and close Tx/Rx pipes. */ | |||
| 547 | urtwn_close_pipes(sc); | |||
| 548 | ||||
| 549 | /* Free Tx/Rx buffers. */ | |||
| 550 | urtwn_free_tx_list(sc); | |||
| 551 | urtwn_free_rx_list(sc); | |||
| 552 | splx(s)spllower(s); | |||
| 553 | ||||
| 554 | return (0); | |||
| 555 | } | |||
| 556 | ||||
| 557 | int | |||
| 558 | urtwn_open_pipes(struct urtwn_softc *sc) | |||
| 559 | { | |||
| 560 | /* Bulk-out endpoints addresses (from highest to lowest prio). */ | |||
| 561 | uint8_t epaddr[R92C_MAX_EPOUT3] = { 0, 0, 0 }; | |||
| 562 | uint8_t rx_no; | |||
| 563 | usb_interface_descriptor_t *id; | |||
| 564 | usb_endpoint_descriptor_t *ed; | |||
| 565 | int i, error, nrx = 0; | |||
| 566 | ||||
| 567 | /* Find all bulk endpoints. */ | |||
| 568 | id = usbd_get_interface_descriptor(sc->sc_iface); | |||
| 569 | for (i = 0; i < id->bNumEndpoints; i++) { | |||
| 570 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | |||
| 571 | if (ed == NULL((void *)0) || UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) != UE_BULK0x02) | |||
| 572 | continue; | |||
| 573 | ||||
| 574 | if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80) { | |||
| 575 | rx_no = ed->bEndpointAddress; | |||
| 576 | nrx++; | |||
| 577 | } else { | |||
| 578 | if (sc->ntx < R92C_MAX_EPOUT3) | |||
| 579 | epaddr[sc->ntx] = ed->bEndpointAddress; | |||
| 580 | sc->ntx++; | |||
| 581 | } | |||
| 582 | } | |||
| 583 | if (nrx
| |||
| 584 | printf("%s: %d: invalid number of Rx bulk pipes\n", | |||
| 585 | sc->sc_dev.dv_xname, nrx); | |||
| 586 | return (EIO5); | |||
| 587 | } | |||
| 588 | DPRINTF(("found %d bulk-out pipes\n", sc->ntx)); | |||
| 589 | if (sc->ntx == 0 || sc->ntx > R92C_MAX_EPOUT3) { | |||
| 590 | printf("%s: %d: invalid number of Tx bulk pipes\n", | |||
| 591 | sc->sc_dev.dv_xname, sc->ntx); | |||
| 592 | return (EIO5); | |||
| 593 | } | |||
| 594 | ||||
| 595 | /* Open bulk-in pipe. */ | |||
| 596 | error = usbd_open_pipe(sc->sc_iface, rx_no, 0, &sc->rx_pipe); | |||
| 597 | if (error != 0) { | |||
| 598 | printf("%s: could not open Rx bulk pipe\n", | |||
| 599 | sc->sc_dev.dv_xname); | |||
| 600 | goto fail; | |||
| 601 | } | |||
| 602 | ||||
| 603 | /* Open bulk-out pipes (up to 3). */ | |||
| 604 | for (i = 0; i < sc->ntx; i++) { | |||
| 605 | error = usbd_open_pipe(sc->sc_iface, epaddr[i], 0, | |||
| ||||
| 606 | &sc->tx_pipe[i]); | |||
| 607 | if (error != 0) { | |||
| 608 | printf("%s: could not open Tx bulk pipe 0x%02x\n", | |||
| 609 | sc->sc_dev.dv_xname, epaddr[i]); | |||
| 610 | goto fail; | |||
| 611 | } | |||
| 612 | } | |||
| 613 | ||||
| 614 | /* Map 802.11 access categories to USB pipes. */ | |||
| 615 | sc->ac2idx[EDCA_AC_BK] = | |||
| 616 | sc->ac2idx[EDCA_AC_BE] = (sc->ntx == 3) ? 2 : ((sc->ntx == 2) ? 1 : 0); | |||
| 617 | sc->ac2idx[EDCA_AC_VI] = (sc->ntx == 3) ? 1 : 0; | |||
| 618 | sc->ac2idx[EDCA_AC_VO] = 0; /* Always use highest prio. */ | |||
| 619 | ||||
| 620 | if (error != 0) | |||
| 621 | fail: urtwn_close_pipes(sc); | |||
| 622 | return (error); | |||
| 623 | } | |||
| 624 | ||||
| 625 | void | |||
| 626 | urtwn_close_pipes(struct urtwn_softc *sc) | |||
| 627 | { | |||
| 628 | int i; | |||
| 629 | ||||
| 630 | /* Close Rx pipe. */ | |||
| 631 | if (sc->rx_pipe != NULL((void *)0)) { | |||
| 632 | usbd_close_pipe(sc->rx_pipe); | |||
| 633 | sc->rx_pipe = NULL((void *)0); | |||
| 634 | } | |||
| 635 | /* Close Tx pipes. */ | |||
| 636 | for (i = 0; i < R92C_MAX_EPOUT3; i++) { | |||
| 637 | if (sc->tx_pipe[i] == NULL((void *)0)) | |||
| 638 | continue; | |||
| 639 | usbd_close_pipe(sc->tx_pipe[i]); | |||
| 640 | sc->tx_pipe[i] = NULL((void *)0); | |||
| 641 | } | |||
| 642 | } | |||
| 643 | ||||
| 644 | int | |||
| 645 | urtwn_alloc_rx_list(struct urtwn_softc *sc) | |||
| 646 | { | |||
| 647 | struct urtwn_rx_data *data; | |||
| 648 | int i, error = 0; | |||
| 649 | ||||
| 650 | for (i = 0; i < URTWN_RX_LIST_COUNT1; i++) { | |||
| 651 | data = &sc->rx_data[i]; | |||
| 652 | ||||
| 653 | data->sc = sc; /* Backpointer for callbacks. */ | |||
| 654 | ||||
| 655 | data->xfer = usbd_alloc_xfer(sc->sc_udev); | |||
| 656 | if (data->xfer == NULL((void *)0)) { | |||
| 657 | printf("%s: could not allocate xfer\n", | |||
| 658 | sc->sc_dev.dv_xname); | |||
| 659 | error = ENOMEM12; | |||
| 660 | break; | |||
| 661 | } | |||
| 662 | data->buf = usbd_alloc_buffer(data->xfer, URTWN_RXBUFSZ(16 * 1024)); | |||
| 663 | if (data->buf == NULL((void *)0)) { | |||
| 664 | printf("%s: could not allocate xfer buffer\n", | |||
| 665 | sc->sc_dev.dv_xname); | |||
| 666 | error = ENOMEM12; | |||
| 667 | break; | |||
| 668 | } | |||
| 669 | } | |||
| 670 | if (error != 0) | |||
| 671 | urtwn_free_rx_list(sc); | |||
| 672 | return (error); | |||
| 673 | } | |||
| 674 | ||||
| 675 | void | |||
| 676 | urtwn_free_rx_list(struct urtwn_softc *sc) | |||
| 677 | { | |||
| 678 | int i; | |||
| 679 | ||||
| 680 | /* NB: Caller must abort pipe first. */ | |||
| 681 | for (i = 0; i < URTWN_RX_LIST_COUNT1; i++) { | |||
| 682 | if (sc->rx_data[i].xfer != NULL((void *)0)) | |||
| 683 | usbd_free_xfer(sc->rx_data[i].xfer); | |||
| 684 | sc->rx_data[i].xfer = NULL((void *)0); | |||
| 685 | } | |||
| 686 | } | |||
| 687 | ||||
| 688 | int | |||
| 689 | urtwn_alloc_tx_list(struct urtwn_softc *sc) | |||
| 690 | { | |||
| 691 | struct urtwn_tx_data *data; | |||
| 692 | int i, error = 0; | |||
| 693 | ||||
| 694 | TAILQ_INIT(&sc->tx_free_list)do { (&sc->tx_free_list)->tqh_first = ((void *)0); ( &sc->tx_free_list)->tqh_last = &(&sc->tx_free_list )->tqh_first; } while (0); | |||
| 695 | for (i = 0; i < URTWN_TX_LIST_COUNT8; i++) { | |||
| 696 | data = &sc->tx_data[i]; | |||
| 697 | ||||
| 698 | data->sc = sc; /* Backpointer for callbacks. */ | |||
| 699 | ||||
| 700 | data->xfer = usbd_alloc_xfer(sc->sc_udev); | |||
| 701 | if (data->xfer == NULL((void *)0)) { | |||
| 702 | printf("%s: could not allocate xfer\n", | |||
| 703 | sc->sc_dev.dv_xname); | |||
| 704 | error = ENOMEM12; | |||
| 705 | break; | |||
| 706 | } | |||
| 707 | data->buf = usbd_alloc_buffer(data->xfer, URTWN_TXBUFSZ(sizeof(struct r92e_tx_desc_usb) + (2300 + 4 + (3 + 1 + 4)))); | |||
| 708 | if (data->buf == NULL((void *)0)) { | |||
| 709 | printf("%s: could not allocate xfer buffer\n", | |||
| 710 | sc->sc_dev.dv_xname); | |||
| 711 | error = ENOMEM12; | |||
| 712 | break; | |||
| 713 | } | |||
| 714 | /* Append this Tx buffer to our free list. */ | |||
| 715 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next)do { (data)->next.tqe_next = ((void *)0); (data)->next. tqe_prev = (&sc->tx_free_list)->tqh_last; *(&sc ->tx_free_list)->tqh_last = (data); (&sc->tx_free_list )->tqh_last = &(data)->next.tqe_next; } while (0); | |||
| 716 | } | |||
| 717 | if (error != 0) | |||
| 718 | urtwn_free_tx_list(sc); | |||
| 719 | return (error); | |||
| 720 | } | |||
| 721 | ||||
| 722 | void | |||
| 723 | urtwn_free_tx_list(struct urtwn_softc *sc) | |||
| 724 | { | |||
| 725 | int i; | |||
| 726 | ||||
| 727 | /* NB: Caller must abort pipe first. */ | |||
| 728 | for (i = 0; i < URTWN_TX_LIST_COUNT8; i++) { | |||
| 729 | if (sc->tx_data[i].xfer != NULL((void *)0)) | |||
| 730 | usbd_free_xfer(sc->tx_data[i].xfer); | |||
| 731 | sc->tx_data[i].xfer = NULL((void *)0); | |||
| 732 | } | |||
| 733 | } | |||
| 734 | ||||
| 735 | void | |||
| 736 | urtwn_task(void *arg) | |||
| 737 | { | |||
| 738 | struct urtwn_softc *sc = arg; | |||
| 739 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | |||
| 740 | struct urtwn_host_cmd *cmd; | |||
| 741 | int s; | |||
| 742 | ||||
| 743 | /* Process host commands. */ | |||
| 744 | s = splusb()splraise(0x2); | |||
| 745 | while (ring->next != ring->cur) { | |||
| 746 | cmd = &ring->cmd[ring->next]; | |||
| 747 | splx(s)spllower(s); | |||
| 748 | /* Invoke callback. */ | |||
| 749 | cmd->cb(sc, cmd->data); | |||
| 750 | s = splusb()splraise(0x2); | |||
| 751 | ring->queued--; | |||
| 752 | ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT32; | |||
| 753 | } | |||
| 754 | splx(s)spllower(s); | |||
| 755 | } | |||
| 756 | ||||
| 757 | void | |||
| 758 | urtwn_do_async(struct urtwn_softc *sc, | |||
| 759 | void (*cb)(struct urtwn_softc *, void *), void *arg, int len) | |||
| 760 | { | |||
| 761 | struct urtwn_host_cmd_ring *ring = &sc->cmdq; | |||
| 762 | struct urtwn_host_cmd *cmd; | |||
| 763 | int s; | |||
| 764 | ||||
| 765 | s = splusb()splraise(0x2); | |||
| 766 | cmd = &ring->cmd[ring->cur]; | |||
| 767 | cmd->cb = cb; | |||
| 768 | KASSERT(len <= sizeof(cmd->data))((len <= sizeof(cmd->data)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/usb/if_urtwn.c", 768, "len <= sizeof(cmd->data)" )); | |||
| 769 | memcpy(cmd->data, arg, len)__builtin_memcpy((cmd->data), (arg), (len)); | |||
| 770 | ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT32; | |||
| 771 | ||||
| 772 | /* If there is no pending command already, schedule a task. */ | |||
| 773 | if (++ring->queued == 1) | |||
| 774 | usb_add_task(sc->sc_udev, &sc->sc_task); | |||
| 775 | splx(s)spllower(s); | |||
| 776 | } | |||
| 777 | ||||
| 778 | void | |||
| 779 | urtwn_wait_async(void *cookie) | |||
| 780 | { | |||
| 781 | struct urtwn_softc *sc = cookie; | |||
| 782 | int s; | |||
| 783 | ||||
| 784 | s = splusb()splraise(0x2); | |||
| 785 | /* Wait for all queued asynchronous commands to complete. */ | |||
| 786 | usb_wait_task(sc->sc_udev, &sc->sc_task); | |||
| 787 | splx(s)spllower(s); | |||
| 788 | } | |||
| 789 | ||||
| 790 | int | |||
| 791 | urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | |||
| 792 | int len) | |||
| 793 | { | |||
| 794 | usb_device_request_t req; | |||
| 795 | ||||
| 796 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00); | |||
| 797 | req.bRequest = R92C_REQ_REGS0x05; | |||
| 798 | USETW(req.wValue, addr)(*(u_int16_t *)(req.wValue) = (addr)); | |||
| 799 | USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0)); | |||
| 800 | USETW(req.wLength, len)(*(u_int16_t *)(req.wLength) = (len)); | |||
| 801 | return (usbd_do_request(sc->sc_udev, &req, buf)); | |||
| 802 | } | |||
| 803 | ||||
| 804 | void | |||
| 805 | urtwn_write_1(void *cookie, uint16_t addr, uint8_t val) | |||
| 806 | { | |||
| 807 | struct urtwn_softc *sc = cookie; | |||
| 808 | ||||
| 809 | urtwn_write_region_1(sc, addr, &val, 1); | |||
| 810 | } | |||
| 811 | ||||
| 812 | void | |||
| 813 | urtwn_write_2(void *cookie, uint16_t addr, uint16_t val) | |||
| 814 | { | |||
| 815 | struct urtwn_softc *sc = cookie; | |||
| 816 | ||||
| 817 | val = htole16(val)((__uint16_t)(val)); | |||
| 818 | urtwn_write_region_1(sc, addr, (uint8_t *)&val, 2); | |||
| 819 | } | |||
| 820 | ||||
| 821 | void | |||
| 822 | urtwn_write_4(void *cookie, uint16_t addr, uint32_t val) | |||
| 823 | { | |||
| 824 | struct urtwn_softc *sc = cookie; | |||
| 825 | ||||
| 826 | val = htole32(val)((__uint32_t)(val)); | |||
| 827 | urtwn_write_region_1(sc, addr, (uint8_t *)&val, 4); | |||
| 828 | } | |||
| 829 | ||||
| 830 | int | |||
| 831 | urtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, | |||
| 832 | int len) | |||
| 833 | { | |||
| 834 | usb_device_request_t req; | |||
| 835 | ||||
| 836 | req.bmRequestType = UT_READ_VENDOR_DEVICE(0x80 | 0x40 | 0x00); | |||
| 837 | req.bRequest = R92C_REQ_REGS0x05; | |||
| 838 | USETW(req.wValue, addr)(*(u_int16_t *)(req.wValue) = (addr)); | |||
| 839 | USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0)); | |||
| 840 | USETW(req.wLength, len)(*(u_int16_t *)(req.wLength) = (len)); | |||
| 841 | return (usbd_do_request(sc->sc_udev, &req, buf)); | |||
| 842 | } | |||
| 843 | ||||
| 844 | uint8_t | |||
| 845 | urtwn_read_1(void *cookie, uint16_t addr) | |||
| 846 | { | |||
| 847 | struct urtwn_softc *sc = cookie; | |||
| 848 | uint8_t val; | |||
| 849 | ||||
| 850 | if (urtwn_read_region_1(sc, addr, &val, 1) != 0) | |||
| 851 | return (0xff); | |||
| 852 | return (val); | |||
| 853 | } | |||
| 854 | ||||
| 855 | uint16_t | |||
| 856 | urtwn_read_2(void *cookie, uint16_t addr) | |||
| 857 | { | |||
| 858 | struct urtwn_softc *sc = cookie; | |||
| 859 | uint16_t val; | |||
| 860 | ||||
| 861 | if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) | |||
| 862 | return (0xffff); | |||
| 863 | return (letoh16(val)((__uint16_t)(val))); | |||
| 864 | } | |||
| 865 | ||||
| 866 | uint32_t | |||
| 867 | urtwn_read_4(void *cookie, uint16_t addr) | |||
| 868 | { | |||
| 869 | struct urtwn_softc *sc = cookie; | |||
| 870 | uint32_t val; | |||
| 871 | ||||
| 872 | if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) | |||
| 873 | return (0xffffffff); | |||
| 874 | return (letoh32(val)((__uint32_t)(val))); | |||
| 875 | } | |||
| 876 | ||||
| 877 | int | |||
| 878 | urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) | |||
| 879 | { | |||
| 880 | int ntries; | |||
| 881 | ||||
| 882 | urtwn_write_4(sc, R92C_LLT_INIT0x1e0, | |||
| 883 | SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE)(((1) << 30) & 0xc0000000) | | |||
| 884 | SM(R92C_LLT_INIT_ADDR, addr)(((addr) << 8) & 0x0000ff00) | | |||
| 885 | SM(R92C_LLT_INIT_DATA, data)(((data) << 0) & 0x000000ff)); | |||
| 886 | /* Wait for write operation to complete. */ | |||
| 887 | for (ntries = 0; ntries < 20; ntries++) { | |||
| 888 | if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP)(((urtwn_read_4(sc, 0x1e0)) & 0xc0000000) >> 30) == | |||
| 889 | R92C_LLT_INIT_OP_NO_ACTIVE0) | |||
| 890 | return (0); | |||
| 891 | DELAY(5)(*delay_func)(5); | |||
| 892 | } | |||
| 893 | return (ETIMEDOUT60); | |||
| 894 | } | |||
| 895 | ||||
| 896 | void | |||
| 897 | urtwn_calib_to(void *arg) | |||
| 898 | { | |||
| 899 | struct urtwn_softc *sc = arg; | |||
| 900 | ||||
| 901 | if (usbd_is_dying(sc->sc_udev)) | |||
| 902 | return; | |||
| 903 | ||||
| 904 | usbd_ref_incr(sc->sc_udev); | |||
| 905 | ||||
| 906 | /* Do it in a process context. */ | |||
| 907 | urtwn_do_async(sc, urtwn_calib_cb, NULL((void *)0), 0); | |||
| 908 | ||||
| 909 | usbd_ref_decr(sc->sc_udev); | |||
| 910 | } | |||
| 911 | ||||
| 912 | void | |||
| 913 | urtwn_calib_cb(struct urtwn_softc *sc, void *arg) | |||
| 914 | { | |||
| 915 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 916 | int s; | |||
| 917 | ||||
| 918 | s = splnet()splraise(0x4); | |||
| 919 | if (ic->ic_opmode == IEEE80211_M_STA) { | |||
| 920 | ieee80211_amrr_choose(&sc->amrr, ic->ic_bss, &sc->amn); | |||
| 921 | } | |||
| 922 | splx(s)spllower(s); | |||
| 923 | ||||
| 924 | rtwn_calib(&sc->sc_sc); | |||
| 925 | } | |||
| 926 | ||||
| 927 | void | |||
| 928 | urtwn_next_calib(void *cookie) | |||
| 929 | { | |||
| 930 | struct urtwn_softc *sc = cookie; | |||
| 931 | ||||
| 932 | if (!usbd_is_dying(sc->sc_udev)) | |||
| 933 | timeout_add_sec(&sc->calib_to, 2); | |||
| 934 | } | |||
| 935 | ||||
| 936 | void | |||
| 937 | urtwn_cancel_calib(void *cookie) | |||
| 938 | { | |||
| 939 | struct urtwn_softc *sc = cookie; | |||
| 940 | ||||
| 941 | if (timeout_initialized(&sc->calib_to)((&sc->calib_to)->to_flags & 0x04)) | |||
| 942 | timeout_del(&sc->calib_to); | |||
| 943 | } | |||
| 944 | ||||
| 945 | void | |||
| 946 | urtwn_scan_to(void *arg) | |||
| 947 | { | |||
| 948 | struct urtwn_softc *sc = arg; | |||
| 949 | ||||
| 950 | if (usbd_is_dying(sc->sc_udev)) | |||
| 951 | return; | |||
| 952 | ||||
| 953 | usbd_ref_incr(sc->sc_udev); | |||
| 954 | rtwn_next_scan(&sc->sc_sc); | |||
| 955 | usbd_ref_decr(sc->sc_udev); | |||
| 956 | } | |||
| 957 | ||||
| 958 | void | |||
| 959 | urtwn_next_scan(void *arg) | |||
| 960 | { | |||
| 961 | struct urtwn_softc *sc = arg; | |||
| 962 | ||||
| 963 | if (!usbd_is_dying(sc->sc_udev)) | |||
| 964 | timeout_add_msec(&sc->scan_to, 200); | |||
| 965 | } | |||
| 966 | ||||
| 967 | void | |||
| 968 | urtwn_cancel_scan(void *cookie) | |||
| 969 | { | |||
| 970 | struct urtwn_softc *sc = cookie; | |||
| 971 | ||||
| 972 | if (timeout_initialized(&sc->scan_to)((&sc->scan_to)->to_flags & 0x04)) | |||
| 973 | timeout_del(&sc->scan_to); | |||
| 974 | } | |||
| 975 | ||||
| 976 | int | |||
| 977 | urtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | |||
| 978 | { | |||
| 979 | struct rtwn_softc *sc_sc = ic->ic_softcic_ac.ac_if.if_softc; | |||
| 980 | struct device *self = sc_sc->sc_pdev; | |||
| 981 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 982 | struct urtwn_cmd_newstate cmd; | |||
| 983 | ||||
| 984 | /* Do it in a process context. */ | |||
| 985 | cmd.state = nstate; | |||
| 986 | cmd.arg = arg; | |||
| 987 | urtwn_do_async(sc, urtwn_newstate_cb, &cmd, sizeof(cmd)); | |||
| 988 | return (0); | |||
| 989 | } | |||
| 990 | ||||
| 991 | void | |||
| 992 | urtwn_newstate_cb(struct urtwn_softc *sc, void *arg) | |||
| 993 | { | |||
| 994 | struct urtwn_cmd_newstate *cmd = arg; | |||
| 995 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 996 | ||||
| 997 | rtwn_newstate(ic, cmd->state, cmd->arg); | |||
| 998 | } | |||
| 999 | ||||
| 1000 | void | |||
| 1001 | urtwn_updateslot(struct ieee80211com *ic) | |||
| 1002 | { | |||
| 1003 | struct rtwn_softc *sc_sc = ic->ic_softcic_ac.ac_if.if_softc; | |||
| 1004 | struct device *self = sc_sc->sc_pdev; | |||
| 1005 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 1006 | ||||
| 1007 | /* Do it in a process context. */ | |||
| 1008 | urtwn_do_async(sc, urtwn_updateslot_cb, NULL((void *)0), 0); | |||
| 1009 | } | |||
| 1010 | ||||
| 1011 | void | |||
| 1012 | urtwn_updateslot_cb(struct urtwn_softc *sc, void *arg) | |||
| 1013 | { | |||
| 1014 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1015 | ||||
| 1016 | rtwn_updateslot(ic); | |||
| 1017 | } | |||
| 1018 | ||||
| 1019 | void | |||
| 1020 | urtwn_updateedca(struct ieee80211com *ic) | |||
| 1021 | { | |||
| 1022 | struct rtwn_softc *sc_sc = ic->ic_softcic_ac.ac_if.if_softc; | |||
| 1023 | struct device *self = sc_sc->sc_pdev; | |||
| 1024 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 1025 | ||||
| 1026 | /* Do it in a process context. */ | |||
| 1027 | urtwn_do_async(sc, urtwn_updateedca_cb, NULL((void *)0), 0); | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | void | |||
| 1031 | urtwn_updateedca_cb(struct urtwn_softc *sc, void *arg) | |||
| 1032 | { | |||
| 1033 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1034 | ||||
| 1035 | rtwn_updateedca(ic); | |||
| 1036 | } | |||
| 1037 | ||||
| 1038 | int | |||
| 1039 | urtwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, | |||
| 1040 | struct ieee80211_key *k) | |||
| 1041 | { | |||
| 1042 | struct rtwn_softc *sc_sc = ic->ic_softcic_ac.ac_if.if_softc; | |||
| 1043 | struct device *self = sc_sc->sc_pdev; | |||
| 1044 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 1045 | struct urtwn_cmd_key cmd; | |||
| 1046 | ||||
| 1047 | /* Only handle keys for CCMP */ | |||
| 1048 | if (k->k_cipher != IEEE80211_CIPHER_CCMP) | |||
| 1049 | return ieee80211_set_key(ic, ni, k); | |||
| 1050 | ||||
| 1051 | /* Defer setting of WEP keys until interface is brought up. */ | |||
| 1052 | if ((ic->ic_ific_ac.ac_if.if_flags & (IFF_UP0x1 | IFF_RUNNING0x40)) != | |||
| 1053 | (IFF_UP0x1 | IFF_RUNNING0x40)) | |||
| 1054 | return (0); | |||
| 1055 | ||||
| 1056 | /* Do it in a process context. */ | |||
| 1057 | cmd.key = *k; | |||
| 1058 | cmd.ni = ni; | |||
| 1059 | urtwn_do_async(sc, urtwn_set_key_cb, &cmd, sizeof(cmd)); | |||
| 1060 | sc->sc_key_tasks++; | |||
| 1061 | ||||
| 1062 | return (EBUSY16); | |||
| 1063 | } | |||
| 1064 | ||||
| 1065 | void | |||
| 1066 | urtwn_set_key_cb(struct urtwn_softc *sc, void *arg) | |||
| 1067 | { | |||
| 1068 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1069 | struct urtwn_cmd_key *cmd = arg; | |||
| 1070 | ||||
| 1071 | sc->sc_key_tasks--; | |||
| 1072 | ||||
| 1073 | if (rtwn_set_key(ic, cmd->ni, &cmd->key) == 0) { | |||
| 1074 | if (sc->sc_key_tasks == 0) { | |||
| 1075 | DPRINTF(("marking port %s valid\n", | |||
| 1076 | ether_sprintf(cmd->ni->ni_macaddr))); | |||
| 1077 | cmd->ni->ni_port_valid = 1; | |||
| 1078 | ieee80211_set_link_state(ic, LINK_STATE_UP4); | |||
| 1079 | } | |||
| 1080 | } else { | |||
| 1081 | IEEE80211_SEND_MGMT(ic, cmd->ni, IEEE80211_FC0_SUBTYPE_DEAUTH,((*(ic)->ic_send_mgmt)(ic, cmd->ni, 0xc0, IEEE80211_REASON_AUTH_LEAVE , 0)) | |||
| 1082 | IEEE80211_REASON_AUTH_LEAVE)((*(ic)->ic_send_mgmt)(ic, cmd->ni, 0xc0, IEEE80211_REASON_AUTH_LEAVE , 0)); | |||
| 1083 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_SCAN), (-1))); | |||
| 1084 | } | |||
| 1085 | } | |||
| 1086 | ||||
| 1087 | void | |||
| 1088 | urtwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, | |||
| 1089 | struct ieee80211_key *k) | |||
| 1090 | { | |||
| 1091 | struct rtwn_softc *sc_sc = ic->ic_softcic_ac.ac_if.if_softc; | |||
| 1092 | struct device *self = sc_sc->sc_pdev; | |||
| 1093 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 1094 | struct urtwn_cmd_key cmd; | |||
| 1095 | ||||
| 1096 | /* Only handle keys for CCMP */ | |||
| 1097 | if (k->k_cipher != IEEE80211_CIPHER_CCMP) { | |||
| 1098 | ieee80211_delete_key(ic, ni, k); | |||
| 1099 | return; | |||
| 1100 | } | |||
| 1101 | ||||
| 1102 | if (!(ic->ic_ific_ac.ac_if.if_flags & IFF_RUNNING0x40) || | |||
| 1103 | ic->ic_state != IEEE80211_S_RUN) | |||
| 1104 | return; /* Nothing to do. */ | |||
| 1105 | ||||
| 1106 | /* Do it in a process context. */ | |||
| 1107 | cmd.key = *k; | |||
| 1108 | cmd.ni = ni; | |||
| 1109 | urtwn_do_async(sc, urtwn_delete_key_cb, &cmd, sizeof(cmd)); | |||
| 1110 | } | |||
| 1111 | ||||
| 1112 | void | |||
| 1113 | urtwn_delete_key_cb(struct urtwn_softc *sc, void *arg) | |||
| 1114 | { | |||
| 1115 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1116 | struct urtwn_cmd_key *cmd = arg; | |||
| 1117 | ||||
| 1118 | rtwn_delete_key(ic, cmd->ni, &cmd->key); | |||
| 1119 | } | |||
| 1120 | ||||
| 1121 | int | |||
| 1122 | urtwn_ccmp_decap(struct urtwn_softc *sc, struct mbuf *m, | |||
| 1123 | struct ieee80211_node *ni) | |||
| 1124 | { | |||
| 1125 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1126 | struct ieee80211_key *k; | |||
| 1127 | struct ieee80211_frame *wh; | |||
| 1128 | uint64_t pn, *prsc; | |||
| 1129 | uint8_t *ivp; | |||
| 1130 | uint8_t tid; | |||
| 1131 | int hdrlen, hasqos; | |||
| 1132 | ||||
| 1133 | k = ieee80211_get_rxkey(ic, m, ni); | |||
| 1134 | if (k == NULL((void *)0)) | |||
| 1135 | return 1; | |||
| 1136 | ||||
| 1137 | wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data)); | |||
| 1138 | hdrlen = ieee80211_get_hdrlen(wh); | |||
| 1139 | ivp = (uint8_t *)wh + hdrlen; | |||
| 1140 | ||||
| 1141 | /* Check that ExtIV bit is set. */ | |||
| 1142 | if (!(ivp[3] & IEEE80211_WEP_EXTIV0x20)) | |||
| 1143 | return 1; | |||
| 1144 | ||||
| 1145 | hasqos = ieee80211_has_qos(wh); | |||
| 1146 | tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID0x000f : 0; | |||
| 1147 | prsc = &k->k_rsc[tid]; | |||
| 1148 | ||||
| 1149 | /* Extract the 48-bit PN from the CCMP header. */ | |||
| 1150 | pn = (uint64_t)ivp[0] | | |||
| 1151 | (uint64_t)ivp[1] << 8 | | |||
| 1152 | (uint64_t)ivp[4] << 16 | | |||
| 1153 | (uint64_t)ivp[5] << 24 | | |||
| 1154 | (uint64_t)ivp[6] << 32 | | |||
| 1155 | (uint64_t)ivp[7] << 40; | |||
| 1156 | if (pn <= *prsc) { | |||
| 1157 | ic->ic_stats.is_ccmp_replays++; | |||
| 1158 | return 1; | |||
| 1159 | } | |||
| 1160 | /* Last seen packet number is updated in ieee80211_inputm(). */ | |||
| 1161 | ||||
| 1162 | /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ | |||
| 1163 | m_adj(m, -IEEE80211_CCMP_MICLEN8); | |||
| 1164 | return 0; | |||
| 1165 | } | |||
| 1166 | ||||
| 1167 | void | |||
| 1168 | urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, | |||
| 1169 | struct mbuf_list *ml) | |||
| 1170 | { | |||
| 1171 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1172 | struct ifnet *ifp = &ic->ic_ific_ac.ac_if; | |||
| 1173 | struct ieee80211_rxinfo rxi; | |||
| 1174 | struct ieee80211_frame *wh; | |||
| 1175 | struct ieee80211_node *ni; | |||
| 1176 | struct r92c_rx_desc_usb *rxd; | |||
| 1177 | uint32_t rxdw0, rxdw3; | |||
| 1178 | struct mbuf *m; | |||
| 1179 | uint8_t rate; | |||
| 1180 | int8_t rssi = 0; | |||
| 1181 | int s, infosz; | |||
| 1182 | ||||
| 1183 | rxd = (struct r92c_rx_desc_usb *)buf; | |||
| 1184 | rxdw0 = letoh32(rxd->rxdw0)((__uint32_t)(rxd->rxdw0)); | |||
| 1185 | rxdw3 = letoh32(rxd->rxdw3)((__uint32_t)(rxd->rxdw3)); | |||
| 1186 | ||||
| 1187 | if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))__builtin_expect(((rxdw0 & (0x00004000 | 0x00008000)) != 0 ), 0)) { | |||
| 1188 | /* | |||
| 1189 | * This should not happen since we setup our Rx filter | |||
| 1190 | * to not receive these frames. | |||
| 1191 | */ | |||
| 1192 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 1193 | return; | |||
| 1194 | } | |||
| 1195 | if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)__builtin_expect(((pktlen < sizeof(*wh) || pktlen > (1 << 11)) != 0), 0)) { | |||
| 1196 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 1197 | return; | |||
| 1198 | } | |||
| 1199 | ||||
| 1200 | rate = (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) ? | |||
| 1201 | MS(rxdw3, R92E_RXDW3_RATE)(((rxdw3) & 0x0000007f) >> 0) : MS(rxdw3, R92C_RXDW3_RATE)(((rxdw3) & 0x0000003f) >> 0); | |||
| 1202 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ)(((rxdw0) & 0x000f0000) >> 16) * 8; | |||
| 1203 | ||||
| 1204 | /* Get RSSI from PHY status descriptor if present. */ | |||
| 1205 | if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST0x04000000)) { | |||
| 1206 | rssi = rtwn_get_rssi(&sc->sc_sc, rate, &rxd[1]); | |||
| 1207 | /* Update our average RSSI. */ | |||
| 1208 | rtwn_update_avgrssi(&sc->sc_sc, rate, rssi); | |||
| 1209 | } | |||
| 1210 | ||||
| 1211 | DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d rssi=%d\n", | |||
| 1212 | pktlen, rate, infosz, rssi)); | |||
| 1213 | ||||
| 1214 | MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1)); | |||
| 1215 | if (__predict_false(m == NULL)__builtin_expect(((m == ((void *)0)) != 0), 0)) { | |||
| 1216 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 1217 | return; | |||
| 1218 | } | |||
| 1219 | if (pktlen > MHLEN((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr))) { | |||
| 1220 | MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11)); | |||
| 1221 | if (__predict_false(!(m->m_flags & M_EXT))__builtin_expect(((!(m->m_hdr.mh_flags & 0x0001)) != 0 ), 0)) { | |||
| 1222 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 1223 | m_freem(m); | |||
| 1224 | return; | |||
| 1225 | } | |||
| 1226 | } | |||
| 1227 | /* Finalize mbuf. */ | |||
| 1228 | wh = (struct ieee80211_frame *)((uint8_t *)&rxd[1] + infosz); | |||
| 1229 | memcpy(mtod(m, uint8_t *), wh, pktlen)__builtin_memcpy((((uint8_t *)((m)->m_hdr.mh_data))), (wh) , (pktlen)); | |||
| 1230 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pktlen; | |||
| 1231 | ||||
| 1232 | s = splnet()splraise(0x4); | |||
| 1233 | #if NBPFILTER1 > 0 | |||
| 1234 | if (__predict_false(sc->sc_drvbpf != NULL)__builtin_expect(((sc->sc_drvbpf != ((void *)0)) != 0), 0)) { | |||
| 1235 | struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtapsc_rxtapu.th; | |||
| 1236 | struct mbuf mb; | |||
| 1237 | ||||
| 1238 | tap->wr_flags = 0; | |||
| 1239 | /* Map HW rate index to 802.11 rate. */ | |||
| 1240 | if (!(rxdw3 & R92C_RXDW3_HT0x00000040)) { | |||
| 1241 | switch (rate) { | |||
| 1242 | /* CCK. */ | |||
| 1243 | case 0: tap->wr_rate = 2; break; | |||
| 1244 | case 1: tap->wr_rate = 4; break; | |||
| 1245 | case 2: tap->wr_rate = 11; break; | |||
| 1246 | case 3: tap->wr_rate = 22; break; | |||
| 1247 | /* OFDM. */ | |||
| 1248 | case 4: tap->wr_rate = 12; break; | |||
| 1249 | case 5: tap->wr_rate = 18; break; | |||
| 1250 | case 6: tap->wr_rate = 24; break; | |||
| 1251 | case 7: tap->wr_rate = 36; break; | |||
| 1252 | case 8: tap->wr_rate = 48; break; | |||
| 1253 | case 9: tap->wr_rate = 72; break; | |||
| 1254 | case 10: tap->wr_rate = 96; break; | |||
| 1255 | case 11: tap->wr_rate = 108; break; | |||
| 1256 | } | |||
| 1257 | if (rate <= 3) | |||
| 1258 | tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE0x02; | |||
| 1259 | } else if (rate >= 12) { /* MCS0~15. */ | |||
| 1260 | /* Bit 7 set means HT MCS instead of rate. */ | |||
| 1261 | tap->wr_rate = 0x80 | (rate - 12); | |||
| 1262 | } | |||
| 1263 | tap->wr_dbm_antsignal = rssi; | |||
| 1264 | tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq)((__uint16_t)(ic->ic_ibss_chan->ic_freq)); | |||
| 1265 | tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags)((__uint16_t)(ic->ic_ibss_chan->ic_flags)); | |||
| 1266 | ||||
| 1267 | mb.m_datam_hdr.mh_data = (caddr_t)tap; | |||
| 1268 | mb.m_lenm_hdr.mh_len = sc->sc_rxtap_len; | |||
| 1269 | mb.m_nextm_hdr.mh_next = m; | |||
| 1270 | mb.m_nextpktm_hdr.mh_nextpkt = NULL((void *)0); | |||
| 1271 | mb.m_typem_hdr.mh_type = 0; | |||
| 1272 | mb.m_flagsm_hdr.mh_flags = 0; | |||
| 1273 | bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN(1 << 0)); | |||
| 1274 | } | |||
| 1275 | #endif | |||
| 1276 | ||||
| 1277 | ni = ieee80211_find_rxnode(ic, wh); | |||
| 1278 | memset(&rxi, 0, sizeof(rxi))__builtin_memset((&rxi), (0), (sizeof(rxi))); | |||
| 1279 | rxi.rxi_rssi = rssi; | |||
| 1280 | ||||
| 1281 | /* Handle hardware decryption. */ | |||
| 1282 | if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK0x0c) != IEEE80211_FC0_TYPE_CTL0x04) | |||
| 1283 | && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED0x40) && | |||
| 1284 | (ni->ni_flags & IEEE80211_NODE_RXPROT0x0008) && | |||
| 1285 | ((!IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01) && | |||
| 1286 | ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) || | |||
| 1287 | (IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01) && | |||
| 1288 | ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP))) { | |||
| 1289 | if (urtwn_ccmp_decap(sc, m, ni) != 0) { | |||
| 1290 | ifp->if_ierrorsif_data.ifi_ierrors++; | |||
| 1291 | m_freem(m); | |||
| 1292 | ieee80211_release_node(ic, ni); | |||
| 1293 | splx(s)spllower(s); | |||
| 1294 | return; | |||
| 1295 | } | |||
| 1296 | rxi.rxi_flags |= IEEE80211_RXI_HWDEC0x00000001; | |||
| 1297 | } | |||
| 1298 | ||||
| 1299 | ieee80211_inputm(ifp, m, ni, &rxi, ml); | |||
| 1300 | /* Node is no longer needed. */ | |||
| 1301 | ieee80211_release_node(ic, ni); | |||
| 1302 | splx(s)spllower(s); | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | void | |||
| 1306 | urtwn_rxeof(struct usbd_xfer *xfer, void *priv, | |||
| 1307 | usbd_status status) | |||
| 1308 | { | |||
| 1309 | struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 }; | |||
| 1310 | struct urtwn_rx_data *data = priv; | |||
| 1311 | struct urtwn_softc *sc = data->sc; | |||
| 1312 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1313 | struct r92c_rx_desc_usb *rxd; | |||
| 1314 | uint32_t rxdw0; | |||
| 1315 | uint8_t *buf; | |||
| 1316 | int len, totlen, pktlen, infosz, npkts, error, align; | |||
| 1317 | ||||
| 1318 | if (__predict_false(status != USBD_NORMAL_COMPLETION)__builtin_expect(((status != USBD_NORMAL_COMPLETION) != 0), 0 )) { | |||
| 1319 | DPRINTF(("RX status=%d\n", status)); | |||
| 1320 | if (status == USBD_STALLED) | |||
| 1321 | usbd_clear_endpoint_stall_async(sc->rx_pipe); | |||
| 1322 | if (status != USBD_CANCELLED) | |||
| 1323 | goto resubmit; | |||
| 1324 | return; | |||
| 1325 | } | |||
| 1326 | usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &len, NULL((void *)0)); | |||
| 1327 | ||||
| 1328 | if (__predict_false(len < sizeof(*rxd))__builtin_expect(((len < sizeof(*rxd)) != 0), 0)) { | |||
| 1329 | DPRINTF(("xfer too short %d\n", len)); | |||
| 1330 | goto resubmit; | |||
| 1331 | } | |||
| 1332 | buf = data->buf; | |||
| 1333 | ||||
| 1334 | /* Get the number of encapsulated frames. */ | |||
| 1335 | rxd = (struct r92c_rx_desc_usb *)buf; | |||
| 1336 | npkts = MS(letoh32(rxd->rxdw2), R92C_RXDW2_PKTCNT)(((((__uint32_t)(rxd->rxdw2))) & 0x00ff0000) >> 16 ); | |||
| 1337 | DPRINTFN(4, ("Rx %d frames in one chunk\n", npkts)); | |||
| 1338 | ||||
| 1339 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) { | |||
| 1340 | int ntries, type; | |||
| 1341 | struct r88e_tx_rpt_ccx *rxstat; | |||
| 1342 | ||||
| 1343 | type = MS(letoh32(rxd->rxdw3), R88E_RXDW3_RPT)(((((__uint32_t)(rxd->rxdw3))) & 0x0000c000) >> 14 ); | |||
| 1344 | ||||
| 1345 | if (type == R88E_RXDW3_RPT_TX11) { | |||
| 1346 | buf += sizeof(struct r92c_rx_desc_usb); | |||
| 1347 | rxstat = (struct r88e_tx_rpt_ccx *)buf; | |||
| 1348 | ntries = MS(letoh32(rxstat->rptb2),(((((__uint32_t)(rxstat->rptb2))) & 0x3f) >> 0) | |||
| 1349 | R88E_RPTB2_RETRY_CNT)(((((__uint32_t)(rxstat->rptb2))) & 0x3f) >> 0); | |||
| 1350 | ||||
| 1351 | if (rxstat->rptb1 & R88E_RPTB1_PKT_OK0x40) | |||
| 1352 | sc->amn.amn_txcnt++; | |||
| 1353 | if (ntries > 0) | |||
| 1354 | sc->amn.amn_retrycnt++; | |||
| 1355 | ||||
| 1356 | goto resubmit; | |||
| 1357 | } | |||
| 1358 | } else if (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) { | |||
| 1359 | int type; | |||
| 1360 | struct r92e_c2h_tx_rpt *txrpt; | |||
| 1361 | ||||
| 1362 | if (letoh32(rxd->rxdw2)((__uint32_t)(rxd->rxdw2)) & R92E_RXDW2_RPT_C2H0x10000000) { | |||
| 1363 | if (len < sizeof(struct r92c_rx_desc_usb) + 2) | |||
| 1364 | goto resubmit; | |||
| 1365 | ||||
| 1366 | type = buf[sizeof(struct r92c_rx_desc_usb)]; | |||
| 1367 | switch (type) { | |||
| 1368 | case R92C_C2HEVT_TX_REPORT3: | |||
| 1369 | buf += sizeof(struct r92c_rx_desc_usb) + 2; | |||
| 1370 | txrpt = (struct r92e_c2h_tx_rpt *)buf; | |||
| 1371 | if (MS(txrpt->rptb2, R92E_RPTB2_RETRY_CNT)(((txrpt->rptb2) & 0x3f) >> 0) > 0) | |||
| 1372 | sc->amn.amn_retrycnt++; | |||
| 1373 | if ((txrpt->rptb0 & (R92E_RPTB0_RETRY_OVER0x80 | | |||
| 1374 | R92E_RPTB0_LIFE_EXPIRE0x40)) == 0) | |||
| 1375 | sc->amn.amn_txcnt++; | |||
| 1376 | break; | |||
| 1377 | default: | |||
| 1378 | break; | |||
| 1379 | } | |||
| 1380 | goto resubmit; | |||
| 1381 | } | |||
| 1382 | } | |||
| 1383 | ||||
| 1384 | align = ((sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) ? 7 : 127); | |||
| 1385 | ||||
| 1386 | /* Process all of them. */ | |||
| 1387 | while (npkts-- > 0) { | |||
| 1388 | if (__predict_false(len < sizeof(*rxd))__builtin_expect(((len < sizeof(*rxd)) != 0), 0)) | |||
| 1389 | break; | |||
| 1390 | rxd = (struct r92c_rx_desc_usb *)buf; | |||
| 1391 | rxdw0 = letoh32(rxd->rxdw0)((__uint32_t)(rxd->rxdw0)); | |||
| 1392 | ||||
| 1393 | pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN)(((rxdw0) & 0x00003fff) >> 0); | |||
| 1394 | if (__predict_false(pktlen == 0)__builtin_expect(((pktlen == 0) != 0), 0)) | |||
| 1395 | break; | |||
| 1396 | ||||
| 1397 | infosz = MS(rxdw0, R92C_RXDW0_INFOSZ)(((rxdw0) & 0x000f0000) >> 16) * 8; | |||
| 1398 | ||||
| 1399 | /* Make sure everything fits in xfer. */ | |||
| 1400 | totlen = sizeof(*rxd) + infosz + pktlen; | |||
| 1401 | if (__predict_false(totlen > len)__builtin_expect(((totlen > len) != 0), 0)) | |||
| 1402 | break; | |||
| 1403 | ||||
| 1404 | /* Process 802.11 frame. */ | |||
| 1405 | urtwn_rx_frame(sc, buf, pktlen, &ml); | |||
| 1406 | ||||
| 1407 | /* Handle chunk alignment. */ | |||
| 1408 | totlen = (totlen + align) & ~align; | |||
| 1409 | buf += totlen; | |||
| 1410 | len -= totlen; | |||
| 1411 | } | |||
| 1412 | if_input(&ic->ic_ific_ac.ac_if, &ml); | |||
| 1413 | ||||
| 1414 | resubmit: | |||
| 1415 | /* Setup a new transfer. */ | |||
| 1416 | usbd_setup_xfer(xfer, sc->rx_pipe, data, data->buf, URTWN_RXBUFSZ(16 * 1024), | |||
| 1417 | USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01, USBD_NO_TIMEOUT0, urtwn_rxeof); | |||
| 1418 | error = usbd_transfer(data->xfer); | |||
| 1419 | if (error != 0 && error != USBD_IN_PROGRESS) | |||
| 1420 | DPRINTF(("could not set up new transfer: %d\n", error)); | |||
| 1421 | } | |||
| 1422 | ||||
| 1423 | void | |||
| 1424 | urtwn_txeof(struct usbd_xfer *xfer, void *priv, | |||
| 1425 | usbd_status status) | |||
| 1426 | { | |||
| 1427 | struct urtwn_tx_data *data = priv; | |||
| 1428 | struct urtwn_softc *sc = data->sc; | |||
| 1429 | struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_ific_ac.ac_if; | |||
| 1430 | int s; | |||
| 1431 | ||||
| 1432 | s = splnet()splraise(0x4); | |||
| 1433 | /* Put this Tx buffer back to our free list. */ | |||
| 1434 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next)do { (data)->next.tqe_next = ((void *)0); (data)->next. tqe_prev = (&sc->tx_free_list)->tqh_last; *(&sc ->tx_free_list)->tqh_last = (data); (&sc->tx_free_list )->tqh_last = &(data)->next.tqe_next; } while (0); | |||
| 1435 | ||||
| 1436 | if (__predict_false(status != USBD_NORMAL_COMPLETION)__builtin_expect(((status != USBD_NORMAL_COMPLETION) != 0), 0 )) { | |||
| 1437 | DPRINTF(("TX status=%d\n", status)); | |||
| 1438 | if (status == USBD_STALLED) | |||
| 1439 | usbd_clear_endpoint_stall_async(data->pipe); | |||
| 1440 | ifp->if_oerrorsif_data.ifi_oerrors++; | |||
| 1441 | splx(s)spllower(s); | |||
| 1442 | return; | |||
| 1443 | } | |||
| 1444 | sc->sc_sc.sc_tx_timer = 0; | |||
| 1445 | ||||
| 1446 | /* We just released a Tx buffer, notify Tx. */ | |||
| 1447 | if (ifq_is_oactive(&ifp->if_snd)) { | |||
| 1448 | ifq_clr_oactive(&ifp->if_snd); | |||
| 1449 | rtwn_start(ifp); | |||
| 1450 | } | |||
| 1451 | splx(s)spllower(s); | |||
| 1452 | } | |||
| 1453 | ||||
| 1454 | void | |||
| 1455 | urtwn_tx_fill_desc(struct urtwn_softc *sc, uint8_t **txdp, struct mbuf *m, | |||
| 1456 | struct ieee80211_frame *wh, struct ieee80211_key *k, | |||
| 1457 | struct ieee80211_node *ni) | |||
| 1458 | { | |||
| 1459 | struct r92c_tx_desc_usb *txd; | |||
| 1460 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1461 | uint8_t raid, type, rtsrate; | |||
| 1462 | uint32_t pktlen; | |||
| 1463 | ||||
| 1464 | txd = (struct r92c_tx_desc_usb *)*txdp; | |||
| 1465 | (*txdp) += sizeof(*txd); | |||
| 1466 | memset(txd, 0, sizeof(*txd))__builtin_memset((txd), (0), (sizeof(*txd))); | |||
| 1467 | ||||
| 1468 | pktlen = m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
| 1469 | if (k != NULL((void *)0) && k->k_cipher == IEEE80211_CIPHER_CCMP) { | |||
| 1470 | txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER,((__uint32_t)((((3) << 22) & 0x00c00000))) | |||
| 1471 | R92C_TXDW1_CIPHER_AES))((__uint32_t)((((3) << 22) & 0x00c00000))); | |||
| 1472 | pktlen += IEEE80211_CCMP_HDRLEN8; | |||
| 1473 | } | |||
| 1474 | ||||
| 1475 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK0x0c; | |||
| 1476 | ||||
| 1477 | txd->txdw0 |= htole32(((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1478 | SM(R92C_TXDW0_PKTLEN, pktlen) |((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1479 | SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1480 | R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG)((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)); | |||
| 1481 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01)) | |||
| 1482 | txd->txdw0 |= htole32(R92C_TXDW0_BMCAST)((__uint32_t)(0x01000000)); | |||
| 1483 | ||||
| 1484 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01) && | |||
| 1485 | type == IEEE80211_FC0_TYPE_DATA0x08) { | |||
| 1486 | if (ic->ic_curmode == IEEE80211_MODE_11B || | |||
| 1487 | (sc->sc_sc.sc_flags & RTWN_FLAG_FORCE_RAID_11B0x04)) | |||
| 1488 | raid = R92C_RAID_11B6; | |||
| 1489 | else | |||
| 1490 | raid = R92C_RAID_11BG4; | |||
| 1491 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) { | |||
| 1492 | txd->txdw1 |= htole32(((__uint32_t)((((0) << 0) & 0x0000003f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1493 | SM(R88E_TXDW1_MACID, R92C_MACID_BSS) |((__uint32_t)((((0) << 0) & 0x0000003f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1494 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |((__uint32_t)((((0) << 0) & 0x0000003f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1495 | SM(R92C_TXDW1_RAID, raid))((__uint32_t)((((0) << 0) & 0x0000003f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))); | |||
| 1496 | txd->txdw2 |= htole32(R88E_TXDW2_AGGBK)((__uint32_t)(0x00010000)); | |||
| 1497 | /* Request TX status report for AMRR */ | |||
| 1498 | txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT)((__uint32_t)(0x00080000)); | |||
| 1499 | } else { | |||
| 1500 | txd->txdw1 |= htole32(((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ) | 0x00000040)) | |||
| 1501 | SM(R92C_TXDW1_MACID, R92C_MACID_BSS) |((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ) | 0x00000040)) | |||
| 1502 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ) | 0x00000040)) | |||
| 1503 | SM(R92C_TXDW1_RAID, raid) | R92C_TXDW1_AGGBK)((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ) | 0x00000040)); | |||
| 1504 | } | |||
| 1505 | ||||
| 1506 | if (pktlen + IEEE80211_CRC_LEN4 > ic->ic_rtsthreshold) { | |||
| 1507 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |((__uint32_t)(0x00001000 | 0x00002000)) | |||
| 1508 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00001000 | 0x00002000)); | |||
| 1509 | } else if (ic->ic_flags & IEEE80211_F_USEPROT0x00100000) { | |||
| 1510 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { | |||
| 1511 | txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF |((__uint32_t)(0x00000800 | 0x00002000)) | |||
| 1512 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00000800 | 0x00002000)); | |||
| 1513 | } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { | |||
| 1514 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |((__uint32_t)(0x00001000 | 0x00002000)) | |||
| 1515 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00001000 | 0x00002000)); | |||
| 1516 | } | |||
| 1517 | } | |||
| 1518 | txd->txdw5 |= htole32(0x0001ff00)((__uint32_t)(0x0001ff00)); | |||
| 1519 | ||||
| 1520 | if (ic->ic_curmode == IEEE80211_MODE_11B) | |||
| 1521 | rtsrate = 0; /* CCK1 */ | |||
| 1522 | else | |||
| 1523 | rtsrate = 8; /* OFDM24 */ | |||
| 1524 | ||||
| 1525 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) { | |||
| 1526 | /* Use AMRR */ | |||
| 1527 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE)((__uint32_t)(0x00000100)); | |||
| 1528 | txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, rtsrate))((__uint32_t)((((rtsrate) << 0) & 0x0000001f))); | |||
| 1529 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE,((__uint32_t)((((ni->ni_txrate) << 0) & 0x0000003f ))) | |||
| 1530 | ni->ni_txrate))((__uint32_t)((((ni->ni_txrate) << 0) & 0x0000003f ))); | |||
| 1531 | } else { | |||
| 1532 | /* Send data at OFDM54. */ | |||
| 1533 | txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, rtsrate))((__uint32_t)((((rtsrate) << 0) & 0x0000001f))); | |||
| 1534 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11))((__uint32_t)((((11) << 0) & 0x0000003f))); | |||
| 1535 | } | |||
| 1536 | } else { | |||
| 1537 | txd->txdw1 |= htole32(((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x12) << 8) & 0x00001f00) | (((6) << 16) & 0x000f0000)) ) | |||
| 1538 | SM(R92C_TXDW1_MACID, 0) |((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x12) << 8) & 0x00001f00) | (((6) << 16) & 0x000f0000)) ) | |||
| 1539 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x12) << 8) & 0x00001f00) | (((6) << 16) & 0x000f0000)) ) | |||
| 1540 | SM(R92C_TXDW1_RAID, R92C_RAID_11B))((__uint32_t)((((0) << 0) & 0x0000001f) | (((0x12) << 8) & 0x00001f00) | (((6) << 16) & 0x000f0000)) ); | |||
| 1541 | ||||
| 1542 | /* Force CCK1. */ | |||
| 1543 | txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE)((__uint32_t)(0x00000100)); | |||
| 1544 | txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0))((__uint32_t)((((0) << 0) & 0x0000003f))); | |||
| 1545 | } | |||
| 1546 | /* Set sequence number (already little endian). */ | |||
| 1547 | txd->txdseq |= (*(uint16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT4; | |||
| 1548 | ||||
| 1549 | if (!ieee80211_has_qos(wh)) { | |||
| 1550 | /* Use HW sequence numbering for non-QoS frames. */ | |||
| 1551 | txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ)((__uint32_t)(0x00000080)); | |||
| 1552 | txd->txdseq |= htole16(R92C_TXDW3_HWSEQEN)((__uint16_t)(0x8000)); | |||
| 1553 | } else | |||
| 1554 | txd->txdw4 |= htole32(R92C_TXDW4_QOS)((__uint32_t)(0x00000040)); | |||
| 1555 | } | |||
| 1556 | ||||
| 1557 | void | |||
| 1558 | urtwn_tx_fill_desc_gen2(struct urtwn_softc *sc, uint8_t **txdp, struct mbuf *m, | |||
| 1559 | struct ieee80211_frame *wh, struct ieee80211_key *k, | |||
| 1560 | struct ieee80211_node *ni) | |||
| 1561 | { | |||
| 1562 | struct r92e_tx_desc_usb *txd; | |||
| 1563 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1564 | uint8_t raid, type; | |||
| 1565 | uint32_t pktlen; | |||
| 1566 | ||||
| 1567 | txd = (struct r92e_tx_desc_usb *)*txdp; | |||
| 1568 | (*txdp) += sizeof(*txd); | |||
| 1569 | memset(txd, 0, sizeof(*txd))__builtin_memset((txd), (0), (sizeof(*txd))); | |||
| 1570 | ||||
| 1571 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK0x0c; | |||
| 1572 | ||||
| 1573 | pktlen = m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
| 1574 | if (k != NULL((void *)0) && k->k_cipher == IEEE80211_CIPHER_CCMP) { | |||
| 1575 | txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER,((__uint32_t)((((3) << 22) & 0x00c00000))) | |||
| 1576 | R92C_TXDW1_CIPHER_AES))((__uint32_t)((((3) << 22) & 0x00c00000))); | |||
| 1577 | pktlen += IEEE80211_CCMP_HDRLEN8; | |||
| 1578 | } | |||
| 1579 | ||||
| 1580 | txd->txdw0 |= htole32(((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1581 | SM(R92C_TXDW0_PKTLEN, pktlen) |((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1582 | SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)) | |||
| 1583 | R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG)((__uint32_t)((((pktlen) << 0) & 0x0000ffff) | (((sizeof (*txd)) << 16) & 0x00ff0000) | 0x80000000 | 0x08000000 | 0x04000000)); | |||
| 1584 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01)) | |||
| 1585 | txd->txdw0 |= htole32(R92C_TXDW0_BMCAST)((__uint32_t)(0x01000000)); | |||
| 1586 | ||||
| 1587 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)(*(wh->i_addr1) & 0x01) && | |||
| 1588 | type == IEEE80211_FC0_TYPE_DATA0x08) { | |||
| 1589 | if (ic->ic_curmode == IEEE80211_MODE_11B || | |||
| 1590 | (sc->sc_sc.sc_flags & RTWN_FLAG_FORCE_RAID_11B0x04)) | |||
| 1591 | raid = R92E_RAID_11B8; | |||
| 1592 | else | |||
| 1593 | raid = R92E_RAID_11BG6; | |||
| 1594 | txd->txdw1 |= htole32(((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1595 | SM(R92E_TXDW1_MACID, R92C_MACID_BSS) |((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1596 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))) | |||
| 1597 | SM(R92C_TXDW1_RAID, raid))((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x00) << 8) & 0x00001f00) | (((raid) << 16) & 0x000f0000 ))); | |||
| 1598 | /* Request TX status report for AMRR */ | |||
| 1599 | txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT | R88E_TXDW2_AGGBK)((__uint32_t)(0x00080000 | 0x00010000)); | |||
| 1600 | ||||
| 1601 | if (pktlen + IEEE80211_CRC_LEN4 > ic->ic_rtsthreshold) { | |||
| 1602 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |((__uint32_t)(0x00001000 | 0x00002000)) | |||
| 1603 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00001000 | 0x00002000)); | |||
| 1604 | } else if (ic->ic_flags & IEEE80211_F_USEPROT0x00100000) { | |||
| 1605 | if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { | |||
| 1606 | txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF |((__uint32_t)(0x00000800 | 0x00002000)) | |||
| 1607 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00000800 | 0x00002000)); | |||
| 1608 | } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { | |||
| 1609 | txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |((__uint32_t)(0x00001000 | 0x00002000)) | |||
| 1610 | R92C_TXDW4_HWRTSEN)((__uint32_t)(0x00001000 | 0x00002000)); | |||
| 1611 | } | |||
| 1612 | } | |||
| 1613 | txd->txdw5 |= htole32(0x0001ff00)((__uint32_t)(0x0001ff00)); | |||
| 1614 | ||||
| 1615 | /* Use AMRR */ | |||
| 1616 | txd->txdw3 |= htole32(R92E_TXDW3_DRVRATE)((__uint32_t)(0x0100)); | |||
| 1617 | txd->txdw4 |= htole32(SM(R92E_TXDW4_RTSRATE, 8))((__uint32_t)((((8) << 24) & 0x1f000000))); | |||
| 1618 | txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATE, ni->ni_txrate))((__uint32_t)((((ni->ni_txrate) << 0) & 0x0000007f ))); | |||
| 1619 | } else { | |||
| 1620 | txd->txdw1 |= htole32(((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x12) << 8) & 0x00001f00) | (((8) << 16) & 0x000f0000)) ) | |||
| 1621 | SM(R92E_TXDW1_MACID, 0) |((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x12) << 8) & 0x00001f00) | (((8) << 16) & 0x000f0000)) ) | |||
| 1622 | SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x12) << 8) & 0x00001f00) | (((8) << 16) & 0x000f0000)) ) | |||
| 1623 | SM(R92C_TXDW1_RAID, R92E_RAID_11B))((__uint32_t)((((0) << 0) & 0x0000007f) | (((0x12) << 8) & 0x00001f00) | (((8) << 16) & 0x000f0000)) ); | |||
| 1624 | ||||
| 1625 | /* Force CCK1. */ | |||
| 1626 | txd->txdw3 |= htole32(R92E_TXDW3_DRVRATE)((__uint32_t)(0x0100)); | |||
| 1627 | txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATE, 0))((__uint32_t)((((0) << 0) & 0x0000007f))); | |||
| 1628 | } | |||
| 1629 | txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATEFB, 0x1f))((__uint32_t)((((0x1f) << 8) & 0x00001f00))); | |||
| 1630 | ||||
| 1631 | txd->txdseq2 |= htole16(SM(R92E_TXDSEQ2_HWSEQ, *(uint16_t *)wh->i_seq))((__uint16_t)((((*(uint16_t *)wh->i_seq) << 11) & 0x0000ffff))); | |||
| 1632 | ||||
| 1633 | if (!ieee80211_has_qos(wh)) { | |||
| 1634 | /* Use HW sequence numbering for non-QoS frames. */ | |||
| 1635 | txd->txdw7 |= htole16(R92C_TXDW3_HWSEQEN)((__uint16_t)(0x8000)); | |||
| 1636 | } | |||
| 1637 | } | |||
| 1638 | ||||
| 1639 | int | |||
| 1640 | urtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) | |||
| 1641 | { | |||
| 1642 | struct urtwn_softc *sc = cookie; | |||
| 1643 | struct ieee80211com *ic = &sc->sc_sc.sc_ic; | |||
| 1644 | struct ieee80211_frame *wh; | |||
| 1645 | struct ieee80211_key *k = NULL((void *)0); | |||
| 1646 | struct urtwn_tx_data *data; | |||
| 1647 | struct usbd_pipe *pipe; | |||
| 1648 | uint16_t qos, sum; | |||
| 1649 | uint8_t tid, qid; | |||
| 1650 | int i, xferlen, error, headerlen; | |||
| 1651 | uint8_t *txdp; | |||
| 1652 | ||||
| 1653 | wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data)); | |||
| 1654 | ||||
| 1655 | if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED0x40) { | |||
| 1656 | k = ieee80211_get_txkey(ic, wh, ni); | |||
| 1657 | if (k->k_cipher != IEEE80211_CIPHER_CCMP) { | |||
| 1658 | if ((m = ieee80211_encrypt(ic, m, k)) == NULL((void *)0)) | |||
| 1659 | return (ENOBUFS55); | |||
| 1660 | wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data)); | |||
| 1661 | } | |||
| 1662 | } | |||
| 1663 | ||||
| 1664 | if (ieee80211_has_qos(wh)) { | |||
| 1665 | qos = ieee80211_get_qos(wh); | |||
| 1666 | tid = qos & IEEE80211_QOS_TID0x000f; | |||
| 1667 | qid = ieee80211_up_to_ac(ic, tid); | |||
| 1668 | } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK0x0c) | |||
| 1669 | != IEEE80211_FC0_TYPE_DATA0x08) { | |||
| 1670 | /* Use AC VO for management frames. */ | |||
| 1671 | qid = EDCA_AC_VO; | |||
| 1672 | } else | |||
| 1673 | qid = EDCA_AC_BE; | |||
| 1674 | ||||
| 1675 | /* Get the USB pipe to use for this AC. */ | |||
| 1676 | pipe = sc->tx_pipe[sc->ac2idx[qid]]; | |||
| 1677 | ||||
| 1678 | /* Grab a Tx buffer from our free list. */ | |||
| 1679 | data = TAILQ_FIRST(&sc->tx_free_list)((&sc->tx_free_list)->tqh_first); | |||
| 1680 | TAILQ_REMOVE(&sc->tx_free_list, data, next)do { if (((data)->next.tqe_next) != ((void *)0)) (data)-> next.tqe_next->next.tqe_prev = (data)->next.tqe_prev; else (&sc->tx_free_list)->tqh_last = (data)->next.tqe_prev ; *(data)->next.tqe_prev = (data)->next.tqe_next; ((data )->next.tqe_prev) = ((void *)-1); ((data)->next.tqe_next ) = ((void *)-1); } while (0); | |||
| 1681 | ||||
| 1682 | /* Fill Tx descriptor. */ | |||
| 1683 | txdp = data->buf; | |||
| 1684 | if (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) | |||
| 1685 | urtwn_tx_fill_desc_gen2(sc, &txdp, m, wh, k, ni); | |||
| 1686 | else | |||
| 1687 | urtwn_tx_fill_desc(sc, &txdp, m, wh, k, ni); | |||
| 1688 | ||||
| 1689 | /* Compute Tx descriptor checksum. */ | |||
| 1690 | sum = 0; | |||
| 1691 | for (i = 0; i < R92C_TXDESC_SUMSIZE32 / 2; i++) | |||
| 1692 | sum ^= ((uint16_t *)data->buf)[i]; | |||
| 1693 | ((uint16_t *)data->buf)[R92C_TXDESC_SUMOFFSET14] = sum; | |||
| 1694 | ||||
| 1695 | #if NBPFILTER1 > 0 | |||
| 1696 | if (__predict_false(sc->sc_drvbpf != NULL)__builtin_expect(((sc->sc_drvbpf != ((void *)0)) != 0), 0)) { | |||
| 1697 | struct urtwn_tx_radiotap_header *tap = &sc->sc_txtapsc_txtapu.th; | |||
| 1698 | struct mbuf mb; | |||
| 1699 | ||||
| 1700 | tap->wt_flags = 0; | |||
| 1701 | tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq)((__uint16_t)(ic->ic_bss->ni_chan->ic_freq)); | |||
| 1702 | tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags)((__uint16_t)(ic->ic_bss->ni_chan->ic_flags)); | |||
| 1703 | ||||
| 1704 | mb.m_datam_hdr.mh_data = (caddr_t)tap; | |||
| 1705 | mb.m_lenm_hdr.mh_len = sc->sc_txtap_len; | |||
| 1706 | mb.m_nextm_hdr.mh_next = m; | |||
| 1707 | mb.m_nextpktm_hdr.mh_nextpkt = NULL((void *)0); | |||
| 1708 | mb.m_typem_hdr.mh_type = 0; | |||
| 1709 | mb.m_flagsm_hdr.mh_flags = 0; | |||
| 1710 | bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT(1 << 1)); | |||
| 1711 | } | |||
| 1712 | #endif | |||
| 1713 | ||||
| 1714 | if (k != NULL((void *)0) && k->k_cipher == IEEE80211_CIPHER_CCMP) { | |||
| 1715 | xferlen = (txdp - data->buf) + m->m_pkthdrM_dat.MH.MH_pkthdr.len + | |||
| 1716 | IEEE80211_CCMP_HDRLEN8; | |||
| 1717 | headerlen = ieee80211_get_hdrlen(wh); | |||
| 1718 | ||||
| 1719 | m_copydata(m, 0, headerlen, txdp); | |||
| 1720 | txdp += headerlen; | |||
| 1721 | ||||
| 1722 | k->k_tsc++; | |||
| 1723 | txdp[0] = k->k_tsc; | |||
| 1724 | txdp[1] = k->k_tsc >> 8; | |||
| 1725 | txdp[2] = 0; | |||
| 1726 | txdp[3] = k->k_id | IEEE80211_WEP_EXTIV0x20; | |||
| 1727 | txdp[4] = k->k_tsc >> 16; | |||
| 1728 | txdp[5] = k->k_tsc >> 24; | |||
| 1729 | txdp[6] = k->k_tsc >> 32; | |||
| 1730 | txdp[7] = k->k_tsc >> 40; | |||
| 1731 | txdp += IEEE80211_CCMP_HDRLEN8; | |||
| 1732 | ||||
| 1733 | m_copydata(m, headerlen, m->m_pkthdrM_dat.MH.MH_pkthdr.len - headerlen, txdp); | |||
| 1734 | m_freem(m); | |||
| 1735 | } else { | |||
| 1736 | xferlen = (txdp - data->buf) + m->m_pkthdrM_dat.MH.MH_pkthdr.len; | |||
| 1737 | m_copydata(m, 0, m->m_pkthdrM_dat.MH.MH_pkthdr.len, txdp); | |||
| 1738 | m_freem(m); | |||
| 1739 | } | |||
| 1740 | ||||
| 1741 | data->pipe = pipe; | |||
| 1742 | usbd_setup_xfer(data->xfer, pipe, data, data->buf, xferlen, | |||
| 1743 | USBD_FORCE_SHORT_XFER0x08 | USBD_NO_COPY0x01, URTWN_TX_TIMEOUT5000, | |||
| 1744 | urtwn_txeof); | |||
| 1745 | error = usbd_transfer(data->xfer); | |||
| 1746 | if (__predict_false(error != USBD_IN_PROGRESS && error != 0)__builtin_expect(((error != USBD_IN_PROGRESS && error != 0) != 0), 0)) { | |||
| 1747 | /* Put this Tx buffer back to our free list. */ | |||
| 1748 | TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next)do { (data)->next.tqe_next = ((void *)0); (data)->next. tqe_prev = (&sc->tx_free_list)->tqh_last; *(&sc ->tx_free_list)->tqh_last = (data); (&sc->tx_free_list )->tqh_last = &(data)->next.tqe_next; } while (0); | |||
| 1749 | return (error); | |||
| 1750 | } | |||
| 1751 | ieee80211_release_node(ic, ni); | |||
| 1752 | return (0); | |||
| 1753 | } | |||
| 1754 | ||||
| 1755 | int | |||
| 1756 | urtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | |||
| 1757 | { | |||
| 1758 | struct rtwn_softc *sc_sc = ifp->if_softc; | |||
| 1759 | struct device *self = sc_sc->sc_pdev; | |||
| 1760 | struct urtwn_softc *sc = (struct urtwn_softc *)self; | |||
| 1761 | int error; | |||
| 1762 | ||||
| 1763 | if (usbd_is_dying(sc->sc_udev)) | |||
| 1764 | return ENXIO6; | |||
| 1765 | ||||
| 1766 | usbd_ref_incr(sc->sc_udev); | |||
| 1767 | error = rtwn_ioctl(ifp, cmd, data); | |||
| 1768 | usbd_ref_decr(sc->sc_udev); | |||
| 1769 | ||||
| 1770 | return (error); | |||
| 1771 | } | |||
| 1772 | ||||
| 1773 | int | |||
| 1774 | urtwn_r92c_power_on(struct urtwn_softc *sc) | |||
| 1775 | { | |||
| 1776 | uint32_t reg; | |||
| 1777 | int ntries; | |||
| 1778 | ||||
| 1779 | /* Wait for autoload done bit. */ | |||
| 1780 | for (ntries = 0; ntries < 1000; ntries++) { | |||
| 1781 | if (urtwn_read_1(sc, R92C_APS_FSMCO0x004) & R92C_APS_FSMCO_PFM_ALDN0x00000002) | |||
| 1782 | break; | |||
| 1783 | DELAY(5)(*delay_func)(5); | |||
| 1784 | } | |||
| 1785 | if (ntries == 1000) { | |||
| 1786 | printf("%s: timeout waiting for chip autoload\n", | |||
| 1787 | sc->sc_dev.dv_xname); | |||
| 1788 | return (ETIMEDOUT60); | |||
| 1789 | } | |||
| 1790 | ||||
| 1791 | /* Unlock ISO/CLK/Power control register. */ | |||
| 1792 | urtwn_write_1(sc, R92C_RSV_CTRL0x01c, 0); | |||
| 1793 | /* Move SPS into PWM mode. */ | |||
| 1794 | urtwn_write_1(sc, R92C_SPS0_CTRL0x011, 0x2b); | |||
| 1795 | DELAY(100)(*delay_func)(100); | |||
| 1796 | ||||
| 1797 | reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL0x021); | |||
| 1798 | if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN0x01)) { | |||
| 1799 | urtwn_write_1(sc, R92C_LDOV12D_CTRL0x021, | |||
| 1800 | reg | R92C_LDOV12D_CTRL_LDV12_EN0x01); | |||
| 1801 | DELAY(100)(*delay_func)(100); | |||
| 1802 | urtwn_write_1(sc, R92C_SYS_ISO_CTRL0x000, | |||
| 1803 | urtwn_read_1(sc, R92C_SYS_ISO_CTRL0x000) & | |||
| 1804 | ~R92C_SYS_ISO_CTRL_MD2PP0x0001); | |||
| 1805 | } | |||
| 1806 | ||||
| 1807 | /* Auto enable WLAN. */ | |||
| 1808 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1809 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) | R92C_APS_FSMCO_APFM_ONMAC0x00000100); | |||
| 1810 | for (ntries = 0; ntries < 1000; ntries++) { | |||
| 1811 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1812 | R92C_APS_FSMCO_APFM_ONMAC0x00000100)) | |||
| 1813 | break; | |||
| 1814 | DELAY(5)(*delay_func)(5); | |||
| 1815 | } | |||
| 1816 | if (ntries == 1000) { | |||
| 1817 | printf("%s: timeout waiting for MAC auto ON\n", | |||
| 1818 | sc->sc_dev.dv_xname); | |||
| 1819 | return (ETIMEDOUT60); | |||
| 1820 | } | |||
| 1821 | ||||
| 1822 | /* Enable radio, GPIO and LED functions. */ | |||
| 1823 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1824 | R92C_APS_FSMCO_AFSM_HSUS0x00000800 | | |||
| 1825 | R92C_APS_FSMCO_PDN_EN0x00000010 | | |||
| 1826 | R92C_APS_FSMCO_PFM_ALDN0x00000002); | |||
| 1827 | /* Release RF digital isolation. */ | |||
| 1828 | urtwn_write_2(sc, R92C_SYS_ISO_CTRL0x000, | |||
| 1829 | urtwn_read_2(sc, R92C_SYS_ISO_CTRL0x000) & ~R92C_SYS_ISO_CTRL_DIOR0x0200); | |||
| 1830 | ||||
| 1831 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | |||
| 1832 | reg = urtwn_read_2(sc, R92C_CR0x100); | |||
| 1833 | reg |= R92C_CR_HCI_TXDMA_EN0x00000001 | R92C_CR_HCI_RXDMA_EN0x00000002 | | |||
| 1834 | R92C_CR_TXDMA_EN0x00000004 | R92C_CR_RXDMA_EN0x00000008 | R92C_CR_PROTOCOL_EN0x00000010 | | |||
| 1835 | R92C_CR_SCHEDULE_EN0x00000020 | R92C_CR_MACTXEN0x00000040 | R92C_CR_MACRXEN0x00000080 | | |||
| 1836 | R92C_CR_ENSEC0x00000200; | |||
| 1837 | urtwn_write_2(sc, R92C_CR0x100, reg); | |||
| 1838 | ||||
| 1839 | urtwn_write_1(sc, 0xfe10, 0x19); | |||
| 1840 | return (0); | |||
| 1841 | } | |||
| 1842 | ||||
| 1843 | int | |||
| 1844 | urtwn_r92e_power_on(struct urtwn_softc *sc) | |||
| 1845 | { | |||
| 1846 | uint32_t reg; | |||
| 1847 | int ntries; | |||
| 1848 | ||||
| 1849 | if (urtwn_read_4(sc, R92C_SYS_CFG0x0f0) & R92E_SYS_CFG_SPSLDO_SEL0x01000000) { | |||
| 1850 | /* LDO. */ | |||
| 1851 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL0x07c, 0xc3); | |||
| 1852 | } else { | |||
| 1853 | reg = urtwn_read_4(sc, R92C_SYS_SWR_CTRL20x014); | |||
| 1854 | reg &= 0xff0fffff; | |||
| 1855 | reg |= 0x00500000; | |||
| 1856 | urtwn_write_4(sc, R92C_SYS_SWR_CTRL20x014, reg); | |||
| 1857 | urtwn_write_1(sc, R92E_LDO_SWR_CTRL0x07c, 0x83); | |||
| 1858 | } | |||
| 1859 | ||||
| 1860 | /* 40MHz crystal source */ | |||
| 1861 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL0x028, | |||
| 1862 | urtwn_read_1(sc, R92C_AFE_PLL_CTRL0x028) & 0xfb); | |||
| 1863 | urtwn_write_4(sc, R92C_AFE_XTAL_CTRL_EXT0x078, | |||
| 1864 | urtwn_read_4(sc, R92C_AFE_XTAL_CTRL_EXT0x078) & 0xfffffc7f); | |||
| 1865 | ||||
| 1866 | urtwn_write_1(sc, R92C_AFE_PLL_CTRL0x028, | |||
| 1867 | urtwn_read_1(sc, R92C_AFE_PLL_CTRL0x028) & 0xbf); | |||
| 1868 | urtwn_write_4(sc, R92C_AFE_XTAL_CTRL_EXT0x078, | |||
| 1869 | urtwn_read_4(sc, R92C_AFE_XTAL_CTRL_EXT0x078) & 0xffdfffff); | |||
| 1870 | ||||
| 1871 | /* Disable HWPDN. */ | |||
| 1872 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1873 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & ~R92C_APS_FSMCO_APDM_HPDN0x00008000); | |||
| 1874 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 1875 | if (urtwn_read_4(sc, R92C_APS_FSMCO0x004) & R92C_APS_FSMCO_SUS_HOST0x00020000) | |||
| 1876 | break; | |||
| 1877 | DELAY(10)(*delay_func)(10); | |||
| 1878 | } | |||
| 1879 | if (ntries == 5000) { | |||
| 1880 | printf("%s: timeout waiting for chip power up\n", | |||
| 1881 | sc->sc_dev.dv_xname); | |||
| 1882 | return (ETIMEDOUT60); | |||
| 1883 | } | |||
| 1884 | ||||
| 1885 | /* Disable WL suspend. */ | |||
| 1886 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1887 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1888 | ~(R92C_APS_FSMCO_AFSM_HSUS0x00000800 | R92C_APS_FSMCO_AFSM_PCIE0x00001000)); | |||
| 1889 | ||||
| 1890 | /* Auto enable WLAN. */ | |||
| 1891 | urtwn_write_4(sc, R92C_APS_FSMCO0x004, | |||
| 1892 | urtwn_read_4(sc, R92C_APS_FSMCO0x004) | R92C_APS_FSMCO_RDY_MACON0x00010000); | |||
| 1893 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1894 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) | R92C_APS_FSMCO_APFM_ONMAC0x00000100); | |||
| 1895 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 1896 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1897 | R92C_APS_FSMCO_APFM_ONMAC0x00000100)) | |||
| 1898 | break; | |||
| 1899 | DELAY(10)(*delay_func)(10); | |||
| 1900 | } | |||
| 1901 | if (ntries == 5000) { | |||
| 1902 | printf("%s: timeout waiting for MAC auto ON\n", | |||
| 1903 | sc->sc_dev.dv_xname); | |||
| 1904 | return (ETIMEDOUT60); | |||
| 1905 | } | |||
| 1906 | ||||
| 1907 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | |||
| 1908 | urtwn_write_2(sc, R92C_CR0x100, 0); | |||
| 1909 | reg = urtwn_read_2(sc, R92C_CR0x100); | |||
| 1910 | reg |= R92C_CR_HCI_TXDMA_EN0x00000001 | R92C_CR_HCI_RXDMA_EN0x00000002 | | |||
| 1911 | R92C_CR_TXDMA_EN0x00000004 | R92C_CR_RXDMA_EN0x00000008 | R92C_CR_PROTOCOL_EN0x00000010 | | |||
| 1912 | R92C_CR_SCHEDULE_EN0x00000020 | R92C_CR_ENSEC0x00000200 | R92C_CR_CALTMR_EN0x00000400; | |||
| 1913 | urtwn_write_2(sc, R92C_CR0x100, reg); | |||
| 1914 | return (0); | |||
| 1915 | } | |||
| 1916 | ||||
| 1917 | int | |||
| 1918 | urtwn_r88e_power_on(struct urtwn_softc *sc) | |||
| 1919 | { | |||
| 1920 | uint32_t reg; | |||
| 1921 | int ntries; | |||
| 1922 | ||||
| 1923 | /* Wait for power ready bit. */ | |||
| 1924 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 1925 | if (urtwn_read_4(sc, R92C_APS_FSMCO0x004) & R92C_APS_FSMCO_SUS_HOST0x00020000) | |||
| 1926 | break; | |||
| 1927 | DELAY(10)(*delay_func)(10); | |||
| 1928 | } | |||
| 1929 | if (ntries == 5000) { | |||
| 1930 | printf("%s: timeout waiting for chip power up\n", | |||
| 1931 | sc->sc_dev.dv_xname); | |||
| 1932 | return (ETIMEDOUT60); | |||
| 1933 | } | |||
| 1934 | ||||
| 1935 | /* Reset BB. */ | |||
| 1936 | urtwn_write_1(sc, R92C_SYS_FUNC_EN0x002, | |||
| 1937 | urtwn_read_1(sc, R92C_SYS_FUNC_EN0x002) & ~(R92C_SYS_FUNC_EN_BBRSTB0x0001 | | |||
| 1938 | R92C_SYS_FUNC_EN_BB_GLB_RST0x0002)); | |||
| 1939 | ||||
| 1940 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL0x024 + 2, | |||
| 1941 | urtwn_read_1(sc, R92C_AFE_XTAL_CTRL0x024 + 2) | 0x80); | |||
| 1942 | ||||
| 1943 | /* Disable HWPDN. */ | |||
| 1944 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1945 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & ~R92C_APS_FSMCO_APDM_HPDN0x00008000); | |||
| 1946 | /* Disable WL suspend. */ | |||
| 1947 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1948 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1949 | ~(R92C_APS_FSMCO_AFSM_HSUS0x00000800 | R92C_APS_FSMCO_AFSM_PCIE0x00001000)); | |||
| 1950 | ||||
| 1951 | /* Auto enable WLAN. */ | |||
| 1952 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1953 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) | R92C_APS_FSMCO_APFM_ONMAC0x00000100); | |||
| 1954 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 1955 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1956 | R92C_APS_FSMCO_APFM_ONMAC0x00000100)) | |||
| 1957 | break; | |||
| 1958 | DELAY(10)(*delay_func)(10); | |||
| 1959 | } | |||
| 1960 | if (ntries == 5000) { | |||
| 1961 | printf("%s: timeout waiting for MAC auto ON\n", | |||
| 1962 | sc->sc_dev.dv_xname); | |||
| 1963 | return (ETIMEDOUT60); | |||
| 1964 | } | |||
| 1965 | ||||
| 1966 | /* Enable LDO normal mode. */ | |||
| 1967 | urtwn_write_1(sc, R92C_LPLDO_CTRL0x023, | |||
| 1968 | urtwn_read_1(sc, R92C_LPLDO_CTRL0x023) & ~0x10); | |||
| 1969 | ||||
| 1970 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | |||
| 1971 | urtwn_write_2(sc, R92C_CR0x100, 0); | |||
| 1972 | reg = urtwn_read_2(sc, R92C_CR0x100); | |||
| 1973 | reg |= R92C_CR_HCI_TXDMA_EN0x00000001 | R92C_CR_HCI_RXDMA_EN0x00000002 | | |||
| 1974 | R92C_CR_TXDMA_EN0x00000004 | R92C_CR_RXDMA_EN0x00000008 | R92C_CR_PROTOCOL_EN0x00000010 | | |||
| 1975 | R92C_CR_SCHEDULE_EN0x00000020 | R92C_CR_ENSEC0x00000200 | R92C_CR_CALTMR_EN0x00000400; | |||
| 1976 | urtwn_write_2(sc, R92C_CR0x100, reg); | |||
| 1977 | return (0); | |||
| 1978 | } | |||
| 1979 | ||||
| 1980 | int | |||
| 1981 | urtwn_r88f_power_on(struct urtwn_softc *sc) | |||
| 1982 | { | |||
| 1983 | uint32_t reg; | |||
| 1984 | int ntries; | |||
| 1985 | ||||
| 1986 | /* Enable WL suspend. */ | |||
| 1987 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1988 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 1989 | ~(R92C_APS_FSMCO_AFSM_HSUS0x00000800 | R92C_APS_FSMCO_AFSM_PCIE0x00001000)); | |||
| 1990 | /* Turn off USB APHY LDO under suspend mode. */ | |||
| 1991 | urtwn_write_1(sc, 0xc4, urtwn_read_1(sc, 0xc4) & ~0x10); | |||
| 1992 | ||||
| 1993 | /* Disable SW LPS. */ | |||
| 1994 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 1995 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & ~R92C_APS_FSMCO_APFM_RSM0x00000400); | |||
| 1996 | /* Wait for power ready bit. */ | |||
| 1997 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 1998 | if (urtwn_read_4(sc, R92C_APS_FSMCO0x004) & R92C_APS_FSMCO_SUS_HOST0x00020000) | |||
| 1999 | break; | |||
| 2000 | DELAY(10)(*delay_func)(10); | |||
| 2001 | } | |||
| 2002 | if (ntries == 5000) { | |||
| 2003 | printf("%s: timeout waiting for chip power up\n", | |||
| 2004 | sc->sc_dev.dv_xname); | |||
| 2005 | return (ETIMEDOUT60); | |||
| 2006 | } | |||
| 2007 | /* Disable HWPDN. */ | |||
| 2008 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 2009 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & ~R92C_APS_FSMCO_APDM_HPDN0x00008000); | |||
| 2010 | /* Disable WL suspend. */ | |||
| 2011 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 2012 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) & ~R92C_APS_FSMCO_AFSM_HSUS0x00000800); | |||
| 2013 | /* Auto enable WLAN. */ | |||
| 2014 | urtwn_write_2(sc, R92C_APS_FSMCO0x004, | |||
| 2015 | urtwn_read_2(sc, R92C_APS_FSMCO0x004) | R92C_APS_FSMCO_APFM_ONMAC0x00000100); | |||
| 2016 | for (ntries = 0; ntries < 5000; ntries++) { | |||
| 2017 | if (!(urtwn_read_2(sc, R92C_APS_FSMCO0x004) & | |||
| 2018 | R92C_APS_FSMCO_APFM_ONMAC0x00000100)) | |||
| 2019 | break; | |||
| 2020 | DELAY(10)(*delay_func)(10); | |||
| 2021 | } | |||
| 2022 | if (ntries == 5000) { | |||
| 2023 | printf("%s: timeout waiting for MAC auto ON\n", | |||
| 2024 | sc->sc_dev.dv_xname); | |||
| 2025 | return (ETIMEDOUT60); | |||
| 2026 | } | |||
| 2027 | /* Reduce RF noise. */ | |||
| 2028 | urtwn_write_1(sc, R92C_AFE_LDO_CTRL0x027, 0x35); | |||
| 2029 | ||||
| 2030 | /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ | |||
| 2031 | urtwn_write_2(sc, R92C_CR0x100, 0); | |||
| 2032 | reg = urtwn_read_2(sc, R92C_CR0x100); | |||
| 2033 | reg |= R92C_CR_HCI_TXDMA_EN0x00000001 | R92C_CR_HCI_RXDMA_EN0x00000002 | | |||
| 2034 | R92C_CR_TXDMA_EN0x00000004 | R92C_CR_RXDMA_EN0x00000008 | R92C_CR_PROTOCOL_EN0x00000010 | | |||
| 2035 | R92C_CR_SCHEDULE_EN0x00000020 | R92C_CR_ENSEC0x00000200 | R92C_CR_CALTMR_EN0x00000400; | |||
| 2036 | urtwn_write_2(sc, R92C_CR0x100, reg); | |||
| 2037 | return (0); | |||
| 2038 | } | |||
| 2039 | ||||
| 2040 | int | |||
| 2041 | urtwn_llt_init(struct urtwn_softc *sc, int page_count) | |||
| 2042 | { | |||
| 2043 | int i, error, pktbuf_count; | |||
| 2044 | ||||
| 2045 | pktbuf_count = (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) ? | |||
| 2046 | R88E_TXPKTBUF_COUNT177 : R92C_TXPKTBUF_COUNT256; | |||
| 2047 | ||||
| 2048 | /* Reserve pages [0; page_count]. */ | |||
| 2049 | for (i = 0; i < page_count; i++) { | |||
| 2050 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) | |||
| 2051 | return (error); | |||
| 2052 | } | |||
| 2053 | /* NB: 0xff indicates end-of-list. */ | |||
| 2054 | if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) | |||
| 2055 | return (error); | |||
| 2056 | /* | |||
| 2057 | * Use pages [page_count + 1; pktbuf_count - 1] | |||
| 2058 | * as ring buffer. | |||
| 2059 | */ | |||
| 2060 | for (++i; i < pktbuf_count - 1; i++) { | |||
| 2061 | if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) | |||
| 2062 | return (error); | |||
| 2063 | } | |||
| 2064 | /* Make the last page point to the beginning of the ring buffer. */ | |||
| 2065 | error = urtwn_llt_write(sc, i, page_count + 1); | |||
| 2066 | return (error); | |||
| 2067 | } | |||
| 2068 | ||||
| 2069 | int | |||
| 2070 | urtwn_auto_llt_init(struct urtwn_softc *sc) | |||
| 2071 | { | |||
| 2072 | int ntries; | |||
| 2073 | ||||
| 2074 | urtwn_write_4(sc, R92E_AUTO_LLT0x224, | |||
| 2075 | urtwn_read_4(sc, R92E_AUTO_LLT0x224) | R92E_AUTO_LLT_EN0x00010000); | |||
| 2076 | for (ntries = 0; ntries < 1000; ntries++) { | |||
| 2077 | if (!(urtwn_read_4(sc, R92E_AUTO_LLT0x224) & R92E_AUTO_LLT_EN0x00010000)) | |||
| 2078 | return (0); | |||
| 2079 | DELAY(2)(*delay_func)(2); | |||
| 2080 | } | |||
| 2081 | ||||
| 2082 | return (ETIMEDOUT60); | |||
| 2083 | } | |||
| 2084 | ||||
| 2085 | int | |||
| 2086 | urtwn_fw_loadpage(void *cookie, int page, uint8_t *buf, int len) | |||
| 2087 | { | |||
| 2088 | struct urtwn_softc *sc = cookie; | |||
| 2089 | uint32_t reg; | |||
| 2090 | int maxblksz, off, mlen, error = 0; | |||
| 2091 | ||||
| 2092 | reg = urtwn_read_4(sc, R92C_MCUFWDL0x080); | |||
| 2093 | reg = RW(reg, R92C_MCUFWDL_PAGE, page)(((reg) & ~0x00070000) | (((page) << 16) & 0x00070000 )); | |||
| 2094 | urtwn_write_4(sc, R92C_MCUFWDL0x080, reg); | |||
| 2095 | ||||
| 2096 | maxblksz = (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) ? 254 : 196; | |||
| 2097 | ||||
| 2098 | off = R92C_FW_START_ADDR0x1000; | |||
| 2099 | while (len > 0) { | |||
| 2100 | if (len > maxblksz) | |||
| 2101 | mlen = maxblksz; | |||
| 2102 | else if (len > 4) | |||
| 2103 | mlen = 4; | |||
| 2104 | else | |||
| 2105 | mlen = 1; | |||
| 2106 | error = urtwn_write_region_1(sc, off, buf, mlen); | |||
| 2107 | if (error != 0) | |||
| 2108 | break; | |||
| 2109 | off += mlen; | |||
| 2110 | buf += mlen; | |||
| 2111 | len -= mlen; | |||
| 2112 | } | |||
| 2113 | return (error); | |||
| 2114 | } | |||
| 2115 | ||||
| 2116 | int | |||
| 2117 | urtwn_load_firmware(void *cookie, u_char **fw, size_t *len) | |||
| 2118 | { | |||
| 2119 | struct urtwn_softc *sc = cookie; | |||
| 2120 | const char *name; | |||
| 2121 | int error; | |||
| 2122 | ||||
| 2123 | if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) | |||
| 2124 | name = "urtwn-rtl8192eu"; | |||
| 2125 | else if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) | |||
| 2126 | name = "urtwn-rtl8188eu"; | |||
| 2127 | else if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) | |||
| 2128 | name = "urtwn-rtl8188ftv"; | |||
| 2129 | else if ((sc->sc_sc.chip & (RTWN_CHIP_UMC_A_CUT0x00000008 | RTWN_CHIP_92C0x00000001)) == | |||
| 2130 | RTWN_CHIP_UMC_A_CUT0x00000008) | |||
| 2131 | name = "urtwn-rtl8192cU"; | |||
| 2132 | else | |||
| 2133 | name = "urtwn-rtl8192cT"; | |||
| 2134 | ||||
| 2135 | error = loadfirmware(name, fw, len); | |||
| 2136 | if (error) | |||
| 2137 | printf("%s: could not read firmware %s (error %d)\n", | |||
| 2138 | sc->sc_dev.dv_xname, name, error); | |||
| 2139 | return (error); | |||
| 2140 | } | |||
| 2141 | ||||
| 2142 | int | |||
| 2143 | urtwn_dma_init(void *cookie) | |||
| 2144 | { | |||
| 2145 | struct urtwn_softc *sc = cookie; | |||
| 2146 | uint32_t reg; | |||
| 2147 | uint16_t dmasize; | |||
| 2148 | int hqpages, lqpages, nqpages, pagecnt, boundary; | |||
| 2149 | int error, hashq, haslq, hasnq; | |||
| 2150 | ||||
| 2151 | /* Default initialization of chipset values. */ | |||
| 2152 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) { | |||
| 2153 | hqpages = R88E_HQ_NPAGES0; | |||
| 2154 | lqpages = R88E_LQ_NPAGES9; | |||
| 2155 | nqpages = R88E_NQ_NPAGES0; | |||
| 2156 | pagecnt = R88E_TX_PAGE_COUNT168; | |||
| 2157 | dmasize = R88E_MAX_RX_DMA_SIZE0x2400; | |||
| 2158 | } else if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2159 | hqpages = R88F_HQ_NPAGES12; | |||
| 2160 | lqpages = R88F_LQ_NPAGES2; | |||
| 2161 | nqpages = R88F_NQ_NPAGES2; | |||
| 2162 | pagecnt = R88F_TX_PAGE_COUNT247; | |||
| 2163 | dmasize = R88F_MAX_RX_DMA_SIZE0x3f80; | |||
| 2164 | } else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) { | |||
| 2165 | hqpages = R92E_HQ_NPAGES16; | |||
| 2166 | lqpages = R92E_LQ_NPAGES16; | |||
| 2167 | nqpages = R92E_NQ_NPAGES16; | |||
| 2168 | pagecnt = R92E_TX_PAGE_COUNT248; | |||
| 2169 | dmasize = R92E_MAX_RX_DMA_SIZE0x3fc0; | |||
| 2170 | } else { | |||
| 2171 | hqpages = R92C_HQ_NPAGES12; | |||
| 2172 | lqpages = R92C_LQ_NPAGES2; | |||
| 2173 | nqpages = R92C_NQ_NPAGES2; | |||
| 2174 | pagecnt = R92C_TX_PAGE_COUNT248; | |||
| 2175 | dmasize = R92C_MAX_RX_DMA_SIZE0x2800; | |||
| 2176 | } | |||
| 2177 | boundary = pagecnt + 1; | |||
| 2178 | ||||
| 2179 | /* Initialize LLT table. */ | |||
| 2180 | if (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) | |||
| 2181 | error = urtwn_auto_llt_init(sc); | |||
| 2182 | else | |||
| 2183 | error = urtwn_llt_init(sc, pagecnt); | |||
| 2184 | if (error != 0) | |||
| 2185 | return (error); | |||
| 2186 | ||||
| 2187 | /* Get Tx queues to USB endpoints mapping. */ | |||
| 2188 | hashq = hasnq = haslq = 0; | |||
| 2189 | switch (sc->ntx) { | |||
| 2190 | case 3: | |||
| 2191 | haslq = 1; | |||
| 2192 | pagecnt -= lqpages; | |||
| 2193 | /* FALLTHROUGH */ | |||
| 2194 | case 2: | |||
| 2195 | hasnq = 1; | |||
| 2196 | pagecnt -= nqpages; | |||
| 2197 | /* FALLTHROUGH */ | |||
| 2198 | case 1: | |||
| 2199 | hashq = 1; | |||
| 2200 | pagecnt -= hqpages; | |||
| 2201 | break; | |||
| 2202 | } | |||
| 2203 | ||||
| 2204 | /* Set number of pages for normal priority queue. */ | |||
| 2205 | urtwn_write_1(sc, R92C_RQPN_NPQ0x214, hasnq ? nqpages : 0); | |||
| 2206 | urtwn_write_4(sc, R92C_RQPN0x200, | |||
| 2207 | /* Set number of pages for public queue. */ | |||
| 2208 | SM(R92C_RQPN_PUBQ, pagecnt)(((pagecnt) << 16) & 0x00ff0000) | | |||
| 2209 | /* Set number of pages for high priority queue. */ | |||
| 2210 | SM(R92C_RQPN_HPQ, hashq ? hqpages : 0)(((hashq ? hqpages : 0) << 0) & 0x000000ff) | | |||
| 2211 | /* Set number of pages for low priority queue. */ | |||
| 2212 | SM(R92C_RQPN_LPQ, haslq ? lqpages : 0)(((haslq ? lqpages : 0) << 8) & 0x0000ff00) | | |||
| 2213 | /* Load values. */ | |||
| 2214 | R92C_RQPN_LD0x80000000); | |||
| 2215 | ||||
| 2216 | urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY0x424, boundary); | |||
| 2217 | urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY0x425, boundary); | |||
| 2218 | urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD0x45d, boundary); | |||
| 2219 | urtwn_write_1(sc, R92C_TRXFF_BNDY0x114, boundary); | |||
| 2220 | urtwn_write_1(sc, R92C_TDECTRL0x208 + 1, boundary); | |||
| 2221 | ||||
| 2222 | /* Set queue to USB pipe mapping. */ | |||
| 2223 | reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL0x10c); | |||
| 2224 | reg &= ~R92C_TRXDMA_CTRL_QMAP_M0xfff0; | |||
| 2225 | if (haslq) | |||
| 2226 | reg |= R92C_TRXDMA_CTRL_QMAP_3EP0xf5b0; | |||
| 2227 | else if (hashq) { | |||
| 2228 | if (!hasnq) | |||
| 2229 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ0xfff0; | |||
| 2230 | else | |||
| 2231 | reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ0xfaf0; | |||
| 2232 | } | |||
| 2233 | urtwn_write_2(sc, R92C_TRXDMA_CTRL0x10c, reg); | |||
| 2234 | ||||
| 2235 | /* Set Tx/Rx transfer page boundary. */ | |||
| 2236 | urtwn_write_2(sc, R92C_TRXFF_BNDY0x114 + 2, dmasize - 1); | |||
| 2237 | ||||
| 2238 | if (!(sc->sc_sc.chip & RTWN_CHIP_92E0x00000040)) { | |||
| 2239 | /* Set Tx/Rx transfer page size. */ | |||
| 2240 | if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2241 | urtwn_write_1(sc, R92C_PBP0x104, | |||
| 2242 | SM(R92C_PBP_PSRX, R92C_PBP_256)(((2) << 0) & 0x0f) | | |||
| 2243 | SM(R92C_PBP_PSTX, R92C_PBP_256)(((2) << 4) & 0xf0)); | |||
| 2244 | } else { | |||
| 2245 | urtwn_write_1(sc, R92C_PBP0x104, | |||
| 2246 | SM(R92C_PBP_PSRX, R92C_PBP_128)(((1) << 0) & 0x0f) | | |||
| 2247 | SM(R92C_PBP_PSTX, R92C_PBP_128)(((1) << 4) & 0xf0)); | |||
| 2248 | } | |||
| 2249 | } | |||
| 2250 | return (error); | |||
| 2251 | } | |||
| 2252 | ||||
| 2253 | void | |||
| 2254 | urtwn_aggr_init(void *cookie) | |||
| 2255 | { | |||
| 2256 | struct urtwn_softc *sc = cookie; | |||
| 2257 | uint32_t reg = 0; | |||
| 2258 | int dmasize, dmatiming, ndesc; | |||
| 2259 | ||||
| 2260 | /* Set burst packet length. */ | |||
| 2261 | if (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) | |||
| 2262 | urtwn_burstlen_init(sc); | |||
| 2263 | ||||
| 2264 | if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2265 | dmasize = 5; | |||
| 2266 | dmatiming = 32; | |||
| 2267 | ndesc = 6; | |||
| 2268 | } else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) { | |||
| 2269 | dmasize = 6; | |||
| 2270 | dmatiming = 32; | |||
| 2271 | ndesc = 3; | |||
| 2272 | } else { | |||
| 2273 | dmasize = 48; | |||
| 2274 | dmatiming = 4; | |||
| 2275 | ndesc = (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) ? 1 : 6; | |||
| 2276 | } | |||
| 2277 | ||||
| 2278 | /* Tx aggregation setting. */ | |||
| 2279 | reg = urtwn_read_4(sc, R92C_TDECTRL0x208); | |||
| 2280 | reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, ndesc)(((reg) & ~0x000000f0) | (((ndesc) << 4) & 0x000000f0 )); | |||
| 2281 | urtwn_write_4(sc, R92C_TDECTRL0x208, reg); | |||
| 2282 | if (sc->sc_sc.chip & (RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040)) | |||
| 2283 | urtwn_write_1(sc, R92E_DWBCN1_CTRL0x228, ndesc << 1); | |||
| 2284 | ||||
| 2285 | /* Rx aggregation setting. */ | |||
| 2286 | urtwn_write_1(sc, R92C_TRXDMA_CTRL0x10c, | |||
| 2287 | urtwn_read_1(sc, R92C_TRXDMA_CTRL0x10c) | R92C_TRXDMA_CTRL_RXDMA_AGG_EN0x0004); | |||
| 2288 | ||||
| 2289 | urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH0x280, dmasize); | |||
| 2290 | if (sc->sc_sc.chip & (RTWN_CHIP_92C0x00000001 | RTWN_CHIP_88C0x00000010)) | |||
| 2291 | urtwn_write_1(sc, R92C_USB_DMA_AGG_TO0xfe5b, dmatiming); | |||
| 2292 | else | |||
| 2293 | urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH0x280 + 1, dmatiming); | |||
| 2294 | ||||
| 2295 | if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2296 | urtwn_write_1(sc, R92E_RXDMA_PRO0x290, | |||
| 2297 | urtwn_read_1(sc, R92E_RXDMA_PRO0x290) | R92E_RXDMA_PRO_DMA_MODE0x02); | |||
| 2298 | } | |||
| 2299 | ||||
| 2300 | /* Drop incorrect bulk out. */ | |||
| 2301 | urtwn_write_4(sc, R92C_TXDMA_OFFSET_CHK0x20c, | |||
| 2302 | urtwn_read_4(sc, R92C_TXDMA_OFFSET_CHK0x20c) | | |||
| 2303 | R92C_TXDMA_OFFSET_CHK_DROP_DATA_EN0x00000200); | |||
| 2304 | } | |||
| 2305 | ||||
| 2306 | void | |||
| 2307 | urtwn_mac_init(void *cookie) | |||
| 2308 | { | |||
| 2309 | struct urtwn_softc *sc = cookie; | |||
| 2310 | int i; | |||
| 2311 | ||||
| 2312 | /* Write MAC initialization values. */ | |||
| 2313 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) { | |||
| 2314 | for (i = 0; i < nitems(rtl8188eu_mac)(sizeof((rtl8188eu_mac)) / sizeof((rtl8188eu_mac)[0])); i++) { | |||
| 2315 | urtwn_write_1(sc, rtl8188eu_mac[i].reg, | |||
| 2316 | rtl8188eu_mac[i].val); | |||
| 2317 | } | |||
| 2318 | urtwn_write_1(sc, R92C_MAX_AGGR_NUM0x4ca, 0x07); | |||
| 2319 | } else if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2320 | for (i = 0; i < nitems(rtl8188ftv_mac)(sizeof((rtl8188ftv_mac)) / sizeof((rtl8188ftv_mac)[0])); i++) { | |||
| 2321 | urtwn_write_1(sc, rtl8188ftv_mac[i].reg, | |||
| 2322 | rtl8188ftv_mac[i].val); | |||
| 2323 | } | |||
| 2324 | } else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) { | |||
| 2325 | for (i = 0; i < nitems(rtl8192eu_mac)(sizeof((rtl8192eu_mac)) / sizeof((rtl8192eu_mac)[0])); i++) { | |||
| 2326 | urtwn_write_1(sc, rtl8192eu_mac[i].reg, | |||
| 2327 | rtl8192eu_mac[i].val); | |||
| 2328 | } | |||
| 2329 | } else { | |||
| 2330 | for (i = 0; i < nitems(rtl8192cu_mac)(sizeof((rtl8192cu_mac)) / sizeof((rtl8192cu_mac)[0])); i++) | |||
| 2331 | urtwn_write_1(sc, rtl8192cu_mac[i].reg, | |||
| 2332 | rtl8192cu_mac[i].val); | |||
| 2333 | } | |||
| 2334 | } | |||
| 2335 | ||||
| 2336 | void | |||
| 2337 | urtwn_bb_init(void *cookie) | |||
| 2338 | { | |||
| 2339 | struct urtwn_softc *sc = cookie; | |||
| 2340 | const struct r92c_bb_prog *prog; | |||
| 2341 | uint32_t reg; | |||
| 2342 | uint8_t xtal; | |||
| 2343 | int i; | |||
| 2344 | ||||
| 2345 | /* Enable BB and RF. */ | |||
| 2346 | urtwn_write_2(sc, R92C_SYS_FUNC_EN0x002, | |||
| 2347 | urtwn_read_2(sc, R92C_SYS_FUNC_EN0x002) | | |||
| 2348 | R92C_SYS_FUNC_EN_BBRSTB0x0001 | R92C_SYS_FUNC_EN_BB_GLB_RST0x0002 | | |||
| 2349 | R92C_SYS_FUNC_EN_DIO_RF0x2000); | |||
| 2350 | ||||
| 2351 | if (!(sc->sc_sc.chip & (RTWN_CHIP_88E0x00000020 | RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040))) | |||
| 2352 | urtwn_write_2(sc, R92C_AFE_PLL_CTRL0x028, 0xdb83); | |||
| 2353 | ||||
| 2354 | urtwn_write_1(sc, R92C_RF_CTRL0x01f, | |||
| 2355 | R92C_RF_CTRL_EN0x01 | R92C_RF_CTRL_RSTB0x02 | R92C_RF_CTRL_SDMRSTB0x04); | |||
| 2356 | urtwn_write_1(sc, R92C_SYS_FUNC_EN0x002, | |||
| 2357 | R92C_SYS_FUNC_EN_USBA0x0004 | R92C_SYS_FUNC_EN_USBD0x0010 | | |||
| 2358 | R92C_SYS_FUNC_EN_BB_GLB_RST0x0002 | R92C_SYS_FUNC_EN_BBRSTB0x0001); | |||
| 2359 | ||||
| 2360 | if (!(sc->sc_sc.chip & | |||
| 2361 | (RTWN_CHIP_88E0x00000020 | RTWN_CHIP_88F0x00000200 | RTWN_CHIP_92E0x00000040))) { | |||
| 2362 | urtwn_write_1(sc, R92C_LDOHCI12_CTRL0x022, 0x0f); | |||
| 2363 | urtwn_write_1(sc, 0x15, 0xe9); | |||
| 2364 | urtwn_write_1(sc, R92C_AFE_XTAL_CTRL0x024 + 1, 0x80); | |||
| 2365 | } | |||
| 2366 | ||||
| 2367 | /* Select BB programming based on board type. */ | |||
| 2368 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) | |||
| 2369 | prog = &rtl8188eu_bb_prog; | |||
| 2370 | else if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) | |||
| 2371 | prog = &rtl8188ftv_bb_prog; | |||
| 2372 | else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) | |||
| 2373 | prog = &rtl8192eu_bb_prog; | |||
| 2374 | else if (!(sc->sc_sc.chip & RTWN_CHIP_92C0x00000001)) { | |||
| 2375 | if (sc->sc_sc.board_type == R92C_BOARD_TYPE_MINICARD2) | |||
| 2376 | prog = &rtl8188ce_bb_prog; | |||
| 2377 | else if (sc->sc_sc.board_type == R92C_BOARD_TYPE_HIGHPA1) | |||
| 2378 | prog = &rtl8188ru_bb_prog; | |||
| 2379 | else | |||
| 2380 | prog = &rtl8188cu_bb_prog; | |||
| 2381 | } else { | |||
| 2382 | if (sc->sc_sc.board_type == R92C_BOARD_TYPE_MINICARD2) | |||
| 2383 | prog = &rtl8192ce_bb_prog; | |||
| 2384 | else | |||
| 2385 | prog = &rtl8192cu_bb_prog; | |||
| 2386 | } | |||
| 2387 | /* Write BB initialization values. */ | |||
| 2388 | for (i = 0; i < prog->count; i++) { | |||
| 2389 | urtwn_bb_writeurtwn_write_4(sc, prog->regs[i], prog->vals[i]); | |||
| 2390 | DELAY(1)(*delay_func)(1); | |||
| 2391 | } | |||
| 2392 | ||||
| 2393 | if (sc->sc_sc.chip & RTWN_CHIP_92C_1T2R0x00000002) { | |||
| 2394 | /* 8192C 1T only configuration. */ | |||
| 2395 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_FPGA0_TXINFO0x804); | |||
| 2396 | reg = (reg & ~0x00000003) | 0x2; | |||
| 2397 | urtwn_bb_writeurtwn_write_4(sc, R92C_FPGA0_TXINFO0x804, reg); | |||
| 2398 | ||||
| 2399 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_FPGA1_TXINFO0x90c); | |||
| 2400 | reg = (reg & ~0x00300033) | 0x00200022; | |||
| 2401 | urtwn_bb_writeurtwn_write_4(sc, R92C_FPGA1_TXINFO0x90c, reg); | |||
| 2402 | ||||
| 2403 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_CCK0_AFESETTING0xa04); | |||
| 2404 | reg = (reg & ~0xff000000) | 0x45 << 24; | |||
| 2405 | urtwn_bb_writeurtwn_write_4(sc, R92C_CCK0_AFESETTING0xa04, reg); | |||
| 2406 | ||||
| 2407 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_OFDM0_TRXPATHENA0xc04); | |||
| 2408 | reg = (reg & ~0x000000ff) | 0x23; | |||
| 2409 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_TRXPATHENA0xc04, reg); | |||
| 2410 | ||||
| 2411 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_OFDM0_AGCPARAM10xc70); | |||
| 2412 | reg = (reg & ~0x00000030) | 1 << 4; | |||
| 2413 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCPARAM10xc70, reg); | |||
| 2414 | ||||
| 2415 | reg = urtwn_bb_readurtwn_read_4(sc, 0xe74); | |||
| 2416 | reg = (reg & ~0x0c000000) | 2 << 26; | |||
| 2417 | urtwn_bb_writeurtwn_write_4(sc, 0xe74, reg); | |||
| 2418 | reg = urtwn_bb_readurtwn_read_4(sc, 0xe78); | |||
| 2419 | reg = (reg & ~0x0c000000) | 2 << 26; | |||
| 2420 | urtwn_bb_writeurtwn_write_4(sc, 0xe78, reg); | |||
| 2421 | reg = urtwn_bb_readurtwn_read_4(sc, 0xe7c); | |||
| 2422 | reg = (reg & ~0x0c000000) | 2 << 26; | |||
| 2423 | urtwn_bb_writeurtwn_write_4(sc, 0xe7c, reg); | |||
| 2424 | reg = urtwn_bb_readurtwn_read_4(sc, 0xe80); | |||
| 2425 | reg = (reg & ~0x0c000000) | 2 << 26; | |||
| 2426 | urtwn_bb_writeurtwn_write_4(sc, 0xe80, reg); | |||
| 2427 | reg = urtwn_bb_readurtwn_read_4(sc, 0xe88); | |||
| 2428 | reg = (reg & ~0x0c000000) | 2 << 26; | |||
| 2429 | urtwn_bb_writeurtwn_write_4(sc, 0xe88, reg); | |||
| 2430 | } | |||
| 2431 | ||||
| 2432 | /* Write AGC values. */ | |||
| 2433 | for (i = 0; i < prog->agccount; i++) { | |||
| 2434 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCRSSITABLE0xc78, | |||
| 2435 | prog->agcvals[i]); | |||
| 2436 | DELAY(1)(*delay_func)(1); | |||
| 2437 | } | |||
| 2438 | ||||
| 2439 | if (sc->sc_sc.chip & (RTWN_CHIP_88E0x00000020 | RTWN_CHIP_88F0x00000200)) { | |||
| 2440 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCCORE1(0)(0xc50 + (0) * 8), 0x69553422); | |||
| 2441 | DELAY(1)(*delay_func)(1); | |||
| 2442 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCCORE1(0)(0xc50 + (0) * 8), 0x69553420); | |||
| 2443 | DELAY(1)(*delay_func)(1); | |||
| 2444 | } else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) { | |||
| 2445 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCCORE1(0)(0xc50 + (0) * 8), 0x00040022); | |||
| 2446 | DELAY(1)(*delay_func)(1); | |||
| 2447 | urtwn_bb_writeurtwn_write_4(sc, R92C_OFDM0_AGCCORE1(0)(0xc50 + (0) * 8), 0x00040020); | |||
| 2448 | DELAY(1)(*delay_func)(1); | |||
| 2449 | } | |||
| 2450 | ||||
| 2451 | if (sc->sc_sc.chip & (RTWN_CHIP_88E0x00000020 | RTWN_CHIP_88F0x00000200)) { | |||
| 2452 | xtal = sc->sc_sc.crystal_cap & 0x3f; | |||
| 2453 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_AFE_XTAL_CTRL0x024); | |||
| 2454 | urtwn_bb_writeurtwn_write_4(sc, R92C_AFE_XTAL_CTRL0x024, | |||
| 2455 | RW(reg, R92C_AFE_XTAL_CTRL_ADDR, xtal | xtal << 6)(((reg) & ~0x007ff800) | (((xtal | xtal << 6) << 11) & 0x007ff800))); | |||
| 2456 | } else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) { | |||
| 2457 | xtal = sc->sc_sc.crystal_cap & 0x3f; | |||
| 2458 | reg = urtwn_bb_readurtwn_read_4(sc, R92C_AFE_CTRL30x02c); | |||
| 2459 | urtwn_bb_writeurtwn_write_4(sc, R92C_AFE_CTRL30x02c, | |||
| 2460 | RW(reg, R92C_AFE_CTRL3_ADDR, xtal | xtal << 6)(((reg) & ~0x00fff000) | (((xtal | xtal << 6) << 12) & 0x00fff000))); | |||
| 2461 | urtwn_write_4(sc, R92C_AFE_XTAL_CTRL0x024, 0x000f81fb); | |||
| 2462 | } | |||
| 2463 | ||||
| 2464 | if (urtwn_bb_readurtwn_read_4(sc, R92C_HSSI_PARAM2(0)(0x824 + (0) * 8)) & R92C_HSSI_PARAM2_CCK_HIPWR0x00000200) | |||
| 2465 | sc->sc_sc.sc_flags |= RTWN_FLAG_CCK_HIPWR0x01; | |||
| 2466 | } | |||
| 2467 | ||||
| 2468 | void | |||
| 2469 | urtwn_burstlen_init(struct urtwn_softc *sc) | |||
| 2470 | { | |||
| 2471 | uint8_t reg; | |||
| 2472 | ||||
| 2473 | reg = urtwn_read_1(sc, R92E_RXDMA_PRO0x290); | |||
| 2474 | reg &= ~0x30; | |||
| 2475 | switch (sc->sc_udev->speed) { | |||
| 2476 | case USB_SPEED_HIGH3: | |||
| 2477 | urtwn_write_1(sc, R92E_RXDMA_PRO0x290, reg | 0x1e); | |||
| 2478 | break; | |||
| 2479 | default: | |||
| 2480 | urtwn_write_1(sc, R92E_RXDMA_PRO0x290, reg | 0x2e); | |||
| 2481 | break; | |||
| 2482 | } | |||
| 2483 | ||||
| 2484 | if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) { | |||
| 2485 | /* Setup AMPDU aggregation. */ | |||
| 2486 | urtwn_write_1(sc, R88F_HT_SINGLE_AMPDU0x4c7, | |||
| 2487 | urtwn_read_1(sc, R88F_HT_SINGLE_AMPDU0x4c7) | | |||
| 2488 | R88F_HT_SINGLE_AMPDU_EN0x80); | |||
| 2489 | urtwn_write_2(sc, R92C_MAX_AGGR_NUM0x4ca, 0x0c14); | |||
| 2490 | urtwn_write_1(sc, R88F_AMPDU_MAX_TIME0x456, 0x70); | |||
| 2491 | urtwn_write_4(sc, R92C_AGGLEN_LMT0x458, 0xffffffff); | |||
| 2492 | ||||
| 2493 | /* For VHT packet length 11K */ | |||
| 2494 | urtwn_write_1(sc, R88F_RX_PKT_LIMIT0x60c, 0x18); | |||
| 2495 | ||||
| 2496 | urtwn_write_1(sc, R92C_PIFS0x512, 0); | |||
| 2497 | urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL0x420, 0x80); | |||
| 2498 | urtwn_write_4(sc, R92C_FAST_EDCA_CTRL0x460, 0x03086666); | |||
| 2499 | urtwn_write_1(sc, R92C_USTIME_TSF0x55c, 0x28); | |||
| 2500 | urtwn_write_1(sc, R88F_USTIME_EDCA0x638, 0x28); | |||
| 2501 | ||||
| 2502 | /* To prevent mac is reseted by bus. */ | |||
| 2503 | urtwn_write_1(sc, R92C_RSV_CTRL0x01c, | |||
| 2504 | urtwn_read_1(sc, R92C_RSV_CTRL0x01c) | | |||
| 2505 | R92C_RSV_CTRL_R_DIS_PRST_00x0020 | R92C_RSV_CTRL_R_DIS_PRST_10x0040); | |||
| 2506 | } | |||
| 2507 | } | |||
| 2508 | ||||
| 2509 | int | |||
| 2510 | urtwn_power_on(void *cookie) | |||
| 2511 | { | |||
| 2512 | struct urtwn_softc *sc = cookie; | |||
| 2513 | ||||
| 2514 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) | |||
| 2515 | return (urtwn_r88e_power_on(sc)); | |||
| 2516 | else if (sc->sc_sc.chip & RTWN_CHIP_88F0x00000200) | |||
| 2517 | return (urtwn_r88f_power_on(sc)); | |||
| 2518 | else if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) | |||
| 2519 | return (urtwn_r92e_power_on(sc)); | |||
| 2520 | ||||
| 2521 | return (urtwn_r92c_power_on(sc)); | |||
| 2522 | } | |||
| 2523 | ||||
| 2524 | int | |||
| 2525 | urtwn_alloc_buffers(void *cookie) | |||
| 2526 | { | |||
| 2527 | struct urtwn_softc *sc = cookie; | |||
| 2528 | int error; | |||
| 2529 | ||||
| 2530 | /* Init host async commands ring. */ | |||
| 2531 | sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; | |||
| 2532 | ||||
| 2533 | /* Allocate Tx/Rx buffers. */ | |||
| 2534 | error = urtwn_alloc_rx_list(sc); | |||
| 2535 | if (error != 0) { | |||
| 2536 | printf("%s: could not allocate Rx buffers\n", | |||
| 2537 | sc->sc_dev.dv_xname); | |||
| 2538 | return (error); | |||
| 2539 | } | |||
| 2540 | error = urtwn_alloc_tx_list(sc); | |||
| 2541 | if (error != 0) { | |||
| 2542 | printf("%s: could not allocate Tx buffers\n", | |||
| 2543 | sc->sc_dev.dv_xname); | |||
| 2544 | return (error); | |||
| 2545 | } | |||
| 2546 | ||||
| 2547 | return (0); | |||
| 2548 | } | |||
| 2549 | ||||
| 2550 | int | |||
| 2551 | urtwn_init(void *cookie) | |||
| 2552 | { | |||
| 2553 | struct urtwn_softc *sc = cookie; | |||
| 2554 | int i, error; | |||
| 2555 | ||||
| 2556 | /* Reset USB mode switch setting. */ | |||
| 2557 | if (sc->sc_sc.chip & RTWN_CHIP_92E0x00000040) | |||
| 2558 | urtwn_write_1(sc, R92C_ACLK_MON0x03e, 0); | |||
| 2559 | ||||
| 2560 | /* Queue Rx xfers. */ | |||
| 2561 | for (i = 0; i < URTWN_RX_LIST_COUNT1; i++) { | |||
| 2562 | struct urtwn_rx_data *data = &sc->rx_data[i]; | |||
| 2563 | ||||
| 2564 | usbd_setup_xfer(data->xfer, sc->rx_pipe, data, data->buf, | |||
| 2565 | URTWN_RXBUFSZ(16 * 1024), USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01, | |||
| 2566 | USBD_NO_TIMEOUT0, urtwn_rxeof); | |||
| 2567 | error = usbd_transfer(data->xfer); | |||
| 2568 | if (error != 0 && error != USBD_IN_PROGRESS) | |||
| 2569 | return (error); | |||
| 2570 | } | |||
| 2571 | ||||
| 2572 | ieee80211_amrr_node_init(&sc->amrr, &sc->amn); | |||
| 2573 | ||||
| 2574 | /* | |||
| 2575 | * Enable TX reports for AMRR. | |||
| 2576 | * In order to get reports we need to explicitly reset the register. | |||
| 2577 | */ | |||
| 2578 | if (sc->sc_sc.chip & RTWN_CHIP_88E0x00000020) | |||
| 2579 | urtwn_write_1(sc, R88E_TX_RPT_CTRL0x4ec, (urtwn_read_1(sc, | |||
| 2580 | R88E_TX_RPT_CTRL0x4ec) & ~0) | R88E_TX_RPT_CTRL_EN0x01); | |||
| 2581 | ||||
| 2582 | return (0); | |||
| 2583 | } | |||
| 2584 | ||||
| 2585 | void | |||
| 2586 | urtwn_stop(void *cookie) | |||
| 2587 | { | |||
| 2588 | struct urtwn_softc *sc = cookie; | |||
| 2589 | int i; | |||
| 2590 | ||||
| 2591 | /* Abort Tx. */ | |||
| 2592 | for (i = 0; i < R92C_MAX_EPOUT3; i++) { | |||
| 2593 | if (sc->tx_pipe[i] != NULL((void *)0)) | |||
| 2594 | usbd_abort_pipe(sc->tx_pipe[i]); | |||
| 2595 | } | |||
| 2596 | /* Stop Rx pipe. */ | |||
| 2597 | usbd_abort_pipe(sc->rx_pipe); | |||
| 2598 | /* Free Tx/Rx buffers. */ | |||
| 2599 | urtwn_free_tx_list(sc); | |||
| 2600 | urtwn_free_rx_list(sc); | |||
| 2601 | } | |||
| 2602 | ||||
| 2603 | int | |||
| 2604 | urtwn_is_oactive(void *cookie) | |||
| 2605 | { | |||
| 2606 | struct urtwn_softc *sc = cookie; | |||
| 2607 | ||||
| 2608 | return (TAILQ_EMPTY(&sc->tx_free_list)(((&sc->tx_free_list)->tqh_first) == ((void *)0))); | |||
| 2609 | } |