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

📄 ne2000.c

📁 VRTX 商用嵌入式实时操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************
*
*		Copyright (c) 1994 MICROTEC RESEARCH INCORPORATED.
*
*	All rights reserved. MICROTEC RESEARCH's source code is an unpublished
*	work and the use of a copyright notice does not imply otherwise.
*	This source code contains confidential, trade secret material of
*	MICROTEC RESEARCH. Any attempt or participation in deciphering,
*	decoding, reverse engineering or in any way altering the source code
*	is strictly prohibited, unless the prior written consent of
*	MICROTEC RESEARCH is obtained.
*
*
*	Module Name:		%M%
*
*	Identification:		%Z% %I% %M%
*
*	Date:			%G%  %U%
*
****************************************************************************
*/


/*
** ne2000.c
**
**    vi/ex options: set tabstop=4 shiftwidth=4
**
**    Ethernet Revision Level:   1
**    Device Driver:             NE2000
**
**    This file contains board independant functions to support
**    the NE2000 plus ethernet controller.
**
**    All register read/write operations are performed through
**    READ/WRITE macros that can call a board specific function.
**
**    Board specific interrupt controllers are supported through
**    the use of the INTERRUPT_START/END macros and the
**    BOARD_SPEC_INT_ENABLE/DISABLE macros.
**
** History:
**
**    Date        Name              Description
**    ---------------------------------------------------------------------- 
**    08-18-94    Microtec Research   modified for ne2000
**    09-01-94    Siprian Rodgirues,MRI Initial working version
**
** References:
**  The National Semiconductor DP83905 AT/LANTIC Databook.
**  Novell's NE2000plus Theory of Operation.  
**/

#include "ansiprot.h"      /* ANSI prototypes */
#include "logio.h"         /* logio defines and typedefs */
#include "vbsp_cbi.h"      /* VBSP control block typedef */
#include "vbsp.h"          /* VBSP return codes and typedefs */
#include "vbuf.h"
#include "ne2000.h"         /* ne2000 defines and typedefs */

struct device		nedev[1];
struct ei_device	eidev[1];

/* EI_DEBUG: use 0 for production, 1 for verification, >2 for debug */


unsigned char SA_prom[32];

/*
 * Physical Layer Interface - used in configuration register B
 * (according to Novell Theory of Operation document)
 *
 * (define's not used because not certain these values are correct!)
 *
 *  0 - twisted-pair 10BaseT
 *  1 - thick ethernet 10Base5
 *  2 - thin ethernet 10Base2
 *  3 - twisted-pair StarLAN-10
 */

/*************************************************************************
**
** ne2000_install
**
** Input/Output:
**
**    dev        A pointer to a caller-allocated  section  of
**               memory   of   size  sizeof(vbsp_dev_desc_t).
**               ne2000_init returns a device  descriptor  at
**               this location.
**
** Return codes:
**
**           VBSP_SUCCESS    The call succeeded
**           VBSP_FAILURE    The call failed
**
** Side-effects:
** Global variables: 
**
*/
vbsp_return_t
ne2000_install(ne2000_config_t *cfg, ether_1_dev_desc_t *dev)
{
	int n = 0;	/* pick the first and only NE2000 */
	struct device *ne = &nedev[n];

	ENTRY("ne2000_install");

	/*
	** Hand-craft a device structure (a.k.a "nedev").
	*/
	ne->base_addr   = cfg->base_addr;	/* device I/O address */
	ne->irq         = cfg->irq;		/* device irq address */
	ne->cable_type	 = cfg->cable_type;
	ne->in_intr   = 0;		/* in interrupt routine boolean */
	ne->start       = 0;		/* device is open */
	ne->tbusy       = 0;		/* transmitter is busy boolean */
	ne->priv        = (void *)&eidev[n]; /* struct ei_device *ei_local */
	/*  ne->dev_addr ... */         /*  this is set up in neprobe ... */
	ne->name        = "generic NE2000";
	ne->shadow_int_flags = 0;
   
	/* linked to the additional RAM space for this device */
	dev->config = cfg->base_config;
	dev->config.specific = (void *)ne; /* &nedev saved here */

	/* register map - not used */
	dev->map = (void *)((unsigned int)ne->base_addr);

	/* initialize the external board function fops entry */
	dev->externio = cfg->externio;

	dev->config.interface_revision_level = ETHER_1_INTERFACE;

	/* initalize the device specific fops entries */
	dev->fops.init             = ne2000_init;
	dev->fops.int_info_set     = ne2000_int_info_set;
	dev->fops.int_info_get     = ne2000_int_info_get;
	dev->fops.pkt_recv         = ne2000_recv; 
	dev->fops.pkt_send         = ne2000_send;
	dev->fops.ether_rx_tst     = ne2000_rxtst;
	dev->fops.ether_tx_tst     = 0;
	dev->fops.ether_err_tst    = 0;
	dev->fops.ether_init_tst   = 0;
	dev->fops.get_ether_address = ne2000_get_ethaddr;

	EXIT("ne2000_install");
	return (VBSP_SUCCESS);
}

/*******************************
* ether_1_config_t interfaces
*******************************/

void
ne2000_get_ether_address(unsigned char *addr)
{
	int i;

	ENTRY("ne2000_get_ether_address");
	for (i = 0; i < 6; i++)
		addr[i] = nedev[0].dev_addr[i];
	EXIT("ne2000_get_ether_address");
}

/*
 * set_ether_address() -- NOT TESTED!
 */
void
ne2000_set_ether_address(unsigned char *addr)
{
	int i;
    int e8390_base = nedev[0].base_addr;

	ENTRY("ne2000_set_ether_address");
    /*
	 * Copy the ethernet address into the DS8390 registers and the
	 * device struct.
	 */
    OUTB(e8390_base, E8390_NODMA + E8390_PAGE1 + E8390_STOP); /* page 1 */
    for(i = 0; i < 6; i++) {
		nedev[0].dev_addr[i] = addr[i];
		OUTB(e8390_base + EN1_PHYS + i, addr[i]);
    }
    OUTB(e8390_base, E8390_NODMA + E8390_PAGE0 + E8390_STOP); /* page 0 */
	EXIT("ne2000_set_ether_address");
}

/*******************************
* ether_1_fops_t interfaces
*******************************/
vbsp_return_t
ne2000_get_ethaddr(unsigned char *addr)
{
	int i;

	ENTRY("ne2000_get_ethaddr");
	for (i = 0; i < 6; i++)
		addr[i] = nedev[0].dev_addr[i];
	EXIT("ne2000_get_ethaddr");
	return VBSP_SUCCESS;
}

/*************************************************************************
**
** ne2000_init
**
**    This function initializes an instance of an ne2000
**    Ethernet controller. The initialization sequence may
**    configure:
**
**           a.   The number of send/receive buffers
**           b.   The interrupt vector
**           c.   Ethernet address
**
**    and then initializes the DP83905.
**
**    This function requires a  device descriptor.  Any  function
**    that needs to access the device must use the descriptor
**    returned by ne2000_init.
** 
** Input/Output:
**
**    dev        an ethernet device descriptor
**
** Return codes:
**
**           VBSP_SUCCESS    The call succeeded
**           VBSP_FAILURE    The call failed
**
** Side-effects:
** Global variables: 
**
*/
vbsp_return_t
ne2000_init(ether_1_dev_desc_t *dev)
{
	struct device *ne = (struct device *)dev->config.specific;
	struct ei_device *ei_local = (struct ei_device *)ne->priv;
	logio_int_entry_t logio_int;

	ENTRY("ne2000_init");
	IFDEBUG( printf("\tdev=%x ne=%x base_addr=%x irq=%x\n",
		dev, ne, ne->base_addr, ne->irq); )

#ifdef NO_PINGPONG
	ei_local->pingpong = 0;
#else /* PINGPONG */
	ei_local->pingpong = 1;
#endif /* PINGPONG */

	/* this will disable interrupts from the ne2000 */
	logio_int.flags = LOGIO_INT_DISABLED;
	(dev->fops.int_info_set)(dev,&logio_int);
 
	if (ne_probe(ne) != 0) {
		return VBSP_FAILURE;
	}

	EXIT2("ne2000_init", 0);
	return VBSP_SUCCESS;
}

/*************************************************************************
**
** ne2000_recv
**
**   This function gets the next available packet from an ne2000.
**
** Return codes:
**
**    VBSP_SUCCESS         The call succeeded
**    VBSP_INVALID_DEV_ID  The ID is invalid 
**    VBSP_FAILURE         The call failed 
**    VBSP_NO_PACKET       No packets are available
**
*/
vbsp_return_t
ne2000_recv(ether_1_dev_desc_t *dev, logio_buff_t **list)
{
	vbsp_return_t rv;
	struct device *ne = (struct device *)dev->config.specific;
	vbuf_t *bptr;

	/*
	 * Remove any packets from the board.
	 *
	 * XXX - someday: only check if not in interrupt mode
	 */
#if 0
	(void)ei_receive(ne);
#endif

	/*
	 * Try to get a buffer from the RX queue.
	 */
	bptr = ne->rx_head;
	if (bptr) {
		ENTRY("ne2000_recv");
		ne->rx_head = vbuf_get_nextpkt(bptr);
		vbuf_set_nextpkt(bptr, (vbuf_t *)0);
		*list = bptr;
		rv = VBSP_SUCCESS;
		EXIT2("ne2000_recv", rv);
#ifdef RWS /* debug */
		{
			static int n;
			if ((++n & 0xf) == 0)
				printf("<");
		}
#endif
	} else {
		rv = VBSP_NO_PACKET;
	}

	return rv;
}

/*************************************************************************
**
** ne2000_send 
**
**    This function sends the packet to an ne2000.
**
** Inputs:
**
**      dev           An ID returned by a call to ne2000_init
**      list            A pointer to a buffer
**
** Outputs:
**
** Return codes:
**
**    VBSP_SUCCESS         The call succeeded
**    VBSP_INVALID_DEV_ID  The ID is invalid
**    VBSP_FAILURE         The call failed
*/
vbsp_return_t
ne2000_send(ether_1_dev_desc_t *dev, logio_buff_t *list)
{
	vbsp_return_t rv = VBSP_SUCCESS;
	struct device *ne = (struct device *)dev->config.specific;
	int e8390_base = ne->base_addr;
	int len;
#ifdef RWS
	static int consecutive;
#endif

	ENTRY("ne2000_send");

	len = vbuf_get_msgcnt(list);
	{
		vbuf_t *bptr = list;
		while (bptr = vbuf_get_nextbuf(bptr))
			len += vbuf_get_msgcnt(bptr);
	}

	/*
	 * Make sure length is reasonable.
	 */
	if (len < 14 || len > LAN_MAX_SIZE) {
		/* XXX - do we need to free packet here??? */ /* NO: SK */
		return( VBSP_FAILURE);
	} else if (len < LAN_MIN_SIZE) {
		/*
		 * If packet size is too short, bump up first block by the amount
		 * that we're short.
		 */
		vbuf_set_msgcnt(list, (vbuf_get_msgcnt(list) + LAN_MIN_SIZE - len));
		len = LAN_MIN_SIZE;
	}
    
	/*
	 * Link packet to end of TX queue.
	 */
	if (ne->tx_head) {
		vbuf_set_nextpkt(ne->tx_tail, list);
	} else {
		ne->tx_head = list;
	}
	ne->tx_tail = list;

	/*
	 * If TX not busy, kick it off -- else if TX interrupt pending, 
	 * run TX interrupt processing (which kicks off next TX).
	 */
	if (!ne->tbusy) {
		(void)ei_start_xmit(ne);
#ifdef RWS /* debugging */
		consecutive = 0;
#endif
	} else if (INPB(e8390_base + EN0_ISR) & (ENISR_TX | ENISR_TX_ERR)) {
		ei_tx_intr(ne);
#ifdef RWS /* debugging */
		consecutive = 0;
#endif
#ifdef RWS /* debugging */
	} else {
		int cr;
		int isr;
		cr = INPB(e8390_base); /* command register */
		isr = INPB(e8390_base + EN0_ISR); /* interrupt status register */
		if (!(cr & E8390_TRANS) && !(isr & (ENISR_TX | ENISR_TX_ERR)))
			printf("ne2000_send: HUNG??? cmdreg=%x isr=%x\n", cr, isr);
		if (++consecutive > 10)
			printf("ne2000_send: BUSY??? cmdreg=%x isr=%x\n", cr, isr);
#endif
	}

done:
	EXIT2("ne2000_send", rv);
	return rv;
}


void
update_stats(struct device *ne)
{
	int e8390_base = ne->base_addr;
	struct ei_device *ei_local = (struct ei_device *) ne->priv;

	ei_local->stat.rx_frame_errors += INPB(e8390_base + EN0_COUNTER0);
	ei_local->stat.rx_crc_errors   += INPB(e8390_base + EN0_COUNTER1);
	ei_local->stat.rx_missed_errors+= INPB(e8390_base + EN0_COUNTER2);
}

/*************************************************************************
**
**  ne2000_rxtst
**
**    This function is called by the logio_default_int_handler in 
**    order to determine whether or not a packet was received. 
**    This function will process the interrupt and return 1 only
**    if the cause of the interrupt was a receive packet event.
**
** Return codes:
**
**    1: ETHER_1 received a packet
**    0: ETHER_1 didn't receive a packet
*/
int
ne2000_rxtst(logio_interrupt_entry_t *entry)
{
	ether_1_dev_desc_t *dev = (ether_1_dev_desc_t *)entry->id->data;
	struct device *ne = (struct device *)dev->config.specific;
	int e8390_base = ne->base_addr;

⌨️ 快捷键说明

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