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