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