📄 ne2000.c
字号:
/***************************************************************************
*
* 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 + -