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/wi/if_wi.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 /*      $NetBSD: wi.c,v 1.109 2003/01/09 08:52:19 dyoung Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1997, 1998, 1999
    5  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * Lucent WaveLAN/IEEE 802.11 PCMCIA driver.
   37  *
   38  * Original FreeBSD driver written by Bill Paul <wpaul@ctr.columbia.edu>
   39  * Electrical Engineering Department
   40  * Columbia University, New York City
   41  */
   42 
   43 /*
   44  * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
   45  * from Lucent. Unlike the older cards, the new ones are programmed
   46  * entirely via a firmware-driven controller called the Hermes.
   47  * Unfortunately, Lucent will not release the Hermes programming manual
   48  * without an NDA (if at all). What they do release is an API library
   49  * called the HCF (Hardware Control Functions) which is supposed to
   50  * do the device-specific operations of a device driver for you. The
   51  * publically available version of the HCF library (the 'HCF Light') is 
   52  * a) extremely gross, b) lacks certain features, particularly support
   53  * for 802.11 frames, and c) is contaminated by the GNU Public License.
   54  *
   55  * This driver does not use the HCF or HCF Light at all. Instead, it
   56  * programs the Hermes controller directly, using information gleaned
   57  * from the HCF Light code and corresponding documentation.
   58  *
   59  * This driver supports the ISA, PCMCIA and PCI versions of the Lucent
   60  * WaveLan cards (based on the Hermes chipset), as well as the newer
   61  * Prism 2 chipsets with firmware from Intersil and Symbol.
   62  */
   63 
   64 #include <sys/cdefs.h>
   65 __FBSDID("$FreeBSD: releng/5.2/sys/dev/wi/if_wi.c 123467 2003-12-11 20:21:20Z imp $");
   66 
   67 #define WI_HERMES_AUTOINC_WAR   /* Work around data write autoinc bug. */
   68 #define WI_HERMES_STATS_WAR     /* Work around stats counter bug. */
   69 
   70 #define NBPFILTER       1
   71 
   72 #include <sys/param.h>
   73 #include <sys/systm.h>
   74 #if __FreeBSD_version >= 500033
   75 #include <sys/endian.h>
   76 #endif
   77 #include <sys/sockio.h>
   78 #include <sys/mbuf.h>
   79 #include <sys/proc.h>
   80 #include <sys/kernel.h>
   81 #include <sys/socket.h>
   82 #include <sys/module.h>
   83 #include <sys/bus.h>
   84 #include <sys/random.h>
   85 #include <sys/syslog.h>
   86 #include <sys/sysctl.h>
   87 
   88 #include <machine/bus.h>
   89 #include <machine/resource.h>
   90 #include <machine/clock.h>
   91 #include <machine/atomic.h>
   92 #include <sys/rman.h>
   93 
   94 #include <net/if.h>
   95 #include <net/if_arp.h>
   96 #include <net/ethernet.h>
   97 #include <net/if_dl.h>
   98 #include <net/if_media.h>
   99 #include <net/if_types.h>
  100 
  101 #include <net80211/ieee80211_var.h>
  102 #include <net80211/ieee80211_ioctl.h>
  103 #include <net80211/ieee80211_radiotap.h>
  104 
  105 #include <netinet/in.h>
  106 #include <netinet/in_systm.h>
  107 #include <netinet/in_var.h>
  108 #include <netinet/ip.h>
  109 #include <netinet/if_ether.h>
  110 
  111 #include <net/bpf.h>
  112 
  113 #include <dev/wi/if_wavelan_ieee.h>
  114 #include <dev/wi/if_wireg.h>
  115 #include <dev/wi/if_wivar.h>
  116 
  117 #define IF_POLL(ifq, m)         ((m) = (ifq)->ifq_head)
  118 #define IFQ_POLL(ifq, m)        IF_POLL((ifq), (m))
  119 #define IFQ_DEQUEUE(ifq, m)     IF_DEQUEUE((ifq), (m))
  120 
  121 static void wi_start(struct ifnet *);
  122 static int  wi_reset(struct wi_softc *);
  123 static void wi_watchdog(struct ifnet *);
  124 static int  wi_ioctl(struct ifnet *, u_long, caddr_t);
  125 static int  wi_media_change(struct ifnet *);
  126 static void wi_media_status(struct ifnet *, struct ifmediareq *);
  127 
  128 static void wi_rx_intr(struct wi_softc *);
  129 static void wi_tx_intr(struct wi_softc *);
  130 static void wi_tx_ex_intr(struct wi_softc *);
  131 static void wi_info_intr(struct wi_softc *);
  132 
  133 static int  wi_get_cfg(struct ifnet *, u_long, caddr_t);
  134 static int  wi_set_cfg(struct ifnet *, u_long, caddr_t);
  135 static int  wi_write_txrate(struct wi_softc *);
  136 static int  wi_write_wep(struct wi_softc *);
  137 static int  wi_write_multi(struct wi_softc *);
  138 static int  wi_alloc_fid(struct wi_softc *, int, int *);
  139 static void wi_read_nicid(struct wi_softc *);
  140 static int  wi_write_ssid(struct wi_softc *, int, u_int8_t *, int);
  141 
  142 static int  wi_cmd(struct wi_softc *, int, int, int, int);
  143 static int  wi_seek_bap(struct wi_softc *, int, int);
  144 static int  wi_read_bap(struct wi_softc *, int, int, void *, int);
  145 static int  wi_write_bap(struct wi_softc *, int, int, void *, int);
  146 static int  wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int);
  147 static int  wi_read_rid(struct wi_softc *, int, void *, int *);
  148 static int  wi_write_rid(struct wi_softc *, int, void *, int);
  149 
  150 static int  wi_newstate(struct ieee80211com *, enum ieee80211_state, int);
  151 
  152 static int  wi_scan_ap(struct wi_softc *, u_int16_t, u_int16_t);
  153 static void wi_scan_result(struct wi_softc *, int, int);
  154 
  155 static void wi_dump_pkt(struct wi_frame *, struct ieee80211_node *, int rssi);
  156 
  157 static int wi_get_debug(struct wi_softc *, struct wi_req *);
  158 static int wi_set_debug(struct wi_softc *, struct wi_req *);
  159 
  160 #if __FreeBSD_version >= 500000
  161 /* support to download firmware for symbol CF card */
  162 static int wi_symbol_write_firm(struct wi_softc *, const void *, int,
  163                 const void *, int);
  164 static int wi_symbol_set_hcr(struct wi_softc *, int);
  165 #endif
  166 
  167 static __inline int
  168 wi_write_val(struct wi_softc *sc, int rid, u_int16_t val)
  169 {
  170 
  171         val = htole16(val);
  172         return wi_write_rid(sc, rid, &val, sizeof(val));
  173 }
  174 
  175 SYSCTL_NODE(_hw, OID_AUTO, wi, CTLFLAG_RD, 0, "Wireless driver parameters");
  176 
  177 static  struct timeval lasttxerror;     /* time of last tx error msg */
  178 static  int curtxeps;                   /* current tx error msgs/sec */
  179 static  int wi_txerate = 0;             /* tx error rate: max msgs/sec */
  180 SYSCTL_INT(_hw_wi, OID_AUTO, txerate, CTLFLAG_RW, &wi_txerate,
  181             0, "max tx error msgs/sec; 0 to disable msgs");
  182 
  183 #define WI_DEBUG
  184 #ifdef WI_DEBUG
  185 static  int wi_debug = 0;
  186 SYSCTL_INT(_hw_wi, OID_AUTO, debug, CTLFLAG_RW, &wi_debug,
  187             0, "control debugging printfs");
  188 
  189 #define DPRINTF(X)      if (wi_debug) printf X
  190 #define DPRINTF2(X)     if (wi_debug > 1) printf X
  191 #define IFF_DUMPPKTS(_ifp) \
  192         (((_ifp)->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
  193 #else
  194 #define DPRINTF(X)
  195 #define DPRINTF2(X)
  196 #define IFF_DUMPPKTS(_ifp)      0
  197 #endif
  198 
  199 #define WI_INTRS        (WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO)
  200 
  201 struct wi_card_ident wi_card_ident[] = {
  202         /* CARD_ID                      CARD_NAME               FIRM_TYPE */
  203         { WI_NIC_LUCENT_ID,             WI_NIC_LUCENT_STR,      WI_LUCENT },
  204         { WI_NIC_SONY_ID,               WI_NIC_SONY_STR,        WI_LUCENT },
  205         { WI_NIC_LUCENT_EMB_ID,         WI_NIC_LUCENT_EMB_STR,  WI_LUCENT },
  206         { WI_NIC_EVB2_ID,               WI_NIC_EVB2_STR,        WI_INTERSIL },
  207         { WI_NIC_HWB3763_ID,            WI_NIC_HWB3763_STR,     WI_INTERSIL },
  208         { WI_NIC_HWB3163_ID,            WI_NIC_HWB3163_STR,     WI_INTERSIL },
  209         { WI_NIC_HWB3163B_ID,           WI_NIC_HWB3163B_STR,    WI_INTERSIL },
  210         { WI_NIC_EVB3_ID,               WI_NIC_EVB3_STR,        WI_INTERSIL },
  211         { WI_NIC_HWB1153_ID,            WI_NIC_HWB1153_STR,     WI_INTERSIL },
  212         { WI_NIC_P2_SST_ID,             WI_NIC_P2_SST_STR,      WI_INTERSIL },
  213         { WI_NIC_EVB2_SST_ID,           WI_NIC_EVB2_SST_STR,    WI_INTERSIL },
  214         { WI_NIC_3842_EVA_ID,           WI_NIC_3842_EVA_STR,    WI_INTERSIL },
  215         { WI_NIC_3842_PCMCIA_AMD_ID,    WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
  216         { WI_NIC_3842_PCMCIA_SST_ID,    WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
  217         { WI_NIC_3842_PCMCIA_ATL_ID,    WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
  218         { WI_NIC_3842_PCMCIA_ATS_ID,    WI_NIC_3842_PCMCIA_STR, WI_INTERSIL },
  219         { WI_NIC_3842_MINI_AMD_ID,      WI_NIC_3842_MINI_STR,   WI_INTERSIL },
  220         { WI_NIC_3842_MINI_SST_ID,      WI_NIC_3842_MINI_STR,   WI_INTERSIL },
  221         { WI_NIC_3842_MINI_ATL_ID,      WI_NIC_3842_MINI_STR,   WI_INTERSIL },
  222         { WI_NIC_3842_MINI_ATS_ID,      WI_NIC_3842_MINI_STR,   WI_INTERSIL },
  223         { WI_NIC_3842_PCI_AMD_ID,       WI_NIC_3842_PCI_STR,    WI_INTERSIL },
  224         { WI_NIC_3842_PCI_SST_ID,       WI_NIC_3842_PCI_STR,    WI_INTERSIL },
  225         { WI_NIC_3842_PCI_ATS_ID,       WI_NIC_3842_PCI_STR,    WI_INTERSIL },
  226         { WI_NIC_3842_PCI_ATL_ID,       WI_NIC_3842_PCI_STR,    WI_INTERSIL },
  227         { WI_NIC_P3_PCMCIA_AMD_ID,      WI_NIC_P3_PCMCIA_STR,   WI_INTERSIL },
  228         { WI_NIC_P3_PCMCIA_SST_ID,      WI_NIC_P3_PCMCIA_STR,   WI_INTERSIL },
  229         { WI_NIC_P3_PCMCIA_ATL_ID,      WI_NIC_P3_PCMCIA_STR,   WI_INTERSIL },
  230         { WI_NIC_P3_PCMCIA_ATS_ID,      WI_NIC_P3_PCMCIA_STR,   WI_INTERSIL },
  231         { WI_NIC_P3_MINI_AMD_ID,        WI_NIC_P3_MINI_STR,     WI_INTERSIL },
  232         { WI_NIC_P3_MINI_SST_ID,        WI_NIC_P3_MINI_STR,     WI_INTERSIL },
  233         { WI_NIC_P3_MINI_ATL_ID,        WI_NIC_P3_MINI_STR,     WI_INTERSIL },
  234         { WI_NIC_P3_MINI_ATS_ID,        WI_NIC_P3_MINI_STR,     WI_INTERSIL },
  235         { 0,    NULL,   0 },
  236 };
  237 
  238 devclass_t wi_devclass;
  239 
  240 int
  241 wi_attach(device_t dev)
  242 {
  243         struct wi_softc *sc = device_get_softc(dev);
  244         struct ieee80211com *ic = &sc->sc_ic;
  245         struct ifnet *ifp = &ic->ic_if;
  246         int i, nrates, buflen;
  247         u_int16_t val;
  248         u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE];
  249         struct ieee80211_rateset *rs;
  250         static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
  251                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  252         };
  253         int error;
  254 
  255         /*
  256          * NB: no locking is needed here; don't put it here
  257          *     unless you can prove it!
  258          */
  259         error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
  260             wi_intr, sc, &sc->wi_intrhand);
  261 
  262         if (error) {
  263                 device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
  264                 wi_free(dev);
  265                 return (error);
  266         }
  267 
  268 #if __FreeBSD_version >= 500000
  269         mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
  270             MTX_DEF | MTX_RECURSE);
  271 #endif
  272 
  273         /* Reset the NIC. */
  274         if (wi_reset(sc) != 0)
  275                 return ENXIO;           /* XXX */
  276 
  277         /*
  278          * Read the station address.
  279          * And do it twice. I've seen PRISM-based cards that return
  280          * an error when trying to read it the first time, which causes
  281          * the probe to fail.
  282          */
  283         buflen = IEEE80211_ADDR_LEN;
  284         error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
  285         if (error != 0) {
  286                 buflen = IEEE80211_ADDR_LEN;
  287                 error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
  288         }
  289         if (error || IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) {
  290                 if (error != 0)
  291                         device_printf(dev, "mac read failed %d\n", error);
  292                 else
  293                         device_printf(dev, "mac read failed (all zeros)\n");
  294                 wi_free(dev);
  295                 return (error);
  296         }
  297         device_printf(dev, "802.11 address: %6D\n", ic->ic_myaddr, ":");
  298 
  299         /* Read NIC identification */
  300         wi_read_nicid(sc);
  301 
  302         ifp->if_softc = sc;
  303         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  304         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  305         ifp->if_ioctl = wi_ioctl;
  306         ifp->if_start = wi_start;
  307         ifp->if_watchdog = wi_watchdog;
  308         ifp->if_init = wi_init;
  309         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  310 
  311         ic->ic_phytype = IEEE80211_T_DS;
  312         ic->ic_opmode = IEEE80211_M_STA;
  313         ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_AHDEMO;
  314         ic->ic_state = IEEE80211_S_INIT;
  315 
  316         /*
  317          * Query the card for available channels and setup the
  318          * channel table.  We assume these are all 11b channels.
  319          */
  320         buflen = sizeof(val);
  321         if (wi_read_rid(sc, WI_RID_CHANNEL_LIST, &val, &buflen) != 0)
  322                 val = htole16(0x1fff);  /* assume 1-11 */
  323         KASSERT(val != 0, ("wi_attach: no available channels listed!"));
  324 
  325         val <<= 1;                      /* shift for base 1 indices */
  326         for (i = 1; i < 16; i++) {
  327                 if (isset((u_int8_t*)&val, i)) {
  328                         ic->ic_channels[i].ic_freq =
  329                                 ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
  330                         ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
  331                 }
  332         }
  333 
  334         /*
  335          * Read the default channel from the NIC. This may vary
  336          * depending on the country where the NIC was purchased, so
  337          * we can't hard-code a default and expect it to work for
  338          * everyone.
  339          *
  340          * If no channel is specified, let the 802.11 code select.
  341          */
  342         buflen = sizeof(val);
  343         if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0) {
  344                 val = le16toh(val);
  345                 KASSERT(val < IEEE80211_CHAN_MAX &&
  346                         ic->ic_channels[val].ic_flags != 0,
  347                         ("wi_attach: invalid own channel %u!", val));
  348                 ic->ic_ibss_chan = &ic->ic_channels[val];
  349         } else {
  350                 device_printf(dev,
  351                         "WI_RID_OWN_CHNL failed, using first channel!\n");
  352                 ic->ic_ibss_chan = &ic->ic_channels[0];
  353         }
  354 
  355         /*
  356          * Set flags based on firmware version.
  357          */
  358         switch (sc->sc_firmware_type) {
  359         case WI_LUCENT:
  360                 sc->sc_ntxbuf = 1;
  361                 sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
  362 #ifdef WI_HERMES_AUTOINC_WAR
  363                 /* XXX: not confirmed, but never seen for recent firmware */
  364                 if (sc->sc_sta_firmware_ver <  40000) {
  365                         sc->sc_flags |= WI_FLAGS_BUG_AUTOINC;
  366                 }
  367 #endif
  368                 if (sc->sc_sta_firmware_ver >= 60000)
  369                         sc->sc_flags |= WI_FLAGS_HAS_MOR;
  370                 if (sc->sc_sta_firmware_ver >= 60006) {
  371                         ic->ic_caps |= IEEE80211_C_IBSS;
  372                         ic->ic_caps |= IEEE80211_C_MONITOR;
  373                 }
  374                 sc->sc_ibss_port = htole16(1);
  375 
  376                 sc->sc_min_rssi = WI_LUCENT_MIN_RSSI;
  377                 sc->sc_max_rssi = WI_LUCENT_MAX_RSSI;
  378                 sc->sc_dbm_offset = WI_LUCENT_DBM_OFFSET;
  379                 break;
  380 
  381         case WI_INTERSIL:
  382                 sc->sc_ntxbuf = WI_NTXBUF;
  383                 sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR;
  384                 sc->sc_flags |= WI_FLAGS_HAS_ROAMING;
  385                 sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
  386                 if (sc->sc_sta_firmware_ver > 10101)
  387                         sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST;
  388                 if (sc->sc_sta_firmware_ver >= 800) {
  389                         ic->ic_caps |= IEEE80211_C_IBSS;
  390                         ic->ic_caps |= IEEE80211_C_MONITOR;
  391                 }
  392                 /*
  393                  * version 0.8.3 and newer are the only ones that are known
  394                  * to currently work.  Earlier versions can be made to work,
  395                  * at least according to the Linux driver.
  396                  */
  397                 if (sc->sc_sta_firmware_ver >= 803)
  398                         ic->ic_caps |= IEEE80211_C_HOSTAP;
  399                 sc->sc_ibss_port = htole16(0);
  400 
  401                 sc->sc_min_rssi = WI_PRISM_MIN_RSSI;
  402                 sc->sc_max_rssi = WI_PRISM_MAX_RSSI;
  403                 sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET;
  404                 break;
  405 
  406         case WI_SYMBOL:
  407                 sc->sc_ntxbuf = 1;
  408                 sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY;
  409                 if (sc->sc_sta_firmware_ver >= 25000)
  410                         ic->ic_caps |= IEEE80211_C_IBSS;
  411                 sc->sc_ibss_port = htole16(4);
  412 
  413                 sc->sc_min_rssi = WI_PRISM_MIN_RSSI;
  414                 sc->sc_max_rssi = WI_PRISM_MAX_RSSI;
  415                 sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET;
  416                 break;
  417         }
  418 
  419         /*
  420          * Find out if we support WEP on this card.
  421          */
  422         buflen = sizeof(val);
  423         if (wi_read_rid(sc, WI_RID_WEP_AVAIL, &val, &buflen) == 0 &&
  424             val != htole16(0))
  425                 ic->ic_caps |= IEEE80211_C_WEP;
  426 
  427         /* Find supported rates. */
  428         buflen = sizeof(ratebuf);
  429         rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
  430         if (wi_read_rid(sc, WI_RID_DATA_RATES, ratebuf, &buflen) == 0) {
  431                 nrates = le16toh(*(u_int16_t *)ratebuf);
  432                 if (nrates > IEEE80211_RATE_MAXSIZE)
  433                         nrates = IEEE80211_RATE_MAXSIZE;
  434                 rs->rs_nrates = 0;
  435                 for (i = 0; i < nrates; i++)
  436                         if (ratebuf[2+i])
  437                                 rs->rs_rates[rs->rs_nrates++] = ratebuf[2+i];
  438         } else {
  439                 /* XXX fallback on error? */
  440                 rs->rs_nrates = 0;
  441         }
  442 
  443         buflen = sizeof(val);
  444         if ((sc->sc_flags & WI_FLAGS_HAS_DBMADJUST) &&
  445             wi_read_rid(sc, WI_RID_DBM_ADJUST, &val, &buflen) == 0) {
  446                 sc->sc_dbm_offset = le16toh(val);
  447         }
  448 
  449         sc->sc_max_datalen = 2304;
  450         sc->sc_system_scale = 1;
  451         sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
  452         sc->sc_roaming_mode = 1;
  453 
  454         sc->sc_portnum = WI_DEFAULT_PORT;
  455         sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
  456 
  457         bzero(sc->sc_nodename, sizeof(sc->sc_nodename));
  458         sc->sc_nodelen = sizeof(WI_DEFAULT_NODENAME) - 1;
  459         bcopy(WI_DEFAULT_NODENAME, sc->sc_nodename, sc->sc_nodelen);
  460 
  461         bzero(sc->sc_net_name, sizeof(sc->sc_net_name));
  462         bcopy(WI_DEFAULT_NETNAME, sc->sc_net_name,
  463             sizeof(WI_DEFAULT_NETNAME) - 1);
  464 
  465         /*
  466          * Call MI attach routine.
  467          */
  468         ieee80211_ifattach(ifp);
  469         /* override state transition method */
  470         sc->sc_newstate = ic->ic_newstate;
  471         ic->ic_newstate = wi_newstate;
  472         ieee80211_media_init(ifp, wi_media_change, wi_media_status);
  473 
  474 #if NBPFILTER > 0
  475         bpfattach2(ifp, DLT_IEEE802_11_RADIO,
  476                 sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th),
  477                 &sc->sc_drvbpf);
  478         /*
  479          * Initialize constant fields.
  480          *
  481          * NB: the channel is setup each time we transition to the
  482          *     RUN state to avoid filling it in for each frame.
  483          */
  484         sc->sc_tx_th.wt_ihdr.it_len = sizeof(sc->sc_tx_th);
  485         sc->sc_tx_th.wt_ihdr.it_present = WI_TX_RADIOTAP_PRESENT;
  486 
  487         sc->sc_rx_th.wr_ihdr.it_len = sizeof(sc->sc_rx_th);
  488         sc->sc_rx_th.wr_ihdr.it_present = WI_RX_RADIOTAP_PRESENT0;
  489         sc->sc_rx_th.wr_present1 = WI_RX_RADIOTAP_PRESENT1;
  490 #endif
  491         return (0);
  492 }
  493 
  494 int
  495 wi_detach(device_t dev)
  496 {
  497         struct wi_softc *sc = device_get_softc(dev);
  498         struct ifnet *ifp = &sc->sc_ic.ic_if;
  499         WI_LOCK_DECL();
  500 
  501         WI_LOCK(sc);
  502 
  503         /* check if device was removed */
  504         sc->wi_gone |= !bus_child_present(dev);
  505 
  506         wi_stop(ifp, 0);
  507 
  508 #if NBPFILTER > 0
  509         bpfdetach(ifp);
  510 #endif
  511         ieee80211_ifdetach(ifp);
  512         WI_UNLOCK(sc);
  513         bus_teardown_intr(dev, sc->irq, sc->wi_intrhand);
  514         wi_free(dev);
  515 #if __FreeBSD_version >= 500000
  516         mtx_destroy(&sc->sc_mtx);
  517 #endif
  518         return (0);
  519 }
  520 
  521 #ifdef __NetBSD__
  522 int
  523 wi_activate(struct device *self, enum devact act)
  524 {
  525         struct wi_softc *sc = (struct wi_softc *)self;
  526         int rv = 0, s;
  527 
  528         s = splnet();
  529         switch (act) {
  530         case DVACT_ACTIVATE:
  531                 rv = EOPNOTSUPP;
  532                 break;
  533 
  534         case DVACT_DEACTIVATE:
  535                 if_deactivate(&sc->sc_ic.ic_if);
  536                 break;
  537         }
  538         splx(s);
  539         return rv;
  540 }
  541 
  542 void
  543 wi_power(struct wi_softc *sc, int why)
  544 {
  545         struct ifnet *ifp = &sc->sc_ic.ic_if;
  546         int s;
  547 
  548         s = splnet();
  549         switch (why) {
  550         case PWR_SUSPEND:
  551         case PWR_STANDBY:
  552                 wi_stop(ifp, 1);
  553                 break;
  554         case PWR_RESUME:
  555                 if (ifp->if_flags & IFF_UP) {
  556                         wi_init(ifp);
  557                         (void)wi_intr(sc);
  558                 }
  559                 break;
  560         case PWR_SOFTSUSPEND:
  561         case PWR_SOFTSTANDBY:
  562         case PWR_SOFTRESUME:
  563                 break;
  564         }
  565         splx(s);
  566 }
  567 #endif /* __NetBSD__ */
  568 
  569 void
  570 wi_shutdown(device_t dev)
  571 {
  572         struct wi_softc *sc = device_get_softc(dev);
  573 
  574         wi_stop(&sc->sc_if, 1);
  575 }
  576 
  577 void
  578 wi_intr(void *arg)
  579 {
  580         struct wi_softc *sc = arg;
  581         struct ifnet *ifp = &sc->sc_ic.ic_if;
  582         u_int16_t status;
  583         WI_LOCK_DECL();
  584 
  585         WI_LOCK(sc);
  586 
  587         if (sc->wi_gone || !sc->sc_enabled || (ifp->if_flags & IFF_UP) == 0) {
  588                 CSR_WRITE_2(sc, WI_INT_EN, 0);
  589                 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
  590                 WI_UNLOCK(sc);
  591                 return;
  592         }
  593 
  594         /* Disable interrupts. */
  595         CSR_WRITE_2(sc, WI_INT_EN, 0);
  596 
  597         status = CSR_READ_2(sc, WI_EVENT_STAT);
  598         if (status & WI_EV_RX)
  599                 wi_rx_intr(sc);
  600         if (status & WI_EV_ALLOC)
  601                 wi_tx_intr(sc);
  602         if (status & WI_EV_TX_EXC)
  603                 wi_tx_ex_intr(sc);
  604         if (status & WI_EV_INFO)
  605                 wi_info_intr(sc);
  606         if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
  607             (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
  608             _IF_QLEN(&ifp->if_snd) != 0)
  609                 wi_start(ifp);
  610 
  611         /* Re-enable interrupts. */
  612         CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
  613 
  614         WI_UNLOCK(sc);
  615 
  616         return;
  617 }
  618 
  619 void
  620 wi_init(void *arg)
  621 {
  622         struct wi_softc *sc = arg;
  623         struct ifnet *ifp = &sc->sc_if;
  624         struct ieee80211com *ic = &sc->sc_ic;
  625         struct wi_joinreq join;
  626         int i;
  627         int error = 0, wasenabled;
  628         struct ifaddr *ifa;
  629         struct sockaddr_dl *sdl;
  630         WI_LOCK_DECL();
  631 
  632         WI_LOCK(sc);
  633 
  634         if (sc->wi_gone) {
  635                 WI_UNLOCK(sc);
  636                 return;
  637         }
  638 
  639         if ((wasenabled = sc->sc_enabled))
  640                 wi_stop(ifp, 1);
  641         wi_reset(sc);
  642 
  643         /* common 802.11 configuration */
  644         ic->ic_flags &= ~IEEE80211_F_IBSSON;
  645         sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
  646         switch (ic->ic_opmode) {
  647         case IEEE80211_M_STA:
  648                 wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS);
  649                 break;
  650         case IEEE80211_M_IBSS:
  651                 wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port);
  652                 ic->ic_flags |= IEEE80211_F_IBSSON;
  653                 break;
  654         case IEEE80211_M_AHDEMO:
  655                 wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
  656                 break;
  657         case IEEE80211_M_HOSTAP:
  658                 /*
  659                  * For PRISM cards, override the empty SSID, because in
  660                  * HostAP mode the controller will lock up otherwise.
  661                  */
  662                 if (sc->sc_firmware_type == WI_INTERSIL &&
  663                     ic->ic_des_esslen == 0) {
  664                         ic->ic_des_essid[0] = ' ';
  665                         ic->ic_des_esslen = 1;
  666                 }
  667                 wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
  668                 break;
  669         case IEEE80211_M_MONITOR:
  670                 if (sc->sc_firmware_type == WI_LUCENT)
  671                         wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
  672                 wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
  673                 break;
  674         }
  675 
  676         /* Intersil interprets this RID as joining ESS even in IBSS mode */
  677         if (sc->sc_firmware_type == WI_LUCENT &&
  678             (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0)
  679                 wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
  680         else
  681                 wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
  682         wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
  683         wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid,
  684             ic->ic_des_esslen);
  685         wi_write_val(sc, WI_RID_OWN_CHNL,
  686                 ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
  687         wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen);
  688 
  689         ifa = ifaddr_byindex(ifp->if_index);
  690         sdl = (struct sockaddr_dl *) ifa->ifa_addr;
  691         IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(sdl));
  692         wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
  693 
  694         wi_write_val(sc, WI_RID_PM_ENABLED,
  695             (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
  696 
  697         /* not yet common 802.11 configuration */
  698         wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen);
  699         wi_write_val(sc, WI_RID_RTS_THRESH, ic->ic_rtsthreshold);
  700         if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
  701                 wi_write_val(sc, WI_RID_FRAG_THRESH, ic->ic_fragthreshold);
  702 
  703         /* driver specific 802.11 configuration */
  704         if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)
  705                 wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale);
  706         if (sc->sc_flags & WI_FLAGS_HAS_ROAMING)
  707                 wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
  708         if (sc->sc_flags & WI_FLAGS_HAS_MOR)
  709                 wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
  710         wi_write_txrate(sc);
  711         wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
  712 
  713         if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
  714             sc->sc_firmware_type == WI_INTERSIL) {
  715                 wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval);
  716                 wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
  717                 wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
  718                 wi_write_val(sc, WI_RID_DTIM_PERIOD, 1);
  719         }
  720 
  721         /*
  722          * Initialize promisc mode.
  723          *      Being in the Host-AP mode causes a great
  724          *      deal of pain if primisc mode is set.
  725          *      Therefore we avoid confusing the firmware
  726          *      and always reset promisc mode in Host-AP
  727          *      mode.  Host-AP sees all the packets anyway.
  728          */
  729         if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
  730             (ifp->if_flags & IFF_PROMISC) != 0) {
  731                 wi_write_val(sc, WI_RID_PROMISC, 1);
  732         } else {
  733                 wi_write_val(sc, WI_RID_PROMISC, 0);
  734         }
  735 
  736         /* Configure WEP. */
  737         if (ic->ic_caps & IEEE80211_C_WEP)
  738                 wi_write_wep(sc);
  739 
  740         /* Set multicast filter. */
  741         wi_write_multi(sc);
  742 
  743         /* Allocate fids for the card */
  744         if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) {
  745                 sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
  746                 if (sc->sc_firmware_type == WI_SYMBOL)
  747                         sc->sc_buflen = 1585;   /* XXX */
  748                 for (i = 0; i < sc->sc_ntxbuf; i++) {
  749                         error = wi_alloc_fid(sc, sc->sc_buflen,
  750                             &sc->sc_txd[i].d_fid);
  751                         if (error) {
  752                                 device_printf(sc->sc_dev,
  753                                     "tx buffer allocation failed (error %u)\n",
  754                                     error);
  755                                 goto out;
  756                         }
  757                         sc->sc_txd[i].d_len = 0;
  758                 }
  759         }
  760         sc->sc_txcur = sc->sc_txnext = 0;
  761 
  762         /* Enable desired port */
  763         wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
  764 
  765         sc->sc_enabled = 1;
  766         ifp->if_flags |= IFF_RUNNING;
  767         ifp->if_flags &= ~IFF_OACTIVE;
  768         if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
  769             ic->ic_opmode == IEEE80211_M_MONITOR ||
  770             ic->ic_opmode == IEEE80211_M_HOSTAP)
  771                 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
  772 
  773         /* Enable interrupts */
  774         CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
  775 
  776         if (!wasenabled &&
  777             ic->ic_opmode == IEEE80211_M_HOSTAP &&
  778             sc->sc_firmware_type == WI_INTERSIL) {
  779                 /* XXX: some card need to be re-enabled for hostap */
  780                 wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
  781                 wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
  782         }
  783 
  784         if (ic->ic_opmode == IEEE80211_M_STA &&
  785             ((ic->ic_flags & IEEE80211_F_DESBSSID) ||
  786             ic->ic_des_chan != IEEE80211_CHAN_ANYC)) {
  787                 memset(&join, 0, sizeof(join));
  788                 if (ic->ic_flags & IEEE80211_F_DESBSSID)
  789                         IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid);
  790                 if (ic->ic_des_chan != IEEE80211_CHAN_ANYC)
  791                         join.wi_chan = htole16(
  792                                 ieee80211_chan2ieee(ic, ic->ic_des_chan));
  793                 /* Lucent firmware does not support the JOIN RID. */
  794                 if (sc->sc_firmware_type != WI_LUCENT)
  795                         wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
  796         }
  797 
  798         WI_UNLOCK(sc);
  799         return;
  800 out:
  801         if (error) {
  802                 if_printf(ifp, "interface not running\n");
  803                 wi_stop(ifp, 1);
  804         }
  805         WI_UNLOCK(sc);
  806         DPRINTF(("wi_init: return %d\n", error));
  807         return;
  808 }
  809 
  810 void
  811 wi_stop(struct ifnet *ifp, int disable)
  812 {
  813         struct ieee80211com *ic = (struct ieee80211com *) ifp;
  814         struct wi_softc *sc = ifp->if_softc;
  815         WI_LOCK_DECL();
  816 
  817         WI_LOCK(sc);
  818 
  819         DELAY(100000);
  820 
  821         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
  822         if (sc->sc_enabled && !sc->wi_gone) {
  823                 CSR_WRITE_2(sc, WI_INT_EN, 0);
  824                 wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
  825                 if (disable) {
  826 #ifdef __NetBSD__
  827                         if (sc->sc_disable)
  828                                 (*sc->sc_disable)(sc);
  829 #endif
  830                         sc->sc_enabled = 0;
  831                 }
  832         } else if (sc->wi_gone && disable)      /* gone --> not enabled */
  833             sc->sc_enabled = 0;
  834 
  835         sc->sc_tx_timer = 0;
  836         sc->sc_scan_timer = 0;
  837         sc->sc_syn_timer = 0;
  838         sc->sc_false_syns = 0;
  839         sc->sc_naps = 0;
  840         ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
  841         ifp->if_timer = 0;
  842 
  843         WI_UNLOCK(sc);
  844 }
  845 
  846 static void
  847 wi_start(struct ifnet *ifp)
  848 {
  849         struct wi_softc *sc = ifp->if_softc;
  850         struct ieee80211com *ic = &sc->sc_ic;
  851         struct ieee80211_node *ni;
  852         struct ieee80211_frame *wh;
  853         struct mbuf *m0;
  854         struct wi_frame frmhdr;
  855         int cur, fid, off, error;
  856         WI_LOCK_DECL();
  857 
  858         WI_LOCK(sc);
  859 
  860         if (sc->wi_gone) {
  861                 WI_UNLOCK(sc);
  862                 return;
  863         }
  864         if (sc->sc_flags & WI_FLAGS_OUTRANGE) {
  865                 WI_UNLOCK(sc);
  866                 return;
  867         }
  868 
  869         memset(&frmhdr, 0, sizeof(frmhdr));
  870         cur = sc->sc_txnext;
  871         for (;;) {
  872                 IF_POLL(&ic->ic_mgtq, m0);
  873                 if (m0 != NULL) {
  874                         if (sc->sc_txd[cur].d_len != 0) {
  875                                 ifp->if_flags |= IFF_OACTIVE;
  876                                 break;
  877                         }
  878                         IF_DEQUEUE(&ic->ic_mgtq, m0);
  879                         /*
  880                          * Hack!  The referenced node pointer is in the
  881                          * rcvif field of the packet header.  This is
  882                          * placed there by ieee80211_mgmt_output because
  883                          * we need to hold the reference with the frame
  884                          * and there's no other way (other than packet
  885                          * tags which we consider too expensive to use)
  886                          * to pass it along.
  887                          */
  888                         ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif;
  889                         m0->m_pkthdr.rcvif = NULL;
  890 
  891                         m_copydata(m0, 4, ETHER_ADDR_LEN * 2,
  892                             (caddr_t)&frmhdr.wi_ehdr);
  893                         frmhdr.wi_ehdr.ether_type = 0;
  894                         wh = mtod(m0, struct ieee80211_frame *);
  895                 } else {
  896                         if (ic->ic_state != IEEE80211_S_RUN)
  897                                 break;
  898                         IFQ_POLL(&ifp->if_snd, m0);
  899                         if (m0 == NULL)
  900                                 break;
  901                         if (sc->sc_txd[cur].d_len != 0) {
  902                                 ifp->if_flags |= IFF_OACTIVE;
  903                                 break;
  904                         }
  905                         IFQ_DEQUEUE(&ifp->if_snd, m0);
  906                         ifp->if_opackets++;
  907                         m_copydata(m0, 0, ETHER_HDR_LEN, 
  908                             (caddr_t)&frmhdr.wi_ehdr);
  909 #if NBPFILTER > 0
  910                         BPF_MTAP(ifp, m0);
  911 #endif
  912 
  913                         m0 = ieee80211_encap(ifp, m0, &ni);
  914                         if (m0 == NULL) {
  915                                 ifp->if_oerrors++;
  916                                 continue;
  917                         }
  918                         wh = mtod(m0, struct ieee80211_frame *);
  919                         if (ic->ic_flags & IEEE80211_F_WEPON)
  920                                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
  921 
  922                 }
  923 #if NBPFILTER > 0
  924                 if (ic->ic_rawbpf)
  925                         bpf_mtap(ic->ic_rawbpf, m0);
  926 #endif
  927                 frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
  928                 if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
  929                     (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
  930                         if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
  931                                 ifp->if_oerrors++;
  932                                 if (ni && ni != ic->ic_bss)
  933                                         ieee80211_free_node(ic, ni);
  934                                 continue;
  935                         }
  936                         frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
  937                 }
  938                 m_copydata(m0, 0, sizeof(struct ieee80211_frame),
  939                     (caddr_t)&frmhdr.wi_whdr);
  940                 m_adj(m0, sizeof(struct ieee80211_frame));
  941                 frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
  942 #if NBPFILTER > 0
  943                 if (sc->sc_drvbpf) {
  944                         struct mbuf *mb;
  945 
  946                         MGETHDR(mb, M_DONTWAIT, m0->m_type);
  947                         if (mb != NULL) {
  948                                 mb->m_next = m0;
  949                                 mb->m_data = (caddr_t)&sc->sc_tx_th;
  950                                 mb->m_len = sizeof(sc->sc_tx_th);
  951                                 mb->m_pkthdr.len += mb->m_len;
  952                                 bpf_mtap(sc->sc_drvbpf, mb);
  953                                 m_free(mb);
  954                         }
  955                 }
  956 #endif
  957                 if (IFF_DUMPPKTS(ifp))
  958                         wi_dump_pkt(&frmhdr, NULL, -1);
  959                 fid = sc->sc_txd[cur].d_fid;
  960                 off = sizeof(frmhdr);
  961                 error = wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0
  962                      || wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0;
  963                 m_freem(m0);
  964                 if (ni && ni != ic->ic_bss)
  965                         ieee80211_free_node(ic, ni);
  966                 if (error) {
  967                         ifp->if_oerrors++;
  968                         continue;
  969                 }
  970                 sc->sc_txd[cur].d_len = off;
  971                 if (sc->sc_txcur == cur) {
  972                         if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
  973                                 if_printf(ifp, "xmit failed\n");
  974                                 sc->sc_txd[cur].d_len = 0;
  975                                 continue;
  976                         }
  977                         sc->sc_tx_timer = 5;
  978                         ifp->if_timer = 1;
  979                 }
  980                 sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
  981         }
  982 
  983         WI_UNLOCK(sc);
  984 }
  985 
  986 static int
  987 wi_reset(struct wi_softc *sc)
  988 {
  989         struct ieee80211com *ic = &sc->sc_ic;
  990         struct ifnet *ifp = &ic->ic_if;
  991 #define WI_INIT_TRIES 3
  992         int i;
  993         int error = 0;
  994         int tries;
  995         
  996         /* Symbol firmware cannot be initialized more than once */
  997         if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_reset)
  998                 return (0);
  999         if (sc->sc_firmware_type == WI_SYMBOL)
 1000                 tries = 1;
 1001         else
 1002                 tries = WI_INIT_TRIES;
 1003 
 1004         for (i = 0; i < tries; i++) {
 1005                 if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
 1006                         break;
 1007                 DELAY(WI_DELAY * 1000);
 1008         }
 1009         sc->sc_reset = 1;
 1010 
 1011         if (i == tries) {
 1012                 if_printf(ifp, "init failed\n");
 1013                 return (error);
 1014         }
 1015 
 1016         CSR_WRITE_2(sc, WI_INT_EN, 0);
 1017         CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
 1018 
 1019         /* Calibrate timer. */
 1020         wi_write_val(sc, WI_RID_TICK_TIME, 8);
 1021 
 1022         return (0);
 1023 #undef WI_INIT_TRIES
 1024 }
 1025 
 1026 static void
 1027 wi_watchdog(struct ifnet *ifp)
 1028 {
 1029         struct wi_softc *sc = ifp->if_softc;
 1030 
 1031         ifp->if_timer = 0;
 1032         if (!sc->sc_enabled)
 1033                 return;
 1034 
 1035         if (sc->sc_tx_timer) {
 1036                 if (--sc->sc_tx_timer == 0) {
 1037                         if_printf(ifp, "device timeout\n");
 1038                         ifp->if_oerrors++;
 1039                         wi_init(ifp->if_softc);
 1040                         return;
 1041                 }
 1042                 ifp->if_timer = 1;
 1043         }
 1044 
 1045         if (sc->sc_scan_timer) {
 1046                 if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT &&
 1047                     sc->sc_firmware_type == WI_INTERSIL) {
 1048                         DPRINTF(("wi_watchdog: inquire scan\n"));
 1049                         wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
 1050                 }
 1051                 if (sc->sc_scan_timer)
 1052                         ifp->if_timer = 1;
 1053         }
 1054 
 1055         if (sc->sc_syn_timer) {
 1056                 if (--sc->sc_syn_timer == 0) {
 1057                         struct ieee80211com *ic = (struct ieee80211com *) ifp;
 1058                         DPRINTF2(("wi_watchdog: %d false syns\n",
 1059                             sc->sc_false_syns));
 1060                         sc->sc_false_syns = 0;
 1061                         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 1062                         sc->sc_syn_timer = 5;
 1063                 }
 1064                 ifp->if_timer = 1;
 1065         }
 1066 
 1067         /* TODO: rate control */
 1068         ieee80211_watchdog(ifp);
 1069 }
 1070 
 1071 static int
 1072 wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1073 {
 1074         struct wi_softc *sc = ifp->if_softc;
 1075         struct ieee80211com *ic = &sc->sc_ic;
 1076         struct ifreq *ifr = (struct ifreq *)data;
 1077         struct ieee80211req *ireq;
 1078         u_int8_t nodename[IEEE80211_NWID_LEN];
 1079         int error = 0;
 1080 #if __FreeBSD_version >= 500000
 1081         struct thread *td = curthread;
 1082 #else
 1083         struct proc *td = curproc;              /* Little white lie */
 1084 #endif
 1085         struct wi_req wreq;
 1086         WI_LOCK_DECL();
 1087 
 1088         WI_LOCK(sc);
 1089 
 1090         if (sc->wi_gone) {
 1091                 error = ENODEV;
 1092                 goto out;
 1093         }
 1094 
 1095         switch (cmd) {
 1096         case SIOCSIFFLAGS:
 1097                 /*
 1098                  * Can't do promisc and hostap at the same time.  If all that's
 1099                  * changing is the promisc flag, try to short-circuit a call to
 1100                  * wi_init() by just setting PROMISC in the hardware.
 1101                  */
 1102                 if (ifp->if_flags & IFF_UP) {
 1103                         if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
 1104                             ifp->if_flags & IFF_RUNNING) {
 1105                                 if (ifp->if_flags & IFF_PROMISC &&
 1106                                     !(sc->sc_if_flags & IFF_PROMISC)) {
 1107                                         wi_write_val(sc, WI_RID_PROMISC, 1);
 1108                                 } else if (!(ifp->if_flags & IFF_PROMISC) &&
 1109                                     sc->sc_if_flags & IFF_PROMISC) {
 1110                                         wi_write_val(sc, WI_RID_PROMISC, 0);
 1111                                 } else {
 1112                                         wi_init(sc);
 1113                                 }
 1114                         } else {
 1115                                 wi_init(sc);
 1116                         }
 1117                 } else {
 1118                         if (ifp->if_flags & IFF_RUNNING) {
 1119                                 wi_stop(ifp, 1);
 1120                         }
 1121                         sc->wi_gone = 0;
 1122                 }
 1123                 sc->sc_if_flags = ifp->if_flags;
 1124                 error = 0;
 1125                 break;
 1126         case SIOCADDMULTI:
 1127         case SIOCDELMULTI:
 1128                 error = wi_write_multi(sc);
 1129                 break;
 1130         case SIOCGIFGENERIC:
 1131                 error = wi_get_cfg(ifp, cmd, data);
 1132                 break;
 1133         case SIOCSIFGENERIC:
 1134                 error = suser(td);
 1135                 if (error)
 1136                         break;
 1137                 error = wi_set_cfg(ifp, cmd, data);
 1138                 break;
 1139         case SIOCGPRISM2DEBUG:
 1140                 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
 1141                 if (error)
 1142                         break;
 1143                 if (!(ifp->if_flags & IFF_RUNNING) ||
 1144                     sc->sc_firmware_type == WI_LUCENT) {
 1145                         error = EIO;
 1146                         break;
 1147                 }
 1148                 error = wi_get_debug(sc, &wreq);
 1149                 if (error == 0)
 1150                         error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
 1151                 break;
 1152         case SIOCSPRISM2DEBUG:
 1153                 if ((error = suser(td)))
 1154                         goto out;
 1155                 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
 1156                 if (error)
 1157                         break;
 1158                 error = wi_set_debug(sc, &wreq);
 1159                 break;
 1160         case SIOCG80211:
 1161                 ireq = (struct ieee80211req *) data;
 1162                 switch (ireq->i_type) {
 1163                 case IEEE80211_IOC_STATIONNAME:
 1164                         ireq->i_len = sc->sc_nodelen + 1;
 1165                         error = copyout(sc->sc_nodename, ireq->i_data,
 1166                                         ireq->i_len);
 1167                         break;
 1168                 default:
 1169                         error = ieee80211_ioctl(ifp, cmd, data);
 1170                         break;
 1171                 }
 1172                 break;
 1173         case SIOCS80211:
 1174                 error = suser(td);
 1175                 if (error)
 1176                         break;
 1177                 ireq = (struct ieee80211req *) data;
 1178                 switch (ireq->i_type) {
 1179                 case IEEE80211_IOC_STATIONNAME:
 1180                         if (ireq->i_val != 0 ||
 1181                             ireq->i_len > IEEE80211_NWID_LEN) {
 1182                                 error = EINVAL;
 1183                                 break;
 1184                         }
 1185                         memset(nodename, 0, IEEE80211_NWID_LEN);
 1186                         error = copyin(ireq->i_data, nodename, ireq->i_len);
 1187                         if (error)
 1188                                 break;
 1189                         if (sc->sc_enabled) {
 1190                                 error = wi_write_ssid(sc, WI_RID_NODENAME,
 1191                                         nodename, ireq->i_len);
 1192                                 if (error)
 1193                                         break;
 1194                         }
 1195                         memcpy(sc->sc_nodename, nodename, IEEE80211_NWID_LEN);
 1196                         sc->sc_nodelen = ireq->i_len;
 1197                         break;
 1198                 default:
 1199                         error = ieee80211_ioctl(ifp, cmd, data);
 1200                         break;
 1201                 }
 1202                 break;
 1203         default:
 1204                 error = ieee80211_ioctl(ifp, cmd, data);
 1205                 break;
 1206         }
 1207         if (error == ENETRESET) {
 1208                 if (sc->sc_enabled)
 1209                         wi_init(sc);    /* XXX no error return */
 1210                 error = 0;
 1211         }
 1212 out:
 1213         WI_UNLOCK(sc);
 1214 
 1215         return (error);
 1216 }
 1217 
 1218 static int
 1219 wi_media_change(struct ifnet *ifp)
 1220 {
 1221         struct wi_softc *sc = ifp->if_softc;
 1222         int error;
 1223 
 1224         error = ieee80211_media_change(ifp);
 1225         if (error == ENETRESET) {
 1226                 if (sc->sc_enabled)
 1227                         wi_init(sc);    /* XXX no error return */
 1228                 error = 0;
 1229         }
 1230         return error;
 1231 }
 1232 
 1233 static void
 1234 wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
 1235 {
 1236         struct wi_softc *sc = ifp->if_softc;
 1237         struct ieee80211com *ic = &sc->sc_ic;
 1238         u_int16_t val;
 1239         int rate, len;
 1240 
 1241         if (sc->wi_gone || !sc->sc_enabled) {
 1242                 imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
 1243                 imr->ifm_status = 0;
 1244                 return;
 1245         }
 1246 
 1247         imr->ifm_status = IFM_AVALID;
 1248         imr->ifm_active = IFM_IEEE80211;
 1249         if (ic->ic_state == IEEE80211_S_RUN &&
 1250             (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0)
 1251                 imr->ifm_status |= IFM_ACTIVE;
 1252         len = sizeof(val);
 1253         if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0)
 1254                 rate = 0;
 1255         else {
 1256                 /* convert to 802.11 rate */
 1257                 rate = val * 2;
 1258                 if (sc->sc_firmware_type == WI_LUCENT) {
 1259                         if (rate == 4 * 2)
 1260                                 rate = 11;      /* 5.5Mbps */
 1261                         else if (rate == 5 * 2)
 1262                                 rate = 22;      /* 11Mbps */
 1263                 } else {
 1264                         if (rate == 4*2)
 1265                                 rate = 11;      /* 5.5Mbps */
 1266                         else if (rate == 8*2)
 1267                                 rate = 22;      /* 11Mbps */
 1268                 }
 1269         }
 1270         imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
 1271         switch (ic->ic_opmode) {
 1272         case IEEE80211_M_STA:
 1273                 break;
 1274         case IEEE80211_M_IBSS:
 1275                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
 1276                 break;
 1277         case IEEE80211_M_AHDEMO:
 1278                 imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
 1279                 break;
 1280         case IEEE80211_M_HOSTAP:
 1281                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
 1282                 break;
 1283         case IEEE80211_M_MONITOR:
 1284                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
 1285                 break;
 1286         }
 1287 }
 1288 
 1289 static void
 1290 wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
 1291 {
 1292         struct ieee80211com *ic = &sc->sc_ic;
 1293         struct ieee80211_node *ni = ic->ic_bss;
 1294         struct ifnet *ifp = &ic->ic_if;
 1295 
 1296         if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
 1297                 return;
 1298 
 1299         DPRINTF(("wi_sync_bssid: bssid %s -> ", ether_sprintf(ni->ni_bssid)));
 1300         DPRINTF(("%s ?\n", ether_sprintf(new_bssid)));
 1301 
 1302         /* In promiscuous mode, the BSSID field is not a reliable
 1303          * indicator of the firmware's BSSID. Damp spurious
 1304          * change-of-BSSID indications.
 1305          */
 1306         if ((ifp->if_flags & IFF_PROMISC) != 0 &&
 1307             sc->sc_false_syns >= WI_MAX_FALSE_SYNS)
 1308                 return;
 1309 
 1310         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 1311 }
 1312 
 1313 static void
 1314 wi_rx_monitor(struct wi_softc *sc, int fid)
 1315 {
 1316         struct ieee80211com *ic = &sc->sc_ic;
 1317         struct ifnet *ifp = &ic->ic_if;
 1318         struct wi_frame *rx_frame;
 1319         struct mbuf *m;
 1320         int datlen, hdrlen;
 1321 
 1322         /* first allocate mbuf for packet storage */
 1323         m = m_getcl(M_DONTWAIT, MT_DATA, 0);
 1324         if (m == NULL) {
 1325                 ifp->if_ierrors++;
 1326                 return;
 1327         }
 1328 
 1329         m->m_pkthdr.rcvif = ifp;
 1330 
 1331         /* now read wi_frame first so we know how much data to read */
 1332         if (wi_read_bap(sc, fid, 0, mtod(m, caddr_t), sizeof(*rx_frame))) {
 1333                 ifp->if_ierrors++;
 1334                 goto done;
 1335         }
 1336 
 1337         rx_frame = mtod(m, struct wi_frame *);
 1338 
 1339         switch ((rx_frame->wi_status & WI_STAT_MAC_PORT) >> 8) {
 1340         case 7:
 1341                 switch (rx_frame->wi_whdr.i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
 1342                 case IEEE80211_FC0_TYPE_DATA:
 1343                         hdrlen = WI_DATA_HDRLEN;
 1344                         datlen = rx_frame->wi_dat_len + WI_FCS_LEN;
 1345                         break;
 1346                 case IEEE80211_FC0_TYPE_MGT:
 1347                         hdrlen = WI_MGMT_HDRLEN;
 1348                         datlen = rx_frame->wi_dat_len + WI_FCS_LEN;
 1349                         break;
 1350                 case IEEE80211_FC0_TYPE_CTL:
 1351                         /*
 1352                          * prism2 cards don't pass control packets
 1353                          * down properly or consistently, so we'll only
 1354                          * pass down the header.
 1355                          */
 1356                         hdrlen = WI_CTL_HDRLEN;
 1357                         datlen = 0;
 1358                         break;
 1359                 default:
 1360                         if_printf(ifp, "received packet of unknown type "
 1361                                 "on port 7\n");
 1362                         ifp->if_ierrors++;
 1363                         goto done;
 1364                 }
 1365                 break;
 1366         case 0:
 1367                 hdrlen = WI_DATA_HDRLEN;
 1368                 datlen = rx_frame->wi_dat_len + WI_FCS_LEN;
 1369                 break;
 1370         default:
 1371                 if_printf(ifp, "received packet on invalid "
 1372                     "port (wi_status=0x%x)\n", rx_frame->wi_status);
 1373                 ifp->if_ierrors++;
 1374                 goto done;
 1375         }
 1376 
 1377         if (hdrlen + datlen + 2 > MCLBYTES) {
 1378                 if_printf(ifp, "oversized packet received "
 1379                     "(wi_dat_len=%d, wi_status=0x%x)\n",
 1380                     datlen, rx_frame->wi_status);
 1381                 ifp->if_ierrors++;
 1382                 goto done;
 1383         }
 1384 
 1385         if (wi_read_bap(sc, fid, hdrlen, mtod(m, caddr_t) + hdrlen,
 1386             datlen + 2) == 0) {
 1387                 m->m_pkthdr.len = m->m_len = hdrlen + datlen;
 1388                 ifp->if_ipackets++;
 1389                 BPF_MTAP(ifp, m);       /* Handle BPF listeners. */
 1390         } else
 1391                 ifp->if_ierrors++;
 1392 done:
 1393         m_freem(m);
 1394 }
 1395 
 1396 static void
 1397 wi_rx_intr(struct wi_softc *sc)
 1398 {
 1399         struct ieee80211com *ic = &sc->sc_ic;
 1400         struct ifnet *ifp = &ic->ic_if;
 1401         struct wi_frame frmhdr;
 1402         struct mbuf *m;
 1403         struct ieee80211_frame *wh;
 1404         struct ieee80211_node *ni;
 1405         int fid, len, off, rssi;
 1406         u_int8_t dir;
 1407         u_int16_t status;
 1408         u_int32_t rstamp;
 1409 
 1410         fid = CSR_READ_2(sc, WI_RX_FID);
 1411 
 1412         if (sc->wi_debug.wi_monitor) {
 1413                 /*
 1414                  * If we are in monitor mode just
 1415                  * read the data from the device.
 1416                  */
 1417                 wi_rx_monitor(sc, fid);
 1418                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1419                 return;
 1420         }
 1421 
 1422         /* First read in the frame header */
 1423         if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) {
 1424                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1425                 ifp->if_ierrors++;
 1426                 DPRINTF(("wi_rx_intr: read fid %x failed\n", fid));
 1427                 return;
 1428         }
 1429 
 1430         if (IFF_DUMPPKTS(ifp))
 1431                 wi_dump_pkt(&frmhdr, NULL, frmhdr.wi_rx_signal);
 1432 
 1433         /*
 1434          * Drop undecryptable or packets with receive errors here
 1435          */
 1436         status = le16toh(frmhdr.wi_status);
 1437         if (status & WI_STAT_ERRSTAT) {
 1438                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1439                 ifp->if_ierrors++;
 1440                 DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status));
 1441                 return;
 1442         }
 1443         rssi = frmhdr.wi_rx_signal;
 1444         rstamp = (le16toh(frmhdr.wi_rx_tstamp0) << 16) |
 1445             le16toh(frmhdr.wi_rx_tstamp1);
 1446 
 1447         len = le16toh(frmhdr.wi_dat_len);
 1448         off = ALIGN(sizeof(struct ieee80211_frame));
 1449 
 1450         /*
 1451          * Sometimes the PRISM2.x returns bogusly large frames. Except
 1452          * in monitor mode, just throw them away.
 1453          */
 1454         if (off + len > MCLBYTES) {
 1455                 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
 1456                         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1457                         ifp->if_ierrors++;
 1458                         DPRINTF(("wi_rx_intr: oversized packet\n"));
 1459                         return;
 1460                 } else
 1461                         len = 0;
 1462         }
 1463 
 1464         MGETHDR(m, M_DONTWAIT, MT_DATA);
 1465         if (m == NULL) {
 1466                 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1467                 ifp->if_ierrors++;
 1468                 DPRINTF(("wi_rx_intr: MGET failed\n"));
 1469                 return;
 1470         }
 1471         if (off + len > MHLEN) {
 1472                 MCLGET(m, M_DONTWAIT);
 1473                 if ((m->m_flags & M_EXT) == 0) {
 1474                         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1475                         m_freem(m);
 1476                         ifp->if_ierrors++;
 1477                         DPRINTF(("wi_rx_intr: MCLGET failed\n"));
 1478                         return;
 1479                 }
 1480         }
 1481 
 1482         m->m_data += off - sizeof(struct ieee80211_frame);
 1483         memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame));
 1484         wi_read_bap(sc, fid, sizeof(frmhdr),
 1485             m->m_data + sizeof(struct ieee80211_frame), len);
 1486         m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
 1487         m->m_pkthdr.rcvif = ifp;
 1488 
 1489         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 1490 
 1491 #if NBPFILTER > 0
 1492         if (sc->sc_drvbpf) {
 1493                 struct mbuf *mb;
 1494 
 1495                 /* XXX pre-allocate space when setting up recv's */
 1496                 MGETHDR(mb, M_DONTWAIT, m->m_type);
 1497                 if (mb != NULL) {
 1498                         /* XXX replace divide by table */
 1499                         sc->sc_rx_th.wr_rate = frmhdr.wi_rx_rate / 5;
 1500                         sc->sc_rx_th.wr_antsignal =
 1501                                 WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_signal);
 1502                         sc->sc_rx_th.wr_antnoise =
 1503                                 WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_silence);
 1504                         sc->sc_rx_th.wr_time =
 1505                                 htole32((frmhdr.wi_rx_tstamp1 << 16) |
 1506                                         frmhdr.wi_rx_tstamp0);
 1507 
 1508                         (void) m_dup_pkthdr(mb, m, M_DONTWAIT);
 1509                         mb->m_next = m;
 1510                         mb->m_data = (caddr_t)&sc->sc_rx_th;
 1511                         mb->m_len = sizeof(sc->sc_rx_th);
 1512                         mb->m_pkthdr.len += mb->m_len;
 1513                         bpf_mtap(sc->sc_drvbpf, mb);
 1514                         m_free(mb);
 1515                 }
 1516         }
 1517 #endif
 1518         wh = mtod(m, struct ieee80211_frame *);
 1519         if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
 1520                 /*
 1521                  * WEP is decrypted by hardware. Clear WEP bit
 1522                  * header for ieee80211_input().
 1523                  */
 1524                 wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
 1525         }
 1526 
 1527         /* synchronize driver's BSSID with firmware's BSSID */
 1528         dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
 1529         if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS)
 1530                 wi_sync_bssid(sc, wh->i_addr3);
 1531 
 1532         /*
 1533          * Locate the node for sender, track state, and
 1534          * then pass this node (referenced) up to the 802.11
 1535          * layer for its use.  We are required to pass
 1536          * something so we fallback to ic_bss when this frame
 1537          * is from an unknown sender.
 1538          */
 1539         if (ic->ic_opmode != IEEE80211_M_STA) {
 1540                 ni = ieee80211_find_node(ic, wh->i_addr2);
 1541                 if (ni == NULL)
 1542                         ni = ieee80211_ref_node(ic->ic_bss);
 1543         } else
 1544                 ni = ieee80211_ref_node(ic->ic_bss);
 1545         /*
 1546          * Send frame up for processing.
 1547          */
 1548         ieee80211_input(ifp, m, ni, rssi, rstamp);
 1549         /*
 1550          * The frame may have caused the node to be marked for
 1551          * reclamation (e.g. in response to a DEAUTH message)
 1552          * so use free_node here instead of unref_node.
 1553          */
 1554         if (ni == ic->ic_bss)
 1555                 ieee80211_unref_node(&ni);
 1556         else
 1557                 ieee80211_free_node(ic, ni);
 1558 }
 1559 
 1560 static void
 1561 wi_tx_ex_intr(struct wi_softc *sc)
 1562 {
 1563         struct ieee80211com *ic = &sc->sc_ic;
 1564         struct ifnet *ifp = &ic->ic_if;
 1565         struct wi_frame frmhdr;
 1566         int fid;
 1567 
 1568         fid = CSR_READ_2(sc, WI_TX_CMP_FID);
 1569         /* Read in the frame header */
 1570         if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) == 0) {
 1571                 u_int16_t status = le16toh(frmhdr.wi_status);
 1572 
 1573                 /*
 1574                  * Spontaneous station disconnects appear as xmit
 1575                  * errors.  Don't announce them and/or count them
 1576                  * as an output error.
 1577                  */
 1578                 if ((status & WI_TXSTAT_DISCONNECT) == 0) {
 1579                         if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) {
 1580                                 if_printf(ifp, "tx failed");
 1581                                 if (status & WI_TXSTAT_RET_ERR)
 1582                                         printf(", retry limit exceeded");
 1583                                 if (status & WI_TXSTAT_AGED_ERR)
 1584                                         printf(", max transmit lifetime exceeded");
 1585                                 if (status & WI_TXSTAT_DISCONNECT)
 1586                                         printf(", port disconnected");
 1587                                 if (status & WI_TXSTAT_FORM_ERR)
 1588                                         printf(", invalid format (data len %u src %6D)",
 1589                                                 le16toh(frmhdr.wi_dat_len),
 1590                                                 frmhdr.wi_ehdr.ether_shost, ":");
 1591                                 if (status & ~0xf)
 1592                                         printf(", status=0x%x", status);
 1593                                 printf("\n");
 1594                         }
 1595                         ifp->if_oerrors++;
 1596                 } else {
 1597                         DPRINTF(("port disconnected\n"));
 1598                         ifp->if_collisions++;   /* XXX */
 1599                 }
 1600         } else
 1601                 DPRINTF(("wi_tx_ex_intr: read fid %x failed\n", fid));
 1602         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
 1603 }
 1604 
 1605 static void
 1606 wi_tx_intr(struct wi_softc *sc)
 1607 {
 1608         struct ieee80211com *ic = &sc->sc_ic;
 1609         struct ifnet *ifp = &ic->ic_if;
 1610         int fid, cur;
 1611 
 1612         if (sc->wi_gone)
 1613                 return;
 1614 
 1615         fid = CSR_READ_2(sc, WI_ALLOC_FID);
 1616         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 1617 
 1618         cur = sc->sc_txcur;
 1619         if (sc->sc_txd[cur].d_fid != fid) {
 1620                 if_printf(ifp, "bad alloc %x != %x, cur %d nxt %d\n",
 1621                     fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext);
 1622                 return;
 1623         }
 1624         sc->sc_tx_timer = 0;
 1625         sc->sc_txd[cur].d_len = 0;
 1626         sc->sc_txcur = cur = (cur + 1) % sc->sc_ntxbuf;
 1627         if (sc->sc_txd[cur].d_len == 0)
 1628                 ifp->if_flags &= ~IFF_OACTIVE;
 1629         else {
 1630                 if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid,
 1631                     0, 0)) {
 1632                         if_printf(ifp, "xmit failed\n");
 1633                         sc->sc_txd[cur].d_len = 0;
 1634                 } else {
 1635                         sc->sc_tx_timer = 5;
 1636                         ifp->if_timer = 1;
 1637                 }
 1638         }
 1639 }
 1640 
 1641 static void
 1642 wi_info_intr(struct wi_softc *sc)
 1643 {
 1644         struct ieee80211com *ic = &sc->sc_ic;
 1645         struct ifnet *ifp = &ic->ic_if;
 1646         int i, fid, len, off;
 1647         u_int16_t ltbuf[2];
 1648         u_int16_t stat;
 1649         u_int32_t *ptr;
 1650 
 1651         fid = CSR_READ_2(sc, WI_INFO_FID);
 1652         wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf));
 1653 
 1654         switch (le16toh(ltbuf[1])) {
 1655 
 1656         case WI_INFO_LINK_STAT:
 1657                 wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat));
 1658                 DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat)));
 1659                 switch (le16toh(stat)) {
 1660                 case WI_INFO_LINK_STAT_CONNECTED:
 1661                         sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
 1662                         if (ic->ic_state == IEEE80211_S_RUN &&
 1663                             ic->ic_opmode != IEEE80211_M_IBSS)
 1664                                 break;
 1665                         /* FALLTHROUGH */
 1666                 case WI_INFO_LINK_STAT_AP_CHG:
 1667                         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 1668                         break;
 1669                 case WI_INFO_LINK_STAT_AP_INR:
 1670                         sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
 1671                         break;
 1672                 case WI_INFO_LINK_STAT_AP_OOR:
 1673                         if (sc->sc_firmware_type == WI_SYMBOL &&
 1674                             sc->sc_scan_timer > 0) {
 1675                                 if (wi_cmd(sc, WI_CMD_INQUIRE,
 1676                                     WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0)
 1677                                         sc->sc_scan_timer = 0;
 1678                                 break;
 1679                         }
 1680                         if (ic->ic_opmode == IEEE80211_M_STA)
 1681                                 sc->sc_flags |= WI_FLAGS_OUTRANGE;
 1682                         break;
 1683                 case WI_INFO_LINK_STAT_DISCONNECTED:
 1684                 case WI_INFO_LINK_STAT_ASSOC_FAILED:
 1685                         if (ic->ic_opmode == IEEE80211_M_STA)
 1686                                 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 1687                         break;
 1688                 }
 1689                 break;
 1690 
 1691         case WI_INFO_COUNTERS:
 1692                 /* some card versions have a larger stats structure */
 1693                 len = min(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4);
 1694                 ptr = (u_int32_t *)&sc->sc_stats;
 1695                 off = sizeof(ltbuf);
 1696                 for (i = 0; i < len; i++, off += 2, ptr++) {
 1697                         wi_read_bap(sc, fid, off, &stat, sizeof(stat));
 1698 #ifdef WI_HERMES_STATS_WAR
 1699                         if (stat & 0xf000)
 1700                                 stat = ~stat;
 1701 #endif
 1702                         *ptr += stat;
 1703                 }
 1704                 ifp->if_collisions = sc->sc_stats.wi_tx_single_retries +
 1705                     sc->sc_stats.wi_tx_multi_retries +
 1706                     sc->sc_stats.wi_tx_retry_limit;
 1707                 break;
 1708 
 1709         case WI_INFO_SCAN_RESULTS:
 1710         case WI_INFO_HOST_SCAN_RESULTS:
 1711                 wi_scan_result(sc, fid, le16toh(ltbuf[0]));
 1712                 break;
 1713 
 1714         default:
 1715                 DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid,
 1716                     le16toh(ltbuf[1]), le16toh(ltbuf[0])));
 1717                 break;
 1718         }
 1719         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
 1720 }
 1721 
 1722 static int
 1723 wi_write_multi(struct wi_softc *sc)
 1724 {
 1725         struct ifnet *ifp = &sc->sc_ic.ic_if;
 1726         int n;
 1727         struct ifmultiaddr *ifma;
 1728         struct wi_mcast mlist;
 1729 
 1730         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
 1731 allmulti:
 1732                 memset(&mlist, 0, sizeof(mlist));
 1733                 return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
 1734                     sizeof(mlist));
 1735         }
 1736 
 1737         n = 0;
 1738 #if __FreeBSD_version < 500000
 1739         LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 1740 #else
 1741         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 1742 #endif
 1743                 if (ifma->ifma_addr->sa_family != AF_LINK)
 1744                         continue;
 1745                 if (n >= 16)
 1746                         goto allmulti;
 1747                 IEEE80211_ADDR_COPY(&mlist.wi_mcast[n],
 1748                     (LLADDR((struct sockaddr_dl *)ifma->ifma_addr)));
 1749                 n++;
 1750         }
 1751         return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
 1752             IEEE80211_ADDR_LEN * n);
 1753 }
 1754 
 1755 static void
 1756 wi_read_nicid(struct wi_softc *sc)
 1757 {
 1758         struct wi_card_ident *id;
 1759         char *p;
 1760         int len;
 1761         u_int16_t ver[4];
 1762 
 1763         /* getting chip identity */
 1764         memset(ver, 0, sizeof(ver));
 1765         len = sizeof(ver);
 1766         wi_read_rid(sc, WI_RID_CARD_ID, ver, &len);
 1767         device_printf(sc->sc_dev, "using ");
 1768 
 1769         sc->sc_firmware_type = WI_NOTYPE;
 1770         for (id = wi_card_ident; id->card_name != NULL; id++) {
 1771                 if (le16toh(ver[0]) == id->card_id) {
 1772                         printf("%s", id->card_name);
 1773                         sc->sc_firmware_type = id->firm_type;
 1774                         break;
 1775                 }
 1776         }
 1777         if (sc->sc_firmware_type == WI_NOTYPE) {
 1778                 if (le16toh(ver[0]) & 0x8000) {
 1779                         printf("Unknown PRISM2 chip");
 1780                         sc->sc_firmware_type = WI_INTERSIL;
 1781                 } else {
 1782                         printf("Unknown Lucent chip");
 1783                         sc->sc_firmware_type = WI_LUCENT;
 1784                 }
 1785         }
 1786 
 1787         /* get primary firmware version (Only Prism chips) */
 1788         if (sc->sc_firmware_type != WI_LUCENT) {
 1789                 memset(ver, 0, sizeof(ver));
 1790                 len = sizeof(ver);
 1791                 wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len);
 1792                 sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 +
 1793                     le16toh(ver[3]) * 100 + le16toh(ver[1]);
 1794         }
 1795 
 1796         /* get station firmware version */
 1797         memset(ver, 0, sizeof(ver));
 1798         len = sizeof(ver);
 1799         wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len);
 1800         sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 +
 1801             le16toh(ver[3]) * 100 + le16toh(ver[1]);
 1802         if (sc->sc_firmware_type == WI_INTERSIL &&
 1803             (sc->sc_sta_firmware_ver == 10102 ||
 1804              sc->sc_sta_firmware_ver == 20102)) {
 1805                 char ident[12];
 1806                 memset(ident, 0, sizeof(ident));
 1807                 len = sizeof(ident);
 1808                 /* value should be the format like "V2.00-11" */
 1809                 if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 &&
 1810                     *(p = (char *)ident) >= 'A' &&
 1811                     p[2] == '.' && p[5] == '-' && p[8] == '\0') {
 1812                         sc->sc_firmware_type = WI_SYMBOL;
 1813                         sc->sc_sta_firmware_ver = (p[1] - '') * 10000 +
 1814                             (p[3] - '') * 1000 + (p[4] - '') * 100 +
 1815                             (p[6] - '') * 10 + (p[7] - '');
 1816                 }
 1817         }
 1818         printf("\n");
 1819         device_printf(sc->sc_dev, "%s Firmware: ",
 1820              sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
 1821             (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
 1822         if (sc->sc_firmware_type != WI_LUCENT)  /* XXX */
 1823                 printf("Primary (%u.%u.%u), ",
 1824                     sc->sc_pri_firmware_ver / 10000,
 1825                     (sc->sc_pri_firmware_ver % 10000) / 100,
 1826                     sc->sc_pri_firmware_ver % 100);
 1827         printf("Station (%u.%u.%u)\n",
 1828             sc->sc_sta_firmware_ver / 10000,
 1829             (sc->sc_sta_firmware_ver % 10000) / 100,
 1830             sc->sc_sta_firmware_ver % 100);
 1831 }
 1832 
 1833 static int
 1834 wi_write_ssid(struct wi_softc *sc, int rid, u_int8_t *buf, int buflen)
 1835 {
 1836         struct wi_ssid ssid;
 1837 
 1838         if (buflen > IEEE80211_NWID_LEN)
 1839                 return ENOBUFS;
 1840         memset(&ssid, 0, sizeof(ssid));
 1841         ssid.wi_len = htole16(buflen);
 1842         memcpy(ssid.wi_ssid, buf, buflen);
 1843         return wi_write_rid(sc, rid, &ssid, sizeof(ssid));
 1844 }
 1845 
 1846 static int
 1847 wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
 1848 {
 1849         struct wi_softc *sc = ifp->if_softc;
 1850         struct ieee80211com *ic = &sc->sc_ic;
 1851         struct ifreq *ifr = (struct ifreq *)data;
 1852         struct wi_req wreq;
 1853         struct wi_scan_res *res;
 1854         size_t reslen;
 1855         int len, n, error, mif, val, off, i;
 1856 
 1857         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
 1858         if (error)
 1859                 return error;
 1860         len = (wreq.wi_len - 1) * 2;
 1861         if (len < sizeof(u_int16_t))
 1862                 return ENOSPC;
 1863         if (len > sizeof(wreq.wi_val))
 1864                 len = sizeof(wreq.wi_val);
 1865 
 1866         switch (wreq.wi_type) {
 1867 
 1868         case WI_RID_IFACE_STATS:
 1869                 memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats));
 1870                 if (len < sizeof(sc->sc_stats))
 1871                         error = ENOSPC;
 1872                 else
 1873                         len = sizeof(sc->sc_stats);
 1874                 break;
 1875 
 1876         case WI_RID_ENCRYPTION:
 1877         case WI_RID_TX_CRYPT_KEY:
 1878         case WI_RID_DEFLT_CRYPT_KEYS:
 1879         case WI_RID_TX_RATE:
 1880                 return ieee80211_cfgget(ifp, cmd, data);
 1881 
 1882         case WI_RID_MICROWAVE_OVEN:
 1883                 if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
 1884                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 1885                             &len);
 1886                         break;
 1887                 }
 1888                 wreq.wi_val[0] = htole16(sc->sc_microwave_oven);
 1889                 len = sizeof(u_int16_t);
 1890                 break;
 1891 
 1892         case WI_RID_DBM_ADJUST:
 1893                 if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_DBMADJUST)) {
 1894                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 1895                             &len);
 1896                         break;
 1897                 }
 1898                 wreq.wi_val[0] = htole16(sc->sc_dbm_offset);
 1899                 len = sizeof(u_int16_t);
 1900                 break;
 1901 
 1902         case WI_RID_ROAMING_MODE:
 1903                 if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) {
 1904                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 1905                             &len);
 1906                         break;
 1907                 }
 1908                 wreq.wi_val[0] = htole16(sc->sc_roaming_mode);
 1909                 len = sizeof(u_int16_t);
 1910                 break;
 1911 
 1912         case WI_RID_SYSTEM_SCALE:
 1913                 if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) {
 1914                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 1915                             &len);
 1916                         break;
 1917                 }
 1918                 wreq.wi_val[0] = htole16(sc->sc_system_scale);
 1919                 len = sizeof(u_int16_t);
 1920                 break;
 1921 
 1922         case WI_RID_FRAG_THRESH:
 1923                 if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)) {
 1924                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 1925                             &len);
 1926                         break;
 1927                 }
 1928                 wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
 1929                 len = sizeof(u_int16_t);
 1930                 break;
 1931 
 1932         case WI_RID_READ_APS:
 1933                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
 1934                         return ieee80211_cfgget(ifp, cmd, data);
 1935                 if (sc->sc_scan_timer > 0) {
 1936                         error = EINPROGRESS;
 1937                         break;
 1938                 }
 1939                 n = sc->sc_naps;
 1940                 if (len < sizeof(n)) {
 1941                         error = ENOSPC;
 1942                         break;
 1943                 }
 1944                 if (len < sizeof(n) + sizeof(struct wi_apinfo) * n)
 1945                         n = (len - sizeof(n)) / sizeof(struct wi_apinfo);
 1946                 len = sizeof(n) + sizeof(struct wi_apinfo) * n;
 1947                 memcpy(wreq.wi_val, &n, sizeof(n));
 1948                 memcpy((caddr_t)wreq.wi_val + sizeof(n), sc->sc_aps,
 1949                     sizeof(struct wi_apinfo) * n);
 1950                 break;
 1951 
 1952         case WI_RID_PRISM2:
 1953                 wreq.wi_val[0] = sc->sc_firmware_type != WI_LUCENT;
 1954                 len = sizeof(u_int16_t);
 1955                 break;
 1956 
 1957         case WI_RID_MIF:
 1958                 mif = wreq.wi_val[0];
 1959                 error = wi_cmd(sc, WI_CMD_READMIF, mif, 0, 0);
 1960                 val = CSR_READ_2(sc, WI_RESP0);
 1961                 wreq.wi_val[0] = val;
 1962                 len = sizeof(u_int16_t);
 1963                 break;
 1964 
 1965         case WI_RID_ZERO_CACHE:
 1966         case WI_RID_PROCFRAME:          /* ignore for compatibility */
 1967                 /* XXX ??? */
 1968                 break;
 1969 
 1970         case WI_RID_READ_CACHE:
 1971                 return ieee80211_cfgget(ifp, cmd, data);
 1972 
 1973         case WI_RID_SCAN_RES:           /* compatibility interface */
 1974                 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
 1975                         return ieee80211_cfgget(ifp, cmd, data);
 1976                 if (sc->sc_scan_timer > 0) {
 1977                         error = EINPROGRESS;
 1978                         break;
 1979                 }
 1980                 n = sc->sc_naps;
 1981                 if (sc->sc_firmware_type == WI_LUCENT) {
 1982                         off = 0;
 1983                         reslen = WI_WAVELAN_RES_SIZE;
 1984                 } else {
 1985                         off = sizeof(struct wi_scan_p2_hdr);
 1986                         reslen = WI_PRISM2_RES_SIZE;
 1987                 }
 1988                 if (len < off + reslen * n)
 1989                         n = (len - off) / reslen;
 1990                 len = off + reslen * n;
 1991                 if (off != 0) {
 1992                         struct wi_scan_p2_hdr *p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
 1993                         /*
 1994                          * Prepend Prism-specific header.
 1995                          */
 1996                         if (len < sizeof(struct wi_scan_p2_hdr)) {
 1997                                 error = ENOSPC;
 1998                                 break;
 1999                         }
 2000                         p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
 2001                         p2->wi_rsvd = 0;
 2002                         p2->wi_reason = n;      /* XXX */
 2003                 }
 2004                 for (i = 0; i < n; i++, off += reslen) {
 2005                         const struct wi_apinfo *ap = &sc->sc_aps[i];
 2006 
 2007                         res = (struct wi_scan_res *)((char *)wreq.wi_val + off);
 2008                         res->wi_chan = ap->channel;
 2009                         res->wi_noise = ap->noise;
 2010                         res->wi_signal = ap->signal;
 2011                         IEEE80211_ADDR_COPY(res->wi_bssid, ap->bssid);
 2012                         res->wi_interval = ap->interval;
 2013                         res->wi_capinfo = ap->capinfo;
 2014                         res->wi_ssid_len = ap->namelen;
 2015                         memcpy(res->wi_ssid, ap->name,
 2016                                 IEEE80211_NWID_LEN);
 2017                         if (sc->sc_firmware_type != WI_LUCENT) {
 2018                                 /* XXX not saved from Prism cards */
 2019                                 memset(res->wi_srates, 0,
 2020                                         sizeof(res->wi_srates));
 2021                                 res->wi_rate = ap->rate;
 2022                                 res->wi_rsvd = 0;
 2023                         }
 2024                 }
 2025                 break;
 2026 
 2027         default:
 2028                 if (sc->sc_enabled) {
 2029                         error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
 2030                             &len);
 2031                         break;
 2032                 }
 2033                 switch (wreq.wi_type) {
 2034                 case WI_RID_MAX_DATALEN:
 2035                         wreq.wi_val[0] = htole16(sc->sc_max_datalen);
 2036                         len = sizeof(u_int16_t);
 2037                         break;
 2038                 case WI_RID_RTS_THRESH:
 2039                         wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
 2040                         len = sizeof(u_int16_t);
 2041                         break;
 2042                 case WI_RID_CNFAUTHMODE:
 2043                         wreq.wi_val[0] = htole16(sc->sc_cnfauthmode);
 2044                         len = sizeof(u_int16_t);
 2045                         break;
 2046                 case WI_RID_NODENAME:
 2047                         if (len < sc->sc_nodelen + sizeof(u_int16_t)) {
 2048                                 error = ENOSPC;
 2049                                 break;
 2050                         }
 2051                         len = sc->sc_nodelen + sizeof(u_int16_t);
 2052                         wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2);
 2053                         memcpy(&wreq.wi_val[1], sc->sc_nodename,
 2054                             sc->sc_nodelen);
 2055                         break;
 2056                 default:
 2057                         return ieee80211_cfgget(ifp, cmd, data);
 2058                 }
 2059                 break;
 2060         }
 2061         if (error)
 2062                 return error;
 2063         wreq.wi_len = (len + 1) / 2 + 1;
 2064         return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2);
 2065 }
 2066 
 2067 static int
 2068 wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
 2069 {
 2070         struct wi_softc *sc = ifp->if_softc;
 2071         struct ieee80211com *ic = &sc->sc_ic;
 2072         struct ifreq *ifr = (struct ifreq *)data;
 2073         struct wi_req wreq;
 2074         struct mbuf *m;
 2075         int i, len, error, mif, val;
 2076         struct ieee80211_rateset *rs;
 2077 
 2078         error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
 2079         if (error)
 2080                 return error;
 2081         len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
 2082         switch (wreq.wi_type) {
 2083         case WI_RID_DBM_ADJUST:
 2084                 return ENODEV;
 2085 
 2086         case WI_RID_NODENAME:
 2087                 if (le16toh(wreq.wi_val[0]) * 2 > len ||
 2088                     le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) {
 2089                         error = ENOSPC;
 2090                         break;
 2091                 }
 2092                 if (sc->sc_enabled) {
 2093                         error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
 2094                             len);
 2095                         if (error)
 2096                                 break;
 2097                 }
 2098                 sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2;
 2099                 memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen);
 2100                 break;
 2101 
 2102         case WI_RID_MICROWAVE_OVEN:
 2103         case WI_RID_ROAMING_MODE:
 2104         case WI_RID_SYSTEM_SCALE:
 2105         case WI_RID_FRAG_THRESH:
 2106                 if (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
 2107                     (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0)
 2108                         break;
 2109                 if (wreq.wi_type == WI_RID_ROAMING_MODE &&
 2110                     (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0)
 2111                         break;
 2112                 if (wreq.wi_type == WI_RID_SYSTEM_SCALE &&
 2113                     (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0)
 2114                         break;
 2115                 if (wreq.wi_type == WI_RID_FRAG_THRESH &&
 2116                     (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) == 0)
 2117                         break;
 2118                 /* FALLTHROUGH */
 2119         case WI_RID_RTS_THRESH:
 2120         case WI_RID_CNFAUTHMODE:
 2121         case WI_RID_MAX_DATALEN:
 2122                 if (sc->sc_enabled) {
 2123                         error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
 2124                             sizeof(u_int16_t));
 2125                         if (error)
 2126                                 break;
 2127                 }
 2128                 switch (wreq.wi_type) {
 2129                 case WI_RID_FRAG_THRESH:
 2130                         ic->ic_fragthreshold = le16toh(wreq.wi_val[0]);
 2131                         break;
 2132                 case WI_RID_RTS_THRESH:
 2133                         ic->ic_rtsthreshold = le16toh(wreq.wi_val[0]);
 2134                         break;
 2135                 case WI_RID_MICROWAVE_OVEN:
 2136                         sc->sc_microwave_oven = le16toh(wreq.wi_val[0]);
 2137                         break;
 2138                 case WI_RID_ROAMING_MODE:
 2139                         sc->sc_roaming_mode = le16toh(wreq.wi_val[0]);
 2140                         break;
 2141                 case WI_RID_SYSTEM_SCALE:
 2142                         sc->sc_system_scale = le16toh(wreq.wi_val[0]);
 2143                         break;
 2144                 case WI_RID_CNFAUTHMODE:
 2145                         sc->sc_cnfauthmode = le16toh(wreq.wi_val[0]);
 2146                         break;
 2147                 case WI_RID_MAX_DATALEN:
 2148                         sc->sc_max_datalen = le16toh(wreq.wi_val[0]);
 2149                         break;
 2150                 }
 2151                 break;
 2152 
 2153         case WI_RID_TX_RATE:
 2154                 switch (le16toh(wreq.wi_val[0])) {
 2155                 case 3:
 2156                         ic->ic_fixed_rate = -1;
 2157                         break;
 2158                 default:
 2159                         rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
 2160                         for (i = 0; i < rs->rs_nrates; i++) {
 2161                                 if ((rs->rs_rates[i] & IEEE80211_RATE_VAL)
 2162                                     / 2 == le16toh(wreq.wi_val[0]))
 2163                                         break;
 2164                         }
 2165                         if (i == rs->rs_nrates)
 2166                                 return EINVAL;
 2167                         ic->ic_fixed_rate = i;
 2168                 }
 2169                 if (sc->sc_enabled)
 2170                         error = wi_write_txrate(sc);
 2171                 break;
 2172 
 2173         case WI_RID_SCAN_APS:
 2174                 if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
 2175                         error = wi_scan_ap(sc, 0x3fff, 0x000f);
 2176                 break;
 2177 
 2178         case WI_RID_SCAN_REQ:           /* compatibility interface */
 2179                 if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
 2180                         error = wi_scan_ap(sc, wreq.wi_val[0], wreq.wi_val[1]);
 2181                 break;
 2182 
 2183         case WI_RID_MGMT_XMIT:
 2184                 if (!sc->sc_enabled) {
 2185                         error = ENETDOWN;
 2186                         break;
 2187                 }
 2188                 if (ic->ic_mgtq.ifq_len > 5) {
 2189                         error = EAGAIN;
 2190                         break;
 2191                 }
 2192                 /* XXX wi_len looks in u_int8_t, not in u_int16_t */
 2193                 m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL);
 2194                 if (m == NULL) {
 2195                         error = ENOMEM;
 2196                         break;
 2197                 }
 2198                 IF_ENQUEUE(&ic->ic_mgtq, m);
 2199                 break;
 2200 
 2201         case WI_RID_MIF:
 2202                 mif = wreq.wi_val[0];
 2203                 val = wreq.wi_val[1];
 2204                 error = wi_cmd(sc, WI_CMD_WRITEMIF, mif, val, 0);
 2205                 break;
 2206 
 2207         case WI_RID_PROCFRAME:          /* ignore for compatibility */
 2208                 break;
 2209 
 2210         case WI_RID_OWN_SSID:
 2211                 if (le16toh(wreq.wi_val[0]) * 2 > len ||
 2212                     le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
 2213                         error = ENOSPC;
 2214                         break;
 2215                 }
 2216                 memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
 2217                 ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
 2218                 memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
 2219                 error = ENETRESET;
 2220                 break;
 2221 
 2222         default:
 2223                 if (sc->sc_enabled) {
 2224                         error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
 2225                             len);
 2226                         if (error)
 2227                                 break;
 2228                 }
 2229                 error = ieee80211_cfgset(ifp, cmd, data);
 2230                 break;
 2231         }
 2232         return error;
 2233 }
 2234 
 2235 static int
 2236 wi_write_txrate(struct wi_softc *sc)
 2237 {
 2238         struct ieee80211com *ic = &sc->sc_ic;
 2239         int i;
 2240         u_int16_t rate;
 2241 
 2242         if (ic->ic_fixed_rate < 0)
 2243                 rate = 0;       /* auto */
 2244         else
 2245                 rate = (ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ic->ic_fixed_rate] &
 2246                     IEEE80211_RATE_VAL) / 2;
 2247 
 2248         /* rate: 0, 1, 2, 5, 11 */
 2249 
 2250         switch (sc->sc_firmware_type) {
 2251         case WI_LUCENT:
 2252                 switch (rate) {
 2253                 case 0:                 /* auto == 11mbps auto */
 2254                         rate = 3;
 2255                         break;
 2256                 /* case 1, 2 map to 1, 2*/
 2257                 case 5:                 /* 5.5Mbps -> 4 */
 2258                         rate = 4;
 2259                         break;
 2260                 case 11:                /* 11mbps -> 5 */
 2261                         rate = 5;
 2262                         break;
 2263                 default:
 2264                         break;
 2265                 }
 2266                 break;
 2267         default:
 2268                 /* Choose a bit according to this table.
 2269                  *
 2270                  * bit | data rate
 2271                  * ----+-------------------
 2272                  * 0   | 1Mbps
 2273                  * 1   | 2Mbps
 2274                  * 2   | 5.5Mbps
 2275                  * 3   | 11Mbps
 2276                  */
 2277                 for (i = 8; i > 0; i >>= 1) {
 2278                         if (rate >= i)
 2279                                 break;
 2280                 }
 2281                 if (i == 0)
 2282                         rate = 0xf;     /* auto */
 2283                 else
 2284                         rate = i;
 2285                 break;
 2286         }
 2287         return wi_write_val(sc, WI_RID_TX_RATE, rate);
 2288 }
 2289 
 2290 static int
 2291 wi_write_wep(struct wi_softc *sc)
 2292 {
 2293         struct ieee80211com *ic = &sc->sc_ic;
 2294         int error = 0;
 2295         int i, keylen;
 2296         u_int16_t val;
 2297         struct wi_key wkey[IEEE80211_WEP_NKID];
 2298 
 2299         switch (sc->sc_firmware_type) {
 2300         case WI_LUCENT:
 2301                 val = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0;
 2302                 error = wi_write_val(sc, WI_RID_ENCRYPTION, val);
 2303                 if (error)
 2304                         break;
 2305                 error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_wep_txkey);
 2306                 if (error)
 2307                         break;
 2308                 memset(wkey, 0, sizeof(wkey));
 2309                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 2310                         keylen = ic->ic_nw_keys[i].wk_len;
 2311                         wkey[i].wi_keylen = htole16(keylen);
 2312                         memcpy(wkey[i].wi_keydat, ic->ic_nw_keys[i].wk_key,
 2313                             keylen);
 2314                 }
 2315                 error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS,
 2316                     wkey, sizeof(wkey));
 2317                 break;
 2318 
 2319         case WI_INTERSIL:
 2320         case WI_SYMBOL:
 2321                 if (ic->ic_flags & IEEE80211_F_WEPON) {
 2322                         /*
 2323                          * ONLY HWB3163 EVAL-CARD Firmware version
 2324                          * less than 0.8 variant2
 2325                          *
 2326                          *   If promiscuous mode disable, Prism2 chip
 2327                          *  does not work with WEP .
 2328                          * It is under investigation for details.
 2329                          * (ichiro@netbsd.org)
 2330                          */
 2331                         if (sc->sc_firmware_type == WI_INTERSIL &&
 2332                             sc->sc_sta_firmware_ver < 802 ) {
 2333                                 /* firm ver < 0.8 variant 2 */
 2334                                 wi_write_val(sc, WI_RID_PROMISC, 1);
 2335                         }
 2336                         wi_write_val(sc, WI_RID_CNFAUTHMODE,
 2337                             sc->sc_cnfauthmode);
 2338                         val = PRIVACY_INVOKED | EXCLUDE_UNENCRYPTED;
 2339                         /*
 2340                          * Encryption firmware has a bug for HostAP mode.
 2341                          */
 2342                         if (sc->sc_firmware_type == WI_INTERSIL &&
 2343                             ic->ic_opmode == IEEE80211_M_HOSTAP)
 2344                                 val |= HOST_ENCRYPT;
 2345                 } else {
 2346                         wi_write_val(sc, WI_RID_CNFAUTHMODE,
 2347                             IEEE80211_AUTH_OPEN);
 2348                         val = HOST_ENCRYPT | HOST_DECRYPT;
 2349                 }
 2350                 error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val);
 2351                 if (error)
 2352                         break;
 2353                 error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY,
 2354                     ic->ic_wep_txkey);
 2355                 if (error)
 2356                         break;
 2357                 /*
 2358                  * It seems that the firmware accept 104bit key only if
 2359                  * all the keys have 104bit length.  We get the length of
 2360                  * the transmit key and use it for all other keys.
 2361                  * Perhaps we should use software WEP for such situation.
 2362                  */
 2363                 keylen = ic->ic_nw_keys[ic->ic_wep_txkey].wk_len;
 2364                 if (keylen > IEEE80211_WEP_KEYLEN)
 2365                         keylen = 13;    /* 104bit keys */
 2366                 else
 2367                         keylen = IEEE80211_WEP_KEYLEN;
 2368                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 2369                         error = wi_write_rid(sc, WI_RID_P2_CRYPT_KEY0 + i,
 2370                             ic->ic_nw_keys[i].wk_key, keylen);
 2371                         if (error)
 2372                                 break;
 2373                 }
 2374                 break;
 2375         }
 2376         return error;
 2377 }
 2378 
 2379 static int
 2380 wi_cmd(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
 2381 {
 2382         int                     i, s = 0;
 2383         static volatile int count  = 0;
 2384         
 2385         if (sc->wi_gone)
 2386                 return (ENODEV);
 2387 
 2388         if (count > 0)
 2389                 panic("Hey partner, hold on there!");
 2390         count++;
 2391 
 2392         /* wait for the busy bit to clear */
 2393         for (i = 5000; i > 0; i--) {    /* 5000ms */
 2394                 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
 2395                         break;
 2396                 DELAY(1*1000);  /* 1ms */
 2397         }
 2398         if (i == 0) {
 2399                 device_printf(sc->sc_dev, "wi_cmd: busy bit won't clear.\n" );
 2400                 sc->wi_gone = 1;
 2401                 count--;
 2402                 return(ETIMEDOUT);
 2403         }
 2404 
 2405         CSR_WRITE_2(sc, WI_PARAM0, val0);
 2406         CSR_WRITE_2(sc, WI_PARAM1, val1);
 2407         CSR_WRITE_2(sc, WI_PARAM2, val2);
 2408         CSR_WRITE_2(sc, WI_COMMAND, cmd);
 2409 
 2410         if (cmd == WI_CMD_INI) {
 2411                 /* XXX: should sleep here. */
 2412                 DELAY(100*1000);                /* 100ms delay for init */
 2413         }
 2414         for (i = 0; i < WI_TIMEOUT; i++) {
 2415                 /*
 2416                  * Wait for 'command complete' bit to be
 2417                  * set in the event status register.
 2418                  */
 2419                 s = CSR_READ_2(sc, WI_EVENT_STAT);
 2420                 if (s & WI_EV_CMD) {
 2421                         /* Ack the event and read result code. */
 2422                         s = CSR_READ_2(sc, WI_STATUS);
 2423                         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
 2424                         if (s & WI_STAT_CMD_RESULT) {
 2425                                 count--;
 2426                                 return(EIO);
 2427                         }
 2428                         break;
 2429                 }
 2430                 DELAY(WI_DELAY);
 2431         }
 2432 
 2433         count--;
 2434         if (i == WI_TIMEOUT) {
 2435                 device_printf(sc->sc_dev,
 2436                     "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s);
 2437                 if (s == 0xffff)
 2438                         sc->wi_gone = 1;
 2439                 return(ETIMEDOUT);
 2440         }
 2441         return (0);
 2442 }
 2443 
 2444 static int
 2445 wi_seek_bap(struct wi_softc *sc, int id, int off)
 2446 {
 2447         int i, status;
 2448 
 2449         CSR_WRITE_2(sc, WI_SEL0, id);
 2450         CSR_WRITE_2(sc, WI_OFF0, off);
 2451 
 2452         for (i = 0; ; i++) {
 2453                 status = CSR_READ_2(sc, WI_OFF0);
 2454                 if ((status & WI_OFF_BUSY) == 0)
 2455                         break;
 2456                 if (i == WI_TIMEOUT) {
 2457                         device_printf(sc->sc_dev, "timeout in wi_seek to %x/%x\n",
 2458                             id, off);
 2459                         sc->sc_bap_off = WI_OFF_ERR;    /* invalidate */
 2460                         if (status == 0xffff)
 2461                                 sc->wi_gone = 1;
 2462                         return ETIMEDOUT;
 2463                 }
 2464                 DELAY(1);
 2465         }
 2466         if (status & WI_OFF_ERR) {
 2467                 device_printf(sc->sc_dev, "failed in wi_seek to %x/%x\n", id, off);
 2468                 sc->sc_bap_off = WI_OFF_ERR;    /* invalidate */
 2469                 return EIO;
 2470         }
 2471         sc->sc_bap_id = id;
 2472         sc->sc_bap_off = off;
 2473         return 0;
 2474 }
 2475 
 2476 static int
 2477 wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen)
 2478 {
 2479         u_int16_t *ptr;
 2480         int i, error, cnt;
 2481 
 2482         if (buflen == 0)
 2483                 return 0;
 2484         if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
 2485                 if ((error = wi_seek_bap(sc, id, off)) != 0)
 2486                         return error;
 2487         }
 2488         cnt = (buflen + 1) / 2;
 2489         ptr = (u_int16_t *)buf;
 2490         for (i = 0; i < cnt; i++)
 2491                 *ptr++ = CSR_READ_2(sc, WI_DATA0);
 2492         sc->sc_bap_off += cnt * 2;
 2493         return 0;
 2494 }
 2495 
 2496 static int
 2497 wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen)
 2498 {
 2499         u_int16_t *ptr;
 2500         int i, error, cnt;
 2501 
 2502         if (buflen == 0)
 2503                 return 0;
 2504 
 2505 #ifdef WI_HERMES_AUTOINC_WAR
 2506   again:
 2507 #endif
 2508         if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
 2509                 if ((error = wi_seek_bap(sc, id, off)) != 0)
 2510                         return error;
 2511         }
 2512         cnt = (buflen + 1) / 2;
 2513         ptr = (u_int16_t *)buf;
 2514         for (i = 0; i < cnt; i++)
 2515                 CSR_WRITE_2(sc, WI_DATA0, ptr[i]);
 2516         sc->sc_bap_off += cnt * 2;
 2517 
 2518 #ifdef WI_HERMES_AUTOINC_WAR
 2519         /*
 2520          * According to the comments in the HCF Light code, there is a bug
 2521          * in the Hermes (or possibly in certain Hermes firmware revisions)
 2522          * where the chip's internal autoincrement counter gets thrown off
 2523          * during data writes:  the autoincrement is missed, causing one
 2524          * data word to be overwritten and subsequent words to be written to
 2525          * the wrong memory locations. The end result is that we could end
 2526          * up transmitting bogus frames without realizing it. The workaround
 2527          * for this is to write a couple of extra guard words after the end
 2528          * of the transfer, then attempt to read then back. If we fail to
 2529          * locate the guard words where we expect them, we preform the
 2530          * transfer over again.
 2531          */
 2532         if ((sc->sc_flags & WI_FLAGS_BUG_AUTOINC) && (id & 0xf000) == 0) {
 2533                 CSR_WRITE_2(sc, WI_DATA0, 0x1234);
 2534                 CSR_WRITE_2(sc, WI_DATA0, 0x5678);
 2535                 wi_seek_bap(sc, id, sc->sc_bap_off);
 2536                 sc->sc_bap_off = WI_OFF_ERR;    /* invalidate */
 2537                 if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
 2538                     CSR_READ_2(sc, WI_DATA0) != 0x5678) {
 2539                         device_printf(sc->sc_dev,
 2540                                 "detect auto increment bug, try again\n");
 2541                         goto again;
 2542                 }
 2543         }
 2544 #endif
 2545         return 0;
 2546 }
 2547 
 2548 static int
 2549 wi_mwrite_bap(struct wi_softc *sc, int id, int off, struct mbuf *m0, int totlen)
 2550 {
 2551         int error, len;
 2552         struct mbuf *m;
 2553 
 2554         for (m = m0; m != NULL && totlen > 0; m = m->m_next) {
 2555                 if (m->m_len == 0)
 2556                         continue;
 2557 
 2558                 len = min(m->m_len, totlen);
 2559 
 2560                 if (((u_long)m->m_data) % 2 != 0 || len % 2 != 0) {
 2561                         m_copydata(m, 0, totlen, (caddr_t)&sc->sc_txbuf);
 2562                         return wi_write_bap(sc, id, off, (caddr_t)&sc->sc_txbuf,
 2563                             totlen);
 2564                 }
 2565 
 2566                 if ((error = wi_write_bap(sc, id, off, m->m_data, len)) != 0)
 2567                         return error;
 2568 
 2569                 off += m->m_len;
 2570                 totlen -= len;
 2571         }
 2572         return 0;
 2573 }
 2574 
 2575 static int
 2576 wi_alloc_fid(struct wi_softc *sc, int len, int *idp)
 2577 {
 2578         int i;
 2579 
 2580         if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
 2581                 device_printf(sc->sc_dev, "failed to allocate %d bytes on NIC\n",
 2582                     len);
 2583                 return ENOMEM;
 2584         }
 2585 
 2586         for (i = 0; i < WI_TIMEOUT; i++) {
 2587                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
 2588                         break;
 2589                 if (i == WI_TIMEOUT) {
 2590                         device_printf(sc->sc_dev, "timeout in alloc\n");
 2591                         return ETIMEDOUT;
 2592                 }
 2593                 DELAY(1);
 2594         }
 2595         *idp = CSR_READ_2(sc, WI_ALLOC_FID);
 2596         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 2597         return 0;
 2598 }
 2599 
 2600 static int
 2601 wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp)
 2602 {
 2603         int error, len;
 2604         u_int16_t ltbuf[2];
 2605 
 2606         /* Tell the NIC to enter record read mode. */
 2607         error = wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_READ, rid, 0, 0);
 2608         if (error)
 2609                 return error;
 2610 
 2611         error = wi_read_bap(sc, rid, 0, ltbuf, sizeof(ltbuf));
 2612         if (error)
 2613                 return error;
 2614 
 2615         if (le16toh(ltbuf[1]) != rid) {
 2616                 device_printf(sc->sc_dev, "record read mismatch, rid=%x, got=%x\n",
 2617                     rid, le16toh(ltbuf[1]));
 2618                 return EIO;
 2619         }
 2620         len = (le16toh(ltbuf[0]) - 1) * 2;       /* already got rid */
 2621         if (*buflenp < len) {
 2622                 device_printf(sc->sc_dev, "record buffer is too small, "
 2623                     "rid=%x, size=%d, len=%d\n",
 2624                     rid, *buflenp, len);
 2625                 return ENOSPC;
 2626         }
 2627         *buflenp = len;
 2628         return wi_read_bap(sc, rid, sizeof(ltbuf), buf, len);
 2629 }
 2630 
 2631 static int
 2632 wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen)
 2633 {
 2634         int error;
 2635         u_int16_t ltbuf[2];
 2636 
 2637         ltbuf[0] = htole16((buflen + 1) / 2 + 1);        /* includes rid */
 2638         ltbuf[1] = htole16(rid);
 2639 
 2640         error = wi_write_bap(sc, rid, 0, ltbuf, sizeof(ltbuf));
 2641         if (error)
 2642                 return error;
 2643         error = wi_write_bap(sc, rid, sizeof(ltbuf), buf, buflen);
 2644         if (error)
 2645                 return error;
 2646 
 2647         return wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_WRITE, rid, 0, 0);
 2648 }
 2649 
 2650 static int
 2651 wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 2652 {
 2653         struct ifnet *ifp = &ic->ic_if;
 2654         struct wi_softc *sc = ifp->if_softc;
 2655         struct ieee80211_node *ni = ic->ic_bss;
 2656         int buflen;
 2657         u_int16_t val;
 2658         struct wi_ssid ssid;
 2659         u_int8_t old_bssid[IEEE80211_ADDR_LEN];
 2660 
 2661         DPRINTF(("%s: %s -> %s\n", __func__,
 2662                 ieee80211_state_name[ic->ic_state],
 2663                 ieee80211_state_name[nstate]));
 2664 
 2665         switch (nstate) {
 2666         case IEEE80211_S_INIT:
 2667                 ic->ic_flags &= ~IEEE80211_F_SIBSS;
 2668                 sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
 2669                 return (*sc->sc_newstate)(ic, nstate, arg);
 2670 
 2671         case IEEE80211_S_RUN:
 2672                 sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
 2673                 buflen = IEEE80211_ADDR_LEN;
 2674                 wi_read_rid(sc, WI_RID_CURRENT_BSSID, ni->ni_bssid, &buflen);
 2675                 IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
 2676                 buflen = sizeof(val);
 2677                 wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
 2678                 /* XXX validate channel */
 2679                 ni->ni_chan = &ic->ic_channels[le16toh(val)];
 2680 #if NBPFILTER > 0
 2681                 sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
 2682                         htole16(ni->ni_chan->ic_freq);
 2683                 sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
 2684                         htole16(ni->ni_chan->ic_flags);
 2685 #endif
 2686 
 2687                 if (IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid))
 2688                         sc->sc_false_syns++;
 2689                 else
 2690                         sc->sc_false_syns = 0;
 2691 
 2692                 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
 2693                         ni->ni_esslen = ic->ic_des_esslen;
 2694                         memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
 2695                         ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B];
 2696                         ni->ni_intval = ic->ic_lintval;
 2697                         ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
 2698                         if (ic->ic_flags & IEEE80211_F_WEPON)
 2699                                 ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
 2700                 } else {
 2701                         /* XXX check return value */
 2702                         buflen = sizeof(ssid);
 2703                         wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen);
 2704                         ni->ni_esslen = le16toh(ssid.wi_len);
 2705                         if (ni->ni_esslen > IEEE80211_NWID_LEN)
 2706                                 ni->ni_esslen = IEEE80211_NWID_LEN;     /*XXX*/
 2707                         memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen);
 2708                 }
 2709                 break;
 2710 
 2711         case IEEE80211_S_SCAN:
 2712         case IEEE80211_S_AUTH:
 2713         case IEEE80211_S_ASSOC:
 2714                 break;
 2715         }
 2716 
 2717         ic->ic_state = nstate;          /* NB: skip normal ieee80211 handling */
 2718         return 0;
 2719 }
 2720 
 2721 static int
 2722 wi_scan_ap(struct wi_softc *sc, u_int16_t chanmask, u_int16_t txrate)
 2723 {
 2724         int error = 0;
 2725         u_int16_t val[2];
 2726 
 2727         if (!sc->sc_enabled)
 2728                 return ENXIO;
 2729         switch (sc->sc_firmware_type) {
 2730         case WI_LUCENT:
 2731                 (void)wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
 2732                 break;
 2733         case WI_INTERSIL:
 2734                 val[0] = chanmask;      /* channel */
 2735                 val[1] = txrate;        /* tx rate */
 2736                 error = wi_write_rid(sc, WI_RID_SCAN_REQ, val, sizeof(val));
 2737                 break;
 2738         case WI_SYMBOL:
 2739                 /*
 2740                  * XXX only supported on 3.x ?
 2741                  */
 2742                 val[0] = BSCAN_BCAST | BSCAN_ONETIME;
 2743                 error = wi_write_rid(sc, WI_RID_BCAST_SCAN_REQ,
 2744                     val, sizeof(val[0]));
 2745                 break;
 2746         }
 2747         if (error == 0) {
 2748                 sc->sc_scan_timer = WI_SCAN_WAIT;
 2749                 sc->sc_ic.ic_if.if_timer = 1;
 2750                 DPRINTF(("wi_scan_ap: start scanning, "
 2751                         "chamask 0x%x txrate 0x%x\n", chanmask, txrate));
 2752         }
 2753         return error;
 2754 }
 2755 
 2756 static void
 2757 wi_scan_result(struct wi_softc *sc, int fid, int cnt)
 2758 {
 2759 #define N(a)    (sizeof (a) / sizeof (a[0]))
 2760         int i, naps, off, szbuf;
 2761         struct wi_scan_header ws_hdr;   /* Prism2 header */
 2762         struct wi_scan_data_p2 ws_dat;  /* Prism2 scantable*/
 2763         struct wi_apinfo *ap;
 2764 
 2765         off = sizeof(u_int16_t) * 2;
 2766         memset(&ws_hdr, 0, sizeof(ws_hdr));
 2767         switch (sc->sc_firmware_type) {
 2768         case WI_INTERSIL:
 2769                 wi_read_bap(sc, fid, off, &ws_hdr, sizeof(ws_hdr));
 2770                 off += sizeof(ws_hdr);
 2771                 szbuf = sizeof(struct wi_scan_data_p2);
 2772                 break;
 2773         case WI_SYMBOL:
 2774                 szbuf = sizeof(struct wi_scan_data_p2) + 6;
 2775                 break;
 2776         case WI_LUCENT:
 2777                 szbuf = sizeof(struct wi_scan_data);
 2778                 break;
 2779         default:
 2780                 device_printf(sc->sc_dev,
 2781                         "wi_scan_result: unknown firmware type %u\n",
 2782                         sc->sc_firmware_type);
 2783                 naps = 0;
 2784                 goto done;
 2785         }
 2786         naps = (cnt * 2 + 2 - off) / szbuf;
 2787         if (naps > N(sc->sc_aps))
 2788                 naps = N(sc->sc_aps);
 2789         sc->sc_naps = naps;
 2790         /* Read Data */
 2791         ap = sc->sc_aps;
 2792         memset(&ws_dat, 0, sizeof(ws_dat));
 2793         for (i = 0; i < naps; i++, ap++) {
 2794                 wi_read_bap(sc, fid, off, &ws_dat,
 2795                     (sizeof(ws_dat) < szbuf ? sizeof(ws_dat) : szbuf));
 2796                 DPRINTF2(("wi_scan_result: #%d: off %d bssid %s\n", i, off,
 2797                     ether_sprintf(ws_dat.wi_bssid)));
 2798                 off += szbuf;
 2799                 ap->scanreason = le16toh(ws_hdr.wi_reason);
 2800                 memcpy(ap->bssid, ws_dat.wi_bssid, sizeof(ap->bssid));
 2801                 ap->channel = le16toh(ws_dat.wi_chid);
 2802                 ap->signal  = le16toh(ws_dat.wi_signal);
 2803                 ap->noise   = le16toh(ws_dat.wi_noise);
 2804                 ap->quality = ap->signal - ap->noise;
 2805                 ap->capinfo = le16toh(ws_dat.wi_capinfo);
 2806                 ap->interval = le16toh(ws_dat.wi_interval);
 2807                 ap->rate    = le16toh(ws_dat.wi_rate);
 2808                 ap->namelen = le16toh(ws_dat.wi_namelen);
 2809                 if (ap->namelen > sizeof(ap->name))
 2810                         ap->namelen = sizeof(ap->name);
 2811                 memcpy(ap->name, ws_dat.wi_name, ap->namelen);
 2812         }
 2813 done:
 2814         /* Done scanning */
 2815         sc->sc_scan_timer = 0;
 2816         DPRINTF(("wi_scan_result: scan complete: ap %d\n", naps));
 2817 #undef N
 2818 }
 2819 
 2820 static void
 2821 wi_dump_pkt(struct wi_frame *wh, struct ieee80211_node *ni, int rssi)
 2822 {
 2823         ieee80211_dump_pkt((u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
 2824             ni ? ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL : -1, rssi);
 2825         printf(" status 0x%x rx_tstamp1 %u rx_tstamp0 0x%u rx_silence %u\n",
 2826                 le16toh(wh->wi_status), le16toh(wh->wi_rx_tstamp1),
 2827                 le16toh(wh->wi_rx_tstamp0), wh->wi_rx_silence);
 2828         printf(" rx_signal %u rx_rate %u rx_flow %u\n",
 2829                 wh->wi_rx_signal, wh->wi_rx_rate, wh->wi_rx_flow);
 2830         printf(" tx_rtry %u tx_rate %u tx_ctl 0x%x dat_len %u\n",
 2831                 wh->wi_tx_rtry, wh->wi_tx_rate,
 2832                 le16toh(wh->wi_tx_ctl), le16toh(wh->wi_dat_len));
 2833         printf(" ehdr dst %6D src %6D type 0x%x\n",
 2834                 wh->wi_ehdr.ether_dhost, ":", wh->wi_ehdr.ether_shost, ":",
 2835                 wh->wi_ehdr.ether_type);
 2836 }
 2837 
 2838 int
 2839 wi_alloc(device_t dev, int rid)
 2840 {
 2841         struct wi_softc *sc = device_get_softc(dev);
 2842 
 2843         if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
 2844                 sc->iobase_rid = rid;
 2845                 sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT,
 2846                     &sc->iobase_rid, 0, ~0, (1 << 6),
 2847                     rman_make_alignment_flags(1 << 6) | RF_ACTIVE);
 2848                 if (!sc->iobase) {
 2849                         device_printf(dev, "No I/O space?!\n");
 2850                         return (ENXIO);
 2851                 }
 2852 
 2853                 sc->wi_io_addr = rman_get_start(sc->iobase);
 2854                 sc->wi_btag = rman_get_bustag(sc->iobase);
 2855                 sc->wi_bhandle = rman_get_bushandle(sc->iobase);
 2856         } else {
 2857                 sc->mem_rid = rid;
 2858                 sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY,
 2859                     &sc->mem_rid, 0, ~0, 1, RF_ACTIVE);
 2860 
 2861                 if (!sc->mem) {
 2862                         device_printf(dev, "No Mem space on prism2.5?\n");
 2863                         return (ENXIO);
 2864                 }
 2865 
 2866                 sc->wi_btag = rman_get_bustag(sc->mem);
 2867                 sc->wi_bhandle = rman_get_bushandle(sc->mem);
 2868         }
 2869 
 2870 
 2871         sc->irq_rid = 0;
 2872         sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
 2873             0, ~0, 1, RF_ACTIVE |
 2874             ((sc->wi_bus_type == WI_BUS_PCCARD) ? 0 : RF_SHAREABLE));
 2875 
 2876         if (!sc->irq) {
 2877                 wi_free(dev);
 2878                 device_printf(dev, "No irq?!\n");
 2879                 return (ENXIO);
 2880         }
 2881 
 2882         sc->sc_dev = dev;
 2883         sc->sc_unit = device_get_unit(dev);
 2884 
 2885         return (0);
 2886 }
 2887 
 2888 void
 2889 wi_free(device_t dev)
 2890 {
 2891         struct wi_softc *sc = device_get_softc(dev);
 2892 
 2893         if (sc->iobase != NULL) {
 2894                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
 2895                 sc->iobase = NULL;
 2896         }
 2897         if (sc->irq != NULL) {
 2898                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
 2899                 sc->irq = NULL;
 2900         }
 2901         if (sc->mem != NULL) {
 2902                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
 2903                 sc->mem = NULL;
 2904         }
 2905 
 2906         return;
 2907 }
 2908 
 2909 static int
 2910 wi_get_debug(struct wi_softc *sc, struct wi_req *wreq)
 2911 {
 2912         int error = 0;
 2913 
 2914         wreq->wi_len = 1;
 2915 
 2916         switch (wreq->wi_type) {
 2917         case WI_DEBUG_SLEEP:
 2918                 wreq->wi_len++;
 2919                 wreq->wi_val[0] = sc->wi_debug.wi_sleep;
 2920                 break;
 2921         case WI_DEBUG_DELAYSUPP:
 2922                 wreq->wi_len++;
 2923                 wreq->wi_val[0] = sc->wi_debug.wi_delaysupp;
 2924                 break;
 2925         case WI_DEBUG_TXSUPP:
 2926                 wreq->wi_len++;
 2927                 wreq->wi_val[0] = sc->wi_debug.wi_txsupp;
 2928                 break;
 2929         case WI_DEBUG_MONITOR:
 2930                 wreq->wi_len++;
 2931                 wreq->wi_val[0] = sc->wi_debug.wi_monitor;
 2932                 break;
 2933         case WI_DEBUG_LEDTEST:
 2934                 wreq->wi_len += 3;
 2935                 wreq->wi_val[0] = sc->wi_debug.wi_ledtest;
 2936                 wreq->wi_val[1] = sc->wi_debug.wi_ledtest_param0;
 2937                 wreq->wi_val[2] = sc->wi_debug.wi_ledtest_param1;
 2938                 break;
 2939         case WI_DEBUG_CONTTX:
 2940                 wreq->wi_len += 2;
 2941                 wreq->wi_val[0] = sc->wi_debug.wi_conttx;
 2942                 wreq->wi_val[1] = sc->wi_debug.wi_conttx_param0;
 2943                 break;
 2944         case WI_DEBUG_CONTRX:
 2945                 wreq->wi_len++;
 2946                 wreq->wi_val[0] = sc->wi_debug.wi_contrx;
 2947                 break;
 2948         case WI_DEBUG_SIGSTATE:
 2949                 wreq->wi_len += 2;
 2950                 wreq->wi_val[0] = sc->wi_debug.wi_sigstate;
 2951                 wreq->wi_val[1] = sc->wi_debug.wi_sigstate_param0;
 2952                 break;
 2953         case WI_DEBUG_CONFBITS:
 2954                 wreq->wi_len += 2;
 2955                 wreq->wi_val[0] = sc->wi_debug.wi_confbits;
 2956                 wreq->wi_val[1] = sc->wi_debug.wi_confbits_param0;
 2957                 break;
 2958         default:
 2959                 error = EIO;
 2960                 break;
 2961         }
 2962 
 2963         return (error);
 2964 }
 2965 
 2966 static int
 2967 wi_set_debug(struct wi_softc *sc, struct wi_req *wreq)
 2968 {
 2969         int error = 0;
 2970         u_int16_t               cmd, param0 = 0, param1 = 0;
 2971 
 2972         switch (wreq->wi_type) {
 2973         case WI_DEBUG_RESET:
 2974         case WI_DEBUG_INIT:
 2975         case WI_DEBUG_CALENABLE:
 2976                 break;
 2977         case WI_DEBUG_SLEEP:
 2978                 sc->wi_debug.wi_sleep = 1;
 2979                 break;
 2980         case WI_DEBUG_WAKE:
 2981                 sc->wi_debug.wi_sleep = 0;
 2982                 break;
 2983         case WI_DEBUG_CHAN:
 2984                 param0 = wreq->wi_val[0];
 2985                 break;
 2986         case WI_DEBUG_DELAYSUPP:
 2987                 sc->wi_debug.wi_delaysupp = 1;
 2988                 break;
 2989         case WI_DEBUG_TXSUPP:
 2990                 sc->wi_debug.wi_txsupp = 1;
 2991                 break;
 2992         case WI_DEBUG_MONITOR:
 2993                 sc->wi_debug.wi_monitor = 1;
 2994                 break;
 2995         case WI_DEBUG_LEDTEST:
 2996                 param0 = wreq->wi_val[0];
 2997                 param1 = wreq->wi_val[1];
 2998                 sc->wi_debug.wi_ledtest = 1;
 2999                 sc->wi_debug.wi_ledtest_param0 = param0;
 3000                 sc->wi_debug.wi_ledtest_param1 = param1;
 3001                 break;
 3002         case WI_DEBUG_CONTTX:
 3003                 param0 = wreq->wi_val[0];
 3004                 sc->wi_debug.wi_conttx = 1;
 3005                 sc->wi_debug.wi_conttx_param0 = param0;
 3006                 break;
 3007         case WI_DEBUG_STOPTEST:
 3008                 sc->wi_debug.wi_delaysupp = 0;
 3009                 sc->wi_debug.wi_txsupp = 0;
 3010                 sc->wi_debug.wi_monitor = 0;
 3011                 sc->wi_debug.wi_ledtest = 0;
 3012                 sc->wi_debug.wi_ledtest_param0 = 0;
 3013                 sc->wi_debug.wi_ledtest_param1 = 0;
 3014                 sc->wi_debug.wi_conttx = 0;
 3015                 sc->wi_debug.wi_conttx_param0 = 0;
 3016                 sc->wi_debug.wi_contrx = 0;
 3017                 sc->wi_debug.wi_sigstate = 0;
 3018                 sc->wi_debug.wi_sigstate_param0 = 0;
 3019                 break;
 3020         case WI_DEBUG_CONTRX:
 3021                 sc->wi_debug.wi_contrx = 1;
 3022                 break;
 3023         case WI_DEBUG_SIGSTATE:
 3024                 param0 = wreq->wi_val[0];
 3025                 sc->wi_debug.wi_sigstate = 1;
 3026                 sc->wi_debug.wi_sigstate_param0 = param0;
 3027                 break;
 3028         case WI_DEBUG_CONFBITS:
 3029                 param0 = wreq->wi_val[0];
 3030                 param1 = wreq->wi_val[1];
 3031                 sc->wi_debug.wi_confbits = param0;
 3032                 sc->wi_debug.wi_confbits_param0 = param1;
 3033                 break;
 3034         default:
 3035                 error = EIO;
 3036                 break;
 3037         }
 3038 
 3039         if (error)
 3040                 return (error);
 3041 
 3042         cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
 3043         error = wi_cmd(sc, cmd, param0, param1, 0);
 3044 
 3045         return (error);
 3046 }
 3047 
 3048 #if __FreeBSD_version >= 500000
 3049 /*
 3050  * Special routines to download firmware for Symbol CF card.
 3051  * XXX: This should be modified generic into any PRISM-2 based card.
 3052  */
 3053 
 3054 #define WI_SBCF_PDIADDR         0x3100
 3055 
 3056 /* unaligned load little endian */
 3057 #define GETLE32(p)      ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
 3058 #define GETLE16(p)      ((p)[0] | ((p)[1]<<8))
 3059 
 3060 int
 3061 wi_symbol_load_firm(struct wi_softc *sc, const void *primsym, int primlen,
 3062     const void *secsym, int seclen)
 3063 {
 3064         uint8_t ebuf[256];
 3065         int i;
 3066 
 3067         /* load primary code and run it */
 3068         wi_symbol_set_hcr(sc, WI_HCR_EEHOLD);
 3069         if (wi_symbol_write_firm(sc, primsym, primlen, NULL, 0))
 3070                 return EIO;
 3071         wi_symbol_set_hcr(sc, WI_HCR_RUN);
 3072         for (i = 0; ; i++) {
 3073                 if (i == 10)
 3074                         return ETIMEDOUT;
 3075                 tsleep(sc, PWAIT, "wiinit", 1);
 3076                 if (CSR_READ_2(sc, WI_CNTL) == WI_CNTL_AUX_ENA_STAT)
 3077                         break;
 3078                 /* write the magic key value to unlock aux port */
 3079                 CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0);
 3080                 CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1);
 3081                 CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2);
 3082                 CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL);
 3083         }
 3084 
 3085         /* issue read EEPROM command: XXX copied from wi_cmd() */
 3086         CSR_WRITE_2(sc, WI_PARAM0, 0);
 3087         CSR_WRITE_2(sc, WI_PARAM1, 0);
 3088         CSR_WRITE_2(sc, WI_PARAM2, 0);
 3089         CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE);
 3090         for (i = 0; i < WI_TIMEOUT; i++) {
 3091                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
 3092                         break;
 3093                 DELAY(1);
 3094         }
 3095         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
 3096 
 3097         CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ);
 3098         CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ);
 3099         CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA,
 3100             (uint16_t *)ebuf, sizeof(ebuf) / 2);
 3101         if (GETLE16(ebuf) > sizeof(ebuf))
 3102                 return EIO;
 3103         if (wi_symbol_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf)))
 3104                 return EIO;
 3105         return 0;
 3106 }
 3107 
 3108 static int
 3109 wi_symbol_write_firm(struct wi_softc *sc, const void *buf, int buflen,
 3110     const void *ebuf, int ebuflen)
 3111 {
 3112         const uint8_t *p, *ep, *q, *eq;
 3113         char *tp;
 3114         uint32_t addr, id, eid;
 3115         int i, len, elen, nblk, pdrlen;
 3116 
 3117         /*
 3118          * Parse the header of the firmware image.
 3119          */
 3120         p = buf;
 3121         ep = p + buflen;
 3122         while (p < ep && *p++ != ' ');  /* FILE: */
 3123         while (p < ep && *p++ != ' ');  /* filename */
 3124         while (p < ep && *p++ != ' ');  /* type of the firmware */
 3125         nblk = strtoul(p, &tp, 10);
 3126         p = tp;
 3127         pdrlen = strtoul(p + 1, &tp, 10);
 3128         p = tp;
 3129         while (p < ep && *p++ != 0x1a); /* skip rest of header */
 3130 
 3131         /*
 3132          * Block records: address[4], length[2], data[length];
 3133          */
 3134         for (i = 0; i < nblk; i++) {
 3135                 addr = GETLE32(p);      p += 4;
 3136                 len  = GETLE16(p);      p += 2;
 3137                 CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
 3138                 CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
 3139                 CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
 3140                     (const uint16_t *)p, len / 2);
 3141                 p += len;
 3142         }
 3143         
 3144         /*
 3145          * PDR: id[4], address[4], length[4];
 3146          */
 3147         for (i = 0; i < pdrlen; ) {
 3148                 id   = GETLE32(p);      p += 4; i += 4;
 3149                 addr = GETLE32(p);      p += 4; i += 4;
 3150                 len  = GETLE32(p);      p += 4; i += 4;
 3151                 /* replace PDR entry with the values from EEPROM, if any */
 3152                 for (q = ebuf, eq = q + ebuflen; q < eq; q += elen * 2) {
 3153                         elen = GETLE16(q);      q += 2;
 3154                         eid  = GETLE16(q);      q += 2;
 3155                         elen--;         /* elen includes eid */
 3156                         if (eid == 0)
 3157                                 break;
 3158                         if (eid != id)
 3159                                 continue;
 3160                         CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
 3161                         CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
 3162                         CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
 3163                             (const uint16_t *)q, len / 2);
 3164                         break;
 3165                 }
 3166         }
 3167         return 0;
 3168 }
 3169 
 3170 static int
 3171 wi_symbol_set_hcr(struct wi_softc *sc, int mode)
 3172 {
 3173         uint16_t hcr;
 3174 
 3175         CSR_WRITE_2(sc, WI_COR, WI_COR_RESET);
 3176         tsleep(sc, PWAIT, "wiinit", 1);
 3177         hcr = CSR_READ_2(sc, WI_HCR);
 3178         hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE);
 3179         CSR_WRITE_2(sc, WI_HCR, hcr);
 3180         tsleep(sc, PWAIT, "wiinit", 1);
 3181         CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE);
 3182         tsleep(sc, PWAIT, "wiinit", 1);
 3183         return 0;
 3184 }
 3185 #endif

Cache object: d640ce224e1c41831ffdc2112154838b


[ 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.