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