⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3c501.c

📁 Minix3.11的源码。[MINIX 3是一个为高可靠性应用而设计的自由且简洁的类UNIX系统。]
💻 C
字号:
/***  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.****  $Id: 3c501.c,v 1.3 2005/08/05 19:08:43 beng Exp $*/#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_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_3C501 *//** 3c501.c **/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -