17453645fSAndriy Voskoboinyk /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 27453645fSAndriy Voskoboinyk 37453645fSAndriy Voskoboinyk /*- 47453645fSAndriy Voskoboinyk * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 57453645fSAndriy Voskoboinyk * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 67453645fSAndriy Voskoboinyk * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 77453645fSAndriy Voskoboinyk * 87453645fSAndriy Voskoboinyk * Permission to use, copy, modify, and distribute this software for any 97453645fSAndriy Voskoboinyk * purpose with or without fee is hereby granted, provided that the above 107453645fSAndriy Voskoboinyk * copyright notice and this permission notice appear in all copies. 117453645fSAndriy Voskoboinyk * 127453645fSAndriy Voskoboinyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 137453645fSAndriy Voskoboinyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 147453645fSAndriy Voskoboinyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 157453645fSAndriy Voskoboinyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 167453645fSAndriy Voskoboinyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 177453645fSAndriy Voskoboinyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 187453645fSAndriy Voskoboinyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 197453645fSAndriy Voskoboinyk */ 207453645fSAndriy Voskoboinyk 217453645fSAndriy Voskoboinyk #include <sys/cdefs.h> 227453645fSAndriy Voskoboinyk __FBSDID("$FreeBSD$"); 237453645fSAndriy Voskoboinyk 247453645fSAndriy Voskoboinyk #include <sys/param.h> 257453645fSAndriy Voskoboinyk #include <sys/sysctl.h> 267453645fSAndriy Voskoboinyk #include <sys/lock.h> 277453645fSAndriy Voskoboinyk #include <sys/mutex.h> 287453645fSAndriy Voskoboinyk #include <sys/mbuf.h> 297453645fSAndriy Voskoboinyk #include <sys/kernel.h> 307453645fSAndriy Voskoboinyk #include <sys/socket.h> 317453645fSAndriy Voskoboinyk #include <sys/systm.h> 327453645fSAndriy Voskoboinyk #include <sys/malloc.h> 337453645fSAndriy Voskoboinyk #include <sys/module.h> 347453645fSAndriy Voskoboinyk #include <sys/bus.h> 357453645fSAndriy Voskoboinyk #include <sys/endian.h> 367453645fSAndriy Voskoboinyk #include <sys/linker.h> 377453645fSAndriy Voskoboinyk #include <sys/kdb.h> 387453645fSAndriy Voskoboinyk 397453645fSAndriy Voskoboinyk #include <net/if.h> 407453645fSAndriy Voskoboinyk #include <net/if_var.h> 417453645fSAndriy Voskoboinyk #include <net/ethernet.h> 427453645fSAndriy Voskoboinyk #include <net/if_media.h> 437453645fSAndriy Voskoboinyk 447453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h> 457453645fSAndriy Voskoboinyk 467453645fSAndriy Voskoboinyk #include <dev/usb/usb.h> 477453645fSAndriy Voskoboinyk #include <dev/usb/usbdi.h> 487453645fSAndriy Voskoboinyk #include "usbdevs.h" 497453645fSAndriy Voskoboinyk 507453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h> 517453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_nop.h> 527453645fSAndriy Voskoboinyk 537453645fSAndriy Voskoboinyk #include <dev/rtwn/usb/rtwn_usb_var.h> 547453645fSAndriy Voskoboinyk 557453645fSAndriy Voskoboinyk #include <dev/rtwn/usb/rtwn_usb_attach.h> 567453645fSAndriy Voskoboinyk #include <dev/rtwn/usb/rtwn_usb_ep.h> 577453645fSAndriy Voskoboinyk #include <dev/rtwn/usb/rtwn_usb_reg.h> 587453645fSAndriy Voskoboinyk #include <dev/rtwn/usb/rtwn_usb_tx.h> 597453645fSAndriy Voskoboinyk 607453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c_reg.h> 617453645fSAndriy Voskoboinyk 627453645fSAndriy Voskoboinyk static device_probe_t rtwn_usb_match; 637453645fSAndriy Voskoboinyk static device_attach_t rtwn_usb_attach; 647453645fSAndriy Voskoboinyk static device_detach_t rtwn_usb_detach; 657453645fSAndriy Voskoboinyk static device_suspend_t rtwn_usb_suspend; 667453645fSAndriy Voskoboinyk static device_resume_t rtwn_usb_resume; 677453645fSAndriy Voskoboinyk 687453645fSAndriy Voskoboinyk static int rtwn_usb_alloc_list(struct rtwn_softc *, 697453645fSAndriy Voskoboinyk struct rtwn_data[], int, int); 707453645fSAndriy Voskoboinyk static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); 717453645fSAndriy Voskoboinyk static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); 727453645fSAndriy Voskoboinyk static void rtwn_usb_free_list(struct rtwn_softc *, 737453645fSAndriy Voskoboinyk struct rtwn_data data[], int); 747453645fSAndriy Voskoboinyk static void rtwn_usb_free_rx_list(struct rtwn_softc *); 757453645fSAndriy Voskoboinyk static void rtwn_usb_free_tx_list(struct rtwn_softc *); 767453645fSAndriy Voskoboinyk static void rtwn_usb_reset_lists(struct rtwn_softc *, 777453645fSAndriy Voskoboinyk struct ieee80211vap *); 787453645fSAndriy Voskoboinyk static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, 797453645fSAndriy Voskoboinyk rtwn_datahead *, struct ieee80211vap *); 807453645fSAndriy Voskoboinyk static void rtwn_usb_start_xfers(struct rtwn_softc *); 817453645fSAndriy Voskoboinyk static void rtwn_usb_abort_xfers(struct rtwn_softc *); 827453645fSAndriy Voskoboinyk static int rtwn_usb_fw_write_block(struct rtwn_softc *, 837453645fSAndriy Voskoboinyk const uint8_t *, uint16_t, int); 84*d067ef0fSAndriy Voskoboinyk static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *); 857453645fSAndriy Voskoboinyk static void rtwn_usb_attach_methods(struct rtwn_softc *); 867453645fSAndriy Voskoboinyk 877453645fSAndriy Voskoboinyk #define RTWN_CONFIG_INDEX 0 887453645fSAndriy Voskoboinyk 897453645fSAndriy Voskoboinyk 907453645fSAndriy Voskoboinyk static int 917453645fSAndriy Voskoboinyk rtwn_usb_match(device_t self) 927453645fSAndriy Voskoboinyk { 937453645fSAndriy Voskoboinyk struct usb_attach_arg *uaa = device_get_ivars(self); 947453645fSAndriy Voskoboinyk 957453645fSAndriy Voskoboinyk if (uaa->usb_mode != USB_MODE_HOST) 967453645fSAndriy Voskoboinyk return (ENXIO); 977453645fSAndriy Voskoboinyk if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) 987453645fSAndriy Voskoboinyk return (ENXIO); 997453645fSAndriy Voskoboinyk if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) 1007453645fSAndriy Voskoboinyk return (ENXIO); 1017453645fSAndriy Voskoboinyk 1027453645fSAndriy Voskoboinyk return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); 1037453645fSAndriy Voskoboinyk } 1047453645fSAndriy Voskoboinyk 1057453645fSAndriy Voskoboinyk static int 1067453645fSAndriy Voskoboinyk rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], 1077453645fSAndriy Voskoboinyk int ndata, int maxsz) 1087453645fSAndriy Voskoboinyk { 1097453645fSAndriy Voskoboinyk int i, error; 1107453645fSAndriy Voskoboinyk 1117453645fSAndriy Voskoboinyk for (i = 0; i < ndata; i++) { 1127453645fSAndriy Voskoboinyk struct rtwn_data *dp = &data[i]; 1137453645fSAndriy Voskoboinyk dp->m = NULL; 1147453645fSAndriy Voskoboinyk dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 1157453645fSAndriy Voskoboinyk if (dp->buf == NULL) { 1167453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 1177453645fSAndriy Voskoboinyk "could not allocate buffer\n"); 1187453645fSAndriy Voskoboinyk error = ENOMEM; 1197453645fSAndriy Voskoboinyk goto fail; 1207453645fSAndriy Voskoboinyk } 1217453645fSAndriy Voskoboinyk dp->ni = NULL; 1227453645fSAndriy Voskoboinyk } 1237453645fSAndriy Voskoboinyk 1247453645fSAndriy Voskoboinyk return (0); 1257453645fSAndriy Voskoboinyk fail: 1267453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, data, ndata); 1277453645fSAndriy Voskoboinyk return (error); 1287453645fSAndriy Voskoboinyk } 1297453645fSAndriy Voskoboinyk 1307453645fSAndriy Voskoboinyk static int 1317453645fSAndriy Voskoboinyk rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) 1327453645fSAndriy Voskoboinyk { 1337453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 1347453645fSAndriy Voskoboinyk int error, i; 1357453645fSAndriy Voskoboinyk 1367453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, 1377453645fSAndriy Voskoboinyk RTWN_RXBUFSZ); 1387453645fSAndriy Voskoboinyk if (error != 0) 1397453645fSAndriy Voskoboinyk return (error); 1407453645fSAndriy Voskoboinyk 1417453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_active); 1427453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_inactive); 1437453645fSAndriy Voskoboinyk 1447453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) 1457453645fSAndriy Voskoboinyk STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); 1467453645fSAndriy Voskoboinyk 1477453645fSAndriy Voskoboinyk return (0); 1487453645fSAndriy Voskoboinyk } 1497453645fSAndriy Voskoboinyk 1507453645fSAndriy Voskoboinyk static int 1517453645fSAndriy Voskoboinyk rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) 1527453645fSAndriy Voskoboinyk { 1537453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 1547453645fSAndriy Voskoboinyk int error, i; 1557453645fSAndriy Voskoboinyk 1567453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, 1577453645fSAndriy Voskoboinyk RTWN_TXBUFSZ); 1587453645fSAndriy Voskoboinyk if (error != 0) 1597453645fSAndriy Voskoboinyk return (error); 1607453645fSAndriy Voskoboinyk 1617453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_active); 1627453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_inactive); 1637453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_pending); 1647453645fSAndriy Voskoboinyk 1657453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) 1667453645fSAndriy Voskoboinyk STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); 1677453645fSAndriy Voskoboinyk 1687453645fSAndriy Voskoboinyk return (0); 1697453645fSAndriy Voskoboinyk } 1707453645fSAndriy Voskoboinyk 1717453645fSAndriy Voskoboinyk static void 1727453645fSAndriy Voskoboinyk rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) 1737453645fSAndriy Voskoboinyk { 1747453645fSAndriy Voskoboinyk int i; 1757453645fSAndriy Voskoboinyk 1767453645fSAndriy Voskoboinyk for (i = 0; i < ndata; i++) { 1777453645fSAndriy Voskoboinyk struct rtwn_data *dp = &data[i]; 1787453645fSAndriy Voskoboinyk 1797453645fSAndriy Voskoboinyk if (dp->buf != NULL) { 1807453645fSAndriy Voskoboinyk free(dp->buf, M_USBDEV); 1817453645fSAndriy Voskoboinyk dp->buf = NULL; 1827453645fSAndriy Voskoboinyk } 1837453645fSAndriy Voskoboinyk if (dp->ni != NULL) { 1847453645fSAndriy Voskoboinyk ieee80211_free_node(dp->ni); 1857453645fSAndriy Voskoboinyk dp->ni = NULL; 1867453645fSAndriy Voskoboinyk } 1877453645fSAndriy Voskoboinyk if (dp->m != NULL) { 1887453645fSAndriy Voskoboinyk m_freem(dp->m); 1897453645fSAndriy Voskoboinyk dp->m = NULL; 1907453645fSAndriy Voskoboinyk } 1917453645fSAndriy Voskoboinyk } 1927453645fSAndriy Voskoboinyk } 1937453645fSAndriy Voskoboinyk 1947453645fSAndriy Voskoboinyk static void 1957453645fSAndriy Voskoboinyk rtwn_usb_free_rx_list(struct rtwn_softc *sc) 1967453645fSAndriy Voskoboinyk { 1977453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 1987453645fSAndriy Voskoboinyk 1997453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); 2007453645fSAndriy Voskoboinyk 2017453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_active); 2027453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_inactive); 2037453645fSAndriy Voskoboinyk } 2047453645fSAndriy Voskoboinyk 2057453645fSAndriy Voskoboinyk static void 2067453645fSAndriy Voskoboinyk rtwn_usb_free_tx_list(struct rtwn_softc *sc) 2077453645fSAndriy Voskoboinyk { 2087453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2097453645fSAndriy Voskoboinyk 2107453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); 2117453645fSAndriy Voskoboinyk 2127453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_active); 2137453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_inactive); 2147453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_pending); 2157453645fSAndriy Voskoboinyk } 2167453645fSAndriy Voskoboinyk 2177453645fSAndriy Voskoboinyk static void 2187453645fSAndriy Voskoboinyk rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) 2197453645fSAndriy Voskoboinyk { 2207453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2217453645fSAndriy Voskoboinyk 2227453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 2237453645fSAndriy Voskoboinyk 2247453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); 2257453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); 2267453645fSAndriy Voskoboinyk if (vap == NULL) 2277453645fSAndriy Voskoboinyk sc->qfullmsk = 0; 2287453645fSAndriy Voskoboinyk } 2297453645fSAndriy Voskoboinyk 2307453645fSAndriy Voskoboinyk static void 2317453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, 2327453645fSAndriy Voskoboinyk rtwn_datahead *head, struct ieee80211vap *vap) 2337453645fSAndriy Voskoboinyk { 2347453645fSAndriy Voskoboinyk struct rtwn_vap *uvp = RTWN_VAP(vap); 2357453645fSAndriy Voskoboinyk struct rtwn_data *dp, *tmp; 2367453645fSAndriy Voskoboinyk int id; 2377453645fSAndriy Voskoboinyk 2387453645fSAndriy Voskoboinyk id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); 2397453645fSAndriy Voskoboinyk 2407453645fSAndriy Voskoboinyk STAILQ_FOREACH_SAFE(dp, head, next, tmp) { 2417453645fSAndriy Voskoboinyk if (vap == NULL || (dp->ni == NULL && 2427453645fSAndriy Voskoboinyk (dp->id == id || id == RTWN_VAP_ID_INVALID)) || 2437453645fSAndriy Voskoboinyk (dp->ni != NULL && dp->ni->ni_vap == vap)) { 2447453645fSAndriy Voskoboinyk if (dp->ni != NULL) { 2457453645fSAndriy Voskoboinyk ieee80211_free_node(dp->ni); 2467453645fSAndriy Voskoboinyk dp->ni = NULL; 2477453645fSAndriy Voskoboinyk } 2487453645fSAndriy Voskoboinyk 2497453645fSAndriy Voskoboinyk if (dp->m != NULL) { 2507453645fSAndriy Voskoboinyk m_freem(dp->m); 2517453645fSAndriy Voskoboinyk dp->m = NULL; 2527453645fSAndriy Voskoboinyk } 2537453645fSAndriy Voskoboinyk 2547453645fSAndriy Voskoboinyk STAILQ_REMOVE(head, dp, rtwn_data, next); 2557453645fSAndriy Voskoboinyk STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); 2567453645fSAndriy Voskoboinyk } 2577453645fSAndriy Voskoboinyk } 2587453645fSAndriy Voskoboinyk } 2597453645fSAndriy Voskoboinyk 2607453645fSAndriy Voskoboinyk static void 2617453645fSAndriy Voskoboinyk rtwn_usb_start_xfers(struct rtwn_softc *sc) 2627453645fSAndriy Voskoboinyk { 2637453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2647453645fSAndriy Voskoboinyk 2657453645fSAndriy Voskoboinyk usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); 2667453645fSAndriy Voskoboinyk } 2677453645fSAndriy Voskoboinyk 2687453645fSAndriy Voskoboinyk static void 2697453645fSAndriy Voskoboinyk rtwn_usb_abort_xfers(struct rtwn_softc *sc) 2707453645fSAndriy Voskoboinyk { 2717453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2727453645fSAndriy Voskoboinyk int i; 2737453645fSAndriy Voskoboinyk 2747453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 2757453645fSAndriy Voskoboinyk 2767453645fSAndriy Voskoboinyk /* abort any pending transfers */ 27777cbc479SAndriy Voskoboinyk RTWN_UNLOCK(sc); 2787453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_N_TRANSFER; i++) 27977cbc479SAndriy Voskoboinyk usbd_transfer_drain(uc->uc_xfer[i]); 28077cbc479SAndriy Voskoboinyk RTWN_LOCK(sc); 2817453645fSAndriy Voskoboinyk } 2827453645fSAndriy Voskoboinyk 2837453645fSAndriy Voskoboinyk static int 2847453645fSAndriy Voskoboinyk rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, 2857453645fSAndriy Voskoboinyk uint16_t reg, int mlen) 2867453645fSAndriy Voskoboinyk { 2877453645fSAndriy Voskoboinyk int error; 2887453645fSAndriy Voskoboinyk 2897453645fSAndriy Voskoboinyk /* XXX fix this deconst */ 2907453645fSAndriy Voskoboinyk error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), 2917453645fSAndriy Voskoboinyk mlen); 2927453645fSAndriy Voskoboinyk 2937453645fSAndriy Voskoboinyk return (error); 2947453645fSAndriy Voskoboinyk } 2957453645fSAndriy Voskoboinyk 2967453645fSAndriy Voskoboinyk static void 2977453645fSAndriy Voskoboinyk rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) 2987453645fSAndriy Voskoboinyk { 2997453645fSAndriy Voskoboinyk 3007453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, 3017453645fSAndriy Voskoboinyk R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); 3027453645fSAndriy Voskoboinyk } 3037453645fSAndriy Voskoboinyk 3047453645fSAndriy Voskoboinyk static void 3057453645fSAndriy Voskoboinyk rtwn_usb_attach_methods(struct rtwn_softc *sc) 3067453645fSAndriy Voskoboinyk { 3077453645fSAndriy Voskoboinyk sc->sc_write_1 = rtwn_usb_write_1; 3087453645fSAndriy Voskoboinyk sc->sc_write_2 = rtwn_usb_write_2; 3097453645fSAndriy Voskoboinyk sc->sc_write_4 = rtwn_usb_write_4; 3107453645fSAndriy Voskoboinyk sc->sc_read_1 = rtwn_usb_read_1; 3117453645fSAndriy Voskoboinyk sc->sc_read_2 = rtwn_usb_read_2; 3127453645fSAndriy Voskoboinyk sc->sc_read_4 = rtwn_usb_read_4; 3137453645fSAndriy Voskoboinyk sc->sc_delay = rtwn_usb_delay; 3147453645fSAndriy Voskoboinyk sc->sc_tx_start = rtwn_usb_tx_start; 3157453645fSAndriy Voskoboinyk sc->sc_start_xfers = rtwn_usb_start_xfers; 3167453645fSAndriy Voskoboinyk sc->sc_reset_lists = rtwn_usb_reset_lists; 3177453645fSAndriy Voskoboinyk sc->sc_abort_xfers = rtwn_usb_abort_xfers; 3187453645fSAndriy Voskoboinyk sc->sc_fw_write_block = rtwn_usb_fw_write_block; 3197453645fSAndriy Voskoboinyk sc->sc_get_qmap = rtwn_usb_get_qmap; 3207453645fSAndriy Voskoboinyk sc->sc_set_desc_addr = rtwn_nop_softc; 3217453645fSAndriy Voskoboinyk sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; 322*d067ef0fSAndriy Voskoboinyk sc->sc_beacon_update_begin = rtwn_nop_softc_vap; 323*d067ef0fSAndriy Voskoboinyk sc->sc_beacon_update_end = rtwn_nop_softc_vap; 324*d067ef0fSAndriy Voskoboinyk sc->sc_beacon_unload = rtwn_nop_softc_int; 325*d067ef0fSAndriy Voskoboinyk 326*d067ef0fSAndriy Voskoboinyk sc->bcn_check_interval = 100; 3277453645fSAndriy Voskoboinyk } 3287453645fSAndriy Voskoboinyk 3297453645fSAndriy Voskoboinyk static int 3307453645fSAndriy Voskoboinyk rtwn_usb_attach(device_t self) 3317453645fSAndriy Voskoboinyk { 3327453645fSAndriy Voskoboinyk struct usb_attach_arg *uaa = device_get_ivars(self); 3337453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 3347453645fSAndriy Voskoboinyk struct rtwn_softc *sc = &uc->uc_sc; 3357453645fSAndriy Voskoboinyk struct ieee80211com *ic = &sc->sc_ic; 3367453645fSAndriy Voskoboinyk int error; 3377453645fSAndriy Voskoboinyk 3387453645fSAndriy Voskoboinyk device_set_usb_desc(self); 3397453645fSAndriy Voskoboinyk uc->uc_udev = uaa->device; 3407453645fSAndriy Voskoboinyk sc->sc_dev = self; 3417453645fSAndriy Voskoboinyk ic->ic_name = device_get_nameunit(self); 3427453645fSAndriy Voskoboinyk 3437453645fSAndriy Voskoboinyk /* Need to be initialized early. */ 3447453645fSAndriy Voskoboinyk rtwn_sysctlattach(sc); 3457453645fSAndriy Voskoboinyk mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); 3467453645fSAndriy Voskoboinyk 3477453645fSAndriy Voskoboinyk rtwn_usb_attach_methods(sc); 3487453645fSAndriy Voskoboinyk rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); 3497453645fSAndriy Voskoboinyk 3507453645fSAndriy Voskoboinyk error = rtwn_usb_setup_endpoints(uc); 3517453645fSAndriy Voskoboinyk if (error != 0) 3527453645fSAndriy Voskoboinyk goto detach; 3537453645fSAndriy Voskoboinyk 3547453645fSAndriy Voskoboinyk /* Allocate Tx/Rx buffers. */ 3557453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_rx_list(sc); 3567453645fSAndriy Voskoboinyk if (error != 0) 3577453645fSAndriy Voskoboinyk goto detach; 3587453645fSAndriy Voskoboinyk 3597453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_tx_list(sc); 3607453645fSAndriy Voskoboinyk if (error != 0) 3617453645fSAndriy Voskoboinyk goto detach; 3627453645fSAndriy Voskoboinyk 3637453645fSAndriy Voskoboinyk /* Generic attach. */ 3647453645fSAndriy Voskoboinyk error = rtwn_attach(sc); 3657453645fSAndriy Voskoboinyk if (error != 0) 3667453645fSAndriy Voskoboinyk goto detach; 3677453645fSAndriy Voskoboinyk 3687453645fSAndriy Voskoboinyk return (0); 3697453645fSAndriy Voskoboinyk 3707453645fSAndriy Voskoboinyk detach: 3717453645fSAndriy Voskoboinyk rtwn_usb_detach(self); /* failure */ 3727453645fSAndriy Voskoboinyk return (ENXIO); 3737453645fSAndriy Voskoboinyk } 3747453645fSAndriy Voskoboinyk 3757453645fSAndriy Voskoboinyk static int 3767453645fSAndriy Voskoboinyk rtwn_usb_detach(device_t self) 3777453645fSAndriy Voskoboinyk { 3787453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 3797453645fSAndriy Voskoboinyk struct rtwn_softc *sc = &uc->uc_sc; 3807453645fSAndriy Voskoboinyk 3817453645fSAndriy Voskoboinyk /* Generic detach. */ 3827453645fSAndriy Voskoboinyk rtwn_detach(sc); 3837453645fSAndriy Voskoboinyk 3847453645fSAndriy Voskoboinyk /* Free Tx/Rx buffers. */ 3857453645fSAndriy Voskoboinyk rtwn_usb_free_tx_list(sc); 3867453645fSAndriy Voskoboinyk rtwn_usb_free_rx_list(sc); 3877453645fSAndriy Voskoboinyk 3887453645fSAndriy Voskoboinyk /* Detach all USB transfers. */ 3897453645fSAndriy Voskoboinyk usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); 3907453645fSAndriy Voskoboinyk 3917453645fSAndriy Voskoboinyk rtwn_detach_private(sc); 3927453645fSAndriy Voskoboinyk mtx_destroy(&sc->sc_mtx); 3937453645fSAndriy Voskoboinyk 3947453645fSAndriy Voskoboinyk return (0); 3957453645fSAndriy Voskoboinyk } 3967453645fSAndriy Voskoboinyk 3977453645fSAndriy Voskoboinyk static int 3987453645fSAndriy Voskoboinyk rtwn_usb_suspend(device_t self) 3997453645fSAndriy Voskoboinyk { 4007453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 4017453645fSAndriy Voskoboinyk 4027453645fSAndriy Voskoboinyk rtwn_suspend(&uc->uc_sc); 4037453645fSAndriy Voskoboinyk 4047453645fSAndriy Voskoboinyk return (0); 4057453645fSAndriy Voskoboinyk } 4067453645fSAndriy Voskoboinyk 4077453645fSAndriy Voskoboinyk static int 4087453645fSAndriy Voskoboinyk rtwn_usb_resume(device_t self) 4097453645fSAndriy Voskoboinyk { 4107453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 4117453645fSAndriy Voskoboinyk 4127453645fSAndriy Voskoboinyk rtwn_resume(&uc->uc_sc); 4137453645fSAndriy Voskoboinyk 4147453645fSAndriy Voskoboinyk return (0); 4157453645fSAndriy Voskoboinyk } 4167453645fSAndriy Voskoboinyk 4177453645fSAndriy Voskoboinyk static device_method_t rtwn_usb_methods[] = { 4187453645fSAndriy Voskoboinyk /* Device interface */ 4197453645fSAndriy Voskoboinyk DEVMETHOD(device_probe, rtwn_usb_match), 4207453645fSAndriy Voskoboinyk DEVMETHOD(device_attach, rtwn_usb_attach), 4217453645fSAndriy Voskoboinyk DEVMETHOD(device_detach, rtwn_usb_detach), 4227453645fSAndriy Voskoboinyk DEVMETHOD(device_suspend, rtwn_usb_suspend), 4237453645fSAndriy Voskoboinyk DEVMETHOD(device_resume, rtwn_usb_resume), 4247453645fSAndriy Voskoboinyk 4257453645fSAndriy Voskoboinyk DEVMETHOD_END 4267453645fSAndriy Voskoboinyk }; 4277453645fSAndriy Voskoboinyk 4287453645fSAndriy Voskoboinyk static driver_t rtwn_usb_driver = { 4297453645fSAndriy Voskoboinyk "rtwn", 4307453645fSAndriy Voskoboinyk rtwn_usb_methods, 4317453645fSAndriy Voskoboinyk sizeof(struct rtwn_usb_softc) 4327453645fSAndriy Voskoboinyk }; 4337453645fSAndriy Voskoboinyk 4347453645fSAndriy Voskoboinyk static devclass_t rtwn_usb_devclass; 4357453645fSAndriy Voskoboinyk 4367453645fSAndriy Voskoboinyk DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); 4377453645fSAndriy Voskoboinyk MODULE_VERSION(rtwn_usb, 1); 4387453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); 4397453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); 4407453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); 4417453645fSAndriy Voskoboinyk USB_PNP_HOST_INFO(rtwn_devs); 442