/*
* Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
* * Any deviations from these conditions require written permission from the copyright holder in advance
*
*
* Disclaimer
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Changes:
* 2009 Lukas Medjrech ported to HelenOS
*/
/** @addtogroup dp8390
* @{
*/
#include <assert.h>
#include <errno.h>
#include "../../include/byteorder.h"
#include "dp8390_drv.h"
#include "dp8390_port.h"
/*
* dp8390.c
*
* Created: before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
*
* Modified Mar 10 1994 by Philip Homburg
* Become a generic dp8390 driver.
*
* Modified Dec 20 1996 by G. Falzoni <falzoni@marina.scn.de>
* Added support for 3c503 boards.
*/
#include "local.h"
#include "dp8390.h"
//static u16_t eth_ign_proto;
//static char *progname;
/* Configuration */
/*typedef struct dp_conf
{
port_t dpc_port;
int dpc_irq;
phys_bytes dpc_mem;
char *dpc_envvar;
} dp_conf_t;
*/
//dp_conf_t dp_conf[]= /* Card addresses */
//{
/* I/O port, IRQ, Buffer address, Env. var. */
/* { 0x280, 3, 0xD0000, "DPETH0" },
{ 0x300, 5, 0xC8000, "DPETH1" },
{ 0x380, 10, 0xD8000, "DPETH2" },
};
*/
/* Test if dp_conf has exactly DE_PORT_NR entries. If not then you will see
* the error: "array size is negative".
*/
//extern int ___dummy[DE_PORT_NR == sizeof(dp_conf)/sizeof(dp_conf[0]) ? 1 : -1];
/* Card inits configured out? */
#if !ENABLE_WDETH
#define wdeth_probe(dep) (0)
#endif
#if !ENABLE_NE2000
#define ne_probe(dep) (0)
#endif
#if !ENABLE_3C503
#define el2_probe(dep) (0)
#endif
/* Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
* on writes to the CR register. Additional CR_STAs do not appear to hurt
* genuine dp8390s
*/
#define CR_EXTRA CR_STA
//#if ENABLE_PCI
//_PROTOTYPE( static void pci_conf, (void) );
//#endif
//_PROTOTYPE( static void do_vwrite, (message *mp, int from_int,
// int vectored) );
//_PROTOTYPE( static void do_vwrite_s, (message *mp, int from_int) );
//_PROTOTYPE( static void do_vread, (message *mp, int vectored) );
//_PROTOTYPE( static void do_vread_s, (message *mp) );
//_PROTOTYPE( static void do_init, (message *mp) );
//_PROTOTYPE( static void do_int, (dpeth_t *dep) );
//_PROTOTYPE( static void do_getstat, (message *mp) );
//_PROTOTYPE( static void do_getstat_s, (message *mp) );
//_PROTOTYPE( static void do_getname, (message *mp) );
//_PROTOTYPE( static void do_stop, (message *mp) );
_PROTOTYPE( static void dp_init, (dpeth_t *dep) );
//_PROTOTYPE( static void dp_confaddr, (dpeth_t *dep) );
_PROTOTYPE( static void dp_reinit, (dpeth_t *dep) );
_PROTOTYPE( static void dp_reset, (dpeth_t *dep) );
//_PROTOTYPE( static void dp_check_ints, (dpeth_t *dep) );
_PROTOTYPE( static void dp_recv, (dpeth_t *dep) );
_PROTOTYPE( static void dp_send, (dpeth_t *dep) );
//_PROTOTYPE( static void dp8390_stop, (void) );
_PROTOTYPE( static void dp_getblock, (dpeth_t *dep, int page,
size_t offset, size_t size, void *dst) );
//_PROTOTYPE( static void dp_pio8_getblock, (dpeth_t *dep, int page,
// size_t offset, size_t size, void *dst) );
//_PROTOTYPE( static void dp_pio16_getblock, (dpeth_t *dep, int page,
// size_t offset, size_t size, void *dst) );
_PROTOTYPE( static int dp_pkt2user, (dpeth_t *dep, int page,
int length) );
//_PROTOTYPE( static int dp_pkt2user_s, (dpeth_t *dep, int page,
// int length) );
//_PROTOTYPE( static void dp_user2nic, (dpeth_t *dep, iovec_dat_t *iovp,
// vir_bytes offset, int nic_addr, vir_bytes count) );
//_PROTOTYPE( static void dp_user2nic_s, (dpeth_t *dep, iovec_dat_s_t *iovp,
// vir_bytes offset, int nic_addr, vir_bytes count) );
//_PROTOTYPE( static void dp_pio8_user2nic, (dpeth_t *dep,
// iovec_dat_t *iovp, vir_bytes offset,
// int nic_addr, vir_bytes count) );
//_PROTOTYPE( static void dp_pio8_user2nic_s, (dpeth_t *dep,
// iovec_dat_s_t *iovp, vir_bytes offset,
// int nic_addr, vir_bytes count) );
//_PROTOTYPE( static void dp_pio16_user2nic, (dpeth_t *dep,
// iovec_dat_t *iovp, vir_bytes offset,
// int nic_addr, vir_bytes count) );
//_PROTOTYPE( static void dp_pio16_user2nic_s, (dpeth_t *dep,
// iovec_dat_s_t *iovp, vir_bytes offset,
// int nic_addr, vir_bytes count) );
_PROTOTYPE( static void dp_nic2user, (dpeth_t *dep, int nic_addr,
iovec_dat_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_nic2user_s, (dpeth_t *dep, int nic_addr,
// iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_pio8_nic2user, (dpeth_t *dep, int nic_addr,
// iovec_dat_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_pio8_nic2user_s, (dpeth_t *dep, int nic_addr,
// iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_pio16_nic2user, (dpeth_t *dep, int nic_addr,
// iovec_dat_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_pio16_nic2user_s, (dpeth_t *dep, int nic_addr,
// iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
//_PROTOTYPE( static void dp_next_iovec, (iovec_dat_t *iovp) );
//_PROTOTYPE( static void dp_next_iovec_s, (iovec_dat_s_t *iovp) );
_PROTOTYPE( static void conf_hw, (dpeth_t *dep) );
//_PROTOTYPE( static void update_conf, (dpeth_t *dep, dp_conf_t *dcp) );
_PROTOTYPE( static void map_hw_buffer, (dpeth_t *dep) );
//_PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp) );
//_PROTOTYPE( static int calc_iovec_size_s, (iovec_dat_s_t *iovp) );
_PROTOTYPE( static void reply, (dpeth_t *dep, int err, int may_block) );
//_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
//_PROTOTYPE( static void get_userdata, (int user_proc,
// vir_bytes user_addr, vir_bytes count, void *loc_addr) );
//_PROTOTYPE( static void get_userdata_s, (int user_proc,
// cp_grant_id_t grant, vir_bytes offset, vir_bytes count,
// void *loc_addr) );
//_PROTOTYPE( static void put_userdata, (int user_proc,
// vir_bytes user_addr, vir_bytes count, void *loc_addr) );
//_PROTOTYPE( static void put_userdata_s, (int user_proc,
// cp_grant_id_t grant, size_t count, void *loc_addr) );
//_PROTOTYPE( static void insb, (port_t port, void *buf, size_t size) );
//_PROTOTYPE( static void insw, (port_t port, void *buf, size_t size) );
//_PROTOTYPE( static void do_vir_insb, (port_t port, int proc,
// vir_bytes buf, size_t size) );
//_PROTOTYPE( static void do_vir_insw, (port_t port, int proc,
// vir_bytes buf, size_t size) );
//_PROTOTYPE( static void do_vir_outsb, (port_t port, int proc,
// vir_bytes buf, size_t size) );
//_PROTOTYPE( static void do_vir_outsw, (port_t port, int proc,
// vir_bytes buf, size_t size) );
int do_probe( dpeth_t * dep ){
/* This is the default, try to (re)locate the device. */
conf_hw(dep);
if (dep->de_mode == DEM_DISABLED)
{
/* Probe failed, or the device is configured off. */
return EXDEV;//ENXIO;
}
if (dep->de_mode == DEM_ENABLED)
dp_init(dep);
return EOK;
}
/*===========================================================================*
* do_init *
*===========================================================================*/
int do_init( dpeth_t * dep, int mode ){
if (dep->de_mode == DEM_DISABLED)
{
// might call do_probe()
return EXDEV;
}
if (dep->de_mode == DEM_SINK)
{
// strncpy((char *) dep->de_address.ea_addr, "ZDP", 6);
// dep->de_address.ea_addr[5] = port;
// dp_confaddr(dep);
//TODO ether address?
// reply_mess.m_type = DL_CONF_REPLY;
// reply_mess.m3_i1 = mp->DL_PORT;
// reply_mess.m3_i2 = DE_PORT_NR;
// *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
// mess_reply(mp, &reply_mess);
// return;
return EOK;
}
//TODO assert?
assert(dep
->de_mode
== DEM_ENABLED
);
assert(dep
->de_flags
& DEF_ENABLED
);
dep->de_flags &= ~(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
if (mode & DL_PROMISC_REQ)
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
if (mode & DL_MULTI_REQ)
dep->de_flags |= DEF_MULTI;
if (mode & DL_BROAD_REQ)
dep->de_flags |= DEF_BROAD;
// dep->de_client = mp->m_source;
dp_reinit(dep);
//TODO ether address?
// reply_mess.m_type = DL_CONF_REPLY;
// reply_mess.m3_i1 = mp->DL_PORT;
// reply_mess.m3_i2 = DE_PORT_NR;
// *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
// mess_reply(mp, &reply_mess);
return EOK;
}
/*===========================================================================*
* do_stop *
*===========================================================================*/
void do_stop( dpeth_t * dep ){
if(( dep->de_mode != DEM_SINK ) && ( dep->de_mode == DEM_ENABLED ) && ( dep->de_flags & DEF_ENABLED )){
outb_reg0( dep, DP_CR, CR_STP | CR_DM_ABORT );
( dep->de_stopf )( dep );
dep->de_flags = DEF_EMPTY;
}
}
/*===========================================================================*
* dp_init *
*===========================================================================*/
void dp_init(dep)
dpeth_t *dep;
{
int dp_rcr_reg;
int i;//, r;
/* General initialization */
dep->de_flags = DEF_EMPTY;
(*dep->de_initf)(dep);
// dp_confaddr(dep);
if (debug)
{
printf("%s: Ethernet address ", dep
->de_name
);
for (i= 0; i < 6; i++)
printf("%x%c", dep
->de_address.
ea_addr[i
],
i < 5 ? ':' : '\n');
}
/* Map buffer */
map_hw_buffer(dep);
/* Initialization of the dp8390 following the mandatory procedure
* in reference manual ("DP8390D/NS32490D NIC Network Interface
* Controller", National Semiconductor, July 1995, Page 29).
*/
/* Step 1: */
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
/* Step 2: */
if (dep->de_16bit)
outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
else
outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
/* Step 3: */
outb_reg0(dep, DP_RBCR0, 0);
outb_reg0(dep, DP_RBCR1, 0);
/* Step 4: */
dp_rcr_reg = 0;
if (dep->de_flags & DEF_PROMISC)
dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
if (dep->de_flags & DEF_BROAD)
dp_rcr_reg |= RCR_AB;
if (dep->de_flags & DEF_MULTI)
dp_rcr_reg |= RCR_AM;
outb_reg0(dep, DP_RCR, dp_rcr_reg);
/* Step 5: */
outb_reg0(dep, DP_TCR, TCR_INTERNAL);
/* Step 6: */
outb_reg0(dep, DP_BNRY, dep->de_startpage);
outb_reg0(dep, DP_PSTART, dep->de_startpage);
outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
/* Step 7: */
outb_reg0(dep, DP_ISR, 0xFF);
/* Step 8: */
outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
IMR_OVWE | IMR_CNTE);
/* Step 9: */
outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
outb_reg1(dep, DP_PAR0, dep->de_address.ea_addr[0]);
outb_reg1(dep, DP_PAR1, dep->de_address.ea_addr[1]);
outb_reg1(dep, DP_PAR2, dep->de_address.ea_addr[2]);
outb_reg1(dep, DP_PAR3, dep->de_address.ea_addr[3]);
outb_reg1(dep, DP_PAR4, dep->de_address.ea_addr[4]);
outb_reg1(dep, DP_PAR5, dep->de_address.ea_addr[5]);
outb_reg1(dep, DP_MAR0, 0xff);
outb_reg1(dep, DP_MAR1, 0xff);
outb_reg1(dep, DP_MAR2, 0xff);
outb_reg1(dep, DP_MAR3, 0xff);
outb_reg1(dep, DP_MAR4, 0xff);
outb_reg1(dep, DP_MAR5, 0xff);
outb_reg1(dep, DP_MAR6, 0xff);
outb_reg1(dep, DP_MAR7, 0xff);
outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
/* Step 10: */
outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
/* Step 11: */
outb_reg0(dep, DP_TCR, TCR_NORMAL);
inb_reg0(dep, DP_CNTR0); /* reset counters by reading */
inb_reg0(dep, DP_CNTR1);
inb_reg0(dep, DP_CNTR2);
/* Finish the initialization. */
dep->de_flags |= DEF_ENABLED;
for (i= 0; i<dep->de_sendq_nr; i++)
dep->de_sendq[i].sq_filled= 0;
dep->de_sendq_head= 0;
dep->de_sendq_tail= 0;
// if (!dep->de_prog_IO)
// {
// dep->de_user2nicf= dp_user2nic;
// dep->de_user2nicf_s= dp_user2nic_s;
dep->de_nic2userf= dp_nic2user;
// dep->de_nic2userf_s= dp_nic2user_s;
dep->de_getblockf= dp_getblock;
// }
// else if (dep->de_16bit)
// {
// dep->de_user2nicf= dp_pio16_user2nic;
// dep->de_user2nicf_s= dp_pio16_user2nic_s;
// dep->de_nic2userf= dp_pio16_nic2user;
// dep->de_nic2userf_s= dp_pio16_nic2user_s;
// dep->de_getblockf= dp_pio16_getblock;
// }
// else
// {
// dep->de_user2nicf= dp_pio8_user2nic;
// dep->de_user2nicf_s= dp_pio8_user2nic_s;
// dep->de_nic2userf= dp_pio8_nic2user;
// dep->de_nic2userf_s= dp_pio8_nic2user_s;
// dep->de_getblockf= dp_pio8_getblock;
// }
/* Set the interrupt handler and policy. Do not automatically
* reenable interrupts. Return the IRQ line number on interrupts.
*/
/* dep->de_hook = dep->de_irq;
r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
if (r != OK)
panic("DP8390", "sys_irqsetpolicy failed", r);
r= sys_irqenable(&dep->de_hook);
if (r != OK)
{
panic("DP8390", "unable enable interrupts", r);
}
*/
}
/*===========================================================================*
* dp_reinit *
*===========================================================================*/
static void dp_reinit(dep)
dpeth_t *dep;
{
int dp_rcr_reg;
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
dp_rcr_reg = 0;
if (dep->de_flags & DEF_PROMISC)
dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
if (dep->de_flags & DEF_BROAD)
dp_rcr_reg |= RCR_AB;
if (dep->de_flags & DEF_MULTI)
dp_rcr_reg |= RCR_AM;
outb_reg0(dep, DP_RCR, dp_rcr_reg);
}
/*===========================================================================*
* dp_reset *
*===========================================================================*/
static void dp_reset(dep)
dpeth_t *dep;
{
int i;
/* Stop chip */
outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
outb_reg0(dep, DP_RBCR0, 0);
outb_reg0(dep, DP_RBCR1, 0);
for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
; /* Do nothing */
outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST);
outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT);
outb_reg0(dep, DP_TCR, TCR_NORMAL);
/* Acknowledge the ISR_RDC (remote dma) interrupt. */
for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); i++)
; /* Do nothing */
outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~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 (i= 0; i<dep->de_sendq_nr; i++)
dep->de_sendq[i].sq_filled= 0;
dp_send(dep);
dep->de_flags &= ~DEF_STOPPED;
}
/*===========================================================================*
* dp_check_ints *
*===========================================================================*/
void dp_check_ints(dep)
dpeth_t *dep;
{
int isr, tsr;
int size, sendq_tail;
if (!(dep->de_flags & DEF_ENABLED))
panic("", "dp8390: got premature interrupt", NO_NUM);
for(;;)
{
isr = inb_reg0(dep, DP_ISR);
if (!isr)
break;
outb_reg0(dep, DP_ISR, isr);
if (isr & (ISR_PTX|ISR_TXE))
{
if (isr & ISR_TXE)
{
#if DEBUG
{ printf("%s: got send Error\n", dep
->de_name
); }
#endif
dep->de_stat.ets_sendErr++;
}
else
{
tsr = inb_reg0(dep, DP_TSR);
if (tsr & TSR_PTX) dep->de_stat.ets_packetT++;
#if 0 /* Reserved in later manuals, should be ignored */
if (!(tsr & TSR_DFR))
{
/* In most (all?) implementations of
* the dp8390, this bit is set
* when the packet is not deferred
*/
dep->de_stat.ets_transDef++;
}
#endif
if (tsr & TSR_COL) dep->de_stat.ets_collision++;
if (tsr & TSR_ABT) dep->de_stat.ets_transAb++;
if (tsr & TSR_CRS) dep->de_stat.ets_carrSense++;
if (tsr & TSR_FU
&& ++dep->de_stat.ets_fifoUnder <= 10)
{
dep->de_name);
}
if (tsr & TSR_CDH
&& ++dep->de_stat.ets_CDheartbeat <= 10)
{
printf("%s: CD heart beat failure\n",
dep->de_name);
}
if (tsr & TSR_OWC) dep->de_stat.ets_OWC++;
}
sendq_tail= dep->de_sendq_tail;
if (!(dep->de_sendq[sendq_tail].sq_filled))
{
/* Software bug? */
/* Or hardware bug? */
"%s: transmit interrupt, but not sending\n",
dep->de_name);
continue;
}
dep->de_sendq[sendq_tail].sq_filled= 0;
if (++sendq_tail == dep->de_sendq_nr)
sendq_tail= 0;
dep->de_sendq_tail= sendq_tail;
if (dep->de_sendq[sendq_tail].sq_filled)
{
size= dep->de_sendq[sendq_tail].sq_size;
outb_reg0(dep, DP_TPSR,
dep->de_sendq[sendq_tail].sq_sendpage);
outb_reg0(dep, DP_TBCR1, size >> 8);
outb_reg0(dep, DP_TBCR0, size & 0xff);
outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
}
if (dep->de_flags & DEF_SEND_AVAIL)
dp_send(dep);
}
if (isr & ISR_PRX)
{
/* Only call dp_recv if there is a read request */
if (dep->de_flags & DEF_READING)
dp_recv(dep);
}
if (isr & ISR_RXE) dep->de_stat.ets_recvErr++;
if (isr & ISR_CNT)
{
dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
}
if (isr & ISR_OVW)
{
dep->de_stat.ets_OVW++;
#if 0
"%s: got overwrite warning\n", dep->de_name); }
#endif
if (dep->de_flags & DEF_READING)
{
"dp_check_ints: strange: overwrite warning and pending read request\n");
dp_recv(dep);
}
}
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.
*/
#if 0
"%s: NIC stopped\n", dep->de_name); }
#endif
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 are
* delivered.
*/
dp_reset(dep);
}
}
/*===========================================================================*
* dp_recv *
*===========================================================================*/
static void dp_recv(dep)
dpeth_t *dep;
{
dp_rcvhdr_t header;
unsigned pageno, curr, next;
vir_bytes length;
int packet_processed, r;
u16_t eth_type;
packet_processed = FALSE;
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 | CR_EXTRA);
curr = inb_reg1(dep, DP_CURR);
outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
if (curr == pageno) break;
(dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header),
&header);
(dep->de_getblockf)(dep, pageno, sizeof(header) +
2*sizeof(ether_addr_t), sizeof(eth_type), ð_type);
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_TAGGED)
{
printf("%s: packet with strange length arrived: %d\n",
dep->de_name, (int) length);
next= curr;
}
else if (next < dep->de_startpage || next >= dep->de_stoppage)
{
printf("%s: strange next page\n", dep
->de_name
);
next= curr;
}
/* else if (eth_type == eth_ign_proto)
{
*/ /* Hack: ignore packets of a given protocol, useful
* if you share a net with 80 computers sending
* Amoeba FLIP broadcasts. (Protocol 0x8146.)
*/
/* static int first= 1;
if (first)
{
first= 0;
printf("%s: dropping proto 0x%04x packets\n",
dep->de_name,
ntohs(eth_ign_proto));
}
dep->de_stat.ets_packetR++;
}
*/ else if (header.dr_status & RSR_FO)
{
/* This is very serious, so we issue a warning and
* reset the buffers */
printf("%s: fifo overrun, resetting receive buffer\n",
dep->de_name);
dep->de_stat.ets_fifoOver++;
next = curr;
}
else if ((header.dr_status & RSR_PRX) &&
(dep->de_flags & DEF_ENABLED))
{
// if (dep->de_safecopy_read)
// r = dp_pkt2user_s(dep, pageno, length);
// else
r = dp_pkt2user(dep, pageno, length);
if (r != OK)
return;
packet_processed = TRUE;
dep->de_stat.ets_packetR++;
}
if (next == dep->de_startpage)
outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
else
outb_reg0(dep, DP_BNRY, next - 1);
pageno = next;
}
while (!packet_processed);
}
/*===========================================================================*
* dp_send *
*===========================================================================*/
static void dp_send(dep)
dpeth_t *dep;
{
/* if (!(dep->de_flags & DEF_SEND_AVAIL))
return;
dep->de_flags &= ~DEF_SEND_AVAIL;
switch(dep->de_sendmsg.m_type)
{
case DL_WRITE: do_vwrite(&dep->de_sendmsg, TRUE, FALSE); break;
case DL_WRITEV: do_vwrite(&dep->de_sendmsg, TRUE, TRUE); break;
case DL_WRITEV_S: do_vwrite_s(&dep->de_sendmsg, TRUE); break;
default:
panic("", "dp8390: wrong type", dep->de_sendmsg.m_type);
break;
}
*/
}
/*===========================================================================*
* dp_getblock *
*===========================================================================*/
static void dp_getblock(dep, page, offset, size, dst)
dpeth_t *dep;
int page;
size_t offset;
size_t size;
void *dst;
{
// int r;
offset = page * DP_PAGESIZE + offset;
memcpy(dst
, dep
->de_locmem
+ offset
, size
);
}
/*===========================================================================*
* dp_pkt2user *
*===========================================================================*/
static int dp_pkt2user(dep, page, length)
dpeth_t *dep;
int page, length;
{
int last, count;
if (!(dep->de_flags & DEF_READING))
return EGENERIC;
last = page + (length - 1) / DP_PAGESIZE;
if (last >= dep->de_stoppage)
{
count = (dep->de_stoppage - page) * DP_PAGESIZE -
sizeof(dp_rcvhdr_t);
/* Save read_iovec since we need it twice. */
dep->de_tmp_iovec = dep->de_read_iovec;
(dep->de_nic2userf)(dep, page * DP_PAGESIZE +
sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec, 0, count);
(dep->de_nic2userf)(dep, dep->de_startpage * DP_PAGESIZE,
&dep->de_read_iovec, count, length - count);
}
else
{
(dep->de_nic2userf)(dep, page * DP_PAGESIZE +
sizeof(dp_rcvhdr_t), &dep->de_read_iovec, 0, length);
}
dep->de_read_s = length;
dep->de_flags |= DEF_PACK_RECV;
dep->de_flags &= ~DEF_READING;
return OK;
}
/*===========================================================================*
* dp_nic2user *
*===========================================================================*/
static void dp_nic2user(dep, nic_addr, iovp, offset, count)
dpeth_t *dep;
int nic_addr;
iovec_dat_t *iovp;
vir_bytes offset;
vir_bytes count;
{
/* vir_bytes vir_hw, vir_user;
int bytes, i, r;
vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
i= 0;
while (count > 0)
{
if (i >= IOVEC_NR)
{
dp_next_iovec(iovp);
i= 0;
continue;
}
assert(i < iovp->iod_iovec_s);
if (offset >= iovp->iod_iovec[i].iov_size)
{
offset -= iovp->iod_iovec[i].iov_size;
i++;
continue;
}
bytes = iovp->iod_iovec[i].iov_size - offset;
if (bytes > count)
bytes = count;
r= sys_vircopy(SELF, D, vir_hw,
iovp->iod_proc_nr, D,
iovp->iod_iovec[i].iov_addr + offset, bytes);
if (r != OK)
panic("DP8390", "dp_nic2user: sys_vircopy failed", r);
count -= bytes;
vir_hw += bytes;
offset += bytes;
}
assert(count == 0);
*/
}
/*===========================================================================*
* conf_hw *
*===========================================================================*/
static void conf_hw(dep)
dpeth_t *dep;
{
// static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
// int ifnr;
// dp_conf_t *dcp;
// dep->de_mode= DEM_DISABLED; /* Superfluous */
// ifnr= dep-de_table;
// dcp= &dp_conf[ifnr];
// update_conf(dep, dcp);
// if (dep->de_mode != DEM_ENABLED)
// return;
if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep))
{
printf("%s: No ethernet card found at 0x%x\n",
dep->de_name, dep->de_base_port);
dep->de_mode= DEM_DISABLED;
return;
}
/* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000;
dep->de_mode = DEM_ENABLED;
dep->de_flags = DEF_EMPTY;
// dep->de_stat = empty_stat;
}
/*===========================================================================*
* map_hw_buffer *
*===========================================================================*/
static void map_hw_buffer(dep)
dpeth_t *dep;
{
// int r;
// size_t o, size;
// char *buf, *abuf;
if (dep->de_prog_IO)
{
//#if 0
if(debug){
"map_hw_buffer: programmed I/O, no need to map buffer\n");
}
//#endif
dep->de_locmem = (char *)-dep->de_ramsize; /* trap errors */
return;
}
// size = dep->de_ramsize + PAGE_SIZE; /* Add PAGE_SIZE for
// * alignment
// */
// buf= malloc(size);
// if (buf == NULL)
// panic(__FILE__, "map_hw_buffer: cannot malloc size", size);
// o= PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE);
// abuf= buf + o;
// printf("buf at 0x%x, abuf at 0x%x\n", buf, abuf);
// r= sys_vm_map(SELF, 1 /* map */, (vir_bytes)abuf,
// dep->de_ramsize, (phys_bytes)dep->de_linmem);
// if (r != OK)
// panic(__FILE__, "map_hw_buffer: sys_vm_map failed", r);
// dep->de_locmem = abuf;
}
/*===========================================================================*
* reply *
*===========================================================================*/
static void reply(dep, err, may_block)
dpeth_t *dep;
int err;
int may_block;
{
/* message reply;
int status;
int r;
status = 0;
if (dep->de_flags & DEF_PACK_SEND)
status |= DL_PACK_SEND;
if (dep->de_flags & DEF_PACK_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;
reply.DL_CLCK = 0; *//* Don't know */
/* r= send(dep->de_client, &reply);
if (r == ELOCKED && may_block)
{
#if 0
printf("send locked\n");
#endif
return;
}
if (r < 0)
panic("", "dp8390: send failed:", r);
dep->de_read_s = 0;
*/ dep->de_flags &= ~(DEF_PACK_SEND | DEF_PACK_RECV);
}
/*
* $PchId: dp8390.c,v 1.25 2005/02/10 17:32:07 philip Exp $
*/
/** @}
*/