]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/isa/if_wl.c
In ascpoll, return revents, not 0.
[FreeBSD/FreeBSD.git] / sys / i386 / isa / if_wl.c
1 /* $FreeBSD$ */
2 /* 
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  * 1. Redistributions of source code must retain all copyright 
7  *    notices, this list of conditions and the following disclaimer.
8  * 2. The names of the authors may not be used to endorse or promote products
9  *    derived from this software withough specific prior written permission
10  *
11  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
12  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21  * 
22  */
23 /*
24  * if_wl.c - original MACH, then BSDI ISA wavelan driver
25  *      ported to mach by Anders Klemets
26  *      to BSDI by Robert Morris
27  *      to FreeBSD by Jim Binkley
28  *      to FreeBSD 2.2+ by Michael Smith
29  *
30  * 2.2 update:
31  * Changed interface to match 2.1-2.2 differences.
32  * Implement IRQ selection logic in wlprobe()
33  * Implement PSA updating.
34  * Pruned heading comments for relevance.
35  * Ripped out all the 'interface counters' cruft.
36  * Cut the missing-interrupt timer back to 100ms.
37  * 2.2.1 update:
38  * now supports all multicast mode (mrouted will work),
39  *      but unfortunately must do that by going into promiscuous mode
40  * NWID sysctl added so that normally promiscuous mode is NWID-specific
41  *      but can be made NWID-inspecific
42  *                      7/14/97 jrb
43  *
44  * Work done:
45  * Ported to FreeBSD, got promiscuous mode working with bpfs,
46  * and rewired timer routine.  The i82586 will hang occasionally on output 
47  * and the watchdog timer will kick it if so and log an entry.
48  * 2 second timeout there.  Apparently the chip loses an interrupt.
49  * Code borrowed from if_ie.c for watchdog timer.
50  *
51  * The wavelan card is a 2mbit radio modem that emulates ethernet;
52  * i.e., it uses MAC addresses.  This should not be a surprise since
53  * it uses an ethernet controller as a major hw item.
54  * It can broadcast, unicast or apparently multicast in a base cell 
55  * using a omni-directional antennae that is 
56  * about 800 feet around the base cell barring walls and metal.  
57  * With directional antennae, it can be used point to point over a mile
58  * or so apparently (haven't tried that).
59  *
60  * There are ISA and pcmcia versions (not supported by this code).
61  * The ISA card has an Intel 82586 lan controller on it.  It consists
62  * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
63  * The latter has an extra set of controller registers that has nothing
64  * to do with the i82586 and allows setting and monitoring of radio
65  * signal strength, etc.  There is a nvram area called the PSA that
66  * contains a number of setup variables including the IRQ and so-called
67  * NWID or Network ID.  The NWID must be set the same for all radio
68  * cards to communicate (unless you are using the ATT/NCR roaming feature
69  * with their access points.  There is no support for that here. Roaming
70  * involves a link-layer beacon sent out from the access points.  End
71  * stations monitor the signal strength and only use the strongest
72  * access point).  This driver assumes that the base ISA port, IRQ, 
73  * and NWID are first set in nvram via the dos-side "instconf.exe" utility 
74  * supplied with the card. This driver takes the ISA port from 
75  * the kernel configuration setup, and then determines the IRQ either 
76  * from the kernel config (if an explicit IRQ is set) or from the 
77  * PSA on the card if not.
78  * The hw also magically just uses the IRQ set in the nvram.
79  * The NWID is used magically as well by the radio-modem
80  * to determine which packets to keep or throw out.  
81  *
82  * sample config:
83  *
84  * device wl0 at isa? port 0x300 net irq ?
85  *
86  * Ifdefs:
87  * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
88  * 2. MULTICAST (on) - turned on and works up to and including mrouted
89  * 3. WLCACHE (off) -  define to turn on a signal strength 
90  * (and other metric) cache that is indexed by sender MAC address.  
91  * Apps can read this out to learn the remote signal strength of a 
92  * sender.  Note that it has a switch so that it only stores 
93  * broadcast/multicast senders but it could be set to store unicast 
94  * too only.  Size is hardwired in if_wl_wavelan.h
95  *
96  * one further note: promiscuous mode is a curious thing.  In this driver,
97  * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
98  * setting.  This is probably more useful in a sense (for snoopers) if
99  * you are interested in all traffic as opposed to if you are interested
100  * in just your own.  There is a driver specific sysctl to turn promiscuous
101  * from just promiscuous to wildly promiscuous...
102  *
103  * This driver also knows how to load the synthesizers in the 2.4 Gz
104  * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
105  * This product consists of a "mothercard" that contains the 82586,
106  * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC. 
107  * The radio transceiver is a "daughtercard" called the WaveMODEM which
108  * connects to the mothercard through two single-inline connectors: a
109  * 20-pin connector provides DC-power and modem signals, and a 3-pin
110  * connector which exports the antenna connection. The code herein
111  * loads the receive and transmit synthesizers and the corresponding
112  * transmitter output power value from an EEPROM controlled through
113  * additional registers via the MMC. The EEPROM address selected
114  * are those whose values are preset by the DOS utility programs
115  * provided with the product, and this provides compatible operation
116  * with the DOS Packet Driver software. A future modification will
117  * add the necessary functionality to this driver and to the wlconfig
118  * utility to completely replace the DOS Configuration Utilities.
119  * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
120  * and is available through Lucent Technologies OEM supply channels.
121  * --RAB 1997/06/08.
122  */
123
124 #define MULTICAST  1
125
126 /* 
127  *      Olivetti PC586 Mach Ethernet driver v1.0
128  *      Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
129  *      All rights reserved.
130  *
131  */ 
132
133 /*
134   Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
135 Cupertino, California.
136
137                 All Rights Reserved
138
139   Permission to use, copy, modify, and distribute this software and
140 its documentation for any purpose and without fee is hereby
141 granted, provided that the above copyright notice appears in all
142 copies and that both the copyright notice and this permission notice
143 appear in supporting documentation, and that the name of Olivetti
144 not be used in advertising or publicity pertaining to distribution
145 of the software without specific, written prior permission.
146
147   OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
154 */
155
156 /*
157   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
158
159                 All Rights Reserved
160
161 Permission to use, copy, modify, and distribute this software and
162 its documentation for any purpose and without fee is hereby
163 granted, provided that the above copyright notice appears in all
164 copies and that both the copyright notice and this permission notice
165 appear in supporting documentation, and that the name of Intel
166 not be used in advertising or publicity pertaining to distribution
167 of the software without specific, written prior permission.
168
169 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176 */
177
178 /*
179  * NOTE:
180  *              by rvb:
181  *  1.  The best book on the 82586 is:
182  *              LAN Components User's Manual by Intel
183  *      The copy I found was dated 1984.  This really tells you
184  *      what the state machines are doing
185  *  2.  In the current design, we only do one write at a time,
186  *      though the hardware is capable of chaining and possibly
187  *      even batching.  The problem is that we only make one
188  *      transmit buffer available in sram space.
189  */
190
191 #include "wl.h"
192 #include "opt_wavelan.h"
193 #include "opt_inet.h"
194
195 #include <sys/param.h>
196 #include <sys/systm.h>
197 #include <sys/kernel.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/bus.h>
203
204 #include <sys/sysctl.h>
205
206 #include <net/ethernet.h>
207 #include <net/if.h>
208 #include <net/if_dl.h>
209
210 #ifdef INET
211 #include <netinet/in.h>
212 #include <netinet/in_systm.h>
213 #include <netinet/ip.h>
214 #include <netinet/if_ether.h>
215 #endif
216
217 #include <net/bpf.h>
218
219
220 #include <i386/isa/isa_device.h>
221
222 #include <i386/isa/ic/if_wl_i82586.h>   /* Definitions for the Intel chip */
223
224 /* was 1000 in original, fed to DELAY(x) */
225 #define DELAYCONST      1000
226 #include <i386/isa/if_wl.h>
227 #include <machine/if_wl_wavelan.h>
228
229 #ifndef COMPAT_OLDISA
230 #error "The wl device requires the old isa compatibility shims"
231 #endif
232
233 static char     t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
234
235 struct wl_softc{ 
236     struct      arpcom  wl_ac;                  /* Ethernet common part */
237 #define wl_if   wl_ac.ac_if                     /* network visible interface */
238 #define wl_addr wl_ac.ac_enaddr                 /* hardware address */
239     u_char      psa[0x40];
240     u_char      nwid[2];        /* current radio modem nwid */
241     short       base;
242     short       unit;
243     int         flags;
244     int         tbusy;          /* flag to determine if xmit is busy */
245     u_short     begin_fd;
246     u_short     end_fd;
247     u_short     end_rbd;
248     u_short     hacr;           /* latest host adapter CR command */
249     short       mode;
250     u_char      chan24;         /* 2.4 Gz: channel number/EEPROM Area # */
251     u_short     freq24;         /* 2.4 Gz: resulting frequency  */
252     struct      callout_handle watchdog_ch;
253 #ifdef WLCACHE
254     int         w_sigitems;     /* number of cached entries */
255     /*  array of cache entries */
256     struct w_sigcache w_sigcache[ MAXCACHEITEMS ];            
257     int w_nextcache;            /* next free cache entry */    
258     int w_wrapindex;            /* next "free" cache entry */
259 #endif
260 };
261 static struct wl_softc wl_softc[NWL];
262
263 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
264
265 static int      wlprobe(struct isa_device *);
266 static int      wlattach(struct isa_device *);
267
268 struct isa_driver wldriver = {
269         INTR_TYPE_NET,
270         wlprobe,
271         wlattach,
272         "wl",
273         0
274 };
275 COMPAT_ISA_DRIVER(wl, wldriver);
276
277 /*
278  * XXX  The Wavelan appears to be prone to dropping stuff if you talk to
279  * it too fast.  This disgusting hack inserts a delay after each packet
280  * is queued which helps avoid this behaviour on fast systems.
281  */
282 static int      wl_xmit_delay = 250;
283 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
284
285 /* 
286  * not XXX, but ZZZ (bizarre).
287  * promiscuous mode can be toggled to ignore NWIDs.  By default,
288  * it does not.  Caution should be exercised about combining
289  * this mode with IFF_ALLMULTI which puts this driver in
290  * promiscuous mode.
291  */
292 static int      wl_ignore_nwid = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
294
295 /*
296  * Emit diagnostics about transmission problems
297  */
298 static int      xmt_watch = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
300
301 /*
302  * Collect SNR statistics
303  */
304 static int      gathersnr = 0;
305 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
306
307 static void     wlstart(struct ifnet *ifp);
308 static void     wlinit(void *xsc);
309 static int      wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
310 static timeout_t wlwatchdog;
311 static ointhand2_t wlintr;
312 static void     wlxmt(int unt, struct mbuf *m);
313 static int      wldiag(int unt); 
314 static int      wlconfig(int unit); 
315 static int      wlcmd(int unit, char *str);
316 static void     wlmmcstat(int unit);
317 static u_short  wlbldru(int unit);
318 static u_short  wlmmcread(u_int base, u_short reg);
319 static void     wlinitmmc(int unit);
320 static int      wlhwrst(int unit);
321 static void     wlrustrt(int unit);
322 static void     wlbldcu(int unit);
323 static int      wlack(int unit);
324 static int      wlread(int unit, u_short fd_p);
325 static void     getsnr(int unit);
326 static void     wlrcv(int unit);
327 static int      wlrequeue(int unit, u_short fd_p);
328 static void     wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
329 static void     wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
330 static void     wltbd(int unit);
331 static void     wlgetpsa(int base, u_char *buf);
332 static void     wlsetpsa(int unit);
333 static u_short  wlpsacrc(u_char *buf);
334 static void     wldump(int unit);
335 #ifdef WLCACHE
336 static void     wl_cache_store(int, int, struct ether_header *, struct mbuf *);
337 static void     wl_cache_zero(int unit);
338 #endif
339 #ifdef MULTICAST
340 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
341 static int      check_allmulti(int unit);
342 # endif
343 #endif
344
345 /* array for maping irq numbers to values for the irq parameter register */
346 static int irqvals[16] = { 
347     0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 
348 };
349 /* mask of valid IRQs */
350 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
351
352 /*
353  * wlprobe:
354  *
355  *      This function "probes" or checks for the WaveLAN board on the bus to
356  *      see if it is there.  As far as I can tell, the best break between this
357  *      routine and the attach code is to simply determine whether the board
358  *      is configured in properly.  Currently my approach to this is to write
359  *      and read a word from the SRAM on the board being probed.  If the word
360  *      comes back properly then we assume the board is there.  The config
361  *      code expects to see a successful return from the probe routine before
362  *      attach will be called.
363  *
364  * input        : address device is mapped to, and unit # being checked
365  * output       : a '1' is returned if the board exists, and a 0 otherwise
366  *
367  */
368 static int
369 wlprobe(struct isa_device *id)
370 {
371     struct wl_softc     *sc = &wl_softc[id->id_unit];   
372     register short      base = id->id_iobase;
373     char                *str = "wl%d: board out of range [0..%d]\n";
374     u_char              inbuf[100];
375     unsigned long       oldpri;
376     int                 irq;
377
378     /* TBD. not true.
379      * regular CMD() will not work, since no softc yet 
380      */
381 #define PCMD(base, hacr) outw((base), (hacr))
382
383     oldpri = splimp();
384     PCMD(base, HACR_RESET);                     /* reset the board */
385     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
386     PCMD(base, HACR_RESET);                     /* reset the board */
387     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
388     splx(oldpri);
389
390     /* clear reset command and set PIO#1 in autoincrement mode */
391     PCMD(base, HACR_DEFAULT);
392     PCMD(base, HACR_DEFAULT);
393     outw(PIOR1(base), 0);                       /* go to beginning of RAM */
394     outsw(PIOP1(base), str, strlen(str)/2+1);   /* write string */
395     
396     outw(PIOR1(base), 0);                       /* rewind */
397     insw(PIOP1(base), inbuf, strlen(str)/2+1);  /* read result */
398     
399     if (bcmp(str, inbuf, strlen(str)))
400         return(0);
401
402     sc->chan24 = 0;                             /* 2.4 Gz: config channel */
403     sc->freq24 = 0;                             /* 2.4 Gz: frequency    */
404
405     /* read the PSA from the board into temporary storage */
406     wlgetpsa(base, inbuf);
407     
408     /* We read the IRQ value from the PSA on the board. */
409     for (irq = 15; irq >= 0; irq--)
410         if (irqvals[irq] == inbuf[WLPSA_IRQNO])
411             break;
412     if ((irq == 0) || (irqvals[irq] == 0)){
413         printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
414         id->id_irq = 0;                         /* no interrupt */
415     } else {
416         /*
417          * If the IRQ requested by the PSA is already claimed by another
418          * device, the board won't work, but the user can still access the
419          * driver to change the IRQ.
420          */
421         id->id_irq = (1<<irq);                  /* use IRQ from PSA */
422     }
423     return(16);
424 }
425
426
427 /*
428  * wlattach:
429  *
430  *      This function attaches a WaveLAN board to the "system".  The rest of
431  *      runtime structures are initialized here (this routine is called after
432  *      a successful probe of the board).  Once the ethernet address is read
433  *      and stored, the board's ifnet structure is attached and readied.
434  *
435  * input        : isa_dev structure setup in autoconfig
436  * output       : board structs and ifnet is setup
437  *
438  */
439 static int
440 wlattach(struct isa_device *id)
441 {
442     struct wl_softc     *sc = (struct wl_softc *) &wl_softc[id->id_unit];
443     register short      base = id->id_iobase;
444     int                 i,j;
445     u_char              unit = id->id_unit;
446     register struct ifnet       *ifp = &sc->wl_if;
447
448 #ifdef WLDEBUG
449     printf("wlattach: base %x, unit %d\n", base, unit);
450 #endif
451     id->id_ointr = wlintr;
452     sc->base = base;
453     sc->unit = unit;
454     sc->flags = 0;
455     sc->mode = 0;
456     sc->hacr = HACR_RESET;
457     callout_handle_init(&sc->watchdog_ch);
458     CMD(unit);                          /* reset the board */
459     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
460         
461     /* clear reset command and set PIO#2 in parameter access mode */
462     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
463     CMD(unit);
464
465     /* Read the PSA from the board for our later reference */
466     wlgetpsa(base, sc->psa);
467
468     /* fetch NWID */
469     sc->nwid[0] = sc->psa[WLPSA_NWID];
470     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
471     
472     /* fetch MAC address - decide which one first */
473     if (sc->psa[WLPSA_MACSEL] & 1) {
474         j = WLPSA_LOCALMAC;
475     } else {
476         j = WLPSA_UNIMAC;
477     }
478     for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
479         sc->wl_addr[i] = sc->psa[j + i];
480     }
481
482     /* enter normal 16 bit mode operation */
483     sc->hacr = HACR_DEFAULT;
484     CMD(unit);
485
486     wlinitmmc(unit);
487     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
488     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
489     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
490     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
491     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
492
493     bzero(ifp, sizeof(ifp));
494     ifp->if_softc = sc;
495     ifp->if_unit = id->id_unit;
496     ifp->if_mtu = WAVELAN_MTU;
497     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
498 #ifdef    WLDEBUG
499     ifp->if_flags |= IFF_DEBUG;
500 #endif
501 #if     MULTICAST
502     ifp->if_flags |= IFF_MULTICAST;
503 #endif  /* MULTICAST */
504     ifp->if_name = "wl";
505     ifp->if_unit = unit;
506     ifp->if_init = wlinit;
507     ifp->if_output = ether_output;
508     ifp->if_start = wlstart;
509     ifp->if_ioctl = wlioctl;
510     ifp->if_timer = 0;   /* paranoia */
511     /* no entries
512        ifp->if_watchdog
513        ifp->if_done
514        ifp->if_reset
515        */
516     ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
517
518     bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
519     printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
520            sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
521     if (sc->freq24) 
522         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
523     printf("\n");                                       /* 2.4 Gz       */
524
525
526     if (bootverbose)
527         wldump(unit);
528     return(1);
529 }
530
531 /*
532  * Print out interesting information about the 82596.
533  */
534 static void
535 wldump(int unit)
536 {
537     register struct wl_softc *sp = WLSOFTC(unit);
538     int         base = sp->base;
539     int         i;
540         
541     printf("hasr %04x\n", inw(HASR(base)));
542         
543     printf("scb at %04x:\n ", OFFSET_SCB);
544     outw(PIOR1(base), OFFSET_SCB);
545     for(i = 0; i < 8; i++)
546         printf("%04x ", inw(PIOP1(base)));
547     printf("\n");
548         
549     printf("cu at %04x:\n ", OFFSET_CU);
550     outw(PIOR1(base), OFFSET_CU);
551     for(i = 0; i < 8; i++)
552         printf("%04x ", inw(PIOP1(base)));
553     printf("\n");
554         
555     printf("tbd at %04x:\n ", OFFSET_TBD);
556     outw(PIOR1(base), OFFSET_TBD);
557     for(i = 0; i < 4; i++)
558         printf("%04x ", inw(PIOP1(base)));
559     printf("\n");
560 }
561
562 /* Initialize the Modem Management Controller */
563 static void
564 wlinitmmc(int unit)
565 {
566     register struct wl_softc *sp = WLSOFTC(unit);
567     int         base = sp->base;
568     int         configured;
569     int         mode = sp->mode;
570     int         i;                              /* 2.4 Gz               */
571         
572     /* enter 8 bit operation */
573     sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
574     CMD(unit);
575
576     configured = sp->psa[WLPSA_CONFIGURED] & 1;
577         
578     /*
579      * Set default modem control parameters.  Taken from NCR document
580      *  407-0024326 Rev. A 
581      */
582     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
583     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
584     MMC_WRITE(MMC_IFS, 0x20);
585     MMC_WRITE(MMC_MOD_DELAY, 0x04);
586     MMC_WRITE(MMC_JAM_TIME, 0x38);
587     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
588     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
589     if (!configured) {
590         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
591         if (sp->psa[WLPSA_COMPATNO] & 1) {
592             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
593         } else {
594             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
595         }
596         MMC_WRITE(MMC_QUALITY_THR, 0x03);
597     } else {
598         /* use configuration defaults from parameter storage area */
599         if (sp->psa[WLPSA_NWIDENABLE] & 1) {
600             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
601                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
602             } else {
603                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
604             }
605         } else {
606             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
607         }
608         MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
609         MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
610     }
611     MMC_WRITE(MMC_FREEZE, 0x00);
612     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
613
614     MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]);       /* set NWID */
615     MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
616
617     /* enter normal 16 bit mode operation */
618     sp->hacr = HACR_DEFAULT;
619     CMD(unit);
620     CMD(unit);                                  /* virtualpc1 needs this! */
621
622     if (sp->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
623                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
624         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
625         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
626         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
627                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
628         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
629             DELAY(40);                          /* 2.4 Gz             */
630             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
631                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
632                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
633                 break;                          /* 2.4 Gz: download finished */
634         }                                       /* 2.4 Gz                    */
635         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
636         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
637         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
638                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
639         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
640             DELAY(40);                          /* 2.4 Gz             */
641             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
642                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
643                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
644                 break;                          /* 2.4 Gz: download finished */
645         }                                       /* 2.4 Gz                    */
646         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
647         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
648                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
649                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
650         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
651         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
652         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
653                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
654         DELAY(40);                              /* 2.4 Gz                    */
655         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
656           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
657         sp->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
658     }
659 }
660
661 /*
662  * wlinit:
663  *
664  *      Another routine that interfaces the "if" layer to this driver.  
665  *      Simply resets the structures that are used by "upper layers".  
666  *      As well as calling wlhwrst that does reset the WaveLAN board.
667  *
668  * input        : softc pointer for this interface
669  * output       : structures (if structs) and board are reset
670  *
671  */     
672 static void
673 wlinit(void *xsc)
674 {
675     register struct wl_softc *sc = xsc;
676     struct ifnet        *ifp = &sc->wl_if;
677     int                 stat;
678     u_long              oldpri;
679
680 #ifdef WLDEBUG
681     if (sc->wl_if.if_flags & IFF_DEBUG)
682         printf("wl%d: entered wlinit()\n",sc->unit);
683 #endif
684 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
685     if (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0) {
686 #else
687     if (ifp->if_addrlist == (struct ifaddr *)0) {
688 #endif
689         return;
690     }
691     oldpri = splimp();
692     if ((stat = wlhwrst(sc->unit)) == TRUE) {
693         sc->wl_if.if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
694         /* 
695          * OACTIVE is used by upper-level routines
696          * and must be set
697          */
698         sc->wl_if.if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
699                 
700         sc->flags |= DSF_RUNNING;
701         sc->tbusy = 0;
702         untimeout(wlwatchdog, sc, sc->watchdog_ch);
703                 
704         wlstart(ifp);
705     } else {
706         printf("wl%d init(): trouble resetting board.\n", sc->unit);
707     }
708     splx(oldpri);
709 }
710
711 /*
712  * wlhwrst:
713  *
714  *      This routine resets the WaveLAN board that corresponds to the 
715  *      board number passed in.
716  *
717  * input        : board number to do a hardware reset
718  * output       : board is reset
719  *
720  */
721 static int
722 wlhwrst(int unit)
723 {
724     register struct wl_softc    *sc = WLSOFTC(unit);
725
726 #ifdef WLDEBUG
727     if (sc->wl_if.if_flags & IFF_DEBUG)
728         printf("wl%d: entered wlhwrst()\n",unit);
729 #endif
730     sc->hacr = HACR_RESET;
731     CMD(unit);                  /* reset the board */
732         
733     /* clear reset command and set PIO#1 in autoincrement mode */
734     sc->hacr = HACR_DEFAULT;
735     CMD(unit);
736
737 #ifdef  WLDEBUG
738     if (sc->wl_if.if_flags & IFF_DEBUG)
739         wlmmcstat(unit);        /* Display MMC registers */
740 #endif  /* WLDEBUG */
741     wlbldcu(unit);              /* set up command unit structures */
742     
743     if (wldiag(unit) == 0)
744         return(0);
745     
746     if (wlconfig(unit) == 0)
747             return(0);
748     /* 
749      * insert code for loopback test here
750      */
751     wlrustrt(unit);             /* start receive unit */
752
753     /* enable interrupts */
754     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
755     CMD(unit);
756     
757     return(1);
758 }
759
760 /*
761  * wlbldcu:
762  *
763  *      This function builds up the command unit structures.  It inits
764  *      the scp, iscp, scb, cb, tbd, and tbuf.
765  *
766  */
767 static void
768 wlbldcu(int unit)
769 {
770     register struct wl_softc *sc = WLSOFTC(unit);
771     short               base = sc->base;
772     scp_t               scp;
773     iscp_t              iscp;
774     scb_t               scb;
775     ac_t                cb;
776     tbd_t               tbd;
777     int         i;
778
779     bzero(&scp, sizeof(scp));
780     scp.scp_sysbus = 0;
781     scp.scp_iscp = OFFSET_ISCP;
782     scp.scp_iscp_base = 0;
783     outw(PIOR1(base), OFFSET_SCP);
784     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
785
786     bzero(&iscp, sizeof(iscp));
787     iscp.iscp_busy = 1;
788     iscp.iscp_scb_offset = OFFSET_SCB;
789     iscp.iscp_scb = 0;
790     iscp.iscp_scb_base = 0;
791     outw(PIOR1(base), OFFSET_ISCP);
792     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
793
794     scb.scb_status = 0;
795     scb.scb_command = SCB_RESET;
796     scb.scb_cbl_offset = OFFSET_CU;
797     scb.scb_rfa_offset = OFFSET_RU;
798     scb.scb_crcerrs = 0;
799     scb.scb_alnerrs = 0;
800     scb.scb_rscerrs = 0;
801     scb.scb_ovrnerrs = 0;
802     outw(PIOR1(base), OFFSET_SCB);
803     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
804
805     SET_CHAN_ATTN(unit);
806
807     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
808     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
809     if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
810     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
811     for (i = STATUS_TRIES; i-- > 0; ) {
812         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
813             break;
814     }
815     if (i <= 0)
816         printf("wl%d bldcu(): not ready after reset.\n", unit);
817     wlack(unit);
818
819     cb.ac_status = 0;
820     cb.ac_command = AC_CW_EL;           /* NOP */
821     cb.ac_link_offset = OFFSET_CU;
822     outw(PIOR1(base), OFFSET_CU);
823     outsw(PIOP1(base), &cb, 6/2);
824
825     tbd.act_count = 0;
826     tbd.next_tbd_offset = I82586NULL;
827     tbd.buffer_addr = 0;
828     tbd.buffer_base = 0;
829     outw(PIOR1(base), OFFSET_TBD);
830     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
831 }
832
833 /*
834  * wlstart:
835  *
836  *      send a packet
837  *
838  * input        : board number
839  * output       : stuff sent to board if any there
840  *
841  */
842 static void
843 wlstart(struct ifnet *ifp)
844 {
845     int                         unit = ifp->if_unit;
846     struct mbuf                 *m;
847     register struct wl_softc    *sc = WLSOFTC(unit);
848     short                       base = sc->base;
849     int                         scb_status, cu_status, scb_command;
850
851 #ifdef WLDEBUG
852     if (sc->wl_if.if_flags & IFF_DEBUG)
853         printf("wl%d: entered wlstart()\n",unit);
854 #endif
855
856     outw(PIOR1(base), OFFSET_CU);
857     cu_status = inw(PIOP1(base));
858     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
859     scb_status = inw(PIOP0(base));
860     outw(PIOR0(base), OFFSET_SCB + 2);
861     scb_command = inw(PIOP0(base));
862
863     /*
864      * don't need OACTIVE check as tbusy here checks to see
865      * if we are already busy 
866      */
867     if (sc->tbusy) {
868         if((scb_status & 0x0700) == SCB_CUS_IDLE &&
869            (cu_status & AC_SW_B) == 0){
870             sc->tbusy = 0;
871             untimeout(wlwatchdog, sc, sc->watchdog_ch);
872             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
873             /*
874              * This is probably just a race.  The xmt'r is just
875              * became idle but WE have masked interrupts so ...
876              */
877 #ifdef WLDEBUG
878             printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
879                    unit, scb_status, scb_command, cu_status);
880 #endif 
881             if (xmt_watch) printf("!!");
882         } else {
883             return;     /* genuinely still busy */
884         }
885     } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
886               (cu_status & AC_SW_B)){
887 #ifdef WLDEBUG
888         printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
889                unit, scb_status, cu_status);
890 #endif
891         if (xmt_watch) printf("wl%d: busy?!",unit);
892         return;         /* hey, why are we busy? */
893     }
894
895     /* get ourselves some data */
896     ifp = &(sc->wl_if);
897     IF_DEQUEUE(&ifp->if_snd, m);
898     if (m != (struct mbuf *)0) {
899         /* let BPF see it before we commit it */
900         if (ifp->if_bpf) {
901             bpf_mtap(ifp, m);
902         }
903         sc->tbusy++;
904         /* set the watchdog timer so that if the board
905          * fails to interrupt we will restart
906          */
907         /* try 10 ticks, not very long */
908         sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
909         sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
910         sc->wl_if.if_opackets++;
911         wlxmt(unit, m);
912     } else {
913         sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
914     }
915     return;
916 }
917
918 /*
919  * wlread:
920  *
921  *      This routine does the actual copy of data (including ethernet header
922  *      structure) from the WaveLAN to an mbuf chain that will be passed up
923  *      to the "if" (network interface) layer.  NOTE:  we currently
924  *      don't handle trailer protocols, so if that is needed, it will
925  *      (at least in part) be added here.  For simplicities sake, this
926  *      routine copies the receive buffers from the board into a local (stack)
927  *      buffer until the frame has been copied from the board.  Once in
928  *      the local buffer, the contents are copied to an mbuf chain that
929  *      is then enqueued onto the appropriate "if" queue.
930  *
931  * input        : board number, and an frame descriptor address
932  * output       : the packet is put into an mbuf chain, and passed up
933  * assumes      : if any errors occur, packet is "dropped on the floor"
934  *
935  */
936 static int
937 wlread(int unit, u_short fd_p)
938 {
939     register struct wl_softc    *sc = WLSOFTC(unit);
940     register struct ifnet       *ifp = &sc->wl_if;
941     short                       base = sc->base;
942     fd_t                        fd;
943     struct ether_header         eh;
944     struct mbuf                 *m, *tm;
945     rbd_t                       rbd;
946     u_char                      *mb_p;
947     u_short                     mlen, len, clen;
948     u_short                     bytes_in_msg, bytes_in_mbuf, bytes;
949
950
951 #ifdef WLDEBUG
952     if (sc->wl_if.if_flags & IFF_DEBUG)
953         printf("wl%d: entered wlread()\n",unit);
954 #endif
955     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
956         printf("wl%d read(): board is not running.\n", ifp->if_unit);
957         sc->hacr &= ~HACR_INTRON;
958         CMD(unit);              /* turn off interrupts */
959     }
960     /* read ether_header info out of device memory. doesn't
961      * go into mbuf.  goes directly into eh structure
962      */
963     len = sizeof(struct ether_header);  /* 14 bytes */
964     outw(PIOR1(base), fd_p);
965     insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
966     insw(PIOP1(base), &eh, (len-2)/2);
967     eh.ether_type = ntohs(inw(PIOP1(base)));
968 #ifdef WLDEBUG
969     if (sc->wl_if.if_flags & IFF_DEBUG) {
970         printf("wlread: rcv packet, type is %x\n", eh.ether_type);
971     }
972 #endif 
973     /*
974      * WARNING.  above is done now in ether_input, above may be
975      * useful for debug. jrb
976      */
977     eh.ether_type = htons(eh.ether_type);
978
979     if (fd.rbd_offset == I82586NULL) {
980         printf("wl%d read(): Invalid buffer\n", unit);
981         if (wlhwrst(unit) != TRUE) {
982             printf("wl%d read(): hwrst trouble.\n", unit);
983         }
984         return 0;
985     }
986
987     outw(PIOR1(base), fd.rbd_offset);
988     insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
989     bytes_in_msg = rbd.status & RBD_SW_COUNT;
990     MGETHDR(m, M_DONTWAIT, MT_DATA);
991     tm = m;
992     if (m == (struct mbuf *)0) {
993         /*
994          * not only do we want to return, we need to drop the packet on
995          * the floor to clear the interrupt.
996          *
997          */
998         if (wlhwrst(unit) != TRUE) {
999             sc->hacr &= ~HACR_INTRON;
1000             CMD(unit);          /* turn off interrupts */
1001             printf("wl%d read(): hwrst trouble.\n", unit);
1002         }
1003         return 0;
1004     }
1005     m->m_next = (struct mbuf *) 0;
1006     m->m_pkthdr.rcvif = ifp;
1007     m->m_pkthdr.len = 0; /* don't know this yet */
1008     m->m_len = MHLEN;
1009
1010     /* always use a cluster. jrb 
1011      */
1012     MCLGET(m, M_DONTWAIT);
1013     if (m->m_flags & M_EXT) {
1014         m->m_len = MCLBYTES;
1015     }
1016     else {
1017         m_freem(m);
1018         if (wlhwrst(unit) != TRUE) {
1019             sc->hacr &= ~HACR_INTRON;
1020             CMD(unit);          /* turn off interrupts */
1021             printf("wl%d read(): hwrst trouble.\n", unit);
1022         }
1023         return 0;
1024     }
1025
1026     mlen = 0;
1027     clen = mlen;
1028     bytes_in_mbuf = m->m_len;
1029     mb_p = mtod(tm, u_char *);
1030     bytes = min(bytes_in_mbuf, bytes_in_msg);
1031     for (;;) {
1032         if (bytes & 1) {
1033             len = bytes + 1;
1034         } else {
1035             len = bytes;
1036         }
1037         outw(PIOR1(base), rbd.buffer_addr);
1038         insw(PIOP1(base), mb_p, len/2);
1039         clen += bytes;
1040         mlen += bytes;
1041
1042         if (!(bytes_in_mbuf -= bytes)) {
1043             MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1044             tm = tm->m_next;
1045             if (tm == (struct mbuf *)0) {
1046                 m_freem(m);
1047                 printf("wl%d read(): No mbuf nth\n", unit);
1048                 if (wlhwrst(unit) != TRUE) {
1049                     sc->hacr &= ~HACR_INTRON;
1050                     CMD(unit);  /* turn off interrupts */
1051                     printf("wl%d read(): hwrst trouble.\n", unit);
1052                 }
1053                 return 0;
1054             }
1055             mlen = 0;
1056             tm->m_len = MLEN;
1057             bytes_in_mbuf = MLEN;
1058             mb_p = mtod(tm, u_char *);
1059         } else {
1060             mb_p += bytes;
1061         }
1062
1063         if (!(bytes_in_msg  -= bytes)) {
1064             if (rbd.status & RBD_SW_EOF ||
1065                 rbd.next_rbd_offset == I82586NULL) {
1066                 tm->m_len = mlen;
1067                 break;
1068             } else {
1069                 outw(PIOR1(base), rbd.next_rbd_offset);
1070                 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1071                 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1072             }
1073         } else {
1074             rbd.buffer_addr += bytes;
1075         }
1076
1077         bytes = min(bytes_in_mbuf, bytes_in_msg);
1078     }
1079
1080     m->m_pkthdr.len = clen;
1081
1082     /*
1083      * If hw is in promiscuous mode (note that I said hardware, not if
1084      * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1085      * packet and the MAC dst is not us, drop it.  This check in normally
1086      * inside ether_input(), but IFF_MULTI causes hw promisc without
1087      * a bpf listener, so this is wrong.
1088      *          Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1089      */
1090     /*
1091      * TBD: also discard packets where NWID does not match.
1092      * However, there does not appear to be a way to read the nwid
1093      * for a received packet.  -gdt 1998-08-07
1094      */
1095     if (
1096 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1097         (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1098 #else
1099         /* hw is in promisc mode if this is true */
1100         (sc->mode & (MOD_PROM | MOD_ENAL))
1101 #endif
1102         &&
1103         (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1104         bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1105              sizeof(eh.ether_dhost)) != 0 ) {
1106       m_freem(m);
1107       return 1;
1108     }
1109
1110 #ifdef WLDEBUG
1111     if (sc->wl_if.if_flags & IFF_DEBUG)
1112         printf("wl%d: wlrecv %d bytes\n", unit, clen);
1113 #endif
1114
1115 #ifdef WLCACHE
1116     wl_cache_store(unit, base, &eh, m);
1117 #endif
1118
1119     /*
1120      * received packet is now in a chain of mbuf's.  next step is
1121      * to pass the packet upwards.
1122      *
1123      */
1124     ether_input(&sc->wl_if, &eh, m);
1125     return 1;
1126 }
1127
1128 /*
1129  * wlioctl:
1130  *
1131  *      This routine processes an ioctl request from the "if" layer
1132  *      above.
1133  *
1134  * input        : pointer the appropriate "if" struct, command, and data
1135  * output       : based on command appropriate action is taken on the
1136  *                WaveLAN board(s) or related structures
1137  * return       : error is returned containing exit conditions
1138  *
1139  */
1140 static int
1141 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1142 {
1143     register struct ifreq       *ifr = (struct ifreq *)data;
1144     int                         unit = ifp->if_unit;
1145     register struct wl_softc    *sc = WLSOFTC(unit);
1146     short               base = sc->base;
1147     short               mode = 0;
1148     int                 opri, error = 0;
1149     struct proc         *p = curproc;   /* XXX */
1150     int                 irq, irqval, i, isroot, size;
1151     caddr_t             up;
1152     char *              cpt;
1153         
1154
1155 #ifdef WLDEBUG
1156     if (sc->wl_if.if_flags & IFF_DEBUG)
1157         printf("wl%d: entered wlioctl()\n",unit);
1158 #endif
1159     opri = splimp();
1160     switch (cmd) {
1161     case SIOCSIFADDR:
1162     case SIOCGIFADDR:
1163     case SIOCSIFMTU:
1164         error = ether_ioctl(ifp, cmd, data);
1165         break;
1166
1167     case SIOCSIFFLAGS:
1168         if (ifp->if_flags & IFF_ALLMULTI) {
1169             mode |= MOD_ENAL;
1170         }
1171         if (ifp->if_flags & IFF_PROMISC) {
1172             mode |= MOD_PROM;
1173         }
1174         if(ifp->if_flags & IFF_LINK0) {
1175             mode |= MOD_PROM;
1176         }
1177         /*
1178          * force a complete reset if the recieve multicast/
1179          * promiscuous mode changes so that these take 
1180          * effect immediately.
1181          *
1182          */
1183         if (sc->mode != mode) {
1184             sc->mode = mode;
1185             if (sc->flags & DSF_RUNNING) {
1186                 sc->flags &= ~DSF_RUNNING;
1187                 wlinit(sc);
1188             }
1189         }
1190         /* if interface is marked DOWN and still running then
1191          * stop it.
1192          */
1193         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1194             printf("wl%d ioctl(): board is not running\n", unit);
1195             sc->flags &= ~DSF_RUNNING;
1196             sc->hacr &= ~HACR_INTRON;
1197             CMD(unit);            /* turn off interrupts */
1198         } 
1199         /* else if interface is UP and RUNNING, start it
1200                 */
1201         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1202             wlinit(sc);
1203         }
1204   
1205         /* if WLDEBUG set on interface, then printf rf-modem regs
1206         */
1207         if(ifp->if_flags & IFF_DEBUG)
1208             wlmmcstat(unit);
1209         break;
1210 #if     MULTICAST
1211     case SIOCADDMULTI:
1212     case SIOCDELMULTI:
1213
1214 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1215         if (cmd == SIOCADDMULTI) {
1216             error = ether_addmulti(ifr, &sc->wl_ac);
1217         }
1218         else {
1219             error = ether_delmulti(ifr, &sc->wl_ac);
1220         }
1221
1222         /* see if we should be in all multicast mode
1223          * note that 82586 cannot do that, must simulate with
1224          * promiscuous mode
1225          */
1226         if ( check_allmulti(unit)) {
1227                 ifp->if_flags |=  IFF_ALLMULTI;
1228                 sc->mode |= MOD_ENAL;
1229                 sc->flags &= ~DSF_RUNNING;
1230                 wlinit(sc);
1231                 error = 0;
1232                 break;
1233         }
1234
1235         if (error == ENETRESET) {
1236             if(sc->flags & DSF_RUNNING) {
1237                 sc->flags &= ~DSF_RUNNING;
1238                 wlinit(sc);
1239             }
1240             error = 0;
1241         }
1242 #else
1243         wlinit(sc);
1244 #endif
1245         break;
1246 #endif  /* MULTICAST */
1247
1248     /* DEVICE SPECIFIC */
1249
1250
1251         /* copy the PSA out to the caller */
1252     case SIOCGWLPSA:
1253         /* pointer to buffer in user space */
1254         up = (void *)ifr->ifr_data;
1255         /* work out if they're root */
1256         isroot = (suser(p) == 0);
1257         
1258         for (i = 0; i < 0x40; i++) {
1259             /* don't hand the DES key out to non-root users */
1260             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1261                 continue;
1262             if (subyte((up + i), sc->psa[i]))
1263                 return(EFAULT);
1264         }
1265         break;
1266
1267
1268         /* copy the PSA in from the caller; we only copy _some_ values */
1269     case SIOCSWLPSA:
1270         /* root only */
1271         if ((error = suser(p)))
1272             break;
1273         error = EINVAL; /* assume the worst */
1274         /* pointer to buffer in user space containing data */
1275         up = (void *)ifr->ifr_data;
1276         
1277         /* check validity of input range */
1278         for (i = 0; i < 0x40; i++)
1279             if (fubyte(up + i) < 0)
1280                 return(EFAULT);
1281
1282         /* check IRQ value */
1283         irqval = fubyte(up+WLPSA_IRQNO);
1284         for (irq = 15; irq >= 0; irq--)
1285             if(irqvals[irq] == irqval)
1286                 break;
1287         if (irq == 0)                   /* oops */
1288             break;
1289         /* new IRQ */
1290         sc->psa[WLPSA_IRQNO] = irqval;
1291
1292         /* local MAC */
1293         for (i = 0; i < 6; i++)
1294             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1295                 
1296         /* MAC select */        
1297         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1298         
1299         /* default nwid */
1300         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1301         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1302
1303         error = 0;
1304         wlsetpsa(unit);         /* update the PSA */
1305         break;
1306
1307
1308         /* get the current NWID out of the sc since we stored it there */
1309     case SIOCGWLCNWID:
1310         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1311         break;
1312
1313
1314         /*
1315          * change the nwid dynamically.  This
1316          * ONLY changes the radio modem and does not
1317          * change the PSA.
1318          *
1319          * 2 steps:
1320          *      1. save in softc "soft registers"
1321          *      2. save in radio modem (MMC)
1322          */
1323     case SIOCSWLCNWID:
1324         /* root only */
1325         if ((error = suser(p)))
1326             break;
1327         if (!(ifp->if_flags & IFF_UP)) {
1328             error = EIO;        /* only allowed while up */
1329         } else {
1330             /* 
1331              * soft c nwid shadows radio modem setting
1332              */
1333             sc->nwid[0] = (int)ifr->ifr_data >> 8;
1334             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1335             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1336             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1337         }
1338         break;
1339
1340         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
1341     case SIOCGWLEEPROM:
1342         /* root only */
1343         if ((error = suser(p)))
1344             break;
1345         /* pointer to buffer in user space */
1346         up = (void *)ifr->ifr_data;
1347         
1348         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
1349             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
1350             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
1351                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
1352             DELAY(40);                          /* 2.4 Gz                   */
1353             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
1354                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1355                ) return(EFAULT);                /* 2.4 Gz:                  */
1356             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
1357                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1358                ) return(EFAULT);                /* 2.4 Gz:                  */
1359         }
1360         break;
1361
1362 #ifdef WLCACHE
1363         /* zero (Delete) the wl cache */
1364     case SIOCDWLCACHE:
1365         /* root only */
1366         if ((error = suser(p)))
1367             break;
1368         wl_cache_zero(unit);
1369         break;
1370
1371         /* read out the number of used cache elements */
1372     case SIOCGWLCITEM:
1373         ifr->ifr_data = (caddr_t) sc->w_sigitems;
1374         break;
1375
1376         /* read out the wl cache */
1377     case SIOCGWLCACHE:
1378         /* pointer to buffer in user space */
1379         up = (void *)ifr->ifr_data;
1380         cpt = (char *) &sc->w_sigcache[0];
1381         size = sc->w_sigitems * sizeof(struct w_sigcache);
1382         
1383         for (i = 0; i < size; i++) {
1384             if (subyte((up + i), *cpt++))
1385                 return(EFAULT);
1386         }
1387         break;
1388 #endif
1389
1390     default:
1391         error = EINVAL;
1392     }
1393     splx(opri);
1394     return (error);
1395 }
1396
1397 /*
1398  * wlwatchdog():
1399  *
1400  * Called if the timer set in wlstart expires before an interrupt is received
1401  * from the wavelan.   It seems to lose interrupts sometimes.
1402  * The watchdog routine gets called if the transmitter failed to interrupt
1403  *
1404  * input        : which board is timing out
1405  * output       : board reset 
1406  *
1407  */
1408 static void
1409 wlwatchdog(void *vsc)
1410 {
1411     struct wl_softc *sc = vsc;
1412     int unit = sc->unit;
1413
1414     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1415     sc->wl_ac.ac_if.if_oerrors++;
1416     wlinit(sc);
1417 }
1418
1419 /*
1420  * wlintr:
1421  *
1422  *      This function is the interrupt handler for the WaveLAN
1423  *      board.  This routine will be called whenever either a packet
1424  *      is received, or a packet has successfully been transfered and
1425  *      the unit is ready to transmit another packet.
1426  *
1427  * input        : board number that interrupted
1428  * output       : either a packet is received, or a packet is transfered
1429  *
1430  */
1431 static void
1432 wlintr(unit)
1433 int unit;
1434 {
1435     register struct wl_softc *sc = &wl_softc[unit];
1436     short               base = sc->base;
1437     int                 ac_status;
1438     u_short             int_type, int_type1;
1439
1440 #ifdef WLDEBUG
1441     if (sc->wl_if.if_flags & IFF_DEBUG)
1442         printf("wl%d: wlintr() called\n",unit);
1443 #endif
1444
1445     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1446         /* handle interrupt from the modem management controler */
1447         /* This will clear the interrupt condition */ 
1448         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1449     }
1450
1451     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
1452         /* commented out. jrb.  it happens when reinit occurs
1453            printf("wlintr: int_type %x, dump follows\n", int_type);
1454            wldump(unit);
1455            */
1456         return;
1457     }
1458
1459     if (gathersnr)
1460         getsnr(unit);
1461     for(;;) {
1462         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
1463         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1464         if (int_type == 0)                      /* no interrupts left */
1465             break;
1466
1467         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
1468         /* make sure no bits disappeared (others may appear) */
1469         if ((int_type & int_type1) != int_type)
1470             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1471                    int_type1, int_type);
1472         int_type = int_type1;                   /* go with the new status */
1473         /* 
1474          * incoming packet
1475          */
1476         if (int_type & SCB_SW_FR) {
1477             sc->wl_if.if_ipackets++;
1478             wlrcv(unit);
1479         }
1480         /*
1481          * receiver not ready
1482          */
1483         if (int_type & SCB_SW_RNR) {
1484             sc->wl_if.if_ierrors++;
1485 #ifdef  WLDEBUG
1486             if (sc->wl_if.if_flags & IFF_DEBUG)
1487                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1488                        unit, sc->begin_fd);
1489 #endif
1490             wlrustrt(unit);
1491         }
1492         /*
1493          * CU not ready
1494          */
1495         if (int_type & SCB_SW_CNA) {
1496             /*
1497              * At present, we don't care about CNA's.  We
1498              * believe they are a side effect of XMT.
1499              */
1500         }
1501         if (int_type & SCB_SW_CX) {
1502             /*
1503              * At present, we only request Interrupt for
1504              * XMT.
1505              */
1506             outw(PIOR1(base), OFFSET_CU);       /* get command status */
1507             ac_status = inw(PIOP1(base));
1508
1509             if (xmt_watch) {                    /* report some anomalies */
1510
1511                 if (sc->tbusy == 0) {
1512                     printf("wl%d: xmt intr but not busy, CU %04x\n",
1513                            unit, ac_status);
1514                 }
1515                 if (ac_status == 0) {
1516                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
1517                 }
1518                 if (ac_status & AC_SW_A) {
1519                     printf("wl%d: xmt aborted\n",unit);
1520                 }
1521 #ifdef  notdef
1522                 if (ac_status & TC_CARRIER) {
1523                     printf("wl%d: no carrier\n", unit);
1524                 }
1525 #endif  /* notdef */
1526                 if (ac_status & TC_CLS) {
1527                     printf("wl%d: no CTS\n", unit);
1528                 }
1529                 if (ac_status & TC_DMA) {
1530                     printf("wl%d: DMA underrun\n", unit);
1531                 }
1532                 if (ac_status & TC_DEFER) {
1533                     printf("wl%d: xmt deferred\n",unit);
1534                 }
1535                 if (ac_status & TC_SQE) {
1536                     printf("wl%d: heart beat\n", unit);
1537                 }
1538                 if (ac_status & TC_COLLISION) {
1539                     printf("wl%d: too many collisions\n", unit);
1540                 }
1541             }
1542             /* if the transmit actually failed, or returned some status */
1543             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1544                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1545                     sc->wl_if.if_oerrors++;
1546                 }
1547                 /* count collisions */
1548                 sc->wl_if.if_collisions += (ac_status & 0xf);
1549                 /* if TC_COLLISION set and collision count zero, 16 collisions */
1550                 if ((ac_status & 0x20) == 0x20) {
1551                     sc->wl_if.if_collisions += 0x10;
1552                 }
1553             }
1554             sc->tbusy = 0;
1555             untimeout(wlwatchdog, sc, sc->watchdog_ch);
1556             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1557             wlstart(&(sc->wl_if));
1558         }
1559     }
1560     return;
1561 }
1562
1563 /*
1564  * wlrcv:
1565  *
1566  *      This routine is called by the interrupt handler to initiate a
1567  *      packet transfer from the board to the "if" layer above this
1568  *      driver.  This routine checks if a buffer has been successfully
1569  *      received by the WaveLAN.  If so, the routine wlread is called
1570  *      to do the actual transfer of the board data (including the
1571  *      ethernet header) into a packet (consisting of an mbuf chain).
1572  *
1573  * input        : number of the board to check
1574  * output       : if a packet is available, it is "sent up"
1575  *
1576  */
1577 static void
1578 wlrcv(int unit)
1579 {
1580     register struct wl_softc *sc = WLSOFTC(unit);
1581     short       base = sc->base;
1582     u_short     fd_p, status, offset, link_offset;
1583
1584 #ifdef WLDEBUG
1585     if (sc->wl_if.if_flags & IFF_DEBUG)
1586         printf("wl%d: entered wlrcv()\n",unit);
1587 #endif
1588     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1589
1590         outw(PIOR0(base), fd_p + 0);    /* address of status */
1591         status = inw(PIOP0(base));
1592         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
1593         link_offset = inw(PIOP1(base));
1594         offset = inw(PIOP1(base));      /* rbd_offset */
1595         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1596             if (wlhwrst(unit) != TRUE)
1597                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1598             return;
1599         } else if (status & AC_SW_C) {
1600             if (status == (RFD_DONE|RFD_RSC)) {
1601                 /* lost one */
1602 #ifdef  WLDEBUG
1603                 if (sc->wl_if.if_flags & IFF_DEBUG)
1604                     printf("wl%d RCV: RSC %x\n", unit, status);
1605 #endif
1606                 sc->wl_if.if_ierrors++;
1607             } else if (!(status & RFD_OK)) {
1608                 printf("wl%d RCV: !OK %x\n", unit, status);
1609                 sc->wl_if.if_ierrors++;
1610             } else if (status & 0xfff) {        /* can't happen */
1611                 printf("wl%d RCV: ERRs %x\n", unit, status);
1612                 sc->wl_if.if_ierrors++;
1613             } else if (!wlread(unit, fd_p))
1614                 return;
1615
1616             if (!wlrequeue(unit, fd_p)) {
1617                 /* abort on chain error */
1618                 if (wlhwrst(unit) != TRUE)
1619                     printf("wl%d rcv(): hwrst trouble.\n", unit);
1620                 return;
1621             }
1622             sc->begin_fd = link_offset;
1623         } else {
1624             break;
1625         }
1626     }
1627     return;
1628 }
1629
1630 /*
1631  * wlrequeue:
1632  *
1633  *      This routine puts rbd's used in the last receive back onto the
1634  *      free list for the next receive.
1635  *
1636  */
1637 static int
1638 wlrequeue(int unit, u_short fd_p)
1639 {
1640     register struct wl_softc *sc = WLSOFTC(unit);
1641     short               base = sc->base;
1642     fd_t                fd;
1643     u_short             l_rbdp, f_rbdp, rbd_offset;
1644
1645     outw(PIOR0(base), fd_p + 6);
1646     rbd_offset = inw(PIOP0(base));
1647     if ((f_rbdp = rbd_offset) != I82586NULL) {
1648         l_rbdp = f_rbdp;
1649         for(;;) {
1650             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
1651             if(inw(PIOP0(base)) & RBD_SW_EOF)
1652                 break;
1653             outw(PIOP0(base), 0);
1654             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
1655             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1656                 break;
1657         }
1658         outw(PIOP0(base), 0);
1659         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
1660         outw(PIOP0(base), I82586NULL);
1661         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
1662         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1663         outw(PIOR0(base), sc->end_rbd + 2);
1664         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
1665         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
1666         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1667         sc->end_rbd = l_rbdp;
1668     }
1669
1670     fd.status = 0;
1671     fd.command = AC_CW_EL;
1672     fd.link_offset = I82586NULL;
1673     fd.rbd_offset = I82586NULL;
1674     outw(PIOR1(base), fd_p);
1675     outsw(PIOP1(base), &fd, 8/2);
1676     
1677     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
1678     outw(PIOP1(base), 0);               /* command = 0 */
1679     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
1680     sc->end_fd = fd_p;
1681
1682     return 1;
1683 }
1684
1685 #ifdef  WLDEBUG
1686 static int xmt_debug = 0;
1687 #endif  /* WLDEBUG */
1688
1689 /*
1690  * wlxmt:
1691  *
1692  *      This routine fills in the appropriate registers and memory
1693  *      locations on the WaveLAN board and starts the board off on
1694  *      the transmit.
1695  *
1696  * input        : board number of interest, and a pointer to the mbuf
1697  * output       : board memory and registers are set for xfer and attention
1698  *
1699  */
1700 static void
1701 wlxmt(int unit, struct mbuf *m)
1702 {
1703     register struct wl_softc *sc = WLSOFTC(unit);
1704     register u_short            xmtdata_p = OFFSET_TBUF;
1705     register u_short            xmtshort_p;
1706     struct      mbuf                    *tm_p = m;
1707     register struct ether_header        *eh_p = mtod(m, struct ether_header *);
1708     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1709     u_short                             count = m->m_len - sizeof(struct ether_header);
1710     ac_t                                cb;
1711     u_short                             tbd_p = OFFSET_TBD;
1712     u_short                             len, clen = 0;
1713     short                               base = sc->base;
1714     int                                 spin;
1715         
1716 #ifdef WLDEBUG
1717     if (sc->wl_if.if_flags & IFF_DEBUG)
1718         printf("wl%d: entered wlxmt()\n",unit);
1719 #endif
1720
1721     cb.ac_status = 0;
1722     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1723     cb.ac_link_offset = I82586NULL;
1724     outw(PIOR1(base), OFFSET_CU);
1725     outsw(PIOP1(base), &cb, 6/2);
1726     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
1727     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1728     outw(PIOP1(base), eh_p->ether_type);
1729
1730 #ifdef  WLDEBUG
1731     if (sc->wl_if.if_flags & IFF_DEBUG) {
1732         if (xmt_debug) {
1733             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
1734             printf("ether type %x\n", eh_p->ether_type);
1735         }
1736     }
1737 #endif  /* WLDEBUG */
1738     outw(PIOR0(base), OFFSET_TBD);
1739     outw(PIOP0(base), 0);               /* act_count */
1740     outw(PIOR1(base), OFFSET_TBD + 4);
1741     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
1742     outw(PIOP1(base), 0);               /* buffer_base */
1743     for (;;) {
1744         if (count) {
1745             if (clen + count > WAVELAN_MTU)
1746                 break;
1747             if (count & 1)
1748                 len = count + 1;
1749             else
1750                 len = count;
1751             outw(PIOR1(base), xmtdata_p);
1752             outsw(PIOP1(base), mb_p, len/2);
1753             clen += count;
1754             outw(PIOR0(base), tbd_p);  /* address of act_count */
1755             outw(PIOP0(base), inw(PIOP0(base)) + count);
1756             xmtdata_p += len;
1757             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1758                 break;
1759             if (count & 1) {
1760                 /* go to the next descriptor */
1761                 outw(PIOR0(base), tbd_p + 2);
1762                 tbd_p += sizeof (tbd_t);
1763                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1764                 outw(PIOR0(base), tbd_p);
1765                 outw(PIOP0(base), 0);   /* act_count */
1766                 outw(PIOR1(base), tbd_p + 4);
1767                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1768                 outw(PIOP1(base), 0);         /* buffer_base */
1769                 /* at the end -> coallesce remaining mbufs */
1770                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1771                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1772                     continue;
1773                 }
1774                 /* next mbuf short -> coallesce as needed */
1775                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1776 #define HDW_THRESHOLD 55
1777                      tm_p->m_len > HDW_THRESHOLD)
1778                     /* ok */;
1779                 else {
1780                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1781                     continue;
1782                 }
1783             }
1784         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1785             break;
1786         count = tm_p->m_len;
1787         mb_p = mtod(tm_p, u_char *);
1788 #ifdef  WLDEBUG
1789         if (sc->wl_if.if_flags & IFF_DEBUG)
1790             if (xmt_debug)
1791                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1792 #endif  /* WLDEBUG */
1793     }
1794 #ifdef  WLDEBUG
1795     if (sc->wl_if.if_flags & IFF_DEBUG)
1796         if (xmt_debug)
1797             printf("CLEN = %d\n", clen);
1798 #endif  /* WLDEBUG */
1799     outw(PIOR0(base), tbd_p);
1800     if (clen < ETHERMIN) {
1801         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1802         outw(PIOR1(base), xmtdata_p);
1803         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1804             outw(PIOP1(base), 0);
1805     }   
1806     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1807     outw(PIOR0(base), tbd_p + 2);
1808     outw(PIOP0(base), I82586NULL);
1809 #ifdef  WLDEBUG
1810     if (sc->wl_if.if_flags & IFF_DEBUG) {
1811         if (xmt_debug) {
1812             wltbd(unit);
1813             printf("\n");
1814         }
1815     }
1816 #endif  /* WLDEBUG */
1817
1818     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
1819     /* 
1820      * wait for 586 to clear previous command, complain if it takes
1821      * too long
1822      */
1823     for (spin = 1;;spin = (spin + 1) % 10000) {
1824         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
1825             break;
1826         }
1827         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
1828                 printf("wl%d: slow accepting xmit\n",unit);
1829         }
1830     }
1831     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
1832     SET_CHAN_ATTN(unit);
1833     
1834     m_freem(m);
1835
1836     /* XXX 
1837      * Pause to avoid transmit overrun problems.
1838      * The required delay tends to vary with platform type, and may be
1839      * related to interrupt loss.
1840      */
1841     if (wl_xmit_delay) {
1842         DELAY(wl_xmit_delay);
1843     }
1844     return;
1845 }
1846
1847 /*
1848  * wlbldru:
1849  *
1850  *      This function builds the linear linked lists of fd's and
1851  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
1852  *
1853  */
1854 static u_short
1855 wlbldru(int unit)
1856 {
1857     register struct wl_softc *sc = WLSOFTC(unit);
1858     short       base = sc->base;
1859     fd_t        fd;
1860     rbd_t       rbd;
1861     u_short     fd_p = OFFSET_RU;
1862     u_short     rbd_p = OFFSET_RBD;
1863     int         i;
1864
1865     sc->begin_fd = fd_p;
1866     for(i = 0; i < N_FD; i++) {
1867         fd.status = 0;
1868         fd.command = 0;
1869         fd.link_offset = fd_p + sizeof(fd_t);
1870         fd.rbd_offset = I82586NULL;
1871         outw(PIOR1(base), fd_p);
1872         outsw(PIOP1(base), &fd, 8/2);
1873         fd_p = fd.link_offset;
1874     }
1875     fd_p -= sizeof(fd_t);
1876     sc->end_fd = fd_p;
1877     outw(PIOR1(base), fd_p + 2);
1878     outw(PIOP1(base), AC_CW_EL);        /* command */
1879     outw(PIOP1(base), I82586NULL);      /* link_offset */
1880     fd_p = OFFSET_RU;
1881     
1882     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
1883     outw(PIOP0(base), rbd_p);
1884     outw(PIOR1(base), rbd_p);
1885     for(i = 0; i < N_RBD; i++) {
1886         rbd.status = 0;
1887         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1888         rbd.buffer_base = 0;
1889         rbd.size = RCVBUFSIZE;
1890         if (i != N_RBD-1) {
1891             rbd_p += sizeof(ru_t);
1892             rbd.next_rbd_offset = rbd_p;
1893         } else {
1894             rbd.next_rbd_offset = I82586NULL;
1895             rbd.size |= AC_CW_EL;
1896             sc->end_rbd = rbd_p;
1897         }
1898         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1899         outw(PIOR1(base), rbd_p);
1900     }
1901     return sc->begin_fd;
1902 }
1903
1904 /*
1905  * wlrustrt:
1906  *
1907  *      This routine starts the receive unit running.  First checks if the
1908  *      board is actually ready, then the board is instructed to receive
1909  *      packets again.
1910  *
1911  */
1912 static void
1913 wlrustrt(int unit)
1914 {
1915     register struct wl_softc *sc = WLSOFTC(unit);
1916     short               base = sc->base;
1917     u_short             rfa;
1918
1919 #ifdef WLDEBUG
1920     if (sc->wl_if.if_flags & IFF_DEBUG)
1921         printf("wl%d: entered wlrustrt()\n",unit);
1922 #endif
1923     outw(PIOR0(base), OFFSET_SCB);
1924     if (inw(PIOP0(base)) & SCB_RUS_READY){
1925         printf("wlrustrt: RUS_READY\n");
1926         return;
1927     }
1928
1929     outw(PIOR0(base), OFFSET_SCB + 2);
1930     outw(PIOP0(base), SCB_RU_STRT);             /* command */
1931     rfa = wlbldru(unit);
1932     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
1933     outw(PIOP0(base), rfa);
1934
1935     SET_CHAN_ATTN(unit);
1936     return;
1937 }
1938
1939 /*
1940  * wldiag:
1941  *
1942  *      This routine does a 586 op-code number 7, and obtains the
1943  *      diagnose status for the WaveLAN.
1944  *
1945  */
1946 static int
1947 wldiag(int unit)
1948 {
1949     register struct wl_softc *sc = WLSOFTC(unit);
1950     short               base = sc->base;
1951     short status;
1952
1953 #ifdef WLDEBUG
1954     if (sc->wl_if.if_flags & IFF_DEBUG)
1955         printf("wl%d: entered wldiag()\n",unit);
1956 #endif
1957     outw(PIOR0(base), OFFSET_SCB);
1958     status = inw(PIOP0(base));
1959     if (status & SCB_SW_INT) {
1960                 /* state is 2000 which seems ok
1961                    printf("wl%d diag(): unexpected initial state %\n",
1962                    unit, inw(PIOP0(base)));
1963                 */
1964         wlack(unit);
1965     }
1966     outw(PIOR1(base), OFFSET_CU);
1967     outw(PIOP1(base), 0);                       /* ac_status */
1968     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1969     if(wlcmd(unit, "diag()") == 0)
1970         return 0;
1971     outw(PIOR0(base), OFFSET_CU);
1972     if (inw(PIOP0(base)) & 0x0800) {
1973         printf("wl%d: i82586 Self Test failed!\n", unit);
1974         return 0;
1975     }
1976     return TRUE;
1977 }
1978
1979 /*
1980  * wlconfig:
1981  *
1982  *      This routine does a standard config of the WaveLAN board.
1983  *
1984  */
1985 static int
1986 wlconfig(int unit)
1987 {
1988     configure_t configure;
1989     register struct wl_softc *sc = WLSOFTC(unit);
1990     short               base = sc->base;
1991
1992 #if     MULTICAST
1993 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
1994     struct ifmultiaddr *ifma;
1995     u_char *addrp;
1996 #else
1997     struct ether_multi *enm;
1998     struct ether_multistep step;
1999 #endif
2000     int cnt = 0;
2001 #endif  /* MULTICAST */
2002
2003 #ifdef WLDEBUG
2004     if (sc->wl_if.if_flags & IFF_DEBUG)
2005         printf("wl%d: entered wlconfig()\n",unit);
2006 #endif
2007     outw(PIOR0(base), OFFSET_SCB);
2008     if (inw(PIOP0(base)) & SCB_SW_INT) {
2009         /*
2010           printf("wl%d config(): unexpected initial state %x\n",
2011           unit, inw(PIOP0(base)));
2012           */
2013     }
2014     wlack(unit);
2015
2016     outw(PIOR1(base), OFFSET_CU);
2017     outw(PIOP1(base), 0);                               /* ac_status */
2018     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
2019
2020 /* jrb hack */
2021     configure.fifolim_bytecnt   = 0x080c;
2022     configure.addrlen_mode      = 0x0600;
2023     configure.linprio_interframe        = 0x2060;
2024     configure.slot_time         = 0xf200;
2025     configure.hardware          = 0x0008;       /* tx even w/o CD */
2026     configure.min_frame_len     = 0x0040;
2027 #if 0
2028     /* This is the configuration block suggested by Marc Meertens
2029      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2030      * Ioannidis on 10 Nov 92.
2031      */
2032     configure.fifolim_bytecnt   = 0x040c;
2033     configure.addrlen_mode      = 0x0600;
2034     configure.linprio_interframe        = 0x2060;
2035     configure.slot_time         = 0xf000;
2036     configure.hardware          = 0x0008;       /* tx even w/o CD */
2037     configure.min_frame_len     = 0x0040;
2038 #else
2039     /*
2040      * below is the default board configuration from p2-28 from 586 book
2041      */
2042     configure.fifolim_bytecnt   = 0x080c;
2043     configure.addrlen_mode      = 0x2600;
2044     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
2045     configure.slot_time         = 0xf00c;       /* slottime=12    */
2046     configure.hardware          = 0x0008;       /* tx even w/o CD */
2047     configure.min_frame_len     = 0x0040;
2048 #endif
2049     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2050         configure.hardware |= 1;
2051     }
2052     outw(PIOR1(base), OFFSET_CU + 6);
2053     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2054
2055     if(wlcmd(unit, "config()-configure") == 0)
2056         return 0;
2057 #if     MULTICAST
2058     outw(PIOR1(base), OFFSET_CU);
2059     outw(PIOP1(base), 0);                               /* ac_status */
2060     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
2061     outw(PIOR1(base), OFFSET_CU + 8);
2062 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2063     TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
2064         if (ifma->ifma_addr->sa_family != AF_LINK)
2065             continue;
2066         
2067         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2068         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2069         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2070         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2071         ++cnt;
2072     }
2073 #else
2074     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2075     while (enm != NULL) {
2076         unsigned int lo, hi;
2077         /* break if setting a multicast range, else we would crash */
2078         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2079                 break;
2080         }
2081         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2082             + enm->enm_addrlo[5];
2083         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2084             + enm->enm_addrhi[5];
2085         while(lo <= hi) {
2086             outw(PIOP1(base),enm->enm_addrlo[0] +
2087                  (enm->enm_addrlo[1] << 8));
2088             outw(PIOP1(base),enm->enm_addrlo[2] +
2089                  ((lo >> 8) & 0xff00));
2090             outw(PIOP1(base), ((lo >> 8) & 0xff) +
2091                  ((lo << 8) & 0xff00));
2092 /* #define MCASTDEBUG */
2093 #ifdef MCASTDEBUG
2094 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2095                 enm->enm_addrlo[0],
2096                 enm->enm_addrlo[1],
2097                 enm->enm_addrlo[2],
2098                 enm->enm_addrlo[3],
2099                 enm->enm_addrlo[4],
2100                 enm->enm_addrlo[5]);
2101 #endif
2102             ++cnt;
2103             ++lo;
2104         }
2105         ETHER_NEXT_MULTI(step, enm);
2106     }
2107 #endif
2108     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
2109     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2110     if(wlcmd(unit, "config()-mcaddress") == 0)
2111         return 0;
2112 #endif  /* MULTICAST */
2113
2114     outw(PIOR1(base), OFFSET_CU);
2115     outw(PIOP1(base), 0);                               /* ac_status */
2116     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
2117     outw(PIOR1(base), OFFSET_CU + 6);
2118     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2119
2120     if(wlcmd(unit, "config()-address") == 0)
2121         return(0);
2122
2123     wlinitmmc(unit);
2124
2125     return(1);
2126 }
2127
2128 /*
2129  * wlcmd:
2130  *
2131  * Set channel attention bit and busy wait until command has
2132  * completed. Then acknowledge the command completion.
2133  */
2134 static int
2135 wlcmd(int unit, char *str)
2136 {
2137     register struct wl_softc *sc = WLSOFTC(unit);
2138     short       base = sc->base;
2139     int i;
2140         
2141     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2142     outw(PIOP0(base), SCB_CU_STRT);
2143     
2144     SET_CHAN_ATTN(unit);
2145     
2146     outw(PIOR0(base), OFFSET_CU);
2147     for(i = 0; i < 0xffff; i++)
2148         if (inw(PIOP0(base)) & AC_SW_C)
2149             break;
2150     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2151         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2152                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2153         outw(PIOR0(base), OFFSET_SCB);
2154         printf("scb_status %x\n", inw(PIOP0(base)));
2155         outw(PIOR0(base), OFFSET_SCB+2);
2156         printf("scb_command %x\n", inw(PIOP0(base)));
2157         outw(PIOR0(base), OFFSET_SCB+4);
2158         printf("scb_cbl %x\n", inw(PIOP0(base)));
2159         outw(PIOR0(base), OFFSET_CU+2);
2160         printf("cu_cmd %x\n", inw(PIOP0(base)));
2161         return(0);
2162     }
2163
2164     outw(PIOR0(base), OFFSET_SCB);
2165     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2166         /*
2167           printf("wl%d %s: unexpected final state %x\n",
2168           unit, str, inw(PIOP0(base)));
2169           */
2170     }
2171     wlack(unit);
2172     return(TRUE);
2173 }       
2174
2175 /*
2176  * wlack: if the 82596 wants attention because it has finished
2177  * sending or receiving a packet, acknowledge its desire and
2178  * return bits indicating the kind of attention. wlack() returns
2179  * these bits so that the caller can service exactly the
2180  * conditions that wlack() acknowledged.
2181  */
2182 static int
2183 wlack(int unit)
2184 {
2185     int i;
2186     register u_short cmd;
2187     register struct wl_softc *sc = WLSOFTC(unit);
2188     short base = sc->base;
2189
2190     outw(PIOR1(base), OFFSET_SCB);
2191     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2192         return(0);
2193 #ifdef WLDEBUG
2194     if (sc->wl_if.if_flags & IFF_DEBUG)
2195         printf("wl%d: doing a wlack()\n",unit);
2196 #endif
2197     outw(PIOP1(base), cmd);
2198     SET_CHAN_ATTN(unit);
2199     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2200     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2201     if (i < 1)
2202         printf("wl%d wlack(): board not accepting command.\n", unit);
2203     return(cmd);
2204 }
2205
2206 static void
2207 wltbd(int unit)
2208 {
2209     register struct wl_softc *sc = WLSOFTC(unit);
2210     short               base = sc->base;
2211     u_short             tbd_p = OFFSET_TBD;
2212     tbd_t               tbd;
2213     int                 i = 0;
2214     int                 sum = 0;
2215
2216     for (;;) {
2217         outw(PIOR1(base), tbd_p);
2218         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2219         sum += (tbd.act_count & ~TBD_SW_EOF);
2220         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2221                i++, tbd.buffer_addr,
2222                (tbd.act_count & ~TBD_SW_EOF), sum,
2223                tbd.next_tbd_offset, tbd.buffer_base);
2224         if (tbd.act_count & TBD_SW_EOF)
2225             break;
2226         tbd_p = tbd.next_tbd_offset;
2227     }
2228 }
2229
2230 static void
2231 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2232 {
2233     struct mbuf *tm_p = *tm_pp;
2234     u_char              *mb_p = *mb_pp;
2235     u_short             count = 0;
2236     u_char              *cp;
2237     int         len;
2238
2239     /*
2240      * can we get a run that will be coallesced or
2241      * that terminates before breaking
2242      */
2243     do {
2244         count += tm_p->m_len;
2245         if (tm_p->m_len & 1)
2246             break;
2247     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2248     if ( (tm_p == (struct mbuf *)0) ||
2249          count > HDW_THRESHOLD) {
2250         *countp = (*tm_pp)->m_len;
2251         *mb_pp = mtod((*tm_pp), u_char *);
2252         return;
2253     }
2254
2255     /* we need to copy */
2256     tm_p = *tm_pp;
2257     mb_p = *mb_pp;
2258     count = 0;
2259     cp = (u_char *) t_packet;
2260     for (;;) {
2261         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2262         count += len;
2263         if (count > HDW_THRESHOLD)
2264                         break;
2265         cp += len;
2266         if (tm_p->m_next == (struct mbuf *)0)
2267             break;
2268         tm_p = tm_p->m_next;
2269     }
2270     *countp = count;
2271     *mb_pp = (u_char *) t_packet;
2272     *tm_pp = tm_p;
2273     return;
2274 }
2275
2276
2277 static void
2278 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2279 {
2280     struct mbuf *tm_p = *tm_pp;
2281     u_short             count = 0;
2282     u_char              *cp = (u_char *) t_packet;
2283     int                 len;
2284
2285     /* we need to copy */
2286     for (;;) {
2287         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2288         count += len;
2289         cp += len;
2290         if (tm_p->m_next == (struct mbuf *)0)
2291             break;
2292         tm_p = tm_p->m_next;
2293     }
2294
2295     *countp = count;
2296     *mb_pp = (u_char *) t_packet;
2297     *tm_pp = tm_p;
2298     return;
2299 }
2300
2301 static void
2302 wlmmcstat(int unit)
2303 {
2304     register struct wl_softc *sc = WLSOFTC(unit);
2305     short       base = sc->base;
2306     u_short tmp;
2307
2308     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2309            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2310     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2311     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2312     printf("Correct NWID's: %d, ", tmp);
2313     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2314     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2315     printf("Wrong NWID's: %d\n", tmp);
2316     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2317     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
2318            wlmmcread(base,MMC_SIGNAL_LVL),
2319            wlmmcread(base,MMC_SILENCE_LVL));
2320     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2321            wlmmcread(base,MMC_SIGN_QUAL),
2322            wlmmcread(base,MMC_NETW_ID_H),
2323            wlmmcread(base,MMC_NETW_ID_L),
2324            wlmmcread(base,MMC_DES_AVAIL));
2325 }
2326
2327 static u_short
2328 wlmmcread(u_int base, u_short reg)
2329 {
2330     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2331     outw(MMCR(base),reg << 1);
2332     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2333     return (u_short)inw(MMCR(base)) >> 8;
2334 }
2335
2336 static void
2337 getsnr(int unit)
2338 {
2339     MMC_WRITE(MMC_FREEZE,1);
2340     /* 
2341      * SNR retrieval procedure :
2342      *
2343      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2344      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2345      */
2346     MMC_WRITE(MMC_FREEZE,0);
2347     /*
2348      * SNR is signal:silence ratio.
2349      */
2350 }
2351
2352 /*
2353 ** wlgetpsa
2354 **
2355 ** Reads the psa for the wavelan at (base) into (buf)
2356 */
2357 static void
2358 wlgetpsa(int base, u_char *buf)
2359 {
2360     int i;
2361
2362     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2363     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2364
2365     for (i = 0; i < 0x40; i++) {
2366         outw(PIOR2(base), i);
2367         buf[i] = inb(PIOP2(base));
2368     }
2369     PCMD(base, HACR_DEFAULT);
2370     PCMD(base, HACR_DEFAULT);
2371 }
2372
2373 /*
2374 ** wlsetpsa
2375 **
2376 ** Writes the psa for wavelan (unit) from the softc back to the
2377 ** board.  Updates the CRC and sets the CRC OK flag.
2378 **
2379 ** Do not call this when the board is operating, as it doesn't 
2380 ** preserve the hacr.
2381 */
2382 static void
2383 wlsetpsa(int unit)
2384 {
2385     register struct wl_softc *sc = WLSOFTC(unit);
2386     short       base = sc->base;
2387     int         i, oldpri;
2388     u_short     crc;
2389
2390     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
2391     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2392     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2393     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
2394
2395     oldpri = splimp();          /* ick, long pause */
2396     
2397     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2398     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2399     
2400     for (i = 0; i < 0x40; i++) {
2401         DELAY(DELAYCONST);
2402         outw(PIOR2(base),i);  /* write param memory */
2403         DELAY(DELAYCONST);
2404         outb(PIOP2(base), sc->psa[i]);
2405     }
2406     DELAY(DELAYCONST);
2407     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
2408     DELAY(DELAYCONST);
2409     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
2410     outb(PIOP2(base), 0xaa);    /* all OK */
2411     DELAY(DELAYCONST);
2412     
2413     PCMD(base, HACR_DEFAULT);
2414     PCMD(base, HACR_DEFAULT);
2415     
2416     splx(oldpri);
2417 }
2418
2419 /* 
2420 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2421 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2422 */
2423
2424 static u_int crc16_table[16] = { 
2425     0x0000, 0xCC01, 0xD801, 0x1400,
2426     0xF001, 0x3C00, 0x2800, 0xE401,
2427     0xA001, 0x6C00, 0x7800, 0xB401,
2428     0x5000, 0x9C01, 0x8801, 0x4400 
2429 };
2430
2431 static u_short
2432 wlpsacrc(u_char *buf)
2433 {
2434     u_short     crc = 0;
2435     int         i, r1;
2436     
2437     for (i = 0; i < 0x3d; i++, buf++) {
2438         /* lower 4 bits */
2439         r1 = crc16_table[crc & 0xF];
2440         crc = (crc >> 4) & 0x0FFF;
2441         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2442         
2443         /* upper 4 bits */
2444         r1 = crc16_table[crc & 0xF];
2445         crc = (crc >> 4) & 0x0FFF;
2446         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2447     }
2448     return(crc);
2449 }
2450 #ifdef WLCACHE
2451
2452 /*
2453  * wl_cache_store
2454  *
2455  * take input packet and cache various radio hw characteristics
2456  * indexed by MAC address.
2457  *
2458  * Some things to think about:
2459  *      note that no space is malloced. 
2460  *      We might hash the mac address if the cache were bigger.
2461  *      It is not clear that the cache is big enough.
2462  *              It is also not clear how big it should be.
2463  *      The cache is IP-specific.  We don't care about that as
2464  *              we want it to be IP-specific.
2465  *      The last N recv. packets are saved.  This will tend
2466  *              to reward agents and mobile hosts that beacon.
2467  *              That is probably fine for mobile ip.
2468  */
2469
2470 /* globals for wavelan signal strength cache */
2471 /* this should go into softc structure above. 
2472 */
2473
2474 /* set true if you want to limit cache items to broadcast/mcast 
2475  * only packets (not unicast)
2476  */
2477 static int wl_cache_mcastonly = 1;
2478 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
2479         &wl_cache_mcastonly, 0, "");
2480
2481 /* set true if you want to limit cache items to IP packets only
2482 */
2483 static int wl_cache_iponly = 1;
2484 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
2485         &wl_cache_iponly, 0, "");
2486
2487 /* zero out the cache
2488 */
2489 static void
2490 wl_cache_zero(int unit)
2491 {
2492         register struct wl_softc        *sc = WLSOFTC(unit);
2493
2494         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2495         sc->w_sigitems = 0;
2496         sc->w_nextcache = 0;
2497         sc->w_wrapindex = 0;
2498 }
2499
2500 /* store hw signal info in cache.
2501  * index is MAC address, but an ip src gets stored too
2502  * There are two filters here controllable via sysctl:
2503  *      throw out unicast (on by default, but can be turned off)
2504  *      throw out non-ip (on by default, but can be turned off)
2505  */
2506 static
2507 void wl_cache_store (int unit, int base, struct ether_header *eh,
2508                      struct mbuf *m)
2509 {
2510         struct ip *ip = NULL;   /* Avoid GCC warning */
2511         int i;
2512         int signal, silence;
2513         int w_insertcache;   /* computed index for cache entry storage */
2514         register struct wl_softc *sc = WLSOFTC(unit);
2515         int ipflag = wl_cache_iponly;
2516
2517         /* filters:
2518          * 1. ip only
2519          * 2. configurable filter to throw out unicast packets,
2520          * keep multicast only.
2521          */
2522  
2523 #ifdef INET
2524         /* reject if not IP packet
2525         */
2526         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2527                 return;
2528         }
2529
2530         /* check if broadcast or multicast packet.  we toss
2531          * unicast packets
2532          */
2533         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2534                 return;
2535         }
2536
2537         /* find the ip header.  we want to store the ip_src
2538          * address.  use the mtod macro(in mbuf.h) 
2539          * to typecast m to struct ip *
2540          */
2541         if (ipflag) {
2542                 ip = mtod(m, struct ip *);
2543         }
2544         
2545         /* do a linear search for a matching MAC address 
2546          * in the cache table
2547          * . MAC address is 6 bytes,
2548          * . var w_nextcache holds total number of entries already cached
2549          */
2550         for(i = 0; i < sc->w_nextcache; i++) {
2551                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
2552                         /* Match!,
2553                          * so we already have this entry,
2554                          * update the data, and LRU age
2555                          */
2556                         break;  
2557                 }
2558         }
2559
2560         /* did we find a matching mac address?
2561          * if yes, then overwrite a previously existing cache entry
2562          */
2563         if (i <  sc->w_nextcache )   {
2564                 w_insertcache = i; 
2565         }
2566         /* else, have a new address entry,so
2567          * add this new entry,
2568          * if table full, then we need to replace entry
2569          */
2570         else    {                          
2571
2572                 /* check for space in cache table 
2573                  * note: w_nextcache also holds number of entries
2574                  * added in the cache table 
2575                  */
2576                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2577                         w_insertcache = sc->w_nextcache;
2578                         sc->w_nextcache++;                 
2579                         sc->w_sigitems = sc->w_nextcache;
2580                 }
2581                 /* no space found, so simply wrap with wrap index
2582                  * and "zap" the next entry
2583                  */
2584                 else {
2585                         if (sc->w_wrapindex == MAXCACHEITEMS) {
2586                                 sc->w_wrapindex = 0;
2587                         }
2588                         w_insertcache = sc->w_wrapindex++;
2589                 }
2590         }
2591
2592         /* invariant: w_insertcache now points at some slot
2593          * in cache.
2594          */
2595         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2596                 log(LOG_ERR, 
2597                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2598                         w_insertcache, MAXCACHEITEMS);
2599                 return;
2600         }
2601
2602         /*  store items in cache
2603          *  .ipsrc
2604          *  .macsrc
2605          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
2606          */
2607         if (ipflag) {
2608                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2609         }
2610         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
2611         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2612         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2613         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2614         if (signal > 0)
2615                 sc->w_sigcache[w_insertcache].snr = 
2616                         signal - silence;
2617         else
2618                 sc->w_sigcache[w_insertcache].snr = 0;
2619 #endif /* INET */
2620
2621 }
2622 #endif /* WLCACHE */
2623
2624 /*
2625  * determine if in all multicast mode or not
2626  * 
2627  * returns: 1 if IFF_ALLMULTI should be set
2628  *          else 0
2629  */
2630 #ifdef MULTICAST
2631
2632 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
2633 static int
2634 check_allmulti(int unit)
2635 {
2636     register struct wl_softc *sc = WLSOFTC(unit);
2637     short  base = sc->base;
2638     struct ether_multi *enm;
2639     struct ether_multistep step;
2640
2641     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2642     while (enm != NULL) {
2643         unsigned int lo, hi;
2644 #ifdef MDEBUG
2645                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2646                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2647                 enm->enm_addrlo[5]);
2648                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2649                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2650                 enm->enm_addrhi[5]);
2651 #endif
2652         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2653                 return(1);
2654         }
2655         ETHER_NEXT_MULTI(step, enm);
2656     }
2657     return(0);
2658 }
2659 #endif
2660 #endif