1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-15 10:17:20 +00:00

Pre 3.0 branch cleanup casualty #3: 3c505 ethernet support

This commit is contained in:
Poul-Henning Kamp 1998-12-27 12:44:57 +00:00
parent 36b2d2c26c
commit e86310b905
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=42077
9 changed files with 7 additions and 979 deletions

View File

@ -1,8 +1,8 @@
# $Id: Makefile,v 1.88 1998/12/04 18:01:22 wpaul Exp $
# $Id: Makefile,v 1.89 1998/12/22 09:36:29 joerg Exp $
MAN4= adv.4 adw.4 aha.4 ahb.4 ahc.4 aic.4 alog.4 apm.4 ar.4 asc.4 bktr.4 \
bt.4 cs.4 cx.4 cy.4 de.4 \
dgb.4 dpt.4 ed.4 eg.4 el.4 en.4 ep.4 ex.4 fdc.4 fe.4 fxp.4 gsc.4 ie.4 \
dgb.4 dpt.4 ed.4 el.4 en.4 ep.4 ex.4 fdc.4 fe.4 fxp.4 gsc.4 ie.4 \
io.4 joy.4 keyboard.4 labpc.4 le.4 lnc.4 lp.4 lpt.4 matcd.4 mcd.4 \
mem.4 meteor.4 mouse.4 mse.4 mtio.4 mx.4 nca.4 ncr.4 npx.4 \
pcf.4 pcm.4 pcvt.4 perfmon.4 pn.4 pnp.4 ppc.4 psm.4 \
@ -29,7 +29,6 @@ MLINKS+= de.4 ../de.4
MLINKS+= dgb.4 ../dgb.4
MLINKS+= dpt.4 ../dpt.4
MLINKS+= ed.4 ../ed.4
MLINKS+= eg.4 ../eg.4
MLINKS+= el.4 ../el.4
MLINKS+= en.4 ../en.4
MLINKS+= ep.4 ../ep.4

View File

@ -1,72 +0,0 @@
.\"
.\" Copyright (c) 1994 James A. Jegers
.\" 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. The name 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.
.\"
.\" $Id: eg.4,v 1.6 1998/03/12 07:30:31 charnier Exp $
.\"
.Dd July 10, 1995
.Dt EG 4 i386
.Os
.Sh NAME
.Nm eg
.Nd Ethernet driver for 3Com 3c505 Etherlink+ Ethernet board
.Sh SYNOPSIS
.Cd "device eg0 at isa? port 0x310 net irq 5"
.Sh DESCRIPTION
The
.Nm
interface provides access to a 10 Mb/s Ethernet network via the
3Com 3c505 board based on the Intel 82586 Ethernet chip.
.Sh DIAGNOSTICS
.Bl -diag
.It "eg%d: configure card command failed"
For some reason, the driver could not initialize the card. Please check
the card's IRQ and I/O settings relative to those in the kernel
configuration file.
.El
.Pp
.Sh BUGS
Uses the onboard firmware, which is not a good way to do it.
Doesn't support DMA or high speeds.
Currently the driver does not support multicast.
The timeout interval can be quite long (16 seconds) for a 512k board.
.Sh SEE ALSO
.Xr ed 4 ,
.Xr el 4 ,
.Xr ep 4 ,
.Xr ie 4 ,
.Xr intro 4 ,
.Xr le 4 ,
.Xr ifconfig 8
.Sh HISTORY
The
.Nm
device driver first appeared in
.Fx 2.0.5
coming from NetBSD.
.Sh AUTHORS
The
.Nm
device driver was written by
.An Dean Huxley .
This manual page was written by
.An James A. Jegers .

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.512 1998/12/27 12:35:35 phk Exp $
# $Id: LINT,v 1.513 1998/12/27 12:40:07 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -1129,7 +1129,6 @@ device ar0 at isa? port 0x300 net irq 10 iomem 0xd0000
device cs0 at isa? port 0x300 net irq ?
device cx0 at isa? port 0x240 net irq 15 drq 7
device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000
device eg0 at isa? port 0x310 net irq 5
device el0 at isa? port 0x300 net irq 9
device ep0 at isa? port 0x300 net irq 10
device ex0 at isa? port? net irq?

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.207 1998/12/21 18:04:20 joerg Exp $
# $Id: files.i386,v 1.208 1998/12/27 12:40:07 phk Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@ -116,7 +116,6 @@ i386/isa/if_ar.c optional ar device-driver
i386/isa/if_cs.c optional cs device-driver
i386/isa/if_cx.c optional cx device-driver
i386/isa/if_ed.c optional ed device-driver
i386/isa/if_eg.c optional eg device-driver
i386/isa/if_el.c optional el device-driver
i386/isa/if_ep.c optional ep device-driver
i386/isa/if_ex.c optional ex device-driver

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.512 1998/12/27 12:35:35 phk Exp $
# $Id: LINT,v 1.513 1998/12/27 12:40:07 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -1129,7 +1129,6 @@ device ar0 at isa? port 0x300 net irq 10 iomem 0xd0000
device cs0 at isa? port 0x300 net irq ?
device cx0 at isa? port 0x240 net irq 15 drq 7
device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000
device eg0 at isa? port 0x310 net irq 5
device el0 at isa? port 0x300 net irq 9
device ep0 at isa? port 0x300 net irq 10
device ex0 at isa? port? net irq?

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.512 1998/12/27 12:35:35 phk Exp $
# $Id: LINT,v 1.513 1998/12/27 12:40:07 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -1129,7 +1129,6 @@ device ar0 at isa? port 0x300 net irq 10 iomem 0xd0000
device cs0 at isa? port 0x300 net irq ?
device cx0 at isa? port 0x240 net irq 15 drq 7
device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000
device eg0 at isa? port 0x310 net irq 5
device el0 at isa? port 0x300 net irq 9
device ep0 at isa? port 0x300 net irq 10
device ex0 at isa? port? net irq?

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.207 1998/12/21 18:04:20 joerg Exp $
# $Id: files.i386,v 1.208 1998/12/27 12:40:07 phk Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@ -116,7 +116,6 @@ i386/isa/if_ar.c optional ar device-driver
i386/isa/if_cs.c optional cs device-driver
i386/isa/if_cx.c optional cx device-driver
i386/isa/if_ed.c optional ed device-driver
i386/isa/if_eg.c optional eg device-driver
i386/isa/if_el.c optional el device-driver
i386/isa/if_ep.c optional ep device-driver
i386/isa/if_ex.c optional ex device-driver

View File

@ -1,791 +0,0 @@
/*
* Copyright (c) 1993 Dean Huxley <dean@fsa.ca>
* 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 includes software developed by Dean Huxley.
* 4. The name of Dean Huxley 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.
*
* $Id: if_eg.c,v 1.28 1998/06/07 17:10:27 dfr Exp $
*
* Support for 3Com 3c505 Etherlink+ card.
*/
/* To do:
* - multicast
* - promiscuous
*/
#include "eg.h"
#include "bpfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/sockio.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_arp.h>
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
#include <machine/clock.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/if_egreg.h>
/* for debugging convenience */
#ifdef EGDEBUG
#define dprintf(x) printf x
#else
#define dprintf(x)
#endif
#define EG_INLEN 10
#define EG_BUFLEN 0x0670
/*
* Ethernet software status per interface.
*/
static struct eg_softc {
struct arpcom sc_arpcom; /* Ethernet common part */
int eg_cmd; /* Command register R/W */
int eg_ctl; /* Control register R/W (EG_CTL_*) */
int eg_stat; /* Status register R/O (EG_STAT_*) */
int eg_data; /* Data register R/W (16 bits) */
u_char eg_rom_major; /* Cards ROM version (major number) */
u_char eg_rom_minor; /* Cards ROM version (minor number) */
short eg_ram; /* Amount of RAM on the card */
u_char eg_pcb[64]; /* Primary Command Block buffer */
u_char eg_incount; /* Number of buffers currently used */
u_char *eg_inbuf; /* Incoming packet buffer */
u_char *eg_outbuf; /* Outgoing packet buffer */
} eg_softc[NEG];
static int egprobe (struct isa_device *);
static int egattach (struct isa_device *);
struct isa_driver egdriver = {
egprobe, egattach, "eg", 0
};
static void egprintpcb __P((struct eg_softc *sc));
static void egprintstat __P((int b));
static int egoutPCB __P((struct eg_softc *sc, int b));
static int egreadPCBstat __P((struct eg_softc *sc, int statb));
static int egreadPCBready __P((struct eg_softc *sc));
static int egwritePCB __P((struct eg_softc *sc));
static int egreadPCB __P((struct eg_softc *sc));
static void eginit __P((struct eg_softc *sc));
static int egioctl (struct ifnet *, u_long, caddr_t);
static void egrecv(struct eg_softc *);
static void egstart(struct ifnet *);
static ointhand2_t egintr;
static void egread __P((struct eg_softc *, caddr_t, int));
static void egstop __P((struct eg_softc *));
static void egwatchdog __P((struct ifnet *));
static void egreset __P((struct eg_softc *));
static struct mbuf *egget __P((struct eg_softc *, caddr_t, int));
/*
* Support stuff
*/
static void
egprintpcb(sc)
struct eg_softc *sc;
{
int i;
for (i = 0; i < sc->eg_pcb[1] + 2; i++)
dprintf(("eg#: pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
}
static void
egprintstat(b)
u_char b;
{
dprintf(("eg#: %s %s %s %s %s %s %s\n",
(b & EG_STAT_HCRE)?"HCRE":"",
(b & EG_STAT_ACRF)?"ACRF":"",
(b & EG_STAT_DIR )?"DIR ":"",
(b & EG_STAT_DONE)?"DONE":"",
(b & EG_STAT_ASF3)?"ASF3":"",
(b & EG_STAT_ASF2)?"ASF2":"",
(b & EG_STAT_ASF1)?"ASF1":""));
}
static int
egoutPCB(sc, b)
struct eg_softc *sc;
u_char b;
{
int i;
for (i=0; i < 4000; i++) {
if (inb(sc->eg_stat) & EG_STAT_HCRE) {
outb(sc->eg_cmd, b);
return 0;
}
DELAY(10);
}
dprintf(("eg#: egoutPCB failed\n"));
return 1;
}
static int
egreadPCBstat(sc, statb)
struct eg_softc *sc;
u_char statb;
{
int i;
for (i=0; i < 5000; i++) {
if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL)
break;
DELAY(10);
}
if ((inb(sc->eg_stat) & EG_PCB_STAT) == statb)
return 0;
return 1;
}
static int
egreadPCBready(sc)
struct eg_softc *sc;
{
int i;
for (i=0; i < 10000; i++) {
if (inb(sc->eg_stat) & EG_STAT_ACRF)
return 0;
DELAY(5);
}
dprintf(("eg#: PCB read not ready\n"));
return 1;
}
static int
egwritePCB(sc)
struct eg_softc *sc;
{
int i;
u_char len;
outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
len = sc->eg_pcb[1] + 2;
for (i = 0; i < len; i++)
egoutPCB(sc, sc->eg_pcb[i]);
for (i=0; i < 4000; i++) {
if (inb(sc->eg_stat) & EG_STAT_HCRE)
break;
DELAY(10);
}
outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_DONE);
egoutPCB(sc, len);
if (egreadPCBstat(sc, EG_PCB_ACCEPT))
return 1;
return 0;
}
static int
egreadPCB(sc)
struct eg_softc *sc;
{
int i;
u_char b;
outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
if (egreadPCBready(sc))
return 1;
sc->eg_pcb[0] = inb(sc->eg_cmd);
if (egreadPCBready(sc))
return 1;
sc->eg_pcb[1] = inb(sc->eg_cmd);
if (sc->eg_pcb[1] > 62) {
dprintf(("eg#: len %d too large\n", sc->eg_pcb[1]));
return 1;
}
for (i = 0; i < sc->eg_pcb[1]; i++) {
if (egreadPCBready(sc))
return 1;
sc->eg_pcb[2+i] = inb(sc->eg_cmd);
}
if (egreadPCBready(sc))
return 1;
if (egreadPCBstat(sc, EG_PCB_DONE))
return 1;
if ((b = inb(sc->eg_cmd)) != sc->eg_pcb[1] + 2) {
dprintf(("eg#: %d != %d\n", b, sc->eg_pcb[1] + 2));
return 1;
}
outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_ACCEPT);
return 0;
}
/*
* Real stuff
*/
static int
egprobe(struct isa_device * id)
{
struct eg_softc *sc = &eg_softc[id->id_unit];
int i;
if (id->id_iobase & ~0x07f0 != 0) {
dprintf(("eg#: Weird iobase %x\n", ia->ia_iobase));
return 0;
}
sc->eg_cmd = id->id_iobase + EG_COMMAND;
sc->eg_ctl = id->id_iobase + EG_CONTROL;
sc->eg_stat = id->id_iobase + EG_STATUS;
sc->eg_data = id->id_iobase + EG_DATA;
/* hard reset card */
outb(sc->eg_ctl, EG_CTL_RESET);
outb(sc->eg_ctl, 0);
for (i = 0; i < 1600; i++) {
DELAY(10000);
if ((inb(sc->eg_stat) & EG_PCB_STAT) == EG_PCB_NULL)
break;
}
if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL) {
dprintf(("eg#: eg: Reset failed\n"));
return 0;
}
sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
sc->eg_pcb[1] = 0;
if (egwritePCB(sc) != 0)
return 0;
if (egreadPCB(sc) != 0) {
egprintpcb(sc);
return 0;
}
if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
sc->eg_pcb[1] != 0x0a) {
egprintpcb(sc);
return 0;
}
sc->eg_rom_major = sc->eg_pcb[3];
sc->eg_rom_minor = sc->eg_pcb[2];
sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
return 8;
}
static int
egattach(struct isa_device *id)
{
struct eg_softc *sc = &eg_softc[id->id_unit];
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
id->id_ointr = egintr;
egstop(sc);
sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
sc->eg_pcb[1] = 0;
if (egwritePCB(sc) != 0) {
dprintf(("eg#: write error\n"));
return 0;
}
if (egreadPCB(sc) != 0) {
dprintf(("eg#: read error\n"));
egprintpcb(sc);
return 0;
}
/* check Get station address response */
if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
dprintf(("eg#: parse error\n"));
egprintpcb(sc);
return 0;
}
bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
printf("eg%d: address %6D, type=3COM 3c505 (v%d.%02d, %dk)\n",
id->id_unit, sc->sc_arpcom.ac_enaddr, ":",
sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram);
sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
if (egwritePCB(sc) != 0) {
dprintf(("eg#: write error2\n"));
return 0;
}
if (egreadPCB(sc) != 0) {
dprintf(("eg#: read error2\n"));
egprintpcb(sc);
return 0;
}
if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
dprintf(("eg#: parse error2\n"));
egprintpcb(sc);
return 0;
}
/* Initialize ifnet structure. */
ifp->if_softc = sc;
ifp->if_unit = id->id_unit;
ifp->if_name = "eg";
ifp->if_output = ether_output;
ifp->if_start = egstart;
ifp->if_ioctl = egioctl;
ifp->if_init = (if_init_f_t*)eginit;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
ifp->if_watchdog = egwatchdog;
/* Now we can attach the interface. */
if_attach(ifp);
ether_ifattach(ifp);
#if NBPFILTER > 0
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
#endif
return 1;
}
static void
eginit(struct eg_softc *sc)
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
/* soft reset the board */
outb(sc->eg_ctl, EG_CTL_FLSH);
DELAY(100);
outb(sc->eg_ctl, EG_CTL_ATTN);
DELAY(100);
outb(sc->eg_ctl, 0);
DELAY(200);
sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
sc->eg_pcb[1] = 2;
sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
sc->eg_pcb[3] = 0;
#ifdef EGDEBUG
if (egwritePCB(sc) != 0)
dprintf(("eg#: write error3\n"));
#endif
if (egreadPCB(sc) != 0) {
dprintf(("eg#: read error\n"));
egprintpcb(sc);
} else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
printf("eg%d: configure card command failed\n", ifp->if_unit);
if (sc->eg_inbuf == NULL)
sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
sc->eg_incount = 0;
if (sc->eg_outbuf == NULL)
sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
outb(sc->eg_ctl, EG_CTL_CMDE);
sc->eg_incount = 0;
egrecv(sc);
/* Interface is now `running', with no output active. */
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
/* Attempt to start output, if any. */
egstart(ifp);
}
static void
egrecv(sc)
struct eg_softc *sc;
{
while (sc->eg_incount < EG_INLEN) {
sc->eg_pcb[0] = EG_CMD_RECVPACKET;
sc->eg_pcb[1] = 0x08;
sc->eg_pcb[2] = 0; /* address not used.. we send zero */
sc->eg_pcb[3] = 0;
sc->eg_pcb[4] = 0;
sc->eg_pcb[5] = 0;
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)
break;
sc->eg_incount++;
}
}
static void
egstart(ifp)
struct ifnet *ifp;
{
register struct eg_softc *sc = ifp->if_softc;
struct mbuf *m0, *m;
caddr_t buffer;
int len;
u_short *ptr;
/* Don't transmit if interface is busy or not running */
if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
return;
loop:
/* Dequeue the next datagram. */
IF_DEQUEUE(&ifp->if_snd, m0);
if (m0 == 0)
return;
ifp->if_flags |= IFF_OACTIVE;
/* We need to use m->m_pkthdr.len, so require the header */
if ((m0->m_flags & M_PKTHDR) == 0)
panic("egstart: no header mbuf");
len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
#if NBPFILTER > 0
if (ifp->if_bpf)
bpf_mtap(ifp, m0);
#endif
sc->eg_pcb[0] = EG_CMD_SENDPACKET;
sc->eg_pcb[1] = 0x06;
sc->eg_pcb[2] = 0; /* address not used, we send zero */
sc->eg_pcb[3] = 0;
sc->eg_pcb[4] = 0;
sc->eg_pcb[5] = 0;
sc->eg_pcb[6] = len; /* length of packet */
sc->eg_pcb[7] = len >> 8;
if (egwritePCB(sc) != 0) {
dprintf(("eg#: egwritePCB in egstart failed\n"));
ifp->if_oerrors++;
ifp->if_flags &= ~IFF_OACTIVE;
goto loop;
}
buffer = sc->eg_outbuf;
for (m = m0; m != 0; m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
}
/* set direction bit: host -> adapter */
outb(sc->eg_ctl, inb(sc->eg_ctl) & ~EG_CTL_DIR);
for (ptr = (u_short *) sc->eg_outbuf; len > 0; len -= 2) {
outw(sc->eg_data, *ptr++);
while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
; /* XXX need timeout here */
}
m_freem(m0);
}
static void
egintr(int unit)
{
register struct eg_softc *sc = &eg_softc[unit];
int i, len;
u_short *ptr;
while (inb(sc->eg_stat) & EG_STAT_ACRF) {
egreadPCB(sc);
switch (sc->eg_pcb[0]) {
case EG_RSP_RECVPACKET:
len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
/* Set direction bit : Adapter -> host */
outb(sc->eg_ctl, inb(sc->eg_ctl) | EG_CTL_DIR);
for (ptr = (u_short *) sc->eg_inbuf; len > 0; len -= 2) {
while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
;
*ptr++ = inw(sc->eg_data);
}
len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
egread(sc, sc->eg_inbuf, len);
sc->eg_incount--;
egrecv(sc);
break;
case EG_RSP_SENDPACKET:
if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
dprintf(("eg#: packet dropped\n"));
sc->sc_arpcom.ac_if.if_oerrors++;
} else
sc->sc_arpcom.ac_if.if_opackets++;
sc->sc_arpcom.ac_if.if_collisions += sc->eg_pcb[8] & 0xf;
sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
egstart(&sc->sc_arpcom.ac_if);
break;
case EG_RSP_GETSTATS:
dprintf(("eg#: Card Statistics\n"));
bcopy(&sc->eg_pcb[2], &i, sizeof(i));
dprintf(("eg#: Receive Packets %d\n", i));
bcopy(&sc->eg_pcb[6], &i, sizeof(i));
dprintf(("eg#: Transmit Packets %d\n", i));
dprintf(("eg#: CRC errors %d\n", *(short*) &sc->eg_pcb[10]));
dprintf(("eg#: alignment errors %d\n", *(short*) &sc->eg_pcb[12]));
dprintf(("eg#: no resources errors %d\n", *(short*) &sc->eg_pcb[14]));
dprintf(("eg#: overrun errors %d\n", *(short*) &sc->eg_pcb[16]));
break;
default:
dprintf(("eg#: egintr: Unknown response %x??\n",
sc->eg_pcb[0]));
egprintpcb(sc);
break;
}
}
return;
}
/*
* Pass a packet up to the higher levels.
*/
static void
egread(sc, buf, len)
struct eg_softc *sc;
caddr_t buf;
int len;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct mbuf *m;
struct ether_header *eh;
if (len <= sizeof(struct ether_header) ||
len > ETHER_MAX_LEN) {
printf("eg#: invalid packet size %d; dropping\n", len);
ifp->if_ierrors++;
return;
}
/* Pull packet off interface. */
m = egget(sc, buf, len);
if (m == 0) {
ifp->if_ierrors++;
return;
}
ifp->if_ipackets++;
/* We assume the header fit entirely in one mbuf. */
eh = mtod(m, struct ether_header *);
#if NBPFILTER > 0
/*
* Check if there's a BPF listener on this interface.
* If so, hand off the raw packet to BPF.
*/
if (ifp->if_bpf) {
bpf_mtap(ifp, m);
/*
* Note that the interface cannot be in promiscuous mode if
* there are no BPF listeners. And if we are in promiscuous
* mode, we have to check if this packet is really ours.
*/
if ((ifp->if_flags & IFF_PROMISC) &&
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
sizeof(eh->ether_dhost)) != 0) {
m_freem(m);
return;
}
}
#endif
/* We assume the header fit entirely in one mbuf. */
m_adj(m, sizeof(struct ether_header));
ether_input(ifp, eh, m);
}
/*
* convert buf into mbufs
*/
static struct mbuf *
egget(sc, buf, totlen)
struct eg_softc *sc;
caddr_t buf;
int totlen;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct mbuf *top, **mp, *m;
int len;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0)
return 0;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
len = MHLEN;
top = 0;
mp = &top;
while (totlen > 0) {
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
m_freem(top);
return 0;
}
len = MLEN;
}
if (totlen >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
len = MCLBYTES;
}
m->m_len = len = min(totlen, len);
bcopy((caddr_t)buf, mtod(m, caddr_t), len);
buf += len;
totlen -= len;
*mp = m;
mp = &m->m_next;
}
return top;
}
static int
egioctl(ifp, command, data)
register struct ifnet *ifp;
u_long command;
caddr_t data;
{
struct eg_softc *sc = ifp->if_softc;
int s, error = 0;
s = splnet();
switch (command) {
case SIOCSIFADDR:
case SIOCGIFADDR:
case SIOCSIFMTU:
error = ether_ioctl(ifp, command, data);
break;
case SIOCSIFFLAGS:
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.
*/
egstop(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.
*/
eginit(sc);
} else {
sc->eg_pcb[0] = EG_CMD_GETSTATS;
sc->eg_pcb[1] = 0;
#ifdef EGDEBUG
if (egwritePCB(sc) != 0)
dprintf(("eg#: write error\n"));
#endif
/*
* XXX deal with flags changes:
* IFF_MULTICAST, IFF_PROMISC,
* IFF_LINK0, IFF_LINK1,
*/
}
break;
default:
error = EINVAL;
break;
}
splx(s);
return error;
}
static void
egreset(sc)
struct eg_softc *sc;
{
int s;
dprintf(("eg#: egreset()\n"));
s = splnet();
egstop(sc);
eginit(sc);
splx(s);
}
static void
egwatchdog(ifp)
struct ifnet *ifp;
{
struct eg_softc *sc = ifp->if_softc;
log(LOG_ERR, "%s: device timeout\n", "eg#");
sc->sc_arpcom.ac_if.if_oerrors++;
egreset(sc);
}
static void
egstop(sc)
register struct eg_softc *sc;
{
outb(sc->eg_ctl, 0);
}

View File

@ -1,103 +0,0 @@
/*
* Copyright (c) 1993 Dean Huxley (dean@fsa.ca)
* 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 includes software developed by Dean Huxley.
* 4. The name of Dean Huxley 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.
*/
/*
* Register offsets from base.
*/
#define EG_COMMAND 0x00
#define EG_STATUS 0x02
#define EG_DATA 0x04
#define EG_CONTROL 0x06
/*
* Host Control Register bits
* EG_CTL_ATTN - does a soft reset
* EG_CTL_FLSH - flushes the data register
* EG_CTL_RESET - does a hard reset
* EG_CTL_DMAE - Used with DIR bit, enables DMA transfers to/from data reg.
* EG_CTL_DIR - if clear then host -> adapter, if set then adapter -> host
* EG_CTL_TCEN - terminal count enable. enables host interrupt after DMA.
* EG_CTL_CMDE - command reg interrupt enable. (when it is written)
* EG_CTL_HSF1 - Host status flag 1
* EG_CTL_HSF2 - Host status flag 2
*/
#define EG_CTL_ATTN 0x80
#define EG_CTL_FLSH 0x40
#define EG_CTL_RESET (EG_CTL_ATTN|EG_CTL_FLSH)
#define EG_CTL_DMAE 0x20
#define EG_CTL_DIR 0x10
#define EG_CTL_TCEN 0x08
#define EG_CTL_CMDE 0x04
#define EG_CTL_HSF2 0x02
#define EG_CTL_HSF1 0x01
/*
* Host Status Register bits
* EG_STAT_HRDY - Data Register ready
* EG_STAT_HCRE - Host Command Register empty
* EG_STAT_ACRF - Adapter Command register full
* EG_STAT_DIR - Direction flag, 0 = host -> adapter, 1 = adapter -> host
* EG_STAT_DONE - DMA done
* EG_STAT_ASF1 - Adapter status flag 1
* EG_STAT_ASF2 - Adapter status flag 2
* EG_STAT_ASF3 - Adapter status flag 3
*/
#define EG_STAT_HRDY 0x80
#define EG_STAT_HCRE 0x40
#define EG_STAT_ACRF 0x20
#define EG_STAT_DIR 0x10
#define EG_STAT_DONE 0x08
#define EG_STAT_ASF3 0x04
#define EG_STAT_ASF2 0x02
#define EG_STAT_ASF1 0x01
#define EG_PCB_NULL 0x00
#define EG_PCB_ACCEPT 0x01
#define EG_PCB_REJECT 0x02
#define EG_PCB_DONE 0x03
#define EG_PCB_STAT 0x03
#define EG_CMD_CONFIG82586 0x02
#define EG_CMD_GETEADDR 0x03
#define EG_CMD_RECVPACKET 0x08
#define EG_CMD_SENDPACKET 0x09
#define EG_CMD_GETSTATS 0x0a
#define EG_CMD_SETEADDR 0x10
#define EG_CMD_GETINFO 0x11
#define EG_RSP_CONFIG82586 0x32
#define EG_RSP_GETEADDR 0x33
#define EG_RSP_RECVPACKET 0x38
#define EG_RSP_SENDPACKET 0x39
#define EG_RSP_GETSTATS 0x3a
#define EG_RSP_SETEADDR 0x40
#define EG_RSP_GETINFO 0x41