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

📄 ne2000.c

📁 VRTX 商用嵌入式实时操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
					 * the board; advance pointers and count.
					 * (The normal case should not go here.)
					 */
					ne_block_input(dev, VBUFMAX, vbuf_get_dataptr(bptr),
								   current_offset);
					vbuf_set_msgcnt(bptr, VBUFMAX);
					pkt_len -= VBUFMAX;
					if ((current_offset += VBUFMAX) > (num_rx_pages << 8))
						current_offset -= (num_rx_pages << 8);
					bptr = vbuf_get_nextbuf(bptr);
				}
#endif /* VBUFMAX < 1600 */
				/*
				 * Copy the rest of the packet in from the board.
				 */
				ne_block_input(dev, pkt_len, vbuf_get_dataptr(bptr),
							   current_offset);
				vbuf_set_msgcnt(bptr, pkt_len);

#if EI_DEBUG > 1 /* DEBUG - display the packet just received. */
				dump(vbuf_get_dataptr(bptr), pkt_len);
#endif /* DEBUG */

				/*
				 * Link received packet to end of RX queue.
				 */
				if (dev->rx_head) {
					vbuf_set_nextpkt(dev->rx_tail, new_bufs);
				} else {
					dev->rx_head = new_bufs;
				}
				dev->rx_tail = new_bufs;

				ei_local->stat.rx_packets++;
			} else {	/* logio_get_free_list() failed */
#if EI_DEBUG > 0
					printf("rcv: alloc %d failed.\n", pkt_len);
#endif
				ei_local->stat.rx_dropped++;
				rv = VBSP_INSUFFICIENT_MBUFS;
			}
		} else {
			int errs = rx_frame.status;
			#if EI_DEBUG > 0
			printf("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
				   dev->name, rx_frame.status, rx_frame.next,
				   rx_frame.count);
			#endif
			if (errs & ENRSR_FO)
				ei_local->stat.rx_fifo_errors++;
		}
		next_frame = rx_frame.next;
		
		/* This _should_ never happen: it's here for avoiding bad clones. */
		if (next_frame >= ei_local->stop_page) {
			printf("%s: next frame inconsistency, %#2x..", dev->name,
				   next_frame);
			next_frame = ei_local->rx_start_page;
		}
		ei_local->current_page = next_frame;
		if (next_frame > ei_local->rx_start_page)
			OUTB(e8390_base+EN0_BOUNDARY, next_frame-1);
		else
			OUTB(e8390_base+EN0_BOUNDARY, ei_local->stop_page-1);
	} /* end for (;;) */

#ifdef RWS /* debug */
	if (dummy > most) {
		printf("\nrcv: %d packets dequeued\n", dummy);
		most = dummy;
	}
#endif
    return rv;
}


#if 0
#ifndef DELAY	/* XXX */
void
DELAY(int n)  /* delay n microseconds */
{
	int i;

	while (n-- > 0)
		for (i = 6; i > 0; i--) ;
}
#endif /* !defined DELAY */
#endif

/*
 * void
 * ei_rx_overrun(struct device *dev)
 *
 * Buffer Ring Overflow handling as specified in the NS8390
 * document.
 */
void
ei_rx_overrun(struct device *dev)
{
    int e8390_base = dev->base_addr;
    struct ei_device *ei_local = (struct ei_device *) dev->priv;
	int txp;
	int resend = 0;

	ENTRY("ei_rx_overrun");

	/* 1. Save TRANSMIT PACKET bit of Command register */
    txp = INPB(e8390_base+E8390_CMD) & E8390_TRANS;

	/* 2. Issue STOP command */
    OUTB(e8390_base+E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_STOP);
    
#if EI_DEBUG > 0
	printf("%s: Receiver overrun.\n", dev->name);
#endif
    ei_local->stat.rx_over_errors++;

	/* 3. Wait at least 1.6 ms */
#if 0
	DELAY(1600); /* XXX */
#else
	wait_on_system_timer (1600000, 0, 0);
#endif

	/* 4. Clear the Remote Byte Count registers */
	OUTB(e8390_base+EN0_RCNTLO, 0);
	OUTB(e8390_base+EN0_RCNTHI, 0);

	/* 5. Determine if there was a tx in progress */
	if (txp && !(INPB(e8390_base+EN0_ISR) & (ENISR_TX | ENISR_TX_ERR)))
		resend = 1;

	/* 6. Place controller in loopback mode */
	OUTB(e8390_base+EN0_TXCR, E8390_TXOFF);

	/* 7. Issue START command */
	OUTB(e8390_base+E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START);

	/* 8. Remove one or more packets from the RX buffer ring */
	(void)ei_receive(dev);

	/* 9. Reset the OVERFLOW bit in the ISR */
    OUTB(e8390_base+EN0_ISR, ENISR_OVER);

	/* 10. Place the controller back in normal transmit mode */
    OUTB(e8390_base+EN0_TXCR, E8390_TXCONFIG);

	/* 11. If "resend" is set, reissue the transmit command */
	if (resend)
		{
		OUTB(e8390_base+E8390_CMD,
			E8390_NODMA+E8390_PAGE0+E8390_TRANS+E8390_START);
		OUTB(e8390_base+EN0_ISR, (ENISR_TX | ENISR_TX_ERR));
		}
	else
		dev->tbusy = 0;

	EXIT("ei_rx_overrun");
}

#ifdef HAVE_MULTICAST /* not tested */
/* Set or clear the multicast filter for this adaptor.
   num_addrs == -1	Promiscuous mode, receive all packets
   num_addrs == 0	Normal mode, clear multicast list
   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
   .   				best-effort filtering.
   */
void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
    short ioaddr = dev->base_addr;
    
    if (num_addrs > 0) {
		/* The multicast-accept list is initialized to accept-all, and we
		   rely on higher-level filtering for now. */
		OUTB(ioaddr + EN0_RXCR, E8390_RXCONFIG | 0x08);
    } else if (num_addrs < 0)
		OUTB(ioaddr + EN0_RXCR, E8390_RXCONFIG | 0x10);
    else
		OUTB(ioaddr + EN0_RXCR, E8390_RXCONFIG);
}
#endif /* HAVE_MULTICAST */


/*
 * Physical Layer Interface (used in configuration register B)
 *  0 - twisted-pair 10BaseT
 *  1 - thick ethernet 10Base5
 *  2 - thin ethernet 10Base2
 *  3 - twisted-pair StarLAN-10
 */

/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
void NS8390_init(struct device *dev, int startp)
{
    int e8390_base = dev->base_addr;
    struct ei_device *ei_local = (struct ei_device *) dev->priv;
    int i, tmp;
    int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
    
    /* Follow National Semi's recommendations for initing the DP83902. */
    OUTB(e8390_base, E8390_NODMA+E8390_PAGE0+E8390_STOP); /* 0x21 */
    OUTB(e8390_base + EN0_DCFG, endcfg);	/* 0x48 or 0x49 */
    /* Clear the remote byte count registers. */
    OUTB(e8390_base + EN0_RCNTLO, 0x00);
    OUTB(e8390_base + EN0_RCNTHI, 0x00);
    /* Set to monitor and loopback mode -- this is vital!. */
    OUTB(e8390_base + EN0_RXCR, E8390_RXOFF); /* 0x20 */
    OUTB(e8390_base + EN0_TXCR, E8390_TXOFF); /* 0x02 */
    /* Set the transmit page and receive ring. */
    OUTB(e8390_base + EN0_TPSR,       ei_local->tx_start_page);
    ei_local->tx1 = ei_local->tx2 = 0;
    OUTB(e8390_base + EN0_STARTPG,    ei_local->rx_start_page);
    OUTB(e8390_base + EN0_BOUNDARY, ei_local->stop_page-1); /* 3c503 says 0x3f,NS0x26*/
    ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
    OUTB(e8390_base + EN0_STOPPG, ei_local->stop_page);
    /* Clear the pending interrupts and mask. */
    OUTB(e8390_base + EN0_ISR, 0xFF);
    OUTB(e8390_base + EN0_IMR, 0x00);
    
    /* Copy the station address into the DS8390 registers,
       and set the multicast hash bitmap to receive all multicasts. */
    OUTB(e8390_base, E8390_NODMA + E8390_PAGE1 + E8390_STOP); /* 0x61 */
    for(i = 0; i < 6; i++) {
		OUTB(e8390_base + EN1_PHYS + i, dev->dev_addr[i]);
    }
    /* Initialize the multicast list to accept-all.  If we enable multicast
       the higher levels can do the filtering. */
    for(i = 0; i < 8; i++)
		OUTB(e8390_base + EN1_MULT + i, 0xff);
    
    OUTB(e8390_base + EN1_CURPAG, ei_local->rx_start_page);
    OUTB(e8390_base, E8390_NODMA+E8390_PAGE0+E8390_STOP);

	/*
	 * Program the IRQ via MODE CONFIGURATION REGISTER A
	 */
	switch (dev->irq) {
	case 3:  i = 0; break;
	case 4:  i = 1; break;
	case 5:  i = 2; break;
	case 9:  i = 3; break;
	case 10: i = 4; break;
	case 11: i = 5; break;
	case 12: i = 6; break;
	default:
	case 15: i = 7; break;
	}
    /*
	 * Setting CONFIGURATION REGISTER A - read then write register 0xA
	 *  bits 0-2 - I/O space map address      (0==0x300)
	 *  bits 3-5 - IRQ                        (selected above)
	 *  bit 6    - wait state control         (0==no wait state)
	 *  bit 7    - memory or I/O mode control (0==I/O mode)
	 *
	 * NOTE: Don't separate this INPB() / OUTB() combination.
	 */
	tmp = INPB(e8390_base + 0xA) & 0x8f;	/* hidden register !!!! Part I */
	OUTB(e8390_base + 0xA, tmp | (i<<4));	/* hidden register !!!! Part II */

    /*
	 * Setting CONFIGURATION REGISTER B - read then write register 0xB
	 *  bits 0-1 - physical layer interface  (selected in cable_type)
	 *  bit 2    - good link test
	 *  bit 3    - IO16 control
	 *  bit 4    - channel ready control
	 *  bit 6    - boot PROM write control
	 *  bit 7    - configuration EEPROM load
	 *
	 * NOTE: Don't separate this INPB() / OUTB() combination.
	 */
	tmp = INPB(e8390_base + 0xB) & 0xFC;		/* hidden register !!!! Part I */
	OUTB(e8390_base + 0xB, tmp | dev->cable_type); /* ... Part II */

    dev->tbusy = 0;
    dev->in_intr = 0;
    ei_local->tx1 = ei_local->tx2 = 0;
    ei_local->txing = 0;
    if (startp) {
		OUTB(e8390_base + EN0_ISR, 0xff);
		OUTB(e8390_base + EN0_IMR, ENISR_ALL);
		OUTB(e8390_base, E8390_NODMA+E8390_PAGE0+E8390_START);
		OUTB(e8390_base + EN0_TXCR, E8390_TXCONFIG); /* xmit on. */
		/* 3c503 TechMan says rxconfig only after the NIC is started. */
		OUTB(e8390_base + EN0_RXCR, E8390_RXCONFIG); /* rx on,  */
    }
}

/* Trigger a transmit start, assuming the length is valid. */
void NS8390_trigger_send(struct device *dev, unsigned int length,
								int start_page)
{
    int e8390_base = dev->base_addr;
    
    ei_status.txing = 1;
    OUTB(e8390_base, E8390_NODMA+E8390_PAGE0);


    if (INPB(e8390_base + E8390_CMD) & E8390_TRANS) {
#if EI_DEBUG > 0
		printf("%s: trigger_send() called with the transmitter busy.\n",
			   dev->name);
#endif
		return;
    }

OUTB(e8390_base+EN0_TXCR, E8390_TXCONFIG); /** FORCE it for now **/

    OUTB(e8390_base + EN0_TCNTLO, length & 0xff);
    OUTB(e8390_base + EN0_TCNTHI, length >> 8);
    OUTB(e8390_base + EN0_TPSR, start_page);
    OUTB(e8390_base + E8390_CMD, E8390_NODMA+E8390_TRANS+E8390_START);
    return;
}

/*  Probe for various non-shared-memory ethercards.

   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
   the SAPROM, while other supposed NE2000 clones must be detected by their
   SA prefix.

   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
   mode results in doubled values, which can be detected and compansated for.

   The probe is also responsible for initializing the card and filling
   in the 'dev' and 'ei_status' structures.

   We use the minimum memory size for some ethercard product lines, iff we can't
   distinguish models.  You can increase the packet buffer size by setting
   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
	E1010   starts at 0x100 and ends at 0x2000.
	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
	E2010	 starts at 0x100 and ends at 0x4000.
	E2010-x starts at 0x100 and ends at 0xffff.  */

int ports[] = {0x200,0x220,0x240,0x240,0x260,0x280,0x300,0x320,0x340,0x360,0};

int ne_probe(struct device *dev)
{
	int *port; 
	short ioaddr = dev->base_addr;

	if (ioaddr < 0)
		return -1;		/* Don't probe at all. */
	if (ioaddr > 0x100)
		return (neprobe1(ioaddr, dev) == 0) ? -1 : 0;

	for (port = &ports[0]; *port; port++) {
		if (INPB(*port) != 0xff && neprobe1(*port, dev)) {
			dev->base_addr = *port;
			return 0;
		}
	}
	dev->base_addr = ioaddr;
	return -1;
}


struct {unsigned char value, offset; } program_seq[] = {
	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
	    {0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
	    {0x00,	EN0_RCNTLO},	/* Clear the count regs. */
	    {0x00,	EN0_RCNTHI},
	    {0x00,	EN0_IMR},	/* Mask completion irq. */
	    {0xFF,	EN0_ISR},
	    {E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
	    {E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
	    {32,	EN0_RCNTLO},
	    {0x00,	EN0_RCNTHI},
	    {0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
	    {0x00,	EN0_RSARHI},
	    {E8390_RREAD+E8390_START, E8390_CMD},
};

int neprobe1(int ioaddr, struct device *dev)
{
    int i;
    int wordlength = 2;
    char *name;
    int start_page, stop_page;
    int neX000, ctron, dlink, dfi;
    int reg0 = INPB(ioaddr);
    int regd;

	if ( reg0 == 0xFF)
		return 0;

    /* Do a quick preliminary check that we have a 8390. */
	OUTB(ioaddr + E8390_CMD, E8390_NODMA+E8390_PAGE1+E8390_STOP);
	regd = INPB(ioaddr + 0x0d);
	OUTB(ioaddr + 0x0d, 0xff);
	OUTB(ioaddr + E8390_CMD, E8390_NODMA+E8390_PAGE0);
	INPB(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
	if (INPB(ioaddr + EN0_COUNTER0) != 0) {
	    OUTB(ioaddr, reg0);
	    OUTB(ioaddr + 0x0d, regd);	/* Restore the old values. */
	    return 0;
    }

    #if EI_DEBUG > 0
    printf("NE*000 ethercard probe at %3x:", ioaddr);
    #endif

    /* Read the 16 bytes of station address prom, returning 1 for
       an eight-bit interface and 2 for a 16-bit interface.
       We must first initialize registers, similar to NS8390_init(eifdev, 0).
       We can't reliably read the SAPROM address without this.
       (I learned the hard way!). */
    {
	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
	    OUTB(ioaddr + program_seq[i].offset, program_seq[i].value);
    }
    for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
	SA_prom[i] = INPB(ioaddr + NE_DATAPORT);
	SA_prom[i+1] = INPB(ioaddr + NE_DATAPORT);
	if (SA_prom[i] != SA_prom[i+1])
	    wordlength = 1;
    }


    if (wordlength == 2) {
	/* We must set the 8390 for word mode. */
	OUTB(ioaddr + EN0_DCFG, 0x49);
	/* We used to reset the ethercard here, but it doesn't seem
	   to be necessary. */
	/* Un-double the SA_prom values. */
	for (i = 0; i < 16; i++)
	    SA_prom[i] = SA_prom[i+i];
    }

#if defined(show_all_SAPROM)
    /* If your ethercard isn't detected define this to see the SA_PROM. */
    for(i = 0; i < sizeof(SA_prom); i++)
		printf(" %2.2x", SA_prom[i]);
    printf("\n");
#endif
#if EI_DEBUG > 0
    printf("\nEthernet Address is:");
#endif
    for(i = 0; i < ETHER_ADDR_LEN; i++) {
		dev->dev_addr[i] = SA_prom[i];
#if EI_DEBUG > 0
		printf(" %2.2x", SA_prom[i]);
#endif
    }

⌨️ 快捷键说明

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