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

📄 lnc.c

📁 一款类linux的操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1994-1998 *	Paul Richards.  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, this list of conditions and the following disclaimer, *    verbatim and that no modifications are made prior to this *    point in the file. * 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. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by Paul Richards. * 4. The name Paul Richards may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``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 PAUL RICHARDS 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_lnc.c,v 1.51.2.1 1999/01/31 00:57:46 paul Exp $ *//* * Ported to Roadrunner by Frank W. Miller */#include <bus/isa.h>#include <bus/pci.h>#include <dev/lnc.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/Am7990.h>#include <sys/i8259.h>#include <sys/intr.h>#include <sys/mem.h>/* XXX Need to get a few more of these in */#define PCI_DEVICE		0x2000/* Board types */#define UNKNOWN			0#define NE2100			1/* Chip types */#define LANCE			1      /* Am7990   */#define C_LANCE			2      /* Am79C90  */#define PCnet_ISA		3      /* Am79C960 */#define PCnet_ISAplus		4      /* Am79C961 */#define PCnet_ISA_II		5      /* Am79C961A */#define PCnet_32		6      /* Am79C965 */#define PCnet_PCI		7      /* Am79C970 */#define PCnet_PCI_II		8      /* Am79C970A */#define PCnet_FAST		9      /* Am79C971 */#define PCnet_FASTplus		10     /* Am79C972 *//* CSR88-89: Chip ID masks */#define AMD_MASK		0x003#define PART_MASK		0xffff#define Am79C960		0x0003#define Am79C961		0x2260#define Am79C961A		0x2261#define Am79C965		0x2430#define Am79C970		0x0242#define Am79C970A		0x2621#define Am79C971		0x2623#define Am79C972		0x2624/* NE2100 port addresses */#define NE2100_IOSIZE		24#define PCNET_RDP		0x10   /* Register data port */#define PCNET_RAP		0x12   /* Register address port */#define PCNET_RESET		0x14#define PCNET_BDP		0x16#define PCNET_VSW		0x18/* struct nic_info mem_mode values */#define DMA_FIXED		0x01#define DMA_MBUF		0x02#define SHMEM			0x04/* Descriptor ring entries */#define NRDRE			3#define NTDRE			3/* Packet buffer sizes (rounded to nearest dword boundary */#define RECVBUFSIZE		1518#define TRANSBUFSIZE		1518/* Number of descriptors */#define NDESC(N) (1 << (N))#define INC_MD_PTR(PTR, ENTRIES)					\    if (++(PTR) >= NDESC(ENTRIES))					\	PTR = 0#define DEC_MD_PTR(PTR, ENTRIES)					\    if (--(PTR) < 0)							\	PTR = NDESC(ENTRIES) - 1;#define MULTICAST_FILTER_LEN	8#define FCS_LEN			4static char *ic_ident[] = {    "Unknown",    "LANCE",    "C-LANCE",    "PCnet-ISA",    "PCnet-ISA+",    "PCnet-ISA II",    "PCnet-32 VL-Bus",    "PCnet-PCI",    "PCnet-PCI II",    "PCnet-FAST",    "PCnet-FAST+"};struct nic_info {    int ident;			       /* Type of card */    int ic;			       /* Type of chip */    int mem_mode;    int mode;			       /* Mode setting at initialization */};struct host_ring_entry {    struct mds *md;    union {	buf_t b;	char *data;    } buff;};struct lnc_softc {    struct isa_device isa_dev;	       /* ISA bus parameters */    etheraddr hwaddr;		       /* Ethernet MAC address */    struct nic_info nic;    u_short rdp;		       /* Register data port */    u_short rap;		       /* Register address port */    int nrdre;    int lnc_mem_size;    struct host_ring_entry *recv_ring;    int recv_next;    int ntdre;    struct host_ring_entry *trans_ring;    int trans_next;    int next_to_send;    int pending_transmits;    struct init_block *init_block;    struct bufq sndq;		       /* Send queue */};static struct lnc_softc sc;static __inline u_shortread_csr(u_short port){    outw(sc.rap, port);    return inw(sc.rdp);}static __inline voidwrite_csr(u_short port, u_short val){    outw(sc.rap, port);    outw(sc.rdp, val);}static intlance_probe(){    write_csr(CSR0, STOP);    if ((read_csr(CSR0) & STOP) && !(read_csr(CSR3))) {	/*	 * Check to see if it's a C-LANCE. For the LANCE the INEA bit	 * cannot be set while the STOP bit is. This restriction is	 * removed for the C-LANCE.	 */	write_csr(CSR0, INEA);	if (read_csr(CSR0) & INEA)	    return C_LANCE;	else	    return LANCE;    } else	return UNKNOWN;}static intpcnet_probe(){    u_long chip_id;    int type;    /*     * The PCnet family doesn't reset the RAP register on reset so we     * have to write during the probe.  It does have an ID register     * though so the probe is just a matter of reading it.     */    if ((type = lance_probe(sc))) {	chip_id = (read_csr(CSR89) << 16) | read_csr(CSR88);	if (chip_id & AMD_MASK) {	    chip_id >>= 12;	    switch (chip_id & PART_MASK) {	    case Am79C960:		return PCnet_ISA;	    case Am79C961:		return PCnet_ISAplus;	    case Am79C961A:		return PCnet_ISA_II;	    case Am79C965:		return PCnet_32;	    case Am79C970:		return PCnet_PCI;	    case Am79C970A:		return PCnet_PCI_II;	    case Am79C971:		return PCnet_FAST;	    case Am79C972:		return PCnet_FASTplus;	    default:		break;	    }	}    }    return type;}static intne2100_probe(){    int i;    sc.rap = sc.isa_dev.id_iobase + PCNET_RAP;    sc.rdp = sc.isa_dev.id_iobase + PCNET_RDP;    sc.nic.ic = pcnet_probe(sc);    if (sc.nic.ic > 0) {	sc.nic.ident = NE2100;	sc.nic.mem_mode = DMA_FIXED;	sc.nic.mode = 0x8000;	       /* Promiscuous */	/* XXX - For now just use the defines */	sc.nrdre = NRDRE;	sc.ntdre = NTDRE;	/* Extract MAC address from PROM */	for (i = 0; i < ETHER_ADDR_LEN; i++)	    sc.hwaddr[i] = inb(sc.isa_dev.id_iobase + i);	return NE2100_IOSIZE;    }    return 0;}static intlnc_send_packet(buf_t b, char *buf){    bcopy(bstart(b), buf, blen(b));    return blen(b);}static voidlnc_start(){    buf_t b;    struct host_ring_entry *desc;    int len;    do {	disable;	b = bdeq(&(sc.sndq));	enable;	if (b == NULL)	    return;	sc.pending_transmits++;	desc = sc.trans_ring + sc.next_to_send;	len = lnc_send_packet(b, desc->buff.data);	desc->md->md3 = 0;	desc->md->md2 = -len;	desc->md->md1 |= OWN | STP | ENP;	INC_MD_PTR(sc.next_to_send, sc.ntdre);	/* Force an immediate poll of the transmit ring */	write_csr(CSR0, TDMD | INEA);	brel(b);    } while (sc.pending_transmits < NDESC(sc.ntdre));}static voidlnc_stop(){    write_csr(CSR0, STOP);}static voidlnc_reset(){    buf_t b;    char *lnc_mem;    u_long lnc_mem_val;    int i;    /* Stop the device */    lnc_stop();    /* Empty send queue */    disable;    for (;;) {	b = bdeq(&(sc.sndq));	if (b == NULL)	    break;	_bfree(b);    }    enable;    bzero(sc.recv_ring, sc.lnc_mem_size);    /* Setup receive and transmit rings */    sc.recv_next = 0;    sc.trans_ring = sc.recv_ring + NDESC(sc.nrdre);    sc.trans_next = 0;    lnc_mem = (char *) (sc.trans_ring + NDESC(sc.ntdre));    lnc_mem = (char *) (((int) lnc_mem + 1) & ~1);    sc.init_block = (struct init_block *) ((int) lnc_mem & ~1);    lnc_mem = (char *) (sc.init_block + 1);    lnc_mem = (char *) (((int) lnc_mem + 7) & ~7);    /* Initialize pointers to descriptor entries */    for (i = 0; i < NDESC(sc.nrdre); i++) {	(sc.recv_ring + i)->md = (struct mds *) lnc_mem;	lnc_mem += sizeof(struct mds);    }    for (i = 0; i < NDESC(sc.ntdre); i++) {	(sc.trans_ring + i)->md = (struct mds *) lnc_mem;	lnc_mem += sizeof(struct mds);    }    /* Initialize descriptor ring entries */    for (i = 0; i < NDESC(sc.nrdre); i++) {	lnc_mem_val = (u_long) lnc_mem;	(sc.recv_ring + i)->md->md0 = (u_short) lnc_mem_val;	(sc.recv_ring + i)->md->md1 = ((lnc_mem_val >> 16) & 0xff) | OWN;	(sc.recv_ring + i)->md->md2 = -RECVBUFSIZE;	(sc.recv_ring + i)->md->md3 = 0;	(sc.recv_ring + i)->buff.data = lnc_mem;	lnc_mem += RECVBUFSIZE;    }    for (i = 0; i < NDESC(sc.ntdre); i++) {	lnc_mem_val = (u_long) lnc_mem;	(sc.trans_ring + i)->md->md0 = lnc_mem_val;	(sc.trans_ring + i)->md->md1 = ((lnc_mem_val >> 16) & 0xff);	(sc.trans_ring + i)->md->md2 = 0;	(sc.trans_ring + i)->md->md3 = 0;	(sc.trans_ring + i)->buff.data = lnc_mem;	lnc_mem += TRANSBUFSIZE;    }    sc.next_to_send = 0;    /* Setup initialization block */    sc.init_block->mode = sc.nic.mode;    for (i = 0; i < ETHER_ADDR_LEN; i++)	sc.init_block->padr[i] = sc.hwaddr[i];    for (i = 0; i < MULTICAST_FILTER_LEN; i++)	sc.init_block->ladrf[i] = 0xff;    sc.init_block->rdra = (u_short) ((u_long) sc.recv_ring->md);    sc.init_block->rlen = (u_short)	(((((u_long) sc.recv_ring->md) >> 16) & 0xff) | (sc.nrdre << 13));    sc.init_block->tdra = (u_short) ((u_long) sc.trans_ring->md);    sc.init_block->tlen = (u_short)	(((((u_long) sc.trans_ring->md) >> 16) & 0xff) | (sc.ntdre << 13));    /* Give the initialization block to the LANCE */    write_csr(CSR1, (u_short) ((u_long) sc.init_block));    write_csr(CSR2, (((u_long) sc.init_block) >> 16) & 0xff);    /*     * Depending on which controller this is, CSR3 has different meanings.     * For the Am7990 it controls DMA operations, for the Am79C960 it     * controls interrupt masks and transmitter algorithms. In either     * case, no flags are set.     */    write_csr(CSR3, 0);    /* Let's see if it starts... */    write_csr(CSR0, INIT);    for (i = 0; i < 1000; i++)	if (read_csr(CSR0) & IDON)	    break;    if (read_csr(CSR0) & IDON) {	/* Enable interrupts and start the LANCE transmitter */	write_csr(CSR0, STRT | INEA);	lnc_start();    } else {#if _DEBUG	kprintf("lnc_init: initialization failed\n");#endif    }

⌨️ 快捷键说明

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