Redo standalone driver for WD8013 / SMC Ultra boards.
(The old one was buggy.) Frontend / backend splitup and most code taken from sys/dev/ic/dp8390.c and sys/dev/isa/if_we.c.
This commit is contained in:
parent
642cbc64e2
commit
b8cdacb8d5
|
@ -1,4 +1,4 @@
|
|||
## $NetBSD: Makefile.inc,v 1.1.1.1 1997/03/14 02:40:33 perry Exp $
|
||||
## $NetBSD: Makefile.inc,v 1.2 1998/02/16 11:21:59 drochner Exp $
|
||||
|
||||
SRCS += netif_small.c
|
||||
.if (${USE_NETIF} == "3c509")
|
||||
|
@ -8,7 +8,7 @@ SRCS += 3c509.c elink3.c
|
|||
SRCS += 3c590.c elink3.c
|
||||
.endif
|
||||
.if (${USE_NETIF} == "wd80x3")
|
||||
SRCS += wd80x3.c
|
||||
SRCS += wd80x3.c dp8390.c
|
||||
.endif
|
||||
.if (${USE_NETIF} == "pcnet_pci")
|
||||
SRCS += pcnet_pci.c am7990.c
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
/* $NetBSD: dp8390.c,v 1.1 1998/02/16 11:22:00 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Polling driver for National Semiconductor DS8390/WD83C690 based
|
||||
* ethernet adapters.
|
||||
*
|
||||
* Copyright (c) 1998 Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 1993, David Greenman. This software may be used, modified,
|
||||
* copied, distributed, and sold, in both source and binary form provided that
|
||||
* the above copyright and these terms are retained. Under no circumstances is
|
||||
* the author responsible for the proper functioning of this software, nor does
|
||||
* the author assume any responsibility for damages incurred with its use.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/pio.h>
|
||||
|
||||
#include <lib/libsa/stand.h>
|
||||
#include <libi386.h>
|
||||
|
||||
#include <dev/ic/dp8390reg.h>
|
||||
#include "dp8390.h"
|
||||
|
||||
#include "etherdrv.h"
|
||||
|
||||
int dp8390_iobase, dp8390_membase, dp8390_memsize;
|
||||
#if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA)
|
||||
int dp8390_is790;
|
||||
#endif
|
||||
u_int8_t dp8390_cr_proto;
|
||||
u_int8_t dp8390_dcr_reg;
|
||||
|
||||
#define WE_IOBASE dp8390_iobase
|
||||
|
||||
static u_short rec_page_start;
|
||||
static u_short rec_page_stop;
|
||||
static u_short next_packet;
|
||||
|
||||
extern u_char eth_myaddr[6];
|
||||
|
||||
#ifndef _STANDALONE
|
||||
static caddr_t vmembase;
|
||||
extern caddr_t mapmem __P((int, int));
|
||||
extern void unmapmem __P((caddr_t, int));
|
||||
extern int mapio __P((void));
|
||||
|
||||
static void bbcopy(src, dst, len)
|
||||
caddr_t src, dst;
|
||||
int len;
|
||||
{
|
||||
char *s = (char *)src, *d = (char *)dst;
|
||||
|
||||
while(len--)
|
||||
*d++ = *s++;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dp8390_read __P((int, char *, u_short));
|
||||
|
||||
#define NIC_GET(reg) inb(WE_IOBASE + reg)
|
||||
#define NIC_PUT(reg, val) outb(WE_IOBASE + reg, val)
|
||||
|
||||
static void
|
||||
dp8390_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Initialize the NIC in the exact order outlined in the NS manual.
|
||||
* This init procedure is "mandatory"...don't change what or when
|
||||
* things happen.
|
||||
*/
|
||||
|
||||
/* Set interface for page 0, remote DMA complete, stopped. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
|
||||
|
||||
if (dp8390_dcr_reg & ED_DCR_LS) {
|
||||
NIC_PUT(ED_P0_DCR, dp8390_dcr_reg);
|
||||
} else {
|
||||
/*
|
||||
* Set FIFO threshold to 8, No auto-init Remote DMA, byte
|
||||
* order=80x86, byte-wide DMA xfers,
|
||||
*/
|
||||
NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
|
||||
}
|
||||
|
||||
/* Clear remote byte count registers. */
|
||||
NIC_PUT(ED_P0_RBCR0, 0);
|
||||
NIC_PUT(ED_P0_RBCR1, 0);
|
||||
|
||||
/* Tell RCR to do nothing for now. */
|
||||
NIC_PUT(ED_P0_RCR, ED_RCR_MON);
|
||||
|
||||
/* Place NIC in internal loopback mode. */
|
||||
NIC_PUT(ED_P0_TCR, ED_TCR_LB0);
|
||||
|
||||
/* Set lower bits of byte addressable framing to 0. */
|
||||
if (dp8390_is790)
|
||||
NIC_PUT(0x09, 0);
|
||||
|
||||
/* Initialize receive buffer ring. */
|
||||
NIC_PUT(ED_P0_BNRY, rec_page_start);
|
||||
NIC_PUT(ED_P0_PSTART, rec_page_start);
|
||||
NIC_PUT(ED_P0_PSTOP, rec_page_stop);
|
||||
|
||||
/*
|
||||
* Clear all interrupts. A '1' in each bit position clears the
|
||||
* corresponding flag.
|
||||
*/
|
||||
NIC_PUT(ED_P0_ISR, 0xff);
|
||||
|
||||
/*
|
||||
* Disable all interrupts.
|
||||
*/
|
||||
NIC_PUT(ED_P0_IMR, 0);
|
||||
|
||||
/* Program command register for page 1. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP);
|
||||
|
||||
/* Copy out our station address. */
|
||||
for (i = 0; i < 6; ++i)
|
||||
NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]);
|
||||
|
||||
/*
|
||||
* Set current page pointer to one page after the boundary pointer, as
|
||||
* recommended in the National manual.
|
||||
*/
|
||||
next_packet = rec_page_start + 1;
|
||||
NIC_PUT(ED_P1_CURR, next_packet);
|
||||
|
||||
/* Program command register for page 0. */
|
||||
NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
|
||||
|
||||
/* directed and broadcast */
|
||||
NIC_PUT(ED_P0_RCR, ED_RCR_AB);
|
||||
|
||||
/* Take interface out of loopback. */
|
||||
NIC_PUT(ED_P0_TCR, 0);
|
||||
|
||||
/* Fire up the interface. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
|
||||
}
|
||||
|
||||
int
|
||||
dp8390_config()
|
||||
{
|
||||
#ifndef _STANDALONE
|
||||
if (mapio()) {
|
||||
printf("no IO access\n");
|
||||
return(-1);
|
||||
}
|
||||
vmembase = mapmem(dp8390_membase, dp8390_memsize);
|
||||
if (!vmembase) {
|
||||
printf("no memory access\n");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
rec_page_start = ED_TXBUF_SIZE;
|
||||
rec_page_stop = dp8390_memsize >> ED_PAGE_SHIFT;
|
||||
|
||||
dp8390_init();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
dp8390_stop()
|
||||
{
|
||||
int n = 5000;
|
||||
|
||||
/* Stop everything on the interface, and select page 0 registers. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
|
||||
|
||||
/*
|
||||
* Wait for interface to enter stopped state, but limit # of checks to
|
||||
* 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
|
||||
* just in case it's an old one.
|
||||
*/
|
||||
while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
|
||||
|
||||
#ifndef _STANDALONE
|
||||
unmapmem(vmembase, dp8390_memsize);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
EtherSend(pkt, len)
|
||||
char *pkt;
|
||||
int len;
|
||||
{
|
||||
#ifdef _STANDALONE
|
||||
vpbcopy(pkt, dp8390_membase, len);
|
||||
#else
|
||||
bbcopy(pkt, vmembase, len);
|
||||
#endif
|
||||
|
||||
/* Set TX buffer start page. */
|
||||
NIC_PUT(ED_P0_TPSR, 0);
|
||||
|
||||
/* Set TX length. */
|
||||
NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len);
|
||||
NIC_PUT(ED_P0_TBCR1, len >> 8);
|
||||
|
||||
/* Set page 0, remote DMA complete, transmit packet, and *start*. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA);
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
static void
|
||||
dp8390_read(buf, dest, len)
|
||||
int buf;
|
||||
char *dest;
|
||||
u_short len;
|
||||
{
|
||||
u_short tmp_amount;
|
||||
|
||||
/* Does copy wrap to lower addr in ring buffer? */
|
||||
if (buf + len > dp8390_membase + dp8390_memsize) {
|
||||
tmp_amount = dp8390_membase + dp8390_memsize - buf;
|
||||
|
||||
/* Copy amount up to end of NIC memory. */
|
||||
#ifdef _STANDALONE
|
||||
pvbcopy(buf, dest, tmp_amount);
|
||||
#else
|
||||
bbcopy(vmembase + buf - dp8390_membase, dest, tmp_amount);
|
||||
#endif
|
||||
|
||||
len -= tmp_amount;
|
||||
buf = dp8390_membase + (rec_page_start << ED_PAGE_SHIFT);
|
||||
dest += tmp_amount;
|
||||
}
|
||||
#ifdef _STANDALONE
|
||||
pvbcopy(buf, dest, len);
|
||||
#else
|
||||
bbcopy(vmembase + buf - dp8390_membase, dest, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
EtherReceive(pkt, maxlen)
|
||||
char *pkt;
|
||||
int maxlen;
|
||||
{
|
||||
struct dp8390_ring packet_hdr;
|
||||
int packet_ptr;
|
||||
u_short len;
|
||||
u_char boundary, current;
|
||||
#ifdef DP8390_OLDCHIPS
|
||||
u_char nlen;
|
||||
#endif
|
||||
|
||||
if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX))
|
||||
return(0); /* XXX error handling */
|
||||
|
||||
/* Set NIC to page 1 registers to get 'current' pointer. */
|
||||
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA);
|
||||
|
||||
/*
|
||||
* 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
|
||||
* it points to where new data has been buffered. The 'CURR' (current)
|
||||
* register points to the logical end of the ring-buffer - i.e. it
|
||||
* points to where additional new data will be added. We loop here
|
||||
* until the logical beginning equals the logical end (or in other
|
||||
* words, until the ring-buffer is empty).
|
||||
*/
|
||||
current = NIC_GET(ED_P1_CURR);
|
||||
|
||||
/* Set NIC to page 0 registers to update boundary register. */
|
||||
NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
|
||||
|
||||
if (next_packet == current)
|
||||
return(0);
|
||||
|
||||
/* Get pointer to this buffer's header structure. */
|
||||
packet_ptr = dp8390_membase + (next_packet << ED_PAGE_SHIFT);
|
||||
|
||||
/*
|
||||
* The byte count includes a 4 byte header that was added by
|
||||
* the NIC.
|
||||
*/
|
||||
#ifdef _STANDALONE
|
||||
pvbcopy(packet_ptr, &packet_hdr, 4);
|
||||
#else
|
||||
bbcopy(vmembase + packet_ptr - dp8390_membase, &packet_hdr, 4);
|
||||
#endif
|
||||
|
||||
len = packet_hdr.count;
|
||||
|
||||
#ifdef DP8390_OLDCHIPS
|
||||
/*
|
||||
* Try do deal with old, buggy chips that sometimes duplicate
|
||||
* the low byte of the length into the high byte. We do this
|
||||
* by simply ignoring the high byte of the length and always
|
||||
* recalculating it.
|
||||
*
|
||||
* NOTE: sc->next_packet is pointing at the current packet.
|
||||
*/
|
||||
if (packet_hdr.next_packet >= next_packet)
|
||||
nlen = (packet_hdr.next_packet - next_packet);
|
||||
else
|
||||
nlen = ((packet_hdr.next_packet - rec_page_start) +
|
||||
(rec_page_stop - next_packet));
|
||||
--nlen;
|
||||
if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE)
|
||||
--nlen;
|
||||
len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (len != packet_hdr.count) {
|
||||
printf("we: length does not match next packet pointer\n");
|
||||
printf("we: len %04x nlen %04x start %02x "
|
||||
"first %02x curr %02x next %02x stop %02x\n",
|
||||
packet_hdr.count, len,
|
||||
rec_page_start, next_packet, current,
|
||||
packet_hdr.next_packet, rec_page_stop);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (packet_hdr.next_packet < rec_page_start ||
|
||||
packet_hdr.next_packet >= rec_page_stop)
|
||||
panic("we: RAM corrupt");
|
||||
|
||||
len -= sizeof(struct dp8390_ring);
|
||||
if (len < maxlen) {
|
||||
/* Go get packet. */
|
||||
dp8390_read(packet_ptr + sizeof(struct dp8390_ring),
|
||||
pkt, len);
|
||||
} else
|
||||
len = 0;
|
||||
|
||||
/* Update next packet pointer. */
|
||||
next_packet = packet_hdr.next_packet;
|
||||
|
||||
/*
|
||||
* Update NIC boundary pointer - being careful to keep it one
|
||||
* buffer behind (as recommended by NS databook).
|
||||
*/
|
||||
boundary = next_packet - 1;
|
||||
if (boundary < rec_page_start)
|
||||
boundary = rec_page_stop - 1;
|
||||
NIC_PUT(ED_P0_BNRY, boundary);
|
||||
|
||||
return(len);
|
||||
}
|
|
@ -1,166 +1,19 @@
|
|||
/* $NetBSD: dp8390.h,v 1.1.1.1 1997/03/14 02:40:33 perry Exp $ */
|
||||
extern int dp8390_config __P((void));
|
||||
extern void dp8390_stop __P((void));
|
||||
|
||||
/*
|
||||
* source in this file came from
|
||||
* the Mach ethernet boot written by Leendert van Doorn.
|
||||
*
|
||||
* National Semiconductor DP8390 Network Interface Controller
|
||||
*/
|
||||
|
||||
/* page 0: for reading */
|
||||
#define DP_CR 0x00 /* read side of command register */
|
||||
#define DP_CLDA0 0x01 /* current local DMA address 0 */
|
||||
#define DP_CLDA1 0x02 /* current local DMA address 1 */
|
||||
#define DP_BNRY 0x03 /* boundary pointer */
|
||||
#define DP_TSR 0x04 /* transmit status register */
|
||||
#define DP_NCR 0x05 /* number of collisions register */
|
||||
#define DP_FIFO 0x06 /* FIFO */
|
||||
#define DP_ISR 0x07 /* interrupt status register */
|
||||
#define DP_CRDA0 0x08 /* current remote DMA address 0 */
|
||||
#define DP_CRDA1 0x09 /* current remote DMA address 1 */
|
||||
#define DP_RSR 0x0C /* receive status register */
|
||||
#define DP_CNTR0 0x0D /* tally counter 0 */
|
||||
#define DP_CNTR1 0x0E /* tally counter 1 */
|
||||
#define DP_CNTR2 0x0F /* tally counter 2 */
|
||||
|
||||
/* page 0: for writing */
|
||||
#define DP_CR 0x00 /* write side of command register */
|
||||
#define DP_PSTART 0x01 /* page start register */
|
||||
#define DP_PSTOP 0x02 /* page stop register */
|
||||
#define DP_BNRY 0x03 /* boundary pointer */
|
||||
#define DP_TPSR 0x04 /* transmit page start register */
|
||||
#define DP_TBCR0 0x05 /* transmit byte count register 0 */
|
||||
#define DP_TBCR1 0x06 /* transmit byte count register 1 */
|
||||
#define DP_ISR 0x07 /* interrupt status register */
|
||||
#define DP_RSAR0 0x08 /* remote start address register 0 */
|
||||
#define DP_RSAR1 0x09 /* remote start address register 1 */
|
||||
#define DP_RBCR0 0x0A /* remote byte count register 0 */
|
||||
#define DP_RBCR1 0x0B /* remote byte count register 1 */
|
||||
#define DP_RCR 0x0C /* receive configuration register */
|
||||
#define DP_TCR 0x0D /* transmit configuration register */
|
||||
#define DP_DCR 0x0E /* data configuration register */
|
||||
#define DP_IMR 0x0F /* interrupt mask register */
|
||||
|
||||
/* page 1: read/write */
|
||||
#define DP_CR 0x00 /* command register */
|
||||
#define DP_PAR0 0x01 /* physical address register 0 */
|
||||
#define DP_PAR1 0x02 /* physical address register 1 */
|
||||
#define DP_PAR2 0x03 /* physical address register 2 */
|
||||
#define DP_PAR3 0x04 /* physical address register 3 */
|
||||
#define DP_PAR4 0x05 /* physical address register 4 */
|
||||
#define DP_PAR5 0x06 /* physical address register 5 */
|
||||
#define DP_CURR 0x07 /* current page register */
|
||||
#define DP_MAR0 0x08 /* multicast address register 0 */
|
||||
#define DP_MAR1 0x09 /* multicast address register 1 */
|
||||
#define DP_MAR2 0x0A /* multicast address register 2 */
|
||||
#define DP_MAR3 0x0B /* multicast address register 3 */
|
||||
#define DP_MAR4 0x0C /* multicast address register 4 */
|
||||
#define DP_MAR5 0x0D /* multicast address register 5 */
|
||||
#define DP_MAR6 0x0E /* multicast address register 6 */
|
||||
#define DP_MAR7 0x0F /* multicast address register 7 */
|
||||
|
||||
/* bits in command register */
|
||||
#define CR_STP 0x01 /* stop: software reset */
|
||||
#define CR_STA 0x02 /* start: activate NIC */
|
||||
#define CR_TXP 0x04 /* transmit packet */
|
||||
#define CR_DMA 0x38 /* mask for DMA control */
|
||||
# define CR_DM_NOP 0x00 /* DMA: no operation */
|
||||
# define CR_DM_RR 0x08 /* DMA: remote read */
|
||||
# define CR_DM_RW 0x10 /* DMA: remote write */
|
||||
# define CR_DM_SP 0x18 /* DMA: send packet */
|
||||
# define CR_DM_ABORT 0x20 /* DMA: abort remote DMA operation */
|
||||
#define CR_PS 0xC0 /* mask for page select */
|
||||
# define CR_PS_P0 0x00 /* register page 0 */
|
||||
# define CR_PS_P1 0x40 /* register page 1 */
|
||||
# define CR_PS_T0 0x80 /* test mode register map */
|
||||
# define CR_SP_T1 0xC0 /* test mode register map */
|
||||
|
||||
/* bits in interrupt status register */
|
||||
#define ISR_PRX 0x01 /* packet received with no errors */
|
||||
#define ISR_PTX 0x02 /* packet transmitted with no errors */
|
||||
#define ISR_RXE 0x04 /* receive error */
|
||||
#define ISR_TXE 0x08 /* transmit error */
|
||||
#define ISR_OVW 0x10 /* overwrite warning */
|
||||
#define ISR_CNT 0x20 /* counter overflow */
|
||||
#define ISR_RDC 0x40 /* remote DMA complete */
|
||||
#define ISR_RST 0x80 /* reset status */
|
||||
|
||||
/* bits in interrupt mask register */
|
||||
#define IMR_PRXE 0x01 /* packet received ienable */
|
||||
#define IMR_PTXE 0x02 /* packet transmitted ienable */
|
||||
#define IMR_RXEE 0x04 /* receive error ienable */
|
||||
#define IMR_TXEE 0x08 /* transmit error ienable */
|
||||
#define IMR_OVWE 0x10 /* overwrite warning ienable */
|
||||
#define IMR_CNTE 0x20 /* counter overflow ienable */
|
||||
#define IMR_RDCE 0x40 /* DMA complete ienable */
|
||||
|
||||
/* bits in data control register */
|
||||
#define DCR_WTS 0x01 /* word transfer select */
|
||||
# define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */
|
||||
# define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */
|
||||
#define DCR_BOS 0x02 /* byte order select */
|
||||
# define DCR_LTLENDIAN 0x00 /* BOS: little endian */
|
||||
# define DCR_BIGENDIAN 0x02 /* BOS: big endian */
|
||||
#define DCR_LAS 0x04 /* long address select */
|
||||
#define DCR_BMS 0x08 /* burst mode select */
|
||||
#define DCR_AR 0x10 /* autoinitialize remote */
|
||||
#define DCR_FTS 0x60 /* FIFO threshold select */
|
||||
# define DCR_2BYTES 0x00 /* 2 bytes */
|
||||
# define DCR_4BYTES 0x40 /* 4 bytes */
|
||||
# define DCR_8BYTES 0x20 /* 8 bytes */
|
||||
# define DCR_12BYTES 0x60 /* 12 bytes */
|
||||
|
||||
/* bits in transmit configuration register */
|
||||
#define TCR_CRC 0x01 /* inhibit CRC */
|
||||
#define TCR_ELC 0x06 /* encoded loopback control */
|
||||
# define TCR_NORMAL 0x00 /* ELC: normal operation */
|
||||
# define TCR_INTERNAL 0x02 /* ELC: internal loopback */
|
||||
# define TCR_0EXTERNAL 0x04 /* ELC: external loopback LPBK=0 */
|
||||
# define TCR_1EXTERNAL 0x06 /* ELC: external loopback LPBK=1 */
|
||||
#define TCR_ATD 0x08 /* auto transmit */
|
||||
#define TCR_OFST 0x10 /* collision offset enable (be nice) */
|
||||
|
||||
/* bits in transmit status register */
|
||||
#define TSR_PTX 0x01 /* packet transmitted (without error)*/
|
||||
#define TSR_DFR 0x02 /* transmit deferred */
|
||||
#define TSR_COL 0x04 /* transmit collided */
|
||||
#define TSR_ABT 0x08 /* transmit aborted */
|
||||
#define TSR_CRS 0x10 /* carrier sense lost */
|
||||
#define TSR_FU 0x20 /* fifo underrun */
|
||||
#define TSR_CDH 0x40 /* CD heartbeat */
|
||||
#define TSR_OWC 0x80 /* out of window collision */
|
||||
|
||||
/* bits in receive configuration register */
|
||||
#define RCR_SEP 0x01 /* save errored packets */
|
||||
#define RCR_AR 0x02 /* accept runt packets */
|
||||
#define RCR_AB 0x04 /* accept broadcast */
|
||||
#define RCR_AM 0x08 /* accept multicast */
|
||||
#define RCR_PRO 0x10 /* physical promiscuous */
|
||||
#define RCR_MON 0x20 /* monitor mode */
|
||||
|
||||
/* bits in receive status register */
|
||||
#define RSR_PRX 0x01 /* packet received intact */
|
||||
#define RSR_CRC 0x02 /* CRC error */
|
||||
#define RSR_FAE 0x04 /* frame alignment error */
|
||||
#define RSR_FO 0x08 /* FIFO overrun */
|
||||
#define RSR_MPA 0x10 /* missed packet */
|
||||
#define RSR_PHY 0x20 /* multicast address match !! */
|
||||
#define RSR_DIS 0x40 /* receiver disabled */
|
||||
|
||||
/* dp8390 configuration information */
|
||||
typedef struct {
|
||||
u_short dc_reg; /* dp8390 base address */
|
||||
u_long dc_mem; /* base memory */
|
||||
u_char dc_tpsr; /* transmit start page */
|
||||
u_char dc_pstart; /* receive start page */
|
||||
u_char dc_pstop; /* receive end page */
|
||||
} dpconf_t;
|
||||
|
||||
|
||||
/* dp8390 receive header */
|
||||
typedef struct {
|
||||
u_char dh_status; /* copy of rsr */
|
||||
u_char dh_next; /* pointer to next packet */
|
||||
u_char dh_rbcl; /* receive byte count low */
|
||||
u_char dh_rbch; /* receive byte count high */
|
||||
} dphdr_t;
|
||||
extern int dp8390_iobase;
|
||||
extern int dp8390_membase;
|
||||
extern int dp8390_memsize;
|
||||
#ifdef SUPPORT_WD80X3
|
||||
#ifdef SUPPORT_SMC_ULTRA
|
||||
extern int dp8390_is790;
|
||||
#else
|
||||
#define dp8390_is790 0
|
||||
#endif
|
||||
#else
|
||||
#ifdef SUPPORT_SMC_ULTRA
|
||||
#define dp8390_is790 1
|
||||
#endif
|
||||
#endif
|
||||
extern u_int8_t dp8390_cr_proto; /* values always set in CR */
|
||||
extern u_int8_t dp8390_dcr_reg; /* override DCR if LS is set */
|
||||
|
|
|
@ -1,266 +1,322 @@
|
|||
/* $NetBSD: wd80x3.c,v 1.4 1997/09/20 12:13:06 drochner Exp $ */
|
||||
/* $NetBSD: wd80x3.c,v 1.5 1998/02/16 11:22:00 drochner Exp $ */
|
||||
|
||||
/* stripped down from netbsd:sys/arch/i386/netboot/wd8x13.c */
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
|
||||
* NASA Ames Research Center.
|
||||
*
|
||||
* 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 NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* source in this file came from
|
||||
* the Mach ethernet boot written by Leendert van Doorn.
|
||||
* Device driver for National Semiconductor DS8390/WD83C690 based ethernet
|
||||
* adapters.
|
||||
*
|
||||
* A very simple network driver for WD80x3 boards that polls.
|
||||
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 1992 by Leendert van Doorn
|
||||
* Copyright (C) 1993, David Greenman. This software may be used, modified,
|
||||
* copied, distributed, and sold, in both source and binary form provided that
|
||||
* the above copyright and these terms are retained. Under no circumstances is
|
||||
* the author responsible for the proper functioning of this software, nor does
|
||||
* the author assume any responsibility for damages incurred with its use.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device driver for the Western Digital/SMC 8003 and 8013 series,
|
||||
* and the SMC Elite Ultra (8216).
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/pio.h>
|
||||
|
||||
#include <lib/libsa/stand.h>
|
||||
#include <lib/libkern/libkern.h>
|
||||
|
||||
#include <libi386.h>
|
||||
|
||||
#ifdef _STANDALONE
|
||||
#include <lib/libkern/libkern.h>
|
||||
#include <bootinfo.h>
|
||||
#endif
|
||||
|
||||
#include "etherdrv.h"
|
||||
#include <dev/ic/dp8390reg.h>
|
||||
#include "dp8390.h"
|
||||
#include <dev/isa/if_wereg.h>
|
||||
|
||||
#ifndef BASEREG
|
||||
#define BASEREG 0x240
|
||||
#define BASEMEM 0xd0000
|
||||
#endif
|
||||
|
||||
static int ourbasereg, ourbasemem;
|
||||
#define WD_BASEREG BASEREG
|
||||
#define WD_BASEMEM BASEMEM
|
||||
|
||||
/* configurable parameters */
|
||||
#define WD_BASEREG ourbasereg /* base register */
|
||||
/* the base address doesn't have to be particularly accurate - the
|
||||
board seems to pick up on addresses in the range a0000..effff.
|
||||
*/
|
||||
#define WD_BASEMEM ourbasemem /* base ram */
|
||||
|
||||
/* bit definitions for board features */
|
||||
#define INTERFACE_CHIP 01 /* has an WD83C583 interface chip */
|
||||
#define BOARD_16BIT 02 /* 16 bit board */
|
||||
#define SLOT_16BIT 04 /* 16 bit slot */
|
||||
|
||||
/* register offset definitions */
|
||||
#define WD_MSR 0x00 /* control (w) and status (r) */
|
||||
#define WD_REG0 0x00 /* generic register definitions */
|
||||
#define WD_REG1 0x01
|
||||
#define WD_REG2 0x02
|
||||
#define WD_REG3 0x03
|
||||
#define WD_REG4 0x04
|
||||
#define WD_REG5 0x05
|
||||
#define WD_REG6 0x06
|
||||
#define WD_REG7 0x07
|
||||
#define WD_EA0 0x08 /* most significant addr byte */
|
||||
#define WD_EA1 0x09
|
||||
#define WD_EA2 0x0A
|
||||
#define WD_EA3 0x0B
|
||||
#define WD_EA4 0x0C
|
||||
#define WD_EA5 0x0D /* least significant addr byte */
|
||||
#define WD_LTB 0x0E /* LAN type byte */
|
||||
#define WD_CHKSUM 0x0F /* sum from WD_EA0 upto here is 0xFF */
|
||||
#define WD_DP8390 0x10 /* natsemi chip */
|
||||
|
||||
/* bits in control register */
|
||||
#define WD_MSR_MEMMASK 0x3F /* memory enable bits mask */
|
||||
#define WD_MSR_MENABLE 0x40 /* memory enable */
|
||||
#define WD_MSR_RESET 0x80 /* software reset */
|
||||
|
||||
/* bits in bus size register */
|
||||
#define WD_BSR_16BIT 0x01 /* 16 bit bus */
|
||||
|
||||
/* bits in LA address register */
|
||||
#define WD_LAAR_A19 0x01 /* address lines for above 1Mb ram */
|
||||
#define WD_LAAR_LAN16E 0x40 /* enables 16bit shrd RAM for LAN */
|
||||
#define WD_LAAR_MEM16E 0x80 /* enables 16bit shrd RAM for host */
|
||||
|
||||
static u_char eth_myaddr[6];
|
||||
|
||||
static int boardid;
|
||||
static dpconf_t dpc;
|
||||
|
||||
static struct btinfo_netif bi_netif;
|
||||
|
||||
/*
|
||||
* Determine whether wd8003 hardware performs register aliasing
|
||||
* (i.e. whether it is an old WD8003E board).
|
||||
*/
|
||||
static int
|
||||
Aliasing(void) {
|
||||
if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1))
|
||||
return 0;
|
||||
if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2))
|
||||
return 0;
|
||||
if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3))
|
||||
return 0;
|
||||
if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4))
|
||||
return 0;
|
||||
if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether this board has 16-bit capabilities
|
||||
*/
|
||||
static int
|
||||
BoardIs16Bit(void) {
|
||||
u_char bsreg = inb(WD_BASEREG + WD_REG1);
|
||||
|
||||
outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT);
|
||||
delay(2000);
|
||||
if (inb(WD_BASEREG + WD_REG1) == bsreg) {
|
||||
/*
|
||||
* Pure magic: LTB is 0x05 indicates that this is a WD8013EB board,
|
||||
* 0x27 indicates that this is an WD8013 Elite board, and 0x29
|
||||
* indicates an SMC Elite 16 board.
|
||||
*/
|
||||
u_char tlb = inb(WD_BASEREG + WD_LTB);
|
||||
return tlb == 0x05 || tlb == 0x27 || tlb == 0x29
|
||||
#ifdef SUPPORT_SMC_ULTRA
|
||||
|| tlb == 0x2b
|
||||
#ifndef _STANDALONE
|
||||
extern int mapio __P((void));
|
||||
#endif
|
||||
;
|
||||
}
|
||||
outb(WD_BASEREG + WD_REG1, bsreg);
|
||||
return 1;
|
||||
|
||||
u_char eth_myaddr[6];
|
||||
|
||||
static u_int8_t we_type;
|
||||
static int we_is16bit;
|
||||
|
||||
#ifdef _STANDALONE
|
||||
static struct btinfo_netif bi_netif;
|
||||
#endif
|
||||
|
||||
const char *
|
||||
we_params()
|
||||
{
|
||||
const char *typestr;
|
||||
|
||||
dp8390_memsize = 8192;
|
||||
|
||||
we_type = inb(WD_BASEREG + WE_CARD_ID);
|
||||
switch (we_type) {
|
||||
#ifdef SUPPORT_WD80X3
|
||||
case WE_TYPE_WD8003S:
|
||||
typestr = "WD8003S";
|
||||
break;
|
||||
case WE_TYPE_WD8003E:
|
||||
typestr = "WD8003E";
|
||||
break;
|
||||
case WE_TYPE_WD8003EB:
|
||||
typestr = "WD8003EB";
|
||||
break;
|
||||
case WE_TYPE_WD8003W:
|
||||
typestr = "WD8003W";
|
||||
break;
|
||||
case WE_TYPE_WD8013EBT:
|
||||
typestr = "WD8013EBT";
|
||||
dp8390_memsize = 16384;
|
||||
we_is16bit = 1;
|
||||
break;
|
||||
case WE_TYPE_WD8013W:
|
||||
typestr = "WD8013W";
|
||||
dp8390_memsize = 16384;
|
||||
we_is16bit = 1;
|
||||
break;
|
||||
case WE_TYPE_WD8013EP: /* also WD8003EP */
|
||||
if (inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) {
|
||||
we_is16bit = 1;
|
||||
dp8390_memsize = 16384;
|
||||
typestr = "WD8013EP";
|
||||
} else
|
||||
typestr = "WD8003EP";
|
||||
break;
|
||||
case WE_TYPE_WD8013WC:
|
||||
typestr = "WD8013WC";
|
||||
dp8390_memsize = 16384;
|
||||
we_is16bit = 1;
|
||||
break;
|
||||
case WE_TYPE_WD8013EBP:
|
||||
typestr = "WD8013EBP";
|
||||
dp8390_memsize = 16384;
|
||||
we_is16bit = 1;
|
||||
break;
|
||||
case WE_TYPE_WD8013EPC:
|
||||
typestr = "WD8013EPC";
|
||||
dp8390_memsize = 16384;
|
||||
we_is16bit = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef SUPPORT_SMC_ULTRA
|
||||
case WE_TYPE_SMC8216C:
|
||||
case WE_TYPE_SMC8216T:
|
||||
{
|
||||
u_int8_t hwr;
|
||||
|
||||
typestr = (we_type == WE_TYPE_SMC8216C) ?
|
||||
"SMC8216/SMC8216C" : "SMC8216T";
|
||||
|
||||
hwr = inb(WD_BASEREG + WE790_HWR);
|
||||
outb(WD_BASEREG + WE790_HWR, hwr | WE790_HWR_SWH);
|
||||
switch (inb(WD_BASEREG + WE790_RAR) & WE790_RAR_SZ64) {
|
||||
case WE790_RAR_SZ64:
|
||||
dp8390_memsize = 65536;
|
||||
break;
|
||||
case WE790_RAR_SZ32:
|
||||
dp8390_memsize = 32768;
|
||||
break;
|
||||
case WE790_RAR_SZ16:
|
||||
dp8390_memsize = 16384;
|
||||
break;
|
||||
case WE790_RAR_SZ8:
|
||||
/* 8216 has 16K shared mem -- 8416 has 8K */
|
||||
typestr = (we_type == WE_TYPE_SMC8216C) ?
|
||||
"SMC8416C/SMC8416BT" : "SMC8416T";
|
||||
dp8390_memsize = 8192;
|
||||
break;
|
||||
}
|
||||
outb(WD_BASEREG + WE790_HWR, hwr);
|
||||
|
||||
we_is16bit = 1;
|
||||
#ifdef SUPPORT_WD80X3
|
||||
dp8390_is790 = 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
/* Not one we recognize. */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make some adjustments to initial values depending on what is
|
||||
* found in the ICR.
|
||||
*/
|
||||
if (we_is16bit && (we_type != WE_TYPE_WD8013EBT) &&
|
||||
(inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) == 0) {
|
||||
we_is16bit = 0;
|
||||
dp8390_memsize = 8192;
|
||||
}
|
||||
|
||||
#ifdef WE_DEBUG
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
|
||||
"memsize = %d\n", we_type, typestr, we_is16bit, dp8390_memsize);
|
||||
for (i = 0; i < 8; i++)
|
||||
printf(" %d -> 0x%x\n", i,
|
||||
inb(WD_BASEREG + i));
|
||||
}
|
||||
#endif
|
||||
|
||||
return (typestr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the 16 bit capable board is plugged
|
||||
* into a 16 bit slot.
|
||||
*/
|
||||
static int
|
||||
SlotIs16Bit(void) {
|
||||
return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset ethernet board after a timeout
|
||||
*/
|
||||
static void
|
||||
edreset() {
|
||||
int dpreg = dpc.dc_reg;
|
||||
/* initialize the board */
|
||||
outb(WD_BASEREG + WD_MSR,
|
||||
WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK));
|
||||
|
||||
/* reset dp8390 ethernet chip */
|
||||
outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT);
|
||||
|
||||
/* initialize first register set */
|
||||
outb(dpreg + DP_IMR, 0);
|
||||
outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT);
|
||||
outb(dpreg + DP_TPSR, dpc.dc_tpsr);
|
||||
outb(dpreg + DP_PSTART, dpc.dc_pstart);
|
||||
outb(dpreg + DP_PSTOP, dpc.dc_pstop);
|
||||
outb(dpreg + DP_BNRY, dpc.dc_pstart);
|
||||
outb(dpreg + DP_RCR, RCR_MON);
|
||||
outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST);
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES);
|
||||
else
|
||||
outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES);
|
||||
outb(dpreg + DP_RBCR0, 0);
|
||||
outb(dpreg + DP_RBCR1, 0);
|
||||
outb(dpreg + DP_ISR, 0xFF);
|
||||
|
||||
/* initialize second register set */
|
||||
outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT);
|
||||
outb(dpreg + DP_PAR0, eth_myaddr[0]);
|
||||
outb(dpreg + DP_PAR1, eth_myaddr[1]);
|
||||
outb(dpreg + DP_PAR2, eth_myaddr[2]);
|
||||
outb(dpreg + DP_PAR3, eth_myaddr[3]);
|
||||
outb(dpreg + DP_PAR4, eth_myaddr[4]);
|
||||
outb(dpreg + DP_PAR5, eth_myaddr[5]);
|
||||
outb(dpreg + DP_CURR, dpc.dc_pstart+1);
|
||||
|
||||
/* and back to first register set */
|
||||
outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT);
|
||||
outb(dpreg + DP_RCR, RCR_AB);
|
||||
|
||||
/* flush counters */
|
||||
(void) inb(dpreg + DP_CNTR0);
|
||||
(void) inb(dpreg + DP_CNTR1);
|
||||
(void) inb(dpreg + DP_CNTR2);
|
||||
|
||||
/* and go ... */
|
||||
outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the WD80X3 board
|
||||
*/
|
||||
int
|
||||
EtherInit(myadr)
|
||||
char *myadr;
|
||||
{
|
||||
unsigned sum;
|
||||
int memsize;
|
||||
int i;
|
||||
const char *typestr;
|
||||
u_int8_t x;
|
||||
int i;
|
||||
u_int8_t laar_proto;
|
||||
u_int8_t msr_proto;
|
||||
|
||||
ourbasereg = BASEREG;
|
||||
ourbasemem = BASEMEM;
|
||||
dp8390_iobase = WD_BASEREG + WE_NIC_OFFSET;
|
||||
dp8390_membase = WD_BASEMEM;
|
||||
|
||||
/* reset the ethernet card */
|
||||
outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
|
||||
delay(2000);
|
||||
outb(WD_BASEREG + WD_MSR, 0);
|
||||
|
||||
/* determine whether the controller is there */
|
||||
sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) +
|
||||
inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) +
|
||||
inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) +
|
||||
inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM);
|
||||
if ((sum & 0xFF) != 0xFF)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Determine the type of board
|
||||
*/
|
||||
boardid = 0;
|
||||
if (!Aliasing()) {
|
||||
if (BoardIs16Bit()) {
|
||||
boardid |= BOARD_16BIT;
|
||||
if (SlotIs16Bit())
|
||||
boardid |= SLOT_16BIT;
|
||||
}
|
||||
}
|
||||
memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */
|
||||
|
||||
/* special setup needed for WD8013 boards */
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E);
|
||||
|
||||
/* get ethernet address */
|
||||
for(i = 0; i < 6; i++)
|
||||
eth_myaddr[i] = myadr[i]= inb(WD_BASEREG + WD_EA0 + i);
|
||||
|
||||
/* save settings for future use */
|
||||
dpc.dc_reg = WD_BASEREG + WD_DP8390;
|
||||
dpc.dc_mem = WD_BASEMEM;
|
||||
dpc.dc_tpsr = 0;
|
||||
dpc.dc_pstart = 6;
|
||||
dpc.dc_pstop = (memsize >> 8) & 0xFF;
|
||||
|
||||
printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize);
|
||||
|
||||
edreset();
|
||||
|
||||
#ifdef SUPPORT_SMC_ULTRA
|
||||
outb(WD_BASEREG + 0, 0x40);
|
||||
outb(WD_BASEREG + 5, 0x80);
|
||||
outb(WD_BASEREG + 6, 0x1);
|
||||
#ifndef _STANDALONE
|
||||
if (mapio()) {
|
||||
printf("no IO access\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
strncpy(bi_netif.ifname, "ed", sizeof(bi_netif.ifname));
|
||||
bi_netif.bus = BI_BUS_ISA;
|
||||
bi_netif.addr.iobase = WD_BASEREG;
|
||||
for (x = 0, i = 0; i < 8; i++)
|
||||
x += inb(WD_BASEREG + WE_PROM + i);
|
||||
|
||||
BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
|
||||
if (x != WE_ROM_CHECKSUM_TOTAL)
|
||||
return(0);
|
||||
|
||||
return 1;
|
||||
/* reset the ethernet card */
|
||||
outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
|
||||
delay(100);
|
||||
outb(WD_BASEREG + WE_MSR, inb(WD_BASEREG + WE_MSR) & ~WE_MSR_RST);
|
||||
delay(5000);
|
||||
|
||||
typestr = we_params();
|
||||
if (!typestr)
|
||||
return(0);
|
||||
|
||||
printf("Using %s board, port 0x%x, iomem 0x%x, iosiz %d\n",
|
||||
typestr, WD_BASEREG, WD_BASEMEM, dp8390_memsize);
|
||||
|
||||
/* get ethernet address */
|
||||
for(i = 0; i < 6; i++)
|
||||
eth_myaddr[i] = myadr[i]= inb(WD_BASEREG + WE_PROM + i);
|
||||
|
||||
/*
|
||||
* Set upper address bits and 8/16 bit access to shared memory.
|
||||
*/
|
||||
if (dp8390_is790) {
|
||||
laar_proto = inb(WD_BASEREG + WE_LAAR) & ~WE_LAAR_M16EN;
|
||||
outb(WD_BASEREG + WE_LAAR, laar_proto |
|
||||
(we_is16bit ? WE_LAAR_M16EN : 0));
|
||||
} else if ((we_type & WE_SOFTCONFIG) ||
|
||||
(we_type == WE_TYPE_WD8013EBT)) {
|
||||
laar_proto = (WD_BASEMEM >> 19) & WE_LAAR_ADDRHI;
|
||||
if (we_is16bit)
|
||||
laar_proto |= WE_LAAR_L16EN;
|
||||
outb(WD_BASEREG + WE_LAAR, laar_proto |
|
||||
(we_is16bit ? WE_LAAR_M16EN : 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set address and enable interface shared memory.
|
||||
*/
|
||||
if (dp8390_is790) {
|
||||
/* XXX MAGIC CONSTANTS XXX */
|
||||
x = inb(WD_BASEREG + 0x04);
|
||||
outb(WD_BASEREG + 0x04, x | 0x80);
|
||||
outb(WD_BASEREG + 0x0b,
|
||||
((WD_BASEMEM >> 13) & 0x0f) |
|
||||
((WD_BASEMEM >> 11) & 0x40) |
|
||||
(inb(WD_BASEREG + 0x0b) & 0xb0));
|
||||
outb(WD_BASEREG + 0x04, x);
|
||||
msr_proto = 0x00;
|
||||
dp8390_cr_proto = 0x00;
|
||||
} else {
|
||||
msr_proto = (WD_BASEMEM >> 13) & WE_MSR_ADDR;
|
||||
dp8390_cr_proto = ED_CR_RD2;
|
||||
}
|
||||
|
||||
outb(WD_BASEREG + WE_MSR, msr_proto | WE_MSR_MENB);
|
||||
delay(2);
|
||||
|
||||
/*
|
||||
* DCR gets:
|
||||
*
|
||||
* FIFO threshold to 8, No auto-init Remote DMA,
|
||||
* byte order=80x86.
|
||||
*
|
||||
* 16-bit cards also get word-wide DMA transfers.
|
||||
*/
|
||||
dp8390_dcr_reg = ED_DCR_FT1 | ED_DCR_LS | (we_is16bit ? ED_DCR_WTS : 0);
|
||||
|
||||
if (dp8390_config())
|
||||
return(0);
|
||||
|
||||
#ifdef _STANDALONE
|
||||
strncpy(bi_netif.ifname, "we", sizeof(bi_netif.ifname));
|
||||
bi_netif.bus = BI_BUS_ISA;
|
||||
bi_netif.addr.iobase = WD_BASEREG;
|
||||
|
||||
BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -268,191 +324,8 @@ char *myadr;
|
|||
*/
|
||||
void
|
||||
EtherStop(void) {
|
||||
/* stop dp8390, followed by a board reset */
|
||||
outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT);
|
||||
outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
|
||||
outb(WD_BASEREG + WD_MSR, 0);
|
||||
/* stop dp8390, followed by a board reset */
|
||||
dp8390_stop();
|
||||
outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
|
||||
outb(WD_BASEREG + WE_MSR, 0);
|
||||
}
|
||||
|
||||
/* TBD - all users must take care to use the current "data seg" value
|
||||
when moving data from/to the controller */
|
||||
static void
|
||||
WdCopyIn(u_long src, void *dst, u_long count) {
|
||||
#if TRACE > 0
|
||||
printf("WdCopy from %x to %x for %d\n", src, dst, count);
|
||||
#endif
|
||||
/* assert(count <= 1514); */
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(WD_BASEREG + WD_REG5,
|
||||
WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
|
||||
pvbcopy(src, dst, count);
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
|
||||
}
|
||||
static void
|
||||
WdCopyOut(void *src, u_long dst, u_long count) {
|
||||
#if TRACE > 0
|
||||
printf("WdCopy from %x to %x for %d\n", src, dst, count);
|
||||
#endif
|
||||
/* assert(count <= 1514); */
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(WD_BASEREG + WD_REG5,
|
||||
WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
|
||||
vpbcopy(src, dst, count);
|
||||
if (boardid & SLOT_16BIT)
|
||||
outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an ethernet packet to destination 'dest'
|
||||
*/
|
||||
int
|
||||
EtherSend(pkt, len)
|
||||
char *pkt;
|
||||
int len;
|
||||
{
|
||||
int newlen=len;
|
||||
if (newlen < 60)
|
||||
newlen = 60;
|
||||
|
||||
#if TRACE > 0
|
||||
{
|
||||
int i;
|
||||
DUMP_STRUCT("EtherSend: pkt", pkt, len);
|
||||
#if 0
|
||||
for(i=0; i<(len<MDUMP?len:MDUMP); i++) printe("%x ", *((u_char*)(pkt+i)));
|
||||
printe("\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt), dpc.dc_mem + (dpc.dc_tpsr << 8), len);
|
||||
#endif
|
||||
WdCopyOut(pkt,
|
||||
dpc.dc_mem + (dpc.dc_tpsr << 8), newlen);
|
||||
outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
|
||||
outb(dpc.dc_reg + DP_TBCR0, (newlen & 0xFF));
|
||||
outb(dpc.dc_reg + DP_TBCR1, (newlen >> 8) & 0xFF);
|
||||
outb(dpc.dc_reg + DP_CR, CR_TXP);
|
||||
|
||||
#if 0
|
||||
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
|
||||
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (len & 0xFF));
|
||||
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (len >> 8) & 0xFF);
|
||||
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy dp8390 packet header for observation
|
||||
*/
|
||||
static void
|
||||
GetHeader(u_long haddr, dphdr_t *dph) {
|
||||
#if TRACE > 0
|
||||
printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t));
|
||||
#endif
|
||||
WdCopyIn(haddr, dph, sizeof(dphdr_t));
|
||||
#if 0
|
||||
DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll the dp8390 just see if there's an Ethernet packet
|
||||
* available. If there is, its contents is returned in a
|
||||
* pkt structure, otherwise a nil pointer is returned.
|
||||
*/
|
||||
int
|
||||
EtherReceive(pkt, maxlen)
|
||||
char *pkt;
|
||||
int maxlen;
|
||||
{
|
||||
u_char pageno, curpage, nextpage;
|
||||
int dpreg = dpc.dc_reg;
|
||||
dphdr_t dph;
|
||||
u_long addr;
|
||||
|
||||
if (inb(dpreg + DP_RSR) & RSR_PRX) {
|
||||
int len;
|
||||
|
||||
/* get current page numbers */
|
||||
pageno = inb(dpreg + DP_BNRY) + 1;
|
||||
if (pageno == dpc.dc_pstop)
|
||||
pageno = dpc.dc_pstart;
|
||||
outb(dpreg + DP_CR, CR_PS_P1);
|
||||
curpage = inb(dpreg + DP_CURR);
|
||||
outb(dpreg + DP_CR, CR_PS_P0);
|
||||
if (pageno == curpage)
|
||||
return 0;
|
||||
|
||||
/* get packet header */
|
||||
addr = dpc.dc_mem + (pageno << 8);
|
||||
GetHeader(addr, &dph);
|
||||
nextpage = dph.dh_next;
|
||||
|
||||
len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF);
|
||||
len -= sizeof(dphdr_t);
|
||||
if (len > 1514) /* bug in dp8390 */
|
||||
len = 1514;
|
||||
|
||||
if(len>maxlen){
|
||||
/* release occupied pages */
|
||||
if (nextpage == dpc.dc_pstart)
|
||||
nextpage = dpc.dc_pstop;
|
||||
outb(dpreg + DP_BNRY, nextpage - 1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
#if TRACE > 0
|
||||
{
|
||||
int i;
|
||||
printe("EtherReceive %d bytes: ", len);
|
||||
printe("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The dp8390 maintains a circular buffer of pages (256 bytes)
|
||||
* in which incomming ethernet packets are stored. The following
|
||||
* if detects wrap arounds, and copies the ethernet packet to
|
||||
* our local buffer in two chunks if necesarry.
|
||||
*/
|
||||
/* assert(len <= (6 << 8));*/
|
||||
if (nextpage < pageno && nextpage > dpc.dc_pstart) {
|
||||
u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t);
|
||||
if(nbytes>len)printf("ep0: fatal size error\n");
|
||||
/* assert(nbytes <= (6 << 8));*/
|
||||
#if TRACE > 0
|
||||
printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt), nbytes);
|
||||
#endif
|
||||
WdCopyIn(addr + sizeof(dphdr_t),
|
||||
pkt, nbytes);
|
||||
if ((len - nbytes) > 0)
|
||||
/* TBD - this OK? */
|
||||
#if TRACE > 0
|
||||
printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt) + nbytes, len - nbytes);
|
||||
#endif
|
||||
WdCopyIn(dpc.dc_mem + (dpc.dc_pstart << 8),
|
||||
pkt + nbytes,
|
||||
len - nbytes);
|
||||
} else {
|
||||
#if TRACE > 0
|
||||
printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt), len);
|
||||
#endif
|
||||
WdCopyIn(addr + sizeof(dphdr_t),
|
||||
pkt, len);
|
||||
}
|
||||
|
||||
/* release occupied pages */
|
||||
if (nextpage == dpc.dc_pstart)
|
||||
nextpage = dpc.dc_pstop;
|
||||
outb(dpreg + DP_BNRY, nextpage - 1);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue