/**************************************************************************
Author: Martin Renters
Date: May/94
This code is based heavily on David Greenman's if_ed.c driver
Copyright (C) 1993-1994, David Greenman, Martin Renters.
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 are the authors responsible for
the proper functioning of this software, nor do the authors assume any
responsibility for damages incurred with its use.
Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
**************************************************************************/
#include "etherboot.h"
#include "nic.h"
#include "ns8390.h"
#ifdef INCLUDE_NS8390
#include "pci.h"
#else
#include "isa.h"
#endif
#ifdef INCLUDE_WD
static unsigned char eth_laar;
#endif
static unsigned char eth_drain_receiver;
#ifdef INCLUDE_WD
static struct wd_board {
const char *name;
char id;
char flags;
char memsize;
} wd_boards[] = {
TYPE_WD8013EP, 0, MEM_8192},
{NULL, 0, 0, 0}
};
#endif
#ifdef INCLUDE_3C503
#endif
#if defined(INCLUDE_WD)
#endif
#endif
#if defined(INCLUDE_3C503)
#endif
#endif
#if defined(INCLUDE_NE)
#endif
#endif
#if defined(INCLUDE_NS8390)
#endif
#endif
#if defined(INCLUDE_3C503)
#else
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
#endif
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
/**************************************************************************
ETH_PIO_READ - Read a frame via Programmed I/O
**************************************************************************/
{
#ifdef INCLUDE_WD
#else
#ifdef INCLUDE_3C503
#endif
#endif
if (eth_flags & FLAG_16BIT)
while(cnt--) {
#ifdef INCLUDE_3C503
;
#endif
if (eth_flags & FLAG_16BIT) {
dst += 2;
}
else
}
#ifdef INCLUDE_3C503
#endif
}
/**************************************************************************
ETH_PIO_WRITE - Write a frame via Programmed I/O
**************************************************************************/
{
#ifdef COMPEX_RL2000_FIX
unsigned int x;
#endif /* COMPEX_RL2000_FIX */
#ifdef INCLUDE_WD
#else
#ifdef INCLUDE_3C503
#endif
#endif
if (eth_flags & FLAG_16BIT)
while(cnt--)
{
#ifdef INCLUDE_3C503
;
#endif
if (eth_flags & FLAG_16BIT) {
src += 2;
}
else
}
#ifdef INCLUDE_3C503
#else
#ifdef COMPEX_RL2000_FIX
for (x = 0;
x < COMPEX_RL2000_TRIES &&
!= D8390_ISR_RDC;
++x);
if (x >= COMPEX_RL2000_TRIES)
printf("Warning: Compex RL2000 aborted wait!\n");
#endif /* COMPEX_RL2000_FIX */
#ifndef INCLUDE_WD
!= D8390_ISR_RDC);
#endif
#endif
}
#else
/**************************************************************************
ETH_PIO_READ - Dummy routine when NE2000 not compiled in
**************************************************************************/
static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {}
#endif
/**************************************************************************
enable_multycast - Enable Multicast
**************************************************************************/
{
int i;
for(i=0;i<8;i++)
{
}
}
/**************************************************************************
NS8390_RESET - Reset adapter
**************************************************************************/
{
int i;
eth_drain_receiver = 0;
#ifdef INCLUDE_WD
else
#endif
if (eth_flags & FLAG_16BIT)
else
#ifdef INCLUDE_WD
#ifdef WD_790_PIO
#else
#endif
}
#endif
#ifdef INCLUDE_WD
else
#endif
for (i=0; i<ETH_ALEN; i++)
for (i=0; i<ETH_ALEN; i++)
#ifdef INCLUDE_WD
else
#endif
#ifdef INCLUDE_3C503
/*
* No way to tell whether or not we're supposed to use
* the 3Com's transceiver unless the user tells us.
* 'flags' should have some compile time default value
* which can be changed from the command menu.
*/
#endif
}
#ifndef INCLUDE_3C503
/**************************************************************************
ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
**************************************************************************/
{
int start_time;
#ifdef INCLUDE_WD
else
#endif
/* wait for at least 1.6ms - we wait one timer tick */
start_time = currticks();
/* Nothing */;
/*
* Linux driver checks for interrupted TX here. This is not necessary,
* because the transmit routine waits until the frame is sent.
*/
/* enter loopback mode and restart NIC */
#ifdef INCLUDE_WD
else
#endif
/* clear the RX ring, acknowledge overrun interrupt */
eth_drain_receiver = 1;
/* Nothing */;
eth_drain_receiver = 0;
/* leave loopback mode - no packets to be resent (see Linux driver) */
}
#endif /* INCLUDE_3C503 */
/**************************************************************************
NS8390_TRANSMIT - Transmit a frame
**************************************************************************/
static void ns8390_transmit(
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
#endif
#ifdef INCLUDE_3C503
*((char *)eth_vmem+13) = t;
s += ETH_HLEN;
}
#endif
#ifdef INCLUDE_WD
if (eth_flags & FLAG_16BIT) {
inb(0x84);
}
#ifndef WD_790_PIO
/* Memory interface */
inb(0x84);
}
inb(0x84);
*((char *)eth_vmem+13) = t;
s += ETH_HLEN;
inb(0x84);
}
#else
inb(0x84);
#endif
#endif
#if defined(INCLUDE_3C503)
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
{
/* Programmed I/O */
unsigned short type;
/* bcc generates worse code without (const+const) below */
s += ETH_HLEN;
}
#endif
#if defined(INCLUDE_3C503)
#endif
#ifdef INCLUDE_WD
if (eth_flags & FLAG_16BIT) {
inb(0x84);
}
else
#endif
#ifdef INCLUDE_WD
else
#endif
}
/**************************************************************************
NS8390_POLL - Wait for a frame
**************************************************************************/
{
int ret = 0;
unsigned short pktoff;
unsigned char *p;
#ifndef INCLUDE_3C503
/* avoid infinite recursion: see eth_rx_overrun() */
return(0);
}
#endif /* INCLUDE_3C503 */
if (!(rstat & D8390_RSTAT_PRX)) return(0);
if ( ! retrieve ) return 1;
#ifdef INCLUDE_WD
if (eth_flags & FLAG_16BIT) {
inb(0x84);
}
#ifndef WD_790_PIO
inb(0x84);
}
#endif
inb(0x84);
#endif
else
/* incoming length includes FCS so must sub 4 */
|| len > ETH_FRAME_LEN) {
printf("Bogus packet, ignoring\n");
return (0);
}
else {
/* read first part */
else
p += frag;
}
/* read second part */
else
ret = 1;
}
#ifdef INCLUDE_WD
#ifndef WD_790_PIO
inb(0x84);
}
#endif
if (eth_flags & FLAG_16BIT) {
inb(0x84);
}
inb(0x84);
#endif
if (next == eth_rx_start)
next = eth_memsize;
return(ret);
}
/**************************************************************************
NS8390_DISABLE - Turn off adapter
**************************************************************************/
{
/* reset and disable merge */
}
/**************************************************************************
NS8390_IRQ - Enable, Disable, or Force interrupts
**************************************************************************/
{
switch ( action ) {
case DISABLE :
break;
case ENABLE :
break;
case FORCE :
break;
}
}
/**************************************************************************
ETH_PROBE - Look for an adapter
**************************************************************************/
#ifdef INCLUDE_NS8390
#else
#endif
{
int i;
#ifdef INCLUDE_NS8390
#endif
eth_drain_receiver = 0;
#ifdef INCLUDE_WD
{
/******************************************************************
******************************************************************/
unsigned short chksum;
unsigned char c;
eth_asic_base += 0x20) {
chksum = 0;
for (i=8; i<16; i++)
/* Extra checks to avoid soundcard */
break;
}
if (eth_asic_base > WD_HIGH_BASE)
return (0);
/* We've found a board */
return (0); /* Unknown type */
}
eth_tx_start = 0;
if ((c == TYPE_WD8013EP) &&
}
eth_bmem = (0x80000 |
} else
/* from Linux driver, 8416BT detects as 8216 sometimes */
brd += 2;
}
}
for (i=0; i<ETH_ALEN; i++) {
}
#ifdef WD_790_PIO
eth_bmem = 0;
#else
#endif
} else {
}
if (eth_flags & FLAG_16BIT) {
} else {
/*
The previous line used to be
WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
it work for WD8013s. This seems to work for my 8013 boards. I
don't know what is really happening. I wish I had data sheets
or more time to decode the Linux driver. - Ken
*/
}
inb(0x84);
}
}
#endif
#ifdef INCLUDE_3C503
#ifdef T503_AUI
#else
#endif
/******************************************************************
******************************************************************/
if (eth_vendor == VENDOR_NONE) {
int idx;
static unsigned short base[] = {
0x300, 0x310, 0x330, 0x350,
0x250, 0x280, 0x2A0, 0x2E0, 0 };
/* Loop through possible addresses checking each one */
/*
* Note that we use the same settings for both 8 and 16 bit cards:
* both have an 8K bank of memory at page 1 while only the 16 bit
* cards have a bank at page 0.
*/
eth_tx_start = 32;
/* Check our base address. iobase and membase should */
/* both have a maximum of 1 bit set or be 0. */
continue; /* nope */
/* Now get the shared memory address */
eth_flags = 0;
switch (membase_reg) {
case _3COM_PCFR_DC000:
eth_bmem = 0xdc000;
break;
case _3COM_PCFR_D8000:
eth_bmem = 0xd8000;
break;
case _3COM_PCFR_CC000:
eth_bmem = 0xcc000;
break;
case _3COM_PCFR_C8000:
eth_bmem = 0xc8000;
break;
case _3COM_PCFR_PIO:
eth_bmem = 0;
break;
default:
continue; /* nope */
}
break;
}
return (0);
#ifndef T503_SHMEM
eth_bmem = 0;
#endif
/* Need this to make ns8390_poll() happy. */
/* Reset NIC and ASIC */
/* Get our ethernet address */
printf("PIO mode");
else
for (i=0; i<ETH_ALEN; i++) {
}
/*
* Initialize GA configuration register. Set bank and enable shared
* mem. We always use bank 1. Disable interrupts.
*/
/*
* Clear memory and verify that it worked (we use only 8K)
*/
for(i = 0; i < 0x2000; ++i)
if (*((char *)(bus_to_virt(eth_bmem+i)))) {
printf ("Failed to clear 3c503 shared mem.\n");
return (0);
}
}
/*
*/
}
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
{
/******************************************************************
******************************************************************/
unsigned char c;
if (eth_vendor == VENDOR_NONE) {
int idx;
static unsigned short base[] = {
#ifdef NE_SCAN
#endif
0 };
/* if no addresses supplied, fall back on defaults */
if (probe_addrs == 0 || probe_addrs[0] == 0)
probe_addrs = base;
eth_bmem = 0; /* No shared memory */
eth_tx_start = 32;
inb(0x84);
#ifdef NS8390_FORCE_16BIT
#endif
break;
eth_flags |= FLAG_16BIT;
eth_tx_start = 64;
break;
}
if (eth_nic_base == 0)
return (0);
eth_flags |= FLAG_16BIT;
for (i=0; i<ETH_ALEN; i++) {
}
printf("\nNE%c000 base %#hx, addr %!\n",
}
}
#endif
if (eth_vendor == VENDOR_NONE)
return(0);
if (eth_vendor != VENDOR_3COM)
/* Based on PnP ISA map */
#ifdef INCLUDE_WD
#endif
#ifdef INCLUDE_3C503
#endif
#ifdef INCLUDE_NE
#endif
return 1;
}
#ifdef INCLUDE_WD
.type = NIC_DRIVER,
.name = "WD",
.ioaddrs = 0,
};
#endif
#ifdef INCLUDE_3C503
.type = NIC_DRIVER,
.name = "3C503",
.probe = t503_probe,
.ioaddrs = 0,
};
#endif
#ifdef INCLUDE_NE
.type = NIC_DRIVER,
.name = "NE*000",
.ioaddrs = 0,
};
#endif
#ifdef INCLUDE_NS8390
/* A few NE2000 PCI clones, list not exhaustive */
};
.type = NIC_DRIVER,
.probe = nepci_probe,
.ids = nepci_nics,
.class = 0,
};
#endif /* INCLUDE_NS8390 */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/