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

📄 ne.c

📁 一款类linux的操作系统源码
💻 C
字号:
/* * Copyright (c) 1995, David Greenman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice unmodified, this list of conditions, and the following *    disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *      $Id: if_ed.c,v 1.148 1999/01/19 00:21:38 peter Exp $ *//* * Ported to Roadrunner by Frank W. Miller */#include <bus/isa.h>#include <dev/ne.h>#include <errno.h>#include <net/arp.h>#include <net/ether.h>#include <net/netif.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys.h>#include <sys/buf.h>#include <sys/i8259.h>#include <sys/intr.h>#include <sys/ne2000.h>#include <sys/time.h>#define MIN_PKT_SIZE	64struct ne_softc {    struct isa_device isa_dev;	       /* ISA bus parameters */    u_char hwaddr[ETHER_ADDR_LEN];     /* Ethernet MAC address */    u_short asic_addr;		       /* ASIC I/O bus address */    u_short nic_addr;		       /* NIC (DP8390) I/O bus address */    u_short mem_start;		       /* NIC memory start address */    u_short mem_end;		       /* NIC memory end address */    u_short mem_size;		       /* Total NIC memory size */    u_short mem_ring;		       /* Start of RX ring-buffer */    u_char mem_shared;		       /* NIC memory shared with host */    u_char tx_busy;		       /* Transmitter busy */    u_char txb_cnt;		       /* Number of TX buffers */    u_char txb_inuse;		       /* Number of TX buffers in-use */    u_char txb_new;		       /* Ptr to where new buffer is added */    u_char txb_next_tx;		       /* Ptr to next buffer ready for TX */    u_short txb_len[8];		       /* Buffered TX buffer lengths */    u_char tx_page_start;	       /* First page of TX buffer area */    u_char rec_page_start;	       /* First page of RX ring-buffer */    u_char rec_page_stop;	       /* Last page of RX ring-buffer */    u_char next_packet;		       /* Ptr to next unread RX packet */    struct bufq sndq;		       /* Send queue */};static struct ne_softc sc;static u_short pad[MIN_PKT_SIZE >> 1];static voidne_readmem(u_short src, u_short * dst, u_short len){    len = ALIGN(len, 2);    /* Abort any remote DMA already in progress */    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);    /* Setup DMA byte count */    outb(sc.nic_addr + ED_P0_RBCR0, len);    outb(sc.nic_addr + ED_P0_RBCR1, len >> 8);    /* Setup NIC memory source address */    outb(sc.nic_addr + ED_P0_RSAR0, src);    outb(sc.nic_addr + ED_P0_RSAR1, src >> 8);    /* Select remote DMA read */    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);    /* Read NIC memory */    insw(sc.asic_addr + ED_NOVELL_DATA, dst, len >> 1);}static intne_probe(){    u_char byte;    u_char romdata[16];    int i;    /* Reset */    byte = inb(sc.asic_addr + ED_NOVELL_RESET);    outb(sc.asic_addr + ED_NOVELL_RESET, byte);    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);    DELAY(5000);    /* Test for a generic DP8390 NIC */    byte = inb(sc.nic_addr + ED_P0_CR);    byte &= ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP;    if (byte != (ED_CR_RD2 | ED_CR_STP))	return 0;    byte = inb(sc.nic_addr + ED_P0_ISR);    byte &= ED_ISR_RST;    if (byte != ED_ISR_RST)	return 0;    /* Assume a 16-bit adapter interface */    sc.mem_start = 16384;    sc.mem_size = 16384;    sc.mem_end = sc.mem_start + sc.mem_size;    sc.tx_page_start = sc.mem_size / ED_PAGE_SIZE;    /* Use two TX buffers */    sc.txb_cnt = 2;    /* Setup RX ring */    sc.mem_ring = sc.mem_start + sc.txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;    sc.rec_page_start = sc.tx_page_start + sc.txb_cnt * ED_TXBUF_SIZE;    sc.rec_page_stop = sc.tx_page_start + sc.mem_size / ED_PAGE_SIZE;    /* Get Ethernet MAC address  */    ne_readmem(0, (u_short *) romdata, 16);    for (i = 0; i < ETHER_ADDR_LEN; i++)	sc.hwaddr[i] = romdata[i * 2];    /* Clear any pending interrupts */    outb(sc.nic_addr + ED_P0_ISR, 0xff);    return 1;}static voidne_recv_ring_copy(u_short src, u_short * dst, u_short len){    /* Check whether copy wraps to lower address in ring buffer */    if (src + len > sc.mem_end) {	u_short tmp = sc.mem_end - src;	ne_readmem(src, dst, tmp);	len -= tmp;	src = sc.mem_ring;	dst += tmp;    }    ne_readmem(src, dst, len);}static buf_tne_get_packet(u_short src, u_short len){    buf_t b;    disable;    b = _bget(ETHER_PKT_LEN);    enable;    if (b == NULL) {#if _DEBUG	kprintf("ne_get_packet: no buffers\n");#endif	return NULL;    }    blen(b) = len;    ne_recv_ring_copy(src, (u_short *) bstart(b), len);    return b;}static voidne_rxisr(){    struct recv_ring_desc packet_hdr;    u_short packet_ptr;    buf_t b;    u_char boundry;    int len;    /* Set page 1 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);    while (sc.next_packet != inb(sc.nic_addr + ED_P1_CURR)) {	/* Get ptr to buffer header structure */	packet_ptr = sc.mem_ring;	packet_ptr += (sc.next_packet - sc.rec_page_start) * ED_PAGE_SIZE;	/* Read receive ring descriptor */	ne_readmem(packet_ptr, (u_short *) & packet_hdr,		   sizeof(struct recv_ring_desc));	/* Check for ring pointer corruption */	if (packet_hdr.next_packet < sc.rec_page_start ||	    packet_hdr.next_packet >= sc.rec_page_stop) {#if _DEBUG	    kprintf("ne_rxisr: receive ring corrupted\n");#endif	    return;	}	len = packet_hdr.count - sizeof(struct recv_ring_desc);	b = ne_get_packet(packet_ptr + sizeof(struct recv_ring_desc), len);	if (b != NULL)	    netif_input(b);	/* Update next packet pointer */	sc.next_packet = packet_hdr.next_packet;	/* Set page 0 registers */	outb(sc.nic_addr + ED_P0_CR, ED_CR_STA);	/* Update boundry pointer */	boundry = sc.next_packet - 1;	if (boundry < sc.rec_page_start)	    boundry = sc.rec_page_stop - 1;	outb(sc.nic_addr + ED_P0_BNRY, boundry);	/* Set page 1 registers */	outb(sc.nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STA);    }}static voidne_transmit(){    u_short len;    len = sc.txb_len[sc.txb_next_tx];    /* Set page 0 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_STA);    /* Set TX buffer start page */    outb(sc.nic_addr + ED_P0_TPSR,	 sc.tx_page_start + sc.txb_next_tx * ED_TXBUF_SIZE);    /* Set TX length */    outb(sc.nic_addr + ED_P0_TBCR0, len);    outb(sc.nic_addr + ED_P0_TBCR1, len >> 8);    /* Set page 0 registers, transmit packet, and start */    outb(sc.nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);    sc.tx_busy = 1;    /* Point to next transmit buffer slot and wrap if necessary */    sc.txb_next_tx++;    if (sc.txb_next_tx == sc.txb_cnt)	sc.txb_next_tx = 0;}static voidne_isr(void *params){    u_char isr;    /* Set page 0 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_STA);    /* Loop until there are no pending interrupts */    while ((isr = inb(sc.nic_addr + ED_P0_ISR)) != 0) {	/* Reset bits for interrupts being acknowledged */	outb(sc.nic_addr + ED_P0_ISR, isr);	/* TX interrupts */	if (isr & (ED_ISR_PTX | ED_ISR_TXE)) {	    if (isr & ED_ISR_TXE)		kprintf("ne_isr: transmit error\n");	    sc.tx_busy = 0;	    if (sc.txb_inuse && --sc.txb_inuse)		ne_transmit();	}	/* RX interrupts */	if (isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) {	    if (isr & ED_ISR_OVW)		kprintf("ne_isr: receive ring buffer overflow\n");	    else {		if (isr & ED_ISR_RXE)		    kprintf("ne_isr: receive error\n");		/* Receive packet */		ne_rxisr();	    }	}	/* Return NIC CR to known state */	outb(sc.nic_addr + ED_P0_CR, ED_CR_STA);    }    /* XXX Hard coded for the moment */    outb(I8259_SLV_CTRL, 0x61);    outb(I8259_MSTR_CTRL, I8259_EOI_CAS);}intne_init(){    ipaddr ip;    char s[20];    int i;    bzero((char *) pad, MIN_PKT_SIZE);    sc.isa_dev.id_iobase = 0x300;    sc.isa_dev.id_irq = 9;    sc.isa_dev.id_maddr = 0xd8000;    sc.asic_addr = sc.isa_dev.id_iobase + ED_NOVELL_ASIC_OFFSET;    sc.nic_addr = sc.isa_dev.id_iobase + ED_NOVELL_NIC_OFFSET;    if (!ne_probe()) {#if _DEBUG	kprintf("ne_init: no adapter found\n");#endif	return EFAIL;    }    ether2str(sc.hwaddr, s);    kprintf("ne_init: NE2000 iobase 0x%x irq %d hwaddr %s\n",	    sc.isa_dev.id_iobase, sc.isa_dev.id_irq, s);    bcopy(sc.hwaddr, netif_primary.hwaddr, ETHER_ADDR_LEN);    netif_primary.state = NETIF_STATE_UP;    str2ip(IPADDR, &ip);    arp_insert(ARP_ENTRY_RESOLVED, ARP_TTL_INFINITE, ip, sc.hwaddr);    binitq(&(sc.sndq));    isr_inst(IRQ2INTR(sc.isa_dev.id_irq), ne_isr, NULL);    intr_unmask(IRQ2INTR(sc.isa_dev.id_irq));    sc.tx_busy = 0;    sc.txb_inuse = 0;    sc.txb_new = 0;    sc.txb_next_tx = 0;    sc.next_packet = sc.rec_page_start + 1;    /* Set page 0 registers, abort remote DMA, stop NIC */    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);    /*     * Set FIFO threshold to 8, no auto-init remote DMA, byte order=80x86,     * word-wide DMA transfers     */    outb(sc.nic_addr + ED_P0_DCR, ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);    /* Clear remote byte count registers */    outb(sc.nic_addr + ED_P0_RBCR0, 0);    outb(sc.nic_addr + ED_P0_RBCR1, 0);    /* Don't store incoming packets in memory for the moment */    outb(sc.nic_addr + ED_P0_RCR, ED_RCR_MON);    /* Place NIC in internal loopback mode */    outb(sc.nic_addr + ED_P0_TCR, ED_TCR_LB0);    /* Initialize transmit/receive (ring-buffer) page start */    outb(sc.nic_addr + ED_P0_TPSR, sc.tx_page_start);    outb(sc.nic_addr + ED_P0_PSTART, sc.rec_page_start);    /* Initialize receiver (ring-buffer) page stop and boundry */    outb(sc.nic_addr + ED_P0_PSTOP, sc.rec_page_stop);    outb(sc.nic_addr + ED_P0_BNRY, sc.rec_page_start);    /* Clear any pending interrupts */    outb(sc.nic_addr + ED_P0_ISR, 0xff);    /*     * Enable the following interrupts: receive/transmit complete,     * receive/transmit error, and receiver overwrite.  Counter overflow     * and remote DMA complete are *NOT* enabled.     */    outb(sc.nic_addr + ED_P0_IMR,	 ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | ED_IMR_OVWE);    /* Set page 1 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_PAGE_1 | ED_CR_STP);    /* Copy out our station address */    for (i = 0; i < ETHER_ADDR_LEN; i++)	outb(sc.nic_addr + ED_P1_PAR0 + i, sc.hwaddr[i]);    /* Set current page pointer to next_packet (initialized above) */    outb(sc.nic_addr + ED_P1_CURR, sc.next_packet);    /*     * Initialize multicast address hashing registers to not accept     * multicasts     */    for (i = 0; i < 8; ++i)	outb(sc.nic_addr + ED_P1_MAR0 + i, 0);    /* Set page 0 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_STP);    /* Accept broadcast packets */    outb(sc.nic_addr + ED_P0_RCR, ED_RCR_AB);    /* Start NIC */    outb(sc.nic_addr + ED_P0_CR, ED_CR_STA);    /* Take NIC out of loopback */    outb(sc.nic_addr + ED_P0_TCR, 0);    return 0;}intne_shut(){    return ENOSYS;}intne_ioctl(int cmd, void *args){    return ENOSYS;}intne_read(buf_t * b){    return ENOSYS;}static u_shortne_writebufs(buf_t b, u_short dst){    u_short len;    u_char byte;    int max_wait = 500;		       /* About 240us */    len = ALIGN(blen(b), 2);    /* Set page 0 registers */    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STA);    /* Reset remote DMA complete flag */    outb(sc.nic_addr + ED_P0_ISR, ED_ISR_RDC);    /* Set up DMA byte count */    outb(sc.nic_addr + ED_P0_RBCR0,	 (len < MIN_PKT_SIZE ? MIN_PKT_SIZE : len));    outb(sc.nic_addr + ED_P0_RBCR1, len >> 8);    /* Set up destination address in NIC memory */    outb(sc.nic_addr + ED_P0_RSAR0, dst);    outb(sc.nic_addr + ED_P0_RSAR1, dst >> 8);    /* Set remote DMA write */    outb(sc.nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);    /* Write packet data */    outsw(sc.asic_addr + ED_NOVELL_DATA, (u_short *) bstart(b), len >> 1);    if (len < MIN_PKT_SIZE)	outsw(sc.asic_addr + ED_NOVELL_DATA, pad, (MIN_PKT_SIZE - len) >> 1);    /*     * Wait for remote DMA complete. This is necessary because on the     * transmit side, data is handled internally by the NIC in bursts and     * we can't start another remote DMA until this one completes. Not     * waiting causes really bad things to happen - like the NIC     * irrecoverably jamming the ISA bus.     */    for (;;) {	byte = inb(sc.nic_addr + ED_P0_ISR) & ED_ISR_RDC;	if ((byte & ED_ISR_RDC) == ED_ISR_RDC)	    break;	if (--max_wait == 0)	    break;    }    return (blen(b) < MIN_PKT_SIZE ? MIN_PKT_SIZE : blen(b));}#define MAX(A, B) ((A) > (B) ? (A) : (B))static voidne_start(){    buf_t b;    u_short mem_ptr, len;    for (;;) {	if (sc.txb_inuse == sc.txb_cnt)	    return;	disable;	b = bdeq(&(sc.sndq));	enable;	if (b == NULL)	    return;	mem_ptr = sc.mem_start + (sc.txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);	len = ne_writebufs(b, mem_ptr);	if (len == 0)	    continue;	brel(b);	sc.txb_len[sc.txb_new] = len;	sc.txb_inuse++;	/* Point to next buffer slot and wrap if necessary */	sc.txb_new++;	if (sc.txb_new == sc.txb_cnt)	    sc.txb_new = 0;	if (sc.tx_busy == 0)	    ne_transmit();    }}intne_write(buf_t * b){    disable;    benq(*b, &(sc.sndq));    enable;    ne_start();    return 0;}

⌨️ 快捷键说明

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