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