diff options
Diffstat (limited to 'sys/dev/isa')
-rw-r--r-- | sys/dev/isa/if_ed.c | 60 | ||||
-rw-r--r-- | sys/dev/isa/if_eg.c | 22 | ||||
-rw-r--r-- | sys/dev/isa/if_el.c | 20 | ||||
-rw-r--r-- | sys/dev/isa/if_fe.c | 16 | ||||
-rw-r--r-- | sys/dev/isa/if_ie.c | 20 | ||||
-rw-r--r-- | sys/dev/isa/if_iy.c | 1353 | ||||
-rw-r--r-- | sys/dev/isa/if_le.c | 463 | ||||
-rw-r--r-- | sys/dev/isa/if_le_isa.c | 367 | ||||
-rw-r--r-- | sys/dev/isa/if_levar.h | 41 |
9 files changed, 1795 insertions, 567 deletions
diff --git a/sys/dev/isa/if_ed.c b/sys/dev/isa/if_ed.c index 5435c1fcdc2..d520b509d41 100644 --- a/sys/dev/isa/if_ed.c +++ b/sys/dev/isa/if_ed.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_ed.c,v 1.14 1996/05/07 07:36:47 deraadt Exp $ */ -/* $NetBSD: if_ed.c,v 1.96 1996/05/03 19:05:30 christos Exp $ */ +/* $OpenBSD: if_ed.c,v 1.15 1996/05/10 12:41:16 deraadt Exp $ */ +/* $NetBSD: if_ed.c,v 1.98 1996/05/07 01:55:13 thorpej Exp $ */ /* * Device driver for National Semiconductor DS8390/WD83C690 based ethernet @@ -77,6 +77,7 @@ struct ed_softc { bus_chipset_tag_t sc_bc; /* bus identifier */ bus_io_handle_t sc_ioh; /* io handle */ + bus_io_handle_t sc_delayioh; /* io handle for `delay port' */ bus_mem_handle_t sc_memh; /* bus memory handle */ bus_io_size_t asic_base; /* offset of ASIC I/O port */ @@ -128,7 +129,7 @@ int ed_find_Novell __P((struct ed_softc *, struct cfdata *, int edintr __P((void *)); int edioctl __P((struct ifnet *, u_long, caddr_t)); void edstart __P((struct ifnet *)); -void edwatchdog __P((int)); +void edwatchdog __P((struct ifnet *)); void edreset __P((struct ed_softc *)); void edinit __P((struct ed_softc *)); void edstop __P((struct ed_softc *)); @@ -451,6 +452,7 @@ ed_find_WD80x3(sc, cf, ia) { bus_chipset_tag_t bc; bus_io_handle_t ioh; + bus_io_handle_t delayioh = ia->ia_delayioh; bus_mem_handle_t memh; u_int memsize; u_char iptr, isa16bit, sum; @@ -537,7 +539,8 @@ ed_find_WD80x3(sc, cf, ia) isa16bit = 1; break; case ED_TYPE_WD8013EP: /* also WD8003EP */ - if (inb(asicbase + ED_WD_ICR) & ED_WD_ICR_16BIT) { + if (bus_io_read_1(bc, ioh, asicbase + ED_WD_ICR) + & ED_WD_ICR_16BIT) { isa16bit = 1; memsize = 16384; sc->type_str = "WD8013EP"; @@ -788,8 +791,8 @@ ed_find_WD80x3(sc, cf, ia) bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, delayioh, 0); + (void) bus_io_read_1(bc, delayioh, 0); /* Now zero memory and verify that it is clear. */ for (i = 0; i < memsize; ++i) @@ -807,8 +810,8 @@ ed_find_WD80x3(sc, cf, ia) if (isa16bit) bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, delayioh, 0); + (void) bus_io_read_1(bc, delayioh, 0); goto out; } @@ -824,8 +827,8 @@ ed_find_WD80x3(sc, cf, ia) if (isa16bit) bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, delayioh, 0); + (void) bus_io_read_1(bc, delayioh, 0); ia->ia_iosize = ED_WD_IO_PORTS; rv = 1; @@ -1399,13 +1402,14 @@ edattach(parent, self, aux) ioh = sc->sc_ioh; /* XXX */ asicbase = sc->asic_base; + sc->sc_delayioh = ia->ia_delayioh; /* Set interface to stopped condition (reset). */ edstop(sc); /* Initialize ifnet structure. */ - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = ed_cd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = edstart; ifp->if_ioctl = edioctl; ifp->if_watchdog = edwatchdog; @@ -1518,10 +1522,10 @@ edstop(sc) * an interrupt after a transmit has been started on it. */ void -edwatchdog(unit) - int unit; +edwatchdog(ifp) + struct ifnet *ifp; { - struct ed_softc *sc = ed_cd.cd_devs[unit]; + struct ed_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -1735,7 +1739,7 @@ void edstart(ifp) struct ifnet *ifp; { - struct ed_softc *sc = ed_cd.cd_devs[ifp->if_unit]; + struct ed_softc *sc = ifp->if_softc; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; struct mbuf *m0, *m; @@ -1796,8 +1800,8 @@ outloop: sc->wd_laar_proto | ED_WD_LAAR_M16EN); bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, sc->sc_delayioh, 0); + (void) bus_io_read_1(bc, sc->sc_delayioh, 0); break; } @@ -1822,8 +1826,8 @@ outloop: if (sc->isa16bit) bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); /* XXX */ + (void) bus_io_read_1(bc, sc->sc_delayioh, 0); + (void) bus_io_read_1(bc, sc->sc_delayioh, 0); break; } } else @@ -2118,9 +2122,10 @@ edintr(arg) bus_io_write_1(bc, ioh, asicbase + ED_WD_MSR, sc->wd_msr_proto | ED_WD_MSR_MENB); - /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); - (void) bus_io_read_1(bc, ioh, 0x84); + (void) bus_io_read_1(bc, + sc->sc_delayioh, 0); + (void) bus_io_read_1(bc, + sc->sc_delayioh, 0); } ed_rint(sc); @@ -2134,9 +2139,10 @@ edintr(arg) bus_io_write_1(bc, ioh, asicbase + ED_WD_LAAR, sc->wd_laar_proto); - /* XXX */ - (void) bus_io_read_1(bc, ioh, 0x84); - (void) bus_io_read_1(bc, ioh, 0x84); + (void) bus_io_read_1(bc, + sc->sc_delayioh, 0); + (void) bus_io_read_1(bc, + sc->sc_delayioh, 0); } } } @@ -2183,7 +2189,7 @@ edioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ed_softc *sc = ed_cd.cd_devs[ifp->if_unit]; + struct ed_softc *sc = ifp->if_softc; register struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; diff --git a/sys/dev/isa/if_eg.c b/sys/dev/isa/if_eg.c index c51baf8aaae..463bbb05457 100644 --- a/sys/dev/isa/if_eg.c +++ b/sys/dev/isa/if_eg.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_eg.c,v 1.24 1996/04/11 22:29:03 cgd Exp $ */ +/* $NetBSD: if_eg.c,v 1.25 1996/05/07 01:55:17 thorpej Exp $ */ /* * Copyright (c) 1993 Dean Huxley <dean@fsa.ca> @@ -125,7 +125,7 @@ void eginit __P((struct eg_softc *)); int egioctl __P((struct ifnet *, u_long, caddr_t)); void egrecv __P((struct eg_softc *)); void egstart __P((struct ifnet *)); -void egwatchdog __P((int)); +void egwatchdog __P((struct ifnet *)); void egreset __P((struct eg_softc *)); void egread __P((struct eg_softc *, caddr_t, int)); struct mbuf *egget __P((struct eg_softc *, caddr_t, int)); @@ -396,8 +396,8 @@ egattach(parent, self, aux) } /* Initialize ifnet structure. */ - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = eg_cd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = egstart; ifp->if_ioctl = egioctl; ifp->if_watchdog = egwatchdog; @@ -475,8 +475,8 @@ egrecv(sc) sc->eg_pcb[3] = 0; sc->eg_pcb[4] = 0; sc->eg_pcb[5] = 0; - sc->eg_pcb[6] = EG_BUFLEN; /* our buffer size */ - sc->eg_pcb[7] = EG_BUFLEN >> 8; + sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */ + sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff; sc->eg_pcb[8] = 0; /* timeout, 0 == none */ sc->eg_pcb[9] = 0; if (egwritePCB(sc) != 0) @@ -489,7 +489,7 @@ void egstart(ifp) struct ifnet *ifp; { - register struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit]; + register struct eg_softc *sc = ifp->if_softc; struct mbuf *m0, *m; caddr_t buffer; int len; @@ -728,7 +728,7 @@ egioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit]; + struct eg_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; @@ -810,10 +810,10 @@ egreset(sc) } void -egwatchdog(unit) - int unit; +egwatchdog(ifp) + struct ifnet *ifp; { - struct eg_softc *sc = eg_cd.cd_devs[unit]; + struct eg_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); sc->sc_arpcom.ac_if.if_oerrors++; diff --git a/sys/dev/isa/if_el.c b/sys/dev/isa/if_el.c index 42213f55926..692b84108ff 100644 --- a/sys/dev/isa/if_el.c +++ b/sys/dev/isa/if_el.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_el.c,v 1.9 1996/05/07 07:36:53 deraadt Exp $ */ -/* $NetBSD: if_el.c,v 1.37 1996/04/29 20:03:17 christos Exp $ */ +/* $OpenBSD: if_el.c,v 1.10 1996/05/10 12:41:18 deraadt Exp $ */ +/* $NetBSD: if_el.c,v 1.38 1996/05/07 01:55:20 thorpej Exp $ */ /* * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted @@ -82,7 +82,7 @@ int elintr __P((void *)); void elinit __P((struct el_softc *)); int elioctl __P((struct ifnet *, u_long, caddr_t)); void elstart __P((struct ifnet *)); -void elwatchdog __P((int)); +void elwatchdog __P((struct ifnet *)); void elreset __P((struct el_softc *)); void elstop __P((struct el_softc *)); static int el_xmit __P((struct el_softc *)); @@ -184,8 +184,8 @@ elattach(parent, self, aux) elstop(sc); /* Initialize ifnet structure. */ - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = el_cd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = elstart; ifp->if_ioctl = elioctl; ifp->if_watchdog = elwatchdog; @@ -303,7 +303,7 @@ void elstart(ifp) struct ifnet *ifp; { - struct el_softc *sc = el_cd.cd_devs[ifp->if_unit]; + struct el_softc *sc = ifp->if_softc; int iobase = sc->sc_iobase; struct mbuf *m, *m0; int s, i, off, retries; @@ -615,7 +615,7 @@ elioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct el_softc *sc = el_cd.cd_devs[ifp->if_unit]; + struct el_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; int s, error = 0; @@ -682,10 +682,10 @@ elioctl(ifp, cmd, data) * Device timeout routine. */ void -elwatchdog(unit) - int unit; +elwatchdog(ifp) + struct ifnet *ifp; { - struct el_softc *sc = el_cd.cd_devs[unit]; + struct el_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); sc->sc_arpcom.ac_if.if_oerrors++; diff --git a/sys/dev/isa/if_fe.c b/sys/dev/isa/if_fe.c index baa3f87796c..7f1a21191fe 100644 --- a/sys/dev/isa/if_fe.c +++ b/sys/dev/isa/if_fe.c @@ -201,7 +201,7 @@ void fe_init __P((struct fe_softc *)); int fe_ioctl __P((struct ifnet *, u_long, caddr_t)); void fe_start __P((struct ifnet *)); void fe_reset __P((struct fe_softc *)); -void fe_watchdog __P((int)); +void fe_watchdog __P((struct ifnet *)); /* Local functions. Order of declaration is confused. FIXME. */ int fe_probe_fmv __P((struct fe_softc *, struct isa_attach_args *)); @@ -991,8 +991,8 @@ feattach(parent, self, aux) fe_stop(sc); /* Initialize ifnet structure. */ - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = fe_cd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = fe_start; ifp->if_ioctl = fe_ioctl; ifp->if_watchdog = fe_watchdog; @@ -1194,10 +1194,10 @@ fe_stop(sc) * generate an interrupt after a transmit has been started on it. */ void -fe_watchdog(unit) - int unit; +fe_watchdog(ifp) + struct ifnet *ifp; { - struct fe_softc *sc = fe_cd.cd_devs[unit]; + struct fe_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); #if FE_DEBUG >= 3 @@ -1419,7 +1419,7 @@ void fe_start(ifp) struct ifnet *ifp; { - struct fe_softc *sc = fe_cd.cd_devs[ifp->if_unit]; + struct fe_softc *sc = ifp->if_softc; struct mbuf *m; #if FE_DEBUG >= 1 @@ -1920,7 +1920,7 @@ fe_ioctl(ifp, command, data) u_long command; caddr_t data; { - struct fe_softc *sc = fe_cd.cd_devs[ifp->if_unit]; + struct fe_softc *sc = ifp->if_softc; register struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; diff --git a/sys/dev/isa/if_ie.c b/sys/dev/isa/if_ie.c index 8c2926131c8..77c99075c63 100644 --- a/sys/dev/isa/if_ie.c +++ b/sys/dev/isa/if_ie.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_ie.c,v 1.9 1996/05/07 07:36:59 deraadt Exp $ */ -/* $NetBSD: if_ie.c,v 1.49 1996/04/30 22:21:54 thorpej Exp $ */ +/* $OpenBSD: if_ie.c,v 1.10 1996/05/10 12:41:20 deraadt Exp $ */ +/* $NetBSD: if_ie.c,v 1.50 1996/05/07 01:55:25 thorpej Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -261,7 +261,7 @@ struct ie_softc { #endif }; -void iewatchdog __P((int)); +void iewatchdog __P((struct ifnet *)); int ieintr __P((void *)); void iestop __P((struct ie_softc *)); int ieinit __P((struct ie_softc *)); @@ -788,8 +788,8 @@ ieattach(parent, self, aux) struct isa_attach_args *ia = aux; struct ifnet *ifp = &sc->sc_arpcom.ac_if; - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = ie_cd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = iestart; ifp->if_ioctl = ieioctl; ifp->if_watchdog = iewatchdog; @@ -818,10 +818,10 @@ ieattach(parent, self, aux) * an interrupt after a transmit has been started on it. */ void -iewatchdog(unit) - int unit; +iewatchdog(ifp) + struct ifnet *ifp; { - struct ie_softc *sc = ie_cd.cd_devs[unit]; + struct ie_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -1473,7 +1473,7 @@ void iestart(ifp) struct ifnet *ifp; { - struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ifp->if_softc; struct mbuf *m0, *m; u_char *buffer; u_short len; @@ -2142,7 +2142,7 @@ ieioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; diff --git a/sys/dev/isa/if_iy.c b/sys/dev/isa/if_iy.c new file mode 100644 index 00000000000..2e8ee044b67 --- /dev/null +++ b/sys/dev/isa/if_iy.c @@ -0,0 +1,1353 @@ +/* $NetBSD: if_iy.c,v 1.2 1996/05/07 01:55:28 thorpej Exp $ */ +/* #define IYDEBUG */ +/* #define IYMEMDEBUG */ +/*- + * Copyright (c) 1996 Ignatios Souvatzis. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product contains software developed by Ignatios Souvatzis for + * the NetBSD project. + * 4. The names of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/buf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_dl.h> +#include <net/netisr.h> +#include <net/route.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + +#include <vm/vm.h> + +#include <machine/cpu.h> +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/ic/i82595reg.h> + +#define ETHER_MIN_LEN 64 +#define ETHER_MAX_LEN 1518 + +/* + * Ethernet status, per interface. + */ +struct iy_softc { + struct device sc_dev; + void *sc_ih; + + int sc_iobase; + struct arpcom sc_arpcom; + +#define MAX_MBS 8 + struct mbuf *mb[MAX_MBS]; + int next_mb, last_mb; + + int mappedirq; + + int hard_vers; + + int promisc; + + int sram, tx_size, rx_size; + + int tx_start, tx_end, tx_last; + int rx_start; + +#ifdef IYDEBUG + int sc_debug; +#endif +}; + +void iywatchdog __P((struct ifnet *)); +int iyioctl __P((struct ifnet *, u_long, caddr_t)); +int iyintr __P((void *)); +void iyinit __P((struct iy_softc *)); +void iystop __P((struct iy_softc *)); +void iystart __P((struct ifnet *)); + +void iy_intr_rx __P((struct iy_softc *)); +void iy_intr_tx __P((struct iy_softc *)); +void eepro_reset_595 __P((struct iy_softc *)); +int eepro_probe __P((struct iy_softc *, struct isa_attach_args *)); +void eepro_eeprom_outbits __P((struct iy_softc *, int, int)); +void eepro_eeprom_clock __P((struct iy_softc *, int)); +u_short eepro_read_eeprom __P((struct iy_softc *, int)); +int eepro_eeprom_inbits __P((struct iy_softc *)); + +void iyreset __P((struct iy_softc *)); +void iy_readframe __P((struct iy_softc *, int)); +void iy_drop_packet_buffer __P((struct iy_softc *)); +void iy_find_mem_size __P((struct iy_softc *)); +void iyrint __P((struct iy_softc *)); +void iytint __P((struct iy_softc *)); +void iyxmit __P((struct iy_softc *)); +void iyget __P((struct iy_softc *, int, int)); +void iymbuffill __P((void *)); +void iymbufempty __P((void *)); +void iyprobemem __P((struct iy_softc *)); + +/* + * void iymeminit __P((void *, struct iy_softc *)); + * static int iy_mc_setup __P((struct iy_softc *, void *)); + * static void iy_mc_reset __P((struct iy_softc *)); + */ +#ifdef IYDEBUGX +void print_rbd __P((volatile struct iy_recv_buf_desc *)); + +int in_ifrint = 0; +int in_iftint = 0; +#endif + +int iyprobe __P((struct device *, void *, void *)); +void iyattach __P((struct device *, struct device *, void *)); + +static u_int16_t eepromread __P((int, int)); + +struct cfattach iy_ca = { + sizeof(struct iy_softc), iyprobe, iyattach +}; + +struct cfdriver iy_cd = { + NULL, "iy", DV_IFNET +}; + +static u_int8_t eepro_irqmap[] = EEPP_INTMAP; +static u_int8_t eepro_revirqmap[] = EEPP_RINTMAP; + +int +iyprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct iy_softc *sc = match; + struct isa_attach_args *ia = aux; + + u_int16_t eaddr[8]; + int iobase; + int i; + + u_int16_t checksum = 0; + u_int16_t eepromtmp; + u_int8_t c, d; + + + iobase = ia->ia_iobase; + + if (iobase == -1) + return 0; + + /* try to find the round robin sig: */ + + /* check here for addresses already given to other devices */ + + c = inb(iobase + ID_REG); + if (c & ID_REG_MASK != ID_REG_SIG) + return 0; + + d = inb(iobase + ID_REG); + if (d & ID_REG_MASK != ID_REG_SIG) + return 0; + + if (((d-c) & R_ROBIN_BITS) != 0x40) + return 0; + + d = inb(iobase + ID_REG); + if (d & ID_REG_MASK != ID_REG_SIG) + return 0; + + if (((d-c) & R_ROBIN_BITS) != 0x80) + return 0; + + d = inb(iobase + ID_REG); + if (d & ID_REG_MASK != ID_REG_SIG) + return 0; + + if (((d-c) & R_ROBIN_BITS) != 0xC0) + return 0; + + d = inb(iobase + ID_REG); + if (d & ID_REG_MASK != ID_REG_SIG) + return 0; + + if (((d-c) & R_ROBIN_BITS) != 0x00) + return 0; + +#ifdef IYDEBUG + printf("eepro_probe verified working ID reg.\n"); +#endif + + for (i=0; i<64; ++i) { + eepromtmp = eepromread(iobase, i); + checksum += eepromtmp; + if (i<(sizeof(eaddr)/sizeof(*eaddr))) + eaddr[i] = eepromtmp; + } + if (checksum != EEPP_CHKSUM) + printf("wrong EEPROM checksum 0x%x should be 0x%x\n", + checksum, EEPP_CHKSUM); + + + if ((eaddr[EEPPEther0] != eepromread(iobase, EEPPEther0a)) && + (eaddr[EEPPEther1] != eepromread(iobase, EEPPEther1a)) && + (eaddr[EEPPEther2] != eepromread(iobase, EEPPEther2a))) + printf("EEPROM Ethernet address differs from copy\n"); + + sc->sc_arpcom.ac_enaddr[1] = eaddr[EEPPEther0] & 0xFF; + sc->sc_arpcom.ac_enaddr[0] = eaddr[EEPPEther0] >> 8; + sc->sc_arpcom.ac_enaddr[3] = eaddr[EEPPEther1] & 0xFF; + sc->sc_arpcom.ac_enaddr[2] = eaddr[EEPPEther1] >> 8; + sc->sc_arpcom.ac_enaddr[5] = eaddr[EEPPEther2] & 0xFF; + sc->sc_arpcom.ac_enaddr[4] = eaddr[EEPPEther2] >> 8; + + if (ia->ia_irq == IRQUNK) + ia->ia_irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int]; + + if (ia->ia_irq >= sizeof(eepro_revirqmap)) + return 0; + + if ((sc->mappedirq = eepro_revirqmap[ia->ia_irq]) == -1) + return 0; + + sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev; + + /* now lets reset the chip */ + + outb(iobase + COMMAND_REG, RESET_CMD); + delay(200); + + ia->ia_iobase = iobase; + ia->ia_iosize = 16; + return 1; /* found */ +} + +void +iyattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct iy_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_start = iystart; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + /* XXX todo: | IFF_MULTICAST */ + sc->sc_iobase = ia->ia_iobase; + + iyprobemem(sc); + + ifp->if_ioctl = iyioctl; + ifp->if_watchdog = iywatchdog; + + /* Attach the interface. */ + if_attach(ifp); + ether_ifattach(ifp); + printf(": address %s, chip rev. %d, %d kB SRAM\n", + ether_sprintf(sc->sc_arpcom.ac_enaddr), + sc->hard_vers, sc->sram/1024); +#if NBPFILTER > 0 + bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB, + sizeof(struct ether_header)); +#endif + + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, iyintr, sc); +} + +void +iystop(sc) +struct iy_softc *sc; +{ + int iobase; +#ifdef IYDEBUG + u_int p, v; +#endif + + iobase = sc->sc_iobase; + + outb(iobase + COMMAND_REG, RCV_DISABLE_CMD); + + outb(iobase + INT_MASK_REG, ALL_INTS); + outb(iobase + STATUS_REG, ALL_INTS); + + outb(iobase + COMMAND_REG, RESET_CMD); + delay(200); +#ifdef IYDEBUG + printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n", + sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last); + p = sc->tx_last; + if (!p) + p = sc->tx_start; + do { + outw(iobase + HOST_ADDR_REG, p); + v = inw(iobase + MEM_PORT_REG); + printf("0x%04x: %b ", p, v, "\020\006Ab\010Dn"); + v = inw(iobase + MEM_PORT_REG); + printf("0x%b", v, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL"); + p = inw(iobase + MEM_PORT_REG); + printf(" 0x%04x", p); + v = inw(iobase + MEM_PORT_REG); + printf(" 0x%b\n", v, "\020\020Ch"); + + } while (v & 0x8000); +#endif + sc->tx_start = sc->tx_end = sc->rx_size; + sc->tx_last = 0; + sc->sc_arpcom.ac_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + + iymbufempty((void *)sc); +} + +void +iyreset(sc) +struct iy_softc *sc; +{ + int s; + s = splimp(); + iystop(sc); + iyinit(sc); + splx(s); +} + +void +iyinit(sc) +struct iy_softc *sc; +{ + int i; + unsigned temp; + struct ifnet *ifp; + int iobase; + + ifp = &sc->sc_arpcom.ac_if; +#ifdef IYDEBUG + printf("ifp is %p\n", ifp); +#endif + iobase = sc->sc_iobase; + + outb(iobase, BANK_SEL(2)); + + temp = inb(iobase + EEPROM_REG); + if (temp & 0x10) + outb(iobase + EEPROM_REG, temp & ~0x10); + + for (i=0; i<6; ++i) { + outb(iobase + I_ADD(i), sc->sc_arpcom.ac_enaddr[i]); + } + + temp = inb(iobase + REG1); + outb(iobase + REG1, temp | XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | + RCV_DISCARD_BAD); + + temp = inb(iobase + RECV_MODES_REG); + outb(iobase + RECV_MODES_REG, temp | MATCH_BRDCST); +#ifdef IYDEBUG + printf("%s: RECV_MODES were %b set to %b\n", + sc->sc_dev.dv_xname, + temp, "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA", + temp|MATCH_BRDCST, + "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA"); +#endif + + + DELAY(500000); /* for the hardware to test for the connector */ + + temp = inb(iobase + MEDIA_SELECT); +#ifdef IYDEBUG + printf("%s: media select was 0x%b", sc->sc_dev.dv_xname, + temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC"); +#endif + temp = (temp & TEST_MODE_MASK) /* | BNC_BIT XXX*/; + outb(iobase + MEDIA_SELECT, temp); +#ifdef IYDEBUG + printf("changed to 0x%b\n", + temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC"); +#endif + + outb(iobase, BANK_SEL(1)); + + temp = inb(iobase + INT_NO_REG); + outb(iobase + INT_NO_REG, (temp & 0xf8) | sc->mappedirq); + +#ifdef IYDEBUG + printf("%s: int no was %b\n", sc->sc_dev.dv_xname, + temp, "\020\4bad_irq\010flash/boot present"); + temp = inb(iobase + INT_NO_REG); + printf("%s: int no now 0x%02x\n", sc->sc_dev.dv_xname, + temp, "\020\4BAD IRQ\010flash/boot present"); +#endif + + + outb(iobase + RCV_LOWER_LIMIT_REG, 0); + outb(iobase + RCV_UPPER_LIMIT_REG, (sc->rx_size - 2) >> 8); + outb(iobase + XMT_LOWER_LIMIT_REG, sc->rx_size >> 8); + outb(iobase + XMT_UPPER_LIMIT_REG, sc->sram >> 8); + + temp = inb(iobase + REG1); +#ifdef IYDEBUG + printf("%s: HW access is %b\n", sc->sc_dev.dv_xname, + temp, "\020\2WORD_WIDTH\010INT_ENABLE"); +#endif + outb(iobase + REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */ + +#ifdef IYDEBUG + temp = inb(iobase + REG1); + printf("%s: HW access is %b\n", sc->sc_dev.dv_xname, + temp, "\020\2WORD_WIDTH\010INT_ENABLE"); +#endif + + outb(iobase, BANK_SEL(0)); + + outb(iobase + INT_MASK_REG, ALL_INTS & ~(RX_BIT|TX_BIT)); + outb(iobase + STATUS_REG, ALL_INTS); /* clear ints */ + + outw(iobase + RCV_START_LOW, 0); + outw(iobase + RCV_STOP_LOW, sc->rx_size - 2); + sc->rx_start = 0; + + outb(iobase, SEL_RESET_CMD); + DELAY(200); + + outw(iobase + XMT_ADDR_REG, sc->rx_size); + + sc->tx_start = sc->tx_end = sc->rx_size; + sc->tx_last = 0; + + outb(iobase, RCV_ENABLE_CMD); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; +} + +void +iystart(ifp) +struct ifnet *ifp; +{ + struct iy_softc *sc; + int iobase; + + struct mbuf *m0, *m; + u_int len, pad, last, end; + u_int llen, residual; + int avail; + caddr_t data; + u_int16_t resval, stat; + +#ifdef IYDEBUG + printf("iystart called\n"); +#endif + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + + sc = ifp->if_softc; + iobase = sc->sc_iobase; + + while ((m0 = ifp->if_snd.ifq_head) != NULL) { +#ifdef IYDEBUG + printf("%s: trying to write another packet to the hardware\n", + sc->sc_dev.dv_xname); +#endif + + /* We need to use m->m_pkthdr.len, so require the header */ + if ((m0->m_flags & M_PKTHDR) == 0) + panic("iystart: no header mbuf"); + + len = m0->m_pkthdr.len; + pad = len & 1; + +#ifdef IYDEBUG + printf("%s: length is %d.\n", sc->sc_dev.dv_xname, len); +#endif + if (len < ETHER_MIN_LEN) { + pad = ETHER_MIN_LEN - len; + } + + if (len + pad > ETHER_MAX_LEN) { + /* packet is obviously too large: toss it */ + ++ifp->if_oerrors; + IF_DEQUEUE(&ifp->if_snd, m0); + m_freem(m0); + continue; + } + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0); +#endif + + avail = sc->tx_start - sc->tx_end; + if (avail <= 0) + avail += sc->tx_size; + +#ifdef IYDEBUG + printf("%s: avail is %d.\n", sc->sc_dev.dv_xname, avail); +#endif + /* + * we MUST RUN at splnet here --- + * XXX todo: or even turn off the boards ints ??? hm... + */ + + /* See if there is room to put another packet in the buffer. */ + + if ((len+pad+2*I595_XMT_HDRLEN) > avail) { + printf("%s: len = %d, avail = %d, setting OACTIVE\n", + sc->sc_dev.dv_xname, len, avail); + ifp->if_flags |= IFF_OACTIVE; + return; + } + + /* we know it fits in the hardware now, so dequeue it */ + IF_DEQUEUE(&ifp->if_snd, m0); + + last = sc->tx_end; + end = last + pad + len + I595_XMT_HDRLEN; + + if (end >= sc->sram) { + if ((sc->sram - last) <= I595_XMT_HDRLEN) { + /* keep header in one piece */ + last = sc->rx_size; + end = last + pad + len + I595_XMT_HDRLEN; + } else + end -= sc->tx_size; + } + + outw(iobase + HOST_ADDR_REG, last); + outw(iobase + MEM_PORT_REG, XMT_CMD); + outw(iobase + MEM_PORT_REG, 0); + outw(iobase + MEM_PORT_REG, 0); + outw(iobase + MEM_PORT_REG, len + pad); + + residual = resval = 0; + + while ((m = m0)!=0) { + data = mtod(m, caddr_t); + llen = m->m_len; + if (residual) { +#ifdef IYDEBUG + printf("%s: merging residual with next mbuf.\n", + sc->sc_dev.dv_xname); +#endif + resval |= *data << 8; + outw(iobase + MEM_PORT_REG, resval); + --llen; + ++data; + } + if (llen > 1) + outsw(iobase + MEM_PORT_REG, data, llen>>1); + residual = llen & 1; + if (residual) { + resval = *(data + llen - 1); +#ifdef IYDEBUG + printf("%s: got odd mbuf to send.\n", + sc->sc_dev.dv_xname); +#endif + } + + MFREE(m, m0); + } + + if (residual) + outw(iobase + MEM_PORT_REG, resval); + + pad >>= 1; + while (pad-- > 0) + outw(iobase + MEM_PORT_REG, 0); + +#ifdef IYDEBUG + printf("%s: new last = 0x%x, end = 0x%x.\n", + sc->sc_dev.dv_xname, last, end); + printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n", + sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last); +#endif + + if (sc->tx_start != sc->tx_end) { + outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_COUNT); + stat = inw(iobase + MEM_PORT_REG); + + outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_CHAIN); + outw(iobase + MEM_PORT_REG, last); + outw(iobase + MEM_PORT_REG, stat | CHAIN); +#ifdef IYDEBUG + printf("%s: setting 0x%x to 0x%x\n", + sc->sc_dev.dv_xname, sc->tx_last + XMT_COUNT, + stat | CHAIN); +#endif + } + stat = inw(iobase + MEM_PORT_REG); /* dummy read */ + + /* XXX todo: enable ints here if disabled */ + + ++ifp->if_opackets; + + if (sc->tx_start == sc->tx_end) { + outw(iobase + XMT_ADDR_REG, last); + outb(iobase, XMT_CMD); + sc->tx_start = last; +#ifdef IYDEBUG + printf("%s: writing 0x%x to XAR and giving XCMD\n", + sc->sc_dev.dv_xname, last); +#endif + } else { + outb(iobase, RESUME_XMT_CMD); +#ifdef IYDEBUG + printf("%s: giving RESUME_XCMD\n", + sc->sc_dev.dv_xname); +#endif + } + sc->tx_last = last; + sc->tx_end = end; + } +} + + +static __inline void +eepromwritebit(eio, what) + int eio, what; +{ + outb(eio, what); + delay(1); + outb(eio, what|EESK); + delay(1); + outb(eio, what); + delay(1); +} + +static __inline int +eepromreadbit(eio) + int eio; +{ + int b; + + outb(eio, EECS|EESK); + delay(1); + b = inb(eio); + outb(eio, EECS); + delay(1); + + return ((b & EEDO) != 0); +} + +static u_int16_t +eepromread(io, offset) + int io, offset; +{ + volatile int i; + volatile int j; + volatile u_int16_t readval; + int eio = io+EEPROM_REG; + + outb(io, BANK_SEL(2)); + delay(1); + outb(io, EECS); + delay(1); + + eepromwritebit(eio, EECS|EEDI); + eepromwritebit(eio, EECS|EEDI); + eepromwritebit(eio, EECS); + + for (j=5; j>=0; --j) { + if ((offset>>j) & 1) + eepromwritebit(eio, EECS|EEDI); + else + eepromwritebit(eio, EECS); + } + + for (readval=0, i=0; i<16; ++i) { + readval<<=1; + readval |= eepromreadbit(eio); + } + + outb(eio, 0|EESK); + delay(1); + outb(eio, 0); + + outb(eio, BANK_SEL(0)); + + return readval; +} + +/* + * Device timeout/watchdog routine. Entered if the device neglects to generate + * an interrupt after a transmit has been started on it. + */ +void +iywatchdog(ifp) + struct ifnet *ifp +{ + struct iy_softc *sc = ifp->if_softc; + + log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); + ++sc->sc_arpcom.ac_if.if_oerrors; + iyreset(sc); +} + +/* + * What to do upon receipt of an interrupt. + */ +int +iyintr(arg) + void *arg; +{ + struct iy_softc *sc = arg; + int iobase; + register u_short status; + + iobase = sc->sc_iobase; + status = inb(iobase + STATUS_REG); +#ifdef IYDEBUG + if (status & ALL_INTS) { + printf("%s: got interupt %b", sc->sc_dev.dv_xname, status, + "\020\1RX_STP\2RX\3TX\4EXEC"); + if (status & EXEC_INT) + printf(" event %b\n", inb(iobase), + "\020\6ABORT"); + else + printf("\n"); + } +#endif + if ((status & (RX_INT | TX_INT) == 0)) + return 0; + + if (status & RX_INT) { + iy_intr_rx(sc); + outb(iobase + STATUS_REG, RX_INT); + } else if (status & TX_INT) { + iy_intr_tx(sc); + outb(iobase + STATUS_REG, TX_INT); + } + return 1; +} + +void +iyget(sc, iobase, rxlen) +struct iy_softc *sc; +int iobase, rxlen; +{ + struct mbuf *m, *top, **mp; + struct ether_header *eh; + struct ifnet *ifp; + int len; + + ifp = &sc->sc_arpcom.ac_if; + + m = sc->mb[sc->next_mb]; + sc->mb[sc->next_mb] = 0; + if (m == 0) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + goto dropped; + } else { + if (sc->last_mb == sc->next_mb) + timeout(iymbuffill, sc, 1); + sc->next_mb = (sc->next_mb + 1) % MAX_MBS; + m->m_data = m->m_pktdat; + m->m_flags = M_PKTHDR; + } + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = rxlen; + len = MHLEN; + top = 0; + mp = ⊤ + + while (rxlen > 0) { + if (top) { + m = sc->mb[sc->next_mb]; + sc->mb[sc->next_mb] = 0; + if (m == 0) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + goto dropped; + } + } else { + sc->next_mb = (sc->next_mb + 1) % MAX_MBS; + } + len = MLEN; + } + if (rxlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + len = MCLBYTES; + } + len = min(rxlen, len); + if (len > 1) { + len &= ~1; + insw(iobase + MEM_PORT_REG, mtod(m, caddr_t), len/2); + } else { +#ifdef IYDEBUG + printf("%s: received odd mbuf\n", sc->sc_dev.dv_xname); +#endif + *(mtod(m, caddr_t)) = inw(iobase + MEM_PORT_REG); + } + m->m_len = len; + rxlen -= len; + *mp = m; + mp = &m->m_next; + } + /* XXX receive the top here */ + ++ifp->if_ipackets; + + eh = mtod(top, struct ether_header *); + +#if NBPFILTER > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp->if_bpf, top); + if ((ifp->if_flags & IFF_PROMISC) && + (eh->ether_dhost[0] & 1) == 0 && + bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0) { + m_freem(top); + return; + } + } +#endif + m_adj(top, sizeof(struct ether_header)); + ether_input(ifp, eh, top); + return; + +dropped: + ++ifp->if_ierrors; + return; +} +void +iy_intr_rx(sc) +struct iy_softc *sc; +{ + struct ifnet *ifp; + int iobase; + u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen; + + iobase = sc->sc_iobase; + ifp = &sc->sc_arpcom.ac_if; + + rxadrs = sc->rx_start; + outw(iobase + HOST_ADDR_REG, rxadrs); + rxevnt = inw(iobase + MEM_PORT_REG); + rxnext = 0; + + while (rxevnt == RCV_DONE) { + rxstatus = inw(iobase + MEM_PORT_REG); + rxnext = inw(iobase + MEM_PORT_REG); + rxlen = inw(iobase + MEM_PORT_REG); +#ifdef IYDEBUG + printf("%s: pck at 0x%04x stat %b next 0x%x len 0x%x\n", + sc->sc_dev.dv_xname, rxadrs, rxstatus, + "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR" + "\014CRCERR\015LENERR\016RCVOK\020TYP", + rxnext, rxlen); +#endif + iyget(sc, iobase, rxlen); + + /* move stop address */ + outw(iobase + RCV_STOP_LOW, + rxnext == 0 ? sc->rx_size - 2 : rxnext - 2); + + outw(iobase + HOST_ADDR_REG, rxnext); + rxadrs = rxnext; + rxevnt = inw(iobase + MEM_PORT_REG); + } + sc->rx_start = rxnext; +} + +void +iy_intr_tx(sc) +struct iy_softc *sc; +{ + int iobase; + struct ifnet *ifp; + u_int txstatus, txstat2, txlen, txnext; + + ifp = &sc->sc_arpcom.ac_if; + iobase = sc->sc_iobase; + + while (sc->tx_start != sc->tx_end) { + outw(iobase + HOST_ADDR_REG, sc->tx_start); + txstatus = inw(iobase + MEM_PORT_REG); + if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD)) + break; + + txstat2 = inw(iobase + MEM_PORT_REG); + txnext = inw(iobase + MEM_PORT_REG); + txlen = inw(iobase + MEM_PORT_REG); +#ifdef IYDEBUG + printf("txstat 0x%x stat2 0x%b next 0x%x len 0x%x\n", + txstatus, txstat2, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF" + "\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL", + txnext, txlen); +#endif + if (txlen & CHAIN) + sc->tx_start = txnext; + else + sc->tx_start = sc->tx_end; + ifp->if_flags &= ~IFF_OACTIVE; + + if ((txstat2 & 0x2000) == 0) + ++ifp->if_oerrors; + if (txstat2 & 0x000f) + ifp->if_oerrors += txstat2 & 0x000f; + } + ifp->if_flags &= ~IFF_OACTIVE; +} + +#if 0 +/* + * Compare two Ether/802 addresses for equality, inlined and unrolled for + * speed. I'd love to have an inline assembler version of this... + */ +static inline int +ether_equal(one, two) + u_char *one, *two; +{ + + if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] || + one[3] != two[3] || one[4] != two[4] || one[5] != two[5]) + return 0; + return 1; +} + +/* + * Check for a valid address. to_bpf is filled in with one of the following: + * 0 -> BPF doesn't get this packet + * 1 -> BPF does get this packet + * 2 -> BPF does get this packet, but we don't + * Return value is true if the packet is for us, and false otherwise. + * + * This routine is a mess, but it's also critical that it be as fast + * as possible. It could be made cleaner if we can assume that the + * only client which will fiddle with IFF_PROMISC is BPF. This is + * probably a good assumption, but we do not make it here. (Yet.) + */ +static inline int +check_eh(sc, eh, to_bpf) + struct iy_softc *sc; + struct ether_header *eh; + int *to_bpf; +{ + int i; + + switch (sc->promisc) { + case IFF_ALLMULTI: + /* + * Receiving all multicasts, but no unicasts except those + * destined for us. + */ +#if NBPFILTER > 0 + *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0); /* BPF gets this packet if anybody cares */ +#endif + if (eh->ether_dhost[0] & 1) + return 1; + if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) + return 1; + return 0; + + case IFF_PROMISC: + /* + * Receiving all packets. These need to be passed on to BPF. + */ +#if NBPFILTER > 0 + *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0); +#endif + /* If for us, accept and hand up to BPF */ + if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) + return 1; + +#if NBPFILTER > 0 + if (*to_bpf) + *to_bpf = 2; /* we don't need to see it */ +#endif + + /* + * Not a multicast, so BPF wants to see it but we don't. + */ + if (!(eh->ether_dhost[0] & 1)) + return 1; + + /* + * If it's one of our multicast groups, accept it and pass it + * up. + */ + for (i = 0; i < sc->mcast_count; i++) { + if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) { +#if NBPFILTER > 0 + if (*to_bpf) + *to_bpf = 1; +#endif + return 1; + } + } + return 1; + + case IFF_ALLMULTI | IFF_PROMISC: + /* + * Acting as a multicast router, and BPF running at the same + * time. Whew! (Hope this is a fast machine...) + */ +#if NBPFILTER > 0 + *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0); +#endif + /* We want to see multicasts. */ + if (eh->ether_dhost[0] & 1) + return 1; + + /* We want to see our own packets */ + if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) + return 1; + + /* Anything else goes to BPF but nothing else. */ +#if NBPFILTER > 0 + if (*to_bpf) + *to_bpf = 2; +#endif + return 1; + + case 0: + /* + * Only accept unicast packets destined for us, or multicasts + * for groups that we belong to. For now, we assume that the + * '586 will only return packets that we asked it for. This + * isn't strictly true (it uses hashing for the multicast + * filter), but it will do in this case, and we want to get out + * of here as quickly as possible. + */ +#if NBPFILTER > 0 + *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0); +#endif + return 1; + } + +#ifdef DIAGNOSTIC + panic("check_eh: impossible"); +#endif +} +#endif + +int +iyioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct iy_softc *sc; + struct ifaddr *ifa; + struct ifreq *ifr; + int s, error = 0; + + sc = ifp->if_softc; + ifa = (struct ifaddr *)data; + ifr = (struct ifreq *)data; + +#ifdef IYDEBUG + printf("iyioctl called with ifp 0x%p (%s) cmd 0x%x data 0x%p\n", + ifp, ifp->if_xname, cmd, data); +#endif + + s = splimp(); + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + iyinit(sc); + arp_ifinit(&sc->sc_arpcom, ifa); + break; +#endif +#ifdef NS + /* XXX - This code is probably wrong. */ + case AF_NS: + { + struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *)(sc->sc_arpcom.ac_enaddr); + else + bcopy(ina->x_host.c_host, + sc->sc_arpcom.ac_enaddr, + sizeof(sc->sc_arpcom.ac_enaddr)); + /* Set new address. */ + iyinit(sc); + break; + } +#endif /* NS */ + default: + iyinit(sc); + break; + } + break; + + case SIOCSIFFLAGS: + sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI); + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + /* + * If interface is marked down and it is running, then + * stop it. + */ + iystop(sc); + ifp->if_flags &= ~IFF_RUNNING; + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* + * If interface is marked up and it is stopped, then + * start it. + */ + iyinit(sc); + } else { + /* + * Reset the interface to pick up changes in any other + * flags that affect hardware registers. + */ + iystop(sc); + iyinit(sc); + } +#ifdef IYDEBUGX + if (ifp->if_flags & IFF_DEBUG) + sc->sc_debug = IFY_ALL; + else + sc->sc_debug = 0; +#endif + break; + +#if 0 /* XXX */ + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_arpcom): + ether_delmulti(ifr, &sc->sc_arpcom); + + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + iy_mc_reset(sc); /* XXX */ + error = 0; + } + break; +#endif + default: + error = EINVAL; + } + splx(s); + return error; +} + +#if 0 +static void +iy_mc_reset(sc) + struct iy_softc *sc; +{ + struct ether_multi *enm; + struct ether_multistep step; + + /* + * Step through the list of addresses. + */ + sc->mcast_count = 0; + ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm); + while (enm) { + if (sc->mcast_count >= MAXMCAST || + bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) { + sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI; + iyioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, (void *)0); + goto setflag; + } + + bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6); + sc->mcast_count++; + ETHER_NEXT_MULTI(step, enm); + } + setflag: + sc->want_mcsetup = 1; +} + +#ifdef IYDEBUG +void +print_rbd(rbd) + volatile struct ie_recv_buf_desc *rbd; +{ + + printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n" + "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual, + rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length, + rbd->mbz); +} +#endif +#endif + +void +iymbuffill(arg) + void *arg; +{ + struct iy_softc *sc = (struct iy_softc *)arg; + int s, i; + + s = splimp(); + i = sc->last_mb; + do { + if (sc->mb[i] == NULL) + MGET(sc->mb[i], M_DONTWAIT, MT_DATA); + if (sc->mb[i] == NULL) + break; + i = (i + 1) % MAX_MBS; + } while (i != sc->next_mb); + sc->last_mb = i; + /* If the queue was not filled, try again. */ + if (sc->last_mb != sc->next_mb) + timeout(iymbuffill, sc, 1); + splx(s); +} + + +void +iymbufempty(arg) + void *arg; +{ + struct iy_softc *sc = (struct iy_softc *)arg; + int s, i; + + s = splimp(); + for (i = 0; i<MAX_MBS; i++) { + if (sc->mb[i]) { + m_freem(sc->mb[i]); + sc->mb[i] = NULL; + } + } + sc->last_mb = sc->next_mb = 0; + untimeout(iymbuffill, sc); + splx(s); +} + +void +iyprobemem(sc) + struct iy_softc *sc; +{ + int iobase; + int testing; + + iobase = sc->sc_iobase; + + outw(iobase + HOST_ADDR_REG, 4096-2); + outw(iobase + MEM_PORT_REG, 0); + + for (testing=65536; testing >= 4096; testing >>= 1) { + outw(iobase + HOST_ADDR_REG, testing-2); + outw(iobase + MEM_PORT_REG, 0xdead); + outw(iobase + HOST_ADDR_REG, testing-2); + if (inw(iobase + MEM_PORT_REG) != 0xdead) { +#ifdef IYMEMDEBUG + printf("%s: Didn't keep 0xdead at 0x%x\n", + sc->sc_dev.dv_xname, testing-2); +#endif + continue; + } + + outw(iobase + HOST_ADDR_REG, testing-2); + outw(iobase + MEM_PORT_REG, 0xbeef); + outw(iobase + HOST_ADDR_REG, testing-2); + if (inw(iobase + MEM_PORT_REG) != 0xbeef) { +#ifdef IYMEMDEBUG + printf("%s: Didn't keep 0xbeef at 0x%x\n", + sc->sc_dev.dv_xname, testing-2); +#endif + continue; + } + + outw(iobase + HOST_ADDR_REG, 0); + outw(iobase + MEM_PORT_REG, 0); + outw(iobase + HOST_ADDR_REG, testing >> 1); + outw(iobase + MEM_PORT_REG, testing >> 1); + outw(iobase + HOST_ADDR_REG, 0); + if (inw(iobase + MEM_PORT_REG) == (testing >> 1)) { +#ifdef IYMEMDEBUG + printf("%s: 0x%x alias of 0x0\n", + sc->sc_dev.dv_xname, testing >> 1); +#endif + continue; + } + + break; + } + + sc->sram = testing; + + switch(testing) { + case 65536: + /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */ + sc->rx_size = 44*1024; + break; + + case 32768: + /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */ + sc->rx_size = 22*1024; + break; + + case 16384: + /* 1 NFS packet + overhead RX, 4 big packets TX */ + sc->rx_size = 10*1024; + break; + default: + sc->rx_size = testing/2; + break; + } + sc->tx_size = testing - sc->rx_size; +} diff --git a/sys/dev/isa/if_le.c b/sys/dev/isa/if_le.c index bc7a2e6070e..e69de29bb2d 100644 --- a/sys/dev/isa/if_le.c +++ b/sys/dev/isa/if_le.c @@ -1,463 +0,0 @@ -/* $OpenBSD: if_le.c,v 1.9 1996/05/02 13:51:53 deraadt Exp $ */ -/* $NetBSD: if_le.c,v 1.43 1996/04/22 02:53:28 christos Exp $ */ - -/*- - * Copyright (c) 1995 Charles M. Hannum. All rights reserved. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ralph Campbell and Rick Macklem. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)if_le.c 8.2 (Berkeley) 11/16/93 - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/syslog.h> -#include <sys/socket.h> -#include <sys/device.h> - -#include <net/if.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/if_ether.h> -#endif - -#include <vm/vm.h> - -#include <machine/cpu.h> -#include <machine/pio.h> - -#include "isa.h" -#include "pci.h" - -#if NISA > 0 -#include <dev/isa/isareg.h> -#include <dev/isa/isavar.h> -#include <dev/isa/isadmavar.h> -#include <i386/isa/isa_machdep.h> -#endif - -#if NPCI > 0 -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> -#endif - -#include <dev/isa/if_levar.h> -#include <dev/ic/am7990reg.h> -#define LE_NEED_BUF_CONTIG -#include <dev/ic/am7990var.h> - -char *card_type[] = {"unknown", "BICC Isolan", "NE2100", "DEPCA", "PCnet-ISA", "PCnet-PCI"}; - -#define LE_SOFTC(unit) le_cd.cd_devs[unit] -#define LE_DELAY(x) delay(x) - -int leprobe __P((struct device *, void *, void *)); -int depca_probe __P((struct le_softc *, struct isa_attach_args *)); -int ne2100_probe __P((struct le_softc *, struct isa_attach_args *)); -int bicc_probe __P((struct le_softc *, struct isa_attach_args *)); -int lance_probe __P((struct le_softc *)); -void leattach __P((struct device *, struct device *, void *)); -int leintr __P((void *)); -int leintredge __P((void *)); -void leshutdown __P((void *)); - -/* XXX the following two structs should be different. */ -struct cfattach le_isa_ca = { - sizeof(struct le_softc), leprobe, leattach -}; - -struct cfattach le_pci_ca = { - sizeof(struct le_softc), leprobe, leattach -}; - -struct cfdriver le_cd = { - NULL, "le", DV_IFNET -}; - -integrate void -lehwinit(sc) - struct le_softc *sc; -{ -} - -integrate void -lewrcsr(sc, port, val) - struct le_softc *sc; - u_int16_t port, val; -{ - - outw(sc->sc_rap, port); - outw(sc->sc_rdp, val); -} - -integrate u_int16_t -lerdcsr(sc, port) - struct le_softc *sc; - u_int16_t port; -{ - u_int16_t val; - - outw(sc->sc_rap, port); - val = inw(sc->sc_rdp); - return (val); -} - -int -leprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct le_softc *sc = match; - extern struct cfdriver isa_cd, pci_cd; - -#if NISA > 0 - if (parent->dv_cfdata->cf_driver == &isa_cd) { - struct isa_attach_args *ia = aux; - - if (bicc_probe(sc, ia)) - return (1); - if (ne2100_probe(sc, ia)) - return (1); - if (depca_probe(sc, ia)) - return (1); - } -#endif - -#if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pci_cd) { - struct pci_attach_args *pa = aux; - - if (pa->pa_id == 0x20001022) - return (1); - } -#endif - - return (0); -} - -#if NISA > 0 -int -depca_probe(sc, ia) - struct le_softc *sc; - struct isa_attach_args *ia; -{ - int iobase = ia->ia_iobase, port; - u_long sum, rom_sum; - u_char x; - int i; - - sc->sc_rap = iobase + DEPCA_RAP; - sc->sc_rdp = iobase + DEPCA_RDP; - sc->sc_card = DEPCA; - - if (lance_probe(sc) == 0) - return 0; - - outb(iobase + DEPCA_CSR, DEPCA_CSR_DUM); - - /* - * Extract the physical MAC address from the ROM. - * - * The address PROM is 32 bytes wide, and we access it through - * a single I/O port. On each read, it rotates to the next - * position. We find the ethernet address by looking for a - * particular sequence of bytes (0xff, 0x00, 0x55, 0xaa, 0xff, - * 0x00, 0x55, 0xaa), and then reading the next 8 bytes (the - * ethernet address and a checksum). - * - * It appears that the PROM can be at one of two locations, so - * we just try both. - */ - port = iobase + DEPCA_ADP; - for (i = 0; i < 32; i++) - if (inb(port) == 0xff && inb(port) == 0x00 && - inb(port) == 0x55 && inb(port) == 0xaa && - inb(port) == 0xff && inb(port) == 0x00 && - inb(port) == 0x55 && inb(port) == 0xaa) - goto found; - port = iobase + DEPCA_ADP + 1; - for (i = 0; i < 32; i++) - if (inb(port) == 0xff && inb(port) == 0x00 && - inb(port) == 0x55 && inb(port) == 0xaa && - inb(port) == 0xff && inb(port) == 0x00 && - inb(port) == 0x55 && inb(port) == 0xaa) - goto found; - printf("%s: address not found\n", sc->sc_dev.dv_xname); - return 0; - -found: - for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) - sc->sc_arpcom.ac_enaddr[i] = inb(port); - -#if 0 - sum = - (sc->sc_arpcom.ac_enaddr[0] << 2) + - (sc->sc_arpcom.ac_enaddr[1] << 10) + - (sc->sc_arpcom.ac_enaddr[2] << 1) + - (sc->sc_arpcom.ac_enaddr[3] << 9) + - (sc->sc_arpcom.ac_enaddr[4] << 0) + - (sc->sc_arpcom.ac_enaddr[5] << 8); - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - - rom_sum = inb(port); - rom_sum |= inb(port) << 8; - - if (sum != rom_sum) { - printf("%s: checksum mismatch; calculated %04x != read %04x", - sc->sc_dev.dv_xname, sum, rom_sum); - return 0; - } -#endif - - outb(iobase + DEPCA_CSR, DEPCA_CSR_NORMAL); - - ia->ia_iosize = 16; - ia->ia_drq = DRQUNK; - return 1; -} - -int -ne2100_probe(sc, ia) - struct le_softc *sc; - struct isa_attach_args *ia; -{ - int iobase = ia->ia_iobase; - int i; - - sc->sc_rap = iobase + NE2100_RAP; - sc->sc_rdp = iobase + NE2100_RDP; - sc->sc_card = NE2100; - - if (lance_probe(sc) == 0) - return 0; - - /* - * Extract the physical MAC address from the ROM. - */ - for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) - sc->sc_arpcom.ac_enaddr[i] = inb(iobase + i); - - ia->ia_iosize = 24; - return 1; -} - -int -bicc_probe(sc, ia) - struct le_softc *sc; - struct isa_attach_args *ia; -{ - int iobase = ia->ia_iobase; - int i; - - sc->sc_rap = iobase + BICC_RAP; - sc->sc_rdp = iobase + BICC_RDP; - sc->sc_card = BICC; - - if (lance_probe(sc) == 0) - return 0; - - /* - * Extract the physical MAC address from the ROM. - */ - for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) - sc->sc_arpcom.ac_enaddr[i] = inb(iobase + i * 2); - - ia->ia_iosize = 16; - return 1; -} - -/* - * Determine which chip is present on the card. - */ -int -lance_probe(sc) - struct le_softc *sc; -{ - - /* Stop the LANCE chip and put it in a known state. */ - lewrcsr(sc, LE_CSR0, LE_C0_STOP); - LE_DELAY(100); - - if (lerdcsr(sc, LE_CSR0) != LE_C0_STOP) - return 0; - - lewrcsr(sc, LE_CSR3, sc->sc_conf3); - return 1; -} -#endif - -void -leattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct le_softc *sc = (void *)self; - extern struct cfdriver isa_cd, pci_cd; - -#if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pci_cd) { - struct pci_attach_args *pa = aux; - int iobase; - - if (pa->pa_id == 0x20001022) { - int i; - - if (pci_map_io(pa->pa_tag, 0x10, &iobase)) - return; - - sc->sc_rap = iobase + NE2100_RAP; - sc->sc_rdp = iobase + NE2100_RDP; - sc->sc_card = PCnet_PCI; - - /* - * Extract the physical MAC address from the ROM. - */ - for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) - sc->sc_arpcom.ac_enaddr[i] = inb(iobase + i); - } - } -#endif - -#if NISA > 0 - if (sc->sc_card == DEPCA) { - struct isa_attach_args *ia = aux; - u_char *mem, val; - int i; - - mem = sc->sc_mem = ISA_HOLE_VADDR(ia->ia_maddr); - - val = 0xff; - for (;;) { - for (i = 0; i < ia->ia_msize; i++) - mem[i] = val; - for (i = 0; i < ia->ia_msize; i++) - if (mem[i] != val) { - printf("%s: failed to clear memory\n", - sc->sc_dev.dv_xname); - return; - } - if (val == 0x00) - break; - val -= 0x55; - } - - sc->sc_conf3 = LE_C3_ACON; - sc->sc_addr = 0; - sc->sc_memsize = ia->ia_msize; - } else -#endif - { - sc->sc_mem = malloc(16384, M_DEVBUF, M_NOWAIT); - if (sc->sc_mem == 0) { - printf("%s: couldn't allocate memory for card\n", - sc->sc_dev.dv_xname); - return; - } - - sc->sc_conf3 = 0; - sc->sc_addr = kvtop(sc->sc_mem); - sc->sc_memsize = 16384; - } - - sc->sc_copytodesc = am7990_copytobuf_contig; - sc->sc_copyfromdesc = am7990_copyfrombuf_contig; - sc->sc_copytobuf = am7990_copytobuf_contig; - sc->sc_copyfrombuf = am7990_copyfrombuf_contig; - sc->sc_zerobuf = am7990_zerobuf_contig; - - sc->sc_arpcom.ac_if.if_name = le_cd.cd_name; - leconfig(sc); - - printf("%s: type %s\n", sc->sc_dev.dv_xname, card_type[sc->sc_card]); - -#if NISA > 0 - if (parent->dv_cfdata->cf_driver == &isa_cd) { - struct isa_attach_args *ia = aux; - - if (ia->ia_drq != DRQUNK) - isa_dmacascade(ia->ia_drq); - - sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, - IPL_NET, leintredge, sc, sc->sc_dev.dv_xname); - } -#endif - -#if NPCI > 0 - if (parent->dv_cfdata->cf_driver == &pci_cd) { - struct pci_attach_args *pa = aux; - pcireg_t csr; - - csr = pci_conf_read(pa->pa_bc, pa->pa_tag, - PCI_COMMAND_STATUS_REG); - pci_conf_write(pa->pa_bc, pa->pa_tag, PCI_COMMAND_STATUS_REG, - csr | PCI_COMMAND_MASTER_ENABLE); - - sc->sc_ih = pci_map_int(pa->pa_tag, IPL_NET, leintr, sc); - } -#endif - - sc->sc_sh = shutdownhook_establish(leshutdown, sc); -} - -void -leshutdown(arg) - void *arg; -{ - struct le_softc *sc = arg; - - lestop(sc); -} - -#if NISA > 0 -/* - * Controller interrupt. - */ -leintredge(arg) - void *arg; -{ - - if (leintr(arg) == 0) - return (0); - for (;;) - if (leintr(arg) == 0) - return (1); -} -#endif - -#include <dev/ic/am7990.c> diff --git a/sys/dev/isa/if_le_isa.c b/sys/dev/isa/if_le_isa.c new file mode 100644 index 00000000000..44aaf16676a --- /dev/null +++ b/sys/dev/isa/if_le_isa.c @@ -0,0 +1,367 @@ +/* $NetBSD: if_le_isa.c,v 1.1 1996/05/07 01:50:05 thorpej Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 + */ + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/device.h> + +#include <net/if.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/if_ether.h> +#endif + +#include <vm/vm.h> + +#include <machine/cpu.h> +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <i386/isa/isa_machdep.h> + +#include <dev/ic/am7990reg.h> +#include <dev/ic/am7990var.h> + +#include <dev/isa/if_levar.h> + +static char *card_type[] = + { "unknown", "BICC Isolan", "NE2100", "DEPCA", "PCnet-ISA" }; + +int le_isa_probe __P((struct device *, void *, void *)); +void le_isa_attach __P((struct device *, struct device *, void *)); + +struct cfattach le_isa_ca = { + sizeof(struct le_softc), le_isa_probe, le_isa_attach +}; + +int depca_isa_probe __P((struct le_softc *, struct isa_attach_args *)); +int ne2100_isa_probe __P((struct le_softc *, struct isa_attach_args *)); +int bicc_isa_probe __P((struct le_softc *, struct isa_attach_args *)); +int lance_isa_probe __P((struct am7990_softc *)); + +int le_isa_intredge __P((void *)); + +hide void le_isa_wrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t)); +hide u_int16_t le_isa_rdcsr __P((struct am7990_softc *, u_int16_t)); + +hide void +le_isa_wrcsr(sc, port, val) + struct am7990_softc *sc; + u_int16_t port, val; +{ + + outw(((struct le_softc *)sc)->sc_rap, port); + outw(((struct le_softc *)sc)->sc_rdp, val); +} + +hide u_int16_t +le_isa_rdcsr(sc, port) + struct am7990_softc *sc; + u_int16_t port; +{ + u_int16_t val; + + outw(((struct le_softc *)sc)->sc_rap, port); + val = inw(((struct le_softc *)sc)->sc_rdp); + return (val); +} + +int +le_isa_probe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct le_softc *lesc = match; + struct isa_attach_args *ia = aux; + + if (bicc_isa_probe(lesc, ia)) + return (1); + if (ne2100_isa_probe(lesc, ia)) + return (1); + if (depca_isa_probe(lesc, ia)) + return (1); + + return (0); +} + +int +depca_isa_probe(lesc, ia) + struct le_softc *lesc; + struct isa_attach_args *ia; +{ + struct am7990_softc *sc = &lesc->sc_am7990; + int iobase = ia->ia_iobase, port; + u_long sum, rom_sum; + u_char x; + int i; + + lesc->sc_rap = iobase + DEPCA_RAP; + lesc->sc_rdp = iobase + DEPCA_RDP; + lesc->sc_card = DEPCA; + + if (lance_isa_probe(sc) == 0) + return 0; + + outb(iobase + DEPCA_CSR, DEPCA_CSR_DUM); + + /* + * Extract the physical MAC address from the ROM. + * + * The address PROM is 32 bytes wide, and we access it through + * a single I/O port. On each read, it rotates to the next + * position. We find the ethernet address by looking for a + * particular sequence of bytes (0xff, 0x00, 0x55, 0xaa, 0xff, + * 0x00, 0x55, 0xaa), and then reading the next 8 bytes (the + * ethernet address and a checksum). + * + * It appears that the PROM can be at one of two locations, so + * we just try both. + */ + port = iobase + DEPCA_ADP; + for (i = 0; i < 32; i++) + if (inb(port) == 0xff && inb(port) == 0x00 && + inb(port) == 0x55 && inb(port) == 0xaa && + inb(port) == 0xff && inb(port) == 0x00 && + inb(port) == 0x55 && inb(port) == 0xaa) + goto found; + port = iobase + DEPCA_ADP + 1; + for (i = 0; i < 32; i++) + if (inb(port) == 0xff && inb(port) == 0x00 && + inb(port) == 0x55 && inb(port) == 0xaa && + inb(port) == 0xff && inb(port) == 0x00 && + inb(port) == 0x55 && inb(port) == 0xaa) + goto found; + printf("%s: address not found\n", sc->sc_dev.dv_xname); + return 0; + +found: + for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) + sc->sc_arpcom.ac_enaddr[i] = inb(port); + +#if 0 + sum = + (sc->sc_arpcom.ac_enaddr[0] << 2) + + (sc->sc_arpcom.ac_enaddr[1] << 10) + + (sc->sc_arpcom.ac_enaddr[2] << 1) + + (sc->sc_arpcom.ac_enaddr[3] << 9) + + (sc->sc_arpcom.ac_enaddr[4] << 0) + + (sc->sc_arpcom.ac_enaddr[5] << 8); + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + rom_sum = inb(port); + rom_sum |= inb(port) << 8; + + if (sum != rom_sum) { + printf("%s: checksum mismatch; calculated %04x != read %04x", + sc->sc_dev.dv_xname, sum, rom_sum); + return 0; + } +#endif + + outb(iobase + DEPCA_CSR, DEPCA_CSR_NORMAL); + + ia->ia_iosize = 16; + ia->ia_drq = DRQUNK; + return 1; +} + +int +ne2100_isa_probe(lesc, ia) + struct le_softc *lesc; + struct isa_attach_args *ia; +{ + struct am7990_softc *sc = &lesc->sc_am7990; + int iobase = ia->ia_iobase; + int i; + + lesc->sc_rap = iobase + NE2100_RAP; + lesc->sc_rdp = iobase + NE2100_RDP; + lesc->sc_card = NE2100; + + if (lance_isa_probe(sc) == 0) + return 0; + + /* + * Extract the physical MAC address from the ROM. + */ + for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) + sc->sc_arpcom.ac_enaddr[i] = inb(iobase + i); + + ia->ia_iosize = 24; + return 1; +} + +int +bicc_isa_probe(lesc, ia) + struct le_softc *lesc; + struct isa_attach_args *ia; +{ + struct am7990_softc *sc = &lesc->sc_am7990; + int iobase = ia->ia_iobase; + int i; + + lesc->sc_rap = iobase + BICC_RAP; + lesc->sc_rdp = iobase + BICC_RDP; + lesc->sc_card = BICC; + + if (lance_isa_probe(sc) == 0) + return 0; + + /* + * Extract the physical MAC address from the ROM. + */ + for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) + sc->sc_arpcom.ac_enaddr[i] = inb(iobase + i * 2); + + ia->ia_iosize = 16; + return 1; +} + +/* + * Determine which chip is present on the card. + */ +int +lance_isa_probe(sc) + struct am7990_softc *sc; +{ + + /* Stop the LANCE chip and put it in a known state. */ + le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP); + delay(100); + + if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) + return 0; + + le_isa_wrcsr(sc, LE_CSR3, sc->sc_conf3); + return 1; +} + +void +le_isa_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct le_softc *lesc = (void *)self; + struct am7990_softc *sc = &lesc->sc_am7990; + struct isa_attach_args *ia = aux; + + printf(": %s Ethernet\n", sc->sc_dev.dv_xname, + card_type[lesc->sc_card]); + + if (lesc->sc_card == DEPCA) { + u_char *mem, val; + int i; + + mem = sc->sc_mem = ISA_HOLE_VADDR(ia->ia_maddr); + + val = 0xff; + for (;;) { + for (i = 0; i < ia->ia_msize; i++) + mem[i] = val; + for (i = 0; i < ia->ia_msize; i++) + if (mem[i] != val) { + printf("%s: failed to clear memory\n", + sc->sc_dev.dv_xname); + return; + } + if (val == 0x00) + break; + val -= 0x55; + } + + sc->sc_conf3 = LE_C3_ACON; + sc->sc_addr = 0; + sc->sc_memsize = ia->ia_msize; + } else { + sc->sc_mem = malloc(16384, M_DEVBUF, M_NOWAIT); + if (sc->sc_mem == 0) { + printf("%s: couldn't allocate memory for card\n", + sc->sc_dev.dv_xname); + return; + } + + sc->sc_conf3 = 0; + sc->sc_addr = kvtop(sc->sc_mem); + sc->sc_memsize = 16384; + } + + sc->sc_copytodesc = am7990_copytobuf_contig; + sc->sc_copyfromdesc = am7990_copyfrombuf_contig; + sc->sc_copytobuf = am7990_copytobuf_contig; + sc->sc_copyfrombuf = am7990_copyfrombuf_contig; + sc->sc_zerobuf = am7990_zerobuf_contig; + + sc->sc_rdcsr = le_isa_rdcsr; + sc->sc_wrcsr = le_isa_wrcsr; + sc->sc_hwinit = NULL; + + printf("%s", sc->sc_dev.dv_xname); + am7990_config(sc); + + if (ia->ia_drq != DRQUNK) + isa_dmacascade(ia->ia_drq); + + lesc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, le_isa_intredge, sc); +} + +/* + * Controller interrupt. + */ +le_isa_intredge(arg) + void *arg; +{ + + if (am7990_intr(arg) == 0) + return (0); + for (;;) + if (am7990_intr(arg) == 0) + return (1); +} diff --git a/sys/dev/isa/if_levar.h b/sys/dev/isa/if_levar.h index e28b35a0966..57c8c3f4ffa 100644 --- a/sys/dev/isa/if_levar.h +++ b/sys/dev/isa/if_levar.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_levar.h,v 1.4 1996/04/29 20:03:23 christos Exp $ */ +/* $NetBSD: if_levar.h,v 1.5 1996/05/07 01:50:07 thorpej Exp $ */ /* * LANCE Ethernet driver header file @@ -20,7 +20,6 @@ #define NE2100 2 #define PCnet_ISA 4 -#define PCnet_PCI 5 #define NE2100_RDP 0x10 #define NE2100_RAP 0x12 @@ -45,44 +44,10 @@ * This structure contains the output queue for the interface, its address, ... */ struct le_softc { - struct device sc_dev; /* base structure */ - struct arpcom sc_arpcom; /* Ethernet common part */ - - void (*sc_copytodesc) /* Copy to descriptor */ - __P((struct le_softc *, void *, int, int)); - void (*sc_copyfromdesc) /* Copy from descriptor */ - __P((struct le_softc *, void *, int, int)); - void (*sc_copytobuf) /* Copy to buffer */ - __P((struct le_softc *, void *, int, int)); - void (*sc_copyfrombuf) /* Copy from buffer */ - __P((struct le_softc *, void *, int, int)); - void (*sc_zerobuf) /* and Zero bytes in buffer */ - __P((struct le_softc *, int, int)); - - u_int16_t sc_conf3; /* CSR3 value */ - - void *sc_mem; /* base address of RAM -- CPU's view */ - u_long sc_addr; /* base address of RAM -- LANCE's view */ - u_long sc_memsize; /* size of RAM */ - - int sc_nrbuf; /* number of receive buffers */ - int sc_ntbuf; /* number of transmit buffers */ - int sc_last_rd; - int sc_first_td, sc_last_td, sc_no_td; - - int sc_initaddr; - int sc_rmdaddr; - int sc_tmdaddr; - int sc_rbufaddr; - int sc_tbufaddr; - -#ifdef LEDEBUG - int sc_debug; -#endif + struct am7990_softc sc_am7990; /* glue to MI code */ void *sc_ih; bus_io_handle_t sc_ioh; - void *sc_sh; int sc_card; - int sc_rap, sc_rdp; /* LANCE registers */ + int sc_rap, sc_rdp; /* offsets to LANCE registers */ }; |