Import of dpeth 3c501/3c509b/.. ethernet driver by
Giovanni Falzoni <fgalzoni@inwind.it>.
This commit is contained in:
parent
81081a4063
commit
6be8c4d8a3
25 changed files with 4424 additions and 13 deletions
|
@ -23,4 +23,4 @@ all install depend clean:
|
||||||
cd ./printer && $(MAKE) $@
|
cd ./printer && $(MAKE) $@
|
||||||
cd ./rtl8139 && $(MAKE) $@
|
cd ./rtl8139 && $(MAKE) $@
|
||||||
cd ./fxp && $(MAKE) $@
|
cd ./fxp && $(MAKE) $@
|
||||||
|
cd ./dpeth && $(MAKE) $@
|
||||||
|
|
428
drivers/dpeth/3c501.c
Normal file
428
drivers/dpeth/3c501.c
Normal file
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
** File: 3c501.c Jan. 14, 1997
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains specific implementation of the ethernet
|
||||||
|
** device driver for 3Com Etherlink (3c501) boards. This is a
|
||||||
|
** very old board and its performances are very poor for today
|
||||||
|
** network environments.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <minix/com.h>
|
||||||
|
#include <net/hton.h>
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if (ENABLE_NETWORKING == 1 && ENABLE_3C501 == 1)
|
||||||
|
|
||||||
|
#include "3c501.h"
|
||||||
|
|
||||||
|
static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
|
||||||
|
static buff_t *TxBuff = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_getstats(dpeth_t *dep)
|
||||||
|
** Function: Reads statistics counters from board.
|
||||||
|
**/
|
||||||
|
static void el1_getstats(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
return; /* Nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_reset(dpeth_t *dep)
|
||||||
|
** Function: Reset function specific for Etherlink hardware.
|
||||||
|
*/
|
||||||
|
static void el1_reset(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
for (ix = 0; ix < 8; ix += 1) /* Resets the board */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RESET);
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||||
|
|
||||||
|
/* Set Ethernet Address on controller */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */
|
||||||
|
for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
|
||||||
|
outb_el1(dep, ix, StationAddress[ix]);
|
||||||
|
|
||||||
|
lock();
|
||||||
|
/* Enable DMA/Interrupt, gain control of Buffer */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||||
|
/* Clear RX packet area */
|
||||||
|
outw_el1(dep, EL1_RECVPTR, 0);
|
||||||
|
/* Enable transmit/receive configuration and flush pending interrupts */
|
||||||
|
outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
|
||||||
|
outb_el1(dep, EL1_RECV, dep->de_recv_mode);
|
||||||
|
inb_el1(dep, EL1_RECV);
|
||||||
|
inb_el1(dep, EL1_XMIT);
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||||
|
unlock();
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size)
|
||||||
|
** Function: Dumps counter on screen (support for console display).
|
||||||
|
*/
|
||||||
|
static void el1_dumpstats(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_mode_init(dpeth_t *dep)
|
||||||
|
** Function: Initializes receicer mode
|
||||||
|
*/
|
||||||
|
static void el1_mode_init(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dep->de_flags & DEF_BROAD) {
|
||||||
|
dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
|
||||||
|
|
||||||
|
} else if (dep->de_flags & DEF_PROMISC) {
|
||||||
|
dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
|
||||||
|
|
||||||
|
} else if (dep->de_flags & DEF_MULTI) {
|
||||||
|
dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
|
||||||
|
}
|
||||||
|
outb_el1(dep, EL1_RECV, dep->de_recv_mode);
|
||||||
|
inb_el1(dep, EL1_RECV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_recv(dpeth_t *dep, int from, int size)
|
||||||
|
** Function: Receive function. Called from interrupt handler to
|
||||||
|
** unload recv. buffer or from main (packet to client)
|
||||||
|
*/
|
||||||
|
static void el1_recv(dpeth_t * dep, int from, int size)
|
||||||
|
{
|
||||||
|
buff_t *rxptr;
|
||||||
|
|
||||||
|
while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
|
||||||
|
|
||||||
|
/* Remove buffer from queue and free buffer */
|
||||||
|
lock();
|
||||||
|
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||||
|
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||||
|
else
|
||||||
|
dep->de_recvq_head = rxptr->next;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
/* Copy buffer to user area */
|
||||||
|
mem2user(dep, rxptr);
|
||||||
|
|
||||||
|
/* Reply information */
|
||||||
|
dep->de_read_s = rxptr->size;
|
||||||
|
dep->de_flags |= DEF_ACK_RECV;
|
||||||
|
dep->de_flags &= NOT(DEF_READING);
|
||||||
|
|
||||||
|
/* Return buffer to the idle pool */
|
||||||
|
free_buff(dep, rxptr);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_send(dpeth_t *dep, int from_int, int pktsize)
|
||||||
|
** Function: Send function. Called from main to transit a packet or
|
||||||
|
** from interrupt handler when a new packet was queued.
|
||||||
|
*/
|
||||||
|
static void el1_send(dpeth_t * dep, int from_int, int pktsize)
|
||||||
|
{
|
||||||
|
buff_t *txbuff;
|
||||||
|
clock_t now;
|
||||||
|
|
||||||
|
if (from_int == FALSE) {
|
||||||
|
|
||||||
|
if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) {
|
||||||
|
|
||||||
|
/* Fill transmit buffer from user area */
|
||||||
|
txbuff->next = NULL;
|
||||||
|
txbuff->size = pktsize;
|
||||||
|
txbuff->client = dep->de_client;
|
||||||
|
user2mem(dep, txbuff);
|
||||||
|
} else
|
||||||
|
panic(dep->de_name, "out of memory for Tx", NO_NUM);
|
||||||
|
|
||||||
|
} else if ((txbuff = dep->de_xmitq_head) != NULL) {
|
||||||
|
|
||||||
|
/* Get first packet in queue */
|
||||||
|
lock();
|
||||||
|
if (dep->de_xmitq_tail == dep->de_xmitq_head)
|
||||||
|
dep->de_xmitq_head = dep->de_xmitq_tail = NULL;
|
||||||
|
else
|
||||||
|
dep->de_xmitq_head = txbuff->next;
|
||||||
|
unlock();
|
||||||
|
pktsize = txbuff->size;
|
||||||
|
|
||||||
|
} else
|
||||||
|
panic(dep->de_name, "should not be sending ", NO_NUM);
|
||||||
|
|
||||||
|
if ((dep->de_flags & DEF_XMIT_BUSY)) {
|
||||||
|
if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
|
||||||
|
getuptime(&now);
|
||||||
|
if ((now - dep->de_xmit_start) > 4) {
|
||||||
|
/* Transmitter timed out */
|
||||||
|
DEBUG(printf("3c501: transmitter timed out ... \n"));
|
||||||
|
dep->de_stat.ets_sendErr += 1;
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||||
|
el1_reset(dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Queue packet */
|
||||||
|
lock(); /* Queue packet to receive queue */
|
||||||
|
if (dep->de_xmitq_head == NULL)
|
||||||
|
dep->de_xmitq_head = txbuff;
|
||||||
|
else
|
||||||
|
dep->de_xmitq_tail->next = txbuff;
|
||||||
|
dep->de_xmitq_tail = txbuff;
|
||||||
|
unlock();
|
||||||
|
} else {
|
||||||
|
/* Save for retransmission */
|
||||||
|
TxBuff = txbuff;
|
||||||
|
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
||||||
|
|
||||||
|
/* Setup board for packet loading */
|
||||||
|
lock(); /* Buffer to processor */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||||
|
inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
|
||||||
|
inb_el1(dep, EL1_XMIT);
|
||||||
|
outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */
|
||||||
|
|
||||||
|
/* Loads packet */
|
||||||
|
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
|
||||||
|
outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize);
|
||||||
|
/* Starts transmitter */
|
||||||
|
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
getuptime(&dep->de_xmit_start);
|
||||||
|
dep->de_flags &= NOT(DEF_SENDING);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_stop(dpeth_t *dep)
|
||||||
|
** Function: Stops board and disable interrupts.
|
||||||
|
*/
|
||||||
|
static void el1_stop(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name));
|
||||||
|
for (ix = 0; ix < 8; ix += 1) /* Reset board */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RESET);
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_SYS);
|
||||||
|
sys_irqdisable(&dep->de_hook); /* Disable interrupt */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_interrupt(dpeth_t *dep)
|
||||||
|
** Function: Interrupt handler. Acknwledges transmit interrupts
|
||||||
|
** or unloads receive buffer to memory queue.
|
||||||
|
*/
|
||||||
|
static void el1_interrupt(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
u16_t csr, isr;
|
||||||
|
int pktsize;
|
||||||
|
buff_t *rxptr;
|
||||||
|
|
||||||
|
csr = inb_el1(dep, EL1_CSR);
|
||||||
|
if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
|
||||||
|
|
||||||
|
/* Got a transmit interrupt */
|
||||||
|
isr = inb_el1(dep, EL1_XMIT);
|
||||||
|
if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
|
||||||
|
DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
|
||||||
|
if (isr & EXSR_JAM) {
|
||||||
|
/* Sending, packet got a collision */
|
||||||
|
dep->de_stat.ets_collision += 1;
|
||||||
|
/* Put pointer back to beginning of packet */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||||
|
outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
|
||||||
|
/* And retrigger transmission */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
|
||||||
|
dep->de_stat.ets_sendErr += 1;
|
||||||
|
|
||||||
|
} else if (isr & EXSR_UNDER) {
|
||||||
|
dep->de_stat.ets_fifoUnder += 1;
|
||||||
|
}
|
||||||
|
DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
|
||||||
|
el1_reset(dep);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
|
||||||
|
/* Packet transmitted successfully */
|
||||||
|
dep->de_stat.ets_packetT += 1;
|
||||||
|
dep->bytes_Tx += (long) (TxBuff->size);
|
||||||
|
free_buff(dep, TxBuff);
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||||
|
if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) {
|
||||||
|
/* Pending transmit request available in queue */
|
||||||
|
el1_send(dep, TRUE, 0);
|
||||||
|
if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
|
||||||
|
|
||||||
|
/* Got a receive interrupt */
|
||||||
|
isr = inb_el1(dep, EL1_RECV);
|
||||||
|
pktsize = inw_el1(dep, EL1_RECVPTR);
|
||||||
|
if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
|
||||||
|
DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
|
||||||
|
dep->de_stat.ets_recvErr += 1;
|
||||||
|
|
||||||
|
} else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) {
|
||||||
|
DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
|
||||||
|
dep->de_stat.ets_recvErr += 1;
|
||||||
|
|
||||||
|
} else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
|
||||||
|
/* Memory not available. Drop packet */
|
||||||
|
dep->de_stat.ets_fifoOver += 1;
|
||||||
|
|
||||||
|
} else if (isr & (ERSR_GOOD | ERSR_ANY)) {
|
||||||
|
/* Got a good packet. Read it from buffer */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
|
||||||
|
outw_el1(dep, EL1_XMITPTR, 0);
|
||||||
|
insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
|
||||||
|
rxptr->next = NULL;
|
||||||
|
rxptr->size = pktsize;
|
||||||
|
dep->de_stat.ets_packetR += 1;
|
||||||
|
dep->bytes_Rx += (long) pktsize;
|
||||||
|
lock(); /* Queue packet to receive queue */
|
||||||
|
if (dep->de_recvq_head == NULL)
|
||||||
|
dep->de_recvq_head = rxptr;
|
||||||
|
else
|
||||||
|
dep->de_recvq_tail->next = rxptr;
|
||||||
|
dep->de_recvq_tail = rxptr;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
/* Reply to pending Receive requests, if any */
|
||||||
|
el1_recv(dep, TRUE, 0);
|
||||||
|
}
|
||||||
|
} else { /* Nasty condition, should never happen */
|
||||||
|
DEBUG(
|
||||||
|
printf("3c501: got interrupt with status 0x%02X\n"
|
||||||
|
" de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n"
|
||||||
|
" xmit buffer = 0x%4X recv buffer = 0x%4X\n",
|
||||||
|
csr, dep->de_flags,
|
||||||
|
inb_el1(dep, EL1_RECV),
|
||||||
|
inb_el1(dep, EL1_XMIT),
|
||||||
|
inw_el1(dep, EL1_XMITPTR),
|
||||||
|
inw_el1(dep, EL1_RECVPTR))
|
||||||
|
);
|
||||||
|
el1_reset(dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move into receive mode */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
|
||||||
|
outw_el1(dep, EL1_RECVPTR, 0);
|
||||||
|
/* Be sure that interrupts are cleared */
|
||||||
|
inb_el1(dep, EL1_RECV);
|
||||||
|
inb_el1(dep, EL1_XMIT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el1_init(dpeth_t *dep)
|
||||||
|
** Function: Initalizes board hardware and driver data structures.
|
||||||
|
*/
|
||||||
|
static void el1_init(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */
|
||||||
|
dep->de_offset_page = 0;
|
||||||
|
dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
|
||||||
|
|
||||||
|
el1_reset(dep); /* Reset and initialize board */
|
||||||
|
|
||||||
|
/* Start receiver (default mode) */
|
||||||
|
outw_el1(dep, EL1_RECVPTR, 0);
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
|
||||||
|
|
||||||
|
/* Initializes buffer pool */
|
||||||
|
init_buff(dep, NULL);
|
||||||
|
el1_mode_init(dep);
|
||||||
|
|
||||||
|
printf("%s: Etherlink (%s) at %X:%d - ",
|
||||||
|
dep->de_name, "3c501", dep->de_base_port, dep->de_irq);
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
|
||||||
|
printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]),
|
||||||
|
ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||||
|
|
||||||
|
/* Device specific functions */
|
||||||
|
dep->de_recvf = el1_recv;
|
||||||
|
dep->de_sendf = el1_send;
|
||||||
|
dep->de_flagsf = el1_mode_init;
|
||||||
|
dep->de_resetf = el1_reset;
|
||||||
|
dep->de_getstatsf = el1_getstats;
|
||||||
|
dep->de_dumpstatsf = el1_dumpstats;
|
||||||
|
dep->de_interruptf = el1_interrupt;
|
||||||
|
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: int el1_probe(dpeth_t *dep)
|
||||||
|
** Function: Checks for presence of the board.
|
||||||
|
*/
|
||||||
|
PUBLIC int el1_probe(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
for (ix = 0; ix < 8; ix += 1) /* Reset the board */
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_RESET);
|
||||||
|
outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */
|
||||||
|
|
||||||
|
/* Check station address */
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
|
||||||
|
outw_el1(dep, EL1_XMITPTR, ix);
|
||||||
|
StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
|
||||||
|
}
|
||||||
|
if (StationAddress[0] != 0x02 || /* Etherlink Station address */
|
||||||
|
StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */
|
||||||
|
StationAddress[2] != 0x8C)
|
||||||
|
return FALSE; /* No Etherlink board at this address */
|
||||||
|
|
||||||
|
dep->de_ramsize = 0; /* RAM size is meaningless */
|
||||||
|
dep->de_linmem = 0L; /* Access is via I/O port */
|
||||||
|
|
||||||
|
/* Device specific functions */
|
||||||
|
dep->de_initf = el1_init;
|
||||||
|
dep->de_stopf = el1_stop;
|
||||||
|
|
||||||
|
return TRUE; /* Etherlink board found */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING */
|
||||||
|
|
||||||
|
/** 3c501.c **/
|
71
drivers/dpeth/3c501.h
Normal file
71
drivers/dpeth/3c501.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
** File: 3c501.h Jan. 14, 1997
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** Interface description for 3Com Etherlink boards
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The various board command registers */
|
||||||
|
#define EL1_ADDRESS 0x00 /* Board station address, 6 bytes */
|
||||||
|
#define EL1_RECV 0x06 /* Board Receive Config/Status Reg. */
|
||||||
|
#define EL1_XMIT 0x07 /* Board Transmit Config/Status Reg. */
|
||||||
|
#define EL1_XMITPTR 0x08 /* Transmit buffer pointer (word access) */
|
||||||
|
#define EL1_RECVPTR 0x0A /* Receive buffer pointer (word access) */
|
||||||
|
#define EL1_SAPROM 0x0C /* Window on Station Addr prom */
|
||||||
|
#define EL1_CSR 0x0E /* Board Command/Status Register */
|
||||||
|
#define EL1_DATAPORT 0x0F /* Window on packet buffer (Data Port) */
|
||||||
|
|
||||||
|
/* Bits in EL1_RECV, interrupt enable on write, status when read */
|
||||||
|
#define ERSR_NONE 0x00 /* Match mode in bits 5-6 (wo) */
|
||||||
|
#define ERSR_ALL 0x40 /* Promiscuous receive (wo) */
|
||||||
|
#define ERSR_BROAD 0x80 /* Station address plus broadcast (wo) */
|
||||||
|
#define ERSR_MULTI 0x80 /* Station address plus multicast 0xC0 */
|
||||||
|
#define ERSR_STALE 0x80 /* Receive status previously read (ro) */
|
||||||
|
#define ERSR_GOOD 0x20 /* Well formed packets only (rw) */
|
||||||
|
#define ERSR_ANY 0x10 /* Any packet, even with errors (rw) */
|
||||||
|
#define ERSR_SHORT 0x08 /* Short frame (rw) */
|
||||||
|
#define ERSR_DRIBBLE 0x04 /* Dribble error (rw) */
|
||||||
|
#define ERSR_FCS 0x02 /* CRC error (rw) */
|
||||||
|
#define ERSR_OVER 0x01 /* Data overflow (rw) */
|
||||||
|
|
||||||
|
#define ERSR_RERROR (ERSR_SHORT|ERSR_DRIBBLE|ERSR_FCS|ERSR_OVER)
|
||||||
|
#define ERSR_RMASK (ERSR_GOOD|ERSR_RERROR)/*(ERSR_GOOD|ERSR_ANY|ERSR_RERROR)*/
|
||||||
|
|
||||||
|
/* Bits in EL1_XMIT, interrupt enable on write, status when read */
|
||||||
|
#define EXSR_IDLE 0x08 /* Transmit idle (send completed) */
|
||||||
|
#define EXSR_16JAM 0x04 /* Packet sending got 16 collisions */
|
||||||
|
#define EXSR_JAM 0x02 /* Packet sending got a collision */
|
||||||
|
#define EXSR_UNDER 0x01 /* Data underflow in sending */
|
||||||
|
|
||||||
|
/* Bits in EL1_CSR (Configuration Status Register) */
|
||||||
|
#define ECSR_RESET 0x80 /* Reset the controller (wo) */
|
||||||
|
#define ECSR_XMTBSY 0x80 /* Transmitter busy (ro) */
|
||||||
|
#define ECSR_RIDE 0x01 /* Request interrupt/DMA enable (rw) */
|
||||||
|
#define ECSR_DMA 0x20 /* DMA request (rw) */
|
||||||
|
#define ECSR_EDMA 0x10 /* DMA done (ro) */
|
||||||
|
#define ECSR_CRC 0x02 /* Causes CRC error on transmit (wo) */
|
||||||
|
#define ECSR_RCVBSY 0x01 /* Receive in progress (ro) */
|
||||||
|
#define ECSR_LOOP (3<<2) /* 2 bit field in bits 2,3, loopback */
|
||||||
|
#define ECSR_RECV (2<<2) /* Gives buffer to receiver (rw) */
|
||||||
|
#define ECSR_XMIT (1<<2) /* Gives buffer to transmit (rw) */
|
||||||
|
#define ECSR_SYS (0<<2) /* Gives buffer to processor (wo) */
|
||||||
|
|
||||||
|
#define EL1_BFRSIZ 2048 /* Number of bytes in board buffer */
|
||||||
|
|
||||||
|
#define inb_el1(dep,reg) (inb(dep->de_base_port+(reg)))
|
||||||
|
#define inw_el1(dep,reg) (inw(dep->de_base_port+(reg)))
|
||||||
|
#define outb_el1(dep,reg,data) (outb(dep->de_base_port+(reg),data))
|
||||||
|
#define outw_el1(dep,reg,data) (outw(dep->de_base_port+(reg),data))
|
||||||
|
|
||||||
|
/** 3c501.h **/
|
175
drivers/dpeth/3c503.c
Normal file
175
drivers/dpeth/3c503.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
** File: 3c503.c Dec. 20, 1996
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** Driver for the Etherlink II boards. Works in shared memory mode.
|
||||||
|
** Programmed I/O could be used as well but would result in poor
|
||||||
|
** performances. This file contains only the board specific code,
|
||||||
|
** the rest is in 8390.c Code specific for ISA bus only
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if ENABLE_NETWORKING == 1 && ENABLE_3C503 == 1
|
||||||
|
|
||||||
|
#include "8390.h"
|
||||||
|
#include "3c503.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el2_init(dpeth_t *dep);
|
||||||
|
** Function: Initalize hardware and data structures.
|
||||||
|
*/
|
||||||
|
static void el2_init(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix, irq;
|
||||||
|
int sendq_nr;
|
||||||
|
int cntr;
|
||||||
|
|
||||||
|
/* Map the address PROM to lower I/O address range */
|
||||||
|
cntr = inb_el2(dep, EL2_CNTR);
|
||||||
|
outb_el2(dep, EL2_CNTR, cntr | ECNTR_SAPROM);
|
||||||
|
|
||||||
|
/* Read station address from PROM */
|
||||||
|
for (ix = EL2_EA0; ix <= EL2_EA5; ix += 1)
|
||||||
|
dep->de_address.ea_addr[ix] = inb_el2(dep, ix);
|
||||||
|
|
||||||
|
/* Map the 8390 back to lower I/O address range */
|
||||||
|
outb_el2(dep, EL2_CNTR, cntr);
|
||||||
|
|
||||||
|
/* Enable memory, but turn off interrupts until we are ready */
|
||||||
|
outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF);
|
||||||
|
|
||||||
|
dep->de_data_port = dep->de_dp8390_port = dep->de_base_port;
|
||||||
|
dep->de_prog_IO = FALSE; /* Programmed I/O not yet available */
|
||||||
|
|
||||||
|
/* Check width of data bus */
|
||||||
|
outb_el2(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STP);
|
||||||
|
outb_el2(dep, DP_DCR, 0);
|
||||||
|
outb_el2(dep, DP_CR, CR_PS_P2 | CR_NO_DMA | CR_STP);
|
||||||
|
dep->de_16bit = (inb_el2(dep, DP_DCR) & DCR_WTS) != 0;
|
||||||
|
outb_el2(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STP);
|
||||||
|
|
||||||
|
/* Allocate one send buffer (1.5kb) per 8kb of on board memory. */
|
||||||
|
/* Only 8kb of 3c503/16 boards are used to avoid specific routines */
|
||||||
|
sendq_nr = dep->de_ramsize / 0x2000;
|
||||||
|
if (sendq_nr < 1)
|
||||||
|
sendq_nr = 1;
|
||||||
|
else if (sendq_nr > SENDQ_NR)
|
||||||
|
sendq_nr = SENDQ_NR;
|
||||||
|
|
||||||
|
dep->de_sendq_nr = sendq_nr;
|
||||||
|
for (ix = 0; ix < sendq_nr; ix++)
|
||||||
|
dep->de_sendq[ix].sq_sendpage = (ix * SENDQ_PAGES) + EL2_SM_START_PG;
|
||||||
|
|
||||||
|
dep->de_startpage = (ix * SENDQ_PAGES) + EL2_SM_START_PG;
|
||||||
|
dep->de_stoppage = EL2_SM_STOP_PG;
|
||||||
|
|
||||||
|
outb_el2(dep, EL2_STARTPG, dep->de_startpage);
|
||||||
|
outb_el2(dep, EL2_STOPPG, dep->de_stoppage);
|
||||||
|
|
||||||
|
/* Point the vector pointer registers somewhere ?harmless?. */
|
||||||
|
outb_el2(dep, EL2_VP2, 0xFF); /* Point at the ROM restart location */
|
||||||
|
outb_el2(dep, EL2_VP1, 0xFF); /* 0xFFFF:0000 (from original sources) */
|
||||||
|
outb_el2(dep, EL2_VP0, 0x00); /* - What for protected mode? */
|
||||||
|
|
||||||
|
/* Set interrupt level for 3c503 */
|
||||||
|
irq = (dep->de_irq &= ~DEI_DEFAULT); /* Strip the default flag. */
|
||||||
|
if (irq == 9) irq = 2;
|
||||||
|
if (irq < 2 || irq > 5) panic(dep->de_name, "bad 3c503 irq configuration", irq);
|
||||||
|
outb_el2(dep, EL2_IDCFG, (0x04 << irq));
|
||||||
|
|
||||||
|
outb_el2(dep, EL2_DRQCNT, 0x08); /* Set burst size to 8 */
|
||||||
|
outb_el2(dep, EL2_DMAAH, EL2_SM_START_PG); /* Put start of TX */
|
||||||
|
outb_el2(dep, EL2_DMAAL, 0x00); /* buffer in the GA DMA reg */
|
||||||
|
|
||||||
|
outb_el2(dep, EL2_CFGR, ECFGR_NORM); /* Enable shared memory */
|
||||||
|
|
||||||
|
ns_init(dep); /* Initialize DP controller */
|
||||||
|
|
||||||
|
printf("%s: Etherlink II%s (%s) at %X:%d:%05lX - ",
|
||||||
|
dep->de_name, dep->de_16bit ? "/16" : "", "3c503",
|
||||||
|
dep->de_base_port, dep->de_irq,
|
||||||
|
dep->de_linmem + dep->de_offset_page);
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
|
||||||
|
printf("%02X%c", dep->de_address.ea_addr[ix],
|
||||||
|
ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el2_stop(dpeth_t *dep);
|
||||||
|
** Function: Stops board by disabling interrupts.
|
||||||
|
*/
|
||||||
|
static void el2_stop(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF);
|
||||||
|
sys_irqdisable(&dep->de_hook); /* disable interrupts */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el2_probe(dpeth_t *dep);
|
||||||
|
** Function: Probe for the presence of an EtherLink II card.
|
||||||
|
** Initialize memory addressing if card detected.
|
||||||
|
*/
|
||||||
|
int el2_probe(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int iobase, membase;
|
||||||
|
int thin;
|
||||||
|
|
||||||
|
/* Thin ethernet or AUI? */
|
||||||
|
thin = (dep->de_linmem & 1) ? ECNTR_AUI : ECNTR_THIN;
|
||||||
|
|
||||||
|
/* Location registers should have 1 bit set */
|
||||||
|
if (!(iobase = inb_el2(dep, EL2_IOBASE))) return FALSE;
|
||||||
|
if (!((membase = inb_el2(dep, EL2_MEMBASE)) & 0xF0)) return FALSE;
|
||||||
|
if ((iobase & (iobase - 1)) || (membase & (membase - 1))) return FALSE;
|
||||||
|
|
||||||
|
/* Resets board */
|
||||||
|
outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin);
|
||||||
|
milli_delay(1);
|
||||||
|
outb_el2(dep, EL2_CNTR, thin);
|
||||||
|
milli_delay(5);
|
||||||
|
|
||||||
|
/* Map the address PROM to lower I/O address range */
|
||||||
|
outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin);
|
||||||
|
if (inb_el2(dep, EL2_EA0) != 0x02 || /* Etherlink II Station address */
|
||||||
|
inb_el2(dep, EL2_EA1) != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */
|
||||||
|
inb_el2(dep, EL2_EA2) != 0x8C)
|
||||||
|
return FALSE; /* No Etherlink board at this address */
|
||||||
|
|
||||||
|
/* Map the 8390 back to lower I/O address range */
|
||||||
|
outb_el2(dep, EL2_CNTR, thin);
|
||||||
|
|
||||||
|
/* Setup shared memory addressing for 3c503 */
|
||||||
|
dep->de_linmem = ((membase & 0xC0) ? EL2_BASE_0D8000 : EL2_BASE_0C8000) +
|
||||||
|
((membase & 0xA0) ? (EL2_BASE_0CC000 - EL2_BASE_0C8000) : 0x0000);
|
||||||
|
|
||||||
|
/* Shared memory starts at 0x2000 (8kb window) */
|
||||||
|
dep->de_offset_page = (EL2_SM_START_PG * DP_PAGESIZE);
|
||||||
|
dep->de_linmem -= dep->de_offset_page;
|
||||||
|
dep->de_ramsize = (EL2_SM_STOP_PG - EL2_SM_START_PG) * DP_PAGESIZE;
|
||||||
|
|
||||||
|
/* Board initialization and stop functions */
|
||||||
|
dep->de_initf = el2_init;
|
||||||
|
dep->de_stopf = el2_stop;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_NETWORKING && ENABLE_3C503 */
|
||||||
|
|
||||||
|
/** 3c503.c **/
|
72
drivers/dpeth/3c503.h
Normal file
72
drivers/dpeth/3c503.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
** File: 3c503.h Dec. 20, 1996
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** Interface description for 3Com Etherlink II boards
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EL2_MEMTEST 0 /* Set to 1 for on board memory test */
|
||||||
|
|
||||||
|
#define EL2_GA 0x0400 /* Offset of registers in Gate Array */
|
||||||
|
|
||||||
|
/* EtherLink II card */
|
||||||
|
|
||||||
|
#define EL2_STARTPG (EL2_GA+0x00) /* Start page matching DP_PSTARTPG */
|
||||||
|
#define EL2_STOPPG (EL2_GA+0x01) /* Stop page matching DP_PSTOPPG */
|
||||||
|
#define EL2_DRQCNT (EL2_GA+0x02) /* DMA burst count */
|
||||||
|
#define EL2_IOBASE (EL2_GA+0x03) /* I/O base jumpers (bit coded) */
|
||||||
|
#define EL2_MEMBASE (EL2_GA+0x04) /* Memory base jumpers (bit coded) */
|
||||||
|
#define EL2_CFGR (EL2_GA+0x05) /* Configuration Register for GA */
|
||||||
|
#define EL2_CNTR (EL2_GA+0x06) /* Control(write) and status(read) */
|
||||||
|
#define EL2_STATUS (EL2_GA+0x07)
|
||||||
|
#define EL2_IDCFG (EL2_GA+0x08) /* Interrupt/DMA configuration reg */
|
||||||
|
#define EL2_DMAAH (EL2_GA+0x09) /* DMA address register (High byte) */
|
||||||
|
#define EL2_DMAAL (EL2_GA+0x0A) /* DMA address register (Low byte) */
|
||||||
|
#define EL2_VP2 (EL2_GA+0x0B) /* Vector pointer - set to */
|
||||||
|
#define EL2_VP1 (EL2_GA+0x0C) /* reset address (0xFFFF:0) */
|
||||||
|
#define EL2_VP0 (EL2_GA+0x0D) /* */
|
||||||
|
#define EL2_FIFOH (EL2_GA+0x0E) /* FIFO for progr. I/O (High byte) */
|
||||||
|
#define EL2_FIFOL (EL2_GA+0x0F) /* FIFO for progr. I/O (Low byte) */
|
||||||
|
|
||||||
|
#define EL2_EA0 0x00 /* Most significant byte of ethernet address */
|
||||||
|
#define EL2_EA1 0x01
|
||||||
|
#define EL2_EA2 0x02
|
||||||
|
#define EL2_EA3 0x03
|
||||||
|
#define EL2_EA4 0x04
|
||||||
|
#define EL2_EA5 0x05 /* Least significant byte of ethernet address */
|
||||||
|
|
||||||
|
/* Bits in EL2_CNTR register */
|
||||||
|
#define ECNTR_RESET 0x01 /* Software Reset */
|
||||||
|
#define ECNTR_THIN 0x02 /* Onboard transceiver enable */
|
||||||
|
#define ECNTR_AUI 0x00 /* Onboard transceiver disable */
|
||||||
|
#define ECNTR_SAPROM 0x04 /* Map the station address prom */
|
||||||
|
|
||||||
|
/* Bits in EL2_CFGR register */
|
||||||
|
#define ECFGR_NORM 0x49 /* Enable 8k shared memory, no DMA, TC int */
|
||||||
|
#define ECFGR_IRQOFF 0xC9 /* As above, disable 8390 IRQ */
|
||||||
|
|
||||||
|
/* Shared memory management parameters */
|
||||||
|
#define EL2_SM_START_PG 0x20 /* First page of TX buffer */
|
||||||
|
#define EL2_SM_STOP_PG 0x40 /* Last page +1 of RX ring */
|
||||||
|
|
||||||
|
/* Physical addresses where an Etherlink board can be configured */
|
||||||
|
#define EL2_BASE_0C8000 0x0C8000
|
||||||
|
#define EL2_BASE_0CC000 0x0CC000
|
||||||
|
#define EL2_BASE_0D8000 0x0D8000
|
||||||
|
#define EL2_BASE_0DC000 0x0DC000
|
||||||
|
|
||||||
|
#define inb_el2(dep,reg) (inb((dep)->de_base_port+(reg)))
|
||||||
|
#define outb_el2(dep,reg,data) (outb((dep)->de_base_port+(reg),(data)))
|
||||||
|
|
||||||
|
/** 3c503.h **/
|
603
drivers/dpeth/3c509.c
Normal file
603
drivers/dpeth/3c509.c
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
/*
|
||||||
|
** File: 3c509.c Jun. 01, 2000
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains specific implementation of the ethernet
|
||||||
|
** device driver for 3Com Etherlink III (3c509) boards.
|
||||||
|
** NOTE: The board has to be setup to disable PnP and to assign
|
||||||
|
** I/O base and IRQ. The driver is for ISA bus only
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <minix/com.h>
|
||||||
|
#include <net/hton.h>
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if ENABLE_NETWORKING == 1 && ENABLE_3C509 == 1
|
||||||
|
|
||||||
|
#include "3c509.h"
|
||||||
|
|
||||||
|
static const char *const IfNamesMsg[] = {
|
||||||
|
"10BaseT", "AUI", "unknown", "BNC",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_update_stats(dpeth_t *dep)
|
||||||
|
** Function: Reads statistic counters from board
|
||||||
|
** and updates local counters.
|
||||||
|
*/
|
||||||
|
static void el3_update_stats(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Disables statistics while reading and switches to the correct window */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StatsDisable);
|
||||||
|
SetWindow(WNO_Statistics);
|
||||||
|
|
||||||
|
/* Reads everything, adding values to the local counters */
|
||||||
|
dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxCarrierLost); /* Reg. 00 */
|
||||||
|
dep->de_stat.ets_sendErr += inb_el3(dep, REG_TxNoCD); /* Reg. 01 */
|
||||||
|
dep->de_stat.ets_collision += inb_el3(dep, REG_TxMultColl); /* Reg. 02 */
|
||||||
|
dep->de_stat.ets_collision += inb_el3(dep, REG_TxSingleColl); /* Reg. 03 */
|
||||||
|
dep->de_stat.ets_collision += inb_el3(dep, REG_TxLate); /* Reg. 04 */
|
||||||
|
dep->de_stat.ets_recvErr += inb_el3(dep, REG_RxDiscarded); /* Reg. 05 */
|
||||||
|
dep->de_stat.ets_packetT += inb_el3(dep, REG_TxFrames); /* Reg. 06 */
|
||||||
|
dep->de_stat.ets_packetR += inb_el3(dep, REG_RxFrames); /* Reg. 07 */
|
||||||
|
dep->de_stat.ets_transDef += inb_el3(dep, REG_TxDefer); /* Reg. 08 */
|
||||||
|
dep->bytes_Rx += (unsigned) inw_el3(dep, REG_RxBytes); /* Reg. 10 */
|
||||||
|
dep->bytes_Tx += (unsigned) inw_el3(dep, REG_TxBytes); /* Reg. 12 */
|
||||||
|
|
||||||
|
/* Goes back to operating window and enables statistics */
|
||||||
|
SetWindow(WNO_Operating);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_getstats(dpeth_t *dep)
|
||||||
|
** Function: Reads statistics counters from board.
|
||||||
|
*/
|
||||||
|
static void el3_getstats(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
lock();
|
||||||
|
el3_update_stats(dep);
|
||||||
|
unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_dodump(dpeth_t *dep)
|
||||||
|
** Function: Dumps counter on screen (support for console display).
|
||||||
|
*/
|
||||||
|
static void el3_dodump(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
el3_getstats(dep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_rx_mode(dpeth_t *dep)
|
||||||
|
** Function: Initializes receiver mode
|
||||||
|
*/
|
||||||
|
static void el3_rx_mode(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
dep->de_recv_mode = FilterIndividual;
|
||||||
|
if (dep->de_flags & DEF_BROAD) dep->de_recv_mode |= FilterBroadcast;
|
||||||
|
if (dep->de_flags & DEF_MULTI) dep->de_recv_mode |= FilterMulticast;
|
||||||
|
if (dep->de_flags & DEF_PROMISC) dep->de_recv_mode |= FilterPromiscuous;
|
||||||
|
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxReset);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxEnable);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_reset(dpeth_t *dep)
|
||||||
|
** Function: Reset function specific for Etherlink hardware.
|
||||||
|
*/
|
||||||
|
static void el3_reset(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_write_fifo(dpeth_t * dep, int pktsize);
|
||||||
|
** Function: Writes a packet from user area to board.
|
||||||
|
** Remark: Writing a word/dword at a time may result faster
|
||||||
|
** but is a lot more complicated. Let's go simpler way.
|
||||||
|
*/
|
||||||
|
static void el3_write_fifo(dpeth_t * dep, int pktsize)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
iovec_dat_t *iovp = &dep->de_write_iovec;
|
||||||
|
int padding = pktsize;
|
||||||
|
|
||||||
|
do { /* Writes chuncks of packet from user buffers */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
/* Writes from user buffer to Tx FIFO */
|
||||||
|
outsb(dep->de_data_port, iovp->iod_proc_nr,
|
||||||
|
(void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_recv(dpeth_t *dep, int fromint, int size)
|
||||||
|
** Function: Receive function. Called from interrupt handler or
|
||||||
|
** from main to unload recv. buffer (packet to client)
|
||||||
|
*/
|
||||||
|
static void el3_recv(dpeth_t *dep, int fromint, int size)
|
||||||
|
{
|
||||||
|
buff_t *rxptr;
|
||||||
|
|
||||||
|
while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
|
||||||
|
|
||||||
|
lock(); /* Remove buffer from queue */
|
||||||
|
if (dep->de_recvq_tail == dep->de_recvq_head)
|
||||||
|
dep->de_recvq_head = dep->de_recvq_tail = NULL;
|
||||||
|
else
|
||||||
|
dep->de_recvq_head = rxptr->next;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
/* Copy buffer to user area and free it */
|
||||||
|
mem2user(dep, rxptr);
|
||||||
|
|
||||||
|
dep->de_read_s = rxptr->size;
|
||||||
|
dep->de_flags |= DEF_ACK_RECV;
|
||||||
|
dep->de_flags &= NOT(DEF_READING);
|
||||||
|
|
||||||
|
/* Return buffer to the idle pool */
|
||||||
|
free_buff(dep, rxptr);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_rx_complete(dpeth_t * dep);
|
||||||
|
** Function: Upon receiving a packet, provides status checks
|
||||||
|
** and if packet is OK copies it to local buffer.
|
||||||
|
*/
|
||||||
|
static void el3_rx_complete(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
short int RxStatus;
|
||||||
|
int pktsize;
|
||||||
|
buff_t *rxptr;
|
||||||
|
|
||||||
|
RxStatus = inw_el3(dep, REG_RxStatus);
|
||||||
|
pktsize = RxStatus & RXS_Length; /* Mask off packet length */
|
||||||
|
|
||||||
|
if (RxStatus & RXS_Error) {
|
||||||
|
|
||||||
|
/* First checks for receiving errors */
|
||||||
|
RxStatus &= RXS_ErrType;
|
||||||
|
switch (RxStatus) { /* Bad packet (see error type) */
|
||||||
|
case RXS_Dribble:
|
||||||
|
case RXS_Oversize:
|
||||||
|
case RXS_Runt: dep->de_stat.ets_recvErr += 1; break;
|
||||||
|
case RXS_Overrun: dep->de_stat.ets_OVW += 1; break;
|
||||||
|
case RXS_Framing: dep->de_stat.ets_frameAll += 1; break;
|
||||||
|
case RXS_CRC: dep->de_stat.ets_CRCerr += 1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
|
||||||
|
/* Memory not available. Drop packet */
|
||||||
|
dep->de_stat.ets_fifoOver += 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Good packet. Read it from FIFO */
|
||||||
|
insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
|
||||||
|
rxptr->next = NULL;
|
||||||
|
rxptr->size = pktsize;
|
||||||
|
|
||||||
|
lock(); /* Queue packet to receive queue */
|
||||||
|
if (dep->de_recvq_head == NULL)
|
||||||
|
dep->de_recvq_head = rxptr;
|
||||||
|
else
|
||||||
|
dep->de_recvq_tail->next = rxptr;
|
||||||
|
dep->de_recvq_tail = rxptr;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
/* Reply to pending Receive requests, if any */
|
||||||
|
el3_recv(dep, TRUE, pktsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Discard top packet from queue */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxDiscard);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_send(dpeth_t *dep, int count)
|
||||||
|
** Function: Send function. Called from main to transit a packet or
|
||||||
|
** from interrupt handler when Tx FIFO gets available.
|
||||||
|
*/
|
||||||
|
static void el3_send(dpeth_t * dep, int from_int, int count)
|
||||||
|
{
|
||||||
|
clock_t now;
|
||||||
|
int ix;
|
||||||
|
short int TxStatus;
|
||||||
|
|
||||||
|
getuptime(&now);
|
||||||
|
if ((dep->de_flags & DEF_XMIT_BUSY) &&
|
||||||
|
(now - dep->de_xmit_start) > 4) {
|
||||||
|
|
||||||
|
DEBUG(printf("3c509: Transmitter timed out. Resetting ....\n");)
|
||||||
|
dep->de_stat.ets_sendErr += 1;
|
||||||
|
/* Resets and restars the transmitter */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxReset);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||||
|
}
|
||||||
|
if (!(dep->de_flags & DEF_XMIT_BUSY)) {
|
||||||
|
|
||||||
|
/* Writes Transmitter preamble 1st Word (packet len, no ints) */
|
||||||
|
outw_el3(dep, REG_TxFIFO, count);
|
||||||
|
/* Writes Transmitter preamble 2nd Word (all zero) */
|
||||||
|
outw_el3(dep, REG_TxFIFO, 0);
|
||||||
|
/* Writes packet */
|
||||||
|
el3_write_fifo(dep, count);
|
||||||
|
|
||||||
|
getuptime(&dep->de_xmit_start);
|
||||||
|
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
||||||
|
if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) {
|
||||||
|
/* Tx has enough room for a packet of maximum size */
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING);
|
||||||
|
} else {
|
||||||
|
/* Interrupt driver when enough room is available */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE);
|
||||||
|
dep->de_flags &= NOT(DEF_SENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pops Tx status stack */
|
||||||
|
for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) {
|
||||||
|
if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1;
|
||||||
|
if (TxStatus & 0x30)
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxReset);
|
||||||
|
if (TxStatus & 0x3C)
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
|
||||||
|
outb_el3(dep, REG_TxStatus, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_close(dpeth_t *dep)
|
||||||
|
** Function: Stops board and makes it ready to shut down.
|
||||||
|
*/
|
||||||
|
static void el3_close(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Disables statistics, Receiver and Transmitter */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StatsDisable);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxDisable);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxDisable);
|
||||||
|
|
||||||
|
if (dep->de_if_port == BNC_XCVR) {
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr);
|
||||||
|
/* milli_delay(5); */
|
||||||
|
|
||||||
|
} else if (dep->de_if_port == TP_XCVR) {
|
||||||
|
SetWindow(WNO_Diagnostics);
|
||||||
|
outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) &
|
||||||
|
NOT((MediaLBeatEnable | MediaJabberEnable)));
|
||||||
|
/* milli_delay(5); */
|
||||||
|
}
|
||||||
|
DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name));
|
||||||
|
/* Issues a global reset
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */
|
||||||
|
sys_irqdisable(&dep->de_hook); /* Disable interrupt */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_interrupt(dpeth_t *dep)
|
||||||
|
** Function: Interrupt handler. Acknwledges transmit interrupts
|
||||||
|
** or unloads receive buffer to memory queue.
|
||||||
|
*/
|
||||||
|
static void el3_interrupt(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int loop;
|
||||||
|
unsigned short isr;
|
||||||
|
|
||||||
|
for (loop = 5; loop > 0 && ((isr = inw_el3(dep, REG_CmdStatus)) &
|
||||||
|
(INT_Latch | INT_RxComplete | INT_UpdateStats)); loop -= 1) {
|
||||||
|
|
||||||
|
if (isr & INT_RxComplete) /* Got a new packet */
|
||||||
|
el3_rx_complete(dep);
|
||||||
|
|
||||||
|
if (isr & INT_TxAvailable) { /* Tx has room for big packets */
|
||||||
|
DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);)
|
||||||
|
dep->de_flags &= NOT(DEF_XMIT_BUSY);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable);
|
||||||
|
if (dep->de_flags & DEF_SENDING) /* Send pending */
|
||||||
|
el3_send(dep, TRUE, dep->de_send_s);
|
||||||
|
}
|
||||||
|
if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) {
|
||||||
|
|
||||||
|
if (isr & INT_UpdateStats) /* Empties statistics */
|
||||||
|
el3_getstats(dep);
|
||||||
|
|
||||||
|
if (isr & INT_RxEarly) /* Not really used. Do nothing */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_RxEarly));
|
||||||
|
|
||||||
|
if (isr & INT_AdapterFail) {
|
||||||
|
/* Adapter error. Reset and re-enable receiver */
|
||||||
|
DEBUG(printf("3c509: got Rx fail interrupt, Status=0x%04x\n", isr);)
|
||||||
|
el3_rx_mode(dep);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_AdapterFail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acknowledge interrupt */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned el3_read_eeprom(port_t port, unsigned address);
|
||||||
|
** Function: Reads the EEPROM at specified address
|
||||||
|
*/
|
||||||
|
static unsigned el3_read_eeprom(port_t port, unsigned address)
|
||||||
|
{
|
||||||
|
unsigned int result;
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
address |= EL3_READ_EEPROM;
|
||||||
|
outb(port, address);
|
||||||
|
milli_delay(5); /* Allows EEPROM reads */
|
||||||
|
for (result = 0, bit = 16; bit > 0; bit -= 1) {
|
||||||
|
result = (result << 1) | (inb(port) & 0x0001);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_read_StationAddress(dpeth_t *dep)
|
||||||
|
** Function: Reads station address from board
|
||||||
|
*/
|
||||||
|
static void el3_read_StationAddress(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
unsigned int ix, rc;
|
||||||
|
|
||||||
|
for (ix = EE_3COM_NODE_ADDR; ix < SA_ADDR_LEN;) {
|
||||||
|
/* Accesses with word No. */
|
||||||
|
rc = el3_read_eeprom(dep->de_id_port, ix / 2);
|
||||||
|
/* Swaps bytes of word */
|
||||||
|
dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF;
|
||||||
|
dep->de_address.ea_addr[ix++] = rc & 0xFF;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_open(dpeth_t *dep)
|
||||||
|
** Function: Initalizes board hardware and driver data structures.
|
||||||
|
*/
|
||||||
|
static void el3_open(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
unsigned int AddrCfgReg, ResCfgReg;
|
||||||
|
unsigned int ix;
|
||||||
|
|
||||||
|
el3_read_StationAddress(dep); /* Get ethernet address */
|
||||||
|
|
||||||
|
/* Get address and resource configurations */
|
||||||
|
AddrCfgReg = el3_read_eeprom(dep->de_id_port, EE_ADDR_CFG);
|
||||||
|
ResCfgReg = el3_read_eeprom(dep->de_id_port, EE_RESOURCE_CFG);
|
||||||
|
outb(dep->de_id_port, EL3_ACTIVATE); /* Activate the board */
|
||||||
|
|
||||||
|
/* Gets xcvr configuration */
|
||||||
|
dep->de_if_port = AddrCfgReg & EL3_CONFIG_XCVR_MASK;
|
||||||
|
|
||||||
|
AddrCfgReg = ((AddrCfgReg & EL3_CONFIG_IOBASE_MASK) << 4) + EL3_IO_BASE_ADDR;
|
||||||
|
if (AddrCfgReg != dep->de_base_port)
|
||||||
|
panic(dep->de_name, "Bad I/O port for Etherlink board", NO_NUM);
|
||||||
|
|
||||||
|
ResCfgReg >>= 12;
|
||||||
|
dep->de_irq &= NOT(DEI_DEFAULT); /* Strips the default flag */
|
||||||
|
if (ResCfgReg != dep->de_irq) panic(dep->de_name, "Bad IRQ for Etherlink board", NO_NUM);
|
||||||
|
|
||||||
|
SetWindow(WNO_Setup);
|
||||||
|
|
||||||
|
/* Reset transmitter and receiver */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxReset);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxReset);
|
||||||
|
|
||||||
|
/* Enable the adapter */
|
||||||
|
outb_el3(dep, REG_CfgControl, EL3_EnableAdapter);
|
||||||
|
/* Disable Status bits */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab + 0x00);
|
||||||
|
|
||||||
|
/* Set "my own" address */
|
||||||
|
SetWindow(WNO_StationAddress);
|
||||||
|
for (ix = 0; ix < 6; ix += 1)
|
||||||
|
outb_el3(dep, REG_SA0_1 + ix, dep->de_address.ea_addr[ix]);
|
||||||
|
|
||||||
|
/* Start Transceivers as required */
|
||||||
|
if (dep->de_if_port == BNC_XCVR) {
|
||||||
|
/* Start internal transceiver for Coaxial cable */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr);
|
||||||
|
milli_delay(5);
|
||||||
|
|
||||||
|
} else if (dep->de_if_port == TP_XCVR) {
|
||||||
|
/* Start internal transceiver for Twisted pair cable */
|
||||||
|
SetWindow(WNO_Diagnostics);
|
||||||
|
outw_el3(dep, REG_MediaStatus,
|
||||||
|
inw_el3(dep, REG_MediaStatus) | (MediaLBeatEnable | MediaJabberEnable));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch to the statistic window, and clear counts (by reading) */
|
||||||
|
SetWindow(WNO_Statistics);
|
||||||
|
for (ix = REG_TxCarrierLost; ix <= REG_TxDefer; ix += 1) inb_el3(dep, ix);
|
||||||
|
inw_el3(dep, REG_RxBytes);
|
||||||
|
inw_el3(dep, REG_TxBytes);
|
||||||
|
|
||||||
|
/* Switch to operating window for normal use */
|
||||||
|
SetWindow(WNO_Operating);
|
||||||
|
|
||||||
|
/* Receive individual address & broadcast. (Mofified later by rx_mode) */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter |
|
||||||
|
(FilterIndividual | FilterBroadcast));
|
||||||
|
|
||||||
|
/* Turn on statistics */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_StatsEnable);
|
||||||
|
|
||||||
|
/* Enable transmitter and receiver */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_TxEnable);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_RxEnable);
|
||||||
|
|
||||||
|
/* Enable all the status bits */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetStatusEnab | 0xFF);
|
||||||
|
|
||||||
|
/* Acknowledge all interrupts to clear adapter. Enable interrupts */
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | 0xFF);
|
||||||
|
outw_el3(dep, REG_CmdStatus, CMD_SetIntMask |
|
||||||
|
(INT_Latch | INT_TxAvailable | INT_RxComplete | INT_UpdateStats));
|
||||||
|
|
||||||
|
/* Ready to operate, sets the environment for eth_task */
|
||||||
|
dep->de_data_port = dep->de_base_port;
|
||||||
|
/* Allocates Rx/Tx buffers */
|
||||||
|
init_buff(dep, NULL);
|
||||||
|
|
||||||
|
/* Device specific functions */
|
||||||
|
dep->de_recvf = el3_recv;
|
||||||
|
dep->de_sendf = el3_send;
|
||||||
|
dep->de_flagsf = el3_rx_mode;
|
||||||
|
dep->de_resetf = el3_reset;
|
||||||
|
dep->de_getstatsf = el3_getstats;
|
||||||
|
dep->de_dumpstatsf = el3_dodump;
|
||||||
|
dep->de_interruptf = el3_interrupt;
|
||||||
|
|
||||||
|
printf("%s: Etherlink III (%s) at %X:%d, %s port - ",
|
||||||
|
dep->de_name, "3c509", dep->de_base_port, dep->de_irq,
|
||||||
|
IfNamesMsg[dep->de_if_port >> 14]);
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
|
||||||
|
printf("%02X%c", dep->de_address.ea_addr[ix],
|
||||||
|
ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||||
|
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned int el3_checksum(port_t port);
|
||||||
|
** Function: Reads EEPROM and computes checksum.
|
||||||
|
*/
|
||||||
|
static unsigned short el3_checksum(port_t port)
|
||||||
|
{
|
||||||
|
unsigned short rc, checksum, address;
|
||||||
|
unsigned char lo, hi;
|
||||||
|
|
||||||
|
for (checksum = address = 0; address < 15; address += 1) {
|
||||||
|
rc = el3_read_eeprom(port, address);
|
||||||
|
lo = rc & 0xFF;
|
||||||
|
hi = (rc >> 8) & 0xFF;
|
||||||
|
if ((address == EE_PROD_ID && (rc & EE_PROD_ID_MASK) != EL3_PRODUCT_ID) ||
|
||||||
|
(address == EE_3COM_CODE && rc != EL3_3COM_CODE))
|
||||||
|
return address;
|
||||||
|
if (address == EE_ADDR_CFG ||
|
||||||
|
address == EE_RESOURCE_CFG ||
|
||||||
|
address == EE_SW_CONFIG_INFO) {
|
||||||
|
lo ^= hi;
|
||||||
|
hi = 0;
|
||||||
|
} else {
|
||||||
|
hi ^= lo;
|
||||||
|
lo = 0;
|
||||||
|
}
|
||||||
|
rc = ((unsigned) hi << 8) + lo;
|
||||||
|
checksum ^= rc;
|
||||||
|
}
|
||||||
|
rc = el3_read_eeprom(port, address);
|
||||||
|
return(checksum ^= rc); /* If OK checksum is 0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void el3_write_id(port_t port);
|
||||||
|
** Function: Writes the ID sequence to the board.
|
||||||
|
*/
|
||||||
|
static void el3_write_id(port_t port)
|
||||||
|
{
|
||||||
|
int ix, pattern;
|
||||||
|
|
||||||
|
outb(port, 0); /* Selects the ID port */
|
||||||
|
outb(port, 0); /* Resets hardware pattern generator */
|
||||||
|
for (pattern = ix = 0x00FF; ix > 0; ix -= 1) {
|
||||||
|
outb(port, pattern);
|
||||||
|
pattern <<= 1;
|
||||||
|
pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: int el3_probe(dpeth_t *dep)
|
||||||
|
** Function: Checks for presence of the board.
|
||||||
|
*/
|
||||||
|
PUBLIC int el3_probe(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
port_t id_port;
|
||||||
|
|
||||||
|
/* Don't ask me what is this for !! */
|
||||||
|
outb(0x0279, 0x02); /* Select PnP config control register. */
|
||||||
|
outb(0x0A79, 0x02); /* Return to WaitForKey state. */
|
||||||
|
/* Tests I/O ports in the 0x1xF range for a valid ID port */
|
||||||
|
for (id_port = 0x110; id_port < 0x200; id_port += 0x10) {
|
||||||
|
outb(id_port, 0x00);
|
||||||
|
outb(id_port, 0xFF);
|
||||||
|
if (inb(id_port) & 0x01) break;
|
||||||
|
}
|
||||||
|
if (id_port == 0x200) return 0; /* No board responding */
|
||||||
|
|
||||||
|
el3_write_id(id_port);
|
||||||
|
outb(id_port, EL3_ID_GLOBAL_RESET); /* Reset the board */
|
||||||
|
milli_delay(5); /* Technical reference says 162 micro sec. */
|
||||||
|
el3_write_id(id_port);
|
||||||
|
outb(id_port, EL3_SET_TAG_REGISTER);
|
||||||
|
milli_delay(5);
|
||||||
|
|
||||||
|
dep->de_id_port = id_port; /* Stores ID port No. */
|
||||||
|
dep->de_ramsize = /* RAM size is meaningless */
|
||||||
|
dep->de_offset_page = 0;
|
||||||
|
dep->de_linmem = 0L; /* Access is via I/O port */
|
||||||
|
|
||||||
|
/* Device specific functions */
|
||||||
|
dep->de_initf = el3_open;
|
||||||
|
dep->de_stopf = el3_close;
|
||||||
|
|
||||||
|
return(el3_checksum(id_port) == 0); /* Etherlink board found/not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING */
|
||||||
|
|
||||||
|
/** 3c509.c **/
|
164
drivers/dpeth/3c509.h
Normal file
164
drivers/dpeth/3c509.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
** File: 3c509.h Jun. 01, 2000
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** Interface description for 3Com Etherlink III board.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Command codes */
|
||||||
|
#define CMD_GlobalReset 0x0000 /* resets adapter (power up status) */
|
||||||
|
#define CMD_SelectWindow (1<<11) /* select register window */
|
||||||
|
#define CMD_StartIntXcvr (2<<11) /* start internal transciver */
|
||||||
|
#define CMD_RxDisable (3<<11) /* rx disable */
|
||||||
|
#define CMD_RxEnable (4<<11) /* rx enable */
|
||||||
|
#define CMD_RxReset (5<<11) /* rx reset */
|
||||||
|
#define CMD_RxDiscard (8<<11) /* rx discard top packet */
|
||||||
|
#define CMD_TxEnable (9<<11) /* tx enable */
|
||||||
|
#define CMD_TxDisable (10<<11) /* tx disable */
|
||||||
|
#define CMD_TxReset (11<<11) /* tx reset */
|
||||||
|
#define CMD_Acknowledge (13<<11) /* acknowledge interrupt */
|
||||||
|
#define CMD_SetIntMask (14<<11) /* set interrupt mask */
|
||||||
|
#define CMD_SetStatusEnab (15<<11) /* set read zero mask */
|
||||||
|
#define CMD_SetRxFilter (16<<11) /* set rx filter */
|
||||||
|
#define CMD_SetTxAvailable (18<<11) /* set tx available threshold */
|
||||||
|
#define CMD_StatsEnable (21<<11) /* statistics enable */
|
||||||
|
#define CMD_StatsDisable (22<<11) /* statistics disable */
|
||||||
|
#define CMD_StopIntXcvr (23<<11) /* start internal transciver */
|
||||||
|
|
||||||
|
/* Status register bits (INT for interrupt sources, ST for the rest) */
|
||||||
|
#define INT_Latch 0x0001 /* interrupt latch */
|
||||||
|
#define INT_AdapterFail 0x0002 /* adapter failure */
|
||||||
|
#define INT_TxComplete 0x0004 /* tx complete */
|
||||||
|
#define INT_TxAvailable 0x0008 /* tx available */
|
||||||
|
#define INT_RxComplete 0x0010 /* rx complete */
|
||||||
|
#define INT_RxEarly 0x0020 /* rx early */
|
||||||
|
#define INT_Requested 0x0040 /* interrupt requested */
|
||||||
|
#define INT_UpdateStats 0x0080 /* update statistics */
|
||||||
|
|
||||||
|
/* Rx Status register bits */
|
||||||
|
#define RXS_Error 0x4000 /* error in packet */
|
||||||
|
#define RXS_Length 0x07FF /* bytes in RxFIFO */
|
||||||
|
#define RXS_ErrType 0x3800 /* Rx error type, bit 13-11 */
|
||||||
|
#define RXS_Overrun 0x0000 /* overrun error */
|
||||||
|
#define RXS_Oversize 0x0800 /* oversize packet error */
|
||||||
|
#define RXS_Dribble 0x1000 /* dribble bit (not an error) */
|
||||||
|
#define RXS_Runt 0x1800 /* runt packet error */
|
||||||
|
#define RXS_Framing 0x2000 /* framing error */
|
||||||
|
#define RXS_CRC 0x2800 /* CRC error */
|
||||||
|
|
||||||
|
/* Tx Status register bits */
|
||||||
|
|
||||||
|
/* Window Numbers */
|
||||||
|
#define WNO_Setup 0x0000 /* setup/configuration */
|
||||||
|
#define WNO_Operating 0x0001 /* operating set */
|
||||||
|
#define WNO_StationAddress 0x0002 /* station address setup/read */
|
||||||
|
#define WNO_Diagnostics 0x0004 /* diagnostics */
|
||||||
|
#define WNO_Statistics 0x0006 /* statistics */
|
||||||
|
|
||||||
|
/* Register offsets - Window 1 (WNO_Operating) */
|
||||||
|
#define REG_CmdStatus 0x000E /* command/status */
|
||||||
|
#define REG_TxFree 0x000C /* free transmit bytes */
|
||||||
|
#define REG_TxStatus 0x000B /* transmit status (byte) */
|
||||||
|
#define REG_RxStatus 0x0008 /* receive status */
|
||||||
|
#define REG_RxFIFO 0x0000 /* RxFIFO read */
|
||||||
|
#define REG_TxFIFO 0x0000 /* TxFIFO write */
|
||||||
|
|
||||||
|
/* Register offsets - Window 0 (WNO_Setup) */
|
||||||
|
#define REG_CfgControl 0x0004 /* configuration control */
|
||||||
|
|
||||||
|
/* Register offsets - Window 2 (WNO_StationAddress) */
|
||||||
|
#define REG_SA0_1 0x0000 /* station address bytes 0,1 */
|
||||||
|
|
||||||
|
/* Register offsets - Window 3 (WNO_FIFO) */
|
||||||
|
|
||||||
|
/* Register offsets - Window 4 (WNO_Diagnostics) */
|
||||||
|
#define REG_MediaStatus 0x000A /* media type/status */
|
||||||
|
|
||||||
|
/* Register offsets - Window 5 (WNO_Readable) */
|
||||||
|
|
||||||
|
/* Register offsets - Window 6 (WNO_Statistics) */
|
||||||
|
#define REG_TxBytes 0x000C /* tx bytes ok */
|
||||||
|
#define REG_RxBytes 0x000A /* rx bytes ok */
|
||||||
|
#define REG_TxDefer 0x0008 /* tx frames deferred (byte) */
|
||||||
|
#define REG_RxFrames 0x0007 /* rx frames ok (byte) */
|
||||||
|
#define REG_TxFrames 0x0006 /* tx frames ok (byte) */
|
||||||
|
#define REG_RxDiscarded 0x0005 /* rx frames discarded (byte) */
|
||||||
|
#define REG_TxLate 0x0004 /* tx frames late coll. (byte) */
|
||||||
|
#define REG_TxSingleColl 0x0003 /* tx frames one coll. (byte) */
|
||||||
|
#define REG_TxMultColl 0x0002 /* tx frames mult. coll. (byte) */
|
||||||
|
#define REG_TxNoCD 0x0001 /* tx frames no CDheartbt (byte) */
|
||||||
|
#define REG_TxCarrierLost 0x0000 /* tx frames carrier lost (byte) */
|
||||||
|
|
||||||
|
/* Various command arguments */
|
||||||
|
|
||||||
|
#define FilterIndividual 0x0001 /* individual address */
|
||||||
|
#define FilterMulticast 0x0002 /* multicast/group addresses */
|
||||||
|
#define FilterBroadcast 0x0004 /* broadcast address */
|
||||||
|
#define FilterPromiscuous 0x0008 /* promiscuous mode */
|
||||||
|
|
||||||
|
/* Resource Configuration Register bits */
|
||||||
|
#define EL3_CONFIG_IRQ_MASK 0xF000
|
||||||
|
|
||||||
|
/* Address Configuration Register bits */
|
||||||
|
#define EL3_CONFIG_XCVR_MASK 0xC000
|
||||||
|
#define EL3_CONFIG_IOBASE_MASK 0x001F
|
||||||
|
|
||||||
|
#define TP_XCVR 0x0000
|
||||||
|
#define BNC_XCVR 0xC000
|
||||||
|
#define AUI_XCVR 0x4000
|
||||||
|
|
||||||
|
#define EL3_IO_BASE_ADDR 0x200
|
||||||
|
|
||||||
|
/* Transmit Preamble */
|
||||||
|
|
||||||
|
/* Bits in various diagnostics registers */
|
||||||
|
#define MediaLBeatEnable 0x0080 /* link beat enable (TP) */
|
||||||
|
#define MediaJabberEnable 0x0040 /* jabber enable (TP) */
|
||||||
|
|
||||||
|
/* Board identification codes, byte swapped in Rev 0 */
|
||||||
|
#define EL3_3COM_CODE 0x6D50 /* EISA manufacturer code */
|
||||||
|
#define EL3_PRODUCT_ID 0x9050 /* Product ID for ISA board */
|
||||||
|
|
||||||
|
/* EEProm access */
|
||||||
|
#define EE_3COM_NODE_ADDR 0x00
|
||||||
|
#define EE_PROD_ID 0x03
|
||||||
|
#define EE_MANUFACTURING_DATA 0x04
|
||||||
|
#define EE_3COM_CODE 0x07
|
||||||
|
#define EE_ADDR_CFG 0x08
|
||||||
|
#define EE_RESOURCE_CFG 0x09
|
||||||
|
#define EE_SW_CONFIG_INFO 0x0D
|
||||||
|
#define EE_PROD_ID_MASK 0xF0FF /* Mask off revision nibble */
|
||||||
|
|
||||||
|
/* Contention logic */
|
||||||
|
#define EL3_READ_EEPROM 0x80
|
||||||
|
#define EL3_ID_GLOBAL_RESET 0xC0
|
||||||
|
#define EL3_SET_TAG_REGISTER 0xD0
|
||||||
|
#define EL3_ACTIVATE_AND_SET_IO 0xE0
|
||||||
|
#define EL3_ACTIVATE 0xFF
|
||||||
|
|
||||||
|
/* Software Configuration Register bits */
|
||||||
|
|
||||||
|
/* Configuration Control Register bits */
|
||||||
|
#define EL3_EnableAdapter 0x01
|
||||||
|
|
||||||
|
/* EL3 access macros */
|
||||||
|
#define inb_el3(dep,reg) (inb((dep)->de_base_port+(reg)))
|
||||||
|
#define inw_el3(dep,reg) (inw((dep)->de_base_port+(reg)))
|
||||||
|
#define outb_el3(dep,reg,data) (outb((dep)->de_base_port+(reg),(data)))
|
||||||
|
#define outw_el3(dep,reg,data) (outw((dep)->de_base_port+(reg),(data)))
|
||||||
|
|
||||||
|
#define SetWindow(win) \
|
||||||
|
outw(dep->de_base_port+REG_CmdStatus,CMD_SelectWindow|(win))
|
||||||
|
|
||||||
|
/** 3c509.h **/
|
739
drivers/dpeth/8390.c
Normal file
739
drivers/dpeth/8390.c
Normal file
|
@ -0,0 +1,739 @@
|
||||||
|
/*
|
||||||
|
** File: 8390.c May 02, 2000
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains an ethernet device driver for NICs
|
||||||
|
** equipped with the National Semiconductor NS 8390 chip.
|
||||||
|
** It has to be associated with the board specific driver.
|
||||||
|
** Rewritten from Minix 2.0.0 ethernet driver dp8390.c
|
||||||
|
** to extract the NS 8390 common functions.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <minix/com.h>
|
||||||
|
#include <net/hton.h>
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if (ENABLE_NETWORKING == 1 && ENABLE_DP8390 == 1)
|
||||||
|
|
||||||
|
#define PIO16 0 /* NOTE: pio 16 functions missing */
|
||||||
|
|
||||||
|
#include "8390.h"
|
||||||
|
|
||||||
|
static const char RdmaErrMsg[] = "remote dma failed to complete";
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
|
||||||
|
** Function: Sets the board for reading/writing.
|
||||||
|
*/
|
||||||
|
static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
|
||||||
|
outb_reg0(dep, DP_RBCR0, size & 0xFF);
|
||||||
|
outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
|
||||||
|
outb_reg0(dep, DP_RSAR0, offset & 0xFF);
|
||||||
|
outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
|
||||||
|
mode |= (CR_PS_P0 | CR_STA);
|
||||||
|
outb_reg0(dep, DP_CR, mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);
|
||||||
|
** Function: Sets the board for for transmitting and fires it.
|
||||||
|
*/
|
||||||
|
static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
|
||||||
|
{
|
||||||
|
|
||||||
|
outb_reg0(dep, DP_TPSR, pageno);
|
||||||
|
outb_reg0(dep, DP_TBCR1, size >> 8);
|
||||||
|
outb_reg0(dep, DP_TBCR0, size & 0xFF);
|
||||||
|
outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void mem_getblock(dpeth_t *dep, u16_t offset,
|
||||||
|
** int size, void *dst)
|
||||||
|
** Function: Reads a block of packet from board (shared memory).
|
||||||
|
*/
|
||||||
|
static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
||||||
|
{
|
||||||
|
|
||||||
|
sys_datacopy(dep->de_memsegm, dep->de_linmem + offset,
|
||||||
|
SELF, (vir_bytes)dst, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
|
||||||
|
** Function: Copies a packet from board to user area (shared memory).
|
||||||
|
*/
|
||||||
|
static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
|
||||||
|
{
|
||||||
|
phys_bytes offset, phys_user;
|
||||||
|
iovec_dat_t *iovp = &dep->de_read_iovec;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
|
||||||
|
/* Computes shared memory address (skipping receive header) */
|
||||||
|
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet into user area */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
|
||||||
|
/* Reads from board to user area */
|
||||||
|
if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
||||||
|
|
||||||
|
/* Circular buffer wrap-around */
|
||||||
|
bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
||||||
|
sys_datacopy(dep->de_memsegm, dep->de_linmem + offset,
|
||||||
|
iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
|
||||||
|
pktsize -= bytes;
|
||||||
|
phys_user += bytes;
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
offset = dep->de_startpage * DP_PAGESIZE;
|
||||||
|
}
|
||||||
|
sys_datacopy(dep->de_memsegm, dep->de_linmem + offset,
|
||||||
|
iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
|
||||||
|
offset += bytes;
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
** Function: Copies a packet from user area to board (shared memory).
|
||||||
|
*/
|
||||||
|
static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
{
|
||||||
|
phys_bytes offset, phys_user;
|
||||||
|
iovec_dat_t *iovp = &dep->de_write_iovec;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
|
||||||
|
/* Computes shared memory address */
|
||||||
|
offset = dep->de_linmem + pageno * DP_PAGESIZE;
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet from user area */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
|
||||||
|
/* Reads from user area to board (shared memory) */
|
||||||
|
sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
|
||||||
|
dep->de_memsegm, dep->de_linmem + offset, bytes);
|
||||||
|
offset += bytes;
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
|
||||||
|
** int size, void *dst)
|
||||||
|
** Function: Reads a block of packet from board (Prog. I/O).
|
||||||
|
*/
|
||||||
|
static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Sets up board for reading */
|
||||||
|
ns_rw_setup(dep, CR_DM_RR, size, offset);
|
||||||
|
|
||||||
|
#if PIO16 == 0
|
||||||
|
insb(dep->de_data_port, SELF, dst, size);
|
||||||
|
#else
|
||||||
|
if (dep->de_16bit == TRUE) {
|
||||||
|
insw(dep->de_data_port, dst, size);
|
||||||
|
} else {
|
||||||
|
insb(dep->de_data_port, dst, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
** Function: Copies a packet from board to user area (Prog. I/O).
|
||||||
|
*/
|
||||||
|
static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
iovec_dat_t *iovp = &dep->de_read_iovec;
|
||||||
|
unsigned offset; int bytes, ix = 0;
|
||||||
|
|
||||||
|
/* Computes memory address (skipping receive header) */
|
||||||
|
offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
||||||
|
/* Sets up board for reading */
|
||||||
|
ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
|
||||||
|
(dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet into user area */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
|
||||||
|
if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
||||||
|
|
||||||
|
/* Circular buffer wrap-around */
|
||||||
|
bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
||||||
|
insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
||||||
|
pktsize -= bytes;
|
||||||
|
iovp->iod_iovec[ix].iov_addr += bytes;
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
offset = dep->de_startpage * DP_PAGESIZE;
|
||||||
|
ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
|
||||||
|
}
|
||||||
|
insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
||||||
|
offset += bytes;
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
** Function: Copies a packet from user area to board (Prog. I/O).
|
||||||
|
*/
|
||||||
|
static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
iovec_dat_t *iovp = &dep->de_write_iovec;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
|
||||||
|
/* Sets up board for writing */
|
||||||
|
ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet from user area */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
outsb(dep->de_data_port, iovp->iod_proc_nr,
|
||||||
|
(void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
|
||||||
|
for (ix = 0; ix < 100; ix += 1) {
|
||||||
|
if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
||||||
|
}
|
||||||
|
if (ix == 100) {
|
||||||
|
panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_stats(dpeth_t * dep)
|
||||||
|
** Function: Updates counters reading from device
|
||||||
|
*/
|
||||||
|
static void ns_stats(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
||||||
|
dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
||||||
|
dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_dodump(dpeth_t * dep)
|
||||||
|
** Function: Displays statistics (a request from F5 key).
|
||||||
|
*/
|
||||||
|
static void ns_dodump(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
ns_stats(dep); /* Forces reading fo counters from board */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_reinit(dpeth_t *dep)
|
||||||
|
** Function: Updates receiver configuration.
|
||||||
|
*/
|
||||||
|
static void ns_reinit(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int dp_reg = 0;
|
||||||
|
|
||||||
|
if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
||||||
|
if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
||||||
|
if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
||||||
|
outb_reg0(dep, DP_CR, CR_PS_P0);
|
||||||
|
outb_reg0(dep, DP_RCR, dp_reg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_send(dpeth_t * dep, int from_int, int size)
|
||||||
|
** Function: Transfers packet to device and starts sending.
|
||||||
|
*/
|
||||||
|
static void ns_send(dpeth_t * dep, int from_int, int size)
|
||||||
|
{
|
||||||
|
int queue;
|
||||||
|
|
||||||
|
if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
|
||||||
|
if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
|
||||||
|
dep->de_send_s = size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
|
||||||
|
dep->bytes_Tx += (long) size;
|
||||||
|
dep->de_sendq[queue].sq_filled = TRUE;
|
||||||
|
dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
||||||
|
if (dep->de_sendq_tail == queue) { /* there it goes.. */
|
||||||
|
ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
|
||||||
|
} else
|
||||||
|
dep->de_sendq[queue].sq_size = size;
|
||||||
|
|
||||||
|
if (++queue == dep->de_sendq_nr) queue = 0;
|
||||||
|
dep->de_sendq_head = queue;
|
||||||
|
dep->de_flags &= NOT(DEF_SENDING);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_reset(dpeth_t *dep)
|
||||||
|
** Function: Resets device.
|
||||||
|
*/
|
||||||
|
static void ns_reset(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
/* Stop chip */
|
||||||
|
outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
|
||||||
|
outb_reg0(dep, DP_RBCR0, 0);
|
||||||
|
outb_reg0(dep, DP_RBCR1, 0);
|
||||||
|
for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
|
||||||
|
/* Do nothing */ ;
|
||||||
|
outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
|
||||||
|
outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
|
||||||
|
outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
|
||||||
|
|
||||||
|
/* Acknowledge the ISR_RDC (remote dma) interrupt. */
|
||||||
|
for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
|
||||||
|
/* Do nothing */ ;
|
||||||
|
outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
|
||||||
|
|
||||||
|
/* Reset the transmit ring. If we were transmitting a packet, we
|
||||||
|
* pretend that the packet is processed. Higher layers will
|
||||||
|
* retransmit if the packet wasn't actually sent. */
|
||||||
|
dep->de_sendq_head = dep->de_sendq_tail = 0;
|
||||||
|
for (ix = 0; ix < dep->de_sendq_nr; ix++)
|
||||||
|
dep->de_sendq[ix].sq_filled = FALSE;
|
||||||
|
ns_send(dep, TRUE, dep->de_send_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
|
||||||
|
** Function: Gets a packet from device
|
||||||
|
*/
|
||||||
|
static void ns_recv(dpeth_t *dep, int fromint, int size)
|
||||||
|
{
|
||||||
|
dp_rcvhdr_t header;
|
||||||
|
dp_rcvhdr_t dummy;
|
||||||
|
unsigned pageno, curr, next;
|
||||||
|
vir_bytes length;
|
||||||
|
int packet_processed = FALSE;
|
||||||
|
#ifdef ETH_IGN_PROTO
|
||||||
|
u16_t eth_type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pageno = inb_reg0(dep, DP_BNRY) + 1;
|
||||||
|
if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* */
|
||||||
|
outb_reg0(dep, DP_CR, CR_PS_P1);
|
||||||
|
curr = inb_reg1(dep, DP_CURR);
|
||||||
|
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
|
||||||
|
|
||||||
|
if (curr == pageno) break;
|
||||||
|
|
||||||
|
(dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
|
||||||
|
#ifdef ETH_IGN_PROTO
|
||||||
|
(dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type);
|
||||||
|
#endif
|
||||||
|
length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
|
||||||
|
next = header.dr_next;
|
||||||
|
|
||||||
|
if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
|
||||||
|
printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
|
||||||
|
dep->de_stat.ets_recvErr += 1;
|
||||||
|
next = curr;
|
||||||
|
|
||||||
|
} else if (next < dep->de_startpage || next >= dep->de_stoppage) {
|
||||||
|
printf("%s: strange next page\n", dep->de_name);
|
||||||
|
dep->de_stat.ets_recvErr += 1;
|
||||||
|
next = curr;
|
||||||
|
|
||||||
|
#ifdef ETH_IGN_PROTO
|
||||||
|
} else if (eth_type == eth_ign_proto) {
|
||||||
|
/* Hack: ignore packets of a given protocol */
|
||||||
|
static int first = TRUE;
|
||||||
|
if (first) {
|
||||||
|
first = FALSE;
|
||||||
|
printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
|
||||||
|
}
|
||||||
|
next = curr;
|
||||||
|
#endif
|
||||||
|
} else if (header.dr_status & RSR_FO) {
|
||||||
|
/* This is very serious, issue a warning and reset buffers */
|
||||||
|
printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
|
||||||
|
dep->de_stat.ets_fifoOver += 1;
|
||||||
|
next = curr;
|
||||||
|
|
||||||
|
} else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
|
||||||
|
|
||||||
|
if (!(dep->de_flags & DEF_READING)) break;
|
||||||
|
|
||||||
|
(dep->de_nic2userf) (dep, pageno, length);
|
||||||
|
dep->de_read_s = length;
|
||||||
|
dep->de_flags |= DEF_ACK_RECV;
|
||||||
|
dep->de_flags &= NOT(DEF_READING);
|
||||||
|
packet_processed = TRUE;
|
||||||
|
}
|
||||||
|
dep->bytes_Rx += (long) length;
|
||||||
|
dep->de_stat.ets_packetR += 1;
|
||||||
|
outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
|
||||||
|
pageno = next;
|
||||||
|
|
||||||
|
} while (!packet_processed);
|
||||||
|
#if 0
|
||||||
|
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
|
||||||
|
/* The chip is stopped, and all arrived packets delivered */
|
||||||
|
(*dep->de_resetf) (dep);
|
||||||
|
dep->de_flags &= NOT(DEF_STOPPED);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_interrupt(dpeth_t * dep)
|
||||||
|
** Function: Handles interrupt.
|
||||||
|
*/
|
||||||
|
static void ns_interrupt(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int isr, tsr;
|
||||||
|
int size, queue;
|
||||||
|
|
||||||
|
while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
|
||||||
|
|
||||||
|
outb_reg0(dep, DP_ISR, isr);
|
||||||
|
if (isr & (ISR_PTX | ISR_TXE)) {
|
||||||
|
|
||||||
|
tsr = inb_reg0(dep, DP_TSR);
|
||||||
|
if (tsr & TSR_PTX) {
|
||||||
|
dep->de_stat.ets_packetT++;
|
||||||
|
}
|
||||||
|
if (tsr & TSR_COL) dep->de_stat.ets_collision++;
|
||||||
|
if (tsr & (TSR_ABT | TSR_FU)) {
|
||||||
|
dep->de_stat.ets_fifoUnder++;
|
||||||
|
}
|
||||||
|
if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
|
||||||
|
printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
|
||||||
|
dep->de_stat.ets_sendErr++;
|
||||||
|
}
|
||||||
|
queue = dep->de_sendq_tail;
|
||||||
|
|
||||||
|
if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
|
||||||
|
printf("%s: transmit interrupt, but not sending\n", dep->de_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dep->de_sendq[queue].sq_filled = FALSE;
|
||||||
|
if (++queue == dep->de_sendq_nr) queue = 0;
|
||||||
|
dep->de_sendq_tail = queue;
|
||||||
|
if (dep->de_sendq[queue].sq_filled) {
|
||||||
|
ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
|
||||||
|
dep->de_sendq[queue].sq_sendpage);
|
||||||
|
}
|
||||||
|
if (dep->de_flags & DEF_SENDING) {
|
||||||
|
ns_send(dep, TRUE, dep->de_send_s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isr & ISR_PRX) {
|
||||||
|
ns_recv(dep, TRUE, 0);
|
||||||
|
}
|
||||||
|
if (isr & ISR_RXE) {
|
||||||
|
printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
|
||||||
|
dep->de_stat.ets_recvErr++;
|
||||||
|
}
|
||||||
|
if (isr & ISR_CNT) {
|
||||||
|
dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
||||||
|
dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
||||||
|
dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
||||||
|
}
|
||||||
|
if (isr & ISR_OVW) {
|
||||||
|
printf("%s: got overwrite warning\n", dep->de_name);
|
||||||
|
}
|
||||||
|
if (isr & ISR_RDC) {
|
||||||
|
/* Nothing to do */
|
||||||
|
}
|
||||||
|
if (isr & ISR_RST) {
|
||||||
|
/* This means we got an interrupt but the ethernet
|
||||||
|
* chip is shutdown. We set the flag DEF_STOPPED, and
|
||||||
|
* continue processing arrived packets. When the
|
||||||
|
* receive buffer is empty, we reset the dp8390. */
|
||||||
|
printf("%s: network interface stopped\n", dep->de_name);
|
||||||
|
dep->de_flags |= DEF_STOPPED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
|
||||||
|
|
||||||
|
/* The chip is stopped, and all arrived packets delivered */
|
||||||
|
ns_reset(dep);
|
||||||
|
dep->de_flags &= NOT(DEF_STOPPED);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ns_init(dpeth_t *dep)
|
||||||
|
** Function: Initializes the NS 8390
|
||||||
|
*/
|
||||||
|
void ns_init(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int dp_reg;
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
/* NS8390 initialization (as recommended in National Semiconductor specs) */
|
||||||
|
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
|
||||||
|
#if PIO16 == 0
|
||||||
|
outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
||||||
|
#else
|
||||||
|
outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
|
||||||
|
DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
||||||
|
#endif
|
||||||
|
outb_reg0(dep, DP_RBCR0, 0);
|
||||||
|
outb_reg0(dep, DP_RBCR1, 0);
|
||||||
|
outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
|
||||||
|
outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
|
||||||
|
outb_reg0(dep, DP_PSTART, dep->de_startpage);
|
||||||
|
outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
|
||||||
|
outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
|
||||||
|
outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
||||||
|
outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
|
||||||
|
|
||||||
|
/* Copies station address in page 1 registers */
|
||||||
|
outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
|
||||||
|
outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
|
||||||
|
for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
|
||||||
|
outb_reg1(dep, ix, 0xFF);
|
||||||
|
|
||||||
|
outb_reg1(dep, DP_CURR, dep->de_startpage);
|
||||||
|
outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
|
||||||
|
|
||||||
|
inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
|
||||||
|
inb_reg0(dep, DP_CNTR1);
|
||||||
|
inb_reg0(dep, DP_CNTR2);
|
||||||
|
|
||||||
|
dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
|
||||||
|
outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
||||||
|
outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
|
||||||
|
|
||||||
|
dp_reg = 0;
|
||||||
|
if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
||||||
|
if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
||||||
|
if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
||||||
|
outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
|
||||||
|
outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
|
||||||
|
|
||||||
|
outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
|
||||||
|
|
||||||
|
/* Initializes the send queue. */
|
||||||
|
for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
|
||||||
|
dep->de_sendq[ix].sq_filled = 0;
|
||||||
|
dep->de_sendq_head = dep->de_sendq_tail = 0;
|
||||||
|
|
||||||
|
/* Device specific functions */
|
||||||
|
if (!dep->de_prog_IO) {
|
||||||
|
dep->de_user2nicf = mem_user2nic;
|
||||||
|
dep->de_nic2userf = mem_nic2user;
|
||||||
|
dep->de_getblockf = mem_getblock;
|
||||||
|
} else {
|
||||||
|
#if PIO16 == 0
|
||||||
|
dep->de_user2nicf = pio_user2nic;
|
||||||
|
dep->de_nic2userf = pio_nic2user;
|
||||||
|
dep->de_getblockf = pio_getblock;
|
||||||
|
#else
|
||||||
|
#error Missing I/O functions for pio 16 bits
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
dep->de_recvf = ns_recv;
|
||||||
|
dep->de_sendf = ns_send;
|
||||||
|
dep->de_flagsf = ns_reinit;
|
||||||
|
dep->de_resetf = ns_reset;
|
||||||
|
dep->de_getstatsf = ns_stats;
|
||||||
|
dep->de_dumpstatsf = ns_dodump;
|
||||||
|
dep->de_interruptf = ns_interrupt;
|
||||||
|
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PIO16 == 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
|
||||||
|
*/
|
||||||
|
static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
{
|
||||||
|
u8_t two_bytes[2];
|
||||||
|
phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
|
||||||
|
vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
|
||||||
|
int bytes, ix = 0, odd_byte = 0;
|
||||||
|
iovec_dat_t *iovp = &dep->de_write_iovec;
|
||||||
|
|
||||||
|
outb_reg0(dep, DP_ISR, ISR_RDC);
|
||||||
|
dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size;
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
|
||||||
|
phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
|
||||||
|
if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
||||||
|
|
||||||
|
if (odd_byte) {
|
||||||
|
phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
|
||||||
|
out_word(dep->de_data_port, *(u16_t *)two_bytes);
|
||||||
|
pktsize--;
|
||||||
|
bytes--;
|
||||||
|
phys_user++;
|
||||||
|
odd_byte = 0;
|
||||||
|
if (!bytes) continue;
|
||||||
|
}
|
||||||
|
ecount = bytes & NOT(0x0001);
|
||||||
|
if (ecount != 0) {
|
||||||
|
phys_outsw(dep->de_data_port, phys_user, ecount);
|
||||||
|
pktsize -= ecount;
|
||||||
|
bytes -= ecount;
|
||||||
|
phys_user += ecount;
|
||||||
|
}
|
||||||
|
if (bytes) {
|
||||||
|
phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
|
||||||
|
pktsize--;
|
||||||
|
bytes--;
|
||||||
|
phys_user++;
|
||||||
|
odd_byte = 1;
|
||||||
|
}
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (bytes > 0);
|
||||||
|
|
||||||
|
if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
|
||||||
|
for (ix = 0; ix < 100; ix++) {
|
||||||
|
if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
||||||
|
}
|
||||||
|
if (ix == 100) {
|
||||||
|
panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
||||||
|
** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
|
||||||
|
*/
|
||||||
|
static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
vir_bytes ecount;
|
||||||
|
int bytes, i;
|
||||||
|
u8_t two_bytes[2];
|
||||||
|
phys_bytes phys_2bytes;
|
||||||
|
int odd_byte;
|
||||||
|
|
||||||
|
ecount = (count + 1) & ~1;
|
||||||
|
phys_2bytes = vir2phys(two_bytes);
|
||||||
|
odd_byte = 0;
|
||||||
|
|
||||||
|
dp_read_setup(dep, ecount, nic_addr);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (count > 0) {
|
||||||
|
if (i >= IOVEC_NR) {
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
i = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bytes = iovp->iod_iovec[i].iov_size;
|
||||||
|
if (bytes > count) bytes = count;
|
||||||
|
|
||||||
|
phys_user = numap(iovp->iod_proc_nr,
|
||||||
|
iovp->iod_iovec[i].iov_addr, bytes);
|
||||||
|
if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
||||||
|
if (odd_byte) {
|
||||||
|
phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
|
||||||
|
count--;
|
||||||
|
bytes--;
|
||||||
|
phys_user++;
|
||||||
|
odd_byte = 0;
|
||||||
|
if (!bytes) continue;
|
||||||
|
}
|
||||||
|
ecount = bytes & ~1;
|
||||||
|
if (ecount != 0) {
|
||||||
|
phys_insw(dep->de_data_port, phys_user, ecount);
|
||||||
|
count -= ecount;
|
||||||
|
bytes -= ecount;
|
||||||
|
phys_user += ecount;
|
||||||
|
}
|
||||||
|
if (bytes) {
|
||||||
|
*(u16_t *) two_bytes = in_word(dep->de_data_port);
|
||||||
|
phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
|
||||||
|
count--;
|
||||||
|
bytes--;
|
||||||
|
phys_user++;
|
||||||
|
odd_byte = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* PIO16 == 1 */
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING && ENABLE_DP8390 */
|
||||||
|
|
||||||
|
/** end 8390.c **/
|
172
drivers/dpeth/8390.h
Normal file
172
drivers/dpeth/8390.h
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
** File: 8390.h May 02, 2000
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** National Semiconductor NS 8390 Network Interface Controller
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define DP_PAGESIZE 256 /* NS 8390 page size */
|
||||||
|
#define SENDQ_PAGES 6 /* SENDQ_PAGES * DP_PAGESIZE >= 1514 bytes */
|
||||||
|
|
||||||
|
/* Page 0, read/write ------------- */
|
||||||
|
#define DP_CR 0x00 /* Command Register RW */
|
||||||
|
#define DP_CLDA0 0x01 /* Current Local Dma Address 0 RO */
|
||||||
|
#define DP_PSTART 0x01 /* Page Start Register WO */
|
||||||
|
#define DP_CLDA1 0x02 /* Current Local Dma Address 1 RO */
|
||||||
|
#define DP_PSTOP 0x02 /* Page Stop Register WO */
|
||||||
|
#define DP_BNRY 0x03 /* Boundary Pointer RW */
|
||||||
|
#define DP_TSR 0x04 /* Transmit Status Register RO */
|
||||||
|
#define DP_TPSR 0x04 /* Transmit Page Start Register WO */
|
||||||
|
#define DP_NCR 0x05 /* No. of Collisions Register RO */
|
||||||
|
#define DP_TBCR0 0x05 /* Transmit Byte Count Reg. 0 WO */
|
||||||
|
#define DP_FIFO 0x06 /* Fifo RO */
|
||||||
|
#define DP_TBCR1 0x06 /* Transmit Byte Count Reg. 1 WO */
|
||||||
|
#define DP_ISR 0x07 /* Interrupt Status Register RW */
|
||||||
|
#define DP_CRDA0 0x08 /* Current Remote Dma Addr.Low RO */
|
||||||
|
#define DP_RSAR0 0x08 /* Remote Start Address Low WO */
|
||||||
|
#define DP_CRDA1 0x09 /* Current Remote Dma Addr.High RO */
|
||||||
|
#define DP_RSAR1 0x09 /* Remote Start Address High WO */
|
||||||
|
#define DP_RBCR0 0x0A /* Remote Byte Count Low WO */
|
||||||
|
#define DP_RBCR1 0x0B /* Remote Byte Count Hihg WO */
|
||||||
|
#define DP_RSR 0x0C /* Receive Status Register RO */
|
||||||
|
#define DP_RCR 0x0C /* Receive Config. Register WO */
|
||||||
|
#define DP_CNTR0 0x0D /* Tally Counter 0 RO */
|
||||||
|
#define DP_TCR 0x0D /* Transmit Config. Register WO */
|
||||||
|
#define DP_CNTR1 0x0E /* Tally Counter 1 RO */
|
||||||
|
#define DP_DCR 0x0E /* Data Configuration Register WO */
|
||||||
|
#define DP_CNTR2 0x0F /* Tally Counter 2 RO */
|
||||||
|
#define DP_IMR 0x0F /* Interrupt Mask Register WO */
|
||||||
|
|
||||||
|
/* Page 1, read/write -------------- */
|
||||||
|
/* 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 dp_cr */
|
||||||
|
#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_RR 0x08 /* DMA: Remote Read */
|
||||||
|
#define CR_DM_RW 0x10 /* DMA: Remote Write */
|
||||||
|
#define CR_DM_SP 0x18 /* DMA: Send Packet */
|
||||||
|
#define CR_NO_DMA 0x20 /* DMA: Stop 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_P2 0x80 /* Register Page 2 */
|
||||||
|
|
||||||
|
/* Bits in dp_isr */
|
||||||
|
#define ISR_MASK 0x3F
|
||||||
|
#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 dp_imr */
|
||||||
|
#define IMR_PRXE 0x01 /* Packet Received Enable */
|
||||||
|
#define IMR_PTXE 0x02 /* Packet Transmitted Enable */
|
||||||
|
#define IMR_RXEE 0x04 /* Receive Error Enable */
|
||||||
|
#define IMR_TXEE 0x08 /* Transmit Error Enable */
|
||||||
|
#define IMR_OVWE 0x10 /* Overwrite Warning Enable */
|
||||||
|
#define IMR_CNTE 0x20 /* Counter Overflow Enable */
|
||||||
|
#define IMR_RDCE 0x40 /* DMA Complete Enable */
|
||||||
|
|
||||||
|
/* Bits in dp_dcr */
|
||||||
|
#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 /* Fifo Threshold: 2 bytes */
|
||||||
|
#define DCR_4BYTES 0x20 /* Fifo Threshold: 4 bytes */
|
||||||
|
#define DCR_8BYTES 0x40 /* Fifo Threshold: 8 bytes */
|
||||||
|
#define DCR_12BYTES 0x60 /* Fifo Threshold: 12 bytes */
|
||||||
|
|
||||||
|
/* Bits in dp_tcr */
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
/* Bits in dp_tsr */
|
||||||
|
#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 dp_rcr */
|
||||||
|
#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 dp_rsr */
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
/* Some macros to simplify accessing the dp8390 */
|
||||||
|
#define inb_reg0(dep,reg) (inb(dep->de_dp8390_port+reg))
|
||||||
|
#define outb_reg0(dep,reg,data) (outb(dep->de_dp8390_port+reg,data))
|
||||||
|
#define inb_reg1(dep,reg) (inb(dep->de_dp8390_port+reg))
|
||||||
|
#define outb_reg1(dep,reg,data) (outb(dep->de_dp8390_port+reg,data))
|
||||||
|
|
||||||
|
typedef struct dp_rcvhdr {
|
||||||
|
u8_t dr_status; /* Copy of rsr */
|
||||||
|
u8_t dr_next; /* Pointer to next packet */
|
||||||
|
u8_t dr_rbcl; /* Receive Byte Count Low */
|
||||||
|
u8_t dr_rbch; /* Receive Byte Count High */
|
||||||
|
} dp_rcvhdr_t;
|
||||||
|
|
||||||
|
void ns_init(dpeth_t *);
|
||||||
|
|
||||||
|
/** 8390.h **/
|
52
drivers/dpeth/Makefile
Normal file
52
drivers/dpeth/Makefile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
##
|
||||||
|
## Makefile for ISA ethernet drivers May 02, 2000
|
||||||
|
##
|
||||||
|
## $Log$
|
||||||
|
## Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
## Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
## Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
##
|
||||||
|
## Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
## Initial revision for Minix 3.0.6
|
||||||
|
##
|
||||||
|
## $Id$
|
||||||
|
|
||||||
|
## Programs, flags, etc.
|
||||||
|
DRIVER = dpeth
|
||||||
|
|
||||||
|
debug = 0
|
||||||
|
|
||||||
|
CC = exec cc
|
||||||
|
LD = $(CC)
|
||||||
|
CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug)
|
||||||
|
CFLAGS = -ws $(CPPFLAGS)
|
||||||
|
LDFLAGS = -i -o $@
|
||||||
|
|
||||||
|
SRCS = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c
|
||||||
|
OBJS = 3c501.o 3c509.o 3c503.o ne.o wd.o 8390.o devio.o netbuff.o dp.o
|
||||||
|
LIBS = -lutils -lsys # -ltimers
|
||||||
|
|
||||||
|
## Build rules
|
||||||
|
all build: $(DRIVER)
|
||||||
|
|
||||||
|
$(DRIVER): $(OBJS)
|
||||||
|
$(CC) $(OBJS) $(LIBS) $(LDFLAGS)
|
||||||
|
install -S 4kw $(DRIVER)
|
||||||
|
|
||||||
|
## Install with other drivers
|
||||||
|
install: /usr/sbin/drivers/$(DRIVER)
|
||||||
|
/usr/sbin/drivers/$(DRIVER): $(DRIVER)
|
||||||
|
install -o root -cs $? $@
|
||||||
|
|
||||||
|
## Generate dependencies
|
||||||
|
|
||||||
|
depend:
|
||||||
|
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
|
||||||
|
|
||||||
|
## Clean directory
|
||||||
|
clean:
|
||||||
|
@rm -f $(DRIVER) *.o *.BAK
|
||||||
|
|
||||||
|
include .depend
|
||||||
|
|
||||||
|
## end
|
38
drivers/dpeth/README
Normal file
38
drivers/dpeth/README
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
This is my implementation of a new network task
|
||||||
|
for the Minix kernel. I did it initially to handle
|
||||||
|
a 3c501 board (Etherlink), but those board are so
|
||||||
|
unstable that it is not worth using them except for
|
||||||
|
learning how to implement a driver. When I got a
|
||||||
|
3c509b board (Etherlink III) it was easier to
|
||||||
|
write the code to handle them.
|
||||||
|
|
||||||
|
The Minix code in 'dp8390.c' is too specific for the
|
||||||
|
National chip set, so what I did was to remove as
|
||||||
|
much as I needed of the code dependant from the chip
|
||||||
|
and produce a generic task that, I hope, will be able
|
||||||
|
to handle many more cards.
|
||||||
|
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
|
||||||
|
Revision 1.3 2004/04/14 12:49:07 lsodgf0
|
||||||
|
Changes for porting to Minix 2.0.4 run on BOCHS
|
||||||
|
|
||||||
|
Revision 1.2 2002/03/25 14:16:09 lsodgf0
|
||||||
|
The driver for the NEx000 has been rewritten to be
|
||||||
|
operational with the ACCTON 18xx (an NE1000 clone)
|
||||||
|
The I/O routines for 16 bit cards are still untested..
|
||||||
|
|
||||||
|
Revision 1.1 2002/02/09 09:35:09 lsodgf0
|
||||||
|
Initial revision
|
||||||
|
The package is not fully tested, i.e. I had only 3Com
|
||||||
|
boards (3c501, 3c503, 3c503/16 and 3c509b) and WD8003.
|
||||||
|
I got also a NE1000 clone but it was not fully
|
||||||
|
operational and I could not appreciate the results.
|
||||||
|
For this reason the changes done to the interface
|
||||||
|
to I/O for 8 and 16 bits are not tested.
|
||||||
|
|
||||||
|
$Id$
|
141
drivers/dpeth/devio.c
Normal file
141
drivers/dpeth/devio.c
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
** File: devio.c Jun. 11, 2005
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains the routines for readind/writing
|
||||||
|
** from/to the device registers.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if ENABLE_NETWORKING == 1
|
||||||
|
#if USE_IOPL == 0
|
||||||
|
|
||||||
|
static void warning(const char *type, int err)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("Warning: eth#0 sys_%s failed (%d)\n", type, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned int inb(unsigned short int port);
|
||||||
|
** Function: Reads a byte from specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC unsigned int inb(unsigned short port)
|
||||||
|
{
|
||||||
|
unsigned int value;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_inb(port, &value)) != OK) warning("inb", rc);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned int inw(unsigned short int port);
|
||||||
|
** Function: Reads a word from specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC unsigned int inw(unsigned short port)
|
||||||
|
{
|
||||||
|
unsigned int value;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_inw(port, &value)) != OK) warning("inw", rc);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned int insb(unsigned short int port, int proc_nr, void *buffer, int count);
|
||||||
|
** Function: Reads a sequence of bytes from specified i/o port to user space buffer.
|
||||||
|
*/
|
||||||
|
PUBLIC void insb(unsigned short int port, int proc_nr, void *buffer, int count)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_insb(port, proc_nr, buffer, count)) != OK)
|
||||||
|
warning("insb", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: unsigned int insw(unsigned short int port, int proc_nr, void *buffer, int count);
|
||||||
|
** Function: Reads a sequence of words from specified i/o port to user space buffer.
|
||||||
|
*/
|
||||||
|
PUBLIC void insw(unsigned short int port, int proc_nr, void *buffer, int count)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_insw(port, proc_nr, buffer, count)) != OK)
|
||||||
|
warning("insw", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void outb(unsigned short int port, unsigned long value);
|
||||||
|
** Function: Writes a byte to specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC void outb(unsigned short port, unsigned long value)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_outb(port, value)) != OK) warning("outb", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void outw(unsigned short int port, unsigned long value);
|
||||||
|
** Function: Writes a word to specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC void outw(unsigned short port, unsigned long value)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_outw(port, value)) != OK) warning("outw", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void outsb(unsigned short int port, int proc_nr, void *buffer, int count);
|
||||||
|
** Function: Writes a sequence of bytes from user space to specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC void outsb(unsigned short port, int proc_nr, void *buffer, int count)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_outsb(port, proc_nr, buffer, count)) != OK)
|
||||||
|
warning("outsb", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void outsw(unsigned short int port, int proc_nr, void *buffer, int count);
|
||||||
|
** Function: Writes a sequence of bytes from user space to specified i/o port.
|
||||||
|
*/
|
||||||
|
PUBLIC void outsw(unsigned short port, int proc_nr, void *buffer, int count)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if ((rc = sys_outsw(port, proc_nr, buffer, count)) != OK)
|
||||||
|
warning("outsw", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error To be implemented
|
||||||
|
#endif /* USE_IOPL */
|
||||||
|
#endif /* ENABLE_NETWORKING */
|
||||||
|
/** devio.c **/
|
641
drivers/dpeth/dp.c
Normal file
641
drivers/dpeth/dp.c
Normal file
|
@ -0,0 +1,641 @@
|
||||||
|
/*
|
||||||
|
** File: eth.c Version 1.00, Jan. 14, 1997
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains the ethernet device driver main task.
|
||||||
|
** It has to be integrated with the board specific drivers.
|
||||||
|
** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c)
|
||||||
|
** to remove bord specific code. It should operate (I hope)
|
||||||
|
** with any board driver.
|
||||||
|
**
|
||||||
|
** The valid messages and their parameters are:
|
||||||
|
**
|
||||||
|
** m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | HARD_INT | | | | | | NOTIFICATION|0
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | SYN_ALARM | | | | | | NOTIFICATION|1
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | HARD_STOP | | | | | | NOTIFICATION|4
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | FKEY_PRESSED | | | | | (99)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_WRITE | port nr | proc nr | count | mode | address | (3)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_WRITEV | port nr | proc nr | count | mode | address | (4)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_READ | port nr | proc nr | count | | address | (5)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_READV | port nr | proc nr | count | | address | (6)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_INIT | port nr | proc nr | | mode | address | (7)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_STOP | port_nr | | | | | (8)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
** | DL_GETSTAT | port nr | proc nr | | | address | (9)
|
||||||
|
** +------------+---------+---------+--------+-------+---------+
|
||||||
|
**
|
||||||
|
** The messages sent are:
|
||||||
|
**
|
||||||
|
** m-type DL_PORT DL_PROC DL_COUNT DL_STAT DL_CLCK
|
||||||
|
** +------------+---------+---------+--------+---------+---------+
|
||||||
|
** |DL_TASK_REPL| port nr | proc nr |rd-count| err|stat| clock | (21)
|
||||||
|
** +------------+---------+---------+--------+---------+---------+
|
||||||
|
**
|
||||||
|
** m_type m3_i1 m3_i2 m3_ca1
|
||||||
|
** +------------+---------+---------+---------------+
|
||||||
|
** |DL_INIT_REPL| port nr |last port| ethernet addr | (20)
|
||||||
|
** +------------+---------+---------+---------------+
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <minix/keymap.h>
|
||||||
|
#include <net/hton.h>
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if ENABLE_NETWORKING == 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Local data
|
||||||
|
*/
|
||||||
|
static dpeth_t de_table[DE_PORT_NR];
|
||||||
|
static int dpeth_tasknr = ANY;
|
||||||
|
|
||||||
|
typedef struct dp_conf { /* Configuration description structure */
|
||||||
|
port_t dpc_port;
|
||||||
|
int dpc_irq;
|
||||||
|
phys_bytes dpc_mem;
|
||||||
|
char *dpc_envvar;
|
||||||
|
} dp_conf_t;
|
||||||
|
|
||||||
|
/* Device default configuration */
|
||||||
|
static dp_conf_t dp_conf[DE_PORT_NR] = {
|
||||||
|
/* I/O port, IRQ, Buff addr, Env. var, Buf. selector */
|
||||||
|
{ 0x300, 5, 0xC8000, "DPETH0", },
|
||||||
|
{ 0x280, 10, 0xCC000, "DPETH1", },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char CopyErrMsg[] = "unable to read/write user data";
|
||||||
|
static const char PortErrMsg[] = "illegal port";
|
||||||
|
static const char RecvErrMsg[] = "receive failed";
|
||||||
|
static const char SendErrMsg[] = "send failed";
|
||||||
|
static const char SizeErrMsg[] = "illegal packet size";
|
||||||
|
static const char TypeErrMsg[] = "illegal message type";
|
||||||
|
static const char DevName[] = "eth#?";
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void reply(dpeth_t *dep, int err)
|
||||||
|
** Function: Fills a DL_TASK_REPLY reply message and sends it.
|
||||||
|
*/
|
||||||
|
static void reply(dpeth_t * dep, int err)
|
||||||
|
{
|
||||||
|
message reply;
|
||||||
|
int status = FALSE;
|
||||||
|
|
||||||
|
if (dep->de_flags & DEF_ACK_SEND) status |= DL_PACK_SEND;
|
||||||
|
if (dep->de_flags & DEF_ACK_RECV) status |= DL_PACK_RECV;
|
||||||
|
|
||||||
|
reply.m_type = DL_TASK_REPLY;
|
||||||
|
reply.DL_PORT = dep - de_table;
|
||||||
|
reply.DL_PROC = dep->de_client;
|
||||||
|
reply.DL_STAT = status | ((u32_t) err << 16);
|
||||||
|
reply.DL_COUNT = dep->de_read_s;
|
||||||
|
getuptime(&reply.DL_CLCK);
|
||||||
|
|
||||||
|
DEBUG(printf("\t reply %d (%ld)\n", reply.m_type, reply.DL_STAT));
|
||||||
|
|
||||||
|
if ((status = send(dep->de_client, &reply)) != OK)
|
||||||
|
panic(dep->de_name, SendErrMsg, dep->de_client);
|
||||||
|
|
||||||
|
dep->de_read_s = 0;
|
||||||
|
dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void dp_confaddr(dpeth_t *dep)
|
||||||
|
** Function: Chechs environment for a User defined ethernet address.
|
||||||
|
*/
|
||||||
|
static void dp_confaddr(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
static char ea_fmt[] = "x:x:x:x:x:x";
|
||||||
|
char ea_key[16];
|
||||||
|
int ix;
|
||||||
|
long val;
|
||||||
|
|
||||||
|
strcpy(ea_key, dp_conf[dep - de_table].dpc_envvar);
|
||||||
|
strcat(ea_key, "_EA");
|
||||||
|
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix++) {
|
||||||
|
val = dep->de_address.ea_addr[ix];
|
||||||
|
if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
|
||||||
|
break;
|
||||||
|
dep->de_address.ea_addr[ix] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ix != 0 && ix != SA_ADDR_LEN)
|
||||||
|
/* It's all or nothing, force a panic */
|
||||||
|
env_parse(ea_key, "?", 0, &val, 0L, 0L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
|
||||||
|
** Function: Gets the default settings from 'dp_conf' table and
|
||||||
|
** modifies them from the environment.
|
||||||
|
*/
|
||||||
|
static void update_conf(dpeth_t * dep, dp_conf_t * dcp)
|
||||||
|
{
|
||||||
|
static char dpc_fmt[] = "x:d:x";
|
||||||
|
long val;
|
||||||
|
|
||||||
|
dep->de_mode = DEM_SINK;
|
||||||
|
val = dcp->dpc_port; /* Get I/O port address */
|
||||||
|
switch (env_parse(dcp->dpc_envvar, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
|
||||||
|
case EP_OFF: dep->de_mode = DEM_DISABLED; break;
|
||||||
|
case EP_ON:
|
||||||
|
case EP_SET: dep->de_mode = DEM_ENABLED; break;
|
||||||
|
}
|
||||||
|
dep->de_base_port = val;
|
||||||
|
|
||||||
|
val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
|
||||||
|
env_parse(dcp->dpc_envvar, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
|
||||||
|
dep->de_irq = val;
|
||||||
|
|
||||||
|
val = dcp->dpc_mem; /* Get shared memory address */
|
||||||
|
env_parse(dcp->dpc_envvar, dpc_fmt, 2, &val, 0L, LONG_MAX);
|
||||||
|
dep->de_linmem = val;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_dump(message *mp)
|
||||||
|
** Function: Displays statistics on screen (SFx key from console)
|
||||||
|
*/
|
||||||
|
static void do_dump(message *mp)
|
||||||
|
{
|
||||||
|
dpeth_t *dep;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
printf("\n\n");
|
||||||
|
for (port = 0, dep = de_table; port < DE_PORT_NR; port += 1, dep += 1) {
|
||||||
|
|
||||||
|
if (dep->de_mode == DEM_DISABLED) continue;
|
||||||
|
|
||||||
|
printf("%s statistics:\t\t", dep->de_name);
|
||||||
|
|
||||||
|
/* Network interface status */
|
||||||
|
printf("Status: 0x%04x\n\n", dep->de_flags);
|
||||||
|
|
||||||
|
(*dep->de_dumpstatsf) (dep);
|
||||||
|
|
||||||
|
/* Transmitted/received bytes */
|
||||||
|
printf("Tx bytes:%10ld\t", dep->bytes_Tx);
|
||||||
|
printf("Rx bytes:%10ld\n", dep->bytes_Rx);
|
||||||
|
|
||||||
|
/* Transmitted/received packets */
|
||||||
|
printf("Tx OK: %8ld\t", dep->de_stat.ets_packetT);
|
||||||
|
printf("Rx OK: %8ld\n", dep->de_stat.ets_packetR);
|
||||||
|
|
||||||
|
/* Transmit/receive errors */
|
||||||
|
printf("Tx Err: %8ld\t", dep->de_stat.ets_sendErr);
|
||||||
|
printf("Rx Err: %8ld\n", dep->de_stat.ets_recvErr);
|
||||||
|
|
||||||
|
/* Transmit unnerruns/receive overrruns */
|
||||||
|
printf("Tx Und: %8ld\t", dep->de_stat.ets_fifoUnder);
|
||||||
|
printf("Rx Ovr: %8ld\n", dep->de_stat.ets_fifoOver);
|
||||||
|
|
||||||
|
/* Transmit collisions/receive CRC errors */
|
||||||
|
printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision);
|
||||||
|
printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
|
||||||
|
** Function: Copies data from user area.
|
||||||
|
*/
|
||||||
|
static void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
vir_bytes len;
|
||||||
|
|
||||||
|
len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
|
||||||
|
if ((rc = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes)loc_addr, len)) != OK)
|
||||||
|
panic(DevName, CopyErrMsg, rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
|
||||||
|
** Function: Init action to setup task
|
||||||
|
*/
|
||||||
|
static void do_first_init(dpeth_t *dep, dp_conf_t *dcp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dep->de_linmem != 0) {
|
||||||
|
dep->de_memsegm = BIOS_SEG;
|
||||||
|
/* phys2seg(&dep->de_memsegm, &dep->de_memoffs, dep->de_linmem); */
|
||||||
|
} else
|
||||||
|
dep->de_linmem = 0xFFFF0000;
|
||||||
|
|
||||||
|
/* Make sure statisics are cleared */
|
||||||
|
memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t));
|
||||||
|
|
||||||
|
/* Device specific initialization */
|
||||||
|
(*dep->de_initf) (dep);
|
||||||
|
|
||||||
|
/* Set the interrupt handler policy */
|
||||||
|
sys_irqsetpolicy(dep->de_irq, IRQ_REENABLE, &dep->de_hook);
|
||||||
|
sys_irqenable(&dep->de_hook);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_init(message *mp)
|
||||||
|
** Function: Checks for hardware presence.
|
||||||
|
** Provides initialization of hardware and data structures
|
||||||
|
*/
|
||||||
|
static void do_init(message * mp)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
dpeth_t *dep;
|
||||||
|
dp_conf_t *dcp;
|
||||||
|
message reply_mess;
|
||||||
|
|
||||||
|
port = mp->DL_PORT;
|
||||||
|
if (port >= 0 && port < DE_PORT_NR) {
|
||||||
|
|
||||||
|
dep = &de_table[port];
|
||||||
|
dcp = &dp_conf[port];
|
||||||
|
strcpy(dep->de_name, DevName);
|
||||||
|
dep->de_name[4] = '0' + port;
|
||||||
|
|
||||||
|
if (dep->de_mode == DEM_DISABLED) {
|
||||||
|
|
||||||
|
update_conf(dep, dcp); /* First time thru */
|
||||||
|
if (dep->de_mode == DEM_ENABLED &&
|
||||||
|
!el1_probe(dep) && /* Probe for 3c501 */
|
||||||
|
!wdeth_probe(dep) && /* Probe for WD80x3 */
|
||||||
|
!ne_probe(dep) && /* Probe for NEx000 */
|
||||||
|
!el2_probe(dep) && /* Probe for 3c503 */
|
||||||
|
!el3_probe(dep)) { /* Probe for 3c509 */
|
||||||
|
printf("%s: warning no ethernet card found at 0x%04X\n",
|
||||||
|
dep->de_name, dep->de_base_port);
|
||||||
|
dep->de_mode = DEM_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'de_mode' may change if probe routines fail, test again */
|
||||||
|
switch (dep->de_mode) {
|
||||||
|
|
||||||
|
case DEM_DISABLED:
|
||||||
|
/* Device is configured OFF or hardware probe failed */
|
||||||
|
port = ENXIO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEM_ENABLED:
|
||||||
|
/* Device is present and probed */
|
||||||
|
if (dep->de_flags == DEF_EMPTY) {
|
||||||
|
/* These actions only the first time */
|
||||||
|
do_first_init(dep, dcp);
|
||||||
|
dep->de_flags |= DEF_ENABLED;
|
||||||
|
}
|
||||||
|
dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
|
||||||
|
if (mp->DL_MODE & DL_PROMISC_REQ)
|
||||||
|
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
|
||||||
|
if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI;
|
||||||
|
if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD;
|
||||||
|
(*dep->de_flagsf) (dep);
|
||||||
|
dep->de_client = mp->m_source;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEM_SINK:
|
||||||
|
/* Device not present (sink mode) */
|
||||||
|
memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
|
||||||
|
dp_confaddr(dep); /* Station address from env. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
*(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
|
||||||
|
|
||||||
|
} else /* Port number is out of range */
|
||||||
|
port = ENXIO;
|
||||||
|
|
||||||
|
reply_mess.m_type = DL_INIT_REPLY;
|
||||||
|
reply_mess.m3_i1 = port;
|
||||||
|
reply_mess.m3_i2 = DE_PORT_NR;
|
||||||
|
DEBUG(printf("\t reply %d\n", reply_mess.m_type));
|
||||||
|
if (send(mp->m_source, &reply_mess) != OK) /* Can't send */
|
||||||
|
panic(dep->de_name, SendErrMsg, mp->m_source);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void dp_next_iovec(iovec_dat_t *iovp)
|
||||||
|
** Function: Retrieves data from next iovec element.
|
||||||
|
*/
|
||||||
|
PUBLIC void dp_next_iovec(iovec_dat_t * iovp)
|
||||||
|
{
|
||||||
|
|
||||||
|
iovp->iod_iovec_s -= IOVEC_NR;
|
||||||
|
iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
|
||||||
|
get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr,
|
||||||
|
iovp->iod_iovec_s, iovp->iod_iovec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: int calc_iovec_size(iovec_dat_t *iovp)
|
||||||
|
** Function: Compute the size of a request.
|
||||||
|
*/
|
||||||
|
static int calc_iovec_size(iovec_dat_t * iovp)
|
||||||
|
{
|
||||||
|
int size, ix;
|
||||||
|
|
||||||
|
size = ix = 0;
|
||||||
|
do {
|
||||||
|
size += iovp->iod_iovec[ix].iov_size;
|
||||||
|
if (++ix >= IOVEC_NR) {
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Till all vectors added */
|
||||||
|
} while (ix < iovp->iod_iovec_s);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_vwrite(message *mp, int vectored)
|
||||||
|
** Function:
|
||||||
|
*/
|
||||||
|
static void do_vwrite(message * mp, int vectored)
|
||||||
|
{
|
||||||
|
int port, size;
|
||||||
|
dpeth_t *dep;
|
||||||
|
|
||||||
|
port = mp->DL_PORT;
|
||||||
|
if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */
|
||||||
|
panic(dep->de_name, PortErrMsg, port);
|
||||||
|
|
||||||
|
dep = &de_table[port];
|
||||||
|
dep->de_client = mp->DL_PROC;
|
||||||
|
|
||||||
|
if (dep->de_mode == DEM_ENABLED) {
|
||||||
|
|
||||||
|
if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */
|
||||||
|
panic(dep->de_name, "send already in progress ", NO_NUM);
|
||||||
|
|
||||||
|
dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
|
||||||
|
if (vectored) {
|
||||||
|
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
|
||||||
|
mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
|
||||||
|
dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
|
||||||
|
dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
|
||||||
|
size = calc_iovec_size(&dep->de_write_iovec);
|
||||||
|
} else {
|
||||||
|
dep->de_write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
|
||||||
|
dep->de_write_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
|
||||||
|
dep->de_write_iovec.iod_iovec_s = 1;
|
||||||
|
dep->de_write_iovec.iod_iovec_addr = 0;
|
||||||
|
}
|
||||||
|
if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
|
||||||
|
panic(dep->de_name, SizeErrMsg, size);
|
||||||
|
|
||||||
|
dep->de_flags |= DEF_SENDING;
|
||||||
|
(*dep->de_sendf) (dep, FALSE, size);
|
||||||
|
|
||||||
|
} else if (dep->de_mode == DEM_SINK)
|
||||||
|
dep->de_flags |= DEF_ACK_SEND;
|
||||||
|
|
||||||
|
reply(dep, OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_vread(message *mp, int vectored)
|
||||||
|
** Function:
|
||||||
|
*/
|
||||||
|
static void do_vread(message * mp, int vectored)
|
||||||
|
{
|
||||||
|
int port, size;
|
||||||
|
dpeth_t *dep;
|
||||||
|
|
||||||
|
port = mp->DL_PORT;
|
||||||
|
if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */
|
||||||
|
panic(dep->de_name, PortErrMsg, port);
|
||||||
|
|
||||||
|
dep = &de_table[port];
|
||||||
|
dep->de_client = mp->DL_PROC;
|
||||||
|
|
||||||
|
if (dep->de_mode == DEM_ENABLED) {
|
||||||
|
|
||||||
|
if (dep->de_flags & DEF_READING) /* Reading in progress */
|
||||||
|
panic(dep->de_name, "read already in progress", NO_NUM);
|
||||||
|
|
||||||
|
dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
|
||||||
|
if (vectored) {
|
||||||
|
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
|
||||||
|
mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
|
||||||
|
dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
|
||||||
|
dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
|
||||||
|
size = calc_iovec_size(&dep->de_read_iovec);
|
||||||
|
} else {
|
||||||
|
dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
|
||||||
|
dep->de_read_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
|
||||||
|
dep->de_read_iovec.iod_iovec_s = 1;
|
||||||
|
dep->de_read_iovec.iod_iovec_addr = 0;
|
||||||
|
}
|
||||||
|
if (size < ETH_MAX_PACK_SIZE) panic(dep->de_name, SizeErrMsg, size);
|
||||||
|
|
||||||
|
dep->de_flags |= DEF_READING;
|
||||||
|
(*dep->de_recvf) (dep, FALSE, size);
|
||||||
|
#if 0
|
||||||
|
if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
|
||||||
|
/* The chip is stopped, and all arrived packets delivered */
|
||||||
|
(*dep->de_resetf) (dep);
|
||||||
|
dep->de_flags &= NOT(DEF_STOPPED);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
reply(dep, OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_getstat(message *mp)
|
||||||
|
** Function: Reports device statistics.
|
||||||
|
*/
|
||||||
|
static void do_getstat(message * mp)
|
||||||
|
{
|
||||||
|
int port, rc;
|
||||||
|
dpeth_t *dep;
|
||||||
|
|
||||||
|
port = mp->DL_PORT;
|
||||||
|
if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */
|
||||||
|
panic(dep->de_name, PortErrMsg, port);
|
||||||
|
|
||||||
|
dep = &de_table[port];
|
||||||
|
dep->de_client = mp->DL_PROC;
|
||||||
|
|
||||||
|
if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
|
||||||
|
if ((rc = sys_datacopy(SELF, (vir_bytes)&dep->de_stat,
|
||||||
|
mp->DL_PROC, (vir_bytes)mp->DL_ADDR,
|
||||||
|
(vir_bytes) sizeof(dep->de_stat))) != OK)
|
||||||
|
panic(DevName, CopyErrMsg, rc);
|
||||||
|
reply(dep, OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void do_stop(message *mp)
|
||||||
|
** Function: Stops network interface.
|
||||||
|
*/
|
||||||
|
static void do_stop(message * mp)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
dpeth_t *dep;
|
||||||
|
|
||||||
|
port = mp->DL_PORT;
|
||||||
|
if (port < 0 || port >= DE_PORT_NR) /* Check for illegal port number */
|
||||||
|
panic(dep->de_name, PortErrMsg, port);
|
||||||
|
|
||||||
|
dep = &de_table[port];
|
||||||
|
if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) {
|
||||||
|
|
||||||
|
/* Stop device */
|
||||||
|
(dep->de_stopf) (dep);
|
||||||
|
dep->de_flags = DEF_EMPTY;
|
||||||
|
dep->de_mode = DEM_DISABLED;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_watchdog(void *message)
|
||||||
|
{
|
||||||
|
|
||||||
|
DEBUG(printf("\t no reply"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: int dpeth_task(void)
|
||||||
|
** Function: Main entry for dp task
|
||||||
|
*/
|
||||||
|
PUBLIC int main(void)
|
||||||
|
{
|
||||||
|
message m;
|
||||||
|
dpeth_t *dep;
|
||||||
|
int rc, fkeys, sfkeys;
|
||||||
|
|
||||||
|
/* Get precess number */
|
||||||
|
if ((rc = getprocnr(&dpeth_tasknr)) != OK)
|
||||||
|
panic(DevName, "getprocnr() failed", rc);
|
||||||
|
#if defined USE_IOPL
|
||||||
|
/* Request direct access to hardware I/O ports */
|
||||||
|
if ((rc = sys_enable_iop(dpeth_tasknr)) != OK)
|
||||||
|
panic(DevName, "sys_enable_iop() failed", rc);
|
||||||
|
#endif
|
||||||
|
/* Request function key for debug dumps */
|
||||||
|
fkeys = sfkeys = 0; bit_set(sfkeys, 8);
|
||||||
|
if ((fkey_map(fkeys, sfkeys)) != OK)
|
||||||
|
printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno);
|
||||||
|
|
||||||
|
#ifdef ETH_IGN_PROTO
|
||||||
|
{
|
||||||
|
static u16_t eth_ign_proto = 0;
|
||||||
|
long val;
|
||||||
|
val = 0xFFFF;
|
||||||
|
env_parse("ETH_IGN_PROTO", "x", 0, &val, 0x0000L, 0xFFFFL);
|
||||||
|
eth_ign_proto = htons((u16_t) val);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf("DPETH: ethernet driver task initialized (process No. %d)\n", dpeth_tasknr);
|
||||||
|
while (TRUE) {
|
||||||
|
if ((rc = receive(ANY, &m)) != OK) panic(dep->de_name, RecvErrMsg, rc);
|
||||||
|
|
||||||
|
DEBUG(printf("eth: got message %d, ", m.m_type));
|
||||||
|
|
||||||
|
switch (m.m_type) {
|
||||||
|
case DL_WRITE: /* Write message to device */
|
||||||
|
do_vwrite(&m, FALSE);
|
||||||
|
break;
|
||||||
|
case DL_WRITEV: /* Write message to device */
|
||||||
|
do_vwrite(&m, TRUE);
|
||||||
|
break;
|
||||||
|
case DL_READ: /* Read message from device */
|
||||||
|
do_vread(&m, FALSE);
|
||||||
|
break;
|
||||||
|
case DL_READV: /* Read message from device */
|
||||||
|
do_vread(&m, TRUE);
|
||||||
|
break;
|
||||||
|
case DL_INIT: /* Initialize device */
|
||||||
|
do_init(&m);
|
||||||
|
break;
|
||||||
|
case DL_GETSTAT: /* Get device statistics */
|
||||||
|
do_getstat(&m);
|
||||||
|
break;
|
||||||
|
case SYN_ALARM: /* to be defined */
|
||||||
|
do_watchdog(&m);
|
||||||
|
break;
|
||||||
|
case DL_STOP: /* Stop device */
|
||||||
|
do_stop(&m);
|
||||||
|
break;
|
||||||
|
case HARD_STOP: /* Shut down */
|
||||||
|
for (rc = 0; rc < DE_PORT_NR; rc += 1) {
|
||||||
|
if (de_table[rc].de_mode == DEM_ENABLED) {
|
||||||
|
m.m_type = DL_STOP;
|
||||||
|
m.DL_PORT = rc;
|
||||||
|
do_stop(&m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sys_exit(0);
|
||||||
|
break;
|
||||||
|
case HARD_INT: /* Interrupt from device */
|
||||||
|
for (dep = de_table; dep < &de_table[DE_PORT_NR]; dep += 1) {
|
||||||
|
/* If device is enabled and interrupt pending */
|
||||||
|
if (dep->de_mode == DEM_ENABLED) {
|
||||||
|
/* dep->de_int_pending = FALSE; */
|
||||||
|
(*dep->de_interruptf) (dep);
|
||||||
|
if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
|
||||||
|
reply(dep, OK);
|
||||||
|
/* enable_irq(&dep->de_hook); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FKEY_PRESSED: /* Function key pressed */
|
||||||
|
do_dump(&m);
|
||||||
|
break;
|
||||||
|
default: /* Invalid message type */
|
||||||
|
panic(DevName, TypeErrMsg, m.m_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK; /* Never reached, but keeps compiler happy */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int main(void) { return 0; }
|
||||||
|
#endif /* ENABLE_NETWORKING */
|
||||||
|
|
||||||
|
/** dp.c **/
|
269
drivers/dpeth/dp.h
Normal file
269
drivers/dpeth/dp.h
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
** File: eth.h Version 1.00, Jan. 14, 1997
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** Interface description for ethernet device driver
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef ENABLE_3C501
|
||||||
|
#undef ENABLE_3C503
|
||||||
|
#undef ENABLE_3C509
|
||||||
|
#undef ENABLE_NE2000
|
||||||
|
#undef ENABLE_WDETH
|
||||||
|
#undef ENABLE_DP8390
|
||||||
|
|
||||||
|
#define ENABLE_NETWORKING ENABLE_DPETH /** (from /usr/include/minix/config.h **/
|
||||||
|
|
||||||
|
#define ENABLE_3C501 1 /* enable 3Com Etherlink I board */
|
||||||
|
#define ENABLE_3C503 1 /* enable 3Com Etherlink II board */
|
||||||
|
#define ENABLE_3C509 1 /* enable 3Com Etherlink III board */
|
||||||
|
#define ENABLE_NE2000 1 /* enable Novell N2000 board */
|
||||||
|
#define ENABLE_WDETH 1 /* enable Western Digital WD80x3 */
|
||||||
|
|
||||||
|
#define ENABLE_DP8390 (ENABLE_3C503|ENABLE_WDETH|ENABLE_NE2000)
|
||||||
|
#define HAVE_BUFFERS (ENABLE_3C501|ENABLE_3C509)
|
||||||
|
|
||||||
|
#undef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#define NOT(x) (~(x))
|
||||||
|
|
||||||
|
#if debug == 1
|
||||||
|
# define DEBUG(statm) statm
|
||||||
|
#else
|
||||||
|
# define DEBUG(statm)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _m_hdr_t { /* Buffer handling header */
|
||||||
|
struct _m_hdr_t *next;
|
||||||
|
int size;
|
||||||
|
} m_hdr_t;
|
||||||
|
|
||||||
|
typedef struct _buff_t { /* Receive/Transmit buffer header */
|
||||||
|
struct _buff_t *next;
|
||||||
|
int size;
|
||||||
|
int client;
|
||||||
|
char buffer[2];
|
||||||
|
} buff_t;
|
||||||
|
|
||||||
|
struct dpeth;
|
||||||
|
struct iovec_dat;
|
||||||
|
typedef void (*dp_eth_t) (struct dpeth *);
|
||||||
|
typedef void (*dp_send_recv_t) (struct dpeth *, int, int);
|
||||||
|
|
||||||
|
#if ENABLE_DP8390 == 1
|
||||||
|
typedef void (*dp_user2nicf_t) (struct dpeth *, int, int);
|
||||||
|
typedef void (*dp_nic2userf_t) (struct dpeth *, int, int);
|
||||||
|
typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DE_PORT_NR 2 /* Number of devices supported */
|
||||||
|
#define SENDQ_NR 2 /* Size of the send queue */
|
||||||
|
#define IOVEC_NR 16 /* Number of IOVEC entries at a time */
|
||||||
|
|
||||||
|
typedef struct iovec_dat {
|
||||||
|
iovec_t iod_iovec[IOVEC_NR];
|
||||||
|
int iod_iovec_s;
|
||||||
|
int iod_proc_nr;
|
||||||
|
vir_bytes iod_iovec_addr;
|
||||||
|
} iovec_dat_t;
|
||||||
|
|
||||||
|
typedef struct dpeth {
|
||||||
|
/* The de_base_port field is the starting point of the probe. The
|
||||||
|
* conf routine also fills de_linmem and de_irq. If the probe routine
|
||||||
|
* knows the irq and/or memory address because they are hardwired in
|
||||||
|
* the board, the probe should modify these fields. Futhermore, the
|
||||||
|
* probe routine should also fill in de_initf and de_stopf fields
|
||||||
|
* with the appropriate function pointers and set de_prog_IO iff
|
||||||
|
* programmed I/O is to be used.
|
||||||
|
*
|
||||||
|
* The initf function fills the following fields. Only cards that do
|
||||||
|
* programmed I/O fill in the de_data_port field. In addition, the
|
||||||
|
* init routine has to fill in the sendq data structures. */
|
||||||
|
|
||||||
|
/* Board hardware interface */
|
||||||
|
port_t de_base_port;
|
||||||
|
port_t de_data_port; /* For boards using Prog. I/O for xmit/recv */
|
||||||
|
|
||||||
|
int de_irq;
|
||||||
|
/* int de_int_pending; */
|
||||||
|
int de_hook; /* V306 irq_hook_t de_hook; */
|
||||||
|
|
||||||
|
char de_name[8];
|
||||||
|
|
||||||
|
#define DEI_DEFAULT 0x8000
|
||||||
|
|
||||||
|
phys_bytes de_linmem; /* For boards using shared memory */
|
||||||
|
unsigned short de_memsegm;
|
||||||
|
vir_bytes de_memoffs;
|
||||||
|
int de_ramsize; /* Size of on board memory */
|
||||||
|
int de_offset_page; /* Offset of shared memory page */
|
||||||
|
|
||||||
|
/* Board specific functions */
|
||||||
|
dp_eth_t de_initf;
|
||||||
|
dp_eth_t de_stopf;
|
||||||
|
dp_eth_t de_resetf;
|
||||||
|
dp_eth_t de_flagsf;
|
||||||
|
dp_eth_t de_getstatsf;
|
||||||
|
dp_eth_t de_dumpstatsf;
|
||||||
|
dp_eth_t de_interruptf;
|
||||||
|
dp_send_recv_t de_recvf;
|
||||||
|
dp_send_recv_t de_sendf;
|
||||||
|
|
||||||
|
ether_addr_t de_address; /* Ethernet Address */
|
||||||
|
eth_stat_t de_stat; /* Ethernet Statistics */
|
||||||
|
unsigned long bytes_Tx; /* Total bytes sent/received */
|
||||||
|
unsigned long bytes_Rx;
|
||||||
|
|
||||||
|
#define SA_ADDR_LEN sizeof(ether_addr_t)
|
||||||
|
|
||||||
|
int de_flags; /* Send/Receive mode (Configuration) */
|
||||||
|
|
||||||
|
#define DEF_EMPTY 0x0000
|
||||||
|
#define DEF_READING 0x0001
|
||||||
|
#define DEF_RECV_BUSY 0x0002
|
||||||
|
#define DEF_ACK_RECV 0x0004
|
||||||
|
#define DEF_SENDING 0x0010
|
||||||
|
#define DEF_XMIT_BUSY 0x0020
|
||||||
|
#define DEF_ACK_SEND 0x0040
|
||||||
|
#define DEF_PROMISC 0x0100
|
||||||
|
#define DEF_MULTI 0x0200
|
||||||
|
#define DEF_BROAD 0x0400
|
||||||
|
#define DEF_ENABLED 0x2000
|
||||||
|
#define DEF_STOPPED 0x4000
|
||||||
|
|
||||||
|
int de_mode; /* Status of the Interface */
|
||||||
|
|
||||||
|
#define DEM_DISABLED 0x0000
|
||||||
|
#define DEM_SINK 0x0001
|
||||||
|
#define DEM_ENABLED 0x0002
|
||||||
|
|
||||||
|
/* Temporary storage for RECV/SEND requests */
|
||||||
|
iovec_dat_t de_read_iovec;
|
||||||
|
iovec_dat_t de_write_iovec;
|
||||||
|
vir_bytes de_read_s;
|
||||||
|
vir_bytes de_send_s;
|
||||||
|
int de_client;
|
||||||
|
/*
|
||||||
|
message de_sendmsg;
|
||||||
|
iovec_dat_t de_tmp_iovec;
|
||||||
|
*/
|
||||||
|
#if ENABLE_DP8390 == 1
|
||||||
|
/* For use by NS DP8390 driver */
|
||||||
|
port_t de_dp8390_port;
|
||||||
|
int de_prog_IO;
|
||||||
|
int de_16bit;
|
||||||
|
int de_startpage;
|
||||||
|
int de_stoppage;
|
||||||
|
|
||||||
|
/* Do it yourself send queue */
|
||||||
|
struct sendq {
|
||||||
|
int sq_filled; /* This buffer contains a packet */
|
||||||
|
int sq_size; /* with this size */
|
||||||
|
int sq_sendpage; /* starting page of the buffer */
|
||||||
|
} de_sendq[SENDQ_NR];
|
||||||
|
int de_sendq_nr;
|
||||||
|
int de_sendq_head; /* Enqueue at the head */
|
||||||
|
int de_sendq_tail; /* Dequeue at the tail */
|
||||||
|
|
||||||
|
dp_user2nicf_t de_user2nicf;
|
||||||
|
dp_nic2userf_t de_nic2userf;
|
||||||
|
dp_getblock_t de_getblockf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_3C509 == 1
|
||||||
|
/* For use by 3Com Etherlink III (3c509) driver */
|
||||||
|
port_t de_id_port;
|
||||||
|
port_t de_if_port;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_3C501 == 1 || ENABLE_3C509 == 1
|
||||||
|
/* For use by 3Com Etherlink (3c501 and 3c509) driver */
|
||||||
|
buff_t *de_recvq_head;
|
||||||
|
buff_t *de_recvq_tail;
|
||||||
|
buff_t *de_xmitq_head;
|
||||||
|
buff_t *de_xmitq_tail;
|
||||||
|
u16_t de_recv_mode;
|
||||||
|
clock_t de_xmit_start;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} dpeth_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* dp.c */
|
||||||
|
void dp_next_iovec(iovec_dat_t * iovp);
|
||||||
|
|
||||||
|
/* devio.c */
|
||||||
|
#if defined USE_IOPL
|
||||||
|
#include <ibm/portio.h>
|
||||||
|
#else
|
||||||
|
unsigned int inb(unsigned short int);
|
||||||
|
unsigned int inw(unsigned short int);
|
||||||
|
void insb(unsigned short int, int, void *, int);
|
||||||
|
void insw(unsigned short int, int, void *, int);
|
||||||
|
void outb(unsigned short int, unsigned long);
|
||||||
|
void outw(unsigned short int, unsigned long);
|
||||||
|
void outsb(unsigned short int, int, void *, int);
|
||||||
|
void outsw(unsigned short int, int, void *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* netbuff.c */
|
||||||
|
void *alloc_buff(dpeth_t *, int);
|
||||||
|
void free_buff(dpeth_t *, void *);
|
||||||
|
void init_buff(dpeth_t *, buff_t **);
|
||||||
|
void mem2user(dpeth_t *, buff_t *);
|
||||||
|
void user2mem(dpeth_t *, buff_t *);
|
||||||
|
|
||||||
|
/* 3c501.c */
|
||||||
|
#if ENABLE_3C501 == 1
|
||||||
|
int el1_probe(dpeth_t *);
|
||||||
|
#else
|
||||||
|
#define el1_probe(x) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 3c503.c */
|
||||||
|
#if ENABLE_3C503 == 1
|
||||||
|
int el2_probe(dpeth_t *);
|
||||||
|
#else
|
||||||
|
#define el2_probe(x) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 3c509.c */
|
||||||
|
#if ENABLE_3C509 == 1
|
||||||
|
int el3_probe(dpeth_t *);
|
||||||
|
#else
|
||||||
|
#define el3_probe(x) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ne.c */
|
||||||
|
#if ENABLE_NE2000 == 1
|
||||||
|
int ne_probe(dpeth_t * dep);
|
||||||
|
#else
|
||||||
|
#define ne_probe(x) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* wd.c */
|
||||||
|
#if ENABLE_WDETH == 1
|
||||||
|
int wdeth_probe(dpeth_t * dep);
|
||||||
|
#else
|
||||||
|
#define wdeth_probe(x) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define lock() sys_irqdisable(&dep->de_hook);
|
||||||
|
#define unlock() sys_irqenable(&dep->de_hook);
|
||||||
|
#define milli_delay(t) tickdelay(1)
|
||||||
|
|
||||||
|
/** dp.h **/
|
201
drivers/dpeth/ne.c
Normal file
201
drivers/dpeth/ne.c
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
** File: ne.c Jun. 08, 2000
|
||||||
|
**
|
||||||
|
** Driver for the NE*000 ethernet cards and derivates.
|
||||||
|
** This file contains only the ne specific code,
|
||||||
|
** the rest is in 8390.c Code specific for ISA bus only
|
||||||
|
**
|
||||||
|
** Created: March 15, 1994 by Philip Homburg <philip@cs.vu.nl>
|
||||||
|
** PchId: ne2000.c,v 1.4 1996/01/19 23:30:34 philip Exp
|
||||||
|
**
|
||||||
|
** Modified: Jun. 08, 2000 by Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
** Adapted to interface new main network task.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if (ENABLE_NETWORKING == 1 && ENABLE_NE2000 == 1)
|
||||||
|
|
||||||
|
#include "8390.h"
|
||||||
|
#include "ne.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ne_reset(dpeth_t * dep);
|
||||||
|
** Function: Resets the board and checks if reset cycle completes
|
||||||
|
*/
|
||||||
|
static int ne_reset(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
/* Reset the ethernet card */
|
||||||
|
outb_ne(dep, NE_RESET, inb_ne(dep, NE_RESET));
|
||||||
|
do {
|
||||||
|
if (++count > 10) return FALSE; /* 20 mSecs. timeout */
|
||||||
|
milli_delay(2);
|
||||||
|
} while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ne_close(dpeth_t * dep);
|
||||||
|
** Function: Stops the board by resetting it and masking interrupts.
|
||||||
|
*/
|
||||||
|
static void ne_close(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
|
||||||
|
(void)ne_reset(dep);
|
||||||
|
outb_ne(dep, DP_ISR, 0xFF);
|
||||||
|
sys_irqdisable(&dep->de_hook);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void ne_init(dpeth_t * dep);
|
||||||
|
** Function: Initialize the board making it ready to work.
|
||||||
|
*/
|
||||||
|
static void ne_init(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
dep->de_data_port = dep->de_base_port + NE_DATA;
|
||||||
|
if (dep->de_16bit) {
|
||||||
|
dep->de_ramsize = NE2000_SIZE;
|
||||||
|
dep->de_offset_page = NE2000_START / DP_PAGESIZE;
|
||||||
|
} else {
|
||||||
|
dep->de_ramsize = NE1000_SIZE;
|
||||||
|
dep->de_offset_page = NE1000_START / DP_PAGESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocates two send buffers from onboard RAM */
|
||||||
|
dep->de_sendq_nr = SENDQ_NR;
|
||||||
|
for (ix = 0; ix < SENDQ_NR; ix += 1) {
|
||||||
|
dep->de_sendq[ix].sq_sendpage = dep->de_offset_page + ix * SENDQ_PAGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remaining onboard RAM allocated for receiving */
|
||||||
|
dep->de_startpage = dep->de_offset_page + ix * SENDQ_PAGES;
|
||||||
|
dep->de_stoppage = dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
|
||||||
|
|
||||||
|
/* Can't override the default IRQ. */
|
||||||
|
dep->de_irq &= NOT(DEI_DEFAULT);
|
||||||
|
|
||||||
|
ns_init(dep); /* Initialize DP controller */
|
||||||
|
|
||||||
|
printf("%s: NE%d000 (%dkB RAM) at %X:%d - ",
|
||||||
|
dep->de_name,
|
||||||
|
dep->de_16bit ? 2 : 1,
|
||||||
|
dep->de_ramsize / 1024,
|
||||||
|
dep->de_base_port, dep->de_irq);
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
|
||||||
|
printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: int ne_probe(dpeth_t * dep);
|
||||||
|
** Function: Probe for the presence of a NE*000 card by testing
|
||||||
|
** whether the board is reachable through the dp8390.
|
||||||
|
** Note that the NE1000 is an 8bit card and has a memory
|
||||||
|
** region distict from the 16bit NE2000.
|
||||||
|
*/
|
||||||
|
PUBLIC int ne_probe(dpeth_t * dep)
|
||||||
|
{
|
||||||
|
int ix, wd, loc1, loc2;
|
||||||
|
char EPROM[32];
|
||||||
|
static const struct {
|
||||||
|
unsigned char offset;
|
||||||
|
unsigned char value;
|
||||||
|
} InitSeq[] =
|
||||||
|
{
|
||||||
|
{ /* Selects page 0. */
|
||||||
|
DP_CR, (CR_NO_DMA | CR_PS_P0 | CR_STP),
|
||||||
|
},
|
||||||
|
{ /* Set byte-wide access and 8 bytes burst mode. */
|
||||||
|
DP_DCR, (DCR_8BYTES | DCR_BMS),
|
||||||
|
},
|
||||||
|
{ /* Clears the count registers. */
|
||||||
|
DP_RBCR0, 0x00, }, { DP_RBCR1, 0x00,
|
||||||
|
},
|
||||||
|
{ /* Mask completion irq. */
|
||||||
|
DP_IMR, 0x00, }, { DP_ISR, 0xFF,
|
||||||
|
},
|
||||||
|
{ /* Set receiver to monitor */
|
||||||
|
DP_RCR, RCR_MON,
|
||||||
|
},
|
||||||
|
{ /* and transmitter to loopback mode. */
|
||||||
|
DP_TCR, TCR_INTERNAL,
|
||||||
|
},
|
||||||
|
{ /* Transmit 32 bytes */
|
||||||
|
DP_RBCR0, 32, }, { DP_RBCR1, 0,
|
||||||
|
},
|
||||||
|
{ /* DMA starting at 0x0000. */
|
||||||
|
DP_RSAR0, 0x00, }, { DP_RSAR1, 0x00,
|
||||||
|
},
|
||||||
|
{ /* Start board (reads) */
|
||||||
|
DP_CR, (CR_PS_P0 | CR_DM_RR | CR_STA),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
dep->de_dp8390_port = dep->de_base_port + NE_DP8390;
|
||||||
|
|
||||||
|
if ((loc1 = inb_ne(dep, NE_DP8390)) == 0xFF) return FALSE;
|
||||||
|
|
||||||
|
/* Check if the dp8390 is really there */
|
||||||
|
outb_ne(dep, DP_CR, CR_STP | CR_NO_DMA | CR_PS_P1);
|
||||||
|
loc2 = inb_ne(dep, DP_MAR5); /* Saves one byte of the address */
|
||||||
|
outb_ne(dep, DP_MAR5, 0xFF); /* Write 0xFF to it (same offset as DP_CNTR0) */
|
||||||
|
outb_ne(dep, DP_CR, CR_NO_DMA | CR_PS_P0); /* Back to page 0 */
|
||||||
|
inb_ne(dep, DP_CNTR0); /* Reading counter resets it */
|
||||||
|
if (inb_ne(dep, DP_CNTR0) != 0) {
|
||||||
|
outb_ne(dep, NE_DP8390, loc1); /* Try to restore modified bytes */
|
||||||
|
outb_ne(dep, DP_TCR, loc2);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to reset the board */
|
||||||
|
if (ne_reset(dep) == FALSE) return FALSE;
|
||||||
|
|
||||||
|
/* Checks whether the board is 8/16bits and a real NE*000 or clone */
|
||||||
|
for (ix = 0; ix < sizeof(InitSeq)/sizeof(InitSeq[0]); ix += 1) {
|
||||||
|
outb_ne(dep, InitSeq[ix].offset, InitSeq[ix].value);
|
||||||
|
}
|
||||||
|
for (ix = 0, wd = 1; ix < 32; ix += 2) {
|
||||||
|
EPROM[ix + 0] = inb_ne(dep, NE_DATA);
|
||||||
|
EPROM[ix + 1] = inb_ne(dep, NE_DATA);
|
||||||
|
/* NE2000s and clones read same value for even and odd addresses */
|
||||||
|
if (EPROM[ix + 0] != EPROM[ix + 1]) wd = 0;
|
||||||
|
}
|
||||||
|
if (wd == 1) { /* Normalize EPROM contents for NE2000 */
|
||||||
|
for (ix = 0; ix < 16; ix += 1) EPROM[ix] = EPROM[ix * 2];
|
||||||
|
}
|
||||||
|
/* Real NE*000 and good clones have '0x57' at locations 14 and 15 */
|
||||||
|
if (EPROM[14] != 0x57 || EPROM[15] != 0x57) return FALSE;
|
||||||
|
|
||||||
|
/* Setup the ethernet address. */
|
||||||
|
for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
|
||||||
|
dep->de_address.ea_addr[ix] = EPROM[ix];
|
||||||
|
}
|
||||||
|
dep->de_16bit = wd;
|
||||||
|
dep->de_linmem = 0; /* Uses Programmed I/O only */
|
||||||
|
dep->de_prog_IO = 1;
|
||||||
|
dep->de_initf = ne_init;
|
||||||
|
dep->de_stopf = ne_close;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING && ENABLE_NE2000 */
|
||||||
|
|
||||||
|
/** ne.c **/
|
37
drivers/dpeth/ne.h
Normal file
37
drivers/dpeth/ne.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
** File: ne.h
|
||||||
|
**
|
||||||
|
** Created: March 15, 1994 by Philip Homburg <philip@cs.vu.nl>
|
||||||
|
** $PchId: ne2000.h,v 1.2 1995/12/22 08:42:31 philip Exp $
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NE2000_H
|
||||||
|
#define NE2000_H
|
||||||
|
|
||||||
|
#define NE_DP8390 0x00
|
||||||
|
#define NE_DATA 0x10
|
||||||
|
#define NE_RESET 0x1F
|
||||||
|
|
||||||
|
#define NE1000_START 0x2000
|
||||||
|
#define NE1000_SIZE 0x2000
|
||||||
|
#define NE2000_START 0x4000
|
||||||
|
#define NE2000_SIZE 0x4000
|
||||||
|
|
||||||
|
#define inb_ne(dep, reg) (inb(dep->de_base_port+reg))
|
||||||
|
#define outb_ne(dep, reg, data) (outb(dep->de_base_port+reg, data))
|
||||||
|
#define inw_ne(dep, reg) (inw(dep->de_base_port+reg))
|
||||||
|
#define outw_ne(dep, reg, data) (outw(dep->de_base_port+reg, data))
|
||||||
|
|
||||||
|
#endif /* NE2000_H */
|
||||||
|
|
||||||
|
/** ne.h **/
|
176
drivers/dpeth/netbuff.c
Normal file
176
drivers/dpeth/netbuff.c
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
** File: netbuff.c Jun. 10, 2000
|
||||||
|
**
|
||||||
|
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
**
|
||||||
|
** This file contains specific implementation of buffering
|
||||||
|
** for network packets.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if ENABLE_NETWORKING == 1 && HAVE_BUFFERS == 1
|
||||||
|
|
||||||
|
static m_hdr_t *allocptr = NULL;
|
||||||
|
static char tx_rx_buff[8192];
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void *alloc_buff(dpeth_t *dep, int size)
|
||||||
|
** Function: Allocates a buffer from the common pool.
|
||||||
|
*/
|
||||||
|
PUBLIC void *alloc_buff(dpeth_t *dep, int size)
|
||||||
|
{
|
||||||
|
m_hdr_t *ptr, *wrk = allocptr;
|
||||||
|
int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1;
|
||||||
|
|
||||||
|
lock();
|
||||||
|
for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) {
|
||||||
|
if (ptr->size >= units) {
|
||||||
|
/* Memory is available, carve requested size from pool */
|
||||||
|
if (ptr->size == units) {
|
||||||
|
wrk->next = ptr->next;
|
||||||
|
} else {
|
||||||
|
/* Get memory from top address */
|
||||||
|
ptr->size -= units;
|
||||||
|
ptr += ptr->size;
|
||||||
|
ptr->size = units;
|
||||||
|
}
|
||||||
|
allocptr = wrk;
|
||||||
|
unlock();
|
||||||
|
return ptr + 1;
|
||||||
|
}
|
||||||
|
if (ptr == allocptr) break;
|
||||||
|
}
|
||||||
|
unlock();
|
||||||
|
return NULL; /* No memory available */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void free_buff(dpeth_t *dep, void *blk)
|
||||||
|
** Function: Returns a buffer to the common pool.
|
||||||
|
*/
|
||||||
|
PUBLIC void free_buff(dpeth_t *dep, void *blk)
|
||||||
|
{
|
||||||
|
m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1;
|
||||||
|
|
||||||
|
lock(); /* Scan linked list for the correct place */
|
||||||
|
for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next)
|
||||||
|
if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break;
|
||||||
|
|
||||||
|
/* Check if adjacent block is free and join blocks */
|
||||||
|
if (ptr + ptr->size == wrk->next) {
|
||||||
|
ptr->size += wrk->next->size;
|
||||||
|
ptr->next = wrk->next->next;
|
||||||
|
} else
|
||||||
|
ptr->next = wrk->next;
|
||||||
|
if (wrk + wrk->size == ptr) {
|
||||||
|
wrk->size += ptr->size;
|
||||||
|
wrk->next = ptr->next;
|
||||||
|
} else
|
||||||
|
wrk->next = ptr;
|
||||||
|
allocptr = wrk; /* Point allocptr to block just released */
|
||||||
|
unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void init_buff(dpeth_t *dep, buff_t **tx_buff)
|
||||||
|
** Function: Initalizes driver data structures.
|
||||||
|
*/
|
||||||
|
PUBLIC void init_buff(dpeth_t *dep, buff_t **tx_buff)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Initializes buffer pool */
|
||||||
|
if (allocptr == NULL) {
|
||||||
|
m_hdr_t *rx = (m_hdr_t *) tx_rx_buff;
|
||||||
|
rx->next = allocptr = rx;
|
||||||
|
rx->size = 0;
|
||||||
|
rx += 1;
|
||||||
|
rx->next = NULL;
|
||||||
|
rx->size = (sizeof(tx_rx_buff) / sizeof(m_hdr_t)) - 1;
|
||||||
|
free_buff(dep, rx + 1);
|
||||||
|
dep->de_recvq_tail = dep->de_recvq_head = NULL;
|
||||||
|
if (tx_buff != NULL) {
|
||||||
|
*tx_buff = alloc_buff(dep, ETH_MAX_PACK_SIZE + sizeof(buff_t));
|
||||||
|
(*tx_buff)->size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return; /* Done */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void mem2user(dpeth_t *dep, buff_t *rxbuff);
|
||||||
|
** Function: Copies a packet from local buffer to user area.
|
||||||
|
*/
|
||||||
|
PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
iovec_dat_t *iovp = &dep->de_read_iovec;
|
||||||
|
int pktsize = rxbuff->size;
|
||||||
|
char *buffer = rxbuff->buffer;
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet into user buffers */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
|
||||||
|
/* Reads from Rx buffer to user area */
|
||||||
|
sys_datacopy(SELF, (vir_bytes)buffer, iovp->iod_proc_nr,
|
||||||
|
iovp->iod_iovec[ix].iov_addr, bytes);
|
||||||
|
buffer += bytes;
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Name: void user2mem(dpeth_t *dep, buff_t *txbuff)
|
||||||
|
** Function: Copies a packet from user area to local buffer.
|
||||||
|
*/
|
||||||
|
PUBLIC void user2mem(dpeth_t *dep, buff_t *txbuff)
|
||||||
|
{
|
||||||
|
phys_bytes phys_user;
|
||||||
|
int bytes, ix = 0;
|
||||||
|
iovec_dat_t *iovp = &dep->de_write_iovec;
|
||||||
|
int pktsize = txbuff->size;
|
||||||
|
char *buffer = txbuff->buffer;
|
||||||
|
|
||||||
|
do { /* Reads chuncks of packet from user buffers */
|
||||||
|
|
||||||
|
bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
|
||||||
|
if (bytes > pktsize) bytes = pktsize;
|
||||||
|
sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
|
||||||
|
SELF, (vir_bytes)buffer, bytes);
|
||||||
|
buffer += bytes;
|
||||||
|
|
||||||
|
if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
||||||
|
dp_next_iovec(iovp);
|
||||||
|
ix = 0;
|
||||||
|
}
|
||||||
|
/* Till packet done */
|
||||||
|
} while ((pktsize -= bytes) > 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING */
|
||||||
|
|
||||||
|
/** netbuff.c **/
|
323
drivers/dpeth/wd.c
Normal file
323
drivers/dpeth/wd.c
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
/*
|
||||||
|
** File: wd.c
|
||||||
|
**
|
||||||
|
** Driver for the Ethercard (WD80x3) and derivates
|
||||||
|
** This file contains only the wd80x3 specific code,
|
||||||
|
** the rest is in 8390.c
|
||||||
|
**
|
||||||
|
** Created: March 14, 1994 by Philip Homburg
|
||||||
|
** PchId:
|
||||||
|
**
|
||||||
|
** Modified: Jun. 08, 2000 by Giovanni Falzoni <gfalzoni@inwind.it>
|
||||||
|
** Adaptation to interfacing new main network task.
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers.h"
|
||||||
|
#include <net/gen/ether.h>
|
||||||
|
#include <net/gen/eth_io.h>
|
||||||
|
#include "dp.h"
|
||||||
|
|
||||||
|
#if (ENABLE_NETWORKING == 1 && ENABLE_WDETH == 1)
|
||||||
|
|
||||||
|
#include "8390.h"
|
||||||
|
#include "wd.h"
|
||||||
|
|
||||||
|
#define WET_ETHERNET 0x01 /* Ethernet transceiver */
|
||||||
|
#define WET_STARLAN 0x02 /* Starlan transceiver */
|
||||||
|
#define WET_INTERF_CHIP 0x04 /* has a WD83C583 interface chip */
|
||||||
|
#define WET_BRD_16BIT 0x08 /* 16 bit board */
|
||||||
|
#define WET_SLT_16BIT 0x10 /* 16 bit slot */
|
||||||
|
#define WET_790 0x20 /* '790 chip */
|
||||||
|
|
||||||
|
static const int we_int_table[8] = {9, 3, 5, 7, 10, 11, 15, 4};
|
||||||
|
static const int we_790int_table[8] = {0, 9, 3, 5, 7, 10, 11, 15};
|
||||||
|
|
||||||
|
_PROTOTYPE(static void we_init, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static void we_stop, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static int we_aliasing, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static int we_interface_chip, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static int we_16bitboard, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static int we_16bitslot, (dpeth_t * dep));
|
||||||
|
_PROTOTYPE(static int we_ultra, (dpeth_t * dep));
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* wdeth_probe *
|
||||||
|
*===========================================================================*/
|
||||||
|
int wdeth_probe(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
int sum;
|
||||||
|
|
||||||
|
if (dep->de_linmem == 0)
|
||||||
|
return FALSE; /* No shared memory, so no WD board */
|
||||||
|
|
||||||
|
sum = inb_we(dep, EPL_EA0) + inb_we(dep, EPL_EA1) +
|
||||||
|
inb_we(dep, EPL_EA2) + inb_we(dep, EPL_EA3) +
|
||||||
|
inb_we(dep, EPL_EA4) + inb_we(dep, EPL_EA5) +
|
||||||
|
inb_we(dep, EPL_TLB) + inb_we(dep, EPL_CHKSUM);
|
||||||
|
if ((sum & 0xFF) != 0xFF)
|
||||||
|
return FALSE; /* No ethernet board at this address */
|
||||||
|
|
||||||
|
dep->de_initf = we_init;
|
||||||
|
dep->de_stopf = we_stop;
|
||||||
|
dep->de_prog_IO = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void we_init(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
int i, int_indx, int_nr;
|
||||||
|
int tlb, rambit, revision;
|
||||||
|
int icr, irr, hwr, b, gcr;
|
||||||
|
int we_type;
|
||||||
|
int sendq_nr;
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i += 1) {
|
||||||
|
dep->de_address.ea_addr[i] = inb_we(dep, EPL_EA0 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
dep->de_dp8390_port = dep->de_base_port + EPL_DP8390;
|
||||||
|
|
||||||
|
dep->de_16bit = 0;
|
||||||
|
|
||||||
|
we_type = 0;
|
||||||
|
we_type |= WET_ETHERNET; /* assume ethernet */
|
||||||
|
if (we_ultra(dep)) we_type |= WET_790;
|
||||||
|
if (!we_aliasing(dep)) {
|
||||||
|
if (we_interface_chip(dep)) we_type |= WET_INTERF_CHIP;
|
||||||
|
if (we_16bitboard(dep)) {
|
||||||
|
we_type |= WET_BRD_16BIT;
|
||||||
|
if (we_16bitslot(dep)) we_type |= WET_SLT_16BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (we_type & WET_SLT_16BIT) dep->de_16bit = 1;
|
||||||
|
|
||||||
|
/* Look at the on board ram size. */
|
||||||
|
tlb = inb_we(dep, EPL_TLB);
|
||||||
|
revision = tlb & E_TLB_REV;
|
||||||
|
rambit = tlb & E_TLB_RAM;
|
||||||
|
|
||||||
|
if (dep->de_ramsize != 0) {
|
||||||
|
/* Size set from boot environment. */
|
||||||
|
} else if (revision < 2) {
|
||||||
|
dep->de_ramsize = 0x2000; /* 8K */
|
||||||
|
if (we_type & WET_BRD_16BIT)
|
||||||
|
dep->de_ramsize = 0x4000; /* 16K */
|
||||||
|
else if ((we_type & WET_INTERF_CHIP) &&
|
||||||
|
inb_we(dep, EPL_ICR) & E_ICR_MEMBIT) {
|
||||||
|
dep->de_ramsize = 0x8000; /* 32K */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (we_type & WET_BRD_16BIT) {
|
||||||
|
/* 32K or 16K */
|
||||||
|
dep->de_ramsize = rambit ? 0x8000 : 0x4000;
|
||||||
|
} else {
|
||||||
|
/* 32K or 8K */
|
||||||
|
dep->de_ramsize = rambit ? 0x8000 : 0x2000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (we_type & WET_790) {
|
||||||
|
outb_we(dep, EPL_MSR, E_MSR_RESET);
|
||||||
|
if ((we_type & (WET_BRD_16BIT | WET_SLT_16BIT)) ==
|
||||||
|
(WET_BRD_16BIT | WET_SLT_16BIT)) {
|
||||||
|
outb_we(dep, EPL_LAAR, E_LAAR_LAN16E | E_LAAR_MEM16E);
|
||||||
|
}
|
||||||
|
} else if (we_type & WET_BRD_16BIT) {
|
||||||
|
if (we_type & WET_SLT_16BIT) {
|
||||||
|
outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_SOFTINT |
|
||||||
|
E_LAAR_LAN16E | E_LAAR_MEM16E);
|
||||||
|
} else {
|
||||||
|
outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_SOFTINT |
|
||||||
|
E_LAAR_LAN16E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (we_type & WET_790) {
|
||||||
|
outb_we(dep, EPL_MSR, E_MSR_MENABLE);
|
||||||
|
hwr = inb_we(dep, EPL_790_HWR);
|
||||||
|
outb_we(dep, EPL_790_HWR, hwr | E_790_HWR_SWH);
|
||||||
|
b = inb_we(dep, EPL_790_B);
|
||||||
|
outb_we(dep, EPL_790_B, ((dep->de_linmem >> 13) & 0x0f) |
|
||||||
|
((dep->de_linmem >> 11) & 0x40) | (b & 0xb0));
|
||||||
|
outb_we(dep, EPL_790_HWR, hwr & ~E_790_HWR_SWH);
|
||||||
|
} else {
|
||||||
|
outb_we(dep, EPL_MSR, E_MSR_RESET);
|
||||||
|
outb_we(dep, EPL_MSR, E_MSR_MENABLE |
|
||||||
|
((dep->de_linmem >> 13) & E_MSR_MEMADDR));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((we_type & WET_INTERF_CHIP) && !(we_type & WET_790)) {
|
||||||
|
icr = inb_we(dep, EPL_ICR);
|
||||||
|
irr = inb_we(dep, EPL_IRR);
|
||||||
|
int_indx = (icr & E_ICR_IR2) | ((irr & (E_IRR_IR0 | E_IRR_IR1)) >> 5);
|
||||||
|
int_nr = we_int_table[int_indx];
|
||||||
|
DEBUG(printf("%s: encoded irq= %d\n", dep->de_name, int_nr));
|
||||||
|
if (dep->de_irq & DEI_DEFAULT) dep->de_irq = int_nr;
|
||||||
|
outb_we(dep, EPL_IRR, irr | E_IRR_IEN);
|
||||||
|
}
|
||||||
|
if (we_type & WET_790) {
|
||||||
|
hwr = inb_we(dep, EPL_790_HWR);
|
||||||
|
outb_we(dep, EPL_790_HWR, hwr | E_790_HWR_SWH);
|
||||||
|
|
||||||
|
gcr = inb_we(dep, EPL_790_GCR);
|
||||||
|
|
||||||
|
outb_we(dep, EPL_790_HWR, hwr & ~E_790_HWR_SWH);
|
||||||
|
|
||||||
|
int_indx = ((gcr & E_790_GCR_IR2) >> 4) |
|
||||||
|
((gcr & (E_790_GCR_IR1 | E_790_GCR_IR0)) >> 2);
|
||||||
|
int_nr = we_790int_table[int_indx];
|
||||||
|
DEBUG(printf("%s: encoded irq= %d\n", dep->de_name, int_nr));
|
||||||
|
if (dep->de_irq & DEI_DEFAULT) dep->de_irq = int_nr;
|
||||||
|
icr = inb_we(dep, EPL_790_ICR);
|
||||||
|
outb_we(dep, EPL_790_ICR, icr | E_790_ICR_EIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strip the "default flag." */
|
||||||
|
dep->de_irq &= ~DEI_DEFAULT;
|
||||||
|
|
||||||
|
dep->de_offset_page = 0; /* Shared memory starts at 0 */
|
||||||
|
/* Allocate one send buffer (1.5KB) per 8KB of on board memory.
|
||||||
|
sendq_nr = dep->de_ramsize / 0x2000;
|
||||||
|
if (sendq_nr < 1)
|
||||||
|
sendq_nr = 1;
|
||||||
|
else if (sendq_nr > SENDQ_NR) */
|
||||||
|
sendq_nr = SENDQ_NR;
|
||||||
|
dep->de_sendq_nr = sendq_nr;
|
||||||
|
for (i = 0; i < sendq_nr; i++) {
|
||||||
|
dep->de_sendq[i].sq_sendpage = i * SENDQ_PAGES;
|
||||||
|
}
|
||||||
|
dep->de_startpage = i * SENDQ_PAGES;
|
||||||
|
dep->de_stoppage = dep->de_ramsize / DP_PAGESIZE;
|
||||||
|
|
||||||
|
ns_init(dep); /* Initialize DP controller */
|
||||||
|
|
||||||
|
printf("%s: WD80%d3 (%dkB RAM) at %X:%d:%lX - ",
|
||||||
|
dep->de_name,
|
||||||
|
we_type & WET_BRD_16BIT ? 1 : 0,
|
||||||
|
dep->de_ramsize / 1024,
|
||||||
|
dep->de_base_port,
|
||||||
|
dep->de_irq,
|
||||||
|
dep->de_linmem);
|
||||||
|
for (i = 0; i < SA_ADDR_LEN; i += 1)
|
||||||
|
printf("%02X%c", dep->de_address.ea_addr[i],
|
||||||
|
i < SA_ADDR_LEN - 1 ? ':' : '\n');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_stop *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void we_stop(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E);
|
||||||
|
outb_we(dep, EPL_MSR, E_MSR_RESET);
|
||||||
|
outb_we(dep, EPL_MSR, 0);
|
||||||
|
sys_irqdisable(&dep->de_hook);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_aliasing *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int we_aliasing(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
/* Determine whether wd8003 hardware performs register aliasing. This implies
|
||||||
|
* an old WD8003E board. */
|
||||||
|
|
||||||
|
if (inb_we(dep, EPL_REG1) != inb_we(dep, EPL_EA1)) return 0;
|
||||||
|
if (inb_we(dep, EPL_REG2) != inb_we(dep, EPL_EA2)) return 0;
|
||||||
|
if (inb_we(dep, EPL_REG3) != inb_we(dep, EPL_EA3)) return 0;
|
||||||
|
if (inb_we(dep, EPL_REG4) != inb_we(dep, EPL_EA4)) return 0;
|
||||||
|
if (inb_we(dep, EPL_REG7) != inb_we(dep, EPL_CHKSUM)) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_interface_chip *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int we_interface_chip(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
/* Determine if the board has an interface chip. */
|
||||||
|
|
||||||
|
outb_we(dep, EPL_GP2, 0x35);
|
||||||
|
if (inb_we(dep, EPL_GP2) != 0x35) return 0;
|
||||||
|
outb_we(dep, EPL_GP2, 0x3A);
|
||||||
|
if (inb_we(dep, EPL_GP2) != 0x3A) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_16bitboard *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int we_16bitboard(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
/* Determine whether the board is capable of doing 16 bit memory moves.
|
||||||
|
* If the 16 bit enable bit is unchangable by software we'll assume an
|
||||||
|
* 8 bit board.
|
||||||
|
*/
|
||||||
|
int icr;
|
||||||
|
u8_t tlb;
|
||||||
|
|
||||||
|
icr = inb_we(dep, EPL_ICR);
|
||||||
|
|
||||||
|
outb_we(dep, EPL_ICR, icr ^ E_ICR_16BIT);
|
||||||
|
if (inb_we(dep, EPL_ICR) == icr) {
|
||||||
|
tlb = inb_we(dep, EPL_TLB);
|
||||||
|
|
||||||
|
DEBUG(printf("%s: tlb= 0x%x\n", dep->de_name, tlb));
|
||||||
|
|
||||||
|
return tlb == E_TLB_EB || tlb == E_TLB_E ||
|
||||||
|
tlb == E_TLB_SMCE || tlb == E_TLB_SMC8216C;
|
||||||
|
}
|
||||||
|
outb_we(dep, EPL_ICR, icr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_16bitslot *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int we_16bitslot(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
/* Determine if the 16 bit board in plugged into a 16 bit slot. */
|
||||||
|
|
||||||
|
return !!(inb_we(dep, EPL_ICR) & E_ICR_16BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* we_ultra *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int we_ultra(dep)
|
||||||
|
dpeth_t *dep;
|
||||||
|
{
|
||||||
|
/* Determine if we has an '790 chip. */
|
||||||
|
u8_t tlb;
|
||||||
|
|
||||||
|
tlb = inb_we(dep, EPL_TLB);
|
||||||
|
return tlb == E_TLB_SMC8216C;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ENABLE_NETWORKING && ENABLE_WDETH */
|
||||||
|
|
||||||
|
/** wd.c **/
|
103
drivers/dpeth/wd.h
Normal file
103
drivers/dpeth/wd.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
** File: wd.h
|
||||||
|
**
|
||||||
|
** Created: before Dec 28, 1992 by Philip Homburg
|
||||||
|
** $PchId: wdeth.h,v 1.4 1995/12/22 08:36:57 philip Exp $
|
||||||
|
**
|
||||||
|
** $Log$
|
||||||
|
** Revision 1.1 2005/06/29 10:16:46 beng
|
||||||
|
** Import of dpeth 3c501/3c509b/.. ethernet driver by
|
||||||
|
** Giovanni Falzoni <fgalzoni@inwind.it>.
|
||||||
|
**
|
||||||
|
** Revision 2.0 2005/06/26 16:16:46 lsodgf0
|
||||||
|
** Initial revision for Minix 3.0.6
|
||||||
|
**
|
||||||
|
** $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WDETH_H
|
||||||
|
#define WDETH_H
|
||||||
|
|
||||||
|
/* Western Digital Ethercard Plus, or WD8003E card. */
|
||||||
|
|
||||||
|
#define EPL_REG0 0x0 /* Control(write) and status(read) */
|
||||||
|
#define EPL_REG1 0x1
|
||||||
|
#define EPL_REG2 0x2
|
||||||
|
#define EPL_REG3 0x3
|
||||||
|
#define EPL_REG4 0x4
|
||||||
|
#define EPL_REG5 0x5
|
||||||
|
#define EPL_REG6 0x6
|
||||||
|
#define EPL_REG7 0x7
|
||||||
|
#define EPL_EA0 0x8 /* Most significant eaddr byte */
|
||||||
|
#define EPL_EA1 0x9
|
||||||
|
#define EPL_EA2 0xA
|
||||||
|
#define EPL_EA3 0xB
|
||||||
|
#define EPL_EA4 0xC
|
||||||
|
#define EPL_EA5 0xD /* Least significant eaddr byte */
|
||||||
|
#define EPL_TLB 0xE
|
||||||
|
#define EPL_CHKSUM 0xF /* sum from epl_ea0 upto here is 0xFF */
|
||||||
|
#define EPL_DP8390 0x10 /* NatSemi chip */
|
||||||
|
|
||||||
|
#define EPL_MSR EPL_REG0/* memory select register */
|
||||||
|
#define EPL_ICR EPL_REG1/* interface configuration register */
|
||||||
|
#define EPL_IRR EPL_REG4/* interrupt request register (IRR) */
|
||||||
|
#define EPL_790_HWR EPL_REG4/* '790 hardware support register */
|
||||||
|
#define EPL_LAAR EPL_REG5/* LA address register (write only) */
|
||||||
|
#define EPL_790_ICR EPL_REG6/* '790 interrupt control register */
|
||||||
|
#define EPL_GP2 EPL_REG7/* general purpose register 2 */
|
||||||
|
#define EPL_790_B EPL_EA3 /* '790 memory register */
|
||||||
|
#define EPL_790_GCR EPL_EA5 /* '790 General Control Register */
|
||||||
|
|
||||||
|
/* Bits in EPL_MSR */
|
||||||
|
#define E_MSR_MEMADDR 0x3F /* Bits SA18-SA13, SA19 implicit 1 */
|
||||||
|
#define E_MSR_MENABLE 0x40 /* Memory Enable */
|
||||||
|
#define E_MSR_RESET 0x80 /* Software Reset */
|
||||||
|
|
||||||
|
/* Bits in EPL_ICR */
|
||||||
|
#define E_ICR_16BIT 0x01 /* 16 bit bus */
|
||||||
|
#define E_ICR_IR2 0x04 /* bit 2 of encoded IRQ */
|
||||||
|
#define E_ICR_MEMBIT 0x08 /* 583 mem size mask */
|
||||||
|
|
||||||
|
/* Bits in EPL_IRR */
|
||||||
|
#define E_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
|
||||||
|
#define E_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
|
||||||
|
#define E_IRR_IEN 0x80 /* enable interrupts */
|
||||||
|
|
||||||
|
/* Bits in EPL_LAAR */
|
||||||
|
#define E_LAAR_A19 0x01 /* address lines for above 1M ram */
|
||||||
|
#define E_LAAR_A20 0x02 /* address lines for above 1M ram */
|
||||||
|
#define E_LAAR_A21 0x04 /* address lines for above 1M ram */
|
||||||
|
#define E_LAAR_A22 0x08 /* address lines for above 1M ram */
|
||||||
|
#define E_LAAR_A23 0x10 /* address lines for above 1M ram */
|
||||||
|
#define E_LAAR_SOFTINT 0x20 /* enable software interrupt */
|
||||||
|
#define E_LAAR_LAN16E 0x40 /* enables 16 bit RAM for LAN */
|
||||||
|
#define E_LAAR_MEM16E 0x80 /* enables 16 bit RAM for host */
|
||||||
|
|
||||||
|
/* Bits and values in EPL_TLB */
|
||||||
|
#define E_TLB_EB 0x05 /* WD8013EB */
|
||||||
|
#define E_TLB_E 0x27 /* WD8013 Elite */
|
||||||
|
#define E_TLB_SMCE 0x29 /* SMC Elite 16 */
|
||||||
|
#define E_TLB_SMC8216C 0x2B /* SMC 8216 C */
|
||||||
|
|
||||||
|
#define E_TLB_REV 0x1F /* revision mask */
|
||||||
|
#define E_TLB_SOFT 0x20 /* soft config */
|
||||||
|
#define E_TLB_RAM 0x40 /* extra ram bit */
|
||||||
|
|
||||||
|
/* Bits in EPL_790_HWR */
|
||||||
|
#define E_790_HWR_SWH 0x80 /* switch register set */
|
||||||
|
|
||||||
|
/* Bits in EPL_790_ICR */
|
||||||
|
#define E_790_ICR_EIL 0x01 /* enable interrupts */
|
||||||
|
|
||||||
|
/* Bits in EPL_790_GCR when E_790_HWR_SWH is set in EPL_790_HWR */
|
||||||
|
#define E_790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */
|
||||||
|
#define E_790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */
|
||||||
|
#define E_790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */
|
||||||
|
|
||||||
|
|
||||||
|
#define inb_we(dep, reg) (inb(dep->de_base_port+reg))
|
||||||
|
#define outb_we(dep, reg, data) (outb(dep->de_base_port+reg, data))
|
||||||
|
|
||||||
|
#endif /* WDETH_H */
|
||||||
|
|
||||||
|
/** wd.h **/
|
|
@ -42,12 +42,14 @@
|
||||||
#define PRINTER (FLOPPY + ENABLE_PRINTER) /* Centronics */
|
#define PRINTER (FLOPPY + ENABLE_PRINTER) /* Centronics */
|
||||||
#define USR8139 (PRINTER + ENABLE_RTL8139) /* Realtek RTL8139 */
|
#define USR8139 (PRINTER + ENABLE_RTL8139) /* Realtek RTL8139 */
|
||||||
#define FXP (USR8139 + ENABLE_FXP) /* Intel Pro/100 */
|
#define FXP (USR8139 + ENABLE_FXP) /* Intel Pro/100 */
|
||||||
#define INIT_PROC_NR (FXP + 1) /* init -- goes multiuser */
|
#define DPETH (FXP + ENABLE_DPETH) /* ISA Network task */
|
||||||
|
#define INIT_PROC_NR (DPETH + 1) /* init -- goes multiuser */
|
||||||
|
|
||||||
/* Number of processes contained in the system image. */
|
/* Number of processes contained in the system image. */
|
||||||
#define IMAGE_SIZE (NR_TASKS + \
|
#define IMAGE_SIZE (NR_TASKS + \
|
||||||
5 + ENABLE_AT_WINI + ENABLE_FLOPPY + \
|
5 + ENABLE_AT_WINI + ENABLE_FLOPPY + \
|
||||||
ENABLE_PRINTER + ENABLE_RTL8139 + ENABLE_FXP + 1 )
|
ENABLE_PRINTER + ENABLE_RTL8139 + ENABLE_FXP + \
|
||||||
|
ENABLE_DPETH + 1 )
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
#define DMA_SECTORS 1 /* DMA buffer size (must be >= 1) */
|
#define DMA_SECTORS 1 /* DMA buffer size (must be >= 1) */
|
||||||
|
|
||||||
/* Enable or disable networking drivers. */
|
/* Enable or disable networking drivers. */
|
||||||
#define ENABLE_DP8390 0 /* enable DP8390 ethernet driver */
|
#define ENABLE_DPETH 1 /* enable DP8390 ethernet driver */
|
||||||
#define ENABLE_WDETH 0 /* add Western Digital WD80x3 */
|
#define ENABLE_WDETH 0 /* add Western Digital WD80x3 */
|
||||||
#define ENABLE_NE2000 0 /* add Novell NE1000/NE2000 */
|
#define ENABLE_NE2000 0 /* add Novell NE1000/NE2000 */
|
||||||
#define ENABLE_3C503 0 /* add 3Com Etherlink II (3c503) */
|
#define ENABLE_3C503 0 /* add 3Com Etherlink II (3c503) */
|
||||||
|
|
|
@ -256,7 +256,7 @@ _phys_insb:
|
||||||
mov edx, 8(ebp) ! port to read from
|
mov edx, 8(ebp) ! port to read from
|
||||||
mov edi, 12(ebp) ! destination addr
|
mov edi, 12(ebp) ! destination addr
|
||||||
mov ecx, 16(ebp) ! byte count
|
mov ecx, 16(ebp) ! byte count
|
||||||
shr ecx, 1 ! word count
|
! shr ecx, 1 ! word count
|
||||||
rep insb ! input many bytes
|
rep insb ! input many bytes
|
||||||
pop es
|
pop es
|
||||||
pop edi
|
pop edi
|
||||||
|
|
|
@ -84,6 +84,9 @@ PUBLIC struct system_image image[] = {
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_FXP
|
#if ENABLE_FXP
|
||||||
{ FXP, 0, 0, 2, 0, SYSTEM_CALL_MASK, ALLOW_ALL_MASK, "FXP" },
|
{ FXP, 0, 0, 2, 0, SYSTEM_CALL_MASK, ALLOW_ALL_MASK, "FXP" },
|
||||||
|
#endif
|
||||||
|
#if ENABLE_DPETH
|
||||||
|
{ DPETH, 0, 0, 2, 0, SYSTEM_CALL_MASK, ALLOW_ALL_MASK, "DPETH" },
|
||||||
#endif
|
#endif
|
||||||
{ INIT_PROC_NR, 0, 0, USER_Q, 0, USER_CALL_MASK, USER_PROC_SENDMASK, "INIT" },
|
{ INIT_PROC_NR, 0, 0, USER_Q, 0, USER_CALL_MASK, USER_PROC_SENDMASK, "INIT" },
|
||||||
};
|
};
|
||||||
|
|
|
@ -138,9 +138,9 @@ PUBLIC void irqtab_dmp()
|
||||||
"clock", /* 00 */
|
"clock", /* 00 */
|
||||||
"keyboard", /* 01 */
|
"keyboard", /* 01 */
|
||||||
"cascade", /* 02 */
|
"cascade", /* 02 */
|
||||||
"eth/rs232", /* 03 */
|
"rs232", /* 03 */
|
||||||
"rs232", /* 04 */
|
"rs232", /* 04 */
|
||||||
"xt_wini", /* 05 */
|
"NIC(eth)", /* 05 */
|
||||||
"floppy", /* 06 */
|
"floppy", /* 06 */
|
||||||
"printer", /* 07 */
|
"printer", /* 07 */
|
||||||
"", /* 08 */
|
"", /* 08 */
|
||||||
|
|
|
@ -18,6 +18,7 @@ PROGRAMS= ../kernel/kernel \
|
||||||
../drivers/printer/printer \
|
../drivers/printer/printer \
|
||||||
../drivers/rtl8139/rtl8139 \
|
../drivers/rtl8139/rtl8139 \
|
||||||
../drivers/fxp/fxp \
|
../drivers/fxp/fxp \
|
||||||
|
../drivers/dpeth/dpeth \
|
||||||
../servers/init/init \
|
../servers/init/init \
|
||||||
# bootdev.img
|
# bootdev.img
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue