📄 dp8390.c
字号:
/*
* dp8390.c
*
* This file contains a ethernet device driver for NS dp8390 based ethernet
* cards.
*
* The valid messages and their parameters are:
*
* m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
* |------------+----------+---------+----------+---------+---------|
* | HARDINT | | | | | |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITE | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_WRITEV | port nr | proc nr | count | mode | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READ | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_READV | port nr | proc nr | count | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_INIT | port nr | proc nr | mode | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_GETSTAT | port nr | proc nr | | | address |
* |------------|----------|---------|----------|---------|---------|
* | DL_STOP | port_nr | | | | |
* |------------|----------|---------|----------|---------|---------|
*
* The messages sent are:
*
* m-type DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
* |------------|----------|---------|----------|---------|---------|
* |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
* |------------|----------|---------|----------|---------|---------|
*
* m_type m3_i1 m3_i2 m3_ca1
* |------------+---------+-----------+---------------|
* |DL_INIT_REPL| port nr | last port | ethernet addr |
* |------------|---------|-----------|---------------|
*
* Created: before Dec 28, 1992 by Philip Homburg <philip@cs.vu.nl>
*
* Modified to become a generic dp8390 driver.
* March 10, 1994, Philip Homburg
*/
#include "kernel.h"
#include <stdlib.h>
#include <minix/com.h>
#include <net/hton.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include "assert.h"
INIT_ASSERT
#include "protect.h"
#include "dp8390.h"
#include "proc.h"
#if ENABLE_NETWORKING
#if !__minix_vmd
#define printW() (void) 0
#define debug 0
#endif
#define DE_PORT_NR 2
static dpeth_t de_table[DE_PORT_NR];
static int int_pending[NR_IRQ_VECTORS];
static int dpeth_tasknr= ANY;
static u16_t eth_ign_proto;
/* Configuration */
typedef struct dp_conf
{
port_t dpc_port;
int dpc_irq;
phys_bytes dpc_mem;
char *dpc_envvar;
segm_t dpc_prot_sel;
} dp_conf_t;
dp_conf_t dp_conf[]= /* Card addresses */
{
/* I/O port, IRQ, Buffer address, Env. var, Buf selector. */
{ 0x280, 3, 0xD0000, "DPETH0", DP_ETH0_SELECTOR },
{ 0x300, 5, 0xCC000, "DPETH1", DP_ETH1_SELECTOR },
};
/* 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];
_PROTOTYPE( static void do_vwrite, (message *mp, int from_int,
int vectored) );
_PROTOTYPE( static void do_vread, (message *mp, int vectored) );
_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_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 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 void dp_user2nic, (dpeth_t *dep, iovec_dat_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_pio16_user2nic, (dpeth_t *dep,
iovec_dat_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_pio8_nic2user, (dpeth_t *dep, int nic_addr,
iovec_dat_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_next_iovec, (iovec_dat_t *iovp) );
_PROTOTYPE( static int dp_handler, (int irq) );
_PROTOTYPE( static void conf_hw, (dpeth_t *dep) );
_PROTOTYPE( static void update_conf, (dpeth_t *dep, dp_conf_t *dcp) );
_PROTOTYPE( static int calc_iovec_size, (iovec_dat_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 put_userdata, (int user_proc,
vir_bytes user_addr, vir_bytes count, void *loc_addr) );
/*===========================================================================*
* dpeth_task *
*===========================================================================*/
void dp8390_task()
{
message m;
int i, irq, r;
dpeth_t *dep;
long v;
dpeth_tasknr= proc_number(proc_ptr);
v= 0xFFFF;
(void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
eth_ign_proto= htons((u16_t) v);
while (TRUE)
{
if ((r= receive(ANY, &m)) != OK)
panic("dp8390: receive failed", r);
switch (m.m_type)
{
case DL_WRITE: do_vwrite(&m, FALSE, FALSE); break;
case DL_WRITEV: do_vwrite(&m, FALSE, TRUE); break;
case DL_READ: do_vread(&m, FALSE); break;
case DL_READV: do_vread(&m, TRUE); break;
case DL_INIT: do_init(&m); break;
case DL_GETSTAT: do_getstat(&m); break;
case DL_STOP: do_stop(&m); break;
case HARD_INT:
for (i= 0, dep= &de_table[0]; i<DE_PORT_NR; i++, dep++)
{
if (dep->de_mode != DEM_ENABLED)
continue;
assert(dep->de_flags & DEF_ENABLED);
irq= dep->de_irq;
assert(irq >= 0 && irq < NR_IRQ_VECTORS);
if (int_pending[irq])
{
int_pending[irq]= 0;
dp_check_ints(dep);
do_int(dep);
}
}
break;
default:
panic("dp8390: illegal message", m.m_type);
}
}
}
/*===========================================================================*
* dp_dump *
*===========================================================================*/
void dp_dump()
{
dpeth_t *dep;
int i, isr;
printf("\n");
for (i= 0, dep = &de_table[0]; i<DE_PORT_NR; i++, dep++)
{
if (dep->de_mode == DEM_DISABLED)
printf("dp8390 port %d is disabled\n", i);
else if (dep->de_mode == DEM_SINK)
printf("dp8390 port %d is in sink mode\n", i);
if (dep->de_mode != DEM_ENABLED)
continue;
printf("dp8390 statistics of port %d:\n", i);
printf("recvErr :%8ld\t", dep->de_stat.ets_recvErr);
printf("sendErr :%8ld\t", dep->de_stat.ets_sendErr);
printf("OVW :%8ld\n", dep->de_stat.ets_OVW);
printf("CRCerr :%8ld\t", dep->de_stat.ets_CRCerr);
printf("frameAll :%8ld\t", dep->de_stat.ets_frameAll);
printf("missedP :%8ld\n", dep->de_stat.ets_missedP);
printf("packetR :%8ld\t", dep->de_stat.ets_packetR);
printf("packetT :%8ld\t", dep->de_stat.ets_packetT);
printf("transDef :%8ld\n", dep->de_stat.ets_transDef);
printf("collision :%8ld\t", dep->de_stat.ets_collision);
printf("transAb :%8ld\t", dep->de_stat.ets_transAb);
printf("carrSense :%8ld\n", dep->de_stat.ets_carrSense);
printf("fifoUnder :%8ld\t", dep->de_stat.ets_fifoUnder);
printf("fifoOver :%8ld\t", dep->de_stat.ets_fifoOver);
printf("CDheartbeat:%8ld\n", dep->de_stat.ets_CDheartbeat);
printf("OWC :%8ld\t", dep->de_stat.ets_OWC);
isr= inb_reg0(dep, DP_ISR);
printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr,
inb_reg0(dep, DP_ISR), dep->de_flags);
}
}
/*===========================================================================*
* dp8390_stop *
*===========================================================================*/
void dp8390_stop()
{
message mess;
int i;
for (i= 0; i<DE_PORT_NR; i++)
{
if (de_table[i].de_mode != DEM_ENABLED)
continue;
mess.m_type= DL_STOP;
mess.DL_PORT= i;
do_stop(&mess);
}
}
/*===========================================================================*
* do_vwrite *
*===========================================================================*/
static void do_vwrite(mp, from_int, vectored)
message *mp;
int from_int;
int vectored;
{
int port, count, size;
int sendq_head;
dpeth_t *dep;
port = mp->DL_PORT;
count = mp->DL_COUNT;
if (port < 0 || port >= DE_PORT_NR)
panic("dp8390: illegal port", port);
dep= &de_table[port];
dep->de_client= mp->DL_PROC;
if (dep->de_mode == DEM_SINK)
{
assert(!from_int);
dep->de_flags |= DEF_PACK_SEND;
reply(dep, OK, FALSE);
return;
}
assert(dep->de_mode == DEM_ENABLED);
assert(dep->de_flags & DEF_ENABLED);
if (dep->de_flags & DEF_SEND_AVAIL)
panic("dp8390: send already in progress", NO_NUM);
sendq_head= dep->de_sendq_head;
if (dep->de_sendq[sendq_head].sq_filled)
{
if (from_int)
panic("dp8390: should not be sending\n", NO_NUM);
dep->de_sendmsg= *mp;
dep->de_flags |= DEF_SEND_AVAIL;
reply(dep, OK, FALSE);
return;
}
assert(!(dep->de_flags & DEF_PACK_SEND));
if (vectored)
{
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_t), dep->de_write_iovec.iod_iovec);
dep->de_write_iovec.iod_iovec_s = count;
dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
dep->de_tmp_iovec = dep->de_write_iovec;
size = calc_iovec_size(&dep->de_tmp_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 =
mp->DL_COUNT;
dep->de_write_iovec.iod_iovec_s = 1;
dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
dep->de_write_iovec.iod_iovec_addr = 0;
size= mp->DL_COUNT;
}
if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
{
panic("dp8390: invalid packet size", size);
}
(dep->de_user2nicf)(dep, &dep->de_write_iovec, 0,
dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE,
size);
dep->de_sendq[sendq_head].sq_filled= TRUE;
if (dep->de_sendq_tail == sendq_head)
{
outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
outb_reg0(dep, DP_TBCR1, size >> 8);
outb_reg0(dep, DP_TBCR0, size & 0xff);
outb_reg0(dep, DP_CR, CR_TXP); /* there it goes.. */
}
else
dep->de_sendq[sendq_head].sq_size= size;
if (++sendq_head == dep->de_sendq_nr)
sendq_head= 0;
assert(sendq_head < SENDQ_NR);
dep->de_sendq_head= sendq_head;
dep->de_flags |= DEF_PACK_SEND;
/* If the interrupt handler called, don't send a reply. The reply
* will be sent after all interrupts are handled.
*/
if (from_int)
return;
reply(dep, OK, FALSE);
assert(dep->de_mode == DEM_ENABLED);
assert(dep->de_flags & DEF_ENABLED);
}
/*===========================================================================*
* do_vread *
*===========================================================================*/
static void do_vread(mp, vectored)
message *mp;
int vectored;
{
int port, count;
int size;
dpeth_t *dep;
port = mp->DL_PORT;
count = mp->DL_COUNT;
if (port < 0 || port >= DE_PORT_NR)
panic("dp8390: illegal port", port);
dep= &de_table[port];
dep->de_client= mp->DL_PROC;
if (dep->de_mode == DEM_SINK)
{
reply(dep, OK, FALSE);
return;
}
assert(dep->de_mode == DEM_ENABLED);
assert(dep->de_flags & DEF_ENABLED);
if(dep->de_flags & DEF_READING)
panic("dp8390: read already in progress", NO_NUM);
if (vectored)
{
get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
(count > IOVEC_NR ? IOVEC_NR : count) *
sizeof(iovec_t), dep->de_read_iovec.iod_iovec);
dep->de_read_iovec.iod_iovec_s = count;
dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
dep->de_tmp_iovec = dep->de_read_iovec;
size= calc_iovec_size(&dep->de_tmp_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 =
mp->DL_COUNT;
dep->de_read_iovec.iod_iovec_s = 1;
dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
dep->de_read_iovec.iod_iovec_addr = 0;
size= count;
}
if (size < ETH_MAX_PACK_SIZE)
panic("dp8390: wrong packet size", size);
dep->de_flags |= DEF_READING;
dp_recv(dep);
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);
}
reply(dep, OK, FALSE);
}
/*===========================================================================*
* do_init *
*===========================================================================*/
static void do_init(mp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -