319 lines
7.4 KiB
C
319 lines
7.4 KiB
C
/*
|
|
** File: dp.c Version 1.01, Oct. 17, 2007
|
|
** Original: 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.
|
|
*/
|
|
|
|
#include <minix/drivers.h>
|
|
#include <minix/netdriver.h>
|
|
#include <minix/endpoint.h>
|
|
#include <net/gen/ether.h>
|
|
#include <net/gen/eth_io.h>
|
|
#include <sys/mman.h>
|
|
#include <assert.h>
|
|
|
|
#include "dp.h"
|
|
|
|
/*
|
|
** Local data
|
|
*/
|
|
static dpeth_t de_state;
|
|
|
|
typedef struct dp_conf { /* Configuration description structure */
|
|
port_t dpc_port;
|
|
int dpc_irq;
|
|
phys_bytes dpc_mem;
|
|
} dp_conf_t;
|
|
|
|
/* Device default configuration */
|
|
#define DP_CONF_NR 3
|
|
static dp_conf_t dp_conf[DP_CONF_NR] = {
|
|
/* I/O port, IRQ, Buff addr, Env. var */
|
|
{ 0x300, 5, 0xC8000, },
|
|
{ 0x280, 10, 0xCC000, },
|
|
{ 0x000, 0, 0x00000, },
|
|
};
|
|
|
|
static int do_init(unsigned int instance, ether_addr_t *addr);
|
|
static void do_stop(void);
|
|
static void do_mode(unsigned int mode);
|
|
static int do_send(struct netdriver_data *data, size_t size);
|
|
static ssize_t do_recv(struct netdriver_data *data, size_t max);
|
|
static void do_stat(eth_stat_t *stat);
|
|
static void do_intr(unsigned int mask);
|
|
static void do_other(const message *m_ptr, int ipc_status);
|
|
|
|
static const struct netdriver dp_table = {
|
|
.ndr_init = do_init,
|
|
.ndr_stop = do_stop,
|
|
.ndr_mode = do_mode,
|
|
.ndr_recv = do_recv,
|
|
.ndr_send = do_send,
|
|
.ndr_stat = do_stat,
|
|
.ndr_intr = do_intr,
|
|
.ndr_other = do_other
|
|
};
|
|
|
|
/*
|
|
** Name: update_conf
|
|
** Function: Gets the default settings from 'dp_conf' table and
|
|
** modifies them from the environment.
|
|
*/
|
|
static void update_conf(dpeth_t * dep, const dp_conf_t * dcp,
|
|
unsigned int instance)
|
|
{
|
|
static char dpc_fmt[] = "x:d:x";
|
|
char ec_key[16];
|
|
long val;
|
|
|
|
strlcpy(ec_key, "DPETH0", sizeof(ec_key));
|
|
ec_key[5] += instance;
|
|
|
|
val = dcp->dpc_port; /* Get I/O port address */
|
|
env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
|
|
dep->de_base_port = val;
|
|
|
|
val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
|
|
env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
|
|
dep->de_irq = val;
|
|
|
|
val = dcp->dpc_mem; /* Get shared memory address */
|
|
env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
|
|
dep->de_linmem = val;
|
|
}
|
|
|
|
/*
|
|
** Name: do_dump
|
|
** Function: Displays statistics on screen (SFx key from console)
|
|
*/
|
|
static void do_dump(void)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
printf("\n\n");
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
** Name: do_first_init
|
|
** Function: Init action to setup task
|
|
*/
|
|
static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
|
|
{
|
|
|
|
dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */
|
|
|
|
/* Make sure statisics are cleared */
|
|
memset(&dep->de_stat, 0, sizeof(dep->de_stat));
|
|
|
|
/* Device specific initialization */
|
|
(*dep->de_initf)(dep);
|
|
|
|
/* Map memory if requested */
|
|
if (dep->de_linmem != 0) {
|
|
assert(dep->de_ramsize > 0);
|
|
dep->de_locmem =
|
|
vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize);
|
|
if (dep->de_locmem == MAP_FAILED)
|
|
panic("unable to map memory");
|
|
}
|
|
|
|
/* Set the interrupt handler policy. Request interrupts not to be reenabled
|
|
* automatically. Return the IRQ line number when an interrupt occurs.
|
|
*/
|
|
dep->de_hook = dep->de_irq;
|
|
if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
|
|
panic("unable to set IRQ policy");
|
|
sys_irqenable(&dep->de_hook);
|
|
}
|
|
|
|
/*
|
|
** Name: do_init
|
|
** Function: Checks for hardware presence.
|
|
** Initialize hardware and data structures.
|
|
** Return status and ethernet address.
|
|
*/
|
|
static int do_init(unsigned int instance, ether_addr_t *addr)
|
|
{
|
|
dpeth_t *dep;
|
|
dp_conf_t *dcp;
|
|
int confnr, fkeys, sfkeys;
|
|
|
|
dep = &de_state;
|
|
|
|
strlcpy(dep->de_name, "dpeth#?", sizeof(dep->de_name));
|
|
dep->de_name[4] = '0' + instance;
|
|
|
|
/* Pick a default configuration for this instance. */
|
|
confnr = MIN(instance, DP_CONF_NR-1);
|
|
|
|
dcp = &dp_conf[confnr];
|
|
|
|
update_conf(dep, dcp, instance);
|
|
|
|
if (!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);
|
|
return ENXIO;
|
|
}
|
|
|
|
do_first_init(dep, dcp);
|
|
|
|
/* Request function key for debug dumps */
|
|
fkeys = sfkeys = 0; bit_set(sfkeys, 7);
|
|
if (fkey_map(&fkeys, &sfkeys) != OK)
|
|
printf("%s: couldn't bind Shift+F7 key (%d)\n", dep->de_name, errno);
|
|
|
|
memcpy(addr, dep->de_address.ea_addr, sizeof(*addr));
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
** Name: de_mode
|
|
** Function: Sets packet receipt mode.
|
|
*/
|
|
static void do_mode(unsigned int mode)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
|
|
if (mode & NDEV_PROMISC)
|
|
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
|
|
if (mode & NDEV_MULTI)
|
|
dep->de_flags |= DEF_MULTI;
|
|
if (mode & NDEV_BROAD)
|
|
dep->de_flags |= DEF_BROAD;
|
|
(*dep->de_flagsf)(dep);
|
|
}
|
|
|
|
/*
|
|
** Name: do_send
|
|
** Function: Send a packet, if possible.
|
|
*/
|
|
static int do_send(struct netdriver_data *data, size_t size)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
return (*dep->de_sendf)(dep, data, size);
|
|
}
|
|
|
|
/*
|
|
** Name: do_recv
|
|
** Function: Receive a packet, if possible.
|
|
*/
|
|
static ssize_t do_recv(struct netdriver_data *data, size_t max)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
return (*dep->de_recvf)(dep, data, max);
|
|
}
|
|
|
|
/*
|
|
** Name: do_stat
|
|
** Function: Reports device statistics.
|
|
*/
|
|
static void do_stat(eth_stat_t *stat)
|
|
{
|
|
|
|
memcpy(stat, &de_state.de_stat, sizeof(*stat));
|
|
}
|
|
|
|
/*
|
|
** Name: do_stop
|
|
** Function: Stops network interface.
|
|
*/
|
|
static void do_stop(void)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
/* Stop device */
|
|
(dep->de_stopf)(dep);
|
|
}
|
|
|
|
/*
|
|
** Name: do_intr
|
|
** Function; Handles interrupts.
|
|
*/
|
|
static void do_intr(unsigned int __unused mask)
|
|
{
|
|
dpeth_t *dep;
|
|
|
|
dep = &de_state;
|
|
|
|
/* If device is enabled and interrupt pending */
|
|
(*dep->de_interruptf)(dep);
|
|
sys_irqenable(&dep->de_hook);
|
|
}
|
|
|
|
/*
|
|
** Name: do_other
|
|
** Function: Processes miscellaneous messages.
|
|
*/
|
|
static void do_other(const message *m_ptr, int ipc_status)
|
|
{
|
|
|
|
if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
|
|
do_dump();
|
|
}
|
|
|
|
/*
|
|
** Name: main
|
|
** Function: Main entry for dp task
|
|
*/
|
|
int main(int argc, char **argv)
|
|
{
|
|
|
|
env_setargs(argc, argv);
|
|
|
|
netdriver_task(&dp_table);
|
|
|
|
return 0;
|
|
}
|