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