File:  [DragonFly] / src / sys / dev / netif / cx / if_cx.c
Revision 1.11: download - view: text, annotated - select for diffs
Tue May 4 12:12:13 2004 UTC (10 years, 7 months ago) by hmp
Branches: MAIN
CVS tags: HEAD
netif/cx/cx.c:
	* Provide arguments to strlcpy() in correct order.

netif/cx/if_cx.c
	* Comment-out unwanted prototypes and externs.

Noticed-by: 	LINT

    1: /*
    2:  * Cronyx-Sigma adapter driver for FreeBSD.
    3:  * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
    4:  * and asyncronous channels with full modem control.
    5:  * Keepalive protocol implemented in both Cisco and PPP modes.
    6:  *
    7:  * Copyright (C) 1994 Cronyx Ltd.
    8:  * Author: Serge Vakulenko, <vak@zebub.msk.su>
    9:  *
   10:  * This software is distributed with NO WARRANTIES, not even the implied
   11:  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   12:  *
   13:  * Authors grant any other persons or organisations permission to use
   14:  * or modify this software as long as this message is kept with the software,
   15:  * all derivative works or modified versions.
   16:  *
   17:  * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
   18:  *
   19:  * $FreeBSD: src/sys/i386/isa/if_cx.c,v 1.32 1999/11/18 08:36:42 peter Exp $
   20:  * $DragonFly: src/sys/dev/netif/cx/if_cx.c,v 1.11 2004/05/04 12:12:13 hmp Exp $
   21:  *
   22:  */
   23: #undef DEBUG
   24: 
   25: #include "use_cx.h"
   26: #include "use_sppp.h"
   27: #if NSPPP <= 0
   28: #error The device 'cx' requires sppp.
   29: #endif
   30: 
   31: #include <sys/param.h>
   32: #include <sys/systm.h>
   33: #include <sys/kernel.h>
   34: #include <sys/malloc.h>
   35: #include <sys/mbuf.h>
   36: #include <sys/sockio.h>
   37: #include <sys/socket.h>
   38: #include <sys/conf.h>
   39: 
   40: #include <net/if.h>
   41: 
   42: #include <net/bpf.h>
   43: 
   44: #include <bus/isa/i386/isa_device.h>
   45: #define watchdog_func_t void(*)(struct ifnet *)
   46: #define start_func_t    void(*)(struct ifnet*)
   47: 
   48: #include <net/sppp/if_sppp.h>
   49: #include <machine/cronyx.h>
   50: #include "cxreg.h"
   51: #include "cx.c"
   52: 
   53: #if 0
   54: /* XXX exported. */
   55: void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
   56: #endif
   57: 
   58: static int cxprobe (struct isa_device *id);
   59: static int cxattach (struct isa_device *id);
   60: static void cxput (cx_chan_t *c, char b);
   61: static void cxsend (cx_chan_t *c);
   62: static void cxrinth (cx_chan_t *c);
   63: static ointhand2_t cxintr;
   64: static int cxtinth (cx_chan_t *c);
   65: 
   66: #ifdef DEBUG
   67: #   define print(s)     printf s
   68: #else
   69: #   define print(s)     {/*void*/}
   70: #endif
   71: 
   72: #define TXTIMEOUT       10              /* transmit timeout in seconds */
   73: #define DMABUFSZ        (6*256)         /* buffer size */
   74: #define PPP_HEADER_LEN  4               /* size of PPP header */
   75: 
   76: /*
   77:  * Under BSDI it's possible to use general p2p protocol scheme,
   78:  * as well as our own one.  Switching is done via IFF_ALTPHYS flag.
   79:  * Our ifnet pointer holds the buffer large enough to contain
   80:  * any of sppp and p2p structures.
   81:  */
   82: #define IFSTRUCTSZ   (sizeof (struct sppp))
   83: #define IFNETSZ         (sizeof (struct ifnet))
   84: 
   85: static int cxsioctl (struct ifnet *ifp, u_long cmd, caddr_t data,
   86: 		     struct ucred *cr);
   87: static void cxstart (struct ifnet *ifp);
   88: static void cxwatchdog (struct ifnet *ifp);
   89: static void cxinput (cx_chan_t *c, void *buf, unsigned len);
   90: #if 0
   91: extern int cxrinta (cx_chan_t *c);
   92: extern void cxtinta (cx_chan_t *c);
   93: extern void cxmint (cx_chan_t *c);
   94: extern timeout_t cxtimeout;
   95: #endif
   96: static void cxdown (cx_chan_t *c);
   97: static void cxup (cx_chan_t *c);
   98: 
   99: cx_board_t cxboard [NCX];           /* adapter state structures */
  100: cx_chan_t *cxchan [NCX*NCHAN];      /* unit to channel struct pointer */
  101: #if 0
  102: extern struct cdevsw cx_cdevsw;
  103: #endif
  104: static unsigned short irq_valid_values [] = { 3, 5, 7, 10, 11, 12, 15, 0 };
  105: static unsigned short drq_valid_values [] = { 5, 6, 7, 0 };
  106: static unsigned short port_valid_values [] = {
  107: 	0x240, 0x260, 0x280, 0x300, 0x320, 0x380, 0x3a0, 0,
  108: };
  109: 
  110: DECLARE_DUMMY_MODULE(if_cx);
  111: 
  112: /*
  113:  * Check that the value is contained in the list of correct values.
  114:  */
  115: static int valid (unsigned short value, unsigned short *list)
  116: {
  117: 	while (*list)
  118: 		if (value == *list++)
  119: 			return (1);
  120: 	return (0);
  121: }
  122: 
  123: /*
  124:  * Print the mbuf chain, for debug purposes only.
  125:  */
  126: static void printmbuf (struct mbuf *m)
  127: {
  128: 	printf ("mbuf:");
  129: 	for (; m; m=m->m_next) {
  130: 		if (m->m_flags & M_PKTHDR)
  131: 			printf (" HDR %d:", m->m_pkthdr.len);
  132: 		if (m->m_flags & M_EXT)
  133: 			printf (" EXT:");
  134: 		printf (" %d", m->m_len);
  135: 	}
  136: 	printf ("\n");
  137: }
  138: 
  139: /*
  140:  * Make an mbuf from data.
  141:  */
  142: static struct mbuf *makembuf (void *buf, unsigned len)
  143: {
  144: 	struct mbuf *m, *o, *p;
  145: 
  146: 	MGETHDR (m, M_DONTWAIT, MT_DATA);
  147: 	if (! m)
  148: 		return (0);
  149: 	if (len >= MINCLSIZE)
  150: 		MCLGET (m, M_DONTWAIT);
  151: 	m->m_pkthdr.len = len;
  152: 	m->m_len = 0;
  153: 
  154: 	p = m;
  155: 	while (len) {
  156: 		unsigned n = M_TRAILINGSPACE (p);
  157: 		if (n > len)
  158: 			n = len;
  159: 
  160: 		if (! n) {
  161: 			/* Allocate new mbuf. */
  162: 			o = p;
  163: 			MGET (p, M_DONTWAIT, MT_DATA);
  164: 			if (! p) {
  165: 				m_freem (m);
  166: 				return (0);
  167: 			}
  168: 			if (len >= MINCLSIZE)
  169: 				MCLGET (p, M_DONTWAIT);
  170: 			p->m_len = 0;
  171: 			o->m_next = p;
  172: 
  173: 			n = M_TRAILINGSPACE (p);
  174: 			if (n > len)
  175: 				n = len;
  176: 		}
  177: 
  178: 		bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
  179: 
  180: 		p->m_len += n;
  181: 		buf = (char *)buf + n;
  182: 		len -= n;
  183: 	}
  184: 	return (m);
  185: }
  186: 
  187: /*
  188:  * Test the presence of the adapter on the given i/o port.
  189:  */
  190: static int
  191: cxprobe (struct isa_device *id)
  192: {
  193: 	int unit = id->id_unit;
  194: 	int iobase = id->id_iobase;
  195: 	int irq = id->id_irq;
  196: 	int drq = id->id_drq;
  197: 	int irqnum;
  198: 	irqnum = ffs (irq) - 1;
  199: 
  200: 	print (("cx%d: probe iobase=0x%x irq=%d drq=%d\n",
  201: 		unit, iobase, irqnum, drq));
  202: 	if (! valid (irqnum, irq_valid_values)) {
  203: 		printf ("cx%d: Incorrect IRQ: %d\n", unit, irqnum);
  204: 		return (0);
  205: 	}
  206: 	if (! valid (iobase, port_valid_values)) {
  207: 		printf ("cx%d: Incorrect port address: 0x%x\n", unit, iobase);
  208: 		return (0);
  209: 	}
  210: 	if (! valid (drq, drq_valid_values)) {
  211: 		printf ("cx%d: Incorrect DMA channel: %d\n", unit, drq);
  212: 		return (0);
  213: 	}
  214: 	if (! cx_probe_board (iobase))
  215: 		return (0);
  216: 
  217: 	return (1);
  218: }
  219: 
  220: /*
  221:  * The adapter is present, initialize the driver structures.
  222:  */
  223: 
  224: static int
  225: cxattach (struct isa_device *id)
  226: {
  227: 	int unit = id->id_unit;
  228: 	int iobase = id->id_iobase;
  229: 	int irq = id->id_irq;
  230: 	int drq = id->id_drq;
  231: 	cx_board_t *b = cxboard + unit;
  232: 	int i;
  233: 	struct sppp *sp;
  234: 
  235: 	id->id_ointr = cxintr;
  236: 
  237: 	/* Initialize the board structure. */
  238: 	cx_init (b, unit, iobase, ffs(irq)-1, drq);
  239: 
  240: 	for (i=0; i<NCHAN; ++i) {
  241: 		cx_chan_t *c = b->chan + i;
  242: 		int u = b->num*NCHAN + i;
  243: 		cxchan[u] = c;
  244: 
  245: 		if (c->type == T_NONE)
  246: 			continue;
  247: 
  248: 		/* Allocate the buffer memory. */
  249: 		c->arbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
  250: 		c->brbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
  251: 		c->atbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
  252: 		c->btbuf = malloc (DMABUFSZ, M_DEVBUF, M_WAITOK);
  253: 
  254: #if 0
  255: 		/* All buffers should be located in lower 16M of memory! */
  256: 		/* XXX all buffers located where?  I don't think so! */
  257: 		if (!c->arbuf || !c->brbuf || !c->atbuf || !c->btbuf) {
  258: 			printf ("cx%d.%d: No memory for channel buffers\n",
  259: 				c->board->num, c->num);
  260: 			c->type = T_NONE;
  261: 		}
  262: #endif
  263: 
  264: 		switch (c->type) {
  265: 		case T_SYNC_RS232:
  266: 		case T_SYNC_V35:
  267: 		case T_SYNC_RS449:
  268: 		case T_UNIV_RS232:
  269: 		case T_UNIV_RS449:
  270: 		case T_UNIV_V35:
  271: 			c->ifp = malloc (IFSTRUCTSZ, M_DEVBUF, M_WAITOK | M_ZERO);
  272: 			c->master = c->ifp;
  273: 			c->ifp->if_softc = c;
  274: 			if_initname(c->ifp, "cx", u);
  275: 			c->ifp->if_mtu = PP_MTU;
  276: 			c->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
  277: 			c->ifp->if_ioctl = cxsioctl;
  278: 			c->ifp->if_start = (start_func_t) cxstart;
  279: 			c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog;
  280: 			/* Init routine is never called by upper level? */
  281: 			sppp_attach (c->ifp);
  282: 			if_attach (c->ifp);
  283: 			sp = (struct sppp*) c->ifp;
  284: 			/* If BPF is in the kernel, call the attach for it. */
  285: 			bpfattach (c->ifp, DLT_PPP, PPP_HEADER_LEN);
  286: 		}
  287: 	}
  288: 
  289: 	/* Reset the adapter. */
  290: 	cx_setup_board (b);
  291: 
  292: 	/* Activate the timeout routine. */
  293: 	if (unit == 0)
  294: 		timeout (cxtimeout, 0, hz*5);
  295: 
  296: 	printf ("cx%d: <Cronyx-%s>\n", unit, b->name);
  297: 	make_dev(&cx_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "cx%d", unit);
  298: 	return (1);
  299: }
  300: 
  301: struct isa_driver cxdriver = { cxprobe, cxattach, "cx" };
  302: 
  303: /*
  304:  * Process an ioctl request.
  305:  */
  306: static int
  307: cxsioctl (struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
  308: {
  309: 	cx_chan_t *q, *c = ifp->if_softc;
  310: 	int error, s, was_up, should_be_up;
  311: 
  312: 	/*
  313: 	 * No socket ioctls while the channel is in async mode.
  314: 	 */
  315: 	if (c->type==T_NONE || c->mode==M_ASYNC)
  316: 		return (EINVAL);
  317: 
  318: 	/*
  319: 	 * Socket ioctls on slave subchannels are not allowed.
  320: 	 */
  321: 	if (c->master != c->ifp)
  322: 		return (EBUSY);
  323: 
  324: 	was_up = (ifp->if_flags & IFF_RUNNING) != 0;
  325: 	error = sppp_ioctl (ifp, cmd, data);
  326: 	if (error)
  327: 		return (error);
  328: 
  329: 	print (("cxioctl (%d.%d, ", c->board->num, c->num));
  330: 	switch (cmd) {
  331: 	default:
  332: 		print (("0x%x)\n", cmd));
  333: 		return (0);
  334: 	case SIOCADDMULTI:
  335: 		print (("SIOCADDMULTI)\n"));
  336: 		return (0);
  337: 	case SIOCDELMULTI:
  338: 		print (("SIOCDELMULTI)\n"));
  339: 		return (0);
  340: 	case SIOCSIFFLAGS:
  341: 		print (("SIOCSIFFLAGS)\n"));
  342: 		break;
  343: 	case SIOCSIFADDR:
  344: 		print (("SIOCSIFADDR)\n"));
  345: 		break;
  346: 	}
  347: 
  348: 	/* We get here only in case of SIFFLAGS or SIFADDR. */
  349: 	s = splimp ();
  350: 	should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
  351: 	if (!was_up && should_be_up) {
  352: 		/* Interface goes up -- start it. */
  353: 		cxup (c);
  354: 
  355: 		/* Start all slave subchannels. */
  356: 		for (q=c->slaveq; q; q=q->slaveq)
  357: 			cxup (q);
  358: 
  359: 		cxstart (c->ifp);
  360: 	} else if (was_up && !should_be_up) {
  361: 		/* Interface is going down -- stop it. */
  362: 		cxdown (c);
  363: 
  364: 		/* Stop all slave subchannels. */
  365: 		for (q=c->slaveq; q; q=q->slaveq)
  366: 			cxdown (q);
  367: 
  368: 		/* Flush the interface output queue */
  369: 		if (! c->sopt.ext)
  370: 			sppp_flush (c->ifp);
  371: 	}
  372: 	splx (s);
  373: 	return (0);
  374: }
  375: 
  376: /*
  377:  * Stop the interface.  Called on splimp().
  378:  */
  379: static void
  380: cxdown (cx_chan_t *c)
  381: {
  382: 	unsigned short port = c->chip->port;
  383: 
  384: 	print (("cx%d.%d: cxdown\n", c->board->num, c->num));
  385: 
  386: 	/* The interface is down, stop it */
  387: 	c->ifp->if_flags &= ~IFF_OACTIVE;
  388: 
  389: 	/* Reset the channel (for sync modes only) */
  390: 		outb (CAR(port), c->num & 3);
  391: 		outb (STCR(port), STC_ABORTTX | STC_SNDSPC);
  392: 
  393: 	cx_setup_chan (c);
  394: }
  395: 
  396: /*
  397:  * Start the interface.  Called on splimp().
  398:  */
  399: static void
  400: cxup (cx_chan_t *c)
  401: {
  402: 	unsigned short port = c->chip->port;
  403: 
  404: 		/* The interface is up, start it */
  405: 	        print (("cx%d.%d: cxup\n", c->board->num, c->num));
  406: 
  407: 		/* Initialize channel, enable receiver and transmitter */
  408: 		cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
  409: 		/* Repeat the command, to avoid the rev.H bug */
  410: 		cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
  411: 
  412: 		/* Start receiver */
  413: 		outw (ARBCNT(port), DMABUFSZ);
  414: 		outb (ARBSTS(port), BSTS_OWN24);
  415: 		outw (BRBCNT(port), DMABUFSZ);
  416: 		outb (BRBSTS(port), BSTS_OWN24);
  417: 
  418: 		/* Raise DTR and RTS */
  419: 		cx_chan_dtr (c, 1);
  420: 		cx_chan_rts (c, 1);
  421: 
  422: 		/* Enable interrupts */
  423: 		outb (IER(port), IER_RXD | IER_TXD);
  424: }
  425: 
  426: /*
  427:  * Fill transmitter buffer with data.
  428:  */
  429: static void 
  430: cxput (cx_chan_t *c, char b)
  431: {
  432: 	struct mbuf *m;
  433: 	unsigned char *buf;
  434: 	unsigned short port = c->chip->port, len, cnt_port, sts_port;
  435: 
  436: 	/* Choose the buffer. */
  437: 	if (b == 'A') {
  438: 		buf      = c->atbuf;
  439: 		cnt_port = ATBCNT(port);
  440: 		sts_port = ATBSTS(port);
  441: 	} else {
  442: 		buf      = c->btbuf;
  443: 		cnt_port = BTBCNT(port);
  444: 		sts_port = BTBSTS(port);
  445: 	}
  446: 
  447: 	/* Is it busy? */
  448: 	if (inb (sts_port) & BSTS_OWN24) {
  449: 		if (c->ifp->if_flags & IFF_DEBUG)
  450: 			print (("cx%d.%d: tbuf %c already busy, bsts=%b\n",
  451: 				c->board->num, c->num, b,
  452: 				inb (sts_port), BSTS_BITS));
  453: 		goto ret;
  454: 	}
  455: 
  456: 	/* Get the packet to send. */
  457: 	m = sppp_dequeue (c->master);
  458: 	if (! m)
  459: 		return;
  460: 	len = m->m_pkthdr.len;
  461: 
  462: 	/* Count the transmitted bytes to the subchannel, not the master. */
  463: 	c->master->if_obytes -= len + 3;
  464: 	c->ifp->if_obytes += len + 3;
  465: 	c->stat->obytes += len + 3;
  466: 
  467: 	if (len >= DMABUFSZ) {
  468: 		printf ("cx%d.%d: too long packet: %d bytes: ",
  469: 			c->board->num, c->num, len);
  470: 		printmbuf (m);
  471: 		m_freem (m);
  472: 		return;
  473: 	}
  474: 	m_copydata (m, 0, len, buf);
  475: 	if (c->ifp->if_bpf)
  476: 		bpf_mtap (c->ifp, m);
  477: 	m_freem (m);
  478: 
  479: 	/* Start transmitter. */
  480: 	outw (cnt_port, len);
  481: 	outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24);
  482: 
  483: 	if (c->ifp->if_flags & IFF_DEBUG)
  484: 		print (("cx%d.%d: enqueue %d bytes to %c\n",
  485: 			c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'));
  486: ret:
  487: 	c->ifp->if_flags |= IFF_OACTIVE;
  488: }
  489: 
  490: /*
  491:  * Start output on the (slave) interface.  Get another datagram to send
  492:  * off of the interface queue, and copy it to the interface
  493:  * before starting the output.
  494:  */
  495: static void
  496: cxsend (cx_chan_t *c)
  497: {
  498: 	unsigned short port = c->chip->port;
  499: 
  500: 	if (c->ifp->if_flags & IFF_DEBUG)
  501: 		print (("cx%d.%d: cxsend\n", c->board->num, c->num));
  502: 
  503: 	/* No output if the interface is down. */
  504: 	if (! (c->ifp->if_flags & IFF_RUNNING))
  505: 		return;
  506: 
  507: 	/* Set the current channel number. */
  508: 	outb (CAR(port), c->num & 3);
  509: 
  510: 	/* Determine the buffer order. */
  511: 	if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
  512: 		cxput (c, 'B');
  513: 		cxput (c, 'A');
  514: 	} else {
  515: 		cxput (c, 'A');
  516: 		cxput (c, 'B');
  517: 	}
  518: 
  519: 	/* Set up transmit timeout. */
  520: 	if (c->master->if_flags & IFF_OACTIVE)
  521: 		c->master->if_timer = TXTIMEOUT;
  522: 
  523: 	/*
  524: 	 * Enable TXMPTY interrupt,
  525: 	 * to catch the case when the second buffer is empty.
  526: 	 */
  527: 	if ((inb (ATBSTS(port)) & BSTS_OWN24) &&
  528: 	    (inb (BTBSTS(port)) & BSTS_OWN24)) {
  529: 		outb (IER(port), IER_RXD | IER_TXD | IER_TXMPTY);
  530: 	} else
  531: 		outb (IER(port), IER_RXD | IER_TXD);
  532: }
  533: 
  534: /*
  535:  * Start output on the (master) interface and all slave interfaces.
  536:  * Always called on splimp().
  537:  */
  538: static void
  539: cxstart (struct ifnet *ifp)
  540: {
  541: 	cx_chan_t *q, *c = ifp->if_softc;
  542: 
  543: 	if (c->ifp->if_flags & IFF_DEBUG)
  544: 		print (("cx%d.%d: cxstart\n", c->board->num, c->num));
  545: 
  546: 	/* Start the master subchannel. */
  547: 	cxsend (c);
  548: 
  549: 	/* Start all slave subchannels. */
  550: 	if (c->slaveq && ! sppp_isempty (c->master))
  551: 		for (q=c->slaveq; q; q=q->slaveq)
  552: 			if ((q->ifp->if_flags & IFF_RUNNING) &&
  553: 			    ! (q->ifp->if_flags & IFF_OACTIVE))
  554: 				cxsend (q);
  555: }
  556: 
  557: /*
  558:  * Handle transmit timeouts.
  559:  * Recover after lost transmit interrupts.
  560:  * Always called on splimp().
  561:  */
  562: static void
  563: cxwatchdog (struct ifnet *ifp)
  564: {
  565: 	cx_chan_t *q, *c = ifp->if_softc;
  566: 
  567: 	if (! (ifp->if_flags & IFF_RUNNING))
  568: 		return;
  569: 	if (ifp->if_flags & IFF_DEBUG)
  570: 		printf ("cx%d.%d: device timeout\n", c->board->num, c->num);
  571: 
  572: 	cxdown (c);
  573: 	for (q=c->slaveq; q; q=q->slaveq)
  574: 		cxdown (q);
  575: 
  576: 	cxup (c);
  577: 	for (q=c->slaveq; q; q=q->slaveq)
  578: 		cxup (q);
  579: 
  580: 		cxstart (ifp);
  581: }
  582: 
  583: /*
  584:  * Handle receive interrupts, including receive errors and
  585:  * receive timeout interrupt.
  586:  */
  587: static void 
  588: cxrinth (cx_chan_t *c)
  589: {
  590: 	unsigned short port = c->chip->port;
  591: 	unsigned short len, risr = inw (RISR(port));
  592: 
  593: 	/* Receive errors. */
  594: 	if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) {
  595: 		if (c->ifp->if_flags & IFF_DEBUG)
  596: 			printf ("cx%d.%d: receive error, risr=%b\n",
  597: 				c->board->num, c->num, risr, RISH_BITS);
  598: 		++c->ifp->if_ierrors;
  599: 		++c->stat->ierrs;
  600: 		if (risr & RIS_OVERRUN)
  601: 			++c->ifp->if_collisions;
  602: 	} else if (risr & RIS_EOBUF) {
  603: 		if (c->ifp->if_flags & IFF_DEBUG)
  604: 			print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
  605: 				c->board->num, c->num, risr, RISH_BITS,
  606: 				inb (ARBSTS(port)), BSTS_BITS,
  607: 				inb (BRBSTS(port)), BSTS_BITS));
  608: 		++c->stat->ipkts;
  609: 
  610: 		/* Handle received data. */
  611: 		len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
  612: 		c->stat->ibytes += len;
  613: 		if (len > DMABUFSZ) {
  614: 			/* Fatal error: actual DMA transfer size
  615: 			 * exceeds our buffer size.  It could be caused
  616: 			 * by incorrectly programmed DMA register or
  617: 			 * hardware fault.  Possibly, should panic here. */
  618: 			printf ("cx%d.%d: panic! DMA buffer overflow: %d bytes\n",
  619: 			       c->board->num, c->num, len);
  620: 			++c->ifp->if_ierrors;
  621: 		} else if (! (risr & RIS_EOFR)) {
  622: 			/* The received frame does not fit in the DMA buffer.
  623: 			 * It could be caused by serial lie noise,
  624: 			 * or if the peer has too big MTU. */
  625: 			if (c->ifp->if_flags & IFF_DEBUG)
  626: 				printf ("cx%d.%d: received frame length exceeds MTU, risr=%b\n",
  627: 					c->board->num, c->num, risr, RISH_BITS);
  628: 			++c->ifp->if_ierrors;
  629: 		} else {
  630: 			/* Valid frame received. */
  631: 			if (c->ifp->if_flags & IFF_DEBUG)
  632: 				print (("cx%d.%d: hdlc received %d bytes\n",
  633: 				c->board->num, c->num, len));
  634: 			cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len);
  635: 			++c->ifp->if_ipackets;
  636: 		}
  637: 	} else if (c->ifp->if_flags & IFF_DEBUG) {
  638: 		print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n",
  639: 			c->board->num, c->num, risr, RISH_BITS));
  640: 		++c->stat->ierrs;
  641: 	}
  642: 
  643: 	/* Restart receiver. */
  644: 	if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
  645: 		outw (ARBCNT(port), DMABUFSZ);
  646: 		outb (ARBSTS(port), BSTS_OWN24);
  647: 	}
  648: 	if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
  649: 		outw (BRBCNT(port), DMABUFSZ);
  650: 		outb (BRBSTS(port), BSTS_OWN24);
  651: 	}
  652: }
  653: 
  654: /*
  655:  * Handle transmit interrupt.
  656:  */
  657: static int
  658: cxtinth (cx_chan_t *c)
  659: {
  660: 	unsigned short port = c->chip->port;
  661: 	unsigned char tisr = inb (TISR(port));
  662: 	unsigned char teoir = 0;
  663: 
  664: 	c->ifp->if_flags &= ~IFF_OACTIVE;
  665: 	if (c->ifp == c->master)
  666: 		c->ifp->if_timer = 0;
  667: 
  668: 	if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) {
  669: 		/* if (c->ifp->if_flags & IFF_DEBUG) */
  670: 			print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n",
  671: 				c->board->num, c->num, tisr, TIS_BITS,
  672: 				inb (ATBSTS(port)), BSTS_BITS,
  673: 				inb (BTBSTS(port)), BSTS_BITS));
  674: 		++c->ifp->if_oerrors;
  675: 		++c->stat->oerrs;
  676: 
  677: 		/* Terminate the failed buffer. */
  678: 		/* teoir = TEOI_TERMBUFF; */
  679: 	} else if (c->ifp->if_flags & IFF_DEBUG)
  680: 		print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
  681: 			c->board->num, c->num, tisr, TIS_BITS,
  682: 			inb (ATBSTS(port)), BSTS_BITS,
  683: 			inb (BTBSTS(port)), BSTS_BITS));
  684: 
  685: 	if (tisr & TIS_EOFR) {
  686: 		++c->ifp->if_opackets;
  687: 		++c->stat->opkts;
  688: 	}
  689: 
  690: 	/* Start output on the (sub-) channel. */
  691: 	cxsend (c);
  692: 
  693: 	return (teoir);
  694: }
  695: 
  696: static void
  697: cxintr (int bnum)
  698: {
  699: 	cx_board_t *b = cxboard + bnum;
  700: 	while (! (inw (BSR(b->port)) & BSR_NOINTR)) {
  701: 		/* Acknowledge the interrupt to enter the interrupt context. */
  702: 		/* Read the local interrupt vector register. */
  703: 		unsigned char livr = inb (IACK(b->port, BRD_INTR_LEVEL));
  704: 		cx_chan_t *c = b->chan + (livr>>2 & 0xf);
  705: 		unsigned short port = c->chip->port;
  706: 		unsigned short eoiport = REOIR(port);
  707: 		unsigned char eoi = 0;
  708: 
  709: 		if (c->type == T_NONE) {
  710: 			printf ("cx%d.%d: unexpected interrupt, livr=0x%x\n",
  711: 				c->board->num, c->num, livr);
  712: 			continue;       /* incorrect channel number? */
  713: 		}
  714: 		/* print (("cx%d.%d: interrupt, livr=0x%x\n",
  715: 			c->board->num, c->num, livr)); */
  716: 
  717: 		/* Clear RTS to stop receiver data flow while we are busy
  718: 		 * processing the interrupt, thus avoiding underruns. */
  719: 		if (! c->sopt.norts) {
  720: 			outb (MSVR_RTS(port), 0);
  721: 			c->rts = 0;
  722: 		}
  723: 
  724: 		switch (livr & 3) {
  725: 		case LIV_EXCEP:         /* receive exception */
  726: 		case LIV_RXDATA:        /* receive interrupt */
  727: 			++c->stat->rintr;
  728: 			switch (c->mode) {
  729: 			case M_ASYNC: eoi = cxrinta (c); break;
  730: 			case M_HDLC:  cxrinth (c);       break;
  731: 			default:;       /* No bisync and X.21 yet */
  732: 			}
  733: 			break;
  734: 		case LIV_TXDATA:        /* transmit interrupt */
  735: 			++c->stat->tintr;
  736: 			eoiport = TEOIR(port);
  737: 			switch (c->mode) {
  738: 			case M_ASYNC: cxtinta (c);       break;
  739: 			case M_HDLC:  eoi = cxtinth (c); break;
  740: 			default:;       /* No bisync and X.21 yet */
  741: 			}
  742: 			break;
  743: 		case LIV_MODEM:         /* modem/timer interrupt */
  744: 			++c->stat->mintr;
  745: 			eoiport = MEOIR(port);
  746: 			cxmint (c);
  747: 			break;
  748: 		}
  749: 
  750: 		/* Raise RTS for this channel if and only if
  751: 		 * both receive buffers are empty. */
  752: 		if (! c->sopt.norts && (inb (CSR(port)) & CSRA_RXEN) &&
  753: 		    (inb (ARBSTS(port)) & BSTS_OWN24) &&
  754: 		    (inb (BRBSTS(port)) & BSTS_OWN24)) {
  755: 			outb (MSVR_RTS(port), MSV_RTS);
  756: 			c->rts = 1;
  757: 		}
  758: 
  759: 		/* Exit from interrupt context. */
  760: 		outb (eoiport, eoi);
  761: 
  762: 		/* Master channel - start output on all idle subchannels. */
  763: 		if (c->master == c->ifp && c->slaveq &&
  764: 		    (livr & 3) == LIV_TXDATA && c->mode == M_HDLC &&
  765: 		    ! sppp_isempty (c->ifp)) {
  766: 			cx_chan_t *q;
  767: 
  768: 			for (q=c->slaveq; q; q=q->slaveq)
  769: 				if ((q->ifp->if_flags & IFF_RUNNING) &&
  770: 				    ! (q->ifp->if_flags & IFF_OACTIVE))
  771: 					cxsend (q);
  772: 		}
  773: 	}
  774: }
  775: 
  776: /*
  777:  * Process the received packet.
  778:  */
  779: static void 
  780: cxinput (cx_chan_t *c, void *buf, unsigned len)
  781: {
  782: 	/* Make an mbuf. */
  783: 	struct mbuf *m = makembuf (buf, len);
  784: 	if (! m) {
  785: 		if (c->ifp->if_flags & IFF_DEBUG)
  786: 			printf ("cx%d.%d: no memory for packet\n",
  787: 				c->board->num, c->num);
  788: 		++c->ifp->if_iqdrops;
  789: 		return;
  790: 	}
  791: 	m->m_pkthdr.rcvif = c->master;
  792: #ifdef DEBUG
  793: 	if (c->ifp->if_flags & IFF_DEBUG)
  794: 	printmbuf (m);
  795: #endif
  796: 
  797: 	/*
  798: 	 * Check if there's a BPF listener on this interface.
  799: 	 * If so, hand off the raw packet to bpf.
  800: 	 */
  801: 	if (c->ifp->if_bpf)
  802: 		bpf_tap (c->ifp, buf, len);
  803: 
  804: 	/* Count the received bytes to the subchannel, not the master. */
  805: 	c->master->if_ibytes -= len + 3;
  806: 	c->ifp->if_ibytes += len + 3;
  807: 
  808: 	sppp_input (c->master, m);
  809: }
  810: 
  811: void cxswitch (cx_chan_t *c, cx_soft_opt_t new)
  812: {
  813: 	new.ext = 0;
  814: 	if (! new.ext) {
  815: 		struct sppp *sp = (struct sppp*) c->ifp;
  816: 
  817: #if 0 /* Doesn't work this way any more 990402 /phk */
  818: 		if (new.cisco)
  819: 			sp->pp_flags |= PP_CISCO;
  820: 		else
  821: 			sp->pp_flags &= ~PP_CISCO;
  822: #endif
  823: 		if (new.keepalive)
  824: 			sp->pp_flags |= PP_KEEPALIVE;
  825: 		else
  826: 			sp->pp_flags &= ~PP_KEEPALIVE;
  827: 	}
  828: 	c->sopt = new;
  829: }