Merge from vendor branch LIBARCHIVE:
[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.17 2005/02/20 03:58:04 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 SIOCSIFADDR:
1152     case SIOCGIFADDR:
1153     case SIOCSIFMTU:
1154         error = ether_ioctl(ifp, cmd, data);
1155         break;
1156
1157     case SIOCSIFFLAGS:
1158         if (ifp->if_flags & IFF_ALLMULTI) {
1159             mode |= MOD_ENAL;
1160         }
1161         if (ifp->if_flags & IFF_PROMISC) {
1162             mode |= MOD_PROM;
1163         }
1164         if(ifp->if_flags & IFF_LINK0) {
1165             mode |= MOD_PROM;
1166         }
1167         /*
1168          * force a complete reset if the recieve multicast/
1169          * promiscuous mode changes so that these take 
1170          * effect immediately.
1171          *
1172          */
1173         if (sc->mode != mode) {
1174             sc->mode = mode;
1175             if (sc->flags & DSF_RUNNING) {
1176                 sc->flags &= ~DSF_RUNNING;
1177                 wlinit(sc);
1178             }
1179         }
1180         /* if interface is marked DOWN and still running then
1181          * stop it.
1182          */
1183         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1184             printf("wl%d ioctl(): board is not running\n", unit);
1185             sc->flags &= ~DSF_RUNNING;
1186             sc->hacr &= ~HACR_INTRON;
1187             CMD(unit);            /* turn off interrupts */
1188         } 
1189         /* else if interface is UP and RUNNING, start it
1190                 */
1191         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1192             wlinit(sc);
1193         }
1194   
1195         /* if WLDEBUG set on interface, then printf rf-modem regs
1196         */
1197         if(ifp->if_flags & IFF_DEBUG)
1198             wlmmcstat(unit);
1199         break;
1200 #if     MULTICAST
1201     case SIOCADDMULTI:
1202     case SIOCDELMULTI:
1203
1204 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1205         if (cmd == SIOCADDMULTI) {
1206             error = ether_addmulti(ifr, &sc->wl_ac);
1207         }
1208         else {
1209             error = ether_delmulti(ifr, &sc->wl_ac);
1210         }
1211
1212         /* see if we should be in all multicast mode
1213          * note that 82586 cannot do that, must simulate with
1214          * promiscuous mode
1215          */
1216         if ( check_allmulti(unit)) {
1217                 ifp->if_flags |=  IFF_ALLMULTI;
1218                 sc->mode |= MOD_ENAL;
1219                 sc->flags &= ~DSF_RUNNING;
1220                 wlinit(sc);
1221                 error = 0;
1222                 break;
1223         }
1224
1225         if (error == ENETRESET) {
1226             if(sc->flags & DSF_RUNNING) {
1227                 sc->flags &= ~DSF_RUNNING;
1228                 wlinit(sc);
1229             }
1230             error = 0;
1231         }
1232 #else
1233         wlinit(sc);
1234 #endif
1235         break;
1236 #endif  /* MULTICAST */
1237
1238     /* DEVICE SPECIFIC */
1239
1240
1241         /* copy the PSA out to the caller */
1242     case SIOCGWLPSA:
1243         /* pointer to buffer in user space */
1244         up = (void *)ifr->ifr_data;
1245         /* work out if they're root */
1246         isroot = (suser(td) == 0);
1247         
1248         for (i = 0; i < 0x40; i++) {
1249             /* don't hand the DES key out to non-root users */
1250             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1251                 continue;
1252             if (subyte((up + i), sc->psa[i]))
1253                 return(EFAULT);
1254         }
1255         break;
1256
1257
1258         /* copy the PSA in from the caller; we only copy _some_ values */
1259     case SIOCSWLPSA:
1260         /* root only */
1261         if ((error = suser(td)))
1262             break;
1263         error = EINVAL; /* assume the worst */
1264         /* pointer to buffer in user space containing data */
1265         up = (void *)ifr->ifr_data;
1266         
1267         /* check validity of input range */
1268         for (i = 0; i < 0x40; i++)
1269             if (fubyte(up + i) < 0)
1270                 return(EFAULT);
1271
1272         /* check IRQ value */
1273         irqval = fubyte(up+WLPSA_IRQNO);
1274         for (irq = 15; irq >= 0; irq--)
1275             if(irqvals[irq] == irqval)
1276                 break;
1277         if (irq == 0)                   /* oops */
1278             break;
1279         /* new IRQ */
1280         sc->psa[WLPSA_IRQNO] = irqval;
1281
1282         /* local MAC */
1283         for (i = 0; i < 6; i++)
1284             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1285                 
1286         /* MAC select */        
1287         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1288         
1289         /* default nwid */
1290         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1291         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1292
1293         error = 0;
1294         wlsetpsa(unit);         /* update the PSA */
1295         break;
1296
1297
1298         /* get the current NWID out of the sc since we stored it there */
1299     case SIOCGWLCNWID:
1300         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1301         break;
1302
1303
1304         /*
1305          * change the nwid dynamically.  This
1306          * ONLY changes the radio modem and does not
1307          * change the PSA.
1308          *
1309          * 2 steps:
1310          *      1. save in softc "soft registers"
1311          *      2. save in radio modem (MMC)
1312          */
1313     case SIOCSWLCNWID:
1314         /* root only */
1315         if ((error = suser(td)))
1316             break;
1317         if (!(ifp->if_flags & IFF_UP)) {
1318             error = EIO;        /* only allowed while up */
1319         } else {
1320             /* 
1321              * soft c nwid shadows radio modem setting
1322              */
1323             sc->nwid[0] = (int)ifr->ifr_data >> 8;
1324             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1325             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1326             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1327         }
1328         break;
1329
1330         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
1331     case SIOCGWLEEPROM:
1332         /* root only */
1333         if ((error = suser(td)))
1334             break;
1335         /* pointer to buffer in user space */
1336         up = (void *)ifr->ifr_data;
1337         
1338         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
1339             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
1340             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
1341                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
1342             DELAY(40);                          /* 2.4 Gz                   */
1343             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
1344                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1345                ) return(EFAULT);                /* 2.4 Gz:                  */
1346             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
1347                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1348                ) return(EFAULT);                /* 2.4 Gz:                  */
1349         }
1350         break;
1351
1352 #ifdef WLCACHE
1353         /* zero (Delete) the wl cache */
1354     case SIOCDWLCACHE:
1355         /* root only */
1356         if ((error = suser(td)))
1357             break;
1358         wl_cache_zero(unit);
1359         break;
1360
1361         /* read out the number of used cache elements */
1362     case SIOCGWLCITEM:
1363         ifr->ifr_data = (caddr_t) sc->w_sigitems;
1364         break;
1365
1366         /* read out the wl cache */
1367     case SIOCGWLCACHE:
1368         /* pointer to buffer in user space */
1369         up = (void *)ifr->ifr_data;
1370         cpt = (char *) &sc->w_sigcache[0];
1371         size = sc->w_sigitems * sizeof(struct w_sigcache);
1372         
1373         for (i = 0; i < size; i++) {
1374             if (subyte((up + i), *cpt++))
1375                 return(EFAULT);
1376         }
1377         break;
1378 #endif
1379
1380     default:
1381         error = EINVAL;
1382     }
1383     splx(opri);
1384     return (error);
1385 }
1386
1387 /*
1388  * wlwatchdog():
1389  *
1390  * Called if the timer set in wlstart expires before an interrupt is received
1391  * from the wavelan.   It seems to lose interrupts sometimes.
1392  * The watchdog routine gets called if the transmitter failed to interrupt
1393  *
1394  * input        : which board is timing out
1395  * output       : board reset 
1396  *
1397  */
1398 static void
1399 wlwatchdog(void *vsc)
1400 {
1401     struct wl_softc *sc = vsc;
1402     int unit = sc->unit;
1403
1404     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1405     sc->wl_ac.ac_if.if_oerrors++;
1406     wlinit(sc);
1407 }
1408
1409 /*
1410  * wlintr:
1411  *
1412  *      This function is the interrupt handler for the WaveLAN
1413  *      board.  This routine will be called whenever either a packet
1414  *      is received, or a packet has successfully been transfered and
1415  *      the unit is ready to transmit another packet.
1416  *
1417  * input        : board number that interrupted
1418  * output       : either a packet is received, or a packet is transfered
1419  *
1420  */
1421 static void
1422 wlintr(unit)
1423 int unit;
1424 {
1425     struct wl_softc *sc = &wl_softc[unit];
1426     short               base = sc->base;
1427     int                 ac_status;
1428     u_short             int_type, int_type1;
1429
1430 #ifdef WLDEBUG
1431     if (sc->wl_if.if_flags & IFF_DEBUG)
1432         printf("wl%d: wlintr() called\n",unit);
1433 #endif
1434
1435     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1436         /* handle interrupt from the modem management controler */
1437         /* This will clear the interrupt condition */ 
1438         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1439     }
1440
1441     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
1442         /* commented out. jrb.  it happens when reinit occurs
1443            printf("wlintr: int_type %x, dump follows\n", int_type);
1444            wldump(unit);
1445            */
1446         return;
1447     }
1448
1449     if (gathersnr)
1450         getsnr(unit);
1451     for(;;) {
1452         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
1453         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1454         if (int_type == 0)                      /* no interrupts left */
1455             break;
1456
1457         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
1458         /* make sure no bits disappeared (others may appear) */
1459         if ((int_type & int_type1) != int_type)
1460             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1461                    int_type1, int_type);
1462         int_type = int_type1;                   /* go with the new status */
1463         /* 
1464          * incoming packet
1465          */
1466         if (int_type & SCB_SW_FR) {
1467             sc->wl_if.if_ipackets++;
1468             wlrcv(unit);
1469         }
1470         /*
1471          * receiver not ready
1472          */
1473         if (int_type & SCB_SW_RNR) {
1474             sc->wl_if.if_ierrors++;
1475 #ifdef  WLDEBUG
1476             if (sc->wl_if.if_flags & IFF_DEBUG)
1477                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1478                        unit, sc->begin_fd);
1479 #endif
1480             wlrustrt(unit);
1481         }
1482         /*
1483          * CU not ready
1484          */
1485         if (int_type & SCB_SW_CNA) {
1486             /*
1487              * At present, we don't care about CNA's.  We
1488              * believe they are a side effect of XMT.
1489              */
1490         }
1491         if (int_type & SCB_SW_CX) {
1492             /*
1493              * At present, we only request Interrupt for
1494              * XMT.
1495              */
1496             outw(PIOR1(base), OFFSET_CU);       /* get command status */
1497             ac_status = inw(PIOP1(base));
1498
1499             if (xmt_watch) {                    /* report some anomalies */
1500
1501                 if (sc->tbusy == 0) {
1502                     printf("wl%d: xmt intr but not busy, CU %04x\n",
1503                            unit, ac_status);
1504                 }
1505                 if (ac_status == 0) {
1506                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
1507                 }
1508                 if (ac_status & AC_SW_A) {
1509                     printf("wl%d: xmt aborted\n",unit);
1510                 }
1511 #ifdef  notdef
1512                 if (ac_status & TC_CARRIER) {
1513                     printf("wl%d: no carrier\n", unit);
1514                 }
1515 #endif  /* notdef */
1516                 if (ac_status & TC_CLS) {
1517                     printf("wl%d: no CTS\n", unit);
1518                 }
1519                 if (ac_status & TC_DMA) {
1520                     printf("wl%d: DMA underrun\n", unit);
1521                 }
1522                 if (ac_status & TC_DEFER) {
1523                     printf("wl%d: xmt deferred\n",unit);
1524                 }
1525                 if (ac_status & TC_SQE) {
1526                     printf("wl%d: heart beat\n", unit);
1527                 }
1528                 if (ac_status & TC_COLLISION) {
1529                     printf("wl%d: too many collisions\n", unit);
1530                 }
1531             }
1532             /* if the transmit actually failed, or returned some status */
1533             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1534                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1535                     sc->wl_if.if_oerrors++;
1536                 }
1537                 /* count collisions */
1538                 sc->wl_if.if_collisions += (ac_status & 0xf);
1539                 /* if TC_COLLISION set and collision count zero, 16 collisions */
1540                 if ((ac_status & 0x20) == 0x20) {
1541                     sc->wl_if.if_collisions += 0x10;
1542                 }
1543             }
1544             sc->tbusy = 0;
1545             callout_stop(&sc->watchdog_ch);
1546             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1547             wlstart(&(sc->wl_if));
1548         }
1549     }
1550     return;
1551 }
1552
1553 /*
1554  * wlrcv:
1555  *
1556  *      This routine is called by the interrupt handler to initiate a
1557  *      packet transfer from the board to the "if" layer above this
1558  *      driver.  This routine checks if a buffer has been successfully
1559  *      received by the WaveLAN.  If so, the routine wlread is called
1560  *      to do the actual transfer of the board data (including the
1561  *      ethernet header) into a packet (consisting of an mbuf chain).
1562  *
1563  * input        : number of the board to check
1564  * output       : if a packet is available, it is "sent up"
1565  *
1566  */
1567 static void
1568 wlrcv(int unit)
1569 {
1570     struct wl_softc *sc = WLSOFTC(unit);
1571     short       base = sc->base;
1572     u_short     fd_p, status, offset, link_offset;
1573
1574 #ifdef WLDEBUG
1575     if (sc->wl_if.if_flags & IFF_DEBUG)
1576         printf("wl%d: entered wlrcv()\n",unit);
1577 #endif
1578     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1579
1580         outw(PIOR0(base), fd_p + 0);    /* address of status */
1581         status = inw(PIOP0(base));
1582         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
1583         link_offset = inw(PIOP1(base));
1584         offset = inw(PIOP1(base));      /* rbd_offset */
1585         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1586             if (wlhwrst(unit) != TRUE)
1587                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1588             return;
1589         } else if (status & AC_SW_C) {
1590             if (status == (RFD_DONE|RFD_RSC)) {
1591                 /* lost one */
1592 #ifdef  WLDEBUG
1593                 if (sc->wl_if.if_flags & IFF_DEBUG)
1594                     printf("wl%d RCV: RSC %x\n", unit, status);
1595 #endif
1596                 sc->wl_if.if_ierrors++;
1597             } else if (!(status & RFD_OK)) {
1598                 printf("wl%d RCV: !OK %x\n", unit, status);
1599                 sc->wl_if.if_ierrors++;
1600             } else if (status & 0xfff) {        /* can't happen */
1601                 printf("wl%d RCV: ERRs %x\n", unit, status);
1602                 sc->wl_if.if_ierrors++;
1603             } else if (!wlread(unit, fd_p))
1604                 return;
1605
1606             if (!wlrequeue(unit, fd_p)) {
1607                 /* abort on chain error */
1608                 if (wlhwrst(unit) != TRUE)
1609                     printf("wl%d rcv(): hwrst trouble.\n", unit);
1610                 return;
1611             }
1612             sc->begin_fd = link_offset;
1613         } else {
1614             break;
1615         }
1616     }
1617     return;
1618 }
1619
1620 /*
1621  * wlrequeue:
1622  *
1623  *      This routine puts rbd's used in the last receive back onto the
1624  *      free list for the next receive.
1625  *
1626  */
1627 static int
1628 wlrequeue(int unit, u_short fd_p)
1629 {
1630     struct wl_softc *sc = WLSOFTC(unit);
1631     short               base = sc->base;
1632     fd_t                fd;
1633     u_short             l_rbdp, f_rbdp, rbd_offset;
1634
1635     outw(PIOR0(base), fd_p + 6);
1636     rbd_offset = inw(PIOP0(base));
1637     if ((f_rbdp = rbd_offset) != I82586NULL) {
1638         l_rbdp = f_rbdp;
1639         for(;;) {
1640             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
1641             if(inw(PIOP0(base)) & RBD_SW_EOF)
1642                 break;
1643             outw(PIOP0(base), 0);
1644             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
1645             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1646                 break;
1647         }
1648         outw(PIOP0(base), 0);
1649         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
1650         outw(PIOP0(base), I82586NULL);
1651         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
1652         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1653         outw(PIOR0(base), sc->end_rbd + 2);
1654         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
1655         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
1656         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1657         sc->end_rbd = l_rbdp;
1658     }
1659
1660     fd.status = 0;
1661     fd.command = AC_CW_EL;
1662     fd.link_offset = I82586NULL;
1663     fd.rbd_offset = I82586NULL;
1664     outw(PIOR1(base), fd_p);
1665     outsw(PIOP1(base), &fd, 8/2);
1666     
1667     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
1668     outw(PIOP1(base), 0);               /* command = 0 */
1669     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
1670     sc->end_fd = fd_p;
1671
1672     return 1;
1673 }
1674
1675 #ifdef  WLDEBUG
1676 static int xmt_debug = 0;
1677 #endif  /* WLDEBUG */
1678
1679 /*
1680  * wlxmt:
1681  *
1682  *      This routine fills in the appropriate registers and memory
1683  *      locations on the WaveLAN board and starts the board off on
1684  *      the transmit.
1685  *
1686  * input        : board number of interest, and a pointer to the mbuf
1687  * output       : board memory and registers are set for xfer and attention
1688  *
1689  */
1690 static void
1691 wlxmt(int unit, struct mbuf *m)
1692 {
1693     struct wl_softc *sc = WLSOFTC(unit);
1694     u_short             xmtdata_p = OFFSET_TBUF;
1695     u_short             xmtshort_p;
1696     struct      mbuf                    *tm_p = m;
1697     struct ether_header *eh_p = mtod(m, struct ether_header *);
1698     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1699     u_short                             count = m->m_len - sizeof(struct ether_header);
1700     ac_t                                cb;
1701     u_short                             tbd_p = OFFSET_TBD;
1702     u_short                             len, clen = 0;
1703     short                               base = sc->base;
1704     int                                 spin;
1705         
1706 #ifdef WLDEBUG
1707     if (sc->wl_if.if_flags & IFF_DEBUG)
1708         printf("wl%d: entered wlxmt()\n",unit);
1709 #endif
1710
1711     cb.ac_status = 0;
1712     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1713     cb.ac_link_offset = I82586NULL;
1714     outw(PIOR1(base), OFFSET_CU);
1715     outsw(PIOP1(base), &cb, 6/2);
1716     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
1717     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1718     outw(PIOP1(base), eh_p->ether_type);
1719
1720 #ifdef  WLDEBUG
1721     if (sc->wl_if.if_flags & IFF_DEBUG) {
1722         if (xmt_debug) {
1723             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
1724             printf("ether type %x\n", eh_p->ether_type);
1725         }
1726     }
1727 #endif  /* WLDEBUG */
1728     outw(PIOR0(base), OFFSET_TBD);
1729     outw(PIOP0(base), 0);               /* act_count */
1730     outw(PIOR1(base), OFFSET_TBD + 4);
1731     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
1732     outw(PIOP1(base), 0);               /* buffer_base */
1733     for (;;) {
1734         if (count) {
1735             if (clen + count > WAVELAN_MTU)
1736                 break;
1737             if (count & 1)
1738                 len = count + 1;
1739             else
1740                 len = count;
1741             outw(PIOR1(base), xmtdata_p);
1742             outsw(PIOP1(base), mb_p, len/2);
1743             clen += count;
1744             outw(PIOR0(base), tbd_p);  /* address of act_count */
1745             outw(PIOP0(base), inw(PIOP0(base)) + count);
1746             xmtdata_p += len;
1747             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1748                 break;
1749             if (count & 1) {
1750                 /* go to the next descriptor */
1751                 outw(PIOR0(base), tbd_p + 2);
1752                 tbd_p += sizeof (tbd_t);
1753                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1754                 outw(PIOR0(base), tbd_p);
1755                 outw(PIOP0(base), 0);   /* act_count */
1756                 outw(PIOR1(base), tbd_p + 4);
1757                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1758                 outw(PIOP1(base), 0);         /* buffer_base */
1759                 /* at the end -> coallesce remaining mbufs */
1760                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1761                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1762                     continue;
1763                 }
1764                 /* next mbuf short -> coallesce as needed */
1765                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1766 #define HDW_THRESHOLD 55
1767                      tm_p->m_len > HDW_THRESHOLD)
1768                     /* ok */;
1769                 else {
1770                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1771                     continue;
1772                 }
1773             }
1774         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1775             break;
1776         count = tm_p->m_len;
1777         mb_p = mtod(tm_p, u_char *);
1778 #ifdef  WLDEBUG
1779         if (sc->wl_if.if_flags & IFF_DEBUG)
1780             if (xmt_debug)
1781                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1782 #endif  /* WLDEBUG */
1783     }
1784 #ifdef  WLDEBUG
1785     if (sc->wl_if.if_flags & IFF_DEBUG)
1786         if (xmt_debug)
1787             printf("CLEN = %d\n", clen);
1788 #endif  /* WLDEBUG */
1789     outw(PIOR0(base), tbd_p);
1790     if (clen < ETHERMIN) {
1791         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1792         outw(PIOR1(base), xmtdata_p);
1793         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1794             outw(PIOP1(base), 0);
1795     }   
1796     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1797     outw(PIOR0(base), tbd_p + 2);
1798     outw(PIOP0(base), I82586NULL);
1799 #ifdef  WLDEBUG
1800     if (sc->wl_if.if_flags & IFF_DEBUG) {
1801         if (xmt_debug) {
1802             wltbd(unit);
1803             printf("\n");
1804         }
1805     }
1806 #endif  /* WLDEBUG */
1807
1808     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
1809     /* 
1810      * wait for 586 to clear previous command, complain if it takes
1811      * too long
1812      */
1813     for (spin = 1;;spin = (spin + 1) % 10000) {
1814         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
1815             break;
1816         }
1817         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
1818                 printf("wl%d: slow accepting xmit\n",unit);
1819         }
1820     }
1821     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
1822     SET_CHAN_ATTN(unit);
1823     
1824     m_freem(m);
1825
1826     /* XXX 
1827      * Pause to avoid transmit overrun problems.
1828      * The required delay tends to vary with platform type, and may be
1829      * related to interrupt loss.
1830      */
1831     if (wl_xmit_delay) {
1832         DELAY(wl_xmit_delay);
1833     }
1834     return;
1835 }
1836
1837 /*
1838  * wlbldru:
1839  *
1840  *      This function builds the linear linked lists of fd's and
1841  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
1842  *
1843  */
1844 static u_short
1845 wlbldru(int unit)
1846 {
1847     struct wl_softc *sc = WLSOFTC(unit);
1848     short       base = sc->base;
1849     fd_t        fd;
1850     rbd_t       rbd;
1851     u_short     fd_p = OFFSET_RU;
1852     u_short     rbd_p = OFFSET_RBD;
1853     int         i;
1854
1855     sc->begin_fd = fd_p;
1856     for(i = 0; i < N_FD; i++) {
1857         fd.status = 0;
1858         fd.command = 0;
1859         fd.link_offset = fd_p + sizeof(fd_t);
1860         fd.rbd_offset = I82586NULL;
1861         outw(PIOR1(base), fd_p);
1862         outsw(PIOP1(base), &fd, 8/2);
1863         fd_p = fd.link_offset;
1864     }
1865     fd_p -= sizeof(fd_t);
1866     sc->end_fd = fd_p;
1867     outw(PIOR1(base), fd_p + 2);
1868     outw(PIOP1(base), AC_CW_EL);        /* command */
1869     outw(PIOP1(base), I82586NULL);      /* link_offset */
1870     fd_p = OFFSET_RU;
1871     
1872     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
1873     outw(PIOP0(base), rbd_p);
1874     outw(PIOR1(base), rbd_p);
1875     for(i = 0; i < N_RBD; i++) {
1876         rbd.status = 0;
1877         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1878         rbd.buffer_base = 0;
1879         rbd.size = RCVBUFSIZE;
1880         if (i != N_RBD-1) {
1881             rbd_p += sizeof(ru_t);
1882             rbd.next_rbd_offset = rbd_p;
1883         } else {
1884             rbd.next_rbd_offset = I82586NULL;
1885             rbd.size |= AC_CW_EL;
1886             sc->end_rbd = rbd_p;
1887         }
1888         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1889         outw(PIOR1(base), rbd_p);
1890     }
1891     return sc->begin_fd;
1892 }
1893
1894 /*
1895  * wlrustrt:
1896  *
1897  *      This routine starts the receive unit running.  First checks if the
1898  *      board is actually ready, then the board is instructed to receive
1899  *      packets again.
1900  *
1901  */
1902 static void
1903 wlrustrt(int unit)
1904 {
1905     struct wl_softc *sc = WLSOFTC(unit);
1906     short               base = sc->base;
1907     u_short             rfa;
1908
1909 #ifdef WLDEBUG
1910     if (sc->wl_if.if_flags & IFF_DEBUG)
1911         printf("wl%d: entered wlrustrt()\n",unit);
1912 #endif
1913     outw(PIOR0(base), OFFSET_SCB);
1914     if (inw(PIOP0(base)) & SCB_RUS_READY){
1915         printf("wlrustrt: RUS_READY\n");
1916         return;
1917     }
1918
1919     outw(PIOR0(base), OFFSET_SCB + 2);
1920     outw(PIOP0(base), SCB_RU_STRT);             /* command */
1921     rfa = wlbldru(unit);
1922     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
1923     outw(PIOP0(base), rfa);
1924
1925     SET_CHAN_ATTN(unit);
1926     return;
1927 }
1928
1929 /*
1930  * wldiag:
1931  *
1932  *      This routine does a 586 op-code number 7, and obtains the
1933  *      diagnose status for the WaveLAN.
1934  *
1935  */
1936 static int
1937 wldiag(int unit)
1938 {
1939     struct wl_softc *sc = WLSOFTC(unit);
1940     short               base = sc->base;
1941     short status;
1942
1943 #ifdef WLDEBUG
1944     if (sc->wl_if.if_flags & IFF_DEBUG)
1945         printf("wl%d: entered wldiag()\n",unit);
1946 #endif
1947     outw(PIOR0(base), OFFSET_SCB);
1948     status = inw(PIOP0(base));
1949     if (status & SCB_SW_INT) {
1950                 /* state is 2000 which seems ok
1951                    printf("wl%d diag(): unexpected initial state %\n",
1952                    unit, inw(PIOP0(base)));
1953                 */
1954         wlack(unit);
1955     }
1956     outw(PIOR1(base), OFFSET_CU);
1957     outw(PIOP1(base), 0);                       /* ac_status */
1958     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1959     if(wlcmd(unit, "diag()") == 0)
1960         return 0;
1961     outw(PIOR0(base), OFFSET_CU);
1962     if (inw(PIOP0(base)) & 0x0800) {
1963         printf("wl%d: i82586 Self Test failed!\n", unit);
1964         return 0;
1965     }
1966     return TRUE;
1967 }
1968
1969 /*
1970  * wlconfig:
1971  *
1972  *      This routine does a standard config of the WaveLAN board.
1973  *
1974  */
1975 static int
1976 wlconfig(int unit)
1977 {
1978     configure_t configure;
1979     struct wl_softc *sc = WLSOFTC(unit);
1980     short               base = sc->base;
1981
1982 #if     MULTICAST
1983 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1984     struct ifmultiaddr *ifma;
1985     u_char *addrp;
1986 #else
1987     struct ether_multi *enm;
1988     struct ether_multistep step;
1989 #endif
1990     int cnt = 0;
1991 #endif  /* MULTICAST */
1992
1993 #ifdef WLDEBUG
1994     if (sc->wl_if.if_flags & IFF_DEBUG)
1995         printf("wl%d: entered wlconfig()\n",unit);
1996 #endif
1997     outw(PIOR0(base), OFFSET_SCB);
1998     if (inw(PIOP0(base)) & SCB_SW_INT) {
1999         /*
2000           printf("wl%d config(): unexpected initial state %x\n",
2001           unit, inw(PIOP0(base)));
2002           */
2003     }
2004     wlack(unit);
2005
2006     outw(PIOR1(base), OFFSET_CU);
2007     outw(PIOP1(base), 0);                               /* ac_status */
2008     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
2009
2010 /* jrb hack */
2011     configure.fifolim_bytecnt   = 0x080c;
2012     configure.addrlen_mode      = 0x0600;
2013     configure.linprio_interframe        = 0x2060;
2014     configure.slot_time         = 0xf200;
2015     configure.hardware          = 0x0008;       /* tx even w/o CD */
2016     configure.min_frame_len     = 0x0040;
2017 #if 0
2018     /* This is the configuration block suggested by Marc Meertens
2019      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2020      * Ioannidis on 10 Nov 92.
2021      */
2022     configure.fifolim_bytecnt   = 0x040c;
2023     configure.addrlen_mode      = 0x0600;
2024     configure.linprio_interframe        = 0x2060;
2025     configure.slot_time         = 0xf000;
2026     configure.hardware          = 0x0008;       /* tx even w/o CD */
2027     configure.min_frame_len     = 0x0040;
2028 #else
2029     /*
2030      * below is the default board configuration from p2-28 from 586 book
2031      */
2032     configure.fifolim_bytecnt   = 0x080c;
2033     configure.addrlen_mode      = 0x2600;
2034     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
2035     configure.slot_time         = 0xf00c;       /* slottime=12    */
2036     configure.hardware          = 0x0008;       /* tx even w/o CD */
2037     configure.min_frame_len     = 0x0040;
2038 #endif
2039     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2040         configure.hardware |= 1;
2041     }
2042     outw(PIOR1(base), OFFSET_CU + 6);
2043     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2044
2045     if(wlcmd(unit, "config()-configure") == 0)
2046         return 0;
2047 #if     MULTICAST
2048     outw(PIOR1(base), OFFSET_CU);
2049     outw(PIOP1(base), 0);                               /* ac_status */
2050     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
2051     outw(PIOR1(base), OFFSET_CU + 8);
2052 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2053     for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2054          ifma = ifma->ifma_link.le_next) {
2055         if (ifma->ifma_addr->sa_family != AF_LINK)
2056             continue;
2057         
2058         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2059         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2060         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2061         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2062         ++cnt;
2063     }
2064 #else
2065     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2066     while (enm != NULL) {
2067         unsigned int lo, hi;
2068         /* break if setting a multicast range, else we would crash */
2069         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2070                 break;
2071         }
2072         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2073             + enm->enm_addrlo[5];
2074         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2075             + enm->enm_addrhi[5];
2076         while(lo <= hi) {
2077             outw(PIOP1(base),enm->enm_addrlo[0] +
2078                  (enm->enm_addrlo[1] << 8));
2079             outw(PIOP1(base),enm->enm_addrlo[2] +
2080                  ((lo >> 8) & 0xff00));
2081             outw(PIOP1(base), ((lo >> 8) & 0xff) +
2082                  ((lo << 8) & 0xff00));
2083 /* #define MCASTDEBUG */
2084 #ifdef MCASTDEBUG
2085 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2086                 enm->enm_addrlo[0],
2087                 enm->enm_addrlo[1],
2088                 enm->enm_addrlo[2],
2089                 enm->enm_addrlo[3],
2090                 enm->enm_addrlo[4],
2091                 enm->enm_addrlo[5]);
2092 #endif
2093             ++cnt;
2094             ++lo;
2095         }
2096         ETHER_NEXT_MULTI(step, enm);
2097     }
2098 #endif
2099     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
2100     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2101     if(wlcmd(unit, "config()-mcaddress") == 0)
2102         return 0;
2103 #endif  /* MULTICAST */
2104
2105     outw(PIOR1(base), OFFSET_CU);
2106     outw(PIOP1(base), 0);                               /* ac_status */
2107     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
2108     outw(PIOR1(base), OFFSET_CU + 6);
2109     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2110
2111     if(wlcmd(unit, "config()-address") == 0)
2112         return(0);
2113
2114     wlinitmmc(unit);
2115
2116     return(1);
2117 }
2118
2119 /*
2120  * wlcmd:
2121  *
2122  * Set channel attention bit and busy wait until command has
2123  * completed. Then acknowledge the command completion.
2124  */
2125 static int
2126 wlcmd(int unit, char *str)
2127 {
2128     struct wl_softc *sc = WLSOFTC(unit);
2129     short       base = sc->base;
2130     int i;
2131         
2132     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2133     outw(PIOP0(base), SCB_CU_STRT);
2134     
2135     SET_CHAN_ATTN(unit);
2136     
2137     outw(PIOR0(base), OFFSET_CU);
2138     for(i = 0; i < 0xffff; i++)
2139         if (inw(PIOP0(base)) & AC_SW_C)
2140             break;
2141     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2142         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2143                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2144         outw(PIOR0(base), OFFSET_SCB);
2145         printf("scb_status %x\n", inw(PIOP0(base)));
2146         outw(PIOR0(base), OFFSET_SCB+2);
2147         printf("scb_command %x\n", inw(PIOP0(base)));
2148         outw(PIOR0(base), OFFSET_SCB+4);
2149         printf("scb_cbl %x\n", inw(PIOP0(base)));
2150         outw(PIOR0(base), OFFSET_CU+2);
2151         printf("cu_cmd %x\n", inw(PIOP0(base)));
2152         return(0);
2153     }
2154
2155     outw(PIOR0(base), OFFSET_SCB);
2156     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2157         /*
2158           printf("wl%d %s: unexpected final state %x\n",
2159           unit, str, inw(PIOP0(base)));
2160           */
2161     }
2162     wlack(unit);
2163     return(TRUE);
2164 }       
2165
2166 /*
2167  * wlack: if the 82596 wants attention because it has finished
2168  * sending or receiving a packet, acknowledge its desire and
2169  * return bits indicating the kind of attention. wlack() returns
2170  * these bits so that the caller can service exactly the
2171  * conditions that wlack() acknowledged.
2172  */
2173 static int
2174 wlack(int unit)
2175 {
2176     int i;
2177     u_short cmd;
2178     struct wl_softc *sc = WLSOFTC(unit);
2179     short base = sc->base;
2180
2181     outw(PIOR1(base), OFFSET_SCB);
2182     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2183         return(0);
2184 #ifdef WLDEBUG
2185     if (sc->wl_if.if_flags & IFF_DEBUG)
2186         printf("wl%d: doing a wlack()\n",unit);
2187 #endif
2188     outw(PIOP1(base), cmd);
2189     SET_CHAN_ATTN(unit);
2190     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2191     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2192     if (i < 1)
2193         printf("wl%d wlack(): board not accepting command.\n", unit);
2194     return(cmd);
2195 }
2196
2197 static void
2198 wltbd(int unit)
2199 {
2200     struct wl_softc *sc = WLSOFTC(unit);
2201     short               base = sc->base;
2202     u_short             tbd_p = OFFSET_TBD;
2203     tbd_t               tbd;
2204     int                 i = 0;
2205     int                 sum = 0;
2206
2207     for (;;) {
2208         outw(PIOR1(base), tbd_p);
2209         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2210         sum += (tbd.act_count & ~TBD_SW_EOF);
2211         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2212                i++, tbd.buffer_addr,
2213                (tbd.act_count & ~TBD_SW_EOF), sum,
2214                tbd.next_tbd_offset, tbd.buffer_base);
2215         if (tbd.act_count & TBD_SW_EOF)
2216             break;
2217         tbd_p = tbd.next_tbd_offset;
2218     }
2219 }
2220
2221 static void
2222 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2223 {
2224     struct mbuf *tm_p = *tm_pp;
2225     u_char              *mb_p = *mb_pp;
2226     u_short             count = 0;
2227     u_char              *cp;
2228     int         len;
2229
2230     /*
2231      * can we get a run that will be coallesced or
2232      * that terminates before breaking
2233      */
2234     do {
2235         count += tm_p->m_len;
2236         if (tm_p->m_len & 1)
2237             break;
2238     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2239     if ( (tm_p == (struct mbuf *)0) ||
2240          count > HDW_THRESHOLD) {
2241         *countp = (*tm_pp)->m_len;
2242         *mb_pp = mtod((*tm_pp), u_char *);
2243         return;
2244     }
2245
2246     /* we need to copy */
2247     tm_p = *tm_pp;
2248     mb_p = *mb_pp;
2249     count = 0;
2250     cp = (u_char *) t_packet;
2251     for (;;) {
2252         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2253         count += len;
2254         if (count > HDW_THRESHOLD)
2255                         break;
2256         cp += len;
2257         if (tm_p->m_next == (struct mbuf *)0)
2258             break;
2259         tm_p = tm_p->m_next;
2260     }
2261     *countp = count;
2262     *mb_pp = (u_char *) t_packet;
2263     *tm_pp = tm_p;
2264     return;
2265 }
2266
2267
2268 static void
2269 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2270 {
2271     struct mbuf *tm_p = *tm_pp;
2272     u_short             count = 0;
2273     u_char              *cp = (u_char *) t_packet;
2274     int                 len;
2275
2276     /* we need to copy */
2277     for (;;) {
2278         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2279         count += len;
2280         cp += len;
2281         if (tm_p->m_next == (struct mbuf *)0)
2282             break;
2283         tm_p = tm_p->m_next;
2284     }
2285
2286     *countp = count;
2287     *mb_pp = (u_char *) t_packet;
2288     *tm_pp = tm_p;
2289     return;
2290 }
2291
2292 static void
2293 wlmmcstat(int unit)
2294 {
2295     struct wl_softc *sc = WLSOFTC(unit);
2296     short       base = sc->base;
2297     u_short tmp;
2298
2299     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2300            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2301     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2302     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2303     printf("Correct NWID's: %d, ", tmp);
2304     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2305     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2306     printf("Wrong NWID's: %d\n", tmp);
2307     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2308     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
2309            wlmmcread(base,MMC_SIGNAL_LVL),
2310            wlmmcread(base,MMC_SILENCE_LVL));
2311     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2312            wlmmcread(base,MMC_SIGN_QUAL),
2313            wlmmcread(base,MMC_NETW_ID_H),
2314            wlmmcread(base,MMC_NETW_ID_L),
2315            wlmmcread(base,MMC_DES_AVAIL));
2316 }
2317
2318 static u_short
2319 wlmmcread(u_int base, u_short reg)
2320 {
2321     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2322     outw(MMCR(base),reg << 1);
2323     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2324     return (u_short)inw(MMCR(base)) >> 8;
2325 }
2326
2327 static void
2328 getsnr(int unit)
2329 {
2330     MMC_WRITE(MMC_FREEZE,1);
2331     /* 
2332      * SNR retrieval procedure :
2333      *
2334      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2335      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2336      */
2337     MMC_WRITE(MMC_FREEZE,0);
2338     /*
2339      * SNR is signal:silence ratio.
2340      */
2341 }
2342
2343 /*
2344 ** wlgetpsa
2345 **
2346 ** Reads the psa for the wavelan at (base) into (buf)
2347 */
2348 static void
2349 wlgetpsa(int base, u_char *buf)
2350 {
2351     int i;
2352
2353     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2354     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2355
2356     for (i = 0; i < 0x40; i++) {
2357         outw(PIOR2(base), i);
2358         buf[i] = inb(PIOP2(base));
2359     }
2360     PCMD(base, HACR_DEFAULT);
2361     PCMD(base, HACR_DEFAULT);
2362 }
2363
2364 /*
2365 ** wlsetpsa
2366 **
2367 ** Writes the psa for wavelan (unit) from the softc back to the
2368 ** board.  Updates the CRC and sets the CRC OK flag.
2369 **
2370 ** Do not call this when the board is operating, as it doesn't 
2371 ** preserve the hacr.
2372 */
2373 static void
2374 wlsetpsa(int unit)
2375 {
2376     struct wl_softc *sc = WLSOFTC(unit);
2377     short       base = sc->base;
2378     int         i, oldpri;
2379     u_short     crc;
2380
2381     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
2382     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2383     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2384     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
2385
2386     oldpri = splimp();          /* ick, long pause */
2387     
2388     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2389     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2390     
2391     for (i = 0; i < 0x40; i++) {
2392         DELAY(DELAYCONST);
2393         outw(PIOR2(base),i);  /* write param memory */
2394         DELAY(DELAYCONST);
2395         outb(PIOP2(base), sc->psa[i]);
2396     }
2397     DELAY(DELAYCONST);
2398     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
2399     DELAY(DELAYCONST);
2400     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
2401     outb(PIOP2(base), 0xaa);    /* all OK */
2402     DELAY(DELAYCONST);
2403     
2404     PCMD(base, HACR_DEFAULT);
2405     PCMD(base, HACR_DEFAULT);
2406     
2407     splx(oldpri);
2408 }
2409
2410 /* 
2411 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2412 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2413 */
2414
2415 static u_int crc16_table[16] = { 
2416     0x0000, 0xCC01, 0xD801, 0x1400,
2417     0xF001, 0x3C00, 0x2800, 0xE401,
2418     0xA001, 0x6C00, 0x7800, 0xB401,
2419     0x5000, 0x9C01, 0x8801, 0x4400 
2420 };
2421
2422 static u_short
2423 wlpsacrc(u_char *buf)
2424 {
2425     u_short     crc = 0;
2426     int         i, r1;
2427     
2428     for (i = 0; i < 0x3d; i++, buf++) {
2429         /* lower 4 bits */
2430         r1 = crc16_table[crc & 0xF];
2431         crc = (crc >> 4) & 0x0FFF;
2432         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2433         
2434         /* upper 4 bits */
2435         r1 = crc16_table[crc & 0xF];
2436         crc = (crc >> 4) & 0x0FFF;
2437         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2438     }
2439     return(crc);
2440 }
2441 #ifdef WLCACHE
2442
2443 /*
2444  * wl_cache_store
2445  *
2446  * take input packet and cache various radio hw characteristics
2447  * indexed by MAC address.
2448  *
2449  * Some things to think about:
2450  *      note that no space is malloced. 
2451  *      We might hash the mac address if the cache were bigger.
2452  *      It is not clear that the cache is big enough.
2453  *              It is also not clear how big it should be.
2454  *      The cache is IP-specific.  We don't care about that as
2455  *              we want it to be IP-specific.
2456  *      The last N recv. packets are saved.  This will tend
2457  *              to reward agents and mobile hosts that beacon.
2458  *              That is probably fine for mobile ip.
2459  */
2460
2461 /* globals for wavelan signal strength cache */
2462 /* this should go into softc structure above. 
2463 */
2464
2465 /* set true if you want to limit cache items to broadcast/mcast 
2466  * only packets (not unicast)
2467  */
2468 static int wl_cache_mcastonly = 1;
2469 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
2470         &wl_cache_mcastonly, 0, "");
2471
2472 /* set true if you want to limit cache items to IP packets only
2473 */
2474 static int wl_cache_iponly = 1;
2475 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
2476         &wl_cache_iponly, 0, "");
2477
2478 /* zero out the cache
2479 */
2480 static void
2481 wl_cache_zero(int unit)
2482 {
2483         struct wl_softc *sc = WLSOFTC(unit);
2484
2485         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2486         sc->w_sigitems = 0;
2487         sc->w_nextcache = 0;
2488         sc->w_wrapindex = 0;
2489 }
2490
2491 /* store hw signal info in cache.
2492  * index is MAC address, but an ip src gets stored too
2493  * There are two filters here controllable via sysctl:
2494  *      throw out unicast (on by default, but can be turned off)
2495  *      throw out non-ip (on by default, but can be turned off)
2496  */
2497 static
2498 void wl_cache_store (int unit, int base, struct ether_header *eh,
2499                      struct mbuf *m)
2500 {
2501         struct ip *ip = NULL;   /* Avoid GCC warning */
2502         int i;
2503         int signal, silence;
2504         int w_insertcache;   /* computed index for cache entry storage */
2505         struct wl_softc *sc = WLSOFTC(unit);
2506         int ipflag = wl_cache_iponly;
2507
2508         /* filters:
2509          * 1. ip only
2510          * 2. configurable filter to throw out unicast packets,
2511          * keep multicast only.
2512          */
2513  
2514 #ifdef INET
2515         /* reject if not IP packet
2516         */
2517         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2518                 return;
2519         }
2520
2521         /* check if broadcast or multicast packet.  we toss
2522          * unicast packets
2523          */
2524         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2525                 return;
2526         }
2527
2528         /* find the ip header.  we want to store the ip_src
2529          * address.  use the mtod macro(in mbuf.h) 
2530          * to typecast m to struct ip *
2531          */
2532         if (ipflag) {
2533                 ip = mtod(m, struct ip *);
2534         }
2535         
2536         /* do a linear search for a matching MAC address 
2537          * in the cache table
2538          * . MAC address is 6 bytes,
2539          * . var w_nextcache holds total number of entries already cached
2540          */
2541         for(i = 0; i < sc->w_nextcache; i++) {
2542                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
2543                         /* Match!,
2544                          * so we already have this entry,
2545                          * update the data, and LRU age
2546                          */
2547                         break;  
2548                 }
2549         }
2550
2551         /* did we find a matching mac address?
2552          * if yes, then overwrite a previously existing cache entry
2553          */
2554         if (i <  sc->w_nextcache )   {
2555                 w_insertcache = i; 
2556         }
2557         /* else, have a new address entry,so
2558          * add this new entry,
2559          * if table full, then we need to replace entry
2560          */
2561         else    {                          
2562
2563                 /* check for space in cache table 
2564                  * note: w_nextcache also holds number of entries
2565                  * added in the cache table 
2566                  */
2567                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2568                         w_insertcache = sc->w_nextcache;
2569                         sc->w_nextcache++;                 
2570                         sc->w_sigitems = sc->w_nextcache;
2571                 }
2572                 /* no space found, so simply wrap with wrap index
2573                  * and "zap" the next entry
2574                  */
2575                 else {
2576                         if (sc->w_wrapindex == MAXCACHEITEMS) {
2577                                 sc->w_wrapindex = 0;
2578                         }
2579                         w_insertcache = sc->w_wrapindex++;
2580                 }
2581         }
2582
2583         /* invariant: w_insertcache now points at some slot
2584          * in cache.
2585          */
2586         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2587                 log(LOG_ERR, 
2588                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2589                         w_insertcache, MAXCACHEITEMS);
2590                 return;
2591         }
2592
2593         /*  store items in cache
2594          *  .ipsrc
2595          *  .macsrc
2596          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
2597          */
2598         if (ipflag) {
2599                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2600         }
2601         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
2602         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2603         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2604         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2605         if (signal > 0)
2606                 sc->w_sigcache[w_insertcache].snr = 
2607                         signal - silence;
2608         else
2609                 sc->w_sigcache[w_insertcache].snr = 0;
2610 #endif /* INET */
2611
2612 }
2613 #endif /* WLCACHE */
2614
2615 /*
2616  * determine if in all multicast mode or not
2617  * 
2618  * returns: 1 if IFF_ALLMULTI should be set
2619  *          else 0
2620  */
2621 #ifdef MULTICAST
2622
2623 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
2624 static int
2625 check_allmulti(int unit)
2626 {
2627     struct wl_softc *sc = WLSOFTC(unit);
2628     short  base = sc->base;
2629     struct ether_multi *enm;
2630     struct ether_multistep step;
2631
2632     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2633     while (enm != NULL) {
2634         unsigned int lo, hi;
2635 #ifdef MDEBUG
2636                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2637                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2638                 enm->enm_addrlo[5]);
2639                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2640                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2641                 enm->enm_addrhi[5]);
2642 #endif
2643         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2644                 return(1);
2645         }
2646         ETHER_NEXT_MULTI(step, enm);
2647     }
2648     return(0);
2649 }
2650 #endif
2651 #endif