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