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