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