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

📄 if_ec.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char *sccsid = "@(#)if_ec.c	4.1	ULTRIX	7/2/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1985 by				* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//************************************************************************ *			Modification History				* * * 01-Jun-89 -- darrell *	Removed cpup -- as it is unused here. * * 12-Apr-88  -- lea	4.35bsd changes + decnet hooks			* *									* * 13-Jun-86   -- jaw 	fix to uba reset and drivers. *									* *	Darrell Dunnuck 04/16/86					* *		badaddr is now called via the macro BADADDR.		* *									* * 18-mar-86  -- jaw     br/cvec changed to NOT use registers. * *	Darrell Dunnuck	03/15/86					* *		cpusw is now only accesed globally once, and the 	* *		pointer cpup is used thereafter.			* *									* *	Chet Juszczak - 03/12/86					* *		Modify MCLGET macro call to match new definition	* *									* * 18-Mar-86 -- jaw  add routines to cpu switch for nexus/unibus addreses *		     also got rid of some globals like nexnum. *		     ka8800 cleanup. *									* *	Larry Cohen  -	09/16/85					* * 		Add 43bsd alpha tape changes for subnet routing		* *									* ************************************************************************/#include "ec.h"#if	NEC > 0 || defined(BINARY)/* * 3Com Ethernet Controller interface * *  @(#) if_ec.c 7.2 (Berkeley) 10/23/87 */#include "../data/if_ec_data.c"#if CLSIZE == 2#define ECBUFSIZE       32              /* on-board memory, clusters */#endifint	ecprobe(), ecattach(), ecrint(), ecxint(), eccollide();u_short ecstd[] = { 0 };struct	uba_driver ecdriver =	{ ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0 };int	ecinit(),ecioctl(),ecoutput(),ecreset();struct	mbuf *ecget();extern struct protosw *iftype_to_proto(), *iffamily_to_proto();extern struct ifnet loif;/* * Configure on-board memory for an interface. * Called from autoconfig and after a uba reset. * The address of the memory on the uba is supplied in the device flags. *//* * Do output DMA to determine interface presence and * interrupt vector.  DMA is too short to disturb other hosts. */ecprobe(reg,ui)        caddr_t reg;        struct uba_device *ui;{       register struct ecdevice *addr = (struct ecdevice *)reg;       register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags];#ifdef lint        ecrint(0); ecxint(0); eccollide(0);#endif        if (BADADDR((caddr_t)addr, 2))                return (-1);	if  ((uba_hd[numuba].uba_type&UBA780) && 			uba_hd[numuba].uh_uba->uba_sr) {                uba_hd[numuba].uh_uba->uba_sr = uba_hd[numuba].uh_uba->uba_sr;                return (-1);	}        /*         * Make sure memory is turned on         */        addr->ec_rcr = EC_AROM;        /*         * Tell the system that the board has memory here, so it won't         * attempt to allocate the addresses later.         */        if (ubamem(numuba, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) {                printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit);                addr->ec_rcr = EC_MDISAB;       /* disable memory */                return (-1);        }        /*         * Check for existence of buffers on Unibus.         */        if (BADADDR((caddr_t)ecbuf, 2)) {bad:                printf("ec%d: buffer mem not found\n", ui->ui_unit);                (void) ubamem(numuba, ui->ui_flags, ECBUFSIZE*2, 0);                addr->ec_rcr = EC_MDISAB;       /* disable memory */                return (-1);        }	if  ((uba_hd[numuba].uba_type&UBA780) && 			uba_hd[numuba].uh_uba->uba_sr) {                uba_hd[numuba].uh_uba->uba_sr = uba_hd[numuba].uh_uba->uba_sr;                goto bad;        }        if (ui->ui_alive == 0)          /* Only printf from autoconfig */                printf("ec%d: mem %x-%x\n", ui->ui_unit,                        ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1);        ui->ui_type = 1;                /* Memory on, allocated */        /*         * Make a one byte packet in what should be buffer #0.         * Submit it for sending.  This should cause an xmit interrupt.         * The xmit interrupt vector is 8 bytes after the receive vector,         * so adjust for this before returning.         */        *(u_short *)ecbuf = (u_short) 03777;        ecbuf[03777] = '\0';        addr->ec_xcr = EC_XINTEN|EC_XWBN;        DELAY(100000);        addr->ec_xcr = EC_XCLR;        if (cvec > 0 && cvec != 0x200) {                if (cvec & 04) {        /* collision interrupt */                        cvec -= 04;                        br += 1;                /* rcv is collision + 1 */                } else {                /* xmit interrupt */                        cvec -= 010;                        br += 2;                /* rcv is xmit + 2 */                }        }        return (1);}/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */ecattach(ui)	struct uba_device *ui;{	struct ec_softc *es = &ec_softc[ui->ui_unit];	register struct ifnet *ifp = &es->es_if;	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;	int i, j;	u_char *cp;	ifp->if_unit = ui->ui_unit;	ifp->if_name = "ec";	ifp->if_mtu = ETHERMTU;	/*	 * Read the ethernet address off the board, one nibble at a time.	 */	addr->ec_xcr = EC_UECLR; /* zero address pointer */	addr->ec_rcr = EC_AROM;	cp = es->es_addr;#define	NEXTBIT	addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM	for (i=0; i < sizeof (es->es_addr); i++) {		*cp = 0;		for (j=0; j<=4; j+=4) {			*cp |= ((addr->ec_rcr >> 8) & 0xf) << j;			NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT;		}		cp++;	}	printf("ec%d: hardware address %s\n", ui->ui_unit,		ether_sprintf(es->es_addr));	ifp->if_init = ecinit;	ifp->if_ioctl = ecioctl;	ifp->if_output = ecoutput;	ifp->if_reset = ecreset;	ifp->if_flags = IFF_BROADCAST;	for (i=0; i<16; i++)		es->es_buf[i] 		    = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i];	if_attach(ifp);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */ecreset(unit, uban)	int unit, uban;{	register struct uba_device *ui;	if (unit >= nNEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 ||	    ui->ui_ubanum != uban)		return;	printf(" ec%d", unit);	ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING;	ecinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */ecinit(unit)	int unit;{	struct ec_softc *es = &ec_softc[unit];	struct ecdevice *addr;	register struct ifnet *ifp = &es->es_if;	int i, s;	/* not yet, if address still unknown */	if (ifp->if_addrlist == (struct ifaddr *)0)		return;	/*	 * Hang receive buffers and start any pending writes.	 * Writing into the rcr also makes sure the memory	 * is turned on.	 */	if ((ifp->if_flags & IFF_RUNNING) == 0) {/*	if ((es->es_if.flags & IFF_RUNNING) == 0) { */		addr = (struct ecdevice *)ecinfo[unit]->ui_addr;		s = splimp();		/*		 * write our ethernet address into the address recognition ROM 		 * so we can always use the same EC_READ bits (referencing ROM),		 * in case we change the address sometime.		 * Note that this is safe here as the receiver is NOT armed.		 */		ec_setaddr(es->es_addr, unit);		/*		 * Arm the receiver		 */		for (i = ECRHBF; i >= ECRLBF; i--)			addr->ec_rcr = EC_READ | i;		es->es_oactive = 0;		es->es_mask = ~0;		es->es_if.if_flags |= IFF_RUNNING;		if (es->es_if.if_snd.ifq_head)			ecstart(unit);		splx(s);	}}/* * Start output on interface.  Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */ecstart(unit){	register struct ec_softc *es = &ec_softc[unit];	struct ecdevice *addr;	struct mbuf *m;	if ((es->es_if.if_flags & IFF_RUNNING) == 0)		return;	IF_DEQUEUE(&es->es_if.if_snd, m);	if (m == 0) {		es->es_oactive = 0;		return;	}	ecput(es->es_buf[ECTBF], m);	addr = (struct ecdevice *)ecinfo[unit]->ui_addr;	addr->ec_xcr = EC_WRITE|ECTBF;	es->es_oactive = 1;}/* * Ethernet interface transmitter interrupt. * Start another output if more data to send. */ecxint(unit)	int unit;{	register struct ec_softc *es = &ec_softc[unit];	register struct ecdevice *addr =		(struct ecdevice *)ecinfo[unit]->ui_addr;	if (es->es_oactive == 0)		return;	if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) {		printf("ec%d: stray xmit interrupt, xcr=%b\n", unit,			addr->ec_xcr, EC_XBITS);		es->es_oactive = 0;		addr->ec_xcr = EC_XCLR;		return;	}	es->es_if.if_opackets++;	es->es_oactive = 0;	es->es_mask = ~0;	addr->ec_xcr = EC_XCLR;	if (es->es_if.if_snd.ifq_head)		ecstart(unit);}/* * Collision on ethernet interface.  Do exponential * backoff, and retransmit.  If have backed off all * the way print warning diagnostic, and drop packet. */eccollide(unit)	int unit;{	register struct ec_softc *es = &ec_softc[unit];	register struct ecdevice *addr =	    (struct ecdevice *)ecinfo[unit]->ui_addr;	register i;	int delay;	es->es_if.if_collisions++;	if (es->es_oactive == 0)		return;	/*	 * Es_mask is a 16 bit number with n low zero bits, with	 * n the number of backoffs.  When es_mask is 0 we have	 * backed off 16 times, and give up.	 */	if (es->es_mask == 0) {		es->es_if.if_oerrors++;		printf("ec%d: send error\n", unit);		/*		 * Reset interface, then requeue rcv buffers.		 * Some incoming packets may be lost, but that		 * can't be helped.		 */		addr->ec_xcr = EC_UECLR;		for (i=ECRHBF; i>=ECRLBF; i--)			addr->ec_rcr = EC_READ|i;		/*		 * Reset and transmit next packet (if any).		 */		es->es_oactive = 0;		es->es_mask = ~0;		if (es->es_if.if_snd.ifq_head)			ecstart(unit);		return;	}	/*	 * Do exponential backoff.  Compute delay based on low bits	 * of the interval timer (1 bit for each transmission attempt,	 * but at most 5 bits).  Then delay for that number of	 * slot times.  A slot time is 51.2 microseconds (rounded to 51).	 * This does not take into account the time already used to	 * process the interrupt.	 */	es->es_mask <<= 1;	delay = mfpr(ICR) & 0x1f &~ es->es_mask;	DELAY(delay * 51);	/*	 * Clear the controller's collision flag, thus enabling retransmit.	 */	addr->ec_xcr = EC_CLEAR;}/* * Ethernet interface receiver interrupt. * If input error just drop packet. * Otherwise examine  * packet to determine type.  If can't determine length * from type, then have to drop packet.  Othewise decapsulate * packet based on type and pass to type specific higher-level * input routine. */ecrint(unit)	int unit;{	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;	while (addr->ec_rcr & EC_RDONE)		ecread(unit);}ecread(unit)	int unit;{	register struct ec_softc *es = &ec_softc[unit];	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;	register struct ether_header *ec;    	struct mbuf *m;	int len, off, resid, ecoff, rbuf;	struct ifqueue *inq;	struct protosw *pr;	u_char *ecbuf;	es->es_if.if_ipackets++;	rbuf = addr->ec_rcr & EC_RBN;	if (rbuf < ECRLBF || rbuf > ECRHBF)		panic("ecrint");	ecbuf = es->es_buf[rbuf];	ecoff = *(short *)ecbuf;	if (ecoff <= ECRDOFF || ecoff > 2046) {		es->es_if.if_ierrors++;#ifdef notdef		if (es->es_if.if_ierrors % 100 == 0)			printf("ec%d: += 100 input errors\n", unit);#endif		goto setup;	}	/*	 * Get input data length.	 * Get pointer to ethernet header (in input buffer).	 * Deal with trailer protocol: if type is trailer type	 * get true type from first 16-bit word past data.	 * Remember that type was trailer by setting off.	 */	len = ecoff - ECRDOFF - sizeof (struct ether_header);	ec = (struct ether_header *)(ecbuf + ECRDOFF);	ec->ether_type = ntohs((u_short)ec->ether_type);#define	ecdataaddr(ec, off, type)	((type)(((caddr_t)((ec)+1)+(off))))	if (ec->ether_type >= ETHERTYPE_TRAIL &&	    ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {		off = (ec->ether_type - ETHERTYPE_TRAIL) * 512;		if (off >= ETHERMTU)			goto setup;		/* sanity */		ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *));		resid = ntohs(*(ecdataaddr(ec, off+2, u_short *)));		if (off + resid > len)			goto setup;		/* sanity */		len = off + resid;	} else		off = 0;	if (len == 0)		goto setup;	/*	 * Pull packet off interface.  Off is nonzero if packet	 * has trailing header; ecget will then force this header	 * information to be at the front, but we still have to drop	 * the type and length which are at the front of any trailer data.	 */	m = ecget(ecbuf, len, off);	if (m == 0)		goto setup;

⌨️ 快捷键说明

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