Merge from vendor branch GCC:
[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.18 2005/05/27 15:36:10 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/ifq_var.h>
210 #include <net/if_dl.h>
211
212 #ifdef INET
213 #include <netinet/in.h>
214 #include <netinet/in_systm.h>
215 #include <netinet/ip.h>
216 #include <netinet/if_ether.h>
217 #endif
218
219 #include <net/bpf.h>
220
221 #include <machine/clock.h>
222
223 #include <bus/isa/i386/isa_device.h>
224 #include "if_wl_i82586.h"       /* Definitions for the Intel chip */
225
226 /* was 1000 in original, fed to DELAY(x) */
227 #define DELAYCONST      1000
228 #include "if_wl.h"
229 #include <machine/if_wl_wavelan.h>
230
231 static char     t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
232
233 struct wl_softc{ 
234     struct      arpcom  wl_ac;                  /* Ethernet common part */
235 #define wl_if   wl_ac.ac_if                     /* network visible interface */
236 #define wl_addr wl_ac.ac_enaddr                 /* hardware address */
237     u_char      psa[0x40];
238     u_char      nwid[2];        /* current radio modem nwid */
239     short       base;
240     short       unit;
241     int         flags;
242     int         tbusy;          /* flag to determine if xmit is busy */
243     u_short     begin_fd;
244     u_short     end_fd;
245     u_short     end_rbd;
246     u_short     hacr;           /* latest host adapter CR command */
247     short       mode;
248     u_char      chan24;         /* 2.4 Gz: channel number/EEPROM Area # */
249     u_short     freq24;         /* 2.4 Gz: resulting frequency  */
250     struct      callout watchdog_ch;
251 #ifdef WLCACHE
252     int         w_sigitems;     /* number of cached entries */
253     /*  array of cache entries */
254     struct w_sigcache w_sigcache[ MAXCACHEITEMS ];            
255     int w_nextcache;            /* next free cache entry */    
256     int w_wrapindex;            /* next "free" cache entry */
257 #endif
258 };
259 static struct wl_softc wl_softc[NWL];
260
261 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
262
263 static int      wlprobe(struct isa_device *);
264 static int      wlattach(struct isa_device *);
265
266 DECLARE_DUMMY_MODULE(if_wl);
267
268 struct isa_driver wldriver = {
269     wlprobe, wlattach, "wl", 0
270 };
271
272 /*
273  * XXX  The Wavelan appears to be prone to dropping stuff if you talk to
274  * it too fast.  This disgusting hack inserts a delay after each packet
275  * is queued which helps avoid this behaviour on fast systems.
276  */
277 static int      wl_xmit_delay = 250;
278 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
279
280 /* 
281  * not XXX, but ZZZ (bizarre).
282  * promiscuous mode can be toggled to ignore NWIDs.  By default,
283  * it does not.  Caution should be exercised about combining
284  * this mode with IFF_ALLMULTI which puts this driver in
285  * promiscuous mode.
286  */
287 static int      wl_ignore_nwid = 0;
288 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
289
290 /*
291  * Emit diagnostics about transmission problems
292  */
293 static int      xmt_watch = 0;
294 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
295
296 /*
297  * Collect SNR statistics
298  */
299 static int      gathersnr = 0;
300 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
301
302 static void     wlstart(struct ifnet *ifp);
303 static void     wlinit(void *xsc);
304 static int      wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
305 static timeout_t wlwatchdog;
306 static ointhand2_t wlintr;
307 static void     wlxmt(int unt, struct mbuf *m);
308 static int      wldiag(int unt); 
309 static int      wlconfig(int unit); 
310 static int      wlcmd(int unit, char *str);
311 static void     wlmmcstat(int unit);
312 static u_short  wlbldru(int unit);
313 static u_short  wlmmcread(u_int base, u_short reg);
314 static void     wlinitmmc(int unit);
315 static int      wlhwrst(int unit);
316 static void     wlrustrt(int unit);
317 static void     wlbldcu(int unit);
318 static int      wlack(int unit);
319 static int      wlread(int unit, u_short fd_p);
320 static void     getsnr(int unit);
321 static void     wlrcv(int unit);
322 static int      wlrequeue(int unit, u_short fd_p);
323 static void     wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324 static void     wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
325 static void     wltbd(int unit);
326 static void     wlgetpsa(int base, u_char *buf);
327 static void     wlsetpsa(int unit);
328 static u_short  wlpsacrc(u_char *buf);
329 static void     wldump(int unit);
330 #ifdef WLCACHE
331 static void     wl_cache_store(int, int, struct ether_header *, struct mbuf *);
332 static void     wl_cache_zero(int unit);
333 #endif
334 #ifdef MULTICAST
335 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
336 static int      check_allmulti(int unit);
337 # endif
338 #endif
339
340 /* array for maping irq numbers to values for the irq parameter register */
341 static int irqvals[16] = { 
342     0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 
343 };
344 /* mask of valid IRQs */
345 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
346
347 /*
348  * wlprobe:
349  *
350  *      This function "probes" or checks for the WaveLAN board on the bus to
351  *      see if it is there.  As far as I can tell, the best break between this
352  *      routine and the attach code is to simply determine whether the board
353  *      is configured in properly.  Currently my approach to this is to write
354  *      and read a word from the SRAM on the board being probed.  If the word
355  *      comes back properly then we assume the board is there.  The config
356  *      code expects to see a successful return from the probe routine before
357  *      attach will be called.
358  *
359  * input        : address device is mapped to, and unit # being checked
360  * output       : a '1' is returned if the board exists, and a 0 otherwise
361  *
362  */
363 static int
364 wlprobe(struct isa_device *id)
365 {
366     struct wl_softc     *sc = &wl_softc[id->id_unit];   
367     short       base = id->id_iobase;
368     char                *str = "wl%d: board out of range [0..%d]\n";
369     u_char              inbuf[100];
370     unsigned long       oldpri;
371     int                 irq;
372
373     /* TBD. not true.
374      * regular CMD() will not work, since no softc yet 
375      */
376 #define PCMD(base, hacr) outw((base), (hacr))
377
378     oldpri = splimp();
379     PCMD(base, HACR_RESET);                     /* reset the board */
380     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
381     PCMD(base, HACR_RESET);                     /* reset the board */
382     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
383     splx(oldpri);
384
385     /* clear reset command and set PIO#1 in autoincrement mode */
386     PCMD(base, HACR_DEFAULT);
387     PCMD(base, HACR_DEFAULT);
388     outw(PIOR1(base), 0);                       /* go to beginning of RAM */
389     outsw(PIOP1(base), str, strlen(str)/2+1);   /* write string */
390     
391     outw(PIOR1(base), 0);                       /* rewind */
392     insw(PIOP1(base), inbuf, strlen(str)/2+1);  /* read result */
393     
394     if (bcmp(str, inbuf, strlen(str)))
395         return(0);
396
397     sc->chan24 = 0;                             /* 2.4 Gz: config channel */
398     sc->freq24 = 0;                             /* 2.4 Gz: frequency    */
399
400     /* read the PSA from the board into temporary storage */
401     wlgetpsa(base, inbuf);
402     
403     /* We read the IRQ value from the PSA on the board. */
404     for (irq = 15; irq >= 0; irq--)
405         if (irqvals[irq] == inbuf[WLPSA_IRQNO])
406             break;
407     if ((irq == 0) || (irqvals[irq] == 0)){
408         printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
409         id->id_irq = 0;                         /* no interrupt */
410     } else {
411         /*
412          * If the IRQ requested by the PSA is already claimed by another
413          * device, the board won't work, but the user can still access the
414          * driver to change the IRQ.
415          */
416         id->id_irq = (1<<irq);                  /* use IRQ from PSA */
417     }
418     return(16);
419 }
420
421
422 /*
423  * wlattach:
424  *
425  *      This function attaches a WaveLAN board to the "system".  The rest of
426  *      runtime structures are initialized here (this routine is called after
427  *      a successful probe of the board).  Once the ethernet address is read
428  *      and stored, the board's ifnet structure is attached and readied.
429  *
430  * input        : isa_dev structure setup in autoconfig
431  * output       : board structs and ifnet is setup
432  *
433  */
434 static int
435 wlattach(struct isa_device *id)
436 {
437     struct wl_softc     *sc = (struct wl_softc *) &wl_softc[id->id_unit];
438     short       base = id->id_iobase;
439     int                 i,j;
440     u_char              unit = id->id_unit;
441     struct ifnet        *ifp = &sc->wl_if;
442
443 #ifdef WLDEBUG
444     printf("wlattach: base %x, unit %d\n", base, unit);
445 #endif
446     id->id_ointr = wlintr;
447     sc->base = base;
448     sc->unit = unit;
449     sc->flags = 0;
450     sc->mode = 0;
451     sc->hacr = HACR_RESET;
452     callout_init(&sc->watchdog_ch);
453     CMD(unit);                          /* reset the board */
454     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
455         
456     /* clear reset command and set PIO#2 in parameter access mode */
457     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
458     CMD(unit);
459
460     /* Read the PSA from the board for our later reference */
461     wlgetpsa(base, sc->psa);
462
463     /* fetch NWID */
464     sc->nwid[0] = sc->psa[WLPSA_NWID];
465     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
466     
467     /* fetch MAC address - decide which one first */
468     if (sc->psa[WLPSA_MACSEL] & 1) {
469         j = WLPSA_LOCALMAC;
470     } else {
471         j = WLPSA_UNIMAC;
472     }
473     for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
474         sc->wl_addr[i] = sc->psa[j + i];
475     }
476
477     /* enter normal 16 bit mode operation */
478     sc->hacr = HACR_DEFAULT;
479     CMD(unit);
480
481     wlinitmmc(unit);
482     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
483     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
484     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
485     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
486     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
487
488     bzero(ifp, sizeof(ifp));
489     ifp->if_softc = sc;
490     if_initname(ifp, "wl", id->id_unit);
491     ifp->if_mtu = WAVELAN_MTU;
492     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
493 #ifdef    WLDEBUG
494     ifp->if_flags |= IFF_DEBUG;
495 #endif
496 #if     MULTICAST
497     ifp->if_flags |= IFF_MULTICAST;
498 #endif  /* MULTICAST */
499     ifp->if_init = wlinit;
500     ifp->if_start = wlstart;
501     ifp->if_ioctl = wlioctl;
502     ifp->if_timer = 0;   /* paranoia */
503     /* no entries
504        ifp->if_watchdog
505        ifp->if_done
506        ifp->if_reset
507        */
508     ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
509     ifq_set_ready(&ifp->if_snd);
510     ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
511
512     bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
513     if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
514     if (sc->freq24) 
515         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
516     printf("\n");                                       /* 2.4 Gz       */
517
518
519     if (bootverbose)
520         wldump(unit);
521     return(1);
522 }
523
524 /*
525  * Print out interesting information about the 82596.
526  */
527 static void
528 wldump(int unit)
529 {
530     struct wl_softc *sp = WLSOFTC(unit);
531     int         base = sp->base;
532     int         i;
533         
534     printf("hasr %04x\n", inw(HASR(base)));
535         
536     printf("scb at %04x:\n ", OFFSET_SCB);
537     outw(PIOR1(base), OFFSET_SCB);
538     for(i = 0; i < 8; i++)
539         printf("%04x ", inw(PIOP1(base)));
540     printf("\n");
541         
542     printf("cu at %04x:\n ", OFFSET_CU);
543     outw(PIOR1(base), OFFSET_CU);
544     for(i = 0; i < 8; i++)
545         printf("%04x ", inw(PIOP1(base)));
546     printf("\n");
547         
548     printf("tbd at %04x:\n ", OFFSET_TBD);
549     outw(PIOR1(base), OFFSET_TBD);
550     for(i = 0; i < 4; i++)
551         printf("%04x ", inw(PIOP1(base)));
552     printf("\n");
553 }
554
555 /* Initialize the Modem Management Controller */
556 static void
557 wlinitmmc(int unit)
558 {
559     struct wl_softc *sp = WLSOFTC(unit);
560     int         base = sp->base;
561     int         configured;
562     int         mode = sp->mode;
563     int         i;                              /* 2.4 Gz               */
564         
565     /* enter 8 bit operation */
566     sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
567     CMD(unit);
568
569     configured = sp->psa[WLPSA_CONFIGURED] & 1;
570         
571     /*
572      * Set default modem control parameters.  Taken from NCR document
573      *  407-0024326 Rev. A 
574      */
575     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
576     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
577     MMC_WRITE(MMC_IFS, 0x20);
578     MMC_WRITE(MMC_MOD_DELAY, 0x04);
579     MMC_WRITE(MMC_JAM_TIME, 0x38);
580     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
581     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
582     if (!configured) {
583         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
584         if (sp->psa[WLPSA_COMPATNO] & 1) {
585             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
586         } else {
587             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
588         }
589         MMC_WRITE(MMC_QUALITY_THR, 0x03);
590     } else {
591         /* use configuration defaults from parameter storage area */
592         if (sp->psa[WLPSA_NWIDENABLE] & 1) {
593             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
594                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
595             } else {
596                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
597             }
598         } else {
599             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
600         }
601         MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
602         MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
603     }
604     MMC_WRITE(MMC_FREEZE, 0x00);
605     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
606
607     MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]);       /* set NWID */
608     MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
609
610     /* enter normal 16 bit mode operation */
611     sp->hacr = HACR_DEFAULT;
612     CMD(unit);
613     CMD(unit);                                  /* virtualpc1 needs this! */
614
615     if (sp->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
616                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
617         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
618         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
619         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
620                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
621         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
622             DELAY(40);                          /* 2.4 Gz             */
623             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
624                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
625                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
626                 break;                          /* 2.4 Gz: download finished */
627         }                                       /* 2.4 Gz                    */
628         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
629         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
630         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
631                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
632         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
633             DELAY(40);                          /* 2.4 Gz             */
634             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
635                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
636                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
637                 break;                          /* 2.4 Gz: download finished */
638         }                                       /* 2.4 Gz                    */
639         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
640         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
641                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
642                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
643         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
644         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
645         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
646                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
647         DELAY(40);                              /* 2.4 Gz                    */
648         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
649           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
650         sp->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
651     }
652 }
653
654 /*
655  * wlinit:
656  *
657  *      Another routine that interfaces the "if" layer to this driver.  
658  *      Simply resets the structures that are used by "upper layers".  
659  *      As well as calling wlhwrst that does reset the WaveLAN board.
660  *
661  * input        : softc pointer for this interface
662  * output       : structures (if structs) and board are reset
663  *
664  */     
665 static void
666 wlinit(void *xsc)
667 {
668     struct wl_softc *sc = xsc;
669     struct ifnet        *ifp = &sc->wl_if;
670     int                 stat;
671     u_long              oldpri;
672
673 #ifdef WLDEBUG
674     if (sc->wl_if.if_flags & IFF_DEBUG)
675         printf("wl%d: entered wlinit()\n",sc->unit);
676 #endif
677 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
678     if (TAILQ_EMPTY(&ifp->if_addrhead)) {
679 #else
680     if (ifp->if_addrlist == (struct ifaddr *)0) {
681 #endif
682         return;
683     }
684     oldpri = splimp();
685     if ((stat = wlhwrst(sc->unit)) == TRUE) {
686         sc->wl_if.if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
687         /* 
688          * OACTIVE is used by upper-level routines
689          * and must be set
690          */
691         sc->wl_if.if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
692                 
693         sc->flags |= DSF_RUNNING;
694         sc->tbusy = 0;
695         callout_stop(&sc->watchdog_ch);
696                 
697         wlstart(ifp);
698     } else {
699         printf("wl%d init(): trouble resetting board.\n", sc->unit);
700     }
701     splx(oldpri);
702 }
703
704 /*
705  * wlhwrst:
706  *
707  *      This routine resets the WaveLAN board that corresponds to the 
708  *      board number passed in.
709  *
710  * input        : board number to do a hardware reset
711  * output       : board is reset
712  *
713  */
714 static int
715 wlhwrst(int unit)
716 {
717     struct wl_softc     *sc = WLSOFTC(unit);
718
719 #ifdef WLDEBUG
720     if (sc->wl_if.if_flags & IFF_DEBUG)
721         printf("wl%d: entered wlhwrst()\n",unit);
722 #endif
723     sc->hacr = HACR_RESET;
724     CMD(unit);                  /* reset the board */
725         
726     /* clear reset command and set PIO#1 in autoincrement mode */
727     sc->hacr = HACR_DEFAULT;
728     CMD(unit);
729
730 #ifdef  WLDEBUG
731     if (sc->wl_if.if_flags & IFF_DEBUG)
732         wlmmcstat(unit);        /* Display MMC registers */
733 #endif  /* WLDEBUG */
734     wlbldcu(unit);              /* set up command unit structures */
735     
736     if (wldiag(unit) == 0)
737         return(0);
738     
739     if (wlconfig(unit) == 0)
740             return(0);
741     /* 
742      * insert code for loopback test here
743      */
744     wlrustrt(unit);             /* start receive unit */
745
746     /* enable interrupts */
747     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
748     CMD(unit);
749     
750     return(1);
751 }
752
753 /*
754  * wlbldcu:
755  *
756  *      This function builds up the command unit structures.  It inits
757  *      the scp, iscp, scb, cb, tbd, and tbuf.
758  *
759  */
760 static void
761 wlbldcu(int unit)
762 {
763     struct wl_softc *sc = WLSOFTC(unit);
764     short               base = sc->base;
765     scp_t               scp;
766     iscp_t              iscp;
767     scb_t               scb;
768     ac_t                cb;
769     tbd_t               tbd;
770     int         i;
771
772     bzero(&scp, sizeof(scp));
773     scp.scp_sysbus = 0;
774     scp.scp_iscp = OFFSET_ISCP;
775     scp.scp_iscp_base = 0;
776     outw(PIOR1(base), OFFSET_SCP);
777     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
778
779     bzero(&iscp, sizeof(iscp));
780     iscp.iscp_busy = 1;
781     iscp.iscp_scb_offset = OFFSET_SCB;
782     iscp.iscp_scb = 0;
783     iscp.iscp_scb_base = 0;
784     outw(PIOR1(base), OFFSET_ISCP);
785     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
786
787     scb.scb_status = 0;
788     scb.scb_command = SCB_RESET;
789     scb.scb_cbl_offset = OFFSET_CU;
790     scb.scb_rfa_offset = OFFSET_RU;
791     scb.scb_crcerrs = 0;
792     scb.scb_alnerrs = 0;
793     scb.scb_rscerrs = 0;
794     scb.scb_ovrnerrs = 0;
795     outw(PIOR1(base), OFFSET_SCB);
796     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
797
798     SET_CHAN_ATTN(unit);
799
800     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
801     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
802     if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
803     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
804     for (i = STATUS_TRIES; i-- > 0; ) {
805         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
806             break;
807     }
808     if (i <= 0)
809         printf("wl%d bldcu(): not ready after reset.\n", unit);
810     wlack(unit);
811
812     cb.ac_status = 0;
813     cb.ac_command = AC_CW_EL;           /* NOP */
814     cb.ac_link_offset = OFFSET_CU;
815     outw(PIOR1(base), OFFSET_CU);
816     outsw(PIOP1(base), &cb, 6/2);
817
818     tbd.act_count = 0;
819     tbd.next_tbd_offset = I82586NULL;
820     tbd.buffer_addr = 0;
821     tbd.buffer_base = 0;
822     outw(PIOR1(base), OFFSET_TBD);
823     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
824 }
825
826 /*
827  * wlstart:
828  *
829  *      send a packet
830  *
831  * input        : board number
832  * output       : stuff sent to board if any there
833  *
834  */
835 static void
836 wlstart(struct ifnet *ifp)
837 {
838     int                         unit = ifp->if_dunit;
839     struct mbuf                 *m;
840     struct wl_softc     *sc = WLSOFTC(unit);
841     short                       base = sc->base;
842     int                         scb_status, cu_status, scb_command;
843
844 #ifdef WLDEBUG
845     if (sc->wl_if.if_flags & IFF_DEBUG)
846         printf("wl%d: entered wlstart()\n",unit);
847 #endif
848
849     outw(PIOR1(base), OFFSET_CU);
850     cu_status = inw(PIOP1(base));
851     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
852     scb_status = inw(PIOP0(base));
853     outw(PIOR0(base), OFFSET_SCB + 2);
854     scb_command = inw(PIOP0(base));
855
856     /*
857      * don't need OACTIVE check as tbusy here checks to see
858      * if we are already busy 
859      */
860     if (sc->tbusy) {
861         if((scb_status & 0x0700) == SCB_CUS_IDLE &&
862            (cu_status & AC_SW_B) == 0){
863             sc->tbusy = 0;
864             callout_stop(&sc->watchdog_ch);
865             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
866             /*
867              * This is probably just a race.  The xmt'r is just
868              * became idle but WE have masked interrupts so ...
869              */
870 #ifdef WLDEBUG
871             printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
872                    unit, scb_status, scb_command, cu_status);
873 #endif 
874             if (xmt_watch) printf("!!");
875         } else {
876             return;     /* genuinely still busy */
877         }
878     } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
879               (cu_status & AC_SW_B)){
880 #ifdef WLDEBUG
881         printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
882                unit, scb_status, cu_status);
883 #endif
884         if (xmt_watch) printf("wl%d: busy?!",unit);
885         return;         /* hey, why are we busy? */
886     }
887
888     /* get ourselves some data */
889     ifp = &(sc->wl_if);
890     m = ifq_dequeue(&ifp->if_snd);
891     if (m != NULL) {
892         BPF_MTAP(ifp, m);
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 SIOCSIFFLAGS:
1152         if (ifp->if_flags & IFF_ALLMULTI) {
1153             mode |= MOD_ENAL;
1154         }
1155         if (ifp->if_flags & IFF_PROMISC) {
1156             mode |= MOD_PROM;
1157         }
1158         if(ifp->if_flags & IFF_LINK0) {
1159             mode |= MOD_PROM;
1160         }
1161         /*
1162          * force a complete reset if the recieve multicast/
1163          * promiscuous mode changes so that these take 
1164          * effect immediately.
1165          *
1166          */
1167         if (sc->mode != mode) {
1168             sc->mode = mode;
1169             if (sc->flags & DSF_RUNNING) {
1170                 sc->flags &= ~DSF_RUNNING;
1171                 wlinit(sc);
1172             }
1173         }
1174         /* if interface is marked DOWN and still running then
1175          * stop it.
1176          */
1177         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1178             printf("wl%d ioctl(): board is not running\n", unit);
1179             sc->flags &= ~DSF_RUNNING;
1180             sc->hacr &= ~HACR_INTRON;
1181             CMD(unit);            /* turn off interrupts */
1182         } 
1183         /* else if interface is UP and RUNNING, start it
1184                 */
1185         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1186             wlinit(sc);
1187         }
1188   
1189         /* if WLDEBUG set on interface, then printf rf-modem regs
1190         */
1191         if(ifp->if_flags & IFF_DEBUG)
1192             wlmmcstat(unit);
1193         break;
1194 #if     MULTICAST
1195     case SIOCADDMULTI:
1196     case SIOCDELMULTI:
1197
1198 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1199         if (cmd == SIOCADDMULTI) {
1200             error = ether_addmulti(ifr, &sc->wl_ac);
1201         }
1202         else {
1203             error = ether_delmulti(ifr, &sc->wl_ac);
1204         }
1205
1206         /* see if we should be in all multicast mode
1207          * note that 82586 cannot do that, must simulate with
1208          * promiscuous mode
1209          */
1210         if ( check_allmulti(unit)) {
1211                 ifp->if_flags |=  IFF_ALLMULTI;
1212                 sc->mode |= MOD_ENAL;
1213                 sc->flags &= ~DSF_RUNNING;
1214                 wlinit(sc);
1215                 error = 0;
1216                 break;
1217         }
1218
1219         if (error == ENETRESET) {
1220             if(sc->flags & DSF_RUNNING) {
1221                 sc->flags &= ~DSF_RUNNING;
1222                 wlinit(sc);
1223             }
1224             error = 0;
1225         }
1226 #else
1227         wlinit(sc);
1228 #endif
1229         break;
1230 #endif  /* MULTICAST */
1231
1232     /* DEVICE SPECIFIC */
1233
1234
1235         /* copy the PSA out to the caller */
1236     case SIOCGWLPSA:
1237         /* pointer to buffer in user space */
1238         up = (void *)ifr->ifr_data;
1239         /* work out if they're root */
1240         isroot = (suser(td) == 0);
1241         
1242         for (i = 0; i < 0x40; i++) {
1243             /* don't hand the DES key out to non-root users */
1244             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1245                 continue;
1246             if (subyte((up + i), sc->psa[i]))
1247                 return(EFAULT);
1248         }
1249         break;
1250
1251
1252         /* copy the PSA in from the caller; we only copy _some_ values */
1253     case SIOCSWLPSA:
1254         /* root only */
1255         if ((error = suser(td)))
1256             break;
1257         error = EINVAL; /* assume the worst */
1258         /* pointer to buffer in user space containing data */
1259         up = (void *)ifr->ifr_data;
1260         
1261         /* check validity of input range */
1262         for (i = 0; i < 0x40; i++)
1263             if (fubyte(up + i) < 0)
1264                 return(EFAULT);
1265
1266         /* check IRQ value */
1267         irqval = fubyte(up+WLPSA_IRQNO);
1268         for (irq = 15; irq >= 0; irq--)
1269             if(irqvals[irq] == irqval)
1270                 break;
1271         if (irq == 0)                   /* oops */
1272             break;
1273         /* new IRQ */
1274         sc->psa[WLPSA_IRQNO] = irqval;
1275
1276         /* local MAC */
1277         for (i = 0; i < 6; i++)
1278             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1279                 
1280         /* MAC select */        
1281         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1282         
1283         /* default nwid */
1284         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1285         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1286
1287         error = 0;
1288         wlsetpsa(unit);         /* update the PSA */
1289         break;
1290
1291
1292         /* get the current NWID out of the sc since we stored it there */
1293     case SIOCGWLCNWID:
1294         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1295         break;
1296
1297
1298         /*
1299          * change the nwid dynamically.  This
1300          * ONLY changes the radio modem and does not
1301          * change the PSA.
1302          *
1303          * 2 steps:
1304          *      1. save in softc "soft registers"
1305          *      2. save in radio modem (MMC)
1306          */
1307     case SIOCSWLCNWID:
1308         /* root only */
1309         if ((error = suser(td)))
1310             break;
1311         if (!(ifp->if_flags & IFF_UP)) {
1312             error = EIO;        /* only allowed while up */
1313         } else {
1314             /* 
1315              * soft c nwid shadows radio modem setting
1316              */
1317             sc->nwid[0] = (int)ifr->ifr_data >> 8;
1318             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1319             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1320             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1321         }
1322         break;
1323
1324         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
1325     case SIOCGWLEEPROM:
1326         /* root only */
1327         if ((error = suser(td)))
1328             break;
1329         /* pointer to buffer in user space */
1330         up = (void *)ifr->ifr_data;
1331         
1332         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
1333             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
1334             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
1335                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
1336             DELAY(40);                          /* 2.4 Gz                   */
1337             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
1338                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1339                ) return(EFAULT);                /* 2.4 Gz:                  */
1340             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
1341                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1342                ) return(EFAULT);                /* 2.4 Gz:                  */
1343         }
1344         break;
1345
1346 #ifdef WLCACHE
1347         /* zero (Delete) the wl cache */
1348     case SIOCDWLCACHE:
1349         /* root only */
1350         if ((error = suser(td)))
1351             break;
1352         wl_cache_zero(unit);
1353         break;
1354
1355         /* read out the number of used cache elements */
1356     case SIOCGWLCITEM:
1357         ifr->ifr_data = (caddr_t) sc->w_sigitems;
1358         break;
1359
1360         /* read out the wl cache */
1361     case SIOCGWLCACHE:
1362         /* pointer to buffer in user space */
1363         up = (void *)ifr->ifr_data;
1364         cpt = (char *) &sc->w_sigcache[0];
1365         size = sc->w_sigitems * sizeof(struct w_sigcache);
1366         
1367         for (i = 0; i < size; i++) {
1368             if (subyte((up + i), *cpt++))
1369                 return(EFAULT);
1370         }
1371         break;
1372 #endif
1373
1374     default:
1375         error = ether_ioctl(ifp, cmd, data);
1376         break;
1377     }
1378     splx(opri);
1379     return (error);
1380 }
1381
1382 /*
1383  * wlwatchdog():
1384  *
1385  * Called if the timer set in wlstart expires before an interrupt is received
1386  * from the wavelan.   It seems to lose interrupts sometimes.
1387  * The watchdog routine gets called if the transmitter failed to interrupt
1388  *
1389  * input        : which board is timing out
1390  * output       : board reset 
1391  *
1392  */
1393 static void
1394 wlwatchdog(void *vsc)
1395 {
1396     struct wl_softc *sc = vsc;
1397     int unit = sc->unit;
1398
1399     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1400     sc->wl_ac.ac_if.if_oerrors++;
1401     wlinit(sc);
1402 }
1403
1404 /*
1405  * wlintr:
1406  *
1407  *      This function is the interrupt handler for the WaveLAN
1408  *      board.  This routine will be called whenever either a packet
1409  *      is received, or a packet has successfully been transfered and
1410  *      the unit is ready to transmit another packet.
1411  *
1412  * input        : board number that interrupted
1413  * output       : either a packet is received, or a packet is transfered
1414  *
1415  */
1416 static void
1417 wlintr(unit)
1418 int unit;
1419 {
1420     struct wl_softc *sc = &wl_softc[unit];
1421     short               base = sc->base;
1422     int                 ac_status;
1423     u_short             int_type, int_type1;
1424
1425 #ifdef WLDEBUG
1426     if (sc->wl_if.if_flags & IFF_DEBUG)
1427         printf("wl%d: wlintr() called\n",unit);
1428 #endif
1429
1430     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1431         /* handle interrupt from the modem management controler */
1432         /* This will clear the interrupt condition */ 
1433         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1434     }
1435
1436     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
1437         /* commented out. jrb.  it happens when reinit occurs
1438            printf("wlintr: int_type %x, dump follows\n", int_type);
1439            wldump(unit);
1440            */
1441         return;
1442     }
1443
1444     if (gathersnr)
1445         getsnr(unit);
1446     for(;;) {
1447         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
1448         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1449         if (int_type == 0)                      /* no interrupts left */
1450             break;
1451
1452         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
1453         /* make sure no bits disappeared (others may appear) */
1454         if ((int_type & int_type1) != int_type)
1455             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1456                    int_type1, int_type);
1457         int_type = int_type1;                   /* go with the new status */
1458         /* 
1459          * incoming packet
1460          */
1461         if (int_type & SCB_SW_FR) {
1462             sc->wl_if.if_ipackets++;
1463             wlrcv(unit);
1464         }
1465         /*
1466          * receiver not ready
1467          */
1468         if (int_type & SCB_SW_RNR) {
1469             sc->wl_if.if_ierrors++;
1470 #ifdef  WLDEBUG
1471             if (sc->wl_if.if_flags & IFF_DEBUG)
1472                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1473                        unit, sc->begin_fd);
1474 #endif
1475             wlrustrt(unit);
1476         }
1477         /*
1478          * CU not ready
1479          */
1480         if (int_type & SCB_SW_CNA) {
1481             /*
1482              * At present, we don't care about CNA's.  We
1483              * believe they are a side effect of XMT.
1484              */
1485         }
1486         if (int_type & SCB_SW_CX) {
1487             /*
1488              * At present, we only request Interrupt for
1489              * XMT.
1490              */
1491             outw(PIOR1(base), OFFSET_CU);       /* get command status */
1492             ac_status = inw(PIOP1(base));
1493
1494             if (xmt_watch) {                    /* report some anomalies */
1495
1496                 if (sc->tbusy == 0) {
1497                     printf("wl%d: xmt intr but not busy, CU %04x\n",
1498                            unit, ac_status);
1499                 }
1500                 if (ac_status == 0) {
1501                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
1502                 }
1503                 if (ac_status & AC_SW_A) {
1504                     printf("wl%d: xmt aborted\n",unit);
1505                 }
1506 #ifdef  notdef
1507                 if (ac_status & TC_CARRIER) {
1508                     printf("wl%d: no carrier\n", unit);
1509                 }
1510 #endif  /* notdef */
1511                 if (ac_status & TC_CLS) {
1512                     printf("wl%d: no CTS\n", unit);
1513                 }
1514                 if (ac_status & TC_DMA) {
1515                     printf("wl%d: DMA underrun\n", unit);
1516                 }
1517                 if (ac_status & TC_DEFER) {
1518                     printf("wl%d: xmt deferred\n",unit);
1519                 }
1520                 if (ac_status & TC_SQE) {
1521                     printf("wl%d: heart beat\n", unit);
1522                 }
1523                 if (ac_status & TC_COLLISION) {
1524                     printf("wl%d: too many collisions\n", unit);
1525                 }
1526             }
1527             /* if the transmit actually failed, or returned some status */
1528             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1529                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1530                     sc->wl_if.if_oerrors++;
1531                 }
1532                 /* count collisions */
1533                 sc->wl_if.if_collisions += (ac_status & 0xf);
1534                 /* if TC_COLLISION set and collision count zero, 16 collisions */
1535                 if ((ac_status & 0x20) == 0x20) {
1536                     sc->wl_if.if_collisions += 0x10;
1537                 }
1538             }
1539             sc->tbusy = 0;
1540             callout_stop(&sc->watchdog_ch);
1541             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1542             wlstart(&(sc->wl_if));
1543         }
1544     }
1545     return;
1546 }
1547
1548 /*
1549  * wlrcv:
1550  *
1551  *      This routine is called by the interrupt handler to initiate a
1552  *      packet transfer from the board to the "if" layer above this
1553  *      driver.  This routine checks if a buffer has been successfully
1554  *      received by the WaveLAN.  If so, the routine wlread is called
1555  *      to do the actual transfer of the board data (including the
1556  *      ethernet header) into a packet (consisting of an mbuf chain).
1557  *
1558  * input        : number of the board to check
1559  * output       : if a packet is available, it is "sent up"
1560  *
1561  */
1562 static void
1563 wlrcv(int unit)
1564 {
1565     struct wl_softc *sc = WLSOFTC(unit);
1566     short       base = sc->base;
1567     u_short     fd_p, status, offset, link_offset;
1568
1569 #ifdef WLDEBUG
1570     if (sc->wl_if.if_flags & IFF_DEBUG)
1571         printf("wl%d: entered wlrcv()\n",unit);
1572 #endif
1573     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1574
1575         outw(PIOR0(base), fd_p + 0);    /* address of status */
1576         status = inw(PIOP0(base));
1577         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
1578         link_offset = inw(PIOP1(base));
1579         offset = inw(PIOP1(base));      /* rbd_offset */
1580         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1581             if (wlhwrst(unit) != TRUE)
1582                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1583             return;
1584         } else if (status & AC_SW_C) {
1585             if (status == (RFD_DONE|RFD_RSC)) {
1586                 /* lost one */
1587 #ifdef  WLDEBUG
1588                 if (sc->wl_if.if_flags & IFF_DEBUG)
1589                     printf("wl%d RCV: RSC %x\n", unit, status);
1590 #endif
1591                 sc->wl_if.if_ierrors++;
1592             } else if (!(status & RFD_OK)) {
1593                 printf("wl%d RCV: !OK %x\n", unit, status);
1594                 sc->wl_if.if_ierrors++;
1595             } else if (status & 0xfff) {        /* can't happen */
1596                 printf("wl%d RCV: ERRs %x\n", unit, status);
1597                 sc->wl_if.if_ierrors++;
1598             } else if (!wlread(unit, fd_p))
1599                 return;
1600
1601             if (!wlrequeue(unit, fd_p)) {
1602                 /* abort on chain error */
1603                 if (wlhwrst(unit) != TRUE)
1604                     printf("wl%d rcv(): hwrst trouble.\n", unit);
1605                 return;
1606             }
1607             sc->begin_fd = link_offset;
1608         } else {
1609             break;
1610         }
1611     }
1612     return;
1613 }
1614
1615 /*
1616  * wlrequeue:
1617  *
1618  *      This routine puts rbd's used in the last receive back onto the
1619  *      free list for the next receive.
1620  *
1621  */
1622 static int
1623 wlrequeue(int unit, u_short fd_p)
1624 {
1625     struct wl_softc *sc = WLSOFTC(unit);
1626     short               base = sc->base;
1627     fd_t                fd;
1628     u_short             l_rbdp, f_rbdp, rbd_offset;
1629
1630     outw(PIOR0(base), fd_p + 6);
1631     rbd_offset = inw(PIOP0(base));
1632     if ((f_rbdp = rbd_offset) != I82586NULL) {
1633         l_rbdp = f_rbdp;
1634         for(;;) {
1635             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
1636             if(inw(PIOP0(base)) & RBD_SW_EOF)
1637                 break;
1638             outw(PIOP0(base), 0);
1639             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
1640             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1641                 break;
1642         }
1643         outw(PIOP0(base), 0);
1644         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
1645         outw(PIOP0(base), I82586NULL);
1646         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
1647         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1648         outw(PIOR0(base), sc->end_rbd + 2);
1649         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
1650         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
1651         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1652         sc->end_rbd = l_rbdp;
1653     }
1654
1655     fd.status = 0;
1656     fd.command = AC_CW_EL;
1657     fd.link_offset = I82586NULL;
1658     fd.rbd_offset = I82586NULL;
1659     outw(PIOR1(base), fd_p);
1660     outsw(PIOP1(base), &fd, 8/2);
1661     
1662     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
1663     outw(PIOP1(base), 0);               /* command = 0 */
1664     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
1665     sc->end_fd = fd_p;
1666
1667     return 1;
1668 }
1669
1670 #ifdef  WLDEBUG
1671 static int xmt_debug = 0;
1672 #endif  /* WLDEBUG */
1673
1674 /*
1675  * wlxmt:
1676  *
1677  *      This routine fills in the appropriate registers and memory
1678  *      locations on the WaveLAN board and starts the board off on
1679  *      the transmit.
1680  *
1681  * input        : board number of interest, and a pointer to the mbuf
1682  * output       : board memory and registers are set for xfer and attention
1683  *
1684  */
1685 static void
1686 wlxmt(int unit, struct mbuf *m)
1687 {
1688     struct wl_softc *sc = WLSOFTC(unit);
1689     u_short             xmtdata_p = OFFSET_TBUF;
1690     u_short             xmtshort_p;
1691     struct      mbuf                    *tm_p = m;
1692     struct ether_header *eh_p = mtod(m, struct ether_header *);
1693     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1694     u_short                             count = m->m_len - sizeof(struct ether_header);
1695     ac_t                                cb;
1696     u_short                             tbd_p = OFFSET_TBD;
1697     u_short                             len, clen = 0;
1698     short                               base = sc->base;
1699     int                                 spin;
1700         
1701 #ifdef WLDEBUG
1702     if (sc->wl_if.if_flags & IFF_DEBUG)
1703         printf("wl%d: entered wlxmt()\n",unit);
1704 #endif
1705
1706     cb.ac_status = 0;
1707     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1708     cb.ac_link_offset = I82586NULL;
1709     outw(PIOR1(base), OFFSET_CU);
1710     outsw(PIOP1(base), &cb, 6/2);
1711     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
1712     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1713     outw(PIOP1(base), eh_p->ether_type);
1714
1715 #ifdef  WLDEBUG
1716     if (sc->wl_if.if_flags & IFF_DEBUG) {
1717         if (xmt_debug) {
1718             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
1719             printf("ether type %x\n", eh_p->ether_type);
1720         }
1721     }
1722 #endif  /* WLDEBUG */
1723     outw(PIOR0(base), OFFSET_TBD);
1724     outw(PIOP0(base), 0);               /* act_count */
1725     outw(PIOR1(base), OFFSET_TBD + 4);
1726     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
1727     outw(PIOP1(base), 0);               /* buffer_base */
1728     for (;;) {
1729         if (count) {
1730             if (clen + count > WAVELAN_MTU)
1731                 break;
1732             if (count & 1)
1733                 len = count + 1;
1734             else
1735                 len = count;
1736             outw(PIOR1(base), xmtdata_p);
1737             outsw(PIOP1(base), mb_p, len/2);
1738             clen += count;
1739             outw(PIOR0(base), tbd_p);  /* address of act_count */
1740             outw(PIOP0(base), inw(PIOP0(base)) + count);
1741             xmtdata_p += len;
1742             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1743                 break;
1744             if (count & 1) {
1745                 /* go to the next descriptor */
1746                 outw(PIOR0(base), tbd_p + 2);
1747                 tbd_p += sizeof (tbd_t);
1748                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1749                 outw(PIOR0(base), tbd_p);
1750                 outw(PIOP0(base), 0);   /* act_count */
1751                 outw(PIOR1(base), tbd_p + 4);
1752                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1753                 outw(PIOP1(base), 0);         /* buffer_base */
1754                 /* at the end -> coallesce remaining mbufs */
1755                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1756                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1757                     continue;
1758                 }
1759                 /* next mbuf short -> coallesce as needed */
1760                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1761 #define HDW_THRESHOLD 55
1762                      tm_p->m_len > HDW_THRESHOLD)
1763                     /* ok */;
1764                 else {
1765                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1766                     continue;
1767                 }
1768             }
1769         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1770             break;
1771         count = tm_p->m_len;
1772         mb_p = mtod(tm_p, u_char *);
1773 #ifdef  WLDEBUG
1774         if (sc->wl_if.if_flags & IFF_DEBUG)
1775             if (xmt_debug)
1776                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1777 #endif  /* WLDEBUG */
1778     }
1779 #ifdef  WLDEBUG
1780     if (sc->wl_if.if_flags & IFF_DEBUG)
1781         if (xmt_debug)
1782             printf("CLEN = %d\n", clen);
1783 #endif  /* WLDEBUG */
1784     outw(PIOR0(base), tbd_p);
1785     if (clen < ETHERMIN) {
1786         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1787         outw(PIOR1(base), xmtdata_p);
1788         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1789             outw(PIOP1(base), 0);
1790     }   
1791     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1792     outw(PIOR0(base), tbd_p + 2);
1793     outw(PIOP0(base), I82586NULL);
1794 #ifdef  WLDEBUG
1795     if (sc->wl_if.if_flags & IFF_DEBUG) {
1796         if (xmt_debug) {
1797             wltbd(unit);
1798             printf("\n");
1799         }
1800     }
1801 #endif  /* WLDEBUG */
1802
1803     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
1804     /* 
1805      * wait for 586 to clear previous command, complain if it takes
1806      * too long
1807      */
1808     for (spin = 1;;spin = (spin + 1) % 10000) {
1809         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
1810             break;
1811         }
1812         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
1813                 printf("wl%d: slow accepting xmit\n",unit);
1814         }
1815     }
1816     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
1817     SET_CHAN_ATTN(unit);
1818     
1819     m_freem(m);
1820
1821     /* XXX 
1822      * Pause to avoid transmit overrun problems.
1823      * The required delay tends to vary with platform type, and may be
1824      * related to interrupt loss.
1825      */
1826     if (wl_xmit_delay) {
1827         DELAY(wl_xmit_delay);
1828     }
1829     return;
1830 }
1831
1832 /*
1833  * wlbldru:
1834  *
1835  *      This function builds the linear linked lists of fd's and
1836  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
1837  *
1838  */
1839 static u_short
1840 wlbldru(int unit)
1841 {
1842     struct wl_softc *sc = WLSOFTC(unit);
1843     short       base = sc->base;
1844     fd_t        fd;
1845     rbd_t       rbd;
1846     u_short     fd_p = OFFSET_RU;
1847     u_short     rbd_p = OFFSET_RBD;
1848     int         i;
1849
1850     sc->begin_fd = fd_p;
1851     for(i = 0; i < N_FD; i++) {
1852         fd.status = 0;
1853         fd.command = 0;
1854         fd.link_offset = fd_p + sizeof(fd_t);
1855         fd.rbd_offset = I82586NULL;
1856         outw(PIOR1(base), fd_p);
1857         outsw(PIOP1(base), &fd, 8/2);
1858         fd_p = fd.link_offset;
1859     }
1860     fd_p -= sizeof(fd_t);
1861     sc->end_fd = fd_p;
1862     outw(PIOR1(base), fd_p + 2);
1863     outw(PIOP1(base), AC_CW_EL);        /* command */
1864     outw(PIOP1(base), I82586NULL);      /* link_offset */
1865     fd_p = OFFSET_RU;
1866     
1867     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
1868     outw(PIOP0(base), rbd_p);
1869     outw(PIOR1(base), rbd_p);
1870     for(i = 0; i < N_RBD; i++) {
1871         rbd.status = 0;
1872         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1873         rbd.buffer_base = 0;
1874         rbd.size = RCVBUFSIZE;
1875         if (i != N_RBD-1) {
1876             rbd_p += sizeof(ru_t);
1877             rbd.next_rbd_offset = rbd_p;
1878         } else {
1879             rbd.next_rbd_offset = I82586NULL;
1880             rbd.size |= AC_CW_EL;
1881             sc->end_rbd = rbd_p;
1882         }
1883         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1884         outw(PIOR1(base), rbd_p);
1885     }
1886     return sc->begin_fd;
1887 }
1888
1889 /*
1890  * wlrustrt:
1891  *
1892  *      This routine starts the receive unit running.  First checks if the
1893  *      board is actually ready, then the board is instructed to receive
1894  *      packets again.
1895  *
1896  */
1897 static void
1898 wlrustrt(int unit)
1899 {
1900     struct wl_softc *sc = WLSOFTC(unit);
1901     short               base = sc->base;
1902     u_short             rfa;
1903
1904 #ifdef WLDEBUG
1905     if (sc->wl_if.if_flags & IFF_DEBUG)
1906         printf("wl%d: entered wlrustrt()\n",unit);
1907 #endif
1908     outw(PIOR0(base), OFFSET_SCB);
1909     if (inw(PIOP0(base)) & SCB_RUS_READY){
1910         printf("wlrustrt: RUS_READY\n");
1911         return;
1912     }
1913
1914     outw(PIOR0(base), OFFSET_SCB + 2);
1915     outw(PIOP0(base), SCB_RU_STRT);             /* command */
1916     rfa = wlbldru(unit);
1917     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
1918     outw(PIOP0(base), rfa);
1919
1920     SET_CHAN_ATTN(unit);
1921     return;
1922 }
1923
1924 /*
1925  * wldiag:
1926  *
1927  *      This routine does a 586 op-code number 7, and obtains the
1928  *      diagnose status for the WaveLAN.
1929  *
1930  */
1931 static int
1932 wldiag(int unit)
1933 {
1934     struct wl_softc *sc = WLSOFTC(unit);
1935     short               base = sc->base;
1936     short status;
1937
1938 #ifdef WLDEBUG
1939     if (sc->wl_if.if_flags & IFF_DEBUG)
1940         printf("wl%d: entered wldiag()\n",unit);
1941 #endif
1942     outw(PIOR0(base), OFFSET_SCB);
1943     status = inw(PIOP0(base));
1944     if (status & SCB_SW_INT) {
1945                 /* state is 2000 which seems ok
1946                    printf("wl%d diag(): unexpected initial state %\n",
1947                    unit, inw(PIOP0(base)));
1948                 */
1949         wlack(unit);
1950     }
1951     outw(PIOR1(base), OFFSET_CU);
1952     outw(PIOP1(base), 0);                       /* ac_status */
1953     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1954     if(wlcmd(unit, "diag()") == 0)
1955         return 0;
1956     outw(PIOR0(base), OFFSET_CU);
1957     if (inw(PIOP0(base)) & 0x0800) {
1958         printf("wl%d: i82586 Self Test failed!\n", unit);
1959         return 0;
1960     }
1961     return TRUE;
1962 }
1963
1964 /*
1965  * wlconfig:
1966  *
1967  *      This routine does a standard config of the WaveLAN board.
1968  *
1969  */
1970 static int
1971 wlconfig(int unit)
1972 {
1973     configure_t configure;
1974     struct wl_softc *sc = WLSOFTC(unit);
1975     short               base = sc->base;
1976
1977 #if     MULTICAST
1978 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1979     struct ifmultiaddr *ifma;
1980     u_char *addrp;
1981 #else
1982     struct ether_multi *enm;
1983     struct ether_multistep step;
1984 #endif
1985     int cnt = 0;
1986 #endif  /* MULTICAST */
1987
1988 #ifdef WLDEBUG
1989     if (sc->wl_if.if_flags & IFF_DEBUG)
1990         printf("wl%d: entered wlconfig()\n",unit);
1991 #endif
1992     outw(PIOR0(base), OFFSET_SCB);
1993     if (inw(PIOP0(base)) & SCB_SW_INT) {
1994         /*
1995           printf("wl%d config(): unexpected initial state %x\n",
1996           unit, inw(PIOP0(base)));
1997           */
1998     }
1999     wlack(unit);
2000
2001     outw(PIOR1(base), OFFSET_CU);
2002     outw(PIOP1(base), 0);                               /* ac_status */
2003     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
2004
2005 /* jrb hack */
2006     configure.fifolim_bytecnt   = 0x080c;
2007     configure.addrlen_mode      = 0x0600;
2008     configure.linprio_interframe        = 0x2060;
2009     configure.slot_time         = 0xf200;
2010     configure.hardware          = 0x0008;       /* tx even w/o CD */
2011     configure.min_frame_len     = 0x0040;
2012 #if 0
2013     /* This is the configuration block suggested by Marc Meertens
2014      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2015      * Ioannidis on 10 Nov 92.
2016      */
2017     configure.fifolim_bytecnt   = 0x040c;
2018     configure.addrlen_mode      = 0x0600;
2019     configure.linprio_interframe        = 0x2060;
2020     configure.slot_time         = 0xf000;
2021     configure.hardware          = 0x0008;       /* tx even w/o CD */
2022     configure.min_frame_len     = 0x0040;
2023 #else
2024     /*
2025      * below is the default board configuration from p2-28 from 586 book
2026      */
2027     configure.fifolim_bytecnt   = 0x080c;
2028     configure.addrlen_mode      = 0x2600;
2029     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
2030     configure.slot_time         = 0xf00c;       /* slottime=12    */
2031     configure.hardware          = 0x0008;       /* tx even w/o CD */
2032     configure.min_frame_len     = 0x0040;
2033 #endif
2034     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2035         configure.hardware |= 1;
2036     }
2037     outw(PIOR1(base), OFFSET_CU + 6);
2038     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2039
2040     if(wlcmd(unit, "config()-configure") == 0)
2041         return 0;
2042 #if     MULTICAST
2043     outw(PIOR1(base), OFFSET_CU);
2044     outw(PIOP1(base), 0);                               /* ac_status */
2045     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
2046     outw(PIOR1(base), OFFSET_CU + 8);
2047 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2048     for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2049          ifma = ifma->ifma_link.le_next) {
2050         if (ifma->ifma_addr->sa_family != AF_LINK)
2051             continue;
2052         
2053         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2054         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2055         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2056         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2057         ++cnt;
2058     }
2059 #else
2060     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2061     while (enm != NULL) {
2062         unsigned int lo, hi;
2063         /* break if setting a multicast range, else we would crash */
2064         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2065                 break;
2066         }
2067         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2068             + enm->enm_addrlo[5];
2069         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2070             + enm->enm_addrhi[5];
2071         while(lo <= hi) {
2072             outw(PIOP1(base),enm->enm_addrlo[0] +
2073                  (enm->enm_addrlo[1] << 8));
2074             outw(PIOP1(base),enm->enm_addrlo[2] +
2075                  ((lo >> 8) & 0xff00));
2076             outw(PIOP1(base), ((lo >> 8) & 0xff) +
2077                  ((lo << 8) & 0xff00));
2078 /* #define MCASTDEBUG */
2079 #ifdef MCASTDEBUG
2080 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2081                 enm->enm_addrlo[0],
2082                 enm->enm_addrlo[1],
2083                 enm->enm_addrlo[2],
2084                 enm->enm_addrlo[3],
2085                 enm->enm_addrlo[4],
2086                 enm->enm_addrlo[5]);
2087 #endif
2088             ++cnt;
2089             ++lo;
2090         }
2091         ETHER_NEXT_MULTI(step, enm);
2092     }
2093 #endif
2094     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
2095     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2096     if(wlcmd(unit, "config()-mcaddress") == 0)
2097         return 0;
2098 #endif  /* MULTICAST */
2099
2100     outw(PIOR1(base), OFFSET_CU);
2101     outw(PIOP1(base), 0);                               /* ac_status */
2102     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
2103     outw(PIOR1(base), OFFSET_CU + 6);
2104     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2105
2106     if(wlcmd(unit, "config()-address") == 0)
2107         return(0);
2108
2109     wlinitmmc(unit);
2110
2111     return(1);
2112 }
2113
2114 /*
2115  * wlcmd:
2116  *
2117  * Set channel attention bit and busy wait until command has
2118  * completed. Then acknowledge the command completion.
2119  */
2120 static int
2121 wlcmd(int unit, char *str)
2122 {
2123     struct wl_softc *sc = WLSOFTC(unit);
2124     short       base = sc->base;
2125     int i;
2126         
2127     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2128     outw(PIOP0(base), SCB_CU_STRT);
2129     
2130     SET_CHAN_ATTN(unit);
2131     
2132     outw(PIOR0(base), OFFSET_CU);
2133     for(i = 0; i < 0xffff; i++)
2134         if (inw(PIOP0(base)) & AC_SW_C)
2135             break;
2136     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2137         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2138                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2139         outw(PIOR0(base), OFFSET_SCB);
2140         printf("scb_status %x\n", inw(PIOP0(base)));
2141         outw(PIOR0(base), OFFSET_SCB+2);
2142         printf("scb_command %x\n", inw(PIOP0(base)));
2143         outw(PIOR0(base), OFFSET_SCB+4);
2144         printf("scb_cbl %x\n", inw(PIOP0(base)));
2145         outw(PIOR0(base), OFFSET_CU+2);
2146         printf("cu_cmd %x\n", inw(PIOP0(base)));
2147         return(0);
2148     }
2149
2150     outw(PIOR0(base), OFFSET_SCB);
2151     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2152         /*
2153           printf("wl%d %s: unexpected final state %x\n",
2154           unit, str, inw(PIOP0(base)));
2155           */
2156     }
2157     wlack(unit);
2158     return(TRUE);
2159 }       
2160
2161 /*
2162  * wlack: if the 82596 wants attention because it has finished
2163  * sending or receiving a packet, acknowledge its desire and
2164  * return bits indicating the kind of attention. wlack() returns
2165  * these bits so that the caller can service exactly the
2166  * conditions that wlack() acknowledged.
2167  */
2168 static int
2169 wlack(int unit)
2170 {
2171     int i;
2172     u_short cmd;
2173     struct wl_softc *sc = WLSOFTC(unit);
2174     short base = sc->base;
2175
2176     outw(PIOR1(base), OFFSET_SCB);
2177     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2178         return(0);
2179 #ifdef WLDEBUG
2180     if (sc->wl_if.if_flags & IFF_DEBUG)
2181         printf("wl%d: doing a wlack()\n",unit);
2182 #endif
2183     outw(PIOP1(base), cmd);
2184     SET_CHAN_ATTN(unit);
2185     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2186     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2187     if (i < 1)
2188         printf("wl%d wlack(): board not accepting command.\n", unit);
2189     return(cmd);
2190 }
2191
2192 static void
2193 wltbd(int unit)
2194 {
2195     struct wl_softc *sc = WLSOFTC(unit);
2196     short               base = sc->base;
2197     u_short             tbd_p = OFFSET_TBD;
2198     tbd_t               tbd;
2199     int                 i = 0;
2200     int                 sum = 0;
2201
2202     for (;;) {
2203         outw(PIOR1(base), tbd_p);
2204         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2205         sum += (tbd.act_count & ~TBD_SW_EOF);
2206         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2207                i++, tbd.buffer_addr,
2208                (tbd.act_count & ~TBD_SW_EOF), sum,
2209                tbd.next_tbd_offset, tbd.buffer_base);
2210         if (tbd.act_count & TBD_SW_EOF)
2211             break;
2212         tbd_p = tbd.next_tbd_offset;
2213     }
2214 }
2215
2216 static void
2217 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2218 {
2219     struct mbuf *tm_p = *tm_pp;
2220     u_char              *mb_p = *mb_pp;
2221     u_short             count = 0;
2222     u_char              *cp;
2223     int         len;
2224
2225     /*
2226      * can we get a run that will be coallesced or
2227      * that terminates before breaking
2228      */
2229     do {
2230         count += tm_p->m_len;
2231         if (tm_p->m_len & 1)
2232             break;
2233     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2234     if ( (tm_p == (struct mbuf *)0) ||
2235          count > HDW_THRESHOLD) {
2236         *countp = (*tm_pp)->m_len;
2237         *mb_pp = mtod((*tm_pp), u_char *);
2238         return;
2239     }
2240
2241     /* we need to copy */
2242     tm_p = *tm_pp;
2243     mb_p = *mb_pp;
2244     count = 0;
2245     cp = (u_char *) t_packet;
2246     for (;;) {
2247         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2248         count += len;
2249         if (count > HDW_THRESHOLD)
2250                         break;
2251         cp += len;
2252         if (tm_p->m_next == (struct mbuf *)0)
2253             break;
2254         tm_p = tm_p->m_next;
2255     }
2256     *countp = count;
2257     *mb_pp = (u_char *) t_packet;
2258     *tm_pp = tm_p;
2259     return;
2260 }
2261
2262
2263 static void
2264 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2265 {
2266     struct mbuf *tm_p = *tm_pp;
2267     u_short             count = 0;
2268     u_char              *cp = (u_char *) t_packet;
2269     int                 len;
2270
2271     /* we need to copy */
2272     for (;;) {
2273         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2274         count += len;
2275         cp += len;
2276         if (tm_p->m_next == (struct mbuf *)0)
2277             break;
2278         tm_p = tm_p->m_next;
2279     }
2280
2281     *countp = count;
2282     *mb_pp = (u_char *) t_packet;
2283     *tm_pp = tm_p;
2284     return;
2285 }
2286
2287 static void
2288 wlmmcstat(int unit)
2289 {
2290     struct wl_softc *sc = WLSOFTC(unit);
2291     short       base = sc->base;
2292     u_short tmp;
2293
2294     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2295            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2296     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2297     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2298     printf("Correct NWID's: %d, ", tmp);
2299     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2300     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2301     printf("Wrong NWID's: %d\n", tmp);
2302     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2303     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
2304            wlmmcread(base,MMC_SIGNAL_LVL),
2305            wlmmcread(base,MMC_SILENCE_LVL));
2306     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2307            wlmmcread(base,MMC_SIGN_QUAL),
2308            wlmmcread(base,MMC_NETW_ID_H),
2309            wlmmcread(base,MMC_NETW_ID_L),
2310            wlmmcread(base,MMC_DES_AVAIL));
2311 }
2312
2313 static u_short
2314 wlmmcread(u_int base, u_short reg)
2315 {
2316     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2317     outw(MMCR(base),reg << 1);
2318     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2319     return (u_short)inw(MMCR(base)) >> 8;
2320 }
2321
2322 static void
2323 getsnr(int unit)
2324 {
2325     MMC_WRITE(MMC_FREEZE,1);
2326     /* 
2327      * SNR retrieval procedure :
2328      *
2329      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2330      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2331      */
2332     MMC_WRITE(MMC_FREEZE,0);
2333     /*
2334      * SNR is signal:silence ratio.
2335      */
2336 }
2337
2338 /*
2339 ** wlgetpsa
2340 **
2341 ** Reads the psa for the wavelan at (base) into (buf)
2342 */
2343 static void
2344 wlgetpsa(int base, u_char *buf)
2345 {
2346     int i;
2347
2348     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2349     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2350
2351     for (i = 0; i < 0x40; i++) {
2352         outw(PIOR2(base), i);
2353         buf[i] = inb(PIOP2(base));
2354     }
2355     PCMD(base, HACR_DEFAULT);
2356     PCMD(base, HACR_DEFAULT);
2357 }
2358
2359 /*
2360 ** wlsetpsa
2361 **
2362 ** Writes the psa for wavelan (unit) from the softc back to the
2363 ** board.  Updates the CRC and sets the CRC OK flag.
2364 **
2365 ** Do not call this when the board is operating, as it doesn't 
2366 ** preserve the hacr.
2367 */
2368 static void
2369 wlsetpsa(int unit)
2370 {
2371     struct wl_softc *sc = WLSOFTC(unit);
2372     short       base = sc->base;
2373     int         i, oldpri;
2374     u_short     crc;
2375
2376     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
2377     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2378     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2379     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
2380
2381     oldpri = splimp();          /* ick, long pause */
2382     
2383     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2384     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2385     
2386     for (i = 0; i < 0x40; i++) {
2387         DELAY(DELAYCONST);
2388         outw(PIOR2(base),i);  /* write param memory */
2389         DELAY(DELAYCONST);
2390         outb(PIOP2(base), sc->psa[i]);
2391     }
2392     DELAY(DELAYCONST);
2393     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
2394     DELAY(DELAYCONST);
2395     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
2396     outb(PIOP2(base), 0xaa);    /* all OK */
2397     DELAY(DELAYCONST);
2398     
2399     PCMD(base, HACR_DEFAULT);
2400     PCMD(base, HACR_DEFAULT);
2401     
2402     splx(oldpri);
2403 }
2404
2405 /* 
2406 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2407 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2408 */
2409
2410 static u_int crc16_table[16] = { 
2411     0x0000, 0xCC01, 0xD801, 0x1400,
2412     0xF001, 0x3C00, 0x2800, 0xE401,
2413     0xA001, 0x6C00, 0x7800, 0xB401,
2414     0x5000, 0x9C01, 0x8801, 0x4400 
2415 };
2416
2417 static u_short
2418 wlpsacrc(u_char *buf)
2419 {
2420     u_short     crc = 0;
2421     int         i, r1;
2422     
2423     for (i = 0; i < 0x3d; i++, buf++) {
2424         /* lower 4 bits */
2425         r1 = crc16_table[crc & 0xF];
2426         crc = (crc >> 4) & 0x0FFF;
2427         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2428         
2429         /* upper 4 bits */
2430         r1 = crc16_table[crc & 0xF];
2431         crc = (crc >> 4) & 0x0FFF;
2432         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2433     }
2434     return(crc);
2435 }
2436 #ifdef WLCACHE
2437
2438 /*
2439  * wl_cache_store
2440  *
2441  * take input packet and cache various radio hw characteristics
2442  * indexed by MAC address.
2443  *
2444  * Some things to think about:
2445  *      note that no space is malloced. 
2446  *      We might hash the mac address if the cache were bigger.
2447  *      It is not clear that the cache is big enough.
2448  *              It is also not clear how big it should be.
2449  *      The cache is IP-specific.  We don't care about that as
2450  *              we want it to be IP-specific.
2451  *      The last N recv. packets are saved.  This will tend
2452  *              to reward agents and mobile hosts that beacon.
2453  *              That is probably fine for mobile ip.
2454  */
2455
2456 /* globals for wavelan signal strength cache */
2457 /* this should go into softc structure above. 
2458 */
2459
2460 /* set true if you want to limit cache items to broadcast/mcast 
2461  * only packets (not unicast)
2462  */
2463 static int wl_cache_mcastonly = 1;
2464 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
2465         &wl_cache_mcastonly, 0, "");
2466
2467 /* set true if you want to limit cache items to IP packets only
2468 */
2469 static int wl_cache_iponly = 1;
2470 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
2471         &wl_cache_iponly, 0, "");
2472
2473 /* zero out the cache
2474 */
2475 static void
2476 wl_cache_zero(int unit)
2477 {
2478         struct wl_softc *sc = WLSOFTC(unit);
2479
2480         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2481         sc->w_sigitems = 0;
2482         sc->w_nextcache = 0;
2483         sc->w_wrapindex = 0;
2484 }
2485
2486 /* store hw signal info in cache.
2487  * index is MAC address, but an ip src gets stored too
2488  * There are two filters here controllable via sysctl:
2489  *      throw out unicast (on by default, but can be turned off)
2490  *      throw out non-ip (on by default, but can be turned off)
2491  */
2492 static
2493 void wl_cache_store (int unit, int base, struct ether_header *eh,
2494                      struct mbuf *m)
2495 {
2496         struct ip *ip = NULL;   /* Avoid GCC warning */
2497         int i;
2498         int signal, silence;
2499         int w_insertcache;   /* computed index for cache entry storage */
2500         struct wl_softc *sc = WLSOFTC(unit);
2501         int ipflag = wl_cache_iponly;
2502
2503         /* filters:
2504          * 1. ip only
2505          * 2. configurable filter to throw out unicast packets,
2506          * keep multicast only.
2507          */
2508  
2509 #ifdef INET
2510         /* reject if not IP packet
2511         */
2512         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2513                 return;
2514         }
2515
2516         /* check if broadcast or multicast packet.  we toss
2517          * unicast packets
2518          */
2519         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2520                 return;
2521         }
2522
2523         /* find the ip header.  we want to store the ip_src
2524          * address.  use the mtod macro(in mbuf.h) 
2525          * to typecast m to struct ip *
2526          */
2527         if (ipflag) {
2528                 ip = mtod(m, struct ip *);
2529         }
2530         
2531         /* do a linear search for a matching MAC address 
2532          * in the cache table
2533          * . MAC address is 6 bytes,
2534          * . var w_nextcache holds total number of entries already cached
2535          */
2536         for(i = 0; i < sc->w_nextcache; i++) {
2537                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
2538                         /* Match!,
2539                          * so we already have this entry,
2540                          * update the data, and LRU age
2541                          */
2542                         break;  
2543                 }
2544         }
2545
2546         /* did we find a matching mac address?
2547          * if yes, then overwrite a previously existing cache entry
2548          */
2549         if (i <  sc->w_nextcache )   {
2550                 w_insertcache = i; 
2551         }
2552         /* else, have a new address entry,so
2553          * add this new entry,
2554          * if table full, then we need to replace entry
2555          */
2556         else    {                          
2557
2558                 /* check for space in cache table 
2559                  * note: w_nextcache also holds number of entries
2560                  * added in the cache table 
2561                  */
2562                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2563                         w_insertcache = sc->w_nextcache;
2564                         sc->w_nextcache++;                 
2565                         sc->w_sigitems = sc->w_nextcache;
2566                 }
2567                 /* no space found, so simply wrap with wrap index
2568                  * and "zap" the next entry
2569                  */
2570                 else {
2571                         if (sc->w_wrapindex == MAXCACHEITEMS) {
2572                                 sc->w_wrapindex = 0;
2573                         }
2574                         w_insertcache = sc->w_wrapindex++;
2575                 }
2576         }
2577
2578         /* invariant: w_insertcache now points at some slot
2579          * in cache.
2580          */
2581         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2582                 log(LOG_ERR, 
2583                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2584                         w_insertcache, MAXCACHEITEMS);
2585                 return;
2586         }
2587
2588         /*  store items in cache
2589          *  .ipsrc
2590          *  .macsrc
2591          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
2592          */
2593         if (ipflag) {
2594                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2595         }
2596         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
2597         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2598         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2599         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2600         if (signal > 0)
2601                 sc->w_sigcache[w_insertcache].snr = 
2602                         signal - silence;
2603         else
2604                 sc->w_sigcache[w_insertcache].snr = 0;
2605 #endif /* INET */
2606
2607 }
2608 #endif /* WLCACHE */
2609
2610 /*
2611  * determine if in all multicast mode or not
2612  * 
2613  * returns: 1 if IFF_ALLMULTI should be set
2614  *          else 0
2615  */
2616 #ifdef MULTICAST
2617
2618 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
2619 static int
2620 check_allmulti(int unit)
2621 {
2622     struct wl_softc *sc = WLSOFTC(unit);
2623     short  base = sc->base;
2624     struct ether_multi *enm;
2625     struct ether_multistep step;
2626
2627     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2628     while (enm != NULL) {
2629         unsigned int lo, hi;
2630 #ifdef MDEBUG
2631                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2632                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2633                 enm->enm_addrlo[5]);
2634                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2635                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2636                 enm->enm_addrhi[5]);
2637 #endif
2638         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2639                 return(1);
2640         }
2641         ETHER_NEXT_MULTI(step, enm);
2642     }
2643     return(0);
2644 }
2645 #endif
2646 #endif