Home | History | Annotate | Line # | Download | only in ic
lance.c revision 1.11
      1  1.11  augustss /*	$NetBSD: lance.c,v 1.11 2000/03/30 12:45:31 augustss 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.11  augustss 	u_int16_t *a = (u_short *) one;
    176  1.11  augustss 	u_int16_t *b = (u_short *) two;
    177  1.11  augustss 	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 	switch (sc->sc_memsize) {
    243   1.1  drochner 	case 8192:
    244   1.1  drochner 		sc->sc_nrbuf = 4;
    245   1.1  drochner 		sc->sc_ntbuf = 1;
    246   1.1  drochner 		break;
    247   1.1  drochner 	case 16384:
    248   1.1  drochner 		sc->sc_nrbuf = 8;
    249   1.1  drochner 		sc->sc_ntbuf = 2;
    250   1.1  drochner 		break;
    251   1.1  drochner 	case 32768:
    252   1.1  drochner 		sc->sc_nrbuf = 16;
    253   1.1  drochner 		sc->sc_ntbuf = 4;
    254   1.1  drochner 		break;
    255   1.1  drochner 	case 65536:
    256   1.1  drochner 		sc->sc_nrbuf = 32;
    257   1.1  drochner 		sc->sc_ntbuf = 8;
    258   1.1  drochner 		break;
    259   1.1  drochner 	case 131072:
    260   1.1  drochner 		sc->sc_nrbuf = 64;
    261   1.1  drochner 		sc->sc_ntbuf = 16;
    262   1.4       leo 		break;
    263   1.4       leo 	case 262144:
    264   1.4       leo 		sc->sc_nrbuf = 128;
    265   1.4       leo 		sc->sc_ntbuf = 32;
    266   1.1  drochner 		break;
    267   1.1  drochner 	default:
    268   1.1  drochner 		panic("lance_config: weird memory size");
    269   1.1  drochner 	}
    270   1.1  drochner 
    271   1.1  drochner 	printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
    272   1.1  drochner 	printf("%s: %d receive buffers, %d transmit buffers\n",
    273   1.1  drochner 	    sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
    274  1.10    simonb 
    275  1.10    simonb 	/* Attach the interface. */
    276  1.10    simonb 	if_attach(ifp);
    277  1.10    simonb 	ether_ifattach(ifp, sc->sc_enaddr);
    278  1.10    simonb 
    279  1.10    simonb #if NBPFILTER > 0
    280  1.10    simonb 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
    281  1.10    simonb #endif
    282   1.1  drochner 
    283   1.1  drochner 	sc->sc_sh = shutdownhook_establish(lance_shutdown, sc);
    284   1.1  drochner 	if (sc->sc_sh == NULL)
    285   1.1  drochner 		panic("lance_config: can't establish shutdownhook");
    286   1.1  drochner 	sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
    287   1.1  drochner 					M_WAITOK);
    288   1.1  drochner 	sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
    289   1.1  drochner 					M_WAITOK);
    290   1.1  drochner 
    291   1.1  drochner #if NRND > 0
    292   1.1  drochner 	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
    293   1.7  explorer 			  RND_TYPE_NET, 0);
    294   1.1  drochner #endif
    295   1.1  drochner }
    296   1.1  drochner 
    297   1.1  drochner void
    298   1.1  drochner lance_reset(sc)
    299   1.1  drochner 	struct lance_softc *sc;
    300   1.1  drochner {
    301   1.1  drochner 	int s;
    302   1.1  drochner 
    303   1.2   mycroft 	s = splnet();
    304   1.1  drochner 	lance_init(sc);
    305   1.1  drochner 	splx(s);
    306   1.1  drochner }
    307   1.1  drochner 
    308   1.1  drochner void
    309   1.1  drochner lance_stop(sc)
    310   1.1  drochner 	struct lance_softc *sc;
    311   1.1  drochner {
    312   1.1  drochner 
    313   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
    314   1.1  drochner }
    315   1.1  drochner 
    316   1.1  drochner /*
    317   1.1  drochner  * Initialization of interface; set up initialization block
    318   1.1  drochner  * and transmit/receive descriptor rings.
    319   1.1  drochner  */
    320   1.1  drochner void
    321   1.1  drochner lance_init(sc)
    322  1.11  augustss 	struct lance_softc *sc;
    323   1.1  drochner {
    324  1.11  augustss 	int timo;
    325   1.1  drochner 	u_long a;
    326   1.1  drochner 
    327   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
    328   1.1  drochner 	DELAY(100);
    329   1.1  drochner 
    330   1.1  drochner 	/* Newer LANCE chips have a reset register */
    331   1.1  drochner 	if (sc->sc_hwreset)
    332   1.1  drochner 		(*sc->sc_hwreset)(sc);
    333   1.1  drochner 
    334   1.1  drochner 	/* Set the correct byte swapping mode, etc. */
    335   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
    336   1.1  drochner 
    337   1.1  drochner 	/* Set up LANCE init block. */
    338   1.1  drochner 	(*sc->sc_meminit)(sc);
    339   1.1  drochner 
    340   1.1  drochner 	/* Give LANCE the physical address of its init block. */
    341   1.1  drochner 	a = sc->sc_addr + LE_INITADDR(sc);
    342   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR1, a);
    343   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
    344   1.1  drochner 
    345   1.1  drochner 	/* Try to initialize the LANCE. */
    346   1.1  drochner 	DELAY(100);
    347   1.1  drochner 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
    348   1.1  drochner 
    349   1.1  drochner 	/* Wait for initialization to finish. */
    350   1.1  drochner 	for (timo = 100000; timo; timo--)
    351   1.1  drochner 		if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
    352   1.1  drochner 			break;
    353   1.1  drochner 
    354   1.1  drochner 	if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
    355   1.1  drochner 		/* Start the LANCE. */
    356   1.1  drochner 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
    357   1.1  drochner 		    LE_C0_IDON);
    358   1.1  drochner 		ifp->if_flags |= IFF_RUNNING;
    359   1.1  drochner 		ifp->if_flags &= ~IFF_OACTIVE;
    360   1.1  drochner 		ifp->if_timer = 0;
    361   1.1  drochner 		(*sc->sc_start)(ifp);
    362   1.1  drochner 	} else
    363   1.1  drochner 		printf("%s: controller failed to initialize\n",
    364   1.1  drochner 			sc->sc_dev.dv_xname);
    365   1.1  drochner 	if (sc->sc_hwinit)
    366   1.1  drochner 		(*sc->sc_hwinit)(sc);
    367   1.1  drochner }
    368   1.1  drochner 
    369   1.1  drochner /*
    370   1.1  drochner  * Routine to copy from mbuf chain to transmit buffer in
    371   1.1  drochner  * network buffer memory.
    372   1.1  drochner  */
    373   1.1  drochner int
    374   1.1  drochner lance_put(sc, boff, m)
    375   1.1  drochner 	struct lance_softc *sc;
    376   1.1  drochner 	int boff;
    377  1.11  augustss 	struct mbuf *m;
    378   1.1  drochner {
    379  1.11  augustss 	struct mbuf *n;
    380  1.11  augustss 	int len, tlen = 0;
    381   1.1  drochner 
    382   1.1  drochner 	for (; m; m = n) {
    383   1.1  drochner 		len = m->m_len;
    384   1.1  drochner 		if (len == 0) {
    385   1.1  drochner 			MFREE(m, n);
    386   1.1  drochner 			continue;
    387   1.1  drochner 		}
    388   1.1  drochner 		(*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
    389   1.1  drochner 		boff += len;
    390   1.1  drochner 		tlen += len;
    391   1.1  drochner 		MFREE(m, n);
    392   1.1  drochner 	}
    393   1.1  drochner 	if (tlen < LEMINSIZE) {
    394   1.1  drochner 		(*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
    395   1.1  drochner 		tlen = LEMINSIZE;
    396   1.1  drochner 	}
    397   1.1  drochner 	return (tlen);
    398   1.1  drochner }
    399   1.1  drochner 
    400   1.1  drochner /*
    401   1.1  drochner  * Pull data off an interface.
    402   1.1  drochner  * Len is length of data, with local net header stripped.
    403   1.1  drochner  * We copy the data into mbufs.  When full cluster sized units are present
    404   1.1  drochner  * we copy into clusters.
    405   1.1  drochner  */
    406   1.1  drochner integrate struct mbuf *
    407   1.1  drochner lance_get(sc, boff, totlen)
    408   1.1  drochner 	struct lance_softc *sc;
    409   1.1  drochner 	int boff, totlen;
    410   1.1  drochner {
    411   1.5   mycroft 	struct mbuf *m, *m0, *newm;
    412   1.1  drochner 	int len;
    413   1.1  drochner 
    414   1.5   mycroft 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
    415   1.5   mycroft 	if (m0 == 0)
    416   1.1  drochner 		return (0);
    417   1.5   mycroft 	m0->m_pkthdr.rcvif = ifp;
    418   1.5   mycroft 	m0->m_pkthdr.len = totlen;
    419   1.1  drochner 	len = MHLEN;
    420   1.5   mycroft 	m = m0;
    421   1.1  drochner 
    422   1.1  drochner 	while (totlen > 0) {
    423   1.1  drochner 		if (totlen >= MINCLSIZE) {
    424   1.1  drochner 			MCLGET(m, M_DONTWAIT);
    425   1.5   mycroft 			if ((m->m_flags & M_EXT) == 0)
    426   1.5   mycroft 				goto bad;
    427   1.1  drochner 			len = MCLBYTES;
    428   1.1  drochner 		}
    429   1.5   mycroft 
    430   1.5   mycroft 		if (m == m0) {
    431   1.5   mycroft 			caddr_t newdata = (caddr_t)
    432   1.5   mycroft 			    ALIGN(m->m_data + sizeof(struct ether_header)) -
    433   1.5   mycroft 			    sizeof(struct ether_header);
    434   1.5   mycroft 			len -= newdata - m->m_data;
    435   1.5   mycroft 			m->m_data = newdata;
    436   1.1  drochner 		}
    437   1.5   mycroft 
    438   1.1  drochner 		m->m_len = len = min(totlen, len);
    439   1.1  drochner 		(*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
    440   1.1  drochner 		boff += len;
    441   1.5   mycroft 
    442   1.1  drochner 		totlen -= len;
    443   1.5   mycroft 		if (totlen > 0) {
    444   1.5   mycroft 			MGET(newm, M_DONTWAIT, MT_DATA);
    445   1.5   mycroft 			if (newm == 0)
    446   1.5   mycroft 				goto bad;
    447   1.5   mycroft 			len = MLEN;
    448   1.5   mycroft 			m = m->m_next = newm;
    449   1.5   mycroft 		}
    450   1.1  drochner 	}
    451   1.1  drochner 
    452   1.5   mycroft 	return (m0);
    453   1.5   mycroft 
    454   1.5   mycroft bad:
    455   1.5   mycroft 	m_freem(m0);
    456   1.5   mycroft 	return (0);
    457   1.1  drochner }
    458   1.1  drochner 
    459   1.1  drochner /*
    460   1.1  drochner  * Pass a packet to the higher levels.
    461   1.1  drochner  */
    462   1.1  drochner void
    463   1.1  drochner lance_read(sc, boff, len)
    464  1.11  augustss 	struct lance_softc *sc;
    465   1.1  drochner 	int boff, len;
    466   1.1  drochner {
    467   1.1  drochner 	struct mbuf *m;
    468   1.1  drochner 	struct ether_header *eh;
    469   1.1  drochner 
    470   1.1  drochner 	if (len <= sizeof(struct ether_header) ||
    471   1.1  drochner 	    len > ETHERMTU + sizeof(struct ether_header)) {
    472   1.1  drochner #ifdef LEDEBUG
    473   1.1  drochner 		printf("%s: invalid packet size %d; dropping\n",
    474   1.1  drochner 		    sc->sc_dev.dv_xname, len);
    475   1.1  drochner #endif
    476   1.1  drochner 		ifp->if_ierrors++;
    477   1.1  drochner 		return;
    478   1.1  drochner 	}
    479   1.1  drochner 
    480   1.1  drochner 	/* Pull packet off interface. */
    481   1.1  drochner 	m = lance_get(sc, boff, len);
    482   1.1  drochner 	if (m == 0) {
    483   1.1  drochner 		ifp->if_ierrors++;
    484   1.1  drochner 		return;
    485   1.1  drochner 	}
    486   1.1  drochner 
    487   1.1  drochner 	ifp->if_ipackets++;
    488   1.1  drochner 
    489   1.1  drochner 	/* We assume that the header fit entirely in one mbuf. */
    490   1.1  drochner 	eh = mtod(m, struct ether_header *);
    491   1.1  drochner 
    492   1.1  drochner #if NBPFILTER > 0
    493   1.1  drochner 	/*
    494   1.1  drochner 	 * Check if there's a BPF listener on this interface.
    495   1.1  drochner 	 * If so, hand off the raw packet to BPF.
    496   1.1  drochner 	 */
    497   1.1  drochner 	if (ifp->if_bpf) {
    498   1.1  drochner 		bpf_mtap(ifp->if_bpf, m);
    499   1.1  drochner 
    500   1.1  drochner #ifndef LANCE_REVC_BUG
    501   1.1  drochner 		/*
    502   1.1  drochner 		 * Note that the interface cannot be in promiscuous mode if
    503   1.1  drochner 		 * there are no BPF listeners.  And if we are in promiscuous
    504   1.1  drochner 		 * mode, we have to check if this packet is really ours.
    505   1.1  drochner 		 */
    506   1.1  drochner 		if ((ifp->if_flags & IFF_PROMISC) != 0 &&
    507   1.1  drochner 		    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
    508   1.1  drochner 		    ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
    509   1.1  drochner 			m_freem(m);
    510   1.1  drochner 			return;
    511   1.1  drochner 		}
    512   1.1  drochner #endif
    513   1.1  drochner 	}
    514   1.1  drochner #endif
    515   1.1  drochner 
    516   1.1  drochner #ifdef LANCE_REVC_BUG
    517   1.1  drochner 	/*
    518   1.1  drochner 	 * The old LANCE (Rev. C) chips have a bug which causes
    519   1.1  drochner 	 * garbage to be inserted in front of the received packet.
    520   1.1  drochner 	 * The work-around is to ignore packets with an invalid
    521   1.1  drochner 	 * destination address (garbage will usually not match).
    522   1.1  drochner 	 * Of course, this precludes multicast support...
    523   1.1  drochner 	 */
    524   1.1  drochner 	if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
    525   1.1  drochner 	    ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
    526   1.1  drochner 		m_freem(m);
    527   1.1  drochner 		return;
    528   1.1  drochner 	}
    529   1.1  drochner #endif
    530   1.1  drochner 
    531   1.9   thorpej 	/* Pass the packet up. */
    532   1.9   thorpej 	(*ifp->if_input)(ifp, m);
    533   1.1  drochner }
    534   1.1  drochner 
    535   1.1  drochner #undef	ifp
    536   1.1  drochner 
    537   1.1  drochner void
    538   1.1  drochner lance_watchdog(ifp)
    539   1.1  drochner 	struct ifnet *ifp;
    540   1.1  drochner {
    541   1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    542   1.1  drochner 
    543   1.1  drochner 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
    544   1.1  drochner 	++ifp->if_oerrors;
    545   1.1  drochner 
    546   1.1  drochner 	lance_reset(sc);
    547   1.1  drochner }
    548   1.1  drochner 
    549   1.1  drochner int
    550   1.1  drochner lance_mediachange(ifp)
    551   1.1  drochner 	struct ifnet *ifp;
    552   1.1  drochner {
    553   1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    554   1.1  drochner 
    555   1.1  drochner 	if (sc->sc_mediachange)
    556   1.1  drochner 		return ((*sc->sc_mediachange)(sc));
    557   1.8   thorpej 	return (0);
    558   1.1  drochner }
    559   1.1  drochner 
    560   1.1  drochner void
    561   1.1  drochner lance_mediastatus(ifp, ifmr)
    562   1.1  drochner 	struct ifnet *ifp;
    563   1.1  drochner 	struct ifmediareq *ifmr;
    564   1.1  drochner {
    565   1.1  drochner 	struct lance_softc *sc = ifp->if_softc;
    566   1.1  drochner 
    567   1.1  drochner 	if ((ifp->if_flags & IFF_UP) == 0)
    568   1.1  drochner 		return;
    569   1.1  drochner 
    570   1.1  drochner 	ifmr->ifm_status = IFM_AVALID;
    571   1.1  drochner 	if (sc->sc_havecarrier)
    572   1.1  drochner 		ifmr->ifm_status |= IFM_ACTIVE;
    573   1.1  drochner 
    574   1.1  drochner 	if (sc->sc_mediastatus)
    575   1.1  drochner 		(*sc->sc_mediastatus)(sc, ifmr);
    576   1.1  drochner }
    577   1.1  drochner 
    578   1.1  drochner /*
    579   1.1  drochner  * Process an ioctl request.
    580   1.1  drochner  */
    581   1.1  drochner int
    582   1.1  drochner lance_ioctl(ifp, cmd, data)
    583  1.11  augustss 	struct ifnet *ifp;
    584   1.1  drochner 	u_long cmd;
    585   1.1  drochner 	caddr_t data;
    586   1.1  drochner {
    587  1.11  augustss 	struct lance_softc *sc = ifp->if_softc;
    588   1.1  drochner 	struct ifaddr *ifa = (struct ifaddr *)data;
    589   1.1  drochner 	struct ifreq *ifr = (struct ifreq *)data;
    590   1.1  drochner 	int s, error = 0;
    591   1.1  drochner 
    592   1.2   mycroft 	s = splnet();
    593   1.1  drochner 
    594   1.1  drochner 	switch (cmd) {
    595   1.1  drochner 
    596   1.1  drochner 	case SIOCSIFADDR:
    597   1.1  drochner 		ifp->if_flags |= IFF_UP;
    598   1.1  drochner 
    599   1.1  drochner 		switch (ifa->ifa_addr->sa_family) {
    600   1.1  drochner #ifdef INET
    601   1.1  drochner 		case AF_INET:
    602   1.1  drochner 			lance_init(sc);
    603   1.1  drochner 			arp_ifinit(ifp, ifa);
    604   1.1  drochner 			break;
    605   1.1  drochner #endif
    606   1.1  drochner #ifdef NS
    607   1.1  drochner 		case AF_NS:
    608   1.1  drochner 		    {
    609  1.11  augustss 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
    610   1.1  drochner 
    611   1.1  drochner 			if (ns_nullhost(*ina))
    612   1.1  drochner 				ina->x_host =
    613   1.1  drochner 				    *(union ns_host *)LLADDR(ifp->if_sadl);
    614   1.1  drochner 			else {
    615   1.1  drochner 				bcopy(ina->x_host.c_host,
    616   1.1  drochner 				    LLADDR(ifp->if_sadl),
    617   1.1  drochner 				    sizeof(sc->sc_enaddr));
    618   1.1  drochner 			}
    619   1.1  drochner 			/* Set new address. */
    620   1.1  drochner 			lance_init(sc);
    621   1.1  drochner 			break;
    622   1.1  drochner 		    }
    623   1.1  drochner #endif
    624   1.1  drochner 		default:
    625   1.1  drochner 			lance_init(sc);
    626   1.1  drochner 			break;
    627   1.1  drochner 		}
    628   1.1  drochner 		break;
    629   1.1  drochner 
    630   1.1  drochner #if defined(CCITT) && defined(LLC)
    631   1.1  drochner 	case SIOCSIFCONF_X25:
    632   1.1  drochner 		ifp->if_flags |= IFF_UP;
    633   1.1  drochner 		ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
    634   1.1  drochner 		error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
    635   1.1  drochner 		if (error == 0)
    636   1.1  drochner 			lance_init(sc);
    637   1.1  drochner 		break;
    638   1.1  drochner #endif /* CCITT && LLC */
    639   1.1  drochner 
    640   1.1  drochner 	case SIOCSIFFLAGS:
    641   1.1  drochner 		if ((ifp->if_flags & IFF_UP) == 0 &&
    642   1.1  drochner 		    (ifp->if_flags & IFF_RUNNING) != 0) {
    643   1.1  drochner 			/*
    644   1.1  drochner 			 * If interface is marked down and it is running, then
    645   1.1  drochner 			 * stop it.
    646   1.1  drochner 			 */
    647   1.1  drochner 			lance_stop(sc);
    648   1.1  drochner 			ifp->if_flags &= ~IFF_RUNNING;
    649   1.1  drochner 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
    650   1.1  drochner 		    	   (ifp->if_flags & IFF_RUNNING) == 0) {
    651   1.1  drochner 			/*
    652   1.1  drochner 			 * If interface is marked up and it is stopped, then
    653   1.1  drochner 			 * start it.
    654   1.1  drochner 			 */
    655   1.1  drochner 			lance_init(sc);
    656   1.6   thorpej 		} else if ((ifp->if_flags & IFF_UP) != 0) {
    657   1.1  drochner 			/*
    658   1.1  drochner 			 * Reset the interface to pick up changes in any other
    659   1.1  drochner 			 * flags that affect hardware registers.
    660   1.1  drochner 			 */
    661   1.1  drochner 			/*lance_stop(sc);*/
    662   1.1  drochner 			lance_init(sc);
    663   1.1  drochner 		}
    664   1.1  drochner #ifdef LEDEBUG
    665   1.1  drochner 		if (ifp->if_flags & IFF_DEBUG)
    666   1.1  drochner 			sc->sc_debug = 1;
    667   1.1  drochner 		else
    668   1.1  drochner 			sc->sc_debug = 0;
    669   1.1  drochner #endif
    670   1.1  drochner 		break;
    671   1.1  drochner 
    672   1.1  drochner 	case SIOCADDMULTI:
    673   1.1  drochner 	case SIOCDELMULTI:
    674   1.1  drochner 		error = (cmd == SIOCADDMULTI) ?
    675   1.1  drochner 		    ether_addmulti(ifr, &sc->sc_ethercom) :
    676   1.1  drochner 		    ether_delmulti(ifr, &sc->sc_ethercom);
    677   1.1  drochner 
    678   1.1  drochner 		if (error == ENETRESET) {
    679   1.1  drochner 			/*
    680   1.1  drochner 			 * Multicast list has changed; set the hardware filter
    681   1.1  drochner 			 * accordingly.
    682   1.1  drochner 			 */
    683   1.1  drochner 			lance_reset(sc);
    684   1.1  drochner 			error = 0;
    685   1.1  drochner 		}
    686   1.1  drochner 		break;
    687   1.1  drochner 
    688   1.1  drochner 	case SIOCGIFMEDIA:
    689   1.1  drochner 	case SIOCSIFMEDIA:
    690   1.1  drochner 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
    691   1.1  drochner 		break;
    692   1.1  drochner 
    693   1.1  drochner 	default:
    694   1.1  drochner 		error = EINVAL;
    695   1.1  drochner 		break;
    696   1.1  drochner 	}
    697   1.1  drochner 
    698   1.1  drochner 	splx(s);
    699   1.1  drochner 	return (error);
    700   1.1  drochner }
    701   1.1  drochner 
    702   1.1  drochner hide void
    703   1.1  drochner lance_shutdown(arg)
    704   1.1  drochner 	void *arg;
    705   1.1  drochner {
    706   1.1  drochner 
    707   1.1  drochner 	lance_stop((struct lance_softc *)arg);
    708   1.1  drochner }
    709   1.1  drochner 
    710   1.1  drochner /*
    711   1.1  drochner  * Set up the logical address filter.
    712   1.1  drochner  */
    713   1.1  drochner void
    714   1.1  drochner lance_setladrf(ac, af)
    715   1.1  drochner 	struct ethercom *ac;
    716   1.1  drochner 	u_int16_t *af;
    717   1.1  drochner {
    718   1.1  drochner 	struct ifnet *ifp = &ac->ec_if;
    719   1.1  drochner 	struct ether_multi *enm;
    720  1.11  augustss 	u_char *cp;
    721  1.11  augustss 	u_int32_t crc;
    722   1.1  drochner 	static const u_int32_t crctab[] = {
    723   1.1  drochner 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    724   1.1  drochner 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    725   1.1  drochner 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    726   1.1  drochner 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    727   1.1  drochner 	};
    728  1.11  augustss 	int len;
    729   1.1  drochner 	struct ether_multistep step;
    730   1.1  drochner 
    731   1.1  drochner 	/*
    732   1.1  drochner 	 * Set up multicast address filter by passing all multicast addresses
    733   1.1  drochner 	 * through a crc generator, and then using the high order 6 bits as an
    734   1.1  drochner 	 * index into the 64 bit logical address filter.  The high order bit
    735   1.1  drochner 	 * selects the word, while the rest of the bits select the bit within
    736   1.1  drochner 	 * the word.
    737   1.1  drochner 	 */
    738   1.1  drochner 
    739   1.1  drochner 	if (ifp->if_flags & IFF_PROMISC)
    740   1.1  drochner 		goto allmulti;
    741   1.1  drochner 
    742   1.1  drochner 	af[0] = af[1] = af[2] = af[3] = 0x0000;
    743   1.1  drochner 	ETHER_FIRST_MULTI(step, ac, enm);
    744   1.1  drochner 	while (enm != NULL) {
    745   1.1  drochner 		if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
    746   1.1  drochner 			/*
    747   1.1  drochner 			 * We must listen to a range of multicast addresses.
    748   1.1  drochner 			 * For now, just accept all multicasts, rather than
    749   1.1  drochner 			 * trying to set only those filter bits needed to match
    750   1.1  drochner 			 * the range.  (At this time, the only use of address
    751   1.1  drochner 			 * ranges is for IP multicast routing, for which the
    752   1.1  drochner 			 * range is big enough to require all bits set.)
    753   1.1  drochner 			 */
    754   1.1  drochner 			goto allmulti;
    755   1.1  drochner 		}
    756   1.1  drochner 
    757   1.1  drochner 		cp = enm->enm_addrlo;
    758   1.1  drochner 		crc = 0xffffffff;
    759   1.1  drochner 		for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
    760   1.1  drochner 			crc ^= *cp++;
    761   1.1  drochner 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    762   1.1  drochner 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    763   1.1  drochner 		}
    764   1.1  drochner 		/* Just want the 6 most significant bits. */
    765   1.1  drochner 		crc >>= 26;
    766   1.1  drochner 
    767   1.1  drochner 		/* Set the corresponding bit in the filter. */
    768   1.1  drochner 		af[crc >> 4] |= 1 << (crc & 0xf);
    769   1.1  drochner 
    770   1.1  drochner 		ETHER_NEXT_MULTI(step, enm);
    771   1.1  drochner 	}
    772   1.1  drochner 	ifp->if_flags &= ~IFF_ALLMULTI;
    773   1.1  drochner 	return;
    774   1.1  drochner 
    775   1.1  drochner allmulti:
    776   1.1  drochner 	ifp->if_flags |= IFF_ALLMULTI;
    777   1.1  drochner 	af[0] = af[1] = af[2] = af[3] = 0xffff;
    778   1.1  drochner }
    779   1.1  drochner 
    780   1.1  drochner /*
    781   1.1  drochner  * Routines for accessing the transmit and receive buffers.
    782   1.1  drochner  * The various CPU and adapter configurations supported by this
    783   1.1  drochner  * driver require three different access methods for buffers
    784   1.1  drochner  * and descriptors:
    785   1.1  drochner  *	(1) contig (contiguous data; no padding),
    786   1.1  drochner  *	(2) gap2 (two bytes of data followed by two bytes of padding),
    787   1.1  drochner  *	(3) gap16 (16 bytes of data followed by 16 bytes of padding).
    788   1.1  drochner  */
    789   1.1  drochner 
    790   1.1  drochner /*
    791   1.1  drochner  * contig: contiguous data with no padding.
    792   1.1  drochner  *
    793   1.1  drochner  * Buffers may have any alignment.
    794   1.1  drochner  */
    795   1.1  drochner 
    796   1.1  drochner void
    797   1.1  drochner lance_copytobuf_contig(sc, from, boff, len)
    798   1.1  drochner 	struct lance_softc *sc;
    799   1.1  drochner 	void *from;
    800   1.1  drochner 	int boff, len;
    801   1.1  drochner {
    802   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    803   1.1  drochner 
    804   1.1  drochner 	/*
    805   1.1  drochner 	 * Just call bcopy() to do the work.
    806   1.1  drochner 	 */
    807   1.1  drochner 	bcopy(from, buf + boff, len);
    808   1.1  drochner }
    809   1.1  drochner 
    810   1.1  drochner void
    811   1.1  drochner lance_copyfrombuf_contig(sc, to, boff, len)
    812   1.1  drochner 	struct lance_softc *sc;
    813   1.1  drochner 	void *to;
    814   1.1  drochner 	int boff, len;
    815   1.1  drochner {
    816   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    817   1.1  drochner 
    818   1.1  drochner 	/*
    819   1.1  drochner 	 * Just call bcopy() to do the work.
    820   1.1  drochner 	 */
    821   1.1  drochner 	bcopy(buf + boff, to, len);
    822   1.1  drochner }
    823   1.1  drochner 
    824   1.1  drochner void
    825   1.1  drochner lance_zerobuf_contig(sc, boff, len)
    826   1.1  drochner 	struct lance_softc *sc;
    827   1.1  drochner 	int boff, len;
    828   1.1  drochner {
    829   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    830   1.1  drochner 
    831   1.1  drochner 	/*
    832   1.1  drochner 	 * Just let bzero() do the work
    833   1.1  drochner 	 */
    834   1.1  drochner 	bzero(buf + boff, len);
    835   1.1  drochner }
    836   1.1  drochner 
    837   1.1  drochner #if 0
    838   1.1  drochner /*
    839   1.1  drochner  * Examples only; duplicate these and tweak (if necessary) in
    840   1.1  drochner  * machine-specific front-ends.
    841   1.1  drochner  */
    842   1.1  drochner 
    843   1.1  drochner /*
    844   1.1  drochner  * gap2: two bytes of data followed by two bytes of pad.
    845   1.1  drochner  *
    846   1.1  drochner  * Buffers must be 4-byte aligned.  The code doesn't worry about
    847   1.1  drochner  * doing an extra byte.
    848   1.1  drochner  */
    849   1.1  drochner 
    850   1.1  drochner void
    851   1.1  drochner lance_copytobuf_gap2(sc, fromv, boff, len)
    852   1.1  drochner 	struct lance_softc *sc;
    853   1.1  drochner 	void *fromv;
    854   1.1  drochner 	int boff;
    855  1.11  augustss 	int len;
    856   1.1  drochner {
    857   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    858  1.11  augustss 	caddr_t from = fromv;
    859  1.11  augustss 	volatile u_int16_t *bptr;
    860   1.1  drochner 
    861   1.1  drochner 	if (boff & 0x1) {
    862   1.1  drochner 		/* handle unaligned first byte */
    863   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    864   1.1  drochner 		*bptr = (*from++ << 8) | (*bptr & 0xff);
    865   1.1  drochner 		bptr += 2;
    866   1.1  drochner 		len--;
    867   1.1  drochner 	} else
    868   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    869   1.1  drochner 	while (len > 1) {
    870   1.1  drochner 		*bptr = (from[1] << 8) | (from[0] & 0xff);
    871   1.1  drochner 		bptr += 2;
    872   1.1  drochner 		from += 2;
    873   1.1  drochner 		len -= 2;
    874   1.1  drochner 	}
    875   1.1  drochner 	if (len == 1)
    876   1.1  drochner 		*bptr = (u_int16_t)*from;
    877   1.1  drochner }
    878   1.1  drochner 
    879   1.1  drochner void
    880   1.1  drochner lance_copyfrombuf_gap2(sc, tov, boff, len)
    881   1.1  drochner 	struct lance_softc *sc;
    882   1.1  drochner 	void *tov;
    883   1.1  drochner 	int boff, len;
    884   1.1  drochner {
    885   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    886  1.11  augustss 	caddr_t to = tov;
    887  1.11  augustss 	volatile u_int16_t *bptr;
    888  1.11  augustss 	u_int16_t tmp;
    889   1.1  drochner 
    890   1.1  drochner 	if (boff & 0x1) {
    891   1.1  drochner 		/* handle unaligned first byte */
    892   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    893   1.1  drochner 		*to++ = (*bptr >> 8) & 0xff;
    894   1.1  drochner 		bptr += 2;
    895   1.1  drochner 		len--;
    896   1.1  drochner 	} else
    897   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    898   1.1  drochner 	while (len > 1) {
    899   1.1  drochner 		tmp = *bptr;
    900   1.1  drochner 		*to++ = tmp & 0xff;
    901   1.1  drochner 		*to++ = (tmp >> 8) & 0xff;
    902   1.1  drochner 		bptr += 2;
    903   1.1  drochner 		len -= 2;
    904   1.1  drochner 	}
    905   1.1  drochner 	if (len == 1)
    906   1.1  drochner 		*to = *bptr & 0xff;
    907   1.1  drochner }
    908   1.1  drochner 
    909   1.1  drochner void
    910   1.1  drochner lance_zerobuf_gap2(sc, boff, len)
    911   1.1  drochner 	struct lance_softc *sc;
    912   1.1  drochner 	int boff, len;
    913   1.1  drochner {
    914   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    915  1.11  augustss 	volatile u_int16_t *bptr;
    916   1.1  drochner 
    917   1.1  drochner 	if ((unsigned)boff & 0x1) {
    918   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + (boff - 1);
    919   1.1  drochner 		*bptr &= 0xff;
    920   1.1  drochner 		bptr += 2;
    921   1.1  drochner 		len--;
    922   1.1  drochner 	} else
    923   1.1  drochner 		bptr = ((volatile u_int16_t *)buf) + boff;
    924   1.1  drochner 	while (len > 0) {
    925   1.1  drochner 		*bptr = 0;
    926   1.1  drochner 		bptr += 2;
    927   1.1  drochner 		len -= 2;
    928   1.1  drochner 	}
    929   1.1  drochner }
    930   1.1  drochner 
    931   1.1  drochner /*
    932   1.1  drochner  * gap16: 16 bytes of data followed by 16 bytes of pad.
    933   1.1  drochner  *
    934   1.1  drochner  * Buffers must be 32-byte aligned.
    935   1.1  drochner  */
    936   1.1  drochner 
    937   1.1  drochner void
    938   1.1  drochner lance_copytobuf_gap16(sc, fromv, boff, len)
    939   1.1  drochner 	struct lance_softc *sc;
    940   1.1  drochner 	void *fromv;
    941   1.1  drochner 	int boff;
    942  1.11  augustss 	int len;
    943   1.1  drochner {
    944   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    945  1.11  augustss 	caddr_t from = fromv;
    946  1.11  augustss 	caddr_t bptr;
    947  1.11  augustss 	int xfer;
    948   1.1  drochner 
    949   1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    950   1.1  drochner 	boff &= 0xf;
    951   1.1  drochner 	xfer = min(len, 16 - boff);
    952   1.1  drochner 	while (len > 0) {
    953   1.1  drochner 		bcopy(from, bptr + boff, xfer);
    954   1.1  drochner 		from += xfer;
    955   1.1  drochner 		bptr += 32;
    956   1.1  drochner 		boff = 0;
    957   1.1  drochner 		len -= xfer;
    958   1.1  drochner 		xfer = min(len, 16);
    959   1.1  drochner 	}
    960   1.1  drochner }
    961   1.1  drochner 
    962   1.1  drochner void
    963   1.1  drochner lance_copyfrombuf_gap16(sc, tov, boff, len)
    964   1.1  drochner 	struct lance_softc *sc;
    965   1.1  drochner 	void *tov;
    966   1.1  drochner 	int boff, len;
    967   1.1  drochner {
    968   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    969  1.11  augustss 	caddr_t to = tov;
    970  1.11  augustss 	caddr_t bptr;
    971  1.11  augustss 	int xfer;
    972   1.1  drochner 
    973   1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    974   1.1  drochner 	boff &= 0xf;
    975   1.1  drochner 	xfer = min(len, 16 - boff);
    976   1.1  drochner 	while (len > 0) {
    977   1.1  drochner 		bcopy(bptr + boff, to, xfer);
    978   1.1  drochner 		to += xfer;
    979   1.1  drochner 		bptr += 32;
    980   1.1  drochner 		boff = 0;
    981   1.1  drochner 		len -= xfer;
    982   1.1  drochner 		xfer = min(len, 16);
    983   1.1  drochner 	}
    984   1.1  drochner }
    985   1.1  drochner 
    986   1.1  drochner void
    987   1.1  drochner lance_zerobuf_gap16(sc, boff, len)
    988   1.1  drochner 	struct lance_softc *sc;
    989   1.1  drochner 	int boff, len;
    990   1.1  drochner {
    991   1.1  drochner 	volatile caddr_t buf = sc->sc_mem;
    992  1.11  augustss 	caddr_t bptr;
    993  1.11  augustss 	int xfer;
    994   1.1  drochner 
    995   1.1  drochner 	bptr = buf + ((boff << 1) & ~0x1f);
    996   1.1  drochner 	boff &= 0xf;
    997   1.1  drochner 	xfer = min(len, 16 - boff);
    998   1.1  drochner 	while (len > 0) {
    999   1.1  drochner 		bzero(bptr + boff, xfer);
   1000   1.1  drochner 		bptr += 32;
   1001   1.1  drochner 		boff = 0;
   1002   1.1  drochner 		len -= xfer;
   1003   1.1  drochner 		xfer = min(len, 16);
   1004   1.1  drochner 	}
   1005   1.1  drochner }
   1006   1.1  drochner #endif /* Example only */
   1007