📄 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_PORT DL_PROC DL_COUNT DL_STAT DL_CLCK * |-------------+----------+---------+----------+---------+---------| * |DL_TASK_REPLY| port nr | proc nr | rd-count | err|stat| clock | * |-------------+----------+---------+----------+---------+---------| * * m_type m3_i1 m3_i2 m3_ca1 * |-------------+---------+-----------+---------------| * |DL_INIT_REPLY| port nr | last port | ethernet addr | * |-------------+---------+-----------+---------------| * * 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 "../drivers.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"#include "local.h"#include "dp8390.h"#define DE_PORT_NR 3static dpeth_t de_table[DE_PORT_NR];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_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_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 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 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) );_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) );/*===========================================================================* * dpeth_task * *===========================================================================*/int main(int argc, char *argv[]){ message m; int i, irq, r, tasknr; dpeth_t *dep; long v; if (argc < 1) { panic("DP8390", "A head which at this time has no name", NO_NUM); } (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]); env_setargs(argc, argv); for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++) { strcpy(dep->de_name, "dp8390#0"); dep->de_name[7] += i; } v= 0; (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL); eth_ign_proto= htons((u16_t) v); /* Try to notify inet that we are present (again) */ r = findproc("inet", &tasknr); if (r == OK) notify(tasknr); while (TRUE) { if ((r= receive(ANY, &m)) != OK) panic("", "dp8390: receive failed", r); switch (m.m_type) { case DEV_PING: notify(m.m_source); continue; 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_GETNAME: do_getname(&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 (dep->de_int_pending || 1) { dep->de_int_pending= 0; dp_check_ints(dep); do_int(dep); r= sys_irqenable(&dep->de_hook); if (r != OK) { panic("DP8390", "unable enable interrupts", r); } } } break; case SYS_SIG: { sigset_t sigset = m.NOTIFY_ARG; if (sigismember(&sigset, SIGKSTOP)) dp8390_stop(); break; } case SYN_ALARM: printf("dp8390: strange, got SYN_ALARM\n"); break; default: panic("", "dp8390: illegal message", m.m_type); } }}#if 0/*===========================================================================* * dp8390_dump * *===========================================================================*/void dp8390_dump(){ dpeth_t *dep; int i, isr; printf("\n"); for (i= 0, dep = &de_table[0]; i<DE_PORT_NR; i++, dep++) {#if XXX 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);#endif 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); }}#endif/*===========================================================================* * dp8390_stop * *===========================================================================*/static 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); }}#if ENABLE_PCI/*===========================================================================* * pci_conf * *===========================================================================*/static void pci_conf(){ int i, h; char *envvar; struct dpeth *dep; static char envfmt[] = "*:d.d.d"; long v; static int first_time= 1; if (!first_time) return; first_time= 0; for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++) { envvar= dp_conf[i].dpc_envvar; if (!(dep->de_pci= env_prefix(envvar, "pci"))) continue; /* no PCI config */ v= 0; (void) env_parse(envvar, envfmt, 1, &v, 0, 255); dep->de_pcibus= v; v= 0; (void) env_parse(envvar, envfmt, 2, &v, 0, 255); dep->de_pcidev= v; v= 0; (void) env_parse(envvar, envfmt, 3, &v, 0, 255); dep->de_pcifunc= v; } for (h= 1; h >= 0; h--) { for (i= 0, dep= de_table; i<DE_PORT_NR; i++, dep++) { if (!dep->de_pci) continue; if (((dep->de_pcibus | dep->de_pcidev | dep->de_pcifunc) != 0) != h) { continue; } if (!rtl_probe(dep)) dep->de_pci= -1; } }}#endif /* ENABLE_PCI *//*===========================================================================* * 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_TAGGED) { 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 | CR_EXTRA);/* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -