if_wi.c revision 46611
1/* 2 * Copyright (c) 1997, 1998, 1999 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * $Id: if_wi.c,v 1.53 1999/05/07 03:14:21 wpaul Exp $ 33 */ 34 35/* 36 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. 37 * 38 * 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 fearures, 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 both the PCMCIA and ISA versions of the 60 * WaveLAN/IEEE cards. Note however that the ISA card isn't really 61 * anything of the sort: it's actually a PCMCIA bridge adapter 62 * that fits into an ISA slot, into which a PCMCIA WaveLAN card is 63 * inserted. Consequently, you need to use the pccard support for 64 * both the ISA and PCMCIA adapters. 65 */ 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#include "bpfilter.h" 71#include "card.h" 72#include "wi.h" 73 74#include <sys/param.h> 75#include <sys/systm.h> 76#include <sys/sockio.h> 77#include <sys/mbuf.h> 78#include <sys/malloc.h> 79#include <sys/kernel.h> 80#include <sys/socket.h> 81 82#include <net/if.h> 83#include <net/if_arp.h> 84#include <net/ethernet.h> 85#include <net/if_dl.h> 86#include <net/if_media.h> 87#include <net/if_types.h> 88 89#ifdef INET 90#include <netinet/in.h> 91#include <netinet/in_systm.h> 92#include <netinet/in_var.h> 93#include <netinet/ip.h> 94#include <netinet/if_ether.h> 95#endif 96 97#if NBPFILTER > 0 98#include <net/bpf.h> 99#endif 100 101#include <machine/clock.h> 102#include <machine/md_var.h> 103#include <machine/bus_pio.h> 104#include <machine/bus.h> 105 106#include <i386/isa/isa_device.h> 107#include <i386/isa/icu.h> 108#include <i386/isa/if_wireg.h> 109#include <machine/if_wavelan_ieee.h> 110 111#if NCARD > 0 112#include <sys/select.h> 113#include <pccard/cardinfo.h> 114#include <pccard/slot.h> 115#endif 116 117#if !defined(lint) 118static const char rcsid[] = 119 "$Id: if_wi.c,v 1.53 1999/05/07 03:14:21 wpaul Exp $"; 120#endif 121 122static struct wi_softc wi_softc[NWI]; 123 124#ifdef foo 125static u_int8_t wi_mcast_addr[6] = { 0x00, 0x60, 0x1D, 0x00, 0x01, 0x00 }; 126#endif 127 128static int wi_probe __P((struct isa_device *)); 129static int wi_attach __P((struct isa_device *)); 130#ifdef PCCARD_MODULE 131static ointhand2_t wi_intr; 132#endif 133static void wi_reset __P((struct wi_softc *)); 134static int wi_ioctl __P((struct ifnet *, u_long, caddr_t)); 135static void wi_init __P((void *)); 136static void wi_start __P((struct ifnet *)); 137static void wi_stop __P((struct wi_softc *)); 138static void wi_watchdog __P((struct ifnet *)); 139static void wi_shutdown __P((int, void *)); 140static void wi_rxeof __P((struct wi_softc *)); 141static void wi_txeof __P((struct wi_softc *, int)); 142static void wi_update_stats __P((struct wi_softc *)); 143static void wi_setmulti __P((struct wi_softc *)); 144 145static int wi_cmd __P((struct wi_softc *, int, int)); 146static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *)); 147static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *)); 148static int wi_read_data __P((struct wi_softc *, int, 149 int, caddr_t, int)); 150static int wi_write_data __P((struct wi_softc *, int, 151 int, caddr_t, int)); 152static int wi_seek __P((struct wi_softc *, int, int, int)); 153static int wi_alloc_nicmem __P((struct wi_softc *, int, int *)); 154static void wi_inquire __P((void *)); 155static void wi_setdef __P((struct wi_softc *, struct wi_req *)); 156static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int)); 157 158struct isa_driver widriver = { 159 wi_probe, 160 wi_attach, 161 "wi", 162 1 163}; 164 165#if NCARD > 0 166static int wi_pccard_init __P((struct pccard_devinfo *)); 167static void wi_pccard_unload __P((struct pccard_devinfo *)); 168static int wi_pccard_intr __P((struct pccard_devinfo *)); 169 170#ifdef PCCARD_MODULE 171PCCARD_MODULE(wi, wi_pccard_init, wi_pccard_unload, 172 wi_pccard_intr, 0, net_imask); 173#else 174static struct pccard_device wi_info = { 175 "wi", 176 wi_pccard_init, 177 wi_pccard_unload, 178 wi_pccard_intr, 179 0, /* Attributes - presently unused */ 180 &net_imask /* Interrupt mask for device */ 181 /* XXX - Should this also include net_imask? */ 182}; 183 184DATA_SET(pccarddrv_set, wi_info); 185#endif 186 187/* Initialize the PCCARD. */ 188static int wi_pccard_init(sc_p) 189 struct pccard_devinfo *sc_p; 190{ 191 struct wi_softc *sc; 192 int i; 193 u_int32_t irq; 194 195 if (sc_p->isahd.id_unit >= NWI) 196 return(ENODEV); 197 198 sc = &wi_softc[sc_p->isahd.id_unit]; 199 sc->wi_gone = 0; 200 sc->wi_unit = sc_p->isahd.id_unit; 201 sc->wi_bhandle = sc_p->isahd.id_iobase; 202 sc->wi_btag = I386_BUS_SPACE_IO; 203 204 /* Make sure interrupts are disabled. */ 205 CSR_WRITE_2(sc, WI_INT_EN, 0); 206 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 207 208 /* Grr. IRQ is encoded as a bitmask. */ 209 irq = sc_p->isahd.id_irq; 210 for (i = 0; i < 32; i++) { 211 if (irq & 0x1) 212 break; 213 irq >>= 1; 214 } 215 216 /* 217 * Print a nice probe message to let the operator 218 * know something interesting is happening. 219 */ 220 printf("wi%d: <WaveLAN/IEEE 802.11> at 0x%x-0x%x irq %d on isa\n", 221 sc_p->isahd.id_unit, sc_p->isahd.id_iobase, 222 sc_p->isahd.id_iobase + WI_IOSIZ - 1, i); 223 224 if (wi_attach(&sc_p->isahd)) 225 return(ENXIO); 226 227 return(0); 228} 229 230static void wi_pccard_unload(sc_p) 231 struct pccard_devinfo *sc_p; 232{ 233 struct wi_softc *sc; 234 struct ifnet *ifp; 235 236 sc = &wi_softc[sc_p->isahd.id_unit]; 237 ifp = &sc->arpcom.ac_if; 238 239 if (sc->wi_gone) { 240 printf("wi%d: already unloaded\n", sc_p->isahd.id_unit); 241 return; 242 } 243 244 ifp->if_flags &= ~IFF_RUNNING; 245 if_down(ifp); 246 sc->wi_gone = 1; 247 printf("wi%d: unloaded\n", sc_p->isahd.id_unit); 248 249 return; 250} 251 252static int wi_pccard_intr(sc_p) 253 struct pccard_devinfo *sc_p; 254{ 255 wi_intr(sc_p->isahd.id_unit); 256 return(1); 257} 258#endif 259 260static int wi_probe(isa_dev) 261 struct isa_device *isa_dev; 262{ 263 /* 264 * The ISA WaveLAN/IEEE card is actually not an ISA card: 265 * it's a PCMCIA card plugged into a PCMCIA expander card 266 * that fits into an ISA slot. Consequently, we will always 267 * be using the pccard support to probe and attach these 268 * devices, so we can never actually probe one from here. 269 */ 270 return(0); 271} 272 273static int wi_attach(isa_dev) 274 struct isa_device *isa_dev; 275{ 276 struct wi_softc *sc; 277 struct wi_ltv_macaddr mac; 278 struct wi_ltv_gen gen; 279 struct ifnet *ifp; 280 char ifname[IFNAMSIZ]; 281 282#ifdef PCCARD_MODULE 283 isa_dev->id_ointr = wi_intr; 284#endif 285 sc = &wi_softc[isa_dev->id_unit]; 286 ifp = &sc->arpcom.ac_if; 287 288 /* Reset the NIC. */ 289 wi_reset(sc); 290 291 /* Read the station address. */ 292 mac.wi_type = WI_RID_MAC_NODE; 293 mac.wi_len = 4; 294 wi_read_record(sc, (struct wi_ltv_gen *)&mac); 295 bcopy((char *)&mac.wi_mac_addr, 296 (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 297 298 printf("wi%d: Ethernet address: %6D\n", sc->wi_unit, 299 sc->arpcom.ac_enaddr, ":"); 300 301 ifp->if_softc = sc; 302 ifp->if_unit = sc->wi_unit; 303 ifp->if_name = "wi"; 304 ifp->if_mtu = ETHERMTU; 305 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 306 ifp->if_ioctl = wi_ioctl; 307 ifp->if_output = ether_output; 308 ifp->if_start = wi_start; 309 ifp->if_watchdog = wi_watchdog; 310 ifp->if_init = wi_init; 311 ifp->if_baudrate = 10000000; 312 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 313 314 bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 315 bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, 316 sizeof(WI_DEFAULT_NODENAME) - 1); 317 318 bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 319 bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, 320 sizeof(WI_DEFAULT_NETNAME) - 1); 321 322 bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 323 bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, 324 sizeof(WI_DEFAULT_IBSS) - 1); 325 326 sc->wi_portnum = WI_DEFAULT_PORT; 327 sc->wi_ptype = WI_PORTTYPE_ADHOC; 328 sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; 329 sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; 330 sc->wi_tx_rate = WI_DEFAULT_TX_RATE; 331 sc->wi_max_data_len = WI_DEFAULT_DATALEN; 332 sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; 333 sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; 334 sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; 335 336 /* 337 * Read the default channel from the NIC. This may vary 338 * depending on the country where the NIC was purchased, so 339 * we can't hard-code a default and expect it to work for 340 * everyone. 341 */ 342 gen.wi_type = WI_RID_OWN_CHNL; 343 gen.wi_len = 2; 344 wi_read_record(sc, &gen); 345 sc->wi_channel = gen.wi_val; 346 347 bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); 348 349 wi_init(sc); 350 wi_stop(sc); 351 352 /* 353 * If this logical interface has already been attached, 354 * don't attach it again or chaos will ensue. 355 */ 356 sprintf(ifname, "wi%d", sc->wi_unit); 357 358 if (ifunit(ifname) == NULL) { 359 callout_handle_init(&sc->wi_stat_ch); 360 /* 361 * Call MI attach routines. 362 */ 363 if_attach(ifp); 364 ether_ifattach(ifp); 365 366#if NBPFILTER > 0 367 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 368#endif 369 370 at_shutdown(wi_shutdown, sc, SHUTDOWN_POST_SYNC); 371 } 372 373 return(0); 374} 375 376static void wi_rxeof(sc) 377 struct wi_softc *sc; 378{ 379 struct ifnet *ifp; 380 struct ether_header *eh; 381 struct wi_frame rx_frame; 382 struct mbuf *m; 383 int id; 384 385 ifp = &sc->arpcom.ac_if; 386 387 id = CSR_READ_2(sc, WI_RX_FID); 388 389 /* First read in the frame header */ 390 if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { 391 ifp->if_ierrors++; 392 return; 393 } 394 395 if (rx_frame.wi_status & WI_STAT_ERRSTAT) { 396 ifp->if_ierrors++; 397 return; 398 } 399 400 MGETHDR(m, M_DONTWAIT, MT_DATA); 401 if (m == NULL) { 402 ifp->if_ierrors++; 403 return; 404 } 405 MCLGET(m, M_DONTWAIT); 406 if (!(m->m_flags & M_EXT)) { 407 m_freem(m); 408 ifp->if_ierrors++; 409 return; 410 } 411 412 eh = mtod(m, struct ether_header *); 413 m->m_pkthdr.rcvif = ifp; 414 415 if (rx_frame.wi_status == WI_STAT_1042 || 416 rx_frame.wi_status == WI_STAT_TUNNEL || 417 rx_frame.wi_status == WI_STAT_WMP_MSG) { 418 m->m_pkthdr.len = m->m_len = 419 rx_frame.wi_dat_len + WI_SNAPHDR_LEN; 420 421 bcopy((char *)&rx_frame.wi_addr1, 422 (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 423 bcopy((char *)&rx_frame.wi_addr2, 424 (char *)&eh->ether_shost, ETHER_ADDR_LEN); 425 bcopy((char *)&rx_frame.wi_type, 426 (char *)&eh->ether_type, sizeof(u_int16_t)); 427 428 if (wi_read_data(sc, id, WI_802_11_OFFSET, 429 mtod(m, caddr_t) + sizeof(struct ether_header), 430 m->m_len + 2)) { 431 m_freem(m); 432 ifp->if_ierrors++; 433 return; 434 } 435 } else { 436 m->m_pkthdr.len = m->m_len = 437 rx_frame.wi_dat_len + sizeof(struct ether_header); 438 439 if (wi_read_data(sc, id, WI_802_3_OFFSET, 440 mtod(m, caddr_t), m->m_len + 2)) { 441 m_freem(m); 442 ifp->if_ierrors++; 443 return; 444 } 445 } 446 447 ifp->if_ipackets++; 448 449#if NBPFILTER > 0 450 /* Handle BPF listeners. */ 451 if (ifp->if_bpf) { 452 bpf_mtap(ifp, m); 453 if (ifp->if_flags & IFF_PROMISC && 454 (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 455 ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { 456 m_freem(m); 457 return; 458 } 459 } 460#endif 461 462 /* Receive packet. */ 463 m_adj(m, sizeof(struct ether_header)); 464 ether_input(ifp, eh, m); 465 466 return; 467} 468 469static void wi_txeof(sc, status) 470 struct wi_softc *sc; 471 int status; 472{ 473 struct ifnet *ifp; 474 475 ifp = &sc->arpcom.ac_if; 476 477 ifp->if_timer = 0; 478 ifp->if_flags &= ~IFF_OACTIVE; 479 480 if (status & WI_EV_TX_EXC) 481 ifp->if_oerrors++; 482 else 483 ifp->if_opackets++; 484 485 return; 486} 487 488void wi_inquire(xsc) 489 void *xsc; 490{ 491 struct wi_softc *sc; 492 struct ifnet *ifp; 493 494 sc = xsc; 495 ifp = &sc->arpcom.ac_if; 496 497 sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 498 499 /* Don't do this while we're transmitting */ 500 if (ifp->if_flags & IFF_OACTIVE) 501 return; 502 503 wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS); 504 505 return; 506} 507 508void wi_update_stats(sc) 509 struct wi_softc *sc; 510{ 511 struct wi_ltv_gen gen; 512 u_int16_t id; 513 struct ifnet *ifp; 514 u_int32_t *ptr; 515 int i; 516 u_int16_t t; 517 518 ifp = &sc->arpcom.ac_if; 519 520 id = CSR_READ_2(sc, WI_INFO_FID); 521 522 wi_read_data(sc, id, 0, (char *)&gen, 4); 523 524 if (gen.wi_type != WI_INFO_COUNTERS || 525 gen.wi_len > (sizeof(sc->wi_stats) / 4) + 1) 526 return; 527 528 ptr = (u_int32_t *)&sc->wi_stats; 529 530 for (i = 0; i < gen.wi_len - 1; i++) { 531 t = CSR_READ_2(sc, WI_DATA1); 532#ifdef WI_HERMES_STATS_WAR 533 if (t > 0xF000) 534 t = ~t & 0xFFFF; 535#endif 536 ptr[i] += t; 537 } 538 539 ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + 540 sc->wi_stats.wi_tx_multi_retries + 541 sc->wi_stats.wi_tx_retry_limit; 542 543 return; 544} 545 546void wi_intr(unit) 547 int unit; 548{ 549 struct wi_softc *sc; 550 struct ifnet *ifp; 551 u_int16_t status; 552 553 sc = &wi_softc[unit]; 554 ifp = &sc->arpcom.ac_if; 555 556 if (!(ifp->if_flags & IFF_UP)) { 557 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 558 CSR_WRITE_2(sc, WI_INT_EN, 0); 559 return; 560 } 561 562 /* Disable interrupts. */ 563 CSR_WRITE_2(sc, WI_INT_EN, 0); 564 565 status = CSR_READ_2(sc, WI_EVENT_STAT); 566 CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); 567 568 if (status & WI_EV_RX) { 569 wi_rxeof(sc); 570 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); 571 } 572 573 if (status & WI_EV_TX) { 574 wi_txeof(sc, status); 575 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); 576 } 577 578 if (status & WI_EV_ALLOC) { 579 int id; 580 id = CSR_READ_2(sc, WI_ALLOC_FID); 581 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 582 if (id == sc->wi_tx_data_id) 583 wi_txeof(sc, status); 584 } 585 586 if (status & WI_EV_INFO) { 587 wi_update_stats(sc); 588 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); 589 } 590 591 if (status & WI_EV_TX_EXC) { 592 wi_txeof(sc, status); 593 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); 594 } 595 596 if (status & WI_EV_INFO_DROP) { 597 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); 598 } 599 600 /* Re-enable interrupts. */ 601 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 602 603 if (ifp->if_snd.ifq_head != NULL) 604 wi_start(ifp); 605 606 return; 607} 608 609static int wi_cmd(sc, cmd, val) 610 struct wi_softc *sc; 611 int cmd; 612 int val; 613{ 614 int i, s = 0; 615 616 CSR_WRITE_2(sc, WI_PARAM0, val); 617 CSR_WRITE_2(sc, WI_COMMAND, cmd); 618 619 for (i = 0; i < WI_TIMEOUT; i++) { 620 /* 621 * Wait for 'command complete' bit to be 622 * set in the event status register. 623 */ 624 s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD; 625 if (s) { 626 /* Ack the event and read result code. */ 627 s = CSR_READ_2(sc, WI_STATUS); 628 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 629#ifdef foo 630 if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) 631 return(EIO); 632#endif 633 if (s & WI_STAT_CMD_RESULT) 634 return(EIO); 635 break; 636 } 637 } 638 639 if (i == WI_TIMEOUT) 640 return(ETIMEDOUT); 641 642 return(0); 643} 644 645static void wi_reset(sc) 646 struct wi_softc *sc; 647{ 648 if (wi_cmd(sc, WI_CMD_INI, 0)) 649 printf("wi%d: init failed\n", sc->wi_unit); 650 CSR_WRITE_2(sc, WI_INT_EN, 0); 651 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 652 653 /* Calibrate timer. */ 654 WI_SETVAL(WI_RID_TICK_TIME, 8); 655 656 return; 657} 658 659/* 660 * Read an LTV record from the NIC. 661 */ 662static int wi_read_record(sc, ltv) 663 struct wi_softc *sc; 664 struct wi_ltv_gen *ltv; 665{ 666 u_int16_t *ptr; 667 int i, len, code; 668 669 /* Tell the NIC to enter record read mode. */ 670 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type)) 671 return(EIO); 672 673 /* Select the record we want to read. */ 674 CSR_WRITE_2(sc, WI_SEL1, ltv->wi_type); 675 676 /* Specify offset -- we always read the whole record. */ 677 CSR_WRITE_2(sc, WI_OFF1, 0); 678 679 /* Wait for NIC to acknowledge */ 680 for (i = 0; i < WI_TIMEOUT; i++) { 681 if (!(CSR_READ_2(sc, WI_OFF1) & (WI_OFF_BUSY|WI_OFF_ERR))) 682 break; 683 } 684 685 if (i == WI_TIMEOUT) 686 return(ETIMEDOUT); 687 688 /* 689 * Read the length and record type and make sure they 690 * match what we expect (this verifies that we have enough 691 * room to hold all of the returned data. 692 */ 693 len = CSR_READ_2(sc, WI_DATA1); 694 if (len > ltv->wi_len) 695 return(ENOSPC); 696 code = CSR_READ_2(sc, WI_DATA1); 697 if (code != ltv->wi_type) 698 return(EIO); 699 700 ltv->wi_len = len; 701 ltv->wi_type = code; 702 703 /* Now read the data. */ 704 ptr = <v->wi_val; 705 for (i = 0; i < ltv->wi_len - 1; i++) 706 ptr[i] = CSR_READ_2(sc, WI_DATA1); 707 708 return(0); 709} 710 711/* 712 * Same as read, except we inject data instead of reading it. 713 */ 714static int wi_write_record(sc, ltv) 715 struct wi_softc *sc; 716 struct wi_ltv_gen *ltv; 717{ 718 u_int16_t *ptr; 719 int i; 720 721 CSR_WRITE_2(sc, WI_SEL1, ltv->wi_type); 722 CSR_WRITE_2(sc, WI_OFF1, 0); 723 724 for (i = 0; i < WI_TIMEOUT; i++) { 725 if (!(CSR_READ_2(sc, WI_OFF1) & (WI_OFF_BUSY|WI_OFF_ERR))) 726 break; 727 } 728 729 if (i == WI_TIMEOUT) 730 return(ETIMEDOUT); 731 732 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); 733 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); 734 735 ptr = <v->wi_val; 736 for (i = 0; i < ltv->wi_len - 1; i++) 737 CSR_WRITE_2(sc, WI_DATA1, ptr[i]); 738 739 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type)) 740 return(EIO); 741 742 return(0); 743} 744 745static int wi_seek(sc, id, off, chan) 746 struct wi_softc *sc; 747 int id, off, chan; 748{ 749 int i; 750 int selreg, offreg; 751 752 switch (chan) { 753 case WI_BAP0: 754 selreg = WI_SEL0; 755 offreg = WI_OFF0; 756 break; 757 case WI_BAP1: 758 selreg = WI_SEL1; 759 offreg = WI_OFF1; 760 break; 761 default: 762 printf("wi%d: invalid data path: %x\n", sc->wi_unit, chan); 763 return(EIO); 764 } 765 766 CSR_WRITE_2(sc, selreg, id); 767 CSR_WRITE_2(sc, offreg, off); 768 769 for (i = 0; i < WI_TIMEOUT; i++) { 770 if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR))) 771 break; 772 } 773 774 if (i == WI_TIMEOUT) 775 return(ETIMEDOUT); 776 777 return(0); 778} 779 780static int wi_read_data(sc, id, off, buf, len) 781 struct wi_softc *sc; 782 int id, off; 783 caddr_t buf; 784 int len; 785{ 786 int i; 787 u_int16_t *ptr; 788 789 if (wi_seek(sc, id, off, WI_BAP1)) 790 return(EIO); 791 792 ptr = (u_int16_t *)buf; 793 for (i = 0; i < len / 2; i++) 794 ptr[i] = CSR_READ_2(sc, WI_DATA1); 795 796 return(0); 797} 798 799/* 800 * According to the comments in the HCF Light code, there is a bug in 801 * the Hermes (or possibly in certain Hermes firmware revisions) where 802 * the chip's internal autoincrement counter gets thrown off during 803 * data writes: the autoincrement is missed, causing one data word to 804 * be overwritten and subsequent words to be written to the wrong memory 805 * locations. The end result is that we could end up transmitting bogus 806 * frames without realizing it. The workaround for this is to write a 807 * couple of extra guard words after the end of the transfer, then 808 * attempt to read then back. If we fail to locate the guard words where 809 * we expect them, we preform the transfer over again. 810 */ 811static int wi_write_data(sc, id, off, buf, len) 812 struct wi_softc *sc; 813 int id, off; 814 caddr_t buf; 815 int len; 816{ 817 int i; 818 u_int16_t *ptr; 819 820#ifdef WI_HERMES_AUTOINC_WAR 821again: 822#endif 823 824 if (wi_seek(sc, id, off, WI_BAP0)) 825 return(EIO); 826 827 ptr = (u_int16_t *)buf; 828 for (i = 0; i < (len / 2); i++) 829 CSR_WRITE_2(sc, WI_DATA0, ptr[i]); 830 831#ifdef WI_HERMES_AUTOINC_WAR 832 CSR_WRITE_2(sc, WI_DATA0, 0x1234); 833 CSR_WRITE_2(sc, WI_DATA0, 0x5678); 834 835 if (wi_seek(sc, id, off + len, WI_BAP0)) 836 return(EIO); 837 838 if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || 839 CSR_READ_2(sc, WI_DATA0) != 0x5678) 840 goto again; 841#endif 842 843 return(0); 844} 845 846/* 847 * Allocate a region of memory inside the NIC and zero 848 * it out. 849 */ 850static int wi_alloc_nicmem(sc, len, id) 851 struct wi_softc *sc; 852 int len; 853 int *id; 854{ 855 int i; 856 857 if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) { 858 printf("wi%d: failed to allocate %d bytes on NIC\n", 859 sc->wi_unit, len); 860 return(ENOMEM); 861 } 862 863 for (i = 0; i < WI_TIMEOUT; i++) { 864 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) 865 break; 866 } 867 868 if (i == WI_TIMEOUT) 869 return(ETIMEDOUT); 870 871 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); 872 *id = CSR_READ_2(sc, WI_ALLOC_FID); 873 874 wi_seek(sc, *id, 0, WI_BAP0); 875 876 for (i = 0; i < len / 2; i++) 877 CSR_WRITE_2(sc, WI_DATA0, 0); 878 879 return(0); 880} 881 882static void wi_setmulti(sc) 883 struct wi_softc *sc; 884{ 885 struct ifnet *ifp; 886 int i = 0; 887 struct ifmultiaddr *ifma; 888 struct wi_ltv_mcast mcast; 889 890 ifp = &sc->arpcom.ac_if; 891 892 bzero((char *)&mcast, sizeof(mcast)); 893 894 mcast.wi_type = WI_RID_MCAST; 895 mcast.wi_len = (3 * 16) + 1; 896 897 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 898 wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 899 return; 900 } 901 902 for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 903 ifma = ifma->ifma_link.le_next) { 904 if (ifma->ifma_addr->sa_family != AF_LINK) 905 continue; 906 if (i < 16) { 907 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 908 (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); 909 i++; 910 } else { 911 bzero((char *)&mcast, sizeof(mcast)); 912 break; 913 } 914 } 915 916 mcast.wi_len = (i * 3) + 1; 917 wi_write_record(sc, (struct wi_ltv_gen *)&mcast); 918 919 return; 920} 921 922static void wi_setdef(sc, wreq) 923 struct wi_softc *sc; 924 struct wi_req *wreq; 925{ 926 struct sockaddr_dl *sdl; 927 struct ifaddr *ifa; 928 struct ifnet *ifp; 929 930 ifp = &sc->arpcom.ac_if; 931 932 switch(wreq->wi_type) { 933 case WI_RID_MAC_NODE: 934 ifa = ifnet_addrs[ifp->if_index - 1]; 935 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 936 bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, 937 ETHER_ADDR_LEN); 938 bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); 939 break; 940 case WI_RID_PORTTYPE: 941 sc->wi_ptype = wreq->wi_val[0]; 942 break; 943 case WI_RID_TX_RATE: 944 sc->wi_tx_rate = wreq->wi_val[0]; 945 break; 946 case WI_RID_MAX_DATALEN: 947 sc->wi_max_data_len = wreq->wi_val[0]; 948 break; 949 case WI_RID_RTS_THRESH: 950 sc->wi_rts_thresh = wreq->wi_val[0]; 951 break; 952 case WI_RID_SYSTEM_SCALE: 953 sc->wi_ap_density = wreq->wi_val[0]; 954 break; 955 case WI_RID_CREATE_IBSS: 956 sc->wi_create_ibss = wreq->wi_val[0]; 957 break; 958 case WI_RID_OWN_CHNL: 959 sc->wi_channel = wreq->wi_val[0]; 960 break; 961 case WI_RID_NODENAME: 962 bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); 963 bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); 964 break; 965 case WI_RID_DESIRED_SSID: 966 bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); 967 bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); 968 break; 969 case WI_RID_OWN_SSID: 970 bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); 971 bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); 972 break; 973 case WI_RID_PM_ENABLED: 974 sc->wi_pm_enabled = wreq->wi_val[0]; 975 break; 976 case WI_RID_MAX_SLEEP: 977 sc->wi_max_sleep = wreq->wi_val[0]; 978 break; 979 default: 980 break; 981 } 982 983 /* Reinitialize WaveLAN. */ 984 wi_init(sc); 985 986 return; 987} 988 989static int wi_ioctl(ifp, command, data) 990 struct ifnet *ifp; 991 u_long command; 992 caddr_t data; 993{ 994 int s, error = 0; 995 struct wi_softc *sc; 996 struct wi_req wreq; 997 struct ifreq *ifr; 998 999 s = splimp(); 1000 1001 sc = ifp->if_softc; 1002 ifr = (struct ifreq *)data; 1003 1004 if (sc->wi_gone) 1005 return(ENODEV); 1006 1007 switch(command) { 1008 case SIOCSIFADDR: 1009 case SIOCGIFADDR: 1010 case SIOCSIFMTU: 1011 error = ether_ioctl(ifp, command, data); 1012 break; 1013 case SIOCSIFFLAGS: 1014 if (ifp->if_flags & IFF_UP) { 1015 if (ifp->if_flags & IFF_RUNNING && 1016 ifp->if_flags & IFF_PROMISC && 1017 !(sc->wi_if_flags & IFF_PROMISC)) { 1018 WI_SETVAL(WI_RID_PROMISC, 1); 1019 } else if (ifp->if_flags & IFF_RUNNING && 1020 !(ifp->if_flags & IFF_PROMISC) && 1021 sc->wi_if_flags & IFF_PROMISC) { 1022 WI_SETVAL(WI_RID_PROMISC, 0); 1023 } else 1024 wi_init(sc); 1025 } else { 1026 if (ifp->if_flags & IFF_RUNNING) { 1027 wi_stop(sc); 1028 } 1029 } 1030 sc->wi_if_flags = ifp->if_flags; 1031 error = 0; 1032 break; 1033 case SIOCADDMULTI: 1034 case SIOCDELMULTI: 1035 wi_setmulti(sc); 1036 error = 0; 1037 break; 1038 case SIOCGWAVELAN: 1039 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 1040 if (error) 1041 break; 1042 if (wreq.wi_type == WI_RID_IFACE_STATS) { 1043 bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, 1044 sizeof(sc->wi_stats)); 1045 wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; 1046 } else { 1047 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { 1048 error = EINVAL; 1049 break; 1050 } 1051 } 1052 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); 1053 break; 1054 case SIOCSWAVELAN: 1055 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); 1056 if (error) 1057 break; 1058 if (wreq.wi_type == WI_RID_IFACE_STATS) { 1059 error = EINVAL; 1060 break; 1061 } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { 1062 error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, 1063 wreq.wi_len); 1064 } else { 1065 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); 1066 if (!error) 1067 wi_setdef(sc, &wreq); 1068 } 1069 break; 1070 default: 1071 error = EINVAL; 1072 break; 1073 } 1074 1075 splx(s); 1076 1077 return(error); 1078} 1079 1080static void wi_init(xsc) 1081 void *xsc; 1082{ 1083 struct wi_softc *sc = xsc; 1084 struct ifnet *ifp = &sc->arpcom.ac_if; 1085 int s; 1086 struct wi_ltv_macaddr mac; 1087 int id = 0; 1088 1089 if (sc->wi_gone) 1090 return; 1091 1092 s = splimp(); 1093 1094 if (ifp->if_flags & IFF_RUNNING) 1095 wi_stop(sc); 1096 1097 wi_reset(sc); 1098 1099 /* Program max data length. */ 1100 WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); 1101 1102 /* Enable/disable IBSS ctration. */ 1103 WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); 1104 1105 /* Set the port type. */ 1106 WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); 1107 1108 /* Program the RTS/CTS threshold. */ 1109 WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); 1110 1111 /* Program the TX rate */ 1112 WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); 1113 1114 /* Access point density */ 1115 WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); 1116 1117 /* Power Management Enabled */ 1118 WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); 1119 1120 /* Power Managment Max Sleep */ 1121 WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); 1122 1123 /* Specify the IBSS name */ 1124 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); 1125 1126 /* Specify the network name */ 1127 WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); 1128 1129 /* Specify the frequency to use */ 1130 WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); 1131 1132 /* Program the nodename. */ 1133 WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); 1134 1135 /* Set our MAC address. */ 1136 mac.wi_len = 4; 1137 mac.wi_type = WI_RID_MAC_NODE; 1138 bcopy((char *)&sc->arpcom.ac_enaddr, 1139 (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); 1140 wi_write_record(sc, (struct wi_ltv_gen *)&mac); 1141 1142 /* Initialize promisc mode. */ 1143 if (ifp->if_flags & IFF_PROMISC) { 1144 WI_SETVAL(WI_RID_PROMISC, 1); 1145 } else { 1146 WI_SETVAL(WI_RID_PROMISC, 0); 1147 } 1148 1149 /* Set multicast filter. */ 1150 wi_setmulti(sc); 1151 1152 /* Enable desired port */ 1153 wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0); 1154 1155 if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id)) 1156 printf("wi%d: tx buffer allocation failed\n", sc->wi_unit); 1157 sc->wi_tx_data_id = id; 1158 1159 if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id)) 1160 printf("wi%d: mgmt. buffer allocation failed\n", sc->wi_unit); 1161 sc->wi_tx_mgmt_id = id; 1162 1163 /* enable interrupts */ 1164 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); 1165 1166 splx(s); 1167 1168 ifp->if_flags |= IFF_RUNNING; 1169 ifp->if_flags &= ~IFF_OACTIVE; 1170 1171 sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); 1172 1173 return; 1174} 1175 1176static void wi_start(ifp) 1177 struct ifnet *ifp; 1178{ 1179 struct wi_softc *sc; 1180 struct mbuf *m0; 1181 struct wi_frame tx_frame; 1182 struct ether_header *eh; 1183 int id; 1184 1185 sc = ifp->if_softc; 1186 1187 if (sc->wi_gone) 1188 return; 1189 1190 if (ifp->if_flags & IFF_OACTIVE) 1191 return; 1192 1193 IF_DEQUEUE(&ifp->if_snd, m0); 1194 if (m0 == NULL) 1195 return; 1196 1197 bzero((char *)&tx_frame, sizeof(tx_frame)); 1198 id = sc->wi_tx_data_id; 1199 eh = mtod(m0, struct ether_header *); 1200 1201 /* 1202 * Use RFC1042 encoding for IP and ARP datagrames, 1203 * 802.3 for anything else. 1204 */ 1205 if (ntohs(eh->ether_type) == ETHERTYPE_IP || 1206 ntohs(eh->ether_type) == ETHERTYPE_ARP || 1207 ntohs(eh->ether_type) == ETHERTYPE_REVARP) { 1208 bcopy((char *)&eh->ether_dhost, 1209 (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); 1210 bcopy((char *)&eh->ether_shost, 1211 (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); 1212 bcopy((char *)&eh->ether_dhost, 1213 (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); 1214 bcopy((char *)&eh->ether_shost, 1215 (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); 1216 1217 tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; 1218 tx_frame.wi_frame_ctl = WI_FTYPE_DATA; 1219 tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); 1220 tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); 1221 tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); 1222 tx_frame.wi_type = eh->ether_type; 1223 1224 m_copydata(m0, sizeof(struct ether_header), 1225 m0->m_pkthdr.len - sizeof(struct ether_header), 1226 (caddr_t)&sc->wi_txbuf); 1227 1228 wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 1229 sizeof(struct wi_frame)); 1230 wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf, 1231 (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); 1232 } else { 1233 tx_frame.wi_dat_len = m0->m_pkthdr.len; 1234 1235 m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); 1236 1237 wi_write_data(sc, id, 0, (caddr_t)&tx_frame, 1238 sizeof(struct wi_frame)); 1239 wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf, 1240 m0->m_pkthdr.len + 2); 1241 } 1242 1243#if NBPFILTER > 0 1244 /* 1245 * If there's a BPF listner, bounce a copy of 1246 * this frame to him. 1247 */ 1248 if (ifp->if_bpf) 1249 bpf_mtap(ifp, m0); 1250#endif 1251 1252 m_freem(m0); 1253 1254 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) 1255 printf("wi%d: xmit failed\n", sc->wi_unit); 1256 1257 ifp->if_flags |= IFF_OACTIVE; 1258 1259 /* 1260 * Set a timeout in case the chip goes out to lunch. 1261 */ 1262 ifp->if_timer = 5; 1263 1264 return; 1265} 1266 1267static int wi_mgmt_xmit(sc, data, len) 1268 struct wi_softc *sc; 1269 caddr_t data; 1270 int len; 1271{ 1272 struct wi_frame tx_frame; 1273 int id; 1274 struct wi_80211_hdr *hdr; 1275 caddr_t dptr; 1276 1277 if (sc->wi_gone) 1278 return(ENODEV); 1279 1280 hdr = (struct wi_80211_hdr *)data; 1281 dptr = data + sizeof(struct wi_80211_hdr); 1282 1283 bzero((char *)&tx_frame, sizeof(tx_frame)); 1284 id = sc->wi_tx_mgmt_id; 1285 1286 bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, 1287 sizeof(struct wi_80211_hdr)); 1288 1289 tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN; 1290 tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); 1291 1292 wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); 1293 wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, 1294 (len - sizeof(struct wi_80211_hdr)) + 2); 1295 1296 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) { 1297 printf("wi%d: xmit failed\n", sc->wi_unit); 1298 return(EIO); 1299 } 1300 1301 return(0); 1302} 1303 1304static void wi_stop(sc) 1305 struct wi_softc *sc; 1306{ 1307 struct ifnet *ifp; 1308 1309 if (sc->wi_gone) 1310 return; 1311 1312 ifp = &sc->arpcom.ac_if; 1313 1314 CSR_WRITE_2(sc, WI_INT_EN, 0); 1315 wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0); 1316 1317 untimeout(wi_inquire, sc, sc->wi_stat_ch); 1318 1319 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 1320 1321 return; 1322} 1323 1324static void wi_watchdog(ifp) 1325 struct ifnet *ifp; 1326{ 1327 struct wi_softc *sc; 1328 1329 sc = ifp->if_softc; 1330 1331 printf("wi%d: device timeout\n", sc->wi_unit); 1332 1333 wi_init(sc); 1334 1335 ifp->if_oerrors++; 1336 1337 return; 1338} 1339 1340static void wi_shutdown(howto, arg) 1341 int howto; 1342 void *arg; 1343{ 1344 struct wi_softc *sc; 1345 1346 sc = arg; 1347 wi_stop(sc); 1348 1349 return; 1350} 1351