1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr 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) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 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 #include <sys/cdefs.h> 22 #include <sys/param.h> 23 #include <sys/sysctl.h> 24 #include <sys/lock.h> 25 #include <sys/mutex.h> 26 #include <sys/mbuf.h> 27 #include <sys/kernel.h> 28 #include <sys/socket.h> 29 #include <sys/systm.h> 30 #include <sys/malloc.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 #include <sys/endian.h> 34 #include <sys/linker.h> 35 #include <sys/kdb.h> 36 37 #include <net/if.h> 38 #include <net/if_var.h> 39 #include <net/ethernet.h> 40 #include <net/if_media.h> 41 42 #include <net80211/ieee80211_var.h> 43 44 #include <dev/usb/usb.h> 45 #include <dev/usb/usbdi.h> 46 #include "usbdevs.h" 47 48 #include <dev/rtwn/if_rtwnvar.h> 49 #include <dev/rtwn/if_rtwn_nop.h> 50 51 #include <dev/rtwn/usb/rtwn_usb_var.h> 52 53 #include <dev/rtwn/usb/rtwn_usb_attach.h> 54 #include <dev/rtwn/usb/rtwn_usb_ep.h> 55 #include <dev/rtwn/usb/rtwn_usb_reg.h> 56 #include <dev/rtwn/usb/rtwn_usb_tx.h> 57 58 #include <dev/rtwn/rtl8192c/r92c_reg.h> 59 60 static device_probe_t rtwn_usb_match; 61 static device_attach_t rtwn_usb_attach; 62 static device_detach_t rtwn_usb_detach; 63 static device_suspend_t rtwn_usb_suspend; 64 static device_resume_t rtwn_usb_resume; 65 66 static int rtwn_usb_alloc_list(struct rtwn_softc *, 67 struct rtwn_data[], int, int); 68 static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); 69 static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); 70 static void rtwn_usb_free_list(struct rtwn_softc *, 71 struct rtwn_data data[], int); 72 static void rtwn_usb_free_rx_list(struct rtwn_softc *); 73 static void rtwn_usb_free_tx_list(struct rtwn_softc *); 74 static void rtwn_usb_reset_lists(struct rtwn_softc *, 75 struct ieee80211vap *); 76 static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, 77 rtwn_datahead *, struct ieee80211vap *); 78 static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *); 79 static void rtwn_usb_start_xfers(struct rtwn_softc *); 80 static void rtwn_usb_abort_xfers(struct rtwn_softc *); 81 static int rtwn_usb_fw_write_block(struct rtwn_softc *, 82 const uint8_t *, uint16_t, int); 83 static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *); 84 static void rtwn_usb_attach_methods(struct rtwn_softc *); 85 static void rtwn_usb_sysctlattach(struct rtwn_softc *); 86 87 #define RTWN_CONFIG_INDEX 0 88 89 static int 90 rtwn_usb_match(device_t self) 91 { 92 struct usb_attach_arg *uaa = device_get_ivars(self); 93 94 if (uaa->usb_mode != USB_MODE_HOST) 95 return (ENXIO); 96 if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) 97 return (ENXIO); 98 if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) 99 return (ENXIO); 100 101 return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); 102 } 103 104 static int 105 rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], 106 int ndata, int maxsz) 107 { 108 int i, error; 109 110 for (i = 0; i < ndata; i++) { 111 struct rtwn_data *dp = &data[i]; 112 dp->m = NULL; 113 dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 114 if (dp->buf == NULL) { 115 device_printf(sc->sc_dev, 116 "could not allocate buffer\n"); 117 error = ENOMEM; 118 goto fail; 119 } 120 dp->ni = NULL; 121 } 122 123 return (0); 124 fail: 125 rtwn_usb_free_list(sc, data, ndata); 126 return (error); 127 } 128 129 static int 130 rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) 131 { 132 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 133 int error, i; 134 135 error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, 136 uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT); 137 if (error != 0) 138 return (error); 139 140 STAILQ_INIT(&uc->uc_rx_active); 141 STAILQ_INIT(&uc->uc_rx_inactive); 142 143 for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) 144 STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); 145 146 return (0); 147 } 148 149 static int 150 rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) 151 { 152 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 153 int error, i; 154 155 error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, 156 RTWN_USB_TXBUFSZ); 157 if (error != 0) 158 return (error); 159 160 STAILQ_INIT(&uc->uc_tx_active); 161 STAILQ_INIT(&uc->uc_tx_inactive); 162 STAILQ_INIT(&uc->uc_tx_pending); 163 164 for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) 165 STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); 166 167 return (0); 168 } 169 170 static void 171 rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) 172 { 173 int i; 174 175 for (i = 0; i < ndata; i++) { 176 struct rtwn_data *dp = &data[i]; 177 178 if (dp->buf != NULL) { 179 free(dp->buf, M_USBDEV); 180 dp->buf = NULL; 181 } 182 if (dp->ni != NULL) { 183 ieee80211_free_node(dp->ni); 184 dp->ni = NULL; 185 } 186 if (dp->m != NULL) { 187 m_freem(dp->m); 188 dp->m = NULL; 189 } 190 } 191 } 192 193 static void 194 rtwn_usb_free_rx_list(struct rtwn_softc *sc) 195 { 196 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 197 198 rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); 199 200 uc->uc_rx_stat_len = 0; 201 uc->uc_rx_off = 0; 202 203 STAILQ_INIT(&uc->uc_rx_active); 204 STAILQ_INIT(&uc->uc_rx_inactive); 205 } 206 207 static void 208 rtwn_usb_free_tx_list(struct rtwn_softc *sc) 209 { 210 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 211 212 rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); 213 214 STAILQ_INIT(&uc->uc_tx_active); 215 STAILQ_INIT(&uc->uc_tx_inactive); 216 STAILQ_INIT(&uc->uc_tx_pending); 217 } 218 219 static void 220 rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) 221 { 222 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 223 224 RTWN_ASSERT_LOCKED(sc); 225 226 rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); 227 rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); 228 if (vap == NULL) { 229 rtwn_usb_reset_rx_list(uc); 230 sc->qfullmsk = 0; 231 } 232 } 233 234 static void 235 rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, 236 rtwn_datahead *head, struct ieee80211vap *vap) 237 { 238 struct rtwn_vap *uvp = RTWN_VAP(vap); 239 struct rtwn_data *dp, *tmp; 240 int id; 241 242 id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); 243 244 STAILQ_FOREACH_SAFE(dp, head, next, tmp) { 245 if (vap == NULL || (dp->ni == NULL && 246 (dp->id == id || id == RTWN_VAP_ID_INVALID)) || 247 (dp->ni != NULL && dp->ni->ni_vap == vap)) { 248 if (dp->ni != NULL) { 249 ieee80211_free_node(dp->ni); 250 dp->ni = NULL; 251 } 252 253 if (dp->m != NULL) { 254 m_freem(dp->m); 255 dp->m = NULL; 256 } 257 258 STAILQ_REMOVE(head, dp, rtwn_data, next); 259 STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); 260 } 261 } 262 } 263 264 static void 265 rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc) 266 { 267 int i; 268 269 for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) { 270 struct rtwn_data *dp = &uc->uc_rx[i]; 271 272 if (dp->m != NULL) { 273 m_freem(dp->m); 274 dp->m = NULL; 275 } 276 } 277 uc->uc_rx_stat_len = 0; 278 uc->uc_rx_off = 0; 279 } 280 281 static void 282 rtwn_usb_start_xfers(struct rtwn_softc *sc) 283 { 284 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 285 286 usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); 287 } 288 289 static void 290 rtwn_usb_abort_xfers(struct rtwn_softc *sc) 291 { 292 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 293 int i; 294 295 RTWN_ASSERT_LOCKED(sc); 296 297 /* abort any pending transfers */ 298 RTWN_UNLOCK(sc); 299 for (i = 0; i < RTWN_N_TRANSFER; i++) 300 usbd_transfer_drain(uc->uc_xfer[i]); 301 RTWN_LOCK(sc); 302 } 303 304 static int 305 rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, 306 uint16_t reg, int mlen) 307 { 308 int error; 309 310 /* XXX fix this deconst */ 311 error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), 312 mlen); 313 314 return (error); 315 } 316 317 static void 318 rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) 319 { 320 321 rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, 322 R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); 323 } 324 325 static void 326 rtwn_usb_attach_methods(struct rtwn_softc *sc) 327 { 328 sc->sc_write_1 = rtwn_usb_write_1; 329 sc->sc_write_2 = rtwn_usb_write_2; 330 sc->sc_write_4 = rtwn_usb_write_4; 331 sc->sc_read_1 = rtwn_usb_read_1; 332 sc->sc_read_2 = rtwn_usb_read_2; 333 sc->sc_read_4 = rtwn_usb_read_4; 334 sc->sc_delay = rtwn_usb_delay; 335 sc->sc_tx_start = rtwn_usb_tx_start; 336 sc->sc_start_xfers = rtwn_usb_start_xfers; 337 sc->sc_reset_lists = rtwn_usb_reset_lists; 338 sc->sc_abort_xfers = rtwn_usb_abort_xfers; 339 sc->sc_fw_write_block = rtwn_usb_fw_write_block; 340 sc->sc_get_qmap = rtwn_usb_get_qmap; 341 sc->sc_set_desc_addr = rtwn_nop_softc; 342 sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; 343 sc->sc_beacon_update_begin = rtwn_nop_softc_vap; 344 sc->sc_beacon_update_end = rtwn_nop_softc_vap; 345 sc->sc_beacon_unload = rtwn_nop_softc_int; 346 347 sc->bcn_check_interval = 100; 348 } 349 350 static void 351 rtwn_usb_sysctlattach(struct rtwn_softc *sc) 352 { 353 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 354 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 355 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 356 char str[64]; 357 int ret; 358 359 ret = snprintf(str, sizeof(str), 360 "Rx buffer size, 512-byte units [%d...%d]", 361 RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX); 362 KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret)); 363 (void) ret; 364 365 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF; 366 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 367 "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size, 368 uc->uc_rx_buf_size, str); 369 if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN) 370 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN; 371 if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX) 372 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX; 373 } 374 375 static int 376 rtwn_usb_attach(device_t self) 377 { 378 struct usb_attach_arg *uaa = device_get_ivars(self); 379 struct rtwn_usb_softc *uc = device_get_softc(self); 380 struct rtwn_softc *sc = &uc->uc_sc; 381 struct ieee80211com *ic = &sc->sc_ic; 382 int error; 383 384 device_set_usb_desc(self); 385 uc->uc_udev = uaa->device; 386 sc->sc_dev = self; 387 ic->ic_name = device_get_nameunit(self); 388 389 /* Need to be initialized early. */ 390 rtwn_sysctlattach(sc); 391 rtwn_usb_sysctlattach(sc); 392 mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); 393 394 rtwn_usb_attach_methods(sc); 395 rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); 396 397 error = rtwn_usb_setup_endpoints(uc); 398 if (error != 0) 399 goto detach; 400 401 /* Allocate Tx/Rx buffers. */ 402 error = rtwn_usb_alloc_rx_list(sc); 403 if (error != 0) 404 goto detach; 405 406 error = rtwn_usb_alloc_tx_list(sc); 407 if (error != 0) 408 goto detach; 409 410 /* Generic attach. */ 411 error = rtwn_attach(sc); 412 if (error != 0) 413 goto detach; 414 415 return (0); 416 417 detach: 418 rtwn_usb_detach(self); /* failure */ 419 return (ENXIO); 420 } 421 422 static int 423 rtwn_usb_detach(device_t self) 424 { 425 struct rtwn_usb_softc *uc = device_get_softc(self); 426 struct rtwn_softc *sc = &uc->uc_sc; 427 428 /* Generic detach. */ 429 rtwn_detach(sc); 430 431 /* Free Tx/Rx buffers. */ 432 rtwn_usb_free_tx_list(sc); 433 rtwn_usb_free_rx_list(sc); 434 435 /* Detach all USB transfers. */ 436 usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); 437 438 rtwn_detach_private(sc); 439 mtx_destroy(&sc->sc_mtx); 440 441 return (0); 442 } 443 444 static int 445 rtwn_usb_suspend(device_t self) 446 { 447 struct rtwn_usb_softc *uc = device_get_softc(self); 448 449 rtwn_suspend(&uc->uc_sc); 450 451 return (0); 452 } 453 454 static int 455 rtwn_usb_resume(device_t self) 456 { 457 struct rtwn_usb_softc *uc = device_get_softc(self); 458 459 rtwn_resume(&uc->uc_sc); 460 461 return (0); 462 } 463 464 static device_method_t rtwn_usb_methods[] = { 465 /* Device interface */ 466 DEVMETHOD(device_probe, rtwn_usb_match), 467 DEVMETHOD(device_attach, rtwn_usb_attach), 468 DEVMETHOD(device_detach, rtwn_usb_detach), 469 DEVMETHOD(device_suspend, rtwn_usb_suspend), 470 DEVMETHOD(device_resume, rtwn_usb_resume), 471 472 DEVMETHOD_END 473 }; 474 475 static driver_t rtwn_usb_driver = { 476 "rtwn", 477 rtwn_usb_methods, 478 sizeof(struct rtwn_usb_softc) 479 }; 480 481 DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, NULL, NULL); 482 MODULE_VERSION(rtwn_usb, 1); 483 MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); 484 MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); 485 MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); 486 USB_PNP_HOST_INFO(rtwn_devs); 487