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