The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/rtwn/usb/rtwn_usb_attach.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_reset_rx_list(struct rtwn_usb_softc *);
   81 static void     rtwn_usb_start_xfers(struct rtwn_softc *);
   82 static void     rtwn_usb_abort_xfers(struct rtwn_softc *);
   83 static int      rtwn_usb_fw_write_block(struct rtwn_softc *,
   84                     const uint8_t *, uint16_t, int);
   85 static void     rtwn_usb_drop_incorrect_tx(struct rtwn_softc *);
   86 static void     rtwn_usb_attach_methods(struct rtwn_softc *);
   87 static void     rtwn_usb_sysctlattach(struct rtwn_softc *);
   88 
   89 #define RTWN_CONFIG_INDEX       0
   90 
   91 static int
   92 rtwn_usb_match(device_t self)
   93 {
   94         struct usb_attach_arg *uaa = device_get_ivars(self);
   95 
   96         if (uaa->usb_mode != USB_MODE_HOST)
   97                 return (ENXIO);
   98         if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX)
   99                 return (ENXIO);
  100         if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX)
  101                 return (ENXIO);
  102 
  103         return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa));
  104 }
  105 
  106 static int
  107 rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[],
  108     int ndata, int maxsz)
  109 {
  110         int i, error;
  111 
  112         for (i = 0; i < ndata; i++) {
  113                 struct rtwn_data *dp = &data[i];
  114                 dp->m = NULL;
  115                 dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
  116                 if (dp->buf == NULL) {
  117                         device_printf(sc->sc_dev,
  118                             "could not allocate buffer\n");
  119                         error = ENOMEM;
  120                         goto fail;
  121                 }
  122                 dp->ni = NULL;
  123         }
  124 
  125         return (0);
  126 fail:
  127         rtwn_usb_free_list(sc, data, ndata);
  128         return (error);
  129 }
  130 
  131 static int
  132 rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
  133 {
  134         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  135         int error, i;
  136 
  137         error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
  138             uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT);
  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_USB_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         uc->uc_rx_stat_len = 0;
  203         uc->uc_rx_off = 0;
  204 
  205         STAILQ_INIT(&uc->uc_rx_active);
  206         STAILQ_INIT(&uc->uc_rx_inactive);
  207 }
  208 
  209 static void
  210 rtwn_usb_free_tx_list(struct rtwn_softc *sc)
  211 {
  212         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  213 
  214         rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT);
  215 
  216         STAILQ_INIT(&uc->uc_tx_active);
  217         STAILQ_INIT(&uc->uc_tx_inactive);
  218         STAILQ_INIT(&uc->uc_tx_pending);
  219 }
  220 
  221 static void
  222 rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
  223 {
  224         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  225 
  226         RTWN_ASSERT_LOCKED(sc);
  227 
  228         rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap);
  229         rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap);
  230         if (vap == NULL) {
  231                 rtwn_usb_reset_rx_list(uc);
  232                 sc->qfullmsk = 0;
  233         }
  234 }
  235 
  236 static void
  237 rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc,
  238     rtwn_datahead *head, struct ieee80211vap *vap)
  239 {
  240         struct rtwn_vap *uvp = RTWN_VAP(vap);
  241         struct rtwn_data *dp, *tmp;
  242         int id;
  243 
  244         id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID);
  245 
  246         STAILQ_FOREACH_SAFE(dp, head, next, tmp) {
  247                 if (vap == NULL || (dp->ni == NULL &&
  248                     (dp->id == id || id == RTWN_VAP_ID_INVALID)) ||
  249                     (dp->ni != NULL && dp->ni->ni_vap == vap)) {
  250                         if (dp->ni != NULL) {
  251                                 ieee80211_free_node(dp->ni);
  252                                 dp->ni = NULL;
  253                         }
  254 
  255                         if (dp->m != NULL) {
  256                                 m_freem(dp->m);
  257                                 dp->m = NULL;
  258                         }
  259 
  260                         STAILQ_REMOVE(head, dp, rtwn_data, next);
  261                         STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next);
  262                 }
  263         }
  264 }
  265 
  266 static void
  267 rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc)
  268 {
  269         int i;
  270 
  271         for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) {
  272                 struct rtwn_data *dp = &uc->uc_rx[i];
  273 
  274                 if (dp->m != NULL) {
  275                         m_freem(dp->m);
  276                         dp->m = NULL;
  277                 }
  278         }
  279         uc->uc_rx_stat_len = 0;
  280         uc->uc_rx_off = 0;
  281 }
  282 
  283 static void
  284 rtwn_usb_start_xfers(struct rtwn_softc *sc)
  285 {
  286         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  287 
  288         usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]);
  289 }
  290 
  291 static void
  292 rtwn_usb_abort_xfers(struct rtwn_softc *sc)
  293 {
  294         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  295         int i;
  296 
  297         RTWN_ASSERT_LOCKED(sc);
  298 
  299         /* abort any pending transfers */
  300         RTWN_UNLOCK(sc);
  301         for (i = 0; i < RTWN_N_TRANSFER; i++)
  302                 usbd_transfer_drain(uc->uc_xfer[i]);
  303         RTWN_LOCK(sc);
  304 }
  305 
  306 static int
  307 rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf,
  308     uint16_t reg, int mlen)
  309 {
  310         int error;
  311 
  312         /* XXX fix this deconst */
  313         error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf),
  314             mlen);
  315 
  316         return (error);
  317 }
  318 
  319 static void
  320 rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc)
  321 {
  322 
  323         rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0,
  324             R92C_TXDMA_OFFSET_DROP_DATA_EN, 1);
  325 }
  326 
  327 static void
  328 rtwn_usb_attach_methods(struct rtwn_softc *sc)
  329 {
  330         sc->sc_write_1          = rtwn_usb_write_1;
  331         sc->sc_write_2          = rtwn_usb_write_2;
  332         sc->sc_write_4          = rtwn_usb_write_4;
  333         sc->sc_read_1           = rtwn_usb_read_1;
  334         sc->sc_read_2           = rtwn_usb_read_2;
  335         sc->sc_read_4           = rtwn_usb_read_4;
  336         sc->sc_delay            = rtwn_usb_delay;
  337         sc->sc_tx_start         = rtwn_usb_tx_start;
  338         sc->sc_start_xfers      = rtwn_usb_start_xfers;
  339         sc->sc_reset_lists      = rtwn_usb_reset_lists;
  340         sc->sc_abort_xfers      = rtwn_usb_abort_xfers;
  341         sc->sc_fw_write_block   = rtwn_usb_fw_write_block;
  342         sc->sc_get_qmap         = rtwn_usb_get_qmap;
  343         sc->sc_set_desc_addr    = rtwn_nop_softc;
  344         sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx;
  345         sc->sc_beacon_update_begin = rtwn_nop_softc_vap;
  346         sc->sc_beacon_update_end = rtwn_nop_softc_vap;
  347         sc->sc_beacon_unload    = rtwn_nop_softc_int;
  348 
  349         sc->bcn_check_interval  = 100;
  350 }
  351 
  352 static void
  353 rtwn_usb_sysctlattach(struct rtwn_softc *sc)
  354 {
  355         struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
  356         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
  357         struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
  358         char str[64];
  359         int ret;
  360 
  361         ret = snprintf(str, sizeof(str),
  362             "Rx buffer size, 512-byte units [%d...%d]",
  363             RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX);
  364         KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret));
  365         (void) ret;
  366 
  367         uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF;
  368         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  369             "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size,
  370             uc->uc_rx_buf_size, str);
  371         if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN)
  372                 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN;
  373         if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX)
  374                 uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX;
  375 }
  376 
  377 static int
  378 rtwn_usb_attach(device_t self)
  379 {
  380         struct usb_attach_arg *uaa = device_get_ivars(self);
  381         struct rtwn_usb_softc *uc = device_get_softc(self);
  382         struct rtwn_softc *sc = &uc->uc_sc;
  383         struct ieee80211com *ic = &sc->sc_ic;
  384         int error;
  385 
  386         device_set_usb_desc(self);
  387         uc->uc_udev = uaa->device;
  388         sc->sc_dev = self;
  389         ic->ic_name = device_get_nameunit(self);
  390 
  391         /* Need to be initialized early. */
  392         rtwn_sysctlattach(sc);
  393         rtwn_usb_sysctlattach(sc);
  394         mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
  395 
  396         rtwn_usb_attach_methods(sc);
  397         rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa));
  398 
  399         error = rtwn_usb_setup_endpoints(uc);
  400         if (error != 0)
  401                 goto detach;
  402 
  403         /* Allocate Tx/Rx buffers. */
  404         error = rtwn_usb_alloc_rx_list(sc);
  405         if (error != 0)
  406                 goto detach;
  407 
  408         error = rtwn_usb_alloc_tx_list(sc);
  409         if (error != 0)
  410                 goto detach;
  411 
  412         /* Generic attach. */
  413         error = rtwn_attach(sc);
  414         if (error != 0)
  415                 goto detach;
  416 
  417         return (0);
  418 
  419 detach:
  420         rtwn_usb_detach(self);          /* failure */
  421         return (ENXIO);
  422 }
  423 
  424 static int
  425 rtwn_usb_detach(device_t self)
  426 {
  427         struct rtwn_usb_softc *uc = device_get_softc(self);
  428         struct rtwn_softc *sc = &uc->uc_sc;
  429 
  430         /* Generic detach. */
  431         rtwn_detach(sc);
  432 
  433         /* Free Tx/Rx buffers. */
  434         rtwn_usb_free_tx_list(sc);
  435         rtwn_usb_free_rx_list(sc);
  436 
  437         /* Detach all USB transfers. */
  438         usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER);
  439 
  440         rtwn_detach_private(sc);
  441         mtx_destroy(&sc->sc_mtx);
  442 
  443         return (0);
  444 }
  445 
  446 static int
  447 rtwn_usb_suspend(device_t self)
  448 {
  449         struct rtwn_usb_softc *uc = device_get_softc(self);
  450 
  451         rtwn_suspend(&uc->uc_sc);
  452 
  453         return (0);
  454 }
  455 
  456 static int
  457 rtwn_usb_resume(device_t self)
  458 {
  459         struct rtwn_usb_softc *uc = device_get_softc(self);
  460 
  461         rtwn_resume(&uc->uc_sc);
  462 
  463         return (0);
  464 }
  465 
  466 static device_method_t rtwn_usb_methods[] = {
  467         /* Device interface */
  468         DEVMETHOD(device_probe,         rtwn_usb_match),
  469         DEVMETHOD(device_attach,        rtwn_usb_attach),
  470         DEVMETHOD(device_detach,        rtwn_usb_detach),
  471         DEVMETHOD(device_suspend,       rtwn_usb_suspend),
  472         DEVMETHOD(device_resume,        rtwn_usb_resume),
  473 
  474         DEVMETHOD_END
  475 };
  476 
  477 static driver_t rtwn_usb_driver = {
  478         "rtwn",
  479         rtwn_usb_methods,
  480         sizeof(struct rtwn_usb_softc)
  481 };
  482 
  483 DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, NULL, NULL);
  484 MODULE_VERSION(rtwn_usb, 1);
  485 MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1);
  486 MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1);
  487 MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2);
  488 USB_PNP_HOST_INFO(rtwn_devs);

Cache object: 8d8fe2bf283ffc9d616b6703f130f91d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.