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 *); 80*9dba6128SAndriy Voskoboinyk static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *); 817453645fSAndriy Voskoboinyk static void rtwn_usb_start_xfers(struct rtwn_softc *); 827453645fSAndriy Voskoboinyk static void rtwn_usb_abort_xfers(struct rtwn_softc *); 837453645fSAndriy Voskoboinyk static int rtwn_usb_fw_write_block(struct rtwn_softc *, 847453645fSAndriy Voskoboinyk const uint8_t *, uint16_t, int); 85d067ef0fSAndriy Voskoboinyk static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *); 867453645fSAndriy Voskoboinyk static void rtwn_usb_attach_methods(struct rtwn_softc *); 87*9dba6128SAndriy Voskoboinyk static void rtwn_usb_sysctlattach(struct rtwn_softc *); 887453645fSAndriy Voskoboinyk 897453645fSAndriy Voskoboinyk #define RTWN_CONFIG_INDEX 0 907453645fSAndriy Voskoboinyk 917453645fSAndriy Voskoboinyk 927453645fSAndriy Voskoboinyk static int 937453645fSAndriy Voskoboinyk rtwn_usb_match(device_t self) 947453645fSAndriy Voskoboinyk { 957453645fSAndriy Voskoboinyk struct usb_attach_arg *uaa = device_get_ivars(self); 967453645fSAndriy Voskoboinyk 977453645fSAndriy Voskoboinyk if (uaa->usb_mode != USB_MODE_HOST) 987453645fSAndriy Voskoboinyk return (ENXIO); 997453645fSAndriy Voskoboinyk if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) 1007453645fSAndriy Voskoboinyk return (ENXIO); 1017453645fSAndriy Voskoboinyk if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) 1027453645fSAndriy Voskoboinyk return (ENXIO); 1037453645fSAndriy Voskoboinyk 1047453645fSAndriy Voskoboinyk return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); 1057453645fSAndriy Voskoboinyk } 1067453645fSAndriy Voskoboinyk 1077453645fSAndriy Voskoboinyk static int 1087453645fSAndriy Voskoboinyk rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], 1097453645fSAndriy Voskoboinyk int ndata, int maxsz) 1107453645fSAndriy Voskoboinyk { 1117453645fSAndriy Voskoboinyk int i, error; 1127453645fSAndriy Voskoboinyk 1137453645fSAndriy Voskoboinyk for (i = 0; i < ndata; i++) { 1147453645fSAndriy Voskoboinyk struct rtwn_data *dp = &data[i]; 1157453645fSAndriy Voskoboinyk dp->m = NULL; 1167453645fSAndriy Voskoboinyk dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 1177453645fSAndriy Voskoboinyk if (dp->buf == NULL) { 1187453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 1197453645fSAndriy Voskoboinyk "could not allocate buffer\n"); 1207453645fSAndriy Voskoboinyk error = ENOMEM; 1217453645fSAndriy Voskoboinyk goto fail; 1227453645fSAndriy Voskoboinyk } 1237453645fSAndriy Voskoboinyk dp->ni = NULL; 1247453645fSAndriy Voskoboinyk } 1257453645fSAndriy Voskoboinyk 1267453645fSAndriy Voskoboinyk return (0); 1277453645fSAndriy Voskoboinyk fail: 1287453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, data, ndata); 1297453645fSAndriy Voskoboinyk return (error); 1307453645fSAndriy Voskoboinyk } 1317453645fSAndriy Voskoboinyk 1327453645fSAndriy Voskoboinyk static int 1337453645fSAndriy Voskoboinyk rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) 1347453645fSAndriy Voskoboinyk { 1357453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 1367453645fSAndriy Voskoboinyk int error, i; 1377453645fSAndriy Voskoboinyk 1387453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, 139*9dba6128SAndriy Voskoboinyk uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT); 1407453645fSAndriy Voskoboinyk if (error != 0) 1417453645fSAndriy Voskoboinyk return (error); 1427453645fSAndriy Voskoboinyk 1437453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_active); 1447453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_inactive); 1457453645fSAndriy Voskoboinyk 1467453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) 1477453645fSAndriy Voskoboinyk STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); 1487453645fSAndriy Voskoboinyk 1497453645fSAndriy Voskoboinyk return (0); 1507453645fSAndriy Voskoboinyk } 1517453645fSAndriy Voskoboinyk 1527453645fSAndriy Voskoboinyk static int 1537453645fSAndriy Voskoboinyk rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) 1547453645fSAndriy Voskoboinyk { 1557453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 1567453645fSAndriy Voskoboinyk int error, i; 1577453645fSAndriy Voskoboinyk 1587453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, 15937376971SAndriy Voskoboinyk RTWN_USB_TXBUFSZ); 1607453645fSAndriy Voskoboinyk if (error != 0) 1617453645fSAndriy Voskoboinyk return (error); 1627453645fSAndriy Voskoboinyk 1637453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_active); 1647453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_inactive); 1657453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_pending); 1667453645fSAndriy Voskoboinyk 1677453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) 1687453645fSAndriy Voskoboinyk STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); 1697453645fSAndriy Voskoboinyk 1707453645fSAndriy Voskoboinyk return (0); 1717453645fSAndriy Voskoboinyk } 1727453645fSAndriy Voskoboinyk 1737453645fSAndriy Voskoboinyk static void 1747453645fSAndriy Voskoboinyk rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) 1757453645fSAndriy Voskoboinyk { 1767453645fSAndriy Voskoboinyk int i; 1777453645fSAndriy Voskoboinyk 1787453645fSAndriy Voskoboinyk for (i = 0; i < ndata; i++) { 1797453645fSAndriy Voskoboinyk struct rtwn_data *dp = &data[i]; 1807453645fSAndriy Voskoboinyk 1817453645fSAndriy Voskoboinyk if (dp->buf != NULL) { 1827453645fSAndriy Voskoboinyk free(dp->buf, M_USBDEV); 1837453645fSAndriy Voskoboinyk dp->buf = NULL; 1847453645fSAndriy Voskoboinyk } 1857453645fSAndriy Voskoboinyk if (dp->ni != NULL) { 1867453645fSAndriy Voskoboinyk ieee80211_free_node(dp->ni); 1877453645fSAndriy Voskoboinyk dp->ni = NULL; 1887453645fSAndriy Voskoboinyk } 1897453645fSAndriy Voskoboinyk if (dp->m != NULL) { 1907453645fSAndriy Voskoboinyk m_freem(dp->m); 1917453645fSAndriy Voskoboinyk dp->m = NULL; 1927453645fSAndriy Voskoboinyk } 1937453645fSAndriy Voskoboinyk } 1947453645fSAndriy Voskoboinyk } 1957453645fSAndriy Voskoboinyk 1967453645fSAndriy Voskoboinyk static void 1977453645fSAndriy Voskoboinyk rtwn_usb_free_rx_list(struct rtwn_softc *sc) 1987453645fSAndriy Voskoboinyk { 1997453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2007453645fSAndriy Voskoboinyk 2017453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); 2027453645fSAndriy Voskoboinyk 203*9dba6128SAndriy Voskoboinyk uc->uc_rx_stat_len = 0; 204*9dba6128SAndriy Voskoboinyk uc->uc_rx_off = 0; 205*9dba6128SAndriy Voskoboinyk 2067453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_active); 2077453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_rx_inactive); 2087453645fSAndriy Voskoboinyk } 2097453645fSAndriy Voskoboinyk 2107453645fSAndriy Voskoboinyk static void 2117453645fSAndriy Voskoboinyk rtwn_usb_free_tx_list(struct rtwn_softc *sc) 2127453645fSAndriy Voskoboinyk { 2137453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2147453645fSAndriy Voskoboinyk 2157453645fSAndriy Voskoboinyk rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); 2167453645fSAndriy Voskoboinyk 2177453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_active); 2187453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_inactive); 2197453645fSAndriy Voskoboinyk STAILQ_INIT(&uc->uc_tx_pending); 2207453645fSAndriy Voskoboinyk } 2217453645fSAndriy Voskoboinyk 2227453645fSAndriy Voskoboinyk static void 2237453645fSAndriy Voskoboinyk rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) 2247453645fSAndriy Voskoboinyk { 2257453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2267453645fSAndriy Voskoboinyk 2277453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 2287453645fSAndriy Voskoboinyk 2297453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); 2307453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); 231*9dba6128SAndriy Voskoboinyk if (vap == NULL) { 232*9dba6128SAndriy Voskoboinyk rtwn_usb_reset_rx_list(uc); 2337453645fSAndriy Voskoboinyk sc->qfullmsk = 0; 2347453645fSAndriy Voskoboinyk } 235*9dba6128SAndriy Voskoboinyk } 2367453645fSAndriy Voskoboinyk 2377453645fSAndriy Voskoboinyk static void 2387453645fSAndriy Voskoboinyk rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, 2397453645fSAndriy Voskoboinyk rtwn_datahead *head, struct ieee80211vap *vap) 2407453645fSAndriy Voskoboinyk { 2417453645fSAndriy Voskoboinyk struct rtwn_vap *uvp = RTWN_VAP(vap); 2427453645fSAndriy Voskoboinyk struct rtwn_data *dp, *tmp; 2437453645fSAndriy Voskoboinyk int id; 2447453645fSAndriy Voskoboinyk 2457453645fSAndriy Voskoboinyk id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); 2467453645fSAndriy Voskoboinyk 2477453645fSAndriy Voskoboinyk STAILQ_FOREACH_SAFE(dp, head, next, tmp) { 2487453645fSAndriy Voskoboinyk if (vap == NULL || (dp->ni == NULL && 2497453645fSAndriy Voskoboinyk (dp->id == id || id == RTWN_VAP_ID_INVALID)) || 2507453645fSAndriy Voskoboinyk (dp->ni != NULL && dp->ni->ni_vap == vap)) { 2517453645fSAndriy Voskoboinyk if (dp->ni != NULL) { 2527453645fSAndriy Voskoboinyk ieee80211_free_node(dp->ni); 2537453645fSAndriy Voskoboinyk dp->ni = NULL; 2547453645fSAndriy Voskoboinyk } 2557453645fSAndriy Voskoboinyk 2567453645fSAndriy Voskoboinyk if (dp->m != NULL) { 2577453645fSAndriy Voskoboinyk m_freem(dp->m); 2587453645fSAndriy Voskoboinyk dp->m = NULL; 2597453645fSAndriy Voskoboinyk } 2607453645fSAndriy Voskoboinyk 2617453645fSAndriy Voskoboinyk STAILQ_REMOVE(head, dp, rtwn_data, next); 2627453645fSAndriy Voskoboinyk STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); 2637453645fSAndriy Voskoboinyk } 2647453645fSAndriy Voskoboinyk } 2657453645fSAndriy Voskoboinyk } 2667453645fSAndriy Voskoboinyk 2677453645fSAndriy Voskoboinyk static void 268*9dba6128SAndriy Voskoboinyk rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc) 269*9dba6128SAndriy Voskoboinyk { 270*9dba6128SAndriy Voskoboinyk int i; 271*9dba6128SAndriy Voskoboinyk 272*9dba6128SAndriy Voskoboinyk for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) { 273*9dba6128SAndriy Voskoboinyk struct rtwn_data *dp = &uc->uc_rx[i]; 274*9dba6128SAndriy Voskoboinyk 275*9dba6128SAndriy Voskoboinyk if (dp->m != NULL) { 276*9dba6128SAndriy Voskoboinyk m_freem(dp->m); 277*9dba6128SAndriy Voskoboinyk dp->m = NULL; 278*9dba6128SAndriy Voskoboinyk } 279*9dba6128SAndriy Voskoboinyk } 280*9dba6128SAndriy Voskoboinyk uc->uc_rx_stat_len = 0; 281*9dba6128SAndriy Voskoboinyk uc->uc_rx_off = 0; 282*9dba6128SAndriy Voskoboinyk } 283*9dba6128SAndriy Voskoboinyk 284*9dba6128SAndriy Voskoboinyk static void 2857453645fSAndriy Voskoboinyk rtwn_usb_start_xfers(struct rtwn_softc *sc) 2867453645fSAndriy Voskoboinyk { 2877453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2887453645fSAndriy Voskoboinyk 2897453645fSAndriy Voskoboinyk usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); 2907453645fSAndriy Voskoboinyk } 2917453645fSAndriy Voskoboinyk 2927453645fSAndriy Voskoboinyk static void 2937453645fSAndriy Voskoboinyk rtwn_usb_abort_xfers(struct rtwn_softc *sc) 2947453645fSAndriy Voskoboinyk { 2957453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 2967453645fSAndriy Voskoboinyk int i; 2977453645fSAndriy Voskoboinyk 2987453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 2997453645fSAndriy Voskoboinyk 3007453645fSAndriy Voskoboinyk /* abort any pending transfers */ 30177cbc479SAndriy Voskoboinyk RTWN_UNLOCK(sc); 3027453645fSAndriy Voskoboinyk for (i = 0; i < RTWN_N_TRANSFER; i++) 30377cbc479SAndriy Voskoboinyk usbd_transfer_drain(uc->uc_xfer[i]); 30477cbc479SAndriy Voskoboinyk RTWN_LOCK(sc); 3057453645fSAndriy Voskoboinyk } 3067453645fSAndriy Voskoboinyk 3077453645fSAndriy Voskoboinyk static int 3087453645fSAndriy Voskoboinyk rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, 3097453645fSAndriy Voskoboinyk uint16_t reg, int mlen) 3107453645fSAndriy Voskoboinyk { 3117453645fSAndriy Voskoboinyk int error; 3127453645fSAndriy Voskoboinyk 3137453645fSAndriy Voskoboinyk /* XXX fix this deconst */ 3147453645fSAndriy Voskoboinyk error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), 3157453645fSAndriy Voskoboinyk mlen); 3167453645fSAndriy Voskoboinyk 3177453645fSAndriy Voskoboinyk return (error); 3187453645fSAndriy Voskoboinyk } 3197453645fSAndriy Voskoboinyk 3207453645fSAndriy Voskoboinyk static void 3217453645fSAndriy Voskoboinyk rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) 3227453645fSAndriy Voskoboinyk { 3237453645fSAndriy Voskoboinyk 3247453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, 3257453645fSAndriy Voskoboinyk R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); 3267453645fSAndriy Voskoboinyk } 3277453645fSAndriy Voskoboinyk 3287453645fSAndriy Voskoboinyk static void 3297453645fSAndriy Voskoboinyk rtwn_usb_attach_methods(struct rtwn_softc *sc) 3307453645fSAndriy Voskoboinyk { 3317453645fSAndriy Voskoboinyk sc->sc_write_1 = rtwn_usb_write_1; 3327453645fSAndriy Voskoboinyk sc->sc_write_2 = rtwn_usb_write_2; 3337453645fSAndriy Voskoboinyk sc->sc_write_4 = rtwn_usb_write_4; 3347453645fSAndriy Voskoboinyk sc->sc_read_1 = rtwn_usb_read_1; 3357453645fSAndriy Voskoboinyk sc->sc_read_2 = rtwn_usb_read_2; 3367453645fSAndriy Voskoboinyk sc->sc_read_4 = rtwn_usb_read_4; 3377453645fSAndriy Voskoboinyk sc->sc_delay = rtwn_usb_delay; 3387453645fSAndriy Voskoboinyk sc->sc_tx_start = rtwn_usb_tx_start; 3397453645fSAndriy Voskoboinyk sc->sc_start_xfers = rtwn_usb_start_xfers; 3407453645fSAndriy Voskoboinyk sc->sc_reset_lists = rtwn_usb_reset_lists; 3417453645fSAndriy Voskoboinyk sc->sc_abort_xfers = rtwn_usb_abort_xfers; 3427453645fSAndriy Voskoboinyk sc->sc_fw_write_block = rtwn_usb_fw_write_block; 3437453645fSAndriy Voskoboinyk sc->sc_get_qmap = rtwn_usb_get_qmap; 3447453645fSAndriy Voskoboinyk sc->sc_set_desc_addr = rtwn_nop_softc; 3457453645fSAndriy Voskoboinyk sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; 346d067ef0fSAndriy Voskoboinyk sc->sc_beacon_update_begin = rtwn_nop_softc_vap; 347d067ef0fSAndriy Voskoboinyk sc->sc_beacon_update_end = rtwn_nop_softc_vap; 348d067ef0fSAndriy Voskoboinyk sc->sc_beacon_unload = rtwn_nop_softc_int; 349d067ef0fSAndriy Voskoboinyk 350d067ef0fSAndriy Voskoboinyk sc->bcn_check_interval = 100; 3517453645fSAndriy Voskoboinyk } 3527453645fSAndriy Voskoboinyk 353*9dba6128SAndriy Voskoboinyk static void 354*9dba6128SAndriy Voskoboinyk rtwn_usb_sysctlattach(struct rtwn_softc *sc) 355*9dba6128SAndriy Voskoboinyk { 356*9dba6128SAndriy Voskoboinyk struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 357*9dba6128SAndriy Voskoboinyk struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 358*9dba6128SAndriy Voskoboinyk struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 359*9dba6128SAndriy Voskoboinyk char str[64]; 360*9dba6128SAndriy Voskoboinyk int ret; 361*9dba6128SAndriy Voskoboinyk 362*9dba6128SAndriy Voskoboinyk ret = snprintf(str, sizeof(str), 363*9dba6128SAndriy Voskoboinyk "Rx buffer size, 512-byte units [%d...%d]", 364*9dba6128SAndriy Voskoboinyk RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX); 365*9dba6128SAndriy Voskoboinyk KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret)); 366*9dba6128SAndriy Voskoboinyk (void) ret; 367*9dba6128SAndriy Voskoboinyk 368*9dba6128SAndriy Voskoboinyk uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF; 369*9dba6128SAndriy Voskoboinyk SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 370*9dba6128SAndriy Voskoboinyk "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size, 371*9dba6128SAndriy Voskoboinyk uc->uc_rx_buf_size, str); 372*9dba6128SAndriy Voskoboinyk if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN) 373*9dba6128SAndriy Voskoboinyk uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN; 374*9dba6128SAndriy Voskoboinyk if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX) 375*9dba6128SAndriy Voskoboinyk uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX; 376*9dba6128SAndriy Voskoboinyk } 377*9dba6128SAndriy Voskoboinyk 3787453645fSAndriy Voskoboinyk static int 3797453645fSAndriy Voskoboinyk rtwn_usb_attach(device_t self) 3807453645fSAndriy Voskoboinyk { 3817453645fSAndriy Voskoboinyk struct usb_attach_arg *uaa = device_get_ivars(self); 3827453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 3837453645fSAndriy Voskoboinyk struct rtwn_softc *sc = &uc->uc_sc; 3847453645fSAndriy Voskoboinyk struct ieee80211com *ic = &sc->sc_ic; 3857453645fSAndriy Voskoboinyk int error; 3867453645fSAndriy Voskoboinyk 3877453645fSAndriy Voskoboinyk device_set_usb_desc(self); 3887453645fSAndriy Voskoboinyk uc->uc_udev = uaa->device; 3897453645fSAndriy Voskoboinyk sc->sc_dev = self; 3907453645fSAndriy Voskoboinyk ic->ic_name = device_get_nameunit(self); 3917453645fSAndriy Voskoboinyk 3927453645fSAndriy Voskoboinyk /* Need to be initialized early. */ 3937453645fSAndriy Voskoboinyk rtwn_sysctlattach(sc); 394*9dba6128SAndriy Voskoboinyk rtwn_usb_sysctlattach(sc); 3957453645fSAndriy Voskoboinyk mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); 3967453645fSAndriy Voskoboinyk 3977453645fSAndriy Voskoboinyk rtwn_usb_attach_methods(sc); 3987453645fSAndriy Voskoboinyk rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); 3997453645fSAndriy Voskoboinyk 4007453645fSAndriy Voskoboinyk error = rtwn_usb_setup_endpoints(uc); 4017453645fSAndriy Voskoboinyk if (error != 0) 4027453645fSAndriy Voskoboinyk goto detach; 4037453645fSAndriy Voskoboinyk 4047453645fSAndriy Voskoboinyk /* Allocate Tx/Rx buffers. */ 4057453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_rx_list(sc); 4067453645fSAndriy Voskoboinyk if (error != 0) 4077453645fSAndriy Voskoboinyk goto detach; 4087453645fSAndriy Voskoboinyk 4097453645fSAndriy Voskoboinyk error = rtwn_usb_alloc_tx_list(sc); 4107453645fSAndriy Voskoboinyk if (error != 0) 4117453645fSAndriy Voskoboinyk goto detach; 4127453645fSAndriy Voskoboinyk 4137453645fSAndriy Voskoboinyk /* Generic attach. */ 4147453645fSAndriy Voskoboinyk error = rtwn_attach(sc); 4157453645fSAndriy Voskoboinyk if (error != 0) 4167453645fSAndriy Voskoboinyk goto detach; 4177453645fSAndriy Voskoboinyk 4187453645fSAndriy Voskoboinyk return (0); 4197453645fSAndriy Voskoboinyk 4207453645fSAndriy Voskoboinyk detach: 4217453645fSAndriy Voskoboinyk rtwn_usb_detach(self); /* failure */ 4227453645fSAndriy Voskoboinyk return (ENXIO); 4237453645fSAndriy Voskoboinyk } 4247453645fSAndriy Voskoboinyk 4257453645fSAndriy Voskoboinyk static int 4267453645fSAndriy Voskoboinyk rtwn_usb_detach(device_t self) 4277453645fSAndriy Voskoboinyk { 4287453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 4297453645fSAndriy Voskoboinyk struct rtwn_softc *sc = &uc->uc_sc; 4307453645fSAndriy Voskoboinyk 4317453645fSAndriy Voskoboinyk /* Generic detach. */ 4327453645fSAndriy Voskoboinyk rtwn_detach(sc); 4337453645fSAndriy Voskoboinyk 4347453645fSAndriy Voskoboinyk /* Free Tx/Rx buffers. */ 4357453645fSAndriy Voskoboinyk rtwn_usb_free_tx_list(sc); 4367453645fSAndriy Voskoboinyk rtwn_usb_free_rx_list(sc); 4377453645fSAndriy Voskoboinyk 4387453645fSAndriy Voskoboinyk /* Detach all USB transfers. */ 4397453645fSAndriy Voskoboinyk usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); 4407453645fSAndriy Voskoboinyk 4417453645fSAndriy Voskoboinyk rtwn_detach_private(sc); 4427453645fSAndriy Voskoboinyk mtx_destroy(&sc->sc_mtx); 4437453645fSAndriy Voskoboinyk 4447453645fSAndriy Voskoboinyk return (0); 4457453645fSAndriy Voskoboinyk } 4467453645fSAndriy Voskoboinyk 4477453645fSAndriy Voskoboinyk static int 4487453645fSAndriy Voskoboinyk rtwn_usb_suspend(device_t self) 4497453645fSAndriy Voskoboinyk { 4507453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 4517453645fSAndriy Voskoboinyk 4527453645fSAndriy Voskoboinyk rtwn_suspend(&uc->uc_sc); 4537453645fSAndriy Voskoboinyk 4547453645fSAndriy Voskoboinyk return (0); 4557453645fSAndriy Voskoboinyk } 4567453645fSAndriy Voskoboinyk 4577453645fSAndriy Voskoboinyk static int 4587453645fSAndriy Voskoboinyk rtwn_usb_resume(device_t self) 4597453645fSAndriy Voskoboinyk { 4607453645fSAndriy Voskoboinyk struct rtwn_usb_softc *uc = device_get_softc(self); 4617453645fSAndriy Voskoboinyk 4627453645fSAndriy Voskoboinyk rtwn_resume(&uc->uc_sc); 4637453645fSAndriy Voskoboinyk 4647453645fSAndriy Voskoboinyk return (0); 4657453645fSAndriy Voskoboinyk } 4667453645fSAndriy Voskoboinyk 4677453645fSAndriy Voskoboinyk static device_method_t rtwn_usb_methods[] = { 4687453645fSAndriy Voskoboinyk /* Device interface */ 4697453645fSAndriy Voskoboinyk DEVMETHOD(device_probe, rtwn_usb_match), 4707453645fSAndriy Voskoboinyk DEVMETHOD(device_attach, rtwn_usb_attach), 4717453645fSAndriy Voskoboinyk DEVMETHOD(device_detach, rtwn_usb_detach), 4727453645fSAndriy Voskoboinyk DEVMETHOD(device_suspend, rtwn_usb_suspend), 4737453645fSAndriy Voskoboinyk DEVMETHOD(device_resume, rtwn_usb_resume), 4747453645fSAndriy Voskoboinyk 4757453645fSAndriy Voskoboinyk DEVMETHOD_END 4767453645fSAndriy Voskoboinyk }; 4777453645fSAndriy Voskoboinyk 4787453645fSAndriy Voskoboinyk static driver_t rtwn_usb_driver = { 4797453645fSAndriy Voskoboinyk "rtwn", 4807453645fSAndriy Voskoboinyk rtwn_usb_methods, 4817453645fSAndriy Voskoboinyk sizeof(struct rtwn_usb_softc) 4827453645fSAndriy Voskoboinyk }; 4837453645fSAndriy Voskoboinyk 4847453645fSAndriy Voskoboinyk static devclass_t rtwn_usb_devclass; 4857453645fSAndriy Voskoboinyk 4867453645fSAndriy Voskoboinyk DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); 4877453645fSAndriy Voskoboinyk MODULE_VERSION(rtwn_usb, 1); 4887453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); 4897453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); 4907453645fSAndriy Voskoboinyk MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); 4917453645fSAndriy Voskoboinyk USB_PNP_HOST_INFO(rtwn_devs); 492