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 /* XXX recheck */ 137 error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, 138 sc->rx_dma_size + 1024); 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_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 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 sc->qfullmsk = 0; 229 } 230 231 static void 232 rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, 233 rtwn_datahead *head, struct ieee80211vap *vap) 234 { 235 struct rtwn_vap *uvp = RTWN_VAP(vap); 236 struct rtwn_data *dp, *tmp; 237 int id; 238 239 id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); 240 241 STAILQ_FOREACH_SAFE(dp, head, next, tmp) { 242 if (vap == NULL || (dp->ni == NULL && 243 (dp->id == id || id == RTWN_VAP_ID_INVALID)) || 244 (dp->ni != NULL && dp->ni->ni_vap == vap)) { 245 if (dp->ni != NULL) { 246 ieee80211_free_node(dp->ni); 247 dp->ni = NULL; 248 } 249 250 if (dp->m != NULL) { 251 m_freem(dp->m); 252 dp->m = NULL; 253 } 254 255 STAILQ_REMOVE(head, dp, rtwn_data, next); 256 STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); 257 } 258 } 259 } 260 261 static void 262 rtwn_usb_start_xfers(struct rtwn_softc *sc) 263 { 264 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 265 266 usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); 267 } 268 269 static void 270 rtwn_usb_abort_xfers(struct rtwn_softc *sc) 271 { 272 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 273 int i; 274 275 RTWN_ASSERT_LOCKED(sc); 276 277 /* abort any pending transfers */ 278 RTWN_UNLOCK(sc); 279 for (i = 0; i < RTWN_N_TRANSFER; i++) 280 usbd_transfer_drain(uc->uc_xfer[i]); 281 RTWN_LOCK(sc); 282 } 283 284 static int 285 rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, 286 uint16_t reg, int mlen) 287 { 288 int error; 289 290 /* XXX fix this deconst */ 291 error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), 292 mlen); 293 294 return (error); 295 } 296 297 static void 298 rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) 299 { 300 301 rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, 302 R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); 303 } 304 305 static void 306 rtwn_usb_attach_methods(struct rtwn_softc *sc) 307 { 308 sc->sc_write_1 = rtwn_usb_write_1; 309 sc->sc_write_2 = rtwn_usb_write_2; 310 sc->sc_write_4 = rtwn_usb_write_4; 311 sc->sc_read_1 = rtwn_usb_read_1; 312 sc->sc_read_2 = rtwn_usb_read_2; 313 sc->sc_read_4 = rtwn_usb_read_4; 314 sc->sc_delay = rtwn_usb_delay; 315 sc->sc_tx_start = rtwn_usb_tx_start; 316 sc->sc_start_xfers = rtwn_usb_start_xfers; 317 sc->sc_reset_lists = rtwn_usb_reset_lists; 318 sc->sc_abort_xfers = rtwn_usb_abort_xfers; 319 sc->sc_fw_write_block = rtwn_usb_fw_write_block; 320 sc->sc_get_qmap = rtwn_usb_get_qmap; 321 sc->sc_set_desc_addr = rtwn_nop_softc; 322 sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; 323 sc->sc_beacon_update_begin = rtwn_nop_softc_vap; 324 sc->sc_beacon_update_end = rtwn_nop_softc_vap; 325 sc->sc_beacon_unload = rtwn_nop_softc_int; 326 327 sc->bcn_check_interval = 100; 328 } 329 330 static int 331 rtwn_usb_attach(device_t self) 332 { 333 struct usb_attach_arg *uaa = device_get_ivars(self); 334 struct rtwn_usb_softc *uc = device_get_softc(self); 335 struct rtwn_softc *sc = &uc->uc_sc; 336 struct ieee80211com *ic = &sc->sc_ic; 337 int error; 338 339 device_set_usb_desc(self); 340 uc->uc_udev = uaa->device; 341 sc->sc_dev = self; 342 ic->ic_name = device_get_nameunit(self); 343 344 /* Need to be initialized early. */ 345 rtwn_sysctlattach(sc); 346 mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); 347 348 rtwn_usb_attach_methods(sc); 349 rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); 350 351 error = rtwn_usb_setup_endpoints(uc); 352 if (error != 0) 353 goto detach; 354 355 /* Allocate Tx/Rx buffers. */ 356 error = rtwn_usb_alloc_rx_list(sc); 357 if (error != 0) 358 goto detach; 359 360 error = rtwn_usb_alloc_tx_list(sc); 361 if (error != 0) 362 goto detach; 363 364 /* Generic attach. */ 365 error = rtwn_attach(sc); 366 if (error != 0) 367 goto detach; 368 369 return (0); 370 371 detach: 372 rtwn_usb_detach(self); /* failure */ 373 return (ENXIO); 374 } 375 376 static int 377 rtwn_usb_detach(device_t self) 378 { 379 struct rtwn_usb_softc *uc = device_get_softc(self); 380 struct rtwn_softc *sc = &uc->uc_sc; 381 382 /* Generic detach. */ 383 rtwn_detach(sc); 384 385 /* Free Tx/Rx buffers. */ 386 rtwn_usb_free_tx_list(sc); 387 rtwn_usb_free_rx_list(sc); 388 389 /* Detach all USB transfers. */ 390 usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); 391 392 rtwn_detach_private(sc); 393 mtx_destroy(&sc->sc_mtx); 394 395 return (0); 396 } 397 398 static int 399 rtwn_usb_suspend(device_t self) 400 { 401 struct rtwn_usb_softc *uc = device_get_softc(self); 402 403 rtwn_suspend(&uc->uc_sc); 404 405 return (0); 406 } 407 408 static int 409 rtwn_usb_resume(device_t self) 410 { 411 struct rtwn_usb_softc *uc = device_get_softc(self); 412 413 rtwn_resume(&uc->uc_sc); 414 415 return (0); 416 } 417 418 static device_method_t rtwn_usb_methods[] = { 419 /* Device interface */ 420 DEVMETHOD(device_probe, rtwn_usb_match), 421 DEVMETHOD(device_attach, rtwn_usb_attach), 422 DEVMETHOD(device_detach, rtwn_usb_detach), 423 DEVMETHOD(device_suspend, rtwn_usb_suspend), 424 DEVMETHOD(device_resume, rtwn_usb_resume), 425 426 DEVMETHOD_END 427 }; 428 429 static driver_t rtwn_usb_driver = { 430 "rtwn", 431 rtwn_usb_methods, 432 sizeof(struct rtwn_usb_softc) 433 }; 434 435 static devclass_t rtwn_usb_devclass; 436 437 DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); 438 MODULE_VERSION(rtwn_usb, 1); 439 MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); 440 MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); 441 MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); 442 USB_PNP_HOST_INFO(rtwn_devs); 443