FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_wi.c
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 * $FreeBSD$
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 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 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)
118 static const char rcsid[] =
119 "$FreeBSD$";
120 #endif
121
122 static struct wi_softc wi_softc[NWI];
123
124 #ifdef foo
125 static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
126 #endif
127
128 static int wi_probe __P((struct isa_device *));
129 static int wi_attach __P((struct isa_device *));
130 #ifdef PCCARD_MODULE
131 static ointhand2_t wi_intr;
132 #endif
133 static void wi_reset __P((struct wi_softc *));
134 static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
135 static void wi_init __P((void *));
136 static void wi_start __P((struct ifnet *));
137 static void wi_stop __P((struct wi_softc *));
138 static void wi_watchdog __P((struct ifnet *));
139 static void wi_shutdown __P((int, void *));
140 static void wi_rxeof __P((struct wi_softc *));
141 static void wi_txeof __P((struct wi_softc *, int));
142 static void wi_update_stats __P((struct wi_softc *));
143 static void wi_setmulti __P((struct wi_softc *));
144
145 static int wi_cmd __P((struct wi_softc *, int, int));
146 static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *));
147 static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *));
148 static int wi_read_data __P((struct wi_softc *, int,
149 int, caddr_t, int));
150 static int wi_write_data __P((struct wi_softc *, int,
151 int, caddr_t, int));
152 static int wi_seek __P((struct wi_softc *, int, int, int));
153 static int wi_alloc_nicmem __P((struct wi_softc *, int, int *));
154 static void wi_inquire __P((void *));
155 static void wi_setdef __P((struct wi_softc *, struct wi_req *));
156 static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int));
157
158 struct isa_driver widriver = {
159 wi_probe,
160 wi_attach,
161 "wi",
162 1
163 };
164
165 #if NCARD > 0
166 static int wi_pccard_init __P((struct pccard_devinfo *));
167 static void wi_pccard_unload __P((struct pccard_devinfo *));
168 static int wi_pccard_intr __P((struct pccard_devinfo *));
169
170 #ifdef PCCARD_MODULE
171 PCCARD_MODULE(wi, wi_pccard_init, wi_pccard_unload,
172 wi_pccard_intr, 0, net_imask);
173 #else
174 static 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
184 DATA_SET(pccarddrv_set, wi_info);
185 #endif
186
187 /* Initialize the PCCARD. */
188 static 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
230 static 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
252 static 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
260 static 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 bridge adapter
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
273 static 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
376 static 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 if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
419 printf("wi%d: oversized packet received "
420 "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
421 rx_frame.wi_dat_len, rx_frame.wi_status);
422 m_freem(m);
423 ifp->if_ierrors++;
424 return;
425 }
426 m->m_pkthdr.len = m->m_len =
427 rx_frame.wi_dat_len + WI_SNAPHDR_LEN;
428
429 bcopy((char *)&rx_frame.wi_addr1,
430 (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
431 bcopy((char *)&rx_frame.wi_addr2,
432 (char *)&eh->ether_shost, ETHER_ADDR_LEN);
433 bcopy((char *)&rx_frame.wi_type,
434 (char *)&eh->ether_type, sizeof(u_int16_t));
435
436 if (wi_read_data(sc, id, WI_802_11_OFFSET,
437 mtod(m, caddr_t) + sizeof(struct ether_header),
438 m->m_len + 2)) {
439 m_freem(m);
440 ifp->if_ierrors++;
441 return;
442 }
443 } else {
444 if((rx_frame.wi_dat_len +
445 sizeof(struct ether_header)) > MCLBYTES) {
446 printf("wi%d: oversized packet received "
447 "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
448 rx_frame.wi_dat_len, rx_frame.wi_status);
449 m_freem(m);
450 ifp->if_ierrors++;
451 return;
452 }
453 m->m_pkthdr.len = m->m_len =
454 rx_frame.wi_dat_len + sizeof(struct ether_header);
455
456 if (wi_read_data(sc, id, WI_802_3_OFFSET,
457 mtod(m, caddr_t), m->m_len + 2)) {
458 m_freem(m);
459 ifp->if_ierrors++;
460 return;
461 }
462 }
463
464 ifp->if_ipackets++;
465
466 #if NBPFILTER > 0
467 /* Handle BPF listeners. */
468 if (ifp->if_bpf) {
469 bpf_mtap(ifp, m);
470 if (ifp->if_flags & IFF_PROMISC &&
471 (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
472 ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) {
473 m_freem(m);
474 return;
475 }
476 }
477 #endif
478
479 /* Receive packet. */
480 m_adj(m, sizeof(struct ether_header));
481 ether_input(ifp, eh, m);
482
483 return;
484 }
485
486 static void wi_txeof(sc, status)
487 struct wi_softc *sc;
488 int status;
489 {
490 struct ifnet *ifp;
491
492 ifp = &sc->arpcom.ac_if;
493
494 ifp->if_timer = 0;
495 ifp->if_flags &= ~IFF_OACTIVE;
496
497 if (status & WI_EV_TX_EXC)
498 ifp->if_oerrors++;
499 else
500 ifp->if_opackets++;
501
502 return;
503 }
504
505 void wi_inquire(xsc)
506 void *xsc;
507 {
508 struct wi_softc *sc;
509 struct ifnet *ifp;
510
511 sc = xsc;
512 ifp = &sc->arpcom.ac_if;
513
514 sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60);
515
516 /* Don't do this while we're transmitting */
517 if (ifp->if_flags & IFF_OACTIVE)
518 return;
519
520 wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS);
521
522 return;
523 }
524
525 void wi_update_stats(sc)
526 struct wi_softc *sc;
527 {
528 struct wi_ltv_gen gen;
529 u_int16_t id;
530 struct ifnet *ifp;
531 u_int32_t *ptr;
532 int i;
533 u_int16_t t;
534
535 ifp = &sc->arpcom.ac_if;
536
537 id = CSR_READ_2(sc, WI_INFO_FID);
538
539 wi_read_data(sc, id, 0, (char *)&gen, 4);
540
541 if (gen.wi_type != WI_INFO_COUNTERS ||
542 gen.wi_len > (sizeof(sc->wi_stats) / 4) + 1)
543 return;
544
545 ptr = (u_int32_t *)&sc->wi_stats;
546
547 for (i = 0; i < gen.wi_len - 1; i++) {
548 t = CSR_READ_2(sc, WI_DATA1);
549 #ifdef WI_HERMES_STATS_WAR
550 if (t > 0xF000)
551 t = ~t & 0xFFFF;
552 #endif
553 ptr[i] += t;
554 }
555
556 ifp->if_collisions = sc->wi_stats.wi_tx_single_retries +
557 sc->wi_stats.wi_tx_multi_retries +
558 sc->wi_stats.wi_tx_retry_limit;
559
560 return;
561 }
562
563 void wi_intr(unit)
564 int unit;
565 {
566 struct wi_softc *sc;
567 struct ifnet *ifp;
568 u_int16_t status;
569
570 sc = &wi_softc[unit];
571 ifp = &sc->arpcom.ac_if;
572
573 if (!(ifp->if_flags & IFF_UP)) {
574 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
575 CSR_WRITE_2(sc, WI_INT_EN, 0);
576 return;
577 }
578
579 /* Disable interrupts. */
580 CSR_WRITE_2(sc, WI_INT_EN, 0);
581
582 status = CSR_READ_2(sc, WI_EVENT_STAT);
583 CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS);
584
585 if (status & WI_EV_RX) {
586 wi_rxeof(sc);
587 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
588 }
589
590 if (status & WI_EV_TX) {
591 wi_txeof(sc, status);
592 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
593 }
594
595 if (status & WI_EV_ALLOC) {
596 int id;
597 id = CSR_READ_2(sc, WI_ALLOC_FID);
598 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
599 if (id == sc->wi_tx_data_id)
600 wi_txeof(sc, status);
601 }
602
603 if (status & WI_EV_INFO) {
604 wi_update_stats(sc);
605 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
606 }
607
608 if (status & WI_EV_TX_EXC) {
609 wi_txeof(sc, status);
610 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
611 }
612
613 if (status & WI_EV_INFO_DROP) {
614 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP);
615 }
616
617 /* Re-enable interrupts. */
618 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
619
620 if (ifp->if_snd.ifq_head != NULL)
621 wi_start(ifp);
622
623 return;
624 }
625
626 static int wi_cmd(sc, cmd, val)
627 struct wi_softc *sc;
628 int cmd;
629 int val;
630 {
631 int i, s = 0;
632
633 CSR_WRITE_2(sc, WI_PARAM0, val);
634 CSR_WRITE_2(sc, WI_COMMAND, cmd);
635
636 for (i = 0; i < WI_TIMEOUT; i++) {
637 /*
638 * Wait for 'command complete' bit to be
639 * set in the event status register.
640 */
641 s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD;
642 if (s) {
643 /* Ack the event and read result code. */
644 s = CSR_READ_2(sc, WI_STATUS);
645 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
646 #ifdef foo
647 if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK))
648 return(EIO);
649 #endif
650 if (s & WI_STAT_CMD_RESULT)
651 return(EIO);
652 break;
653 }
654 }
655
656 if (i == WI_TIMEOUT)
657 return(ETIMEDOUT);
658
659 return(0);
660 }
661
662 static void wi_reset(sc)
663 struct wi_softc *sc;
664 {
665 if (wi_cmd(sc, WI_CMD_INI, 0))
666 printf("wi%d: init failed\n", sc->wi_unit);
667 CSR_WRITE_2(sc, WI_INT_EN, 0);
668 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
669
670 /* Calibrate timer. */
671 WI_SETVAL(WI_RID_TICK_TIME, 8);
672
673 return;
674 }
675
676 /*
677 * Read an LTV record from the NIC.
678 */
679 static int wi_read_record(sc, ltv)
680 struct wi_softc *sc;
681 struct wi_ltv_gen *ltv;
682 {
683 u_int16_t *ptr;
684 int i, len, code;
685
686 /* Tell the NIC to enter record read mode. */
687 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type))
688 return(EIO);
689
690 /* Seek to the record. */
691 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
692 return(EIO);
693
694 /*
695 * Read the length and record type and make sure they
696 * match what we expect (this verifies that we have enough
697 * room to hold all of the returned data).
698 */
699 len = CSR_READ_2(sc, WI_DATA1);
700 if (len > ltv->wi_len)
701 return(ENOSPC);
702 code = CSR_READ_2(sc, WI_DATA1);
703 if (code != ltv->wi_type)
704 return(EIO);
705
706 ltv->wi_len = len;
707 ltv->wi_type = code;
708
709 /* Now read the data. */
710 ptr = <v->wi_val;
711 for (i = 0; i < ltv->wi_len - 1; i++)
712 ptr[i] = CSR_READ_2(sc, WI_DATA1);
713
714 return(0);
715 }
716
717 /*
718 * Same as read, except we inject data instead of reading it.
719 */
720 static int wi_write_record(sc, ltv)
721 struct wi_softc *sc;
722 struct wi_ltv_gen *ltv;
723 {
724 u_int16_t *ptr;
725 int i;
726
727 if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
728 return(EIO);
729
730 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len);
731 CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type);
732
733 ptr = <v->wi_val;
734 for (i = 0; i < ltv->wi_len - 1; i++)
735 CSR_WRITE_2(sc, WI_DATA1, ptr[i]);
736
737 if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type))
738 return(EIO);
739
740 return(0);
741 }
742
743 static int wi_seek(sc, id, off, chan)
744 struct wi_softc *sc;
745 int id, off, chan;
746 {
747 int i;
748 int selreg, offreg;
749
750 switch (chan) {
751 case WI_BAP0:
752 selreg = WI_SEL0;
753 offreg = WI_OFF0;
754 break;
755 case WI_BAP1:
756 selreg = WI_SEL1;
757 offreg = WI_OFF1;
758 break;
759 default:
760 printf("wi%d: invalid data path: %x\n", sc->wi_unit, chan);
761 return(EIO);
762 }
763
764 CSR_WRITE_2(sc, selreg, id);
765 CSR_WRITE_2(sc, offreg, off);
766
767 for (i = 0; i < WI_TIMEOUT; i++) {
768 if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
769 break;
770 }
771
772 if (i == WI_TIMEOUT)
773 return(ETIMEDOUT);
774
775 return(0);
776 }
777
778 static int wi_read_data(sc, id, off, buf, len)
779 struct wi_softc *sc;
780 int id, off;
781 caddr_t buf;
782 int len;
783 {
784 int i;
785 u_int16_t *ptr;
786
787 if (wi_seek(sc, id, off, WI_BAP1))
788 return(EIO);
789
790 ptr = (u_int16_t *)buf;
791 for (i = 0; i < len / 2; i++)
792 ptr[i] = CSR_READ_2(sc, WI_DATA1);
793
794 return(0);
795 }
796
797 /*
798 * According to the comments in the HCF Light code, there is a bug in
799 * the Hermes (or possibly in certain Hermes firmware revisions) where
800 * the chip's internal autoincrement counter gets thrown off during
801 * data writes: the autoincrement is missed, causing one data word to
802 * be overwritten and subsequent words to be written to the wrong memory
803 * locations. The end result is that we could end up transmitting bogus
804 * frames without realizing it. The workaround for this is to write a
805 * couple of extra guard words after the end of the transfer, then
806 * attempt to read then back. If we fail to locate the guard words where
807 * we expect them, we preform the transfer over again.
808 */
809 static int wi_write_data(sc, id, off, buf, len)
810 struct wi_softc *sc;
811 int id, off;
812 caddr_t buf;
813 int len;
814 {
815 int i;
816 u_int16_t *ptr;
817
818 #ifdef WI_HERMES_AUTOINC_WAR
819 again:
820 #endif
821
822 if (wi_seek(sc, id, off, WI_BAP0))
823 return(EIO);
824
825 ptr = (u_int16_t *)buf;
826 for (i = 0; i < (len / 2); i++)
827 CSR_WRITE_2(sc, WI_DATA0, ptr[i]);
828
829 #ifdef WI_HERMES_AUTOINC_WAR
830 CSR_WRITE_2(sc, WI_DATA0, 0x1234);
831 CSR_WRITE_2(sc, WI_DATA0, 0x5678);
832
833 if (wi_seek(sc, id, off + len, WI_BAP0))
834 return(EIO);
835
836 if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
837 CSR_READ_2(sc, WI_DATA0) != 0x5678)
838 goto again;
839 #endif
840
841 return(0);
842 }
843
844 /*
845 * Allocate a region of memory inside the NIC and zero
846 * it out.
847 */
848 static int wi_alloc_nicmem(sc, len, id)
849 struct wi_softc *sc;
850 int len;
851 int *id;
852 {
853 int i;
854
855 if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) {
856 printf("wi%d: failed to allocate %d bytes on NIC\n",
857 sc->wi_unit, len);
858 return(ENOMEM);
859 }
860
861 for (i = 0; i < WI_TIMEOUT; i++) {
862 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
863 break;
864 }
865
866 if (i == WI_TIMEOUT)
867 return(ETIMEDOUT);
868
869 CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
870 *id = CSR_READ_2(sc, WI_ALLOC_FID);
871
872 if (wi_seek(sc, *id, 0, WI_BAP0))
873 return(EIO);
874
875 for (i = 0; i < len / 2; i++)
876 CSR_WRITE_2(sc, WI_DATA0, 0);
877
878 return(0);
879 }
880
881 static void wi_setmulti(sc)
882 struct wi_softc *sc;
883 {
884 struct ifnet *ifp;
885 int i = 0;
886 struct ifmultiaddr *ifma;
887 struct wi_ltv_mcast mcast;
888
889 ifp = &sc->arpcom.ac_if;
890
891 bzero((char *)&mcast, sizeof(mcast));
892
893 mcast.wi_type = WI_RID_MCAST;
894 mcast.wi_len = (3 * 16) + 1;
895
896 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
897 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
898 return;
899 }
900
901 for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
902 ifma = ifma->ifma_link.le_next) {
903 if (ifma->ifma_addr->sa_family != AF_LINK)
904 continue;
905 if (i < 16) {
906 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
907 (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN);
908 i++;
909 } else {
910 bzero((char *)&mcast, sizeof(mcast));
911 break;
912 }
913 }
914
915 mcast.wi_len = (i * 3) + 1;
916 wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
917
918 return;
919 }
920
921 static void wi_setdef(sc, wreq)
922 struct wi_softc *sc;
923 struct wi_req *wreq;
924 {
925 struct sockaddr_dl *sdl;
926 struct ifaddr *ifa;
927 struct ifnet *ifp;
928
929 ifp = &sc->arpcom.ac_if;
930
931 switch(wreq->wi_type) {
932 case WI_RID_MAC_NODE:
933 ifa = ifnet_addrs[ifp->if_index - 1];
934 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
935 bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr,
936 ETHER_ADDR_LEN);
937 bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
938 break;
939 case WI_RID_PORTTYPE:
940 sc->wi_ptype = wreq->wi_val[0];
941 break;
942 case WI_RID_TX_RATE:
943 sc->wi_tx_rate = wreq->wi_val[0];
944 break;
945 case WI_RID_MAX_DATALEN:
946 sc->wi_max_data_len = wreq->wi_val[0];
947 break;
948 case WI_RID_RTS_THRESH:
949 sc->wi_rts_thresh = wreq->wi_val[0];
950 break;
951 case WI_RID_SYSTEM_SCALE:
952 sc->wi_ap_density = wreq->wi_val[0];
953 break;
954 case WI_RID_CREATE_IBSS:
955 sc->wi_create_ibss = wreq->wi_val[0];
956 break;
957 case WI_RID_OWN_CHNL:
958 sc->wi_channel = wreq->wi_val[0];
959 break;
960 case WI_RID_NODENAME:
961 bzero(sc->wi_node_name, sizeof(sc->wi_node_name));
962 bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30);
963 break;
964 case WI_RID_DESIRED_SSID:
965 bzero(sc->wi_net_name, sizeof(sc->wi_net_name));
966 bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30);
967 break;
968 case WI_RID_OWN_SSID:
969 bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name));
970 bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30);
971 break;
972 case WI_RID_PM_ENABLED:
973 sc->wi_pm_enabled = wreq->wi_val[0];
974 break;
975 case WI_RID_MAX_SLEEP:
976 sc->wi_max_sleep = wreq->wi_val[0];
977 break;
978 default:
979 break;
980 }
981
982 /* Reinitialize WaveLAN. */
983 wi_init(sc);
984
985 return;
986 }
987
988 static int wi_ioctl(ifp, command, data)
989 struct ifnet *ifp;
990 u_long command;
991 caddr_t data;
992 {
993 int s, error = 0;
994 struct wi_softc *sc;
995 struct wi_req wreq;
996 struct ifreq *ifr;
997
998 s = splimp();
999
1000 sc = ifp->if_softc;
1001 ifr = (struct ifreq *)data;
1002
1003 if (sc->wi_gone)
1004 return(ENODEV);
1005
1006 switch(command) {
1007 case SIOCSIFADDR:
1008 case SIOCGIFADDR:
1009 case SIOCSIFMTU:
1010 error = ether_ioctl(ifp, command, data);
1011 break;
1012 case SIOCSIFFLAGS:
1013 if (ifp->if_flags & IFF_UP) {
1014 if (ifp->if_flags & IFF_RUNNING &&
1015 ifp->if_flags & IFF_PROMISC &&
1016 !(sc->wi_if_flags & IFF_PROMISC)) {
1017 WI_SETVAL(WI_RID_PROMISC, 1);
1018 } else if (ifp->if_flags & IFF_RUNNING &&
1019 !(ifp->if_flags & IFF_PROMISC) &&
1020 sc->wi_if_flags & IFF_PROMISC) {
1021 WI_SETVAL(WI_RID_PROMISC, 0);
1022 } else
1023 wi_init(sc);
1024 } else {
1025 if (ifp->if_flags & IFF_RUNNING) {
1026 wi_stop(sc);
1027 }
1028 }
1029 sc->wi_if_flags = ifp->if_flags;
1030 error = 0;
1031 break;
1032 case SIOCADDMULTI:
1033 case SIOCDELMULTI:
1034 wi_setmulti(sc);
1035 error = 0;
1036 break;
1037 case SIOCGWAVELAN:
1038 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1039 if (error)
1040 break;
1041 if (wreq.wi_type == WI_RID_IFACE_STATS) {
1042 bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
1043 sizeof(sc->wi_stats));
1044 wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
1045 } else {
1046 if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) {
1047 error = EINVAL;
1048 break;
1049 }
1050 }
1051 error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1052 break;
1053 case SIOCSWAVELAN:
1054 error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1055 if (error)
1056 break;
1057 if (wreq.wi_type == WI_RID_IFACE_STATS) {
1058 error = EINVAL;
1059 break;
1060 } else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
1061 error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
1062 wreq.wi_len);
1063 } else {
1064 error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
1065 if (!error)
1066 wi_setdef(sc, &wreq);
1067 }
1068 break;
1069 default:
1070 error = EINVAL;
1071 break;
1072 }
1073
1074 splx(s);
1075
1076 return(error);
1077 }
1078
1079 static void wi_init(xsc)
1080 void *xsc;
1081 {
1082 struct wi_softc *sc = xsc;
1083 struct ifnet *ifp = &sc->arpcom.ac_if;
1084 int s;
1085 struct wi_ltv_macaddr mac;
1086 int id = 0;
1087
1088 if (sc->wi_gone)
1089 return;
1090
1091 s = splimp();
1092
1093 if (ifp->if_flags & IFF_RUNNING)
1094 wi_stop(sc);
1095
1096 wi_reset(sc);
1097
1098 /* Program max data length. */
1099 WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
1100
1101 /* Enable/disable IBSS creation. */
1102 WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
1103
1104 /* Set the port type. */
1105 WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
1106
1107 /* Program the RTS/CTS threshold. */
1108 WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
1109
1110 /* Program the TX rate */
1111 WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate);
1112
1113 /* Access point density */
1114 WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density);
1115
1116 /* Power Management Enabled */
1117 WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled);
1118
1119 /* Power Managment Max Sleep */
1120 WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
1121
1122 /* Specify the IBSS name */
1123 WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name);
1124
1125 /* Specify the network name */
1126 WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
1127
1128 /* Specify the frequency to use */
1129 WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel);
1130
1131 /* Program the nodename. */
1132 WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name);
1133
1134 /* Set our MAC address. */
1135 mac.wi_len = 4;
1136 mac.wi_type = WI_RID_MAC_NODE;
1137 bcopy((char *)&sc->arpcom.ac_enaddr,
1138 (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN);
1139 wi_write_record(sc, (struct wi_ltv_gen *)&mac);
1140
1141 /* Initialize promisc mode. */
1142 if (ifp->if_flags & IFF_PROMISC) {
1143 WI_SETVAL(WI_RID_PROMISC, 1);
1144 } else {
1145 WI_SETVAL(WI_RID_PROMISC, 0);
1146 }
1147
1148 /* Set multicast filter. */
1149 wi_setmulti(sc);
1150
1151 /* Enable desired port */
1152 wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
1153
1154 if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
1155 printf("wi%d: tx buffer allocation failed\n", sc->wi_unit);
1156 sc->wi_tx_data_id = id;
1157
1158 if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
1159 printf("wi%d: mgmt. buffer allocation failed\n", sc->wi_unit);
1160 sc->wi_tx_mgmt_id = id;
1161
1162 /* enable interrupts */
1163 CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
1164
1165 splx(s);
1166
1167 ifp->if_flags |= IFF_RUNNING;
1168 ifp->if_flags &= ~IFF_OACTIVE;
1169
1170 sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60);
1171
1172 return;
1173 }
1174
1175 static void wi_start(ifp)
1176 struct ifnet *ifp;
1177 {
1178 struct wi_softc *sc;
1179 struct mbuf *m0;
1180 struct wi_frame tx_frame;
1181 struct ether_header *eh;
1182 int id;
1183
1184 sc = ifp->if_softc;
1185
1186 if (sc->wi_gone)
1187 return;
1188
1189 if (ifp->if_flags & IFF_OACTIVE)
1190 return;
1191
1192 IF_DEQUEUE(&ifp->if_snd, m0);
1193 if (m0 == NULL)
1194 return;
1195
1196 bzero((char *)&tx_frame, sizeof(tx_frame));
1197 id = sc->wi_tx_data_id;
1198 eh = mtod(m0, struct ether_header *);
1199
1200 /*
1201 * Use RFC1042 encoding for IP and ARP datagrams,
1202 * 802.3 for anything else.
1203 */
1204 if (ntohs(eh->ether_type) == ETHERTYPE_IP ||
1205 ntohs(eh->ether_type) == ETHERTYPE_ARP ||
1206 ntohs(eh->ether_type) == ETHERTYPE_REVARP) {
1207 bcopy((char *)&eh->ether_dhost,
1208 (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN);
1209 bcopy((char *)&eh->ether_shost,
1210 (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN);
1211 bcopy((char *)&eh->ether_dhost,
1212 (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN);
1213 bcopy((char *)&eh->ether_shost,
1214 (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN);
1215
1216 tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN;
1217 tx_frame.wi_frame_ctl = WI_FTYPE_DATA;
1218 tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0);
1219 tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1);
1220 tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN);
1221 tx_frame.wi_type = eh->ether_type;
1222
1223 m_copydata(m0, sizeof(struct ether_header),
1224 m0->m_pkthdr.len - sizeof(struct ether_header),
1225 (caddr_t)&sc->wi_txbuf);
1226
1227 wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
1228 sizeof(struct wi_frame));
1229 wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf,
1230 (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2);
1231 } else {
1232 tx_frame.wi_dat_len = m0->m_pkthdr.len;
1233
1234 m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf);
1235
1236 wi_write_data(sc, id, 0, (caddr_t)&tx_frame,
1237 sizeof(struct wi_frame));
1238 wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf,
1239 m0->m_pkthdr.len + 2);
1240 }
1241
1242 #if NBPFILTER > 0
1243 /*
1244 * If there's a BPF listner, bounce a copy of
1245 * this frame to him.
1246 */
1247 if (ifp->if_bpf)
1248 bpf_mtap(ifp, m0);
1249 #endif
1250
1251 m_freem(m0);
1252
1253 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
1254 printf("wi%d: xmit failed\n", sc->wi_unit);
1255
1256 ifp->if_flags |= IFF_OACTIVE;
1257
1258 /*
1259 * Set a timeout in case the chip goes out to lunch.
1260 */
1261 ifp->if_timer = 5;
1262
1263 return;
1264 }
1265
1266 static int wi_mgmt_xmit(sc, data, len)
1267 struct wi_softc *sc;
1268 caddr_t data;
1269 int len;
1270 {
1271 struct wi_frame tx_frame;
1272 int id;
1273 struct wi_80211_hdr *hdr;
1274 caddr_t dptr;
1275
1276 if (sc->wi_gone)
1277 return(ENODEV);
1278
1279 hdr = (struct wi_80211_hdr *)data;
1280 dptr = data + sizeof(struct wi_80211_hdr);
1281
1282 bzero((char *)&tx_frame, sizeof(tx_frame));
1283 id = sc->wi_tx_mgmt_id;
1284
1285 bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl,
1286 sizeof(struct wi_80211_hdr));
1287
1288 tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN;
1289 tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN);
1290
1291 wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame));
1292 wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr,
1293 (len - sizeof(struct wi_80211_hdr)) + 2);
1294
1295 if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
1296 printf("wi%d: xmit failed\n", sc->wi_unit);
1297 return(EIO);
1298 }
1299
1300 return(0);
1301 }
1302
1303 static void wi_stop(sc)
1304 struct wi_softc *sc;
1305 {
1306 struct ifnet *ifp;
1307
1308 if (sc->wi_gone)
1309 return;
1310
1311 ifp = &sc->arpcom.ac_if;
1312
1313 CSR_WRITE_2(sc, WI_INT_EN, 0);
1314 wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0);
1315
1316 untimeout(wi_inquire, sc, sc->wi_stat_ch);
1317
1318 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
1319
1320 return;
1321 }
1322
1323 static void wi_watchdog(ifp)
1324 struct ifnet *ifp;
1325 {
1326 struct wi_softc *sc;
1327
1328 sc = ifp->if_softc;
1329
1330 printf("wi%d: device timeout\n", sc->wi_unit);
1331
1332 wi_init(sc);
1333
1334 ifp->if_oerrors++;
1335
1336 return;
1337 }
1338
1339 static void wi_shutdown(howto, arg)
1340 int howto;
1341 void *arg;
1342 {
1343 struct wi_softc *sc;
1344
1345 sc = arg;
1346 wi_stop(sc);
1347
1348 return;
1349 }
Cache object: 747b8eb0782c794cc1fe3b1dc12d0bb9
|