Announce MAC address in ether_ifattach, not in each NIC indepently.
[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.12 2004/07/02 17:42:20 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_handle 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_handle_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_output = ether_output;
500     ifp->if_start = wlstart;
501     ifp->if_ioctl = wlioctl;
502     ifp->if_timer = 0;   /* paranoia */
503     /* no entries
504        ifp->if_watchdog
505        ifp->if_done
506        ifp->if_reset
507        */
508     ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
509
510     bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
511     if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
512     if (sc->freq24) 
513         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
514     printf("\n");                                       /* 2.4 Gz       */
515
516
517     if (bootverbose)
518         wldump(unit);
519     return(1);
520 }
521
522 /*
523  * Print out interesting information about the 82596.
524  */
525 static void
526 wldump(int unit)
527 {
528     struct wl_softc *sp = WLSOFTC(unit);
529     int         base = sp->base;
530     int         i;
531         
532     printf("hasr %04x\n", inw(HASR(base)));
533         
534     printf("scb at %04x:\n ", OFFSET_SCB);
535     outw(PIOR1(base), OFFSET_SCB);
536     for(i = 0; i < 8; i++)
537         printf("%04x ", inw(PIOP1(base)));
538     printf("\n");
539         
540     printf("cu at %04x:\n ", OFFSET_CU);
541     outw(PIOR1(base), OFFSET_CU);
542     for(i = 0; i < 8; i++)
543         printf("%04x ", inw(PIOP1(base)));
544     printf("\n");
545         
546     printf("tbd at %04x:\n ", OFFSET_TBD);
547     outw(PIOR1(base), OFFSET_TBD);
548     for(i = 0; i < 4; i++)
549         printf("%04x ", inw(PIOP1(base)));
550     printf("\n");
551 }
552
553 /* Initialize the Modem Management Controller */
554 static void
555 wlinitmmc(int unit)
556 {
557     struct wl_softc *sp = WLSOFTC(unit);
558     int         base = sp->base;
559     int         configured;
560     int         mode = sp->mode;
561     int         i;                              /* 2.4 Gz               */
562         
563     /* enter 8 bit operation */
564     sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
565     CMD(unit);
566
567     configured = sp->psa[WLPSA_CONFIGURED] & 1;
568         
569     /*
570      * Set default modem control parameters.  Taken from NCR document
571      *  407-0024326 Rev. A 
572      */
573     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
574     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
575     MMC_WRITE(MMC_IFS, 0x20);
576     MMC_WRITE(MMC_MOD_DELAY, 0x04);
577     MMC_WRITE(MMC_JAM_TIME, 0x38);
578     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
579     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
580     if (!configured) {
581         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
582         if (sp->psa[WLPSA_COMPATNO] & 1) {
583             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
584         } else {
585             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
586         }
587         MMC_WRITE(MMC_QUALITY_THR, 0x03);
588     } else {
589         /* use configuration defaults from parameter storage area */
590         if (sp->psa[WLPSA_NWIDENABLE] & 1) {
591             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
592                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
593             } else {
594                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
595             }
596         } else {
597             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
598         }
599         MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
600         MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
601     }
602     MMC_WRITE(MMC_FREEZE, 0x00);
603     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
604
605     MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]);       /* set NWID */
606     MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
607
608     /* enter normal 16 bit mode operation */
609     sp->hacr = HACR_DEFAULT;
610     CMD(unit);
611     CMD(unit);                                  /* virtualpc1 needs this! */
612
613     if (sp->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
614                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
615         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
616         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
617         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
618                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
619         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
620             DELAY(40);                          /* 2.4 Gz             */
621             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
622                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
623                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
624                 break;                          /* 2.4 Gz: download finished */
625         }                                       /* 2.4 Gz                    */
626         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
627         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
628         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
629                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
630         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
631             DELAY(40);                          /* 2.4 Gz             */
632             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
633                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
634                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
635                 break;                          /* 2.4 Gz: download finished */
636         }                                       /* 2.4 Gz                    */
637         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
638         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
639                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
640                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
641         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
642         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
643         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
644                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
645         DELAY(40);                              /* 2.4 Gz                    */
646         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
647           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
648         sp->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
649     }
650 }
651
652 /*
653  * wlinit:
654  *
655  *      Another routine that interfaces the "if" layer to this driver.  
656  *      Simply resets the structures that are used by "upper layers".  
657  *      As well as calling wlhwrst that does reset the WaveLAN board.
658  *
659  * input        : softc pointer for this interface
660  * output       : structures (if structs) and board are reset
661  *
662  */     
663 static void
664 wlinit(void *xsc)
665 {
666     struct wl_softc *sc = xsc;
667     struct ifnet        *ifp = &sc->wl_if;
668     int                 stat;
669     u_long              oldpri;
670
671 #ifdef WLDEBUG
672     if (sc->wl_if.if_flags & IFF_DEBUG)
673         printf("wl%d: entered wlinit()\n",sc->unit);
674 #endif
675 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
676     if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
677 #else
678     if (ifp->if_addrlist == (struct ifaddr *)0) {
679 #endif
680         return;
681     }
682     oldpri = splimp();
683     if ((stat = wlhwrst(sc->unit)) == TRUE) {
684         sc->wl_if.if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
685         /* 
686          * OACTIVE is used by upper-level routines
687          * and must be set
688          */
689         sc->wl_if.if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
690                 
691         sc->flags |= DSF_RUNNING;
692         sc->tbusy = 0;
693         untimeout(wlwatchdog, sc, sc->watchdog_ch);
694                 
695         wlstart(ifp);
696     } else {
697         printf("wl%d init(): trouble resetting board.\n", sc->unit);
698     }
699     splx(oldpri);
700 }
701
702 /*
703  * wlhwrst:
704  *
705  *      This routine resets the WaveLAN board that corresponds to the 
706  *      board number passed in.
707  *
708  * input        : board number to do a hardware reset
709  * output       : board is reset
710  *
711  */
712 static int
713 wlhwrst(int unit)
714 {
715     struct wl_softc     *sc = WLSOFTC(unit);
716
717 #ifdef WLDEBUG
718     if (sc->wl_if.if_flags & IFF_DEBUG)
719         printf("wl%d: entered wlhwrst()\n",unit);
720 #endif
721     sc->hacr = HACR_RESET;
722     CMD(unit);                  /* reset the board */
723         
724     /* clear reset command and set PIO#1 in autoincrement mode */
725     sc->hacr = HACR_DEFAULT;
726     CMD(unit);
727
728 #ifdef  WLDEBUG
729     if (sc->wl_if.if_flags & IFF_DEBUG)
730         wlmmcstat(unit);        /* Display MMC registers */
731 #endif  /* WLDEBUG */
732     wlbldcu(unit);              /* set up command unit structures */
733     
734     if (wldiag(unit) == 0)
735         return(0);
736     
737     if (wlconfig(unit) == 0)
738             return(0);
739     /* 
740      * insert code for loopback test here
741      */
742     wlrustrt(unit);             /* start receive unit */
743
744     /* enable interrupts */
745     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
746     CMD(unit);
747     
748     return(1);
749 }
750
751 /*
752  * wlbldcu:
753  *
754  *      This function builds up the command unit structures.  It inits
755  *      the scp, iscp, scb, cb, tbd, and tbuf.
756  *
757  */
758 static void
759 wlbldcu(int unit)
760 {
761     struct wl_softc *sc = WLSOFTC(unit);
762     short               base = sc->base;
763     scp_t               scp;
764     iscp_t              iscp;
765     scb_t               scb;
766     ac_t                cb;
767     tbd_t               tbd;
768     int         i;
769
770     bzero(&scp, sizeof(scp));
771     scp.scp_sysbus = 0;
772     scp.scp_iscp = OFFSET_ISCP;
773     scp.scp_iscp_base = 0;
774     outw(PIOR1(base), OFFSET_SCP);
775     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
776
777     bzero(&iscp, sizeof(iscp));
778     iscp.iscp_busy = 1;
779     iscp.iscp_scb_offset = OFFSET_SCB;
780     iscp.iscp_scb = 0;
781     iscp.iscp_scb_base = 0;
782     outw(PIOR1(base), OFFSET_ISCP);
783     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
784
785     scb.scb_status = 0;
786     scb.scb_command = SCB_RESET;
787     scb.scb_cbl_offset = OFFSET_CU;
788     scb.scb_rfa_offset = OFFSET_RU;
789     scb.scb_crcerrs = 0;
790     scb.scb_alnerrs = 0;
791     scb.scb_rscerrs = 0;
792     scb.scb_ovrnerrs = 0;
793     outw(PIOR1(base), OFFSET_SCB);
794     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
795
796     SET_CHAN_ATTN(unit);
797
798     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
799     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
800     if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
801     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
802     for (i = STATUS_TRIES; i-- > 0; ) {
803         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
804             break;
805     }
806     if (i <= 0)
807         printf("wl%d bldcu(): not ready after reset.\n", unit);
808     wlack(unit);
809
810     cb.ac_status = 0;
811     cb.ac_command = AC_CW_EL;           /* NOP */
812     cb.ac_link_offset = OFFSET_CU;
813     outw(PIOR1(base), OFFSET_CU);
814     outsw(PIOP1(base), &cb, 6/2);
815
816     tbd.act_count = 0;
817     tbd.next_tbd_offset = I82586NULL;
818     tbd.buffer_addr = 0;
819     tbd.buffer_base = 0;
820     outw(PIOR1(base), OFFSET_TBD);
821     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
822 }
823
824 /*
825  * wlstart:
826  *
827  *      send a packet
828  *
829  * input        : board number
830  * output       : stuff sent to board if any there
831  *
832  */
833 static void
834 wlstart(struct ifnet *ifp)
835 {
836     int                         unit = ifp->if_dunit;
837     struct mbuf                 *m;
838     struct wl_softc     *sc = WLSOFTC(unit);
839     short                       base = sc->base;
840     int                         scb_status, cu_status, scb_command;
841
842 #ifdef WLDEBUG
843     if (sc->wl_if.if_flags & IFF_DEBUG)
844         printf("wl%d: entered wlstart()\n",unit);
845 #endif
846
847     outw(PIOR1(base), OFFSET_CU);
848     cu_status = inw(PIOP1(base));
849     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
850     scb_status = inw(PIOP0(base));
851     outw(PIOR0(base), OFFSET_SCB + 2);
852     scb_command = inw(PIOP0(base));
853
854     /*
855      * don't need OACTIVE check as tbusy here checks to see
856      * if we are already busy 
857      */
858     if (sc->tbusy) {
859         if((scb_status & 0x0700) == SCB_CUS_IDLE &&
860            (cu_status & AC_SW_B) == 0){
861             sc->tbusy = 0;
862             untimeout(wlwatchdog, sc, sc->watchdog_ch);
863             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
864             /*
865              * This is probably just a race.  The xmt'r is just
866              * became idle but WE have masked interrupts so ...
867              */
868 #ifdef WLDEBUG
869             printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
870                    unit, scb_status, scb_command, cu_status);
871 #endif 
872             if (xmt_watch) printf("!!");
873         } else {
874             return;     /* genuinely still busy */
875         }
876     } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
877               (cu_status & AC_SW_B)){
878 #ifdef WLDEBUG
879         printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
880                unit, scb_status, cu_status);
881 #endif
882         if (xmt_watch) printf("wl%d: busy?!",unit);
883         return;         /* hey, why are we busy? */
884     }
885
886     /* get ourselves some data */
887     ifp = &(sc->wl_if);
888     IF_DEQUEUE(&ifp->if_snd, m);
889     if (m != (struct mbuf *)0) {
890         /* let BPF see it before we commit it */
891         if (ifp->if_bpf) {
892             bpf_mtap(ifp, m);
893         }
894         sc->tbusy++;
895         /* set the watchdog timer so that if the board
896          * fails to interrupt we will restart
897          */
898         /* try 10 ticks, not very long */
899         sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
900         sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
901         sc->wl_if.if_opackets++;
902         wlxmt(unit, m);
903     } else {
904         sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
905     }
906     return;
907 }
908
909 /*
910  * wlread:
911  *
912  *      This routine does the actual copy of data (including ethernet header
913  *      structure) from the WaveLAN to an mbuf chain that will be passed up
914  *      to the "if" (network interface) layer.  NOTE:  we currently
915  *      don't handle trailer protocols, so if that is needed, it will
916  *      (at least in part) be added here.  For simplicities sake, this
917  *      routine copies the receive buffers from the board into a local (stack)
918  *      buffer until the frame has been copied from the board.  Once in
919  *      the local buffer, the contents are copied to an mbuf chain that
920  *      is then enqueued onto the appropriate "if" queue.
921  *
922  * input        : board number, and an frame descriptor address
923  * output       : the packet is put into an mbuf chain, and passed up
924  * assumes      : if any errors occur, packet is "dropped on the floor"
925  *
926  */
927 static int
928 wlread(int unit, u_short fd_p)
929 {
930     struct wl_softc     *sc = WLSOFTC(unit);
931     struct ifnet        *ifp = &sc->wl_if;
932     short                       base = sc->base;
933     fd_t                        fd;
934     struct ether_header         eh;
935     struct mbuf                 *m, *tm;
936     rbd_t                       rbd;
937     u_char                      *mb_p;
938     u_short                     mlen, len, clen;
939     u_short                     bytes_in_msg, bytes_in_mbuf, bytes;
940
941
942 #ifdef WLDEBUG
943     if (sc->wl_if.if_flags & IFF_DEBUG)
944         printf("wl%d: entered wlread()\n",unit);
945 #endif
946     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
947         printf("%s read(): board is not running.\n", ifp->if_xname);
948         sc->hacr &= ~HACR_INTRON;
949         CMD(unit);              /* turn off interrupts */
950     }
951     /* read ether_header info out of device memory. doesn't
952      * go into mbuf.  goes directly into eh structure
953      */
954     len = sizeof(struct ether_header);  /* 14 bytes */
955     outw(PIOR1(base), fd_p);
956     insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
957     insw(PIOP1(base), &eh, (len-2)/2);
958     eh.ether_type = ntohs(inw(PIOP1(base)));
959 #ifdef WLDEBUG
960     if (sc->wl_if.if_flags & IFF_DEBUG) {
961         printf("wlread: rcv packet, type is %x\n", eh.ether_type);
962     }
963 #endif 
964     /*
965      * WARNING.  above is done now in ether_input, above may be
966      * useful for debug. jrb
967      */
968     eh.ether_type = htons(eh.ether_type);
969
970     if (fd.rbd_offset == I82586NULL) {
971         printf("wl%d read(): Invalid buffer\n", unit);
972         if (wlhwrst(unit) != TRUE) {
973             printf("wl%d read(): hwrst trouble.\n", unit);
974         }
975         return 0;
976     }
977
978     outw(PIOR1(base), fd.rbd_offset);
979     insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
980     bytes_in_msg = rbd.status & RBD_SW_COUNT;
981     MGETHDR(m, MB_DONTWAIT, MT_DATA);
982     tm = m;
983     if (m == (struct mbuf *)0) {
984         /*
985          * not only do we want to return, we need to drop the packet on
986          * the floor to clear the interrupt.
987          *
988          */
989         if (wlhwrst(unit) != TRUE) {
990             sc->hacr &= ~HACR_INTRON;
991             CMD(unit);          /* turn off interrupts */
992             printf("wl%d read(): hwrst trouble.\n", unit);
993         }
994         return 0;
995     }
996     m->m_next = (struct mbuf *) 0;
997     m->m_pkthdr.rcvif = ifp;
998     m->m_pkthdr.len = 0; /* don't know this yet */
999     m->m_len = MHLEN;
1000
1001     /* always use a cluster. jrb 
1002      */
1003     MCLGET(m, MB_DONTWAIT);
1004     if (m->m_flags & M_EXT) {
1005         m->m_len = MCLBYTES;
1006     }
1007     else {
1008         m_freem(m);
1009         if (wlhwrst(unit) != TRUE) {
1010             sc->hacr &= ~HACR_INTRON;
1011             CMD(unit);          /* turn off interrupts */
1012             printf("wl%d read(): hwrst trouble.\n", unit);
1013         }
1014         return 0;
1015     }
1016
1017     mlen = 0;
1018     clen = mlen;
1019     bytes_in_mbuf = m->m_len;
1020     mb_p = mtod(tm, u_char *);
1021     bytes = min(bytes_in_mbuf, bytes_in_msg);
1022     for (;;) {
1023         if (bytes & 1) {
1024             len = bytes + 1;
1025         } else {
1026             len = bytes;
1027         }
1028         outw(PIOR1(base), rbd.buffer_addr);
1029         insw(PIOP1(base), mb_p, len/2);
1030         clen += bytes;
1031         mlen += bytes;
1032
1033         if (!(bytes_in_mbuf -= bytes)) {
1034             MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1035             tm = tm->m_next;
1036             if (tm == (struct mbuf *)0) {
1037                 m_freem(m);
1038                 printf("wl%d read(): No mbuf nth\n", unit);
1039                 if (wlhwrst(unit) != TRUE) {
1040                     sc->hacr &= ~HACR_INTRON;
1041                     CMD(unit);  /* turn off interrupts */
1042                     printf("wl%d read(): hwrst trouble.\n", unit);
1043                 }
1044                 return 0;
1045             }
1046             mlen = 0;
1047             tm->m_len = MLEN;
1048             bytes_in_mbuf = MLEN;
1049             mb_p = mtod(tm, u_char *);
1050         } else {
1051             mb_p += bytes;
1052         }
1053
1054         if (!(bytes_in_msg  -= bytes)) {
1055             if (rbd.status & RBD_SW_EOF ||
1056                 rbd.next_rbd_offset == I82586NULL) {
1057                 tm->m_len = mlen;
1058                 break;
1059             } else {
1060                 outw(PIOR1(base), rbd.next_rbd_offset);
1061                 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1062                 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1063             }
1064         } else {
1065             rbd.buffer_addr += bytes;
1066         }
1067
1068         bytes = min(bytes_in_mbuf, bytes_in_msg);
1069     }
1070
1071     m->m_pkthdr.len = clen;
1072
1073     /*
1074      * If hw is in promiscuous mode (note that I said hardware, not if
1075      * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1076      * packet and the MAC dst is not us, drop it.  This check in normally
1077      * inside ether_input(), but IFF_MULTI causes hw promisc without
1078      * a bpf listener, so this is wrong.
1079      *          Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1080      */
1081     /*
1082      * TBD: also discard packets where NWID does not match.
1083      * However, there does not appear to be a way to read the nwid
1084      * for a received packet.  -gdt 1998-08-07
1085      */
1086     if (
1087 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1088         (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1089 #else
1090         /* hw is in promisc mode if this is true */
1091         (sc->mode & (MOD_PROM | MOD_ENAL))
1092 #endif
1093         &&
1094         (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1095         bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1096              sizeof(eh.ether_dhost)) != 0 ) {
1097       m_freem(m);
1098       return 1;
1099     }
1100
1101 #ifdef WLDEBUG
1102     if (sc->wl_if.if_flags & IFF_DEBUG)
1103         printf("wl%d: wlrecv %d bytes\n", unit, clen);
1104 #endif
1105
1106 #ifdef WLCACHE
1107     wl_cache_store(unit, base, &eh, m);
1108 #endif
1109
1110     /*
1111      * received packet is now in a chain of mbuf's.  next step is
1112      * to pass the packet upwards.
1113      *
1114      */
1115     ether_input(&sc->wl_if, &eh, m);
1116     return 1;
1117 }
1118
1119 /*
1120  * wlioctl:
1121  *
1122  *      This routine processes an ioctl request from the "if" layer
1123  *      above.
1124  *
1125  * input        : pointer the appropriate "if" struct, command, and data
1126  * output       : based on command appropriate action is taken on the
1127  *                WaveLAN board(s) or related structures
1128  * return       : error is returned containing exit conditions
1129  *
1130  */
1131 static int
1132 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1133 {
1134     struct ifreq        *ifr = (struct ifreq *)data;
1135     int                         unit = ifp->if_dunit;
1136     struct wl_softc     *sc = WLSOFTC(unit);
1137     short               base = sc->base;
1138     short               mode = 0;
1139     int                 opri, error = 0;
1140     int                 irq, irqval, i, isroot, size;
1141     caddr_t             up;
1142     char *              cpt;
1143     struct thread *td = curthread; /* XXX */
1144         
1145
1146 #ifdef WLDEBUG
1147     if (sc->wl_if.if_flags & IFF_DEBUG)
1148         printf("wl%d: entered wlioctl()\n",unit);
1149 #endif
1150     opri = splimp();
1151     switch (cmd) {
1152     case SIOCSIFADDR:
1153     case SIOCGIFADDR:
1154     case SIOCSIFMTU:
1155         error = ether_ioctl(ifp, cmd, data);
1156         break;
1157
1158     case SIOCSIFFLAGS:
1159         if (ifp->if_flags & IFF_ALLMULTI) {
1160             mode |= MOD_ENAL;
1161         }
1162         if (ifp->if_flags & IFF_PROMISC) {
1163             mode |= MOD_PROM;
1164         }
1165         if(ifp->if_flags & IFF_LINK0) {
1166             mode |= MOD_PROM;
1167         }
1168         /*
1169          * force a complete reset if the recieve multicast/
1170          * promiscuous mode changes so that these take 
1171          * effect immediately.
1172          *
1173          */
1174         if (sc->mode != mode) {
1175             sc->mode = mode;
1176             if (sc->flags & DSF_RUNNING) {
1177                 sc->flags &= ~DSF_RUNNING;
1178                 wlinit(sc);
1179             }
1180         }
1181         /* if interface is marked DOWN and still running then
1182          * stop it.
1183          */
1184         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1185             printf("wl%d ioctl(): board is not running\n", unit);
1186             sc->flags &= ~DSF_RUNNING;
1187             sc->hacr &= ~HACR_INTRON;
1188             CMD(unit);            /* turn off interrupts */
1189         } 
1190         /* else if interface is UP and RUNNING, start it
1191                 */
1192         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1193             wlinit(sc);
1194         }
1195   
1196         /* if WLDEBUG set on interface, then printf rf-modem regs
1197         */
1198         if(ifp->if_flags & IFF_DEBUG)
1199             wlmmcstat(unit);
1200         break;
1201 #if     MULTICAST
1202     case SIOCADDMULTI:
1203     case SIOCDELMULTI:
1204
1205 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1206         if (cmd == SIOCADDMULTI) {
1207             error = ether_addmulti(ifr, &sc->wl_ac);
1208         }
1209         else {
1210             error = ether_delmulti(ifr, &sc->wl_ac);
1211         }
1212
1213         /* see if we should be in all multicast mode
1214          * note that 82586 cannot do that, must simulate with
1215          * promiscuous mode
1216          */
1217         if ( check_allmulti(unit)) {
1218                 ifp->if_flags |=  IFF_ALLMULTI;
1219                 sc->mode |= MOD_ENAL;
1220                 sc->flags &= ~DSF_RUNNING;
1221                 wlinit(sc);
1222                 error = 0;
1223                 break;
1224         }
1225
1226         if (error == ENETRESET) {
1227             if(sc->flags & DSF_RUNNING) {
1228                 sc->flags &= ~DSF_RUNNING;
1229                 wlinit(sc);
1230             }
1231             error = 0;
1232         }
1233 #else
1234         wlinit(sc);
1235 #endif
1236         break;
1237 #endif  /* MULTICAST */
1238
1239     /* DEVICE SPECIFIC */
1240
1241
1242         /* copy the PSA out to the caller */
1243     case SIOCGWLPSA:
1244         /* pointer to buffer in user space */
1245         up = (void *)ifr->ifr_data;
1246         /* work out if they're root */
1247         isroot = (suser(td) == 0);
1248         
1249         for (i = 0; i < 0x40; i++) {
1250             /* don't hand the DES key out to non-root users */
1251             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1252                 continue;
1253             if (subyte((up + i), sc->psa[i]))
1254                 return(EFAULT);
1255         }
1256         break;
1257
1258
1259         /* copy the PSA in from the caller; we only copy _some_ values */
1260     case SIOCSWLPSA:
1261         /* root only */
1262         if ((error = suser(td)))
1263             break;
1264         error = EINVAL; /* assume the worst */
1265         /* pointer to buffer in user space containing data */
1266         up = (void *)ifr->ifr_data;
1267         
1268         /* check validity of input range */
1269         for (i = 0; i < 0x40; i++)
1270             if (fubyte(up + i) < 0)
1271                 return(EFAULT);
1272
1273         /* check IRQ value */
1274         irqval = fubyte(up+WLPSA_IRQNO);
1275         for (irq = 15; irq >= 0; irq--)
1276             if(irqvals[irq] == irqval)
1277                 break;
1278         if (irq == 0)                   /* oops */
1279             break;
1280         /* new IRQ */
1281         sc->psa[WLPSA_IRQNO] = irqval;
1282
1283         /* local MAC */
1284         for (i = 0; i < 6; i++)
1285             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1286                 
1287         /* MAC select */        
1288         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1289         
1290         /* default nwid */
1291         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1292         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1293
1294         error = 0;
1295         wlsetpsa(unit);         /* update the PSA */
1296         break;
1297
1298
1299         /* get the current NWID out of the sc since we stored it there */
1300     case SIOCGWLCNWID:
1301         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1302         break;
1303
1304
1305         /*
1306          * change the nwid dynamically.  This
1307          * ONLY changes the radio modem and does not
1308          * change the PSA.
1309          *
1310          * 2 steps:
1311          *      1. save in softc "soft registers"
1312          *      2. save in radio modem (MMC)
1313          */
1314     case SIOCSWLCNWID:
1315         /* root only */
1316         if ((error = suser(td)))
1317             break;
1318         if (!(ifp->if_flags & IFF_UP)) {
1319             error = EIO;        /* only allowed while up */
1320         } else {
1321             /* 
1322              * soft c nwid shadows radio modem setting
1323              */
1324             sc->nwid[0] = (int)ifr->ifr_data >> 8;
1325             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1326             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1327             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1328         }
1329         break;
1330
1331         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
1332     case SIOCGWLEEPROM:
1333         /* root only */
1334         if ((error = suser(td)))
1335             break;
1336         /* pointer to buffer in user space */
1337         up = (void *)ifr->ifr_data;
1338         
1339         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
1340             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
1341             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
1342                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
1343             DELAY(40);                          /* 2.4 Gz                   */
1344             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
1345                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1346                ) return(EFAULT);                /* 2.4 Gz:                  */
1347             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
1348                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1349                ) return(EFAULT);                /* 2.4 Gz:                  */
1350         }
1351         break;
1352
1353 #ifdef WLCACHE
1354         /* zero (Delete) the wl cache */
1355     case SIOCDWLCACHE:
1356         /* root only */
1357         if ((error = suser(td)))
1358             break;
1359         wl_cache_zero(unit);
1360         break;
1361
1362         /* read out the number of used cache elements */
1363     case SIOCGWLCITEM:
1364         ifr->ifr_data = (caddr_t) sc->w_sigitems;
1365         break;
1366
1367         /* read out the wl cache */
1368     case SIOCGWLCACHE:
1369         /* pointer to buffer in user space */
1370         up = (void *)ifr->ifr_data;
1371         cpt = (char *) &sc->w_sigcache[0];
1372         size = sc->w_sigitems * sizeof(struct w_sigcache);
1373         
1374         for (i = 0; i < size; i++) {
1375             if (subyte((up + i), *cpt++))
1376                 return(EFAULT);
1377         }
1378         break;
1379 #endif
1380
1381     default:
1382         error = EINVAL;
1383     }
1384     splx(opri);
1385     return (error);
1386 }
1387
1388 /*
1389  * wlwatchdog():
1390  *
1391  * Called if the timer set in wlstart expires before an interrupt is received
1392  * from the wavelan.   It seems to lose interrupts sometimes.
1393  * The watchdog routine gets called if the transmitter failed to interrupt
1394  *
1395  * input        : which board is timing out
1396  * output       : board reset 
1397  *
1398  */
1399 static void
1400 wlwatchdog(void *vsc)
1401 {
1402     struct wl_softc *sc = vsc;
1403     int unit = sc->unit;
1404
1405     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1406     sc->wl_ac.ac_if.if_oerrors++;
1407     wlinit(sc);
1408 }
1409
1410 /*
1411  * wlintr:
1412  *
1413  *      This function is the interrupt handler for the WaveLAN
1414  *      board.  This routine will be called whenever either a packet
1415  *      is received, or a packet has successfully been transfered and
1416  *      the unit is ready to transmit another packet.
1417  *
1418  * input        : board number that interrupted
1419  * output       : either a packet is received, or a packet is transfered
1420  *
1421  */
1422 static void
1423 wlintr(unit)
1424 int unit;
1425 {
1426     struct wl_softc *sc = &wl_softc[unit];
1427     short               base = sc->base;
1428     int                 ac_status;
1429     u_short             int_type, int_type1;
1430
1431 #ifdef WLDEBUG
1432     if (sc->wl_if.if_flags & IFF_DEBUG)
1433         printf("wl%d: wlintr() called\n",unit);
1434 #endif
1435
1436     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1437         /* handle interrupt from the modem management controler */
1438         /* This will clear the interrupt condition */ 
1439         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1440     }
1441
1442     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
1443         /* commented out. jrb.  it happens when reinit occurs
1444            printf("wlintr: int_type %x, dump follows\n", int_type);
1445            wldump(unit);
1446            */
1447         return;
1448     }
1449
1450     if (gathersnr)
1451         getsnr(unit);
1452     for(;;) {
1453         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
1454         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1455         if (int_type == 0)                      /* no interrupts left */
1456             break;
1457
1458         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
1459         /* make sure no bits disappeared (others may appear) */
1460         if ((int_type & int_type1) != int_type)
1461             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1462                    int_type1, int_type);
1463         int_type = int_type1;                   /* go with the new status */
1464         /* 
1465          * incoming packet
1466          */
1467         if (int_type & SCB_SW_FR) {
1468             sc->wl_if.if_ipackets++;
1469             wlrcv(unit);
1470         }
1471         /*
1472          * receiver not ready
1473          */
1474         if (int_type & SCB_SW_RNR) {
1475             sc->wl_if.if_ierrors++;
1476 #ifdef  WLDEBUG
1477             if (sc->wl_if.if_flags & IFF_DEBUG)
1478                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1479                        unit, sc->begin_fd);
1480 #endif
1481             wlrustrt(unit);
1482         }
1483         /*
1484          * CU not ready
1485          */
1486         if (int_type & SCB_SW_CNA) {
1487             /*
1488              * At present, we don't care about CNA's.  We
1489              * believe they are a side effect of XMT.
1490              */
1491         }
1492         if (int_type & SCB_SW_CX) {
1493             /*
1494              * At present, we only request Interrupt for
1495              * XMT.
1496              */
1497             outw(PIOR1(base), OFFSET_CU);       /* get command status */
1498             ac_status = inw(PIOP1(base));
1499
1500             if (xmt_watch) {                    /* report some anomalies */
1501
1502                 if (sc->tbusy == 0) {
1503                     printf("wl%d: xmt intr but not busy, CU %04x\n",
1504                            unit, ac_status);
1505                 }
1506                 if (ac_status == 0) {
1507                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
1508                 }
1509                 if (ac_status & AC_SW_A) {
1510                     printf("wl%d: xmt aborted\n",unit);
1511                 }
1512 #ifdef  notdef
1513                 if (ac_status & TC_CARRIER) {
1514                     printf("wl%d: no carrier\n", unit);
1515                 }
1516 #endif  /* notdef */
1517                 if (ac_status & TC_CLS) {
1518                     printf("wl%d: no CTS\n", unit);
1519                 }
1520                 if (ac_status & TC_DMA) {
1521                     printf("wl%d: DMA underrun\n", unit);
1522                 }
1523                 if (ac_status & TC_DEFER) {
1524                     printf("wl%d: xmt deferred\n",unit);
1525                 }
1526                 if (ac_status & TC_SQE) {
1527                     printf("wl%d: heart beat\n", unit);
1528                 }
1529                 if (ac_status & TC_COLLISION) {
1530                     printf("wl%d: too many collisions\n", unit);
1531                 }
1532             }
1533             /* if the transmit actually failed, or returned some status */
1534             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1535                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1536                     sc->wl_if.if_oerrors++;
1537                 }
1538                 /* count collisions */
1539                 sc->wl_if.if_collisions += (ac_status & 0xf);
1540                 /* if TC_COLLISION set and collision count zero, 16 collisions */
1541                 if ((ac_status & 0x20) == 0x20) {
1542                     sc->wl_if.if_collisions += 0x10;
1543                 }
1544             }
1545             sc->tbusy = 0;
1546             untimeout(wlwatchdog, sc, sc->watchdog_ch);
1547             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1548             wlstart(&(sc->wl_if));
1549         }
1550     }
1551     return;
1552 }
1553
1554 /*
1555  * wlrcv:
1556  *
1557  *      This routine is called by the interrupt handler to initiate a
1558  *      packet transfer from the board to the "if" layer above this
1559  *      driver.  This routine checks if a buffer has been successfully
1560  *      received by the WaveLAN.  If so, the routine wlread is called
1561  *      to do the actual transfer of the board data (including the
1562  *      ethernet header) into a packet (consisting of an mbuf chain).
1563  *
1564  * input        : number of the board to check
1565  * output       : if a packet is available, it is "sent up"
1566  *
1567  */
1568 static void
1569 wlrcv(int unit)
1570 {
1571     struct wl_softc *sc = WLSOFTC(unit);
1572     short       base = sc->base;
1573     u_short     fd_p, status, offset, link_offset;
1574
1575 #ifdef WLDEBUG
1576     if (sc->wl_if.if_flags & IFF_DEBUG)
1577         printf("wl%d: entered wlrcv()\n",unit);
1578 #endif
1579     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1580
1581         outw(PIOR0(base), fd_p + 0);    /* address of status */
1582         status = inw(PIOP0(base));
1583         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
1584         link_offset = inw(PIOP1(base));
1585         offset = inw(PIOP1(base));      /* rbd_offset */
1586         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1587             if (wlhwrst(unit) != TRUE)
1588                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1589             return;
1590         } else if (status & AC_SW_C) {
1591             if (status == (RFD_DONE|RFD_RSC)) {
1592                 /* lost one */
1593 #ifdef  WLDEBUG
1594                 if (sc->wl_if.if_flags & IFF_DEBUG)
1595                     printf("wl%d RCV: RSC %x\n", unit, status);
1596 #endif
1597                 sc->wl_if.if_ierrors++;
1598             } else if (!(status & RFD_OK)) {
1599                 printf("wl%d RCV: !OK %x\n", unit, status);
1600                 sc->wl_if.if_ierrors++;
1601             } else if (status & 0xfff) {        /* can't happen */
1602                 printf("wl%d RCV: ERRs %x\n", unit, status);
1603                 sc->wl_if.if_ierrors++;
1604             } else if (!wlread(unit, fd_p))
1605                 return;
1606
1607             if (!wlrequeue(unit, fd_p)) {
1608                 /* abort on chain error */
1609                 if (wlhwrst(unit) != TRUE)
1610                     printf("wl%d rcv(): hwrst trouble.\n", unit);
1611                 return;
1612             }
1613             sc->begin_fd = link_offset;
1614         } else {
1615             break;
1616         }
1617     }
1618     return;
1619 }
1620
1621 /*
1622  * wlrequeue:
1623  *
1624  *      This routine puts rbd's used in the last receive back onto the
1625  *      free list for the next receive.
1626  *
1627  */
1628 static int
1629 wlrequeue(int unit, u_short fd_p)
1630 {
1631     struct wl_softc *sc = WLSOFTC(unit);
1632     short               base = sc->base;
1633     fd_t                fd;
1634     u_short             l_rbdp, f_rbdp, rbd_offset;
1635
1636     outw(PIOR0(base), fd_p + 6);
1637     rbd_offset = inw(PIOP0(base));
1638     if ((f_rbdp = rbd_offset) != I82586NULL) {
1639         l_rbdp = f_rbdp;
1640         for(;;) {
1641             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
1642             if(inw(PIOP0(base)) & RBD_SW_EOF)
1643                 break;
1644             outw(PIOP0(base), 0);
1645             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
1646             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1647                 break;
1648         }
1649         outw(PIOP0(base), 0);
1650         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
1651         outw(PIOP0(base), I82586NULL);
1652         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
1653         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1654         outw(PIOR0(base), sc->end_rbd + 2);
1655         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
1656         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
1657         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1658         sc->end_rbd = l_rbdp;
1659     }
1660
1661     fd.status = 0;
1662     fd.command = AC_CW_EL;
1663     fd.link_offset = I82586NULL;
1664     fd.rbd_offset = I82586NULL;
1665     outw(PIOR1(base), fd_p);
1666     outsw(PIOP1(base), &fd, 8/2);
1667     
1668     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
1669     outw(PIOP1(base), 0);               /* command = 0 */
1670     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
1671     sc->end_fd = fd_p;
1672
1673     return 1;
1674 }
1675
1676 #ifdef  WLDEBUG
1677 static int xmt_debug = 0;
1678 #endif  /* WLDEBUG */
1679
1680 /*
1681  * wlxmt:
1682  *
1683  *      This routine fills in the appropriate registers and memory
1684  *      locations on the WaveLAN board and starts the board off on
1685  *      the transmit.
1686  *
1687  * input        : board number of interest, and a pointer to the mbuf
1688  * output       : board memory and registers are set for xfer and attention
1689  *
1690  */
1691 static void
1692 wlxmt(int unit, struct mbuf *m)
1693 {
1694     struct wl_softc *sc = WLSOFTC(unit);
1695     u_short             xmtdata_p = OFFSET_TBUF;
1696     u_short             xmtshort_p;
1697     struct      mbuf                    *tm_p = m;
1698     struct ether_header *eh_p = mtod(m, struct ether_header *);
1699     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1700     u_short                             count = m->m_len - sizeof(struct ether_header);
1701     ac_t                                cb;
1702     u_short                             tbd_p = OFFSET_TBD;
1703     u_short                             len, clen = 0;
1704     short                               base = sc->base;
1705     int                                 spin;
1706         
1707 #ifdef WLDEBUG
1708     if (sc->wl_if.if_flags & IFF_DEBUG)
1709         printf("wl%d: entered wlxmt()\n",unit);
1710 #endif
1711
1712     cb.ac_status = 0;
1713     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1714     cb.ac_link_offset = I82586NULL;
1715     outw(PIOR1(base), OFFSET_CU);
1716     outsw(PIOP1(base), &cb, 6/2);
1717     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
1718     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1719     outw(PIOP1(base), eh_p->ether_type);
1720
1721 #ifdef  WLDEBUG
1722     if (sc->wl_if.if_flags & IFF_DEBUG) {
1723         if (xmt_debug) {
1724             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
1725             printf("ether type %x\n", eh_p->ether_type);
1726         }
1727     }
1728 #endif  /* WLDEBUG */
1729     outw(PIOR0(base), OFFSET_TBD);
1730     outw(PIOP0(base), 0);               /* act_count */
1731     outw(PIOR1(base), OFFSET_TBD + 4);
1732     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
1733     outw(PIOP1(base), 0);               /* buffer_base */
1734     for (;;) {
1735         if (count) {
1736             if (clen + count > WAVELAN_MTU)
1737                 break;
1738             if (count & 1)
1739                 len = count + 1;
1740             else
1741                 len = count;
1742             outw(PIOR1(base), xmtdata_p);
1743             outsw(PIOP1(base), mb_p, len/2);
1744             clen += count;
1745             outw(PIOR0(base), tbd_p);  /* address of act_count */
1746             outw(PIOP0(base), inw(PIOP0(base)) + count);
1747             xmtdata_p += len;
1748             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1749                 break;
1750             if (count & 1) {
1751                 /* go to the next descriptor */
1752                 outw(PIOR0(base), tbd_p + 2);
1753                 tbd_p += sizeof (tbd_t);
1754                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1755                 outw(PIOR0(base), tbd_p);
1756                 outw(PIOP0(base), 0);   /* act_count */
1757                 outw(PIOR1(base), tbd_p + 4);
1758                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1759                 outw(PIOP1(base), 0);         /* buffer_base */
1760                 /* at the end -> coallesce remaining mbufs */
1761                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1762                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1763                     continue;
1764                 }
1765                 /* next mbuf short -> coallesce as needed */
1766                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1767 #define HDW_THRESHOLD 55
1768                      tm_p->m_len > HDW_THRESHOLD)
1769                     /* ok */;
1770                 else {
1771                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1772                     continue;
1773                 }
1774             }
1775         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1776             break;
1777         count = tm_p->m_len;
1778         mb_p = mtod(tm_p, u_char *);
1779 #ifdef  WLDEBUG
1780         if (sc->wl_if.if_flags & IFF_DEBUG)
1781             if (xmt_debug)
1782                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1783 #endif  /* WLDEBUG */
1784     }
1785 #ifdef  WLDEBUG
1786     if (sc->wl_if.if_flags & IFF_DEBUG)
1787         if (xmt_debug)
1788             printf("CLEN = %d\n", clen);
1789 #endif  /* WLDEBUG */
1790     outw(PIOR0(base), tbd_p);
1791     if (clen < ETHERMIN) {
1792         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1793         outw(PIOR1(base), xmtdata_p);
1794         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1795             outw(PIOP1(base), 0);
1796     }   
1797     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1798     outw(PIOR0(base), tbd_p + 2);
1799     outw(PIOP0(base), I82586NULL);
1800 #ifdef  WLDEBUG
1801     if (sc->wl_if.if_flags & IFF_DEBUG) {
1802         if (xmt_debug) {
1803             wltbd(unit);
1804             printf("\n");
1805         }
1806     }
1807 #endif  /* WLDEBUG */
1808
1809     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
1810     /* 
1811      * wait for 586 to clear previous command, complain if it takes
1812      * too long
1813      */
1814     for (spin = 1;;spin = (spin + 1) % 10000) {
1815         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
1816             break;
1817         }
1818         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
1819                 printf("wl%d: slow accepting xmit\n",unit);
1820         }
1821     }
1822     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
1823     SET_CHAN_ATTN(unit);
1824     
1825     m_freem(m);
1826
1827     /* XXX 
1828      * Pause to avoid transmit overrun problems.
1829      * The required delay tends to vary with platform type, and may be
1830      * related to interrupt loss.
1831      */
1832     if (wl_xmit_delay) {
1833         DELAY(wl_xmit_delay);
1834     }
1835     return;
1836 }
1837
1838 /*
1839  * wlbldru:
1840  *
1841  *      This function builds the linear linked lists of fd's and
1842  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
1843  *
1844  */
1845 static u_short
1846 wlbldru(int unit)
1847 {
1848     struct wl_softc *sc = WLSOFTC(unit);
1849     short       base = sc->base;
1850     fd_t        fd;
1851     rbd_t       rbd;
1852     u_short     fd_p = OFFSET_RU;
1853     u_short     rbd_p = OFFSET_RBD;
1854     int         i;
1855
1856     sc->begin_fd = fd_p;
1857     for(i = 0; i < N_FD; i++) {
1858         fd.status = 0;
1859         fd.command = 0;
1860         fd.link_offset = fd_p + sizeof(fd_t);
1861         fd.rbd_offset = I82586NULL;
1862         outw(PIOR1(base), fd_p);
1863         outsw(PIOP1(base), &fd, 8/2);
1864         fd_p = fd.link_offset;
1865     }
1866     fd_p -= sizeof(fd_t);
1867     sc->end_fd = fd_p;
1868     outw(PIOR1(base), fd_p + 2);
1869     outw(PIOP1(base), AC_CW_EL);        /* command */
1870     outw(PIOP1(base), I82586NULL);      /* link_offset */
1871     fd_p = OFFSET_RU;
1872     
1873     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
1874     outw(PIOP0(base), rbd_p);
1875     outw(PIOR1(base), rbd_p);
1876     for(i = 0; i < N_RBD; i++) {
1877         rbd.status = 0;
1878         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1879         rbd.buffer_base = 0;
1880         rbd.size = RCVBUFSIZE;
1881         if (i != N_RBD-1) {
1882             rbd_p += sizeof(ru_t);
1883             rbd.next_rbd_offset = rbd_p;
1884         } else {
1885             rbd.next_rbd_offset = I82586NULL;
1886             rbd.size |= AC_CW_EL;
1887             sc->end_rbd = rbd_p;
1888         }
1889         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1890         outw(PIOR1(base), rbd_p);
1891     }
1892     return sc->begin_fd;
1893 }
1894
1895 /*
1896  * wlrustrt:
1897  *
1898  *      This routine starts the receive unit running.  First checks if the
1899  *      board is actually ready, then the board is instructed to receive
1900  *      packets again.
1901  *
1902  */
1903 static void
1904 wlrustrt(int unit)
1905 {
1906     struct wl_softc *sc = WLSOFTC(unit);
1907     short               base = sc->base;
1908     u_short             rfa;
1909
1910 #ifdef WLDEBUG
1911     if (sc->wl_if.if_flags & IFF_DEBUG)
1912         printf("wl%d: entered wlrustrt()\n",unit);
1913 #endif
1914     outw(PIOR0(base), OFFSET_SCB);
1915     if (inw(PIOP0(base)) & SCB_RUS_READY){
1916         printf("wlrustrt: RUS_READY\n");
1917         return;
1918     }
1919
1920     outw(PIOR0(base), OFFSET_SCB + 2);
1921     outw(PIOP0(base), SCB_RU_STRT);             /* command */
1922     rfa = wlbldru(unit);
1923     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
1924     outw(PIOP0(base), rfa);
1925
1926     SET_CHAN_ATTN(unit);
1927     return;
1928 }
1929
1930 /*
1931  * wldiag:
1932  *
1933  *      This routine does a 586 op-code number 7, and obtains the
1934  *      diagnose status for the WaveLAN.
1935  *
1936  */
1937 static int
1938 wldiag(int unit)
1939 {
1940     struct wl_softc *sc = WLSOFTC(unit);
1941     short               base = sc->base;
1942     short status;
1943
1944 #ifdef WLDEBUG
1945     if (sc->wl_if.if_flags & IFF_DEBUG)
1946         printf("wl%d: entered wldiag()\n",unit);
1947 #endif
1948     outw(PIOR0(base), OFFSET_SCB);
1949     status = inw(PIOP0(base));
1950     if (status & SCB_SW_INT) {
1951                 /* state is 2000 which seems ok
1952                    printf("wl%d diag(): unexpected initial state %\n",
1953                    unit, inw(PIOP0(base)));
1954                 */
1955         wlack(unit);
1956     }
1957     outw(PIOR1(base), OFFSET_CU);
1958     outw(PIOP1(base), 0);                       /* ac_status */
1959     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1960     if(wlcmd(unit, "diag()") == 0)
1961         return 0;
1962     outw(PIOR0(base), OFFSET_CU);
1963     if (inw(PIOP0(base)) & 0x0800) {
1964         printf("wl%d: i82586 Self Test failed!\n", unit);
1965         return 0;
1966     }
1967     return TRUE;
1968 }
1969
1970 /*
1971  * wlconfig:
1972  *
1973  *      This routine does a standard config of the WaveLAN board.
1974  *
1975  */
1976 static int
1977 wlconfig(int unit)
1978 {
1979     configure_t configure;
1980     struct wl_softc *sc = WLSOFTC(unit);
1981     short               base = sc->base;
1982
1983 #if     MULTICAST
1984 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1985     struct ifmultiaddr *ifma;
1986     u_char *addrp;
1987 #else
1988     struct ether_multi *enm;
1989     struct ether_multistep step;
1990 #endif
1991     int cnt = 0;
1992 #endif  /* MULTICAST */
1993
1994 #ifdef WLDEBUG
1995     if (sc->wl_if.if_flags & IFF_DEBUG)
1996         printf("wl%d: entered wlconfig()\n",unit);
1997 #endif
1998     outw(PIOR0(base), OFFSET_SCB);
1999     if (inw(PIOP0(base)) & SCB_SW_INT) {
2000         /*
2001           printf("wl%d config(): unexpected initial state %x\n",
2002           unit, inw(PIOP0(base)));
2003           */
2004     }
2005     wlack(unit);
2006
2007     outw(PIOR1(base), OFFSET_CU);
2008     outw(PIOP1(base), 0);                               /* ac_status */
2009     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
2010
2011 /* jrb hack */
2012     configure.fifolim_bytecnt   = 0x080c;
2013     configure.addrlen_mode      = 0x0600;
2014     configure.linprio_interframe        = 0x2060;
2015     configure.slot_time         = 0xf200;
2016     configure.hardware          = 0x0008;       /* tx even w/o CD */
2017     configure.min_frame_len     = 0x0040;
2018 #if 0
2019     /* This is the configuration block suggested by Marc Meertens
2020      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2021      * Ioannidis on 10 Nov 92.
2022      */
2023     configure.fifolim_bytecnt   = 0x040c;
2024     configure.addrlen_mode      = 0x0600;
2025     configure.linprio_interframe        = 0x2060;
2026     configure.slot_time         = 0xf000;
2027     configure.hardware          = 0x0008;       /* tx even w/o CD */
2028     configure.min_frame_len     = 0x0040;
2029 #else
2030     /*
2031      * below is the default board configuration from p2-28 from 586 book
2032      */
2033     configure.fifolim_bytecnt   = 0x080c;
2034     configure.addrlen_mode      = 0x2600;
2035     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
2036     configure.slot_time         = 0xf00c;       /* slottime=12    */
2037     configure.hardware          = 0x0008;       /* tx even w/o CD */
2038     configure.min_frame_len     = 0x0040;
2039 #endif
2040     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2041         configure.hardware |= 1;
2042     }
2043     outw(PIOR1(base), OFFSET_CU + 6);
2044     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2045
2046     if(wlcmd(unit, "config()-configure") == 0)
2047         return 0;
2048 #if     MULTICAST
2049     outw(PIOR1(base), OFFSET_CU);
2050     outw(PIOP1(base), 0);                               /* ac_status */
2051     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
2052     outw(PIOR1(base), OFFSET_CU + 8);
2053 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2054     for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2055          ifma = ifma->ifma_link.le_next) {
2056         if (ifma->ifma_addr->sa_family != AF_LINK)
2057             continue;
2058         
2059         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2060         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2061         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2062         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2063         ++cnt;
2064     }
2065 #else
2066     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2067     while (enm != NULL) {
2068         unsigned int lo, hi;
2069         /* break if setting a multicast range, else we would crash */
2070         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2071                 break;
2072         }
2073         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2074             + enm->enm_addrlo[5];
2075         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2076             + enm->enm_addrhi[5];
2077         while(lo <= hi) {
2078             outw(PIOP1(base),enm->enm_addrlo[0] +
2079                  (enm->enm_addrlo[1] << 8));
2080             outw(PIOP1(base),enm->enm_addrlo[2] +
2081                  ((lo >> 8) & 0xff00));
2082             outw(PIOP1(base), ((lo >> 8) & 0xff) +
2083                  ((lo << 8) & 0xff00));
2084 /* #define MCASTDEBUG */
2085 #ifdef MCASTDEBUG
2086 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2087                 enm->enm_addrlo[0],
2088                 enm->enm_addrlo[1],
2089                 enm->enm_addrlo[2],
2090                 enm->enm_addrlo[3],
2091                 enm->enm_addrlo[4],
2092                 enm->enm_addrlo[5]);
2093 #endif
2094             ++cnt;
2095             ++lo;
2096         }
2097         ETHER_NEXT_MULTI(step, enm);
2098     }
2099 #endif
2100     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
2101     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2102     if(wlcmd(unit, "config()-mcaddress") == 0)
2103         return 0;
2104 #endif  /* MULTICAST */
2105
2106     outw(PIOR1(base), OFFSET_CU);
2107     outw(PIOP1(base), 0);                               /* ac_status */
2108     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
2109     outw(PIOR1(base), OFFSET_CU + 6);
2110     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2111
2112     if(wlcmd(unit, "config()-address") == 0)
2113         return(0);
2114
2115     wlinitmmc(unit);
2116
2117     return(1);
2118 }
2119
2120 /*
2121  * wlcmd:
2122  *
2123  * Set channel attention bit and busy wait until command has
2124  * completed. Then acknowledge the command completion.
2125  */
2126 static int
2127 wlcmd(int unit, char *str)
2128 {
2129     struct wl_softc *sc = WLSOFTC(unit);
2130     short       base = sc->base;
2131     int i;
2132         
2133     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2134     outw(PIOP0(base), SCB_CU_STRT);
2135     
2136     SET_CHAN_ATTN(unit);
2137     
2138     outw(PIOR0(base), OFFSET_CU);
2139     for(i = 0; i < 0xffff; i++)
2140         if (inw(PIOP0(base)) & AC_SW_C)
2141             break;
2142     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2143         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2144                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2145         outw(PIOR0(base), OFFSET_SCB);
2146         printf("scb_status %x\n", inw(PIOP0(base)));
2147         outw(PIOR0(base), OFFSET_SCB+2);
2148         printf("scb_command %x\n", inw(PIOP0(base)));
2149         outw(PIOR0(base), OFFSET_SCB+4);
2150         printf("scb_cbl %x\n", inw(PIOP0(base)));
2151         outw(PIOR0(base), OFFSET_CU+2);
2152         printf("cu_cmd %x\n", inw(PIOP0(base)));
2153         return(0);
2154     }
2155
2156     outw(PIOR0(base), OFFSET_SCB);
2157     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2158         /*
2159           printf("wl%d %s: unexpected final state %x\n",
2160           unit, str, inw(PIOP0(base)));
2161           */
2162     }
2163     wlack(unit);
2164     return(TRUE);
2165 }       
2166
2167 /*
2168  * wlack: if the 82596 wants attention because it has finished
2169  * sending or receiving a packet, acknowledge its desire and
2170  * return bits indicating the kind of attention. wlack() returns
2171  * these bits so that the caller can service exactly the
2172  * conditions that wlack() acknowledged.
2173  */
2174 static int
2175 wlack(int unit)
2176 {
2177     int i;
2178     u_short cmd;
2179     struct wl_softc *sc = WLSOFTC(unit);
2180     short base = sc->base;
2181
2182     outw(PIOR1(base), OFFSET_SCB);
2183     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2184         return(0);
2185 #ifdef WLDEBUG
2186     if (sc->wl_if.if_flags & IFF_DEBUG)
2187         printf("wl%d: doing a wlack()\n",unit);
2188 #endif
2189     outw(PIOP1(base), cmd);
2190     SET_CHAN_ATTN(unit);
2191     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2192     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2193     if (i < 1)
2194         printf("wl%d wlack(): board not accepting command.\n", unit);
2195     return(cmd);
2196 }
2197
2198 static void
2199 wltbd(int unit)
2200 {
2201     struct wl_softc *sc = WLSOFTC(unit);
2202     short               base = sc->base;
2203     u_short             tbd_p = OFFSET_TBD;
2204     tbd_t               tbd;
2205     int                 i = 0;
2206     int                 sum = 0;
2207
2208     for (;;) {
2209         outw(PIOR1(base), tbd_p);
2210         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2211         sum += (tbd.act_count & ~TBD_SW_EOF);
2212         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2213                i++, tbd.buffer_addr,
2214                (tbd.act_count & ~TBD_SW_EOF), sum,
2215                tbd.next_tbd_offset, tbd.buffer_base);
2216         if (tbd.act_count & TBD_SW_EOF)
2217             break;
2218         tbd_p = tbd.next_tbd_offset;
2219     }
2220 }
2221
2222 static void
2223 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2224 {
2225     struct mbuf *tm_p = *tm_pp;
2226     u_char              *mb_p = *mb_pp;
2227     u_short             count = 0;
2228     u_char              *cp;
2229     int         len;
2230
2231     /*
2232      * can we get a run that will be coallesced or
2233      * that terminates before breaking
2234      */
2235     do {
2236         count += tm_p->m_len;
2237         if (tm_p->m_len & 1)
2238             break;
2239     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2240     if ( (tm_p == (struct mbuf *)0) ||
2241          count > HDW_THRESHOLD) {
2242         *countp = (*tm_pp)->m_len;
2243         *mb_pp = mtod((*tm_pp), u_char *);
2244         return;
2245     }
2246
2247     /* we need to copy */
2248     tm_p = *tm_pp;
2249     mb_p = *mb_pp;
2250     count = 0;
2251     cp = (u_char *) t_packet;
2252     for (;;) {
2253         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2254         count += len;
2255         if (count > HDW_THRESHOLD)
2256                         break;
2257         cp += len;
2258         if (tm_p->m_next == (struct mbuf *)0)
2259             break;
2260         tm_p = tm_p->m_next;
2261     }
2262     *countp = count;
2263     *mb_pp = (u_char *) t_packet;
2264     *tm_pp = tm_p;
2265     return;
2266 }
2267
2268
2269 static void
2270 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2271 {
2272     struct mbuf *tm_p = *tm_pp;
2273     u_short             count = 0;
2274     u_char              *cp = (u_char *) t_packet;
2275     int                 len;
2276
2277     /* we need to copy */
2278     for (;;) {
2279         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2280         count += len;
2281         cp += len;
2282         if (tm_p->m_next == (struct mbuf *)0)
2283             break;
2284         tm_p = tm_p->m_next;
2285     }
2286
2287     *countp = count;
2288     *mb_pp = (u_char *) t_packet;
2289     *tm_pp = tm_p;
2290     return;
2291 }
2292
2293 static void
2294 wlmmcstat(int unit)
2295 {
2296     struct wl_softc *sc = WLSOFTC(unit);
2297     short       base = sc->base;
2298     u_short tmp;
2299
2300     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2301            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2302     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2303     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2304     printf("Correct NWID's: %d, ", tmp);
2305     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2306     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2307     printf("Wrong NWID's: %d\n", tmp);
2308     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2309     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
2310            wlmmcread(base,MMC_SIGNAL_LVL),
2311            wlmmcread(base,MMC_SILENCE_LVL));
2312     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2313            wlmmcread(base,MMC_SIGN_QUAL),
2314            wlmmcread(base,MMC_NETW_ID_H),
2315            wlmmcread(base,MMC_NETW_ID_L),
2316            wlmmcread(base,MMC_DES_AVAIL));
2317 }
2318
2319 static u_short
2320 wlmmcread(u_int base, u_short reg)
2321 {
2322     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2323     outw(MMCR(base),reg << 1);
2324     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2325     return (u_short)inw(MMCR(base)) >> 8;
2326 }
2327
2328 static void
2329 getsnr(int unit)
2330 {
2331     MMC_WRITE(MMC_FREEZE,1);
2332     /* 
2333      * SNR retrieval procedure :
2334      *
2335      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2336      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2337      */
2338     MMC_WRITE(MMC_FREEZE,0);
2339     /*
2340      * SNR is signal:silence ratio.
2341      */
2342 }
2343
2344 /*
2345 ** wlgetpsa
2346 **
2347 ** Reads the psa for the wavelan at (base) into (buf)
2348 */
2349 static void
2350 wlgetpsa(int base, u_char *buf)
2351 {
2352     int i;
2353
2354     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2355     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2356
2357     for (i = 0; i < 0x40; i++) {
2358         outw(PIOR2(base), i);
2359         buf[i] = inb(PIOP2(base));
2360     }
2361     PCMD(base, HACR_DEFAULT);
2362     PCMD(base, HACR_DEFAULT);
2363 }
2364
2365 /*
2366 ** wlsetpsa
2367 **
2368 ** Writes the psa for wavelan (unit) from the softc back to the
2369 ** board.  Updates the CRC and sets the CRC OK flag.
2370 **
2371 ** Do not call this when the board is operating, as it doesn't 
2372 ** preserve the hacr.
2373 */
2374 static void
2375 wlsetpsa(int unit)
2376 {
2377     struct wl_softc *sc = WLSOFTC(unit);
2378     short       base = sc->base;
2379     int         i, oldpri;
2380     u_short     crc;
2381
2382     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
2383     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2384     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2385     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
2386
2387     oldpri = splimp();          /* ick, long pause */
2388     
2389     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2390     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2391     
2392     for (i = 0; i < 0x40; i++) {
2393         DELAY(DELAYCONST);
2394         outw(PIOR2(base),i);  /* write param memory */
2395         DELAY(DELAYCONST);
2396         outb(PIOP2(base), sc->psa[i]);
2397     }
2398     DELAY(DELAYCONST);
2399     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
2400     DELAY(DELAYCONST);
2401     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
2402     outb(PIOP2(base), 0xaa);    /* all OK */
2403     DELAY(DELAYCONST);
2404     
2405     PCMD(base, HACR_DEFAULT);
2406     PCMD(base, HACR_DEFAULT);
2407     
2408     splx(oldpri);
2409 }
2410
2411 /* 
2412 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2413 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2414 */
2415
2416 static u_int crc16_table[16] = { 
2417     0x0000, 0xCC01, 0xD801, 0x1400,
2418     0xF001, 0x3C00, 0x2800, 0xE401,
2419     0xA001, 0x6C00, 0x7800, 0xB401,
2420     0x5000, 0x9C01, 0x8801, 0x4400 
2421 };
2422
2423 static u_short
2424 wlpsacrc(u_char *buf)
2425 {
2426     u_short     crc = 0;
2427     int         i, r1;
2428     
2429     for (i = 0; i < 0x3d; i++, buf++) {
2430         /* lower 4 bits */
2431         r1 = crc16_table[crc & 0xF];
2432         crc = (crc >> 4) & 0x0FFF;
2433         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2434         
2435         /* upper 4 bits */
2436         r1 = crc16_table[crc & 0xF];
2437         crc = (crc >> 4) & 0x0FFF;
2438         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2439     }
2440     return(crc);
2441 }
2442 #ifdef WLCACHE
2443
2444 /*
2445  * wl_cache_store
2446  *
2447  * take input packet and cache various radio hw characteristics
2448  * indexed by MAC address.
2449  *
2450  * Some things to think about:
2451  *      note that no space is malloced. 
2452  *      We might hash the mac address if the cache were bigger.
2453  *      It is not clear that the cache is big enough.
2454  *              It is also not clear how big it should be.
2455  *      The cache is IP-specific.  We don't care about that as
2456  *              we want it to be IP-specific.
2457  *      The last N recv. packets are saved.  This will tend
2458  *              to reward agents and mobile hosts that beacon.
2459  *              That is probably fine for mobile ip.
2460  */
2461
2462 /* globals for wavelan signal strength cache */
2463 /* this should go into softc structure above. 
2464 */
2465
2466 /* set true if you want to limit cache items to broadcast/mcast 
2467  * only packets (not unicast)
2468  */
2469 static int wl_cache_mcastonly = 1;
2470 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
2471         &wl_cache_mcastonly, 0, "");
2472
2473 /* set true if you want to limit cache items to IP packets only
2474 */
2475 static int wl_cache_iponly = 1;
2476 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
2477         &wl_cache_iponly, 0, "");
2478
2479 /* zero out the cache
2480 */
2481 static void
2482 wl_cache_zero(int unit)
2483 {
2484         struct wl_softc *sc = WLSOFTC(unit);
2485
2486         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2487         sc->w_sigitems = 0;
2488         sc->w_nextcache = 0;
2489         sc->w_wrapindex = 0;
2490 }
2491
2492 /* store hw signal info in cache.
2493  * index is MAC address, but an ip src gets stored too
2494  * There are two filters here controllable via sysctl:
2495  *      throw out unicast (on by default, but can be turned off)
2496  *      throw out non-ip (on by default, but can be turned off)
2497  */
2498 static
2499 void wl_cache_store (int unit, int base, struct ether_header *eh,
2500                      struct mbuf *m)
2501 {
2502         struct ip *ip = NULL;   /* Avoid GCC warning */
2503         int i;
2504         int signal, silence;
2505         int w_insertcache;   /* computed index for cache entry storage */
2506         struct wl_softc *sc = WLSOFTC(unit);
2507         int ipflag = wl_cache_iponly;
2508
2509         /* filters:
2510          * 1. ip only
2511          * 2. configurable filter to throw out unicast packets,
2512          * keep multicast only.
2513          */
2514  
2515 #ifdef INET
2516         /* reject if not IP packet
2517         */
2518         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2519                 return;
2520         }
2521
2522         /* check if broadcast or multicast packet.  we toss
2523          * unicast packets
2524          */
2525         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2526                 return;
2527         }
2528
2529         /* find the ip header.  we want to store the ip_src
2530          * address.  use the mtod macro(in mbuf.h) 
2531          * to typecast m to struct ip *
2532          */
2533         if (ipflag) {
2534                 ip = mtod(m, struct ip *);
2535         }
2536         
2537         /* do a linear search for a matching MAC address 
2538          * in the cache table
2539          * . MAC address is 6 bytes,
2540          * . var w_nextcache holds total number of entries already cached
2541          */
2542         for(i = 0; i < sc->w_nextcache; i++) {
2543                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
2544                         /* Match!,
2545                          * so we already have this entry,
2546                          * update the data, and LRU age
2547                          */
2548                         break;  
2549                 }
2550         }
2551
2552         /* did we find a matching mac address?
2553          * if yes, then overwrite a previously existing cache entry
2554          */
2555         if (i <  sc->w_nextcache )   {
2556                 w_insertcache = i; 
2557         }
2558         /* else, have a new address entry,so
2559          * add this new entry,
2560          * if table full, then we need to replace entry
2561          */
2562         else    {                          
2563
2564                 /* check for space in cache table 
2565                  * note: w_nextcache also holds number of entries
2566                  * added in the cache table 
2567                  */
2568                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2569                         w_insertcache = sc->w_nextcache;
2570                         sc->w_nextcache++;                 
2571                         sc->w_sigitems = sc->w_nextcache;
2572                 }
2573                 /* no space found, so simply wrap with wrap index
2574                  * and "zap" the next entry
2575                  */
2576                 else {
2577                         if (sc->w_wrapindex == MAXCACHEITEMS) {
2578                                 sc->w_wrapindex = 0;
2579                         }
2580                         w_insertcache = sc->w_wrapindex++;
2581                 }
2582         }
2583
2584         /* invariant: w_insertcache now points at some slot
2585          * in cache.
2586          */
2587         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2588                 log(LOG_ERR, 
2589                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2590                         w_insertcache, MAXCACHEITEMS);
2591                 return;
2592         }
2593
2594         /*  store items in cache
2595          *  .ipsrc
2596          *  .macsrc
2597          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
2598          */
2599         if (ipflag) {
2600                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2601         }
2602         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
2603         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2604         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2605         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2606         if (signal > 0)
2607                 sc->w_sigcache[w_insertcache].snr = 
2608                         signal - silence;
2609         else
2610                 sc->w_sigcache[w_insertcache].snr = 0;
2611 #endif /* INET */
2612
2613 }
2614 #endif /* WLCACHE */
2615
2616 /*
2617  * determine if in all multicast mode or not
2618  * 
2619  * returns: 1 if IFF_ALLMULTI should be set
2620  *          else 0
2621  */
2622 #ifdef MULTICAST
2623
2624 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
2625 static int
2626 check_allmulti(int unit)
2627 {
2628     struct wl_softc *sc = WLSOFTC(unit);
2629     short  base = sc->base;
2630     struct ether_multi *enm;
2631     struct ether_multistep step;
2632
2633     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2634     while (enm != NULL) {
2635         unsigned int lo, hi;
2636 #ifdef MDEBUG
2637                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2638                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2639                 enm->enm_addrlo[5]);
2640                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2641                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2642                 enm->enm_addrhi[5]);
2643 #endif
2644         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2645                 return(1);
2646         }
2647         ETHER_NEXT_MULTI(step, enm);
2648     }
2649     return(0);
2650 }
2651 #endif
2652 #endif