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