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