Home | History | Annotate | Line # | Download | only in ic
lance.c revision 1.3
      1  1.3   mycroft /*	$NetBSD: lance.c,v 1.3 1998/08/15 10:51:18 mycroft Exp $	*/
      2  1.1  drochner 
      3  1.1  drochner /*-
      4  1.3   mycroft  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
      5  1.1  drochner  * All rights reserved.
      6  1.1  drochner  *
      7  1.1  drochner  * This code is derived from software contributed to The NetBSD Foundation
      8  1.3   mycroft  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
      9  1.3   mycroft  * Simulation Facility, NASA Ames Research Center.
     10  1.1  drochner  *
     11  1.1  drochner  * Redistribution and use in source and binary forms, with or without
     12  1.1  drochner  * modification, are permitted provided that the following conditions
     13  1.1  drochner  * are met:
     14  1.1  drochner  * 1. Redistributions of source code must retain the above copyright
     15  1.1  drochner  *    notice, this list of conditions and the following disclaimer.
     16  1.1  drochner  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1  drochner  *    notice, this list of conditions and the following disclaimer in the
     18  1.1  drochner  *    documentation and/or other materials provided with the distribution.
     19  1.1  drochner  * 3. All advertising materials mentioning features or use of this software
     20  1.1  drochner  *    must display the following acknowledgement:
     21  1.1  drochner  *	This product includes software developed by the NetBSD
     22  1.1  drochner  *	Foundation, Inc. and its contributors.
     23  1.1  drochner  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  1.1  drochner  *    contributors may be used to endorse or promote products derived
     25  1.1  drochner  *    from this software without specific prior written permission.
     26  1.1  drochner  *
     27  1.1  drochner  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  1.1  drochner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  1.1  drochner  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  1.1  drochner  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  1.1  drochner  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  1.1  drochner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  1.1  drochner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  1.1  drochner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  1.1  drochner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  1.1  drochner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  1.1  drochner  * POSSIBILITY OF SUCH DAMAGE.
     38  1.1  drochner  */
     39  1.1  drochner 
     40  1.1  drochner /*-
     41  1.1  drochner  * Copyright (c) 1992, 1993
     42  1.1  drochner  *	The Regents of the University of California.  All rights reserved.
     43  1.1  drochner  *
     44  1.1  drochner  * This code is derived from software contributed to Berkeley by
     45  1.1  drochner  * Ralph Campbell and Rick Macklem.
     46  1.1  drochner  *
     47  1.1  drochner  * Redistribution and use in source and binary forms, with or without
     48  1.1  drochner  * modification, are permitted provided that the following conditions
     49  1.1  drochner  * are met:
     50  1.1  drochner  * 1. Redistributions of source code must retain the above copyright
     51  1.1  drochner  *    notice, this list of conditions and the following disclaimer.
     52  1.1  drochner  * 2. Redistributions in binary form must reproduce the above copyright
     53  1.1  drochner  *    notice, this list of conditions and the following disclaimer in the
     54  1.1  drochner  *    documentation and/or other materials provided with the distribution.
     55  1.1  drochner  * 3. All advertising materials mentioning features or use of this software
     56  1.1  drochner  *    must display the following acknowledgement:
     57  1.1  drochner  *	This product includes software developed by the University of
     58  1.1  drochner  *	California, Berkeley and its contributors.
     59  1.1  drochner  * 4. Neither the name of the University nor the names of its contributors
     60  1.1  drochner  *    may be used to endorse or promote products derived from this software
     61  1.1  drochner  *    without specific prior written permission.
     62  1.1  drochner  *
     63  1.1  drochner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     64  1.1  drochner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     65  1.1  drochner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     66  1.1  drochner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     67  1.1  drochner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     68  1.1  drochner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     69  1.1  drochner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     70  1.1  drochner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     71  1.1  drochner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     72  1.1  drochner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     73  1.1  drochner  * SUCH DAMAGE.
     74  1.1  drochner  *
     75  1.1  drochner  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
     76  1.1  drochner  */
     77  1.1  drochner 
     78  1.1  drochner #include "opt_inet.h"
     79  1.1  drochner #include "opt_ccitt.h"
     80  1.1  drochner #include "opt_llc.h"
     81  1.1  drochner #include "opt_ns.h"
     82  1.1  drochner #include "bpfilter.h"
     83  1.1  drochner #include "rnd.h"
     84  1.1  drochner 
     85  1.1  drochner #include <sys/param.h>
     86  1.1  drochner #include <sys/systm.h>
     87  1.1  drochner #include <sys/mbuf.h>
     88  1.1  drochner #include <sys/syslog.h>
     89  1.1  drochner #include <sys/socket.h>
     90  1.1  drochner #include <sys/device.h>
     91  1.1  drochner #include <sys/malloc.h>
     92  1.1  drochner #include <sys/ioctl.h>
     93  1.1  drochner #include <sys/errno.h>
     94  1.1  drochner #if NRND > 0
     95  1.1  drochner #include <sys/rnd.h>
     96  1.1  drochner #endif
     97  1.1  drochner 
     98  1.1  drochner #include <net/if.h>
     99  1.1  drochner #include <net/if_dl.h>
    100  1.1  drochner #include <net/if_ether.h>
    101  1.1  drochner #include <net/if_media.h>
    102  1.1  drochner 
    103  1.1  drochner #ifdef INET
    104  1.1  drochner #include <netinet/in.h>
    105  1.1  drochner #include <netinet/if_inarp.h>
    106  1.1  drochner #include <netinet/in_systm.h>
    107  1.1  drochner #include <netinet/in_var.h>
    108  1.1  drochner #include <netinet/ip.h>
    109  1.1  drochner #endif
    110  1.1  drochner 
    111  1.1  drochner #ifdef NS
    112  1.1  drochner #include <netns/ns.h>
    113  1.1  drochner #include <netns/ns_if.h>
    114  1.1  drochner #endif
    115  1.1  drochner 
    116  1.1  drochner #if defined(CCITT) && defined(LLC)
    117  1.1  drochner #include <sys/socketvar.h>
    118  1.1  drochner #include <netccitt/x25.h>
    119  1.1  drochner #include <netccitt/pk.h>
    120  1.1  drochner #include <netccitt/pk_var.h>
    121  1.1  drochner #include <netccitt/pk_extern.h>
    122  1.1  drochner #endif
    123  1.1  drochner 
    124  1.1  drochner #if NBPFILTER > 0
    125  1.1  drochner #include <net/bpf.h>
    126  1.1  drochner #include <net/bpfdesc.h>
    127  1.1  drochner #endif
    128  1.1  drochner 
    129  1.1  drochner #include <dev/ic/lancereg.h>
    130  1.1  drochner #include <dev/ic/lancevar.h>
    131  1.1  drochner 
    132  1.1  drochner #if defined(_KERNEL) && !defined(_LKM)
    133  1.1  drochner #include "opt_ddb.h"
    134  1.1  drochner #endif
    135  1.1  drochner 
    136  1.1  drochner #ifdef DDB
    137  1.1  drochner #define	integrate
    138  1.1  drochner #define hide
    139  1.1  drochner #else
    140  1.1  drochner #define	integrate	static __inline
    141  1.1  drochner #define hide		static
    142  1.1  drochner #endif
    143  1.1  drochner 
    144  1.1  drochner integrate struct mbuf *lance_get __P((struct lance_softc *, int, int));
    145  1.1  drochner 
    146  1.1  drochner hide void lance_shutdown __P((void *));
    147  1.1  drochner 
    148  1.1  drochner int lance_mediachange __P((struct ifnet *));
    149  1.1  drochner void lance_mediastatus __P((struct ifnet *, struct ifmediareq *));
    150  1.1  drochner 
    151  1.1  drochner static inline u_int16_t ether_cmp __P((void *, void *));
    152  1.1  drochner 
    153  1.1  drochner void lance_stop __P((struct lance_softc *));
    154  1.1  drochner int lance_ioctl __P((struct ifnet *, u_long, caddr_t));
    155  1.1  drochner void lance_watchdog __P((struct ifnet *));
    156  1.1  drochner 
    157  1.1  drochner /*
    158  1.1  drochner  * Compare two Ether/802 addresses for equality, inlined and
    159  1.1  drochner  * unrolled for speed.  Use this like bcmp().
    160  1.1  drochner  *
    161  1.1  drochner  * XXX: Add <machine/inlines.h> for stuff like this?
    162  1.1  drochner  * XXX: or maybe add it to libkern.h instead?
    163  1.1  drochner  *
    164  1.1  drochner  * "I'd love to have an inline assembler version of this."
    165  1.1  drochner  * XXX: Who wanted that? mycroft?  I wrote one, but this
    166  1.1  drochner  * version in C is as good as hand-coded assembly. -gwr
    167  1.1  drochner  *
    168  1.1  drochner  * Please do NOT tweak this without looking at the actual
    169  1.1  drochner  * assembly code generated before and after your tweaks!
    170  1.1  drochner  */
    171  1.1  drochner static inline u_int16_t
    172  1.1  drochner ether_cmp(one, two)
    173  1.1  drochner 	void *one, *two;
    174  1.1  drochner {
    175  1.1  drochner 	register u_int16_t *a = (u_short *) one;
    176  1.1  drochner 	register u_int16_t *b = (u_short *) two;
    177  1.1  drochner 	register u_int16_t diff;
    178  1.1  drochner 
    179  1.1  drochner #ifdef	m68k
    180  1.1  drochner 	/*
    181  1.1  drochner 	 * The post-increment-pointer form produces the best
    182  1.1  drochner 	 * machine code for m68k.  This was carefully tuned
    183  1.1  drochner 	 * so it compiles to just 8 short (2-byte) op-codes!
    184  1.1  drochner 	 */
    185  1.1  drochner 	diff  = *a++ - *b++;
    186  1.1  drochner 	diff |= *a++ - *b++;
    187  1.1  drochner 	diff |= *a++ - *b++;
    188  1.1  drochner #else
    189  1.1  drochner 	/*
    190  1.1  drochner 	 * Most modern CPUs do better with a single expresion.
    191  1.1  drochner 	 * Note that short-cut evaluation is NOT helpful here,
    192  1.1  drochner 	 * because it just makes the code longer, not faster!
    193  1.1  drochner 	 */
    194  1.1  drochner 	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
    195  1.1  drochner #endif
    196  1.1  drochner 
    197  1.1  drochner 	return (diff);
    198  1.1  drochner }
    199  1.1  drochner 
    200  1.1  drochner #define ETHER_CMP	ether_cmp
    201  1.1  drochner 
    202  1.1  drochner #ifdef LANCE_REVC_BUG
    203  1.1  drochner /* Make sure this is short-aligned, for ether_cmp(). */
    204  1.1  drochner static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
    205  1.1  drochner #endif
    206  1.1  drochner 
    207  1.1  drochner #define	ifp	(&sc->sc_ethercom.ec_if)
    208  1.1  drochner 
    209  1.1  drochner void
    210  1.1  drochner lance_config(sc)
    211  1.1  drochner 	struct lance_softc *sc;
    212  1.1  drochner {
    213  1.1  drochner 	int i;
    214  1.1  drochner 
    215  1.1  drochner 	/* Make sure the chip is stopped. */
    216  1.1  drochner 	lance_stop(sc);
    217  1.1  drochner 
    218  1.1  drochner 	/* Initialize ifnet structure. */
    219  1.1  drochner 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
    220  1.1  drochner 	ifp->if_softc = sc;
    221  1.1  drochner 	ifp->if_start = sc->sc_start;
    222  1.1  drochner 	ifp->if_ioctl = lance_ioctl;
    223  1.1  drochner 	ifp->if_watchdog = lance_watchdog;
    224  1.1  drochner 	ifp->if_flags =
    225  1.1  drochner 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
    226  1.1  drochner #ifdef LANCE_REVC_BUG
    227  1.1  drochner 	ifp->if_flags &= ~IFF_MULTICAST;
    228  1.1  drochner #endif
    229  1.1  drochner 
    230  1.1  drochner 	/* Initialize ifmedia structures. */
    231  1.1  drochner 	ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
    232  1.1  drochner 	if (sc->sc_supmedia != NULL) {
    233  1.1  drochner 		for (i = 0; i < sc->sc_nsupmedia; i++)
    234  1.1  drochner 			ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
    235  1.1  drochner 			   0, NULL);
    236  1.1  drochner 		ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
    237  1.1  drochner 	} else {
    238  1.1  drochner 		ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
    239  1.1  drochner 		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
    240  1.1  drochner 	}
    241  1.1  drochner 
    242  1.1  drochner 	/* Attach the interface. */
    243  1.1  drochner 	if_attach(ifp);
    244  1.1  drochner 	ether_ifattach(ifp, sc->sc_enaddr);
    245  1.1  drochner 
    246  1.1  drochner #if NBPFILTER > 0
    247  1.1  drochner 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
    248  1.1  drochner #endif
    249  1.1  drochner 
    250  1.1  drochner 	switch (sc->sc_memsize) {
    251  1.1  drochner 	case 8192:
    252  1.1  drochner 		sc->sc_nrbuf = 4;
    253  1.1  drochner 		sc->sc_ntbuf = 1;
    254  1.1  drochner 		break;
    255  1.1  drochner 	case 16384:
    256  1.1  drochner 		sc->sc_nrbuf = 8;
    257  1.1  drochner 		sc->sc_ntbuf = 2;
    258  1.1  drochner 		break;
    259  1.1  drochner 	case 32768:
    260  1.1  drochner 		sc->sc_nrbuf = 16;
    261  1.1  drochner 		sc->sc_ntbuf = 4;
    262  1.1  drochner 		break;
    263  1.1  drochner 	case 65536:
    264  1.1  drochner 		sc->sc_nrbuf = 32;
    265  1.1  drochner 		sc->sc_ntbuf = 8;
    266  1.1  drochner 		break;
    267  1.1  drochner 	case 131072:
    268  1.1  drochner 		sc->sc_nrbuf = 64;
    269  1.1  drochner 		sc->sc_ntbuf = 16;
    270  1.1  drochner 		break;
    271  1.1  drochner 	default:
    272  1.1  drochner 		panic("lance_config: weird memory size");
    273  1.1  drochner 	}
    274  1.1  drochner 
    275  1.1  drochner 	printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
    276  1.1  drochner 	printf("%s: %d receive buffers, %d transmit buffers\n",
    277  1.1  drochner 	    sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
    278  1.1  drochner 
    279  1.1  drochner 	sc->sc_sh = shutdownhook_establish(lance_shutdown, sc);
    280  1.1  drochner 	if (sc->sc_sh == NULL)
    281  1.1  drochner 		panic("lance_config: can't establish shutdownhook");
    282  1.1  drochner 	sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
    283  1.1  drochner 					M_WAITOK);
    284  1.1  drochner 	sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
    285  1.1  drochner 					M_WAITOK);
    286  1.1  drochner 
    287  1.1  drochner #if NRND > 0
    288  1.1  drochner 	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
    289  1.1  drochner 			  RND_TYPE_NET);
    290  1.1  drochner #endif
    291  1.1  drochner }
    292  1.1  drochner 
    293  1.1  drochner void
    294  1.1  drochner lance_reset(sc)
    295  1.1  drochner 	struct lance_softc *sc;
    296  1.1  drochner {
    297  1.1  drochner 	int s;
    298  1.1  drochner 
    299  1.2   mycroft 	s = splnet();
    300  1.1  drochner 	lance_init(sc);
    301  1.1  drochner 	splx(s);
    302  1.1  drochner }
    303  1.1  drochner 
    304  1.1  drochner void
    305  1.1  drochner lance_stop(sc)
    306  1.1  drochner 	struct lance_softc *sc;
    307  1.1  drochner {
    308  1.1  drochner 
    309  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
    310  1.1  drochner }
    311  1.1  drochner 
    312  1.1  drochner /*
    313  1.1  drochner  * Initialization of interface; set up initialization block
    314  1.1  drochner  * and transmit/receive descriptor rings.
    315  1.1  drochner  */
    316  1.1  drochner void
    317  1.1  drochner lance_init(sc)
    318  1.1  drochner 	register struct lance_softc *sc;
    319  1.1  drochner {
    320  1.1  drochner 	register int timo;
    321  1.1  drochner 	u_long a;
    322  1.1  drochner 
    323  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
    324  1.1  drochner 	DELAY(100);
    325  1.1  drochner 
    326  1.1  drochner 	/* Newer LANCE chips have a reset register */
    327  1.1  drochner 	if (sc->sc_hwreset)
    328  1.1  drochner 		(*sc->sc_hwreset)(sc);
    329  1.1  drochner 
    330  1.1  drochner 	/* Set the correct byte swapping mode, etc. */
    331  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
    332  1.1  drochner 
    333  1.1  drochner 	/* Set up LANCE init block. */
    334  1.1  drochner 	(*sc->sc_meminit)(sc);
    335  1.1  drochner 
    336  1.1  drochner 	/* Give LANCE the physical address of its init block. */
    337  1.1  drochner 	a = sc->sc_addr + LE_INITADDR(sc);
    338  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR1, a);
    339  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
    340  1.1  drochner 
    341  1.1  drochner 	/* Try to initialize the LANCE. */
    342  1.1  drochner 	DELAY(100);
    343  1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
    344  1.1  drochner 
    345  1.1  drochner 	/* Wait for initialization to finish. */
    346  1.1  drochner 	for (timo = 100000; timo; timo--)
    347  1.1  drochner 		if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
    348  1.1  drochner 			break;
    349  1.1  drochner 
    350  1.1  drochner 	if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
    351  1.1  drochner 		/* Start the LANCE. */
    352  1.1  drochner 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
    353  1.1  drochner 		    LE_C0_IDON);
    354  1.1  drochner 		ifp->if_flags |= IFF_RUNNING;
    355  1.1  drochner 		ifp->if_flags &= ~IFF_OACTIVE;
    356  1.1  drochner 		ifp->if_timer = 0;
    357  1.1  drochner 		(*sc->sc_start)(ifp);
    358  1.1  drochner 	} else
    359  1.1  drochner 		printf("%s: controller failed to initialize\n",
    360  1.1  drochner 			sc->sc_dev.dv_xname);
    361  1.1  drochner 	if (sc->sc_hwinit)
    362  1.1  drochner 		(*sc->sc_hwinit)(sc);
    363  1.1  drochner }
    364  1.1  drochner 
    365  1.1  drochner /*
    366  1.1  drochner  * Routine to copy from mbuf chain to transmit buffer in
    367  1.1  drochner  * network buffer memory.
    368  1.1  drochner  */
    369  1.1  drochner int
    370  1.1  drochner lance_put(sc, boff, m)
    371  1.1  drochner 	struct lance_softc *sc;
    372  1.1  drochner 	int boff;
    373  1.1  drochner 	register struct mbuf *m;
    374  1.1  drochner {
    375  1.1  drochner 	register struct mbuf *n;
    376  1.1  drochner 	register int len, tlen = 0;
    377  1.1  drochner 
    378  1.1  drochner 	for (; m; m = n) {
    379  1.1  drochner 		len = m->m_len;
    380  1.1  drochner 		if (len == 0) {
    381  1.1  drochner 			MFREE(m, n);
    382  1.1  drochner 			continue;
    383  1.1  drochner 		}
    384  1.1  drochner 		(*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
    385  1.1  drochner 		boff += len;
    386  1.1  drochner 		tlen += len;
    387  1.1  drochner 		MFREE(m, n);
    388  1.1  drochner 	}
    389  1.1  drochner 	if (tlen < LEMINSIZE) {
    390  1.1  drochner 		(*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
    391  1.1  drochner 		tlen = LEMINSIZE;
    392  1.1  drochner 	}
    393  1.1  drochner 	return (tlen);
    394  1.1  drochner }
    395  1.1  drochner 
    396  1.1  drochner /*
    397  1.1  drochner  * Pull data off an interface.
    398  1.1  drochner  * Len is length of data, with local net header stripped.
    399  1.1  drochner  * We copy the data into mbufs.  When full cluster sized units are present
    400  1.1  drochner  * we copy into clusters.
    401  1.1  drochner  */
    402  1.1  drochner integrate struct mbuf *
    403  1.1  drochner lance_get(sc, boff, totlen)
    404  1.1  drochner 	struct lance_softc *sc;
    405  1.1  drochner 	int boff, totlen;
    406  1.1  drochner {
    407  1.1  drochner 	register struct mbuf *m;
    408  1.1  drochner 	struct mbuf *top, **mp;
    409  1.1  drochner 	int len;
    410  1.1  drochner 
    411  1.1  drochner 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    412  1.1  drochner 	if (m == 0)
    413  1.1  drochner 		return (0);
    414  1.1  drochner 	m->m_pkthdr.rcvif = ifp;
    415  1.1  drochner 	m->m_pkthdr.len = totlen;
    416  1.1  drochner 	len = MHLEN;
    417  1.1  drochner 	top = 0;
    418  1.1  drochner 	mp = &top;
    419  1.1  drochner 
    420  1.1  drochner 	while (totlen > 0) {
    421  1.1  drochner 		if (top) {
    422  1.1  drochner 			MGET(m, M_DONTWAIT, MT_DATA);
    423  1.1  drochner 			if (m == 0) {
    424  1.1  drochner 				m_freem(top);
    425  1.1  drochner 				return 0;
    426  1.1  drochner 			}
    427  1.1  drochner 			len = MLEN;
    428  1.1  drochner 		}
    429  1.1  drochner 		if (totlen >= MINCLSIZE) {
    430  1.1  drochner 			MCLGET(m, M_DONTWAIT);
    431  1.1  drochner 			if ((m->m_flags & M_EXT) == 0) {
    432  1.1  drochner 				m_free(m);
    433  1.1  drochner 				m_freem(top);
    434  1.1  drochner 				return 0;
    435  1.1  drochner 			}
    436  1.1  drochner 			len = MCLBYTES;
    437  1.1  drochner 		}
    438  1.1  drochner 		if (!top) {
    439  1.1  drochner 			register int pad =
    440  1.1  drochner 			    ALIGN(sizeof(struct ether_header)) -
    441  1.1  drochner 			        sizeof(struct ether_header);
    442  1.1  drochner 			m->m_data += pad;
    443  1.1  drochner 			len -= pad;
    444  1.1  drochner 		}
    445  1.1  drochner 		m->m_len = len = min(totlen, len);
    446  1.1  drochner 		(*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
    447  1.1  drochner 		boff += len;
    448  1.1  drochner 		totlen -= len;
    449  1.1  drochner 		*mp = m;
    450  1.1  drochner 		mp = &m->m_next;
    451  1.1  drochner 	}
    452  1.1  drochner 
    453  1.1  drochner 	return (top);
    454  1.1  drochner }
    455  1.1  drochner 
    456  1.1  drochner /*
    457  1.1  drochner  * Pass a packet to the higher levels.
    458  1.1  drochner  */
    459  1.1  drochner void
    460  1.1  drochner lance_read(sc, boff, len)
    461  1.1  drochner 	register struct lance_softc *sc;
    462  1.1  drochner 	int boff, len;
    463  1.1  drochner {
    464  1.1  drochner 	struct mbuf *m;
    465  1.1  drochner 	struct ether_header *eh;
    466  1.1  drochner 
    467  1.1  drochner 	if (len <= sizeof(struct ether_header) ||
    468  1.1  drochner 	    len > ETHERMTU + sizeof(struct ether_header)) {
    469  1.1  drochner #ifdef LEDEBUG
    470  1.1  drochner 		printf("%s: invalid packet size %d; dropping\n",
    471  1.1  drochner 		    sc->sc_dev.dv_xname, len);
    472  1.1  drochner #endif
    473  1.1  drochner 		ifp->if_ierrors++;
    474  1.1  drochner 		return;
    475  1.1  drochner 	}
    476  1.1  drochner 
    477  1.1  drochner 	/* Pull packet off interface. */
    478  1.1  drochner 	m = lance_get(sc, boff, len);
    479  1.1  drochner 	if (m == 0) {
    480  1.1  drochner 		ifp->if_ierrors++;
    481  1.1  drochner 		return;
    482  1.1  drochner 	}
    483  1.1  drochner 
    484  1.1  drochner 	ifp->if_ipackets++;
    485  1.1  drochner 
    486  1.1  drochner 	/* We assume that the header fit entirely in one mbuf. */
    487  1.1  drochner 	eh = mtod(m, struct ether_header *);
    488  1.1  drochner 
    489  1.1  drochner #if NBPFILTER > 0
    490  1.1  drochner 	/*
    491  1.1  drochner 	 * Check if there's a BPF listener on this interface.
    492  1.1  drochner 	 * If so, hand off the raw packet to BPF.
    493  1.1  drochner 	 */
    494  1.1  drochner 	if (ifp->if_bpf) {
    495  1.1  drochner 		bpf_mtap(ifp->if_bpf, m);
    496  1.1  drochner 
    497  1.1  drochner #ifndef LANCE_REVC_BUG
    498  1.1  drochner 		/*
    499  1.1  drochner 		 * Note that the interface cannot be in promiscuous mode if
    500  1.1  drochner 		 * there are no BPF listeners.  And if we are in promiscuous
    501  1.1  drochner 		 * mode, we have to check if this packet is really ours.
    502  1.1  drochner 		 */
    503  1.1  drochner 		if ((ifp->if_flags & IFF_PROMISC) != 0 &&
    504  1.1  drochner 		    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
    505  1.1  drochner 		    ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
    506  1.1  drochner 			m_freem(m);
    507  1.1  drochner 			return;
    508  1.1  drochner 		}
    509  1.1  drochner #endif
    510  1.1  drochner 	}
    511  1.1  drochner #endif
    512  1.1  drochner 
    513  1.1  drochner #ifdef LANCE_REVC_BUG
    514  1.1  drochner 	/*
    515  1.1  drochner 	 * The old LANCE (Rev. C) chips have a bug which causes
    516  1.1  drochner 	 * garbage to be inserted in front of the received packet.
    517  1.1  drochner 	 * The work-around is to ignore packets with an invalid
    518  1.1  drochner 	 * destination address (garbage will usually not match).
    519  1.1  drochner 	 * Of course, this precludes multicast support...
    520  1.1  drochner 	 */
    521  1.1  drochner 	if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
    522  1.1  drochner 	    ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
    523  1.1  drochner 		m_freem(m);
    524  1.1  drochner 		return;
    525  1.1  drochner 	}
    526  1.1  drochner #endif
    527  1.1  drochner 
    528  1.1  drochner 	/* Pass the packet up, with the ether header sort-of removed. */
    529  1.1  drochner 	m_adj(m, sizeof(struct ether_header));
    530  1.1  drochner 	ether_input(ifp, eh, m);
    531  1.1  drochner }
    532  1.1  drochner 
    533  1.1  drochner #undef	ifp
    534  1.1  drochner 
    535  1.1  drochner void
    536  1.1  drochner lance_watchdog(ifp)
    537  1.1  drochner 	struct ifnet *ifp;
    538  1.1  drochner {
    539  1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    540  1.1  drochner 
    541  1.1  drochner 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
    542  1.1  drochner 	++ifp->if_oerrors;
    543  1.1  drochner 
    544  1.1  drochner 	lance_reset(sc);
    545  1.1  drochner }
    546  1.1  drochner 
    547  1.1  drochner int
    548  1.1  drochner lance_mediachange(ifp)
    549  1.1  drochner 	struct ifnet *ifp;
    550  1.1  drochner {
    551  1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    552  1.1  drochner 
    553  1.1  drochner 	if (sc->sc_mediachange)
    554  1.1  drochner 		return ((*sc->sc_mediachange)(sc));
    555  1.1  drochner 	return (EINVAL);
    556  1.1  drochner }
    557  1.1  drochner 
    558  1.1  drochner void
    559  1.1  drochner lance_mediastatus(ifp, ifmr)
    560  1.1  drochner 	struct ifnet *ifp;
    561  1.1  drochner 	struct ifmediareq *ifmr;
    562  1.1  drochner {
    563  1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    564  1.1  drochner 
    565  1.1  drochner 	if ((ifp->if_flags & IFF_UP) == 0)
    566  1.1  drochner 		return;
    567  1.1  drochner 
    568  1.1  drochner 	ifmr->ifm_status = IFM_AVALID;
    569  1.1  drochner 	if (sc->sc_havecarrier)
    570  1.1  drochner 		ifmr->ifm_status |= IFM_ACTIVE;
    571  1.1  drochner 
    572  1.1  drochner 	if (sc->sc_mediastatus)
    573  1.1  drochner 		(*sc->sc_mediastatus)(sc, ifmr);
    574  1.1  drochner }
    575  1.1  drochner 
    576  1.1  drochner /*
    577  1.1  drochner  * Process an ioctl request.
    578  1.1  drochner  */
    579  1.1  drochner int
    580  1.1  drochner lance_ioctl(ifp, cmd, data)
    581  1.1  drochner 	register struct ifnet *ifp;
    582  1.1  drochner 	u_long cmd;
    583  1.1  drochner 	caddr_t data;
    584  1.1  drochner {
    585  1.1  drochner 	register struct lance_softc *sc = ifp->if_softc;
    586  1.1  drochner 	struct ifaddr *ifa = (struct ifaddr *)data;
    587  1.1  drochner 	struct ifreq *ifr = (struct ifreq *)data;
    588  1.1  drochner 	int s, error = 0;
    589  1.1  drochner 
    590  1.2   mycroft 	s = splnet();
    591  1.1  drochner 
    592  1.1  drochner 	switch (cmd) {
    593  1.1  drochner 
    594  1.1  drochner 	case SIOCSIFADDR:
    595  1.1  drochner 		ifp->if_flags |= IFF_UP;
    596  1.1  drochner 
    597  1.1  drochner 		switch (ifa->ifa_addr->sa_family) {
    598  1.1  drochner #ifdef INET
    599  1.1  drochner 		case AF_INET:
    600  1.1  drochner 			lance_init(sc);
    601  1.1  drochner 			arp_ifinit(ifp, ifa);
    602  1.1  drochner 			break;
    603  1.1  drochner #endif
    604  1.1  drochner #ifdef NS
    605  1.1  drochner 		case AF_NS:
    606  1.1  drochner 		    {
    607  1.1  drochner 			register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
    608  1.1  drochner 
    609  1.1  drochner 			if (ns_nullhost(*ina))
    610  1.1  drochner 				ina->x_host =
    611  1.1  drochner 				    *(union ns_host *)LLADDR(ifp->if_sadl);
    612  1.1  drochner 			else {
    613  1.1  drochner 				bcopy(ina->x_host.c_host,
    614  1.1  drochner 				    LLADDR(ifp->if_sadl),
    615  1.1  drochner 				    sizeof(sc->sc_enaddr));
    616  1.1  drochner 			}
    617  1.1  drochner 			/* Set new address. */
    618  1.1  drochner 			lance_init(sc);
    619  1.1  drochner 			break;
    620  1.1  drochner 		    }
    621  1.1  drochner #endif
    622  1.1  drochner 		default:
    623  1.1  drochner 			lance_init(sc);
    624  1.1  drochner 			break;
    625  1.1  drochner 		}
    626  1.1  drochner 		break;
    627  1.1  drochner 
    628  1.1  drochner #if defined(CCITT) && defined(LLC)
    629  1.1  drochner 	case SIOCSIFCONF_X25:
    630  1.1  drochner 		ifp->if_flags |= IFF_UP;
    631  1.1  drochner 		ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
    632  1.1  drochner 		error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
    633  1.1  drochner 		if (error == 0)
    634  1.1  drochner 			lance_init(sc);
    635  1.1  drochner 		break;
    636  1.1  drochner #endif /* CCITT && LLC */
    637  1.1  drochner 
    638  1.1  drochner 	case SIOCSIFFLAGS:
    639  1.1  drochner 		if ((ifp->if_flags & IFF_UP) == 0 &&
    640  1.1  drochner 		    (ifp->if_flags & IFF_RUNNING) != 0) {
    641  1.1  drochner 			/*
    642  1.1  drochner 			 * If interface is marked down and it is running, then
    643  1.1  drochner 			 * stop it.
    644  1.1  drochner 			 */
    645  1.1  drochner 			lance_stop(sc);
    646  1.1  drochner 			ifp->if_flags &= ~IFF_RUNNING;
    647  1.1  drochner 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
    648  1.1  drochner 		    	   (ifp->if_flags & IFF_RUNNING) == 0) {
    649  1.1  drochner 			/*
    650  1.1  drochner 			 * If interface is marked up and it is stopped, then
    651  1.1  drochner 			 * start it.
    652  1.1  drochner 			 */
    653  1.1  drochner 			lance_init(sc);
    654  1.1  drochner 		} else {
    655  1.1  drochner 			/*
    656  1.1  drochner 			 * Reset the interface to pick up changes in any other
    657  1.1  drochner 			 * flags that affect hardware registers.
    658  1.1  drochner 			 */
    659  1.1  drochner 			/*lance_stop(sc);*/
    660  1.1  drochner 			lance_init(sc);
    661  1.1  drochner 		}
    662  1.1  drochner #ifdef LEDEBUG
    663  1.1  drochner 		if (ifp->if_flags & IFF_DEBUG)
    664  1.1  drochner 			sc->sc_debug = 1;
    665  1.1  drochner 		else
    666  1.1  drochner 			sc->sc_debug = 0;
    667  1.1  drochner #endif
    668  1.1  drochner 		break;
    669  1.1  drochner 
    670  1.1  drochner 	case SIOCADDMULTI:
    671  1.1  drochner 	case SIOCDELMULTI:
    672  1.1  drochner 		error = (cmd == SIOCADDMULTI) ?
    673  1.1  drochner 		    ether_addmulti(ifr, &sc->sc_ethercom) :
    674  1.1  drochner 		    ether_delmulti(ifr, &sc->sc_ethercom);
    675  1.1  drochner 
    676  1.1  drochner 		if (error == ENETRESET) {
    677  1.1  drochner 			/*
    678  1.1  drochner 			 * Multicast list has changed; set the hardware filter
    679  1.1  drochner 			 * accordingly.
    680  1.1  drochner 			 */
    681  1.1  drochner 			lance_reset(sc);
    682  1.1  drochner 			error = 0;
    683  1.1  drochner 		}
    684  1.1  drochner 		break;
    685  1.1  drochner 
    686  1.1  drochner 	case SIOCGIFMEDIA:
    687  1.1  drochner 	case SIOCSIFMEDIA:
    688  1.1  drochner 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
    689  1.1  drochner 		break;
    690  1.1  drochner 
    691  1.1  drochner 	default:
    692  1.1  drochner 		error = EINVAL;
    693  1.1  drochner 		break;
    694  1.1  drochner 	}
    695  1.1  drochner 
    696  1.1  drochner 	splx(s);
    697  1.1  drochner 	return (error);
    698  1.1  drochner }
    699  1.1  drochner 
    700  1.1  drochner hide void
    701  1.1  drochner lance_shutdown(arg)
    702  1.1  drochner 	void *arg;
    703  1.1  drochner {
    704  1.1  drochner 
    705  1.1  drochner 	lance_stop((struct lance_softc *)arg);
    706  1.1  drochner }
    707  1.1  drochner 
    708  1.1  drochner /*
    709  1.1  drochner  * Set up the logical address filter.
    710  1.1  drochner  */
    711  1.1  drochner void
    712  1.1  drochner lance_setladrf(ac, af)
    713  1.1  drochner 	struct ethercom *ac;
    714  1.1  drochner 	u_int16_t *af;
    715  1.1  drochner {
    716  1.1  drochner 	struct ifnet *ifp = &ac->ec_if;
    717  1.1  drochner 	struct ether_multi *enm;
    718  1.1  drochner 	register u_char *cp;
    719  1.1  drochner 	register u_int32_t crc;
    720  1.1  drochner 	static const u_int32_t crctab[] = {
    721  1.1  drochner 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    722  1.1  drochner 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    723  1.1  drochner 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    724  1.1  drochner 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    725  1.1  drochner 	};
    726  1.1  drochner 	register int len;
    727  1.1  drochner 	struct ether_multistep step;
    728  1.1  drochner 
    729  1.1  drochner 	/*
    730  1.1  drochner 	 * Set up multicast address filter by passing all multicast addresses
    731  1.1  drochner 	 * through a crc generator, and then using the high order 6 bits as an
    732  1.1  drochner 	 * index into the 64 bit logical address filter.  The high order bit
    733  1.1  drochner 	 * selects the word, while the rest of the bits select the bit within
    734  1.1  drochner 	 * the word.
    735  1.1  drochner 	 */
    736  1.1  drochner 
    737  1.1  drochner 	if (ifp->if_flags & IFF_PROMISC)
    738  1.1  drochner 		goto allmulti;
    739  1.1  drochner 
    740  1.1  drochner 	af[0] = af[1] = af[2] = af[3] = 0x0000;
    741  1.1  drochner 	ETHER_FIRST_MULTI(step, ac, enm);
    742  1.1  drochner 	while (enm != NULL) {
    743  1.1  drochner 		if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
    744  1.1  drochner 			/*
    745  1.1  drochner 			 * We must listen to a range of multicast addresses.
    746  1.1  drochner 			 * For now, just accept all multicasts, rather than
    747  1.1  drochner 			 * trying to set only those filter bits needed to match
    748  1.1  drochner 			 * the range.  (At this time, the only use of address
    749  1.1  drochner 			 * ranges is for IP multicast routing, for which the
    750  1.1  drochner 			 * range is big enough to require all bits set.)
    751  1.1  drochner 			 */
    752  1.1  drochner 			goto allmulti;
    753  1.1  drochner 		}
    754  1.1  drochner 
    755  1.1  drochner 		cp = enm->enm_addrlo;
    756  1.1  drochner 		crc = 0xffffffff;
    757  1.1  drochner 		for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
    758  1.1  drochner 			crc ^= *cp++;
    759  1.1  drochner 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    760  1.1  drochner 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    761  1.1  drochner 		}
    762  1.1  drochner 		/* Just want the 6 most significant bits. */
    763  1.1  drochner 		crc >>= 26;
    764  1.1  drochner 
    765  1.1  drochner 		/* Set the corresponding bit in the filter. */
    766  1.1  drochner 		af[crc >> 4] |= 1 << (crc & 0xf);
    767  1.1  drochner 
    768  1.1  drochner 		ETHER_NEXT_MULTI(step, enm);
    769  1.1  drochner 	}
    770  1.1  drochner 	ifp->if_flags &= ~IFF_ALLMULTI;
    771  1.1  drochner 	return;
    772  1.1  drochner 
    773  1.1  drochner allmulti:
    774  1.1  drochner 	ifp->if_flags |= IFF_ALLMULTI;
    775  1.1  drochner 	af[0] = af[1] = af[2] = af[3] = 0xffff;
    776  1.1  drochner }
    777  1.1  drochner 
    778  1.1  drochner /*
    779  1.1  drochner  * Routines for accessing the transmit and receive buffers.
    780  1.1  drochner  * The various CPU and adapter configurations supported by this
    781  1.1  drochner  * driver require three different access methods for buffers
    782  1.1  drochner  * and descriptors:
    783  1.1  drochner  *	(1) contig (contiguous data; no padding),
    784  1.1  drochner  *	(2) gap2 (two bytes of data followed by two bytes of padding),
    785  1.1  drochner  *	(3) gap16 (16 bytes of data followed by 16 bytes of padding).
    786  1.1  drochner  */
    787  1.1  drochner 
    788  1.1  drochner /*
    789  1.1  drochner  * contig: contiguous data with no padding.
    790  1.1  drochner  *
    791  1.1  drochner  * Buffers may have any alignment.
    792  1.1  drochner  */
    793  1.1  drochner 
    794  1.1  drochner void
    795  1.1  drochner lance_copytobuf_contig(sc, from, boff, len)
    796  1.1  drochner 	struct lance_softc *sc;
    797  1.1  drochner 	void *from;
    798  1.1  drochner 	int boff, len;
    799  1.1  drochner {
    800  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    801  1.1  drochner 
    802  1.1  drochner 	/*
    803  1.1  drochner 	 * Just call bcopy() to do the work.
    804  1.1  drochner 	 */
    805  1.1  drochner 	bcopy(from, buf + boff, len);
    806  1.1  drochner }
    807  1.1  drochner 
    808  1.1  drochner void
    809  1.1  drochner lance_copyfrombuf_contig(sc, to, boff, len)
    810  1.1  drochner 	struct lance_softc *sc;
    811  1.1  drochner 	void *to;
    812  1.1  drochner 	int boff, len;
    813  1.1  drochner {
    814  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    815  1.1  drochner 
    816  1.1  drochner 	/*
    817  1.1  drochner 	 * Just call bcopy() to do the work.
    818  1.1  drochner 	 */
    819  1.1  drochner 	bcopy(buf + boff, to, len);
    820  1.1  drochner }
    821  1.1  drochner 
    822  1.1  drochner void
    823  1.1  drochner lance_zerobuf_contig(sc, boff, len)
    824  1.1  drochner 	struct lance_softc *sc;
    825  1.1  drochner 	int boff, len;
    826  1.1  drochner {
    827  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    828  1.1  drochner 
    829  1.1  drochner 	/*
    830  1.1  drochner 	 * Just let bzero() do the work
    831  1.1  drochner 	 */
    832  1.1  drochner 	bzero(buf + boff, len);
    833  1.1  drochner }
    834  1.1  drochner 
    835  1.1  drochner #if 0
    836  1.1  drochner /*
    837  1.1  drochner  * Examples only; duplicate these and tweak (if necessary) in
    838  1.1  drochner  * machine-specific front-ends.
    839  1.1  drochner  */
    840  1.1  drochner 
    841  1.1  drochner /*
    842  1.1  drochner  * gap2: two bytes of data followed by two bytes of pad.
    843  1.1  drochner  *
    844  1.1  drochner  * Buffers must be 4-byte aligned.  The code doesn't worry about
    845  1.1  drochner  * doing an extra byte.
    846  1.1  drochner  */
    847  1.1  drochner 
    848  1.1  drochner void
    849  1.1  drochner lance_copytobuf_gap2(sc, fromv, boff, len)
    850  1.1  drochner 	struct lance_softc *sc;
    851  1.1  drochner 	void *fromv;
    852  1.1  drochner 	int boff;
    853  1.1  drochner 	register int len;
    854  1.1  drochner {
    855  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    856  1.1  drochner 	register caddr_t from = fromv;
    857  1.1  drochner 	register volatile u_int16_t *bptr;
    858  1.1  drochner 
    859  1.1  drochner 	if (boff & 0x1) {
    860  1.1  drochner 		/* handle unaligned first byte */
    861  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    862  1.1  drochner 		*bptr = (*from++ << 8) | (*bptr & 0xff);
    863  1.1  drochner 		bptr += 2;
    864  1.1  drochner 		len--;
    865  1.1  drochner 	} else
    866  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    867  1.1  drochner 	while (len > 1) {
    868  1.1  drochner 		*bptr = (from[1] << 8) | (from[0] & 0xff);
    869  1.1  drochner 		bptr += 2;
    870  1.1  drochner 		from += 2;
    871  1.1  drochner 		len -= 2;
    872  1.1  drochner 	}
    873  1.1  drochner 	if (len == 1)
    874  1.1  drochner 		*bptr = (u_int16_t)*from;
    875  1.1  drochner }
    876  1.1  drochner 
    877  1.1  drochner void
    878  1.1  drochner lance_copyfrombuf_gap2(sc, tov, boff, len)
    879  1.1  drochner 	struct lance_softc *sc;
    880  1.1  drochner 	void *tov;
    881  1.1  drochner 	int boff, len;
    882  1.1  drochner {
    883  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    884  1.1  drochner 	register caddr_t to = tov;
    885  1.1  drochner 	register volatile u_int16_t *bptr;
    886  1.1  drochner 	register u_int16_t tmp;
    887  1.1  drochner 
    888  1.1  drochner 	if (boff & 0x1) {
    889  1.1  drochner 		/* handle unaligned first byte */
    890  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    891  1.1  drochner 		*to++ = (*bptr >> 8) & 0xff;
    892  1.1  drochner 		bptr += 2;
    893  1.1  drochner 		len--;
    894  1.1  drochner 	} else
    895  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    896  1.1  drochner 	while (len > 1) {
    897  1.1  drochner 		tmp = *bptr;
    898  1.1  drochner 		*to++ = tmp & 0xff;
    899  1.1  drochner 		*to++ = (tmp >> 8) & 0xff;
    900  1.1  drochner 		bptr += 2;
    901  1.1  drochner 		len -= 2;
    902  1.1  drochner 	}
    903  1.1  drochner 	if (len == 1)
    904  1.1  drochner 		*to = *bptr & 0xff;
    905  1.1  drochner }
    906  1.1  drochner 
    907  1.1  drochner void
    908  1.1  drochner lance_zerobuf_gap2(sc, boff, len)
    909  1.1  drochner 	struct lance_softc *sc;
    910  1.1  drochner 	int boff, len;
    911  1.1  drochner {
    912  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    913  1.1  drochner 	register volatile u_int16_t *bptr;
    914  1.1  drochner 
    915  1.1  drochner 	if ((unsigned)boff & 0x1) {
    916  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    917  1.1  drochner 		*bptr &= 0xff;
    918  1.1  drochner 		bptr += 2;
    919  1.1  drochner 		len--;
    920  1.1  drochner 	} else
    921  1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    922  1.1  drochner 	while (len > 0) {
    923  1.1  drochner 		*bptr = 0;
    924  1.1  drochner 		bptr += 2;
    925  1.1  drochner 		len -= 2;
    926  1.1  drochner 	}
    927  1.1  drochner }
    928  1.1  drochner 
    929  1.1  drochner /*
    930  1.1  drochner  * gap16: 16 bytes of data followed by 16 bytes of pad.
    931  1.1  drochner  *
    932  1.1  drochner  * Buffers must be 32-byte aligned.
    933  1.1  drochner  */
    934  1.1  drochner 
    935  1.1  drochner void
    936  1.1  drochner lance_copytobuf_gap16(sc, fromv, boff, len)
    937  1.1  drochner 	struct lance_softc *sc;
    938  1.1  drochner 	void *fromv;
    939  1.1  drochner 	int boff;
    940  1.1  drochner 	register int len;
    941  1.1  drochner {
    942  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    943  1.1  drochner 	register caddr_t from = fromv;
    944  1.1  drochner 	register caddr_t bptr;
    945  1.1  drochner 	register int xfer;
    946  1.1  drochner 
    947  1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    948  1.1  drochner 	boff &= 0xf;
    949  1.1  drochner 	xfer = min(len, 16 - boff);
    950  1.1  drochner 	while (len > 0) {
    951  1.1  drochner 		bcopy(from, bptr + boff, xfer);
    952  1.1  drochner 		from += xfer;
    953  1.1  drochner 		bptr += 32;
    954  1.1  drochner 		boff = 0;
    955  1.1  drochner 		len -= xfer;
    956  1.1  drochner 		xfer = min(len, 16);
    957  1.1  drochner 	}
    958  1.1  drochner }
    959  1.1  drochner 
    960  1.1  drochner void
    961  1.1  drochner lance_copyfrombuf_gap16(sc, tov, boff, len)
    962  1.1  drochner 	struct lance_softc *sc;
    963  1.1  drochner 	void *tov;
    964  1.1  drochner 	int boff, len;
    965  1.1  drochner {
    966  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    967  1.1  drochner 	register caddr_t to = tov;
    968  1.1  drochner 	register caddr_t bptr;
    969  1.1  drochner 	register int xfer;
    970  1.1  drochner 
    971  1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    972  1.1  drochner 	boff &= 0xf;
    973  1.1  drochner 	xfer = min(len, 16 - boff);
    974  1.1  drochner 	while (len > 0) {
    975  1.1  drochner 		bcopy(bptr + boff, to, xfer);
    976  1.1  drochner 		to += xfer;
    977  1.1  drochner 		bptr += 32;
    978  1.1  drochner 		boff = 0;
    979  1.1  drochner 		len -= xfer;
    980  1.1  drochner 		xfer = min(len, 16);
    981  1.1  drochner 	}
    982  1.1  drochner }
    983  1.1  drochner 
    984  1.1  drochner void
    985  1.1  drochner lance_zerobuf_gap16(sc, boff, len)
    986  1.1  drochner 	struct lance_softc *sc;
    987  1.1  drochner 	int boff, len;
    988  1.1  drochner {
    989  1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    990  1.1  drochner 	register caddr_t bptr;
    991  1.1  drochner 	register int xfer;
    992  1.1  drochner 
    993  1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    994  1.1  drochner 	boff &= 0xf;
    995  1.1  drochner 	xfer = min(len, 16 - boff);
    996  1.1  drochner 	while (len > 0) {
    997  1.1  drochner 		bzero(bptr + boff, xfer);
    998  1.1  drochner 		bptr += 32;
    999  1.1  drochner 		boff = 0;
   1000  1.1  drochner 		len -= xfer;
   1001  1.1  drochner 		xfer = min(len, 16);
   1002  1.1  drochner 	}
   1003  1.1  drochner }
   1004  1.1  drochner #endif /* Example only */
   1005