File:  [DragonFly] / src / sys / net / i4b / driver / i4b_rbch.c
Revision 1.10: download - view: text, annotated - select for diffs
Thu May 13 23:49:24 2004 UTC (9 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
    3:  *
    4:  * Redistribution and use in source and binary forms, with or without
    5:  * modification, are permitted provided that the following conditions
    6:  * are met:
    7:  * 1. Redistributions of source code must retain the above copyright
    8:  *    notice, this list of conditions and the following disclaimer.
    9:  * 2. Redistributions in binary form must reproduce the above copyright
   10:  *    notice, this list of conditions and the following disclaimer in the
   11:  *    documentation and/or other materials provided with the distribution.
   12:  *
   13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23:  * SUCH DAMAGE.
   24:  *
   25:  *---------------------------------------------------------------------------
   26:  *
   27:  *	i4b_rbch.c - device driver for raw B channel data
   28:  *	---------------------------------------------------
   29:  *
   30:  * $FreeBSD: src/sys/i4b/driver/i4b_rbch.c,v 1.10.2.3 2001/08/12 16:22:48 hm Exp $
   31:  * $DragonFly: src/sys/net/i4b/driver/i4b_rbch.c,v 1.10 2004/05/13 23:49:24 dillon Exp $
   32:  *
   33:  *	last edit-date: [Sat Aug 11 18:06:57 2001]
   34:  *
   35:  *---------------------------------------------------------------------------*/
   36: 
   37: #include "use_i4brbch.h"
   38: 
   39: #if NI4BRBCH > 0
   40: 
   41: #include <sys/param.h>
   42: #include <sys/systm.h>
   43: 
   44: #include <sys/conf.h>
   45: #include <sys/uio.h>
   46: #include <sys/kernel.h>
   47: #include <sys/mbuf.h>
   48: #include <sys/socket.h>
   49: #include <net/if.h>
   50: #include <sys/tty.h>
   51: 
   52: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
   53: #include <sys/callout.h>
   54: #endif
   55: 
   56: #if defined (__NetBSD__) || defined (__OpenBSD__)
   57: extern cc_t ttydefchars;
   58: #define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
   59: #endif
   60: 
   61: #if defined(__DragonFly__) || defined(__FreeBSD__)
   62: 
   63: #ifdef DEVFS
   64: #include <sys/devfsext.h>
   65: #endif
   66: 
   67: #endif /* __FreeBSD__ */
   68: 
   69: #ifdef __NetBSD__
   70: #include <sys/filio.h>
   71: #endif
   72: 
   73: #if defined(__DragonFly__) || defined(__FreeBSD__)
   74: #include <net/i4b/include/machine/i4b_ioctl.h>
   75: #include <net/i4b/include/machine/i4b_rbch_ioctl.h>
   76: #include <net/i4b/include/machine/i4b_debug.h>
   77: #else
   78: #include <i4b/i4b_ioctl.h>
   79: #include <i4b/i4b_rbch_ioctl.h>
   80: #include <i4b/i4b_debug.h>
   81: #endif
   82: 
   83: #include "../include/i4b_global.h"
   84: #include "../include/i4b_mbuf.h"
   85: #include "../include/i4b_l3l4.h"
   86: #include "../layer4/i4b_l4.h"
   87: 
   88: #ifdef __bsdi__
   89: #include <sys/device.h>
   90: #endif
   91: 
   92: #ifdef OS_USES_POLL
   93: #include <sys/ioccom.h>
   94: #include <sys/poll.h>
   95: #else
   96: #include <sys/fcntl.h>
   97: #include <sys/ioctl.h>
   98: #endif
   99: 
  100: #if defined(__DragonFly__) || defined(__FreeBSD__)
  101: #include <sys/filio.h>
  102: #endif
  103: 
  104: static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
  105: static isdn_link_t *isdn_linktab[NI4BRBCH];
  106: 
  107: #define I4BRBCHACCT		1 	/* enable accounting messages */
  108: #define	I4BRBCHACCTINTVL	2	/* accounting msg interval in secs */
  109: 
  110: static struct rbch_softc {
  111: 
  112: 	int sc_unit;			/* unit number 		*/
  113: 
  114: 	int sc_devstate;		/* state of driver	*/
  115: #define ST_IDLE		0x00
  116: #define ST_CONNECTED	0x01
  117: #define ST_ISOPEN	0x02
  118: #define ST_RDWAITDATA	0x04
  119: #define ST_WRWAITEMPTY	0x08
  120: #define ST_NOBLOCK	0x10
  121: 
  122: 	int sc_bprot;			/* B-ch protocol used	*/
  123: 
  124: 	call_desc_t *sc_cd;		/* Call Descriptor */
  125: 
  126: 	struct termios it_in;
  127: 
  128: 	struct ifqueue sc_hdlcq;	/* hdlc read queue	*/
  129: #define I4BRBCHMAXQLEN	10
  130: 
  131: 	struct selinfo selp;		/* select / poll	*/
  132: 
  133: #if I4BRBCHACCT
  134: #if defined(__DragonFly__) || defined(__FreeBSD__)
  135: 	struct callout_handle sc_callout;
  136: #endif	
  137: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
  138: 	struct callout	sc_callout;
  139: #endif
  140: 
  141: 	int		sc_iinb;	/* isdn driver # of inbytes	*/
  142: 	int		sc_ioutb;	/* isdn driver # of outbytes	*/
  143: 	int		sc_linb;	/* last # of bytes rx'd		*/
  144: 	int		sc_loutb;	/* last # of bytes tx'd 	*/
  145: 	int		sc_fn;		/* flag, first null acct	*/
  146: #endif	
  147: } rbch_softc[NI4BRBCH];
  148: 
  149: static void rbch_rx_data_rdy(int unit);
  150: static void rbch_tx_queue_empty(int unit);
  151: static void rbch_connect(int unit, void *cdp);
  152: static void rbch_disconnect(int unit, void *cdp);
  153: static void rbch_init_linktab(int unit);
  154: static void rbch_clrq(int unit);
  155: 
  156: #if !defined(__DragonFly__) && !defined(__FreeBSD__)
  157: #define PDEVSTATIC	/* - not static - */
  158: #define IOCTL_CMD_T	u_long
  159: void i4brbchattach (void);
  160: int i4brbchopen (dev_t dev, int flag, int fmt, struct proc *p);
  161: int i4brbchclose (dev_t dev, int flag, int fmt, struct proc *p);
  162: int i4brbchread (dev_t dev, struct uio *uio, int ioflag);
  163: int i4brbchwrite (dev_t dev, struct uio *uio, int ioflag);
  164: int i4brbchioctl (dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct proc* pr);
  165: #ifdef OS_USES_POLL
  166: int i4brbchpoll (dev_t dev, int events, struct proc *p);
  167: #else
  168: PDEVSTATIC int i4brbchselect (dev_t dev, int rw, struct proc *p);
  169: #endif
  170: #endif
  171: 
  172: #if defined(__DragonFly__) || (BSD > 199306 && defined(__FreeBSD__))
  173: #define PDEVSTATIC	static
  174: #define IOCTL_CMD_T	u_long
  175: 
  176: PDEVSTATIC d_open_t i4brbchopen;
  177: PDEVSTATIC d_close_t i4brbchclose;
  178: PDEVSTATIC d_read_t i4brbchread;
  179: PDEVSTATIC d_read_t i4brbchwrite;
  180: PDEVSTATIC d_ioctl_t i4brbchioctl;
  181: 
  182: #ifdef OS_USES_POLL
  183: PDEVSTATIC d_poll_t i4brbchpoll;
  184: #define POLLFIELD	i4brbchpoll
  185: #else
  186: PDEVSTATIC d_select_t i4brbchselect;
  187: #define POLLFIELD	i4brbchselect
  188: #endif
  189: 
  190: #define CDEV_MAJOR 57
  191: 
  192: static struct cdevsw i4brbch_cdevsw = {
  193: 	/* name */      "i4brbch",
  194: 	/* maj */       CDEV_MAJOR,
  195: 	/* flags */     0,
  196: 	/* port */	NULL,
  197: 	/* clone */	NULL,
  198: 
  199: 	/* open */      i4brbchopen,
  200: 	/* close */     i4brbchclose,
  201: 	/* read */      i4brbchread,
  202: 	/* write */     i4brbchwrite,
  203: 	/* ioctl */     i4brbchioctl,
  204: 	/* poll */      POLLFIELD,
  205: 	/* mmap */      nommap,
  206: 	/* strategy */  nostrategy,
  207: 	/* dump */      nodump,
  208: 	/* psize */     nopsize
  209: };
  210: 
  211: static void i4brbchattach(void *);
  212: PSEUDO_SET(i4brbchattach, i4b_rbch);
  213: 
  214: /*===========================================================================*
  215:  *			DEVICE DRIVER ROUTINES
  216:  *===========================================================================*/
  217: 
  218: /*---------------------------------------------------------------------------*
  219:  *	initialization at kernel load time
  220:  *---------------------------------------------------------------------------*/
  221: static void
  222: i4brbchinit(void *unused)
  223: {
  224: 	cdevsw_add(&i4brbch_cdevsw);
  225: }
  226: 
  227: SYSINIT(i4brbchdev, SI_SUB_DRIVERS,
  228: 	SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL);
  229: 
  230: #endif /* BSD > 199306 && defined(__FreeBSD__) */
  231: 
  232: #ifdef __bsdi__
  233: int i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux);
  234: void dummy_i4brbchattach(struct device*, struct device *, void *);
  235: 
  236: #define CDEV_MAJOR 61
  237: 
  238: static struct cfdriver i4brbchcd =
  239: 	{ NULL, "i4brbch", i4brbchmatch, dummy_i4brbchattach, DV_DULL,
  240: 	  sizeof(struct cfdriver) };
  241: struct devsw i4brbchsw = 
  242: 	{ &i4brbchcd,
  243: 	  i4brbchopen,	i4brbchclose,	i4brbchread,	i4brbchwrite,
  244: 	  i4brbchioctl,	seltrue,	nommap,		nostrat,
  245: 	  nodump,	nopsize,	0,		nostop
  246: };
  247: 
  248: int
  249: i4brbchmatch(struct device *parent, struct cfdata *cf, void *aux)
  250: {
  251: 	printf("i4brbchmatch: aux=0x%x\n", aux);
  252: 	return 1;
  253: }
  254: void
  255: dummy_i4brbchattach(struct device *parent, struct device *self, void *aux)
  256: {
  257: 	printf("dummy_i4brbchattach: aux=0x%x\n", aux);
  258: }
  259: #endif /* __bsdi__ */
  260: 
  261: /*---------------------------------------------------------------------------*
  262:  *	interface attach routine
  263:  *---------------------------------------------------------------------------*/
  264: PDEVSTATIC void
  265: #if defined(__DragonFly__) || defined(__FreeBSD__)
  266: i4brbchattach(void *dummy)
  267: #else
  268: i4brbchattach()
  269: #endif
  270: {
  271: 	int i;
  272: 
  273: #ifndef HACK_NO_PSEUDO_ATTACH_MSG
  274: 	printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
  275: #endif
  276: 	
  277: 	for(i=0; i < NI4BRBCH; i++)
  278: 	{
  279: #if defined(__DragonFly__) || defined(__FreeBSD__)
  280: 		make_dev(&i4brbch_cdevsw, i,
  281: 			UID_ROOT, GID_WHEEL, 0600, "i4brbch%d", i);
  282: #endif
  283: 
  284: #if I4BRBCHACCT
  285: #if defined(__DragonFly__) || defined(__FreeBSD__)
  286: 		callout_handle_init(&rbch_softc[i].sc_callout);
  287: #endif
  288: #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
  289: 		callout_init(&rbch_softc[i].sc_callout);
  290: #endif
  291: 		rbch_softc[i].sc_fn = 1;
  292: #endif
  293: 		rbch_softc[i].sc_unit = i;
  294: 		rbch_softc[i].sc_devstate = ST_IDLE;
  295: 		rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
  296: #if defined(__FreeBSD__) && __FreeBSD__ > 4
  297: 		mtx_init(&rbch_softc[i].sc_hdlcq.ifq_mtx, "i4b_rbch", MTX_DEF);
  298: #endif		
  299: 		rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
  300: 		termioschars(&rbch_softc[i].it_in);
  301: 		rbch_init_linktab(i);
  302: 	}
  303: }
  304: 
  305: /*---------------------------------------------------------------------------*
  306:  *	open rbch device
  307:  *---------------------------------------------------------------------------*/
  308: PDEVSTATIC int
  309: i4brbchopen(dev_t dev, int flag, int fmt, struct thread *td)
  310: {
  311: 	int unit = minor(dev);
  312: 	
  313: 	if(unit >= NI4BRBCH)
  314: 		return(ENXIO);
  315: 
  316: 	if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
  317: 		return(EBUSY);
  318: 
  319: #if 0
  320: 	rbch_clrq(unit);
  321: #endif
  322: 	
  323: 	rbch_softc[unit].sc_devstate |= ST_ISOPEN;		
  324: 
  325: 	NDBGL4(L4_RBCHDBG, "unit %d, open", unit);	
  326: 
  327: 	return(0);
  328: }
  329: 
  330: /*---------------------------------------------------------------------------*
  331:  *	close rbch device
  332:  *---------------------------------------------------------------------------*/
  333: PDEVSTATIC int
  334: i4brbchclose(dev_t dev, int flag, int fmt, struct thread *td)
  335: {
  336: 	int unit = minor(dev);
  337: 	struct rbch_softc *sc = &rbch_softc[unit];
  338: 	
  339: 	if(sc->sc_devstate & ST_CONNECTED)
  340: 		i4b_l4_drvrdisc(BDRV_RBCH, unit);
  341: 
  342: 	sc->sc_devstate &= ~ST_ISOPEN;		
  343: 
  344: 	rbch_clrq(unit);
  345: 	
  346: 	NDBGL4(L4_RBCHDBG, "unit %d, closed", unit);
  347: 	
  348: 	return(0);
  349: }
  350: 
  351: /*---------------------------------------------------------------------------*
  352:  *	read from rbch device
  353:  *---------------------------------------------------------------------------*/
  354: PDEVSTATIC int
  355: i4brbchread(dev_t dev, struct uio *uio, int ioflag)
  356: {
  357: 	struct mbuf *m;
  358: 	int error = 0;
  359: 	int unit = minor(dev);
  360: 	struct ifqueue *iqp;
  361: 	struct rbch_softc *sc = &rbch_softc[unit];
  362: 
  363: 	CRIT_VAR;
  364: 	
  365: 	NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit);
  366: 	
  367: 	CRIT_BEG;
  368: 	if(!(sc->sc_devstate & ST_ISOPEN))
  369: 	{
  370: 		CRIT_END;
  371: 		NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit);
  372: 		return(EIO);
  373: 	}
  374: 
  375: 	if((sc->sc_devstate & ST_NOBLOCK))
  376: 	{
  377: 		if(!(sc->sc_devstate & ST_CONNECTED)) {
  378: 			CRIT_END;
  379: 			return(EWOULDBLOCK);
  380: 		}
  381: 
  382: 		if(sc->sc_bprot == BPROT_RHDLC)
  383: 			iqp = &sc->sc_hdlcq;
  384: 		else
  385: 			iqp = isdn_linktab[unit]->rx_queue;	
  386: 
  387: 		if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) {
  388: 			CRIT_END;
  389: 			return(EWOULDBLOCK);
  390: 	}
  391: 	}
  392: 	else
  393: 	{
  394: 		while(!(sc->sc_devstate & ST_CONNECTED))
  395: 		{
  396: 			NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit);
  397: 		
  398: 			if((error = tsleep((caddr_t) &rbch_softc[unit],
  399: 					       PCATCH, "rrrbch", 0 )) != 0)
  400: 			{
  401: 				CRIT_END;
  402: 				NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error);
  403: 				return(error);
  404: 			}
  405: 		}
  406: 
  407: 		if(sc->sc_bprot == BPROT_RHDLC)
  408: 			iqp = &sc->sc_hdlcq;
  409: 		else
  410: 			iqp = isdn_linktab[unit]->rx_queue;	
  411: 
  412: 		while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN))
  413: 		{
  414: 			sc->sc_devstate |= ST_RDWAITDATA;
  415: 		
  416: 			NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit);
  417: 		
  418: 			if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
  419: 					   PCATCH, "rrbch", 0 )) != 0)
  420: 			{
  421: 				CRIT_END;
  422: 				NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error);
  423: 				sc->sc_devstate &= ~ST_RDWAITDATA;
  424: 				return(error);
  425: 			}
  426: 		}
  427: 	}
  428: 
  429: 	IF_DEQUEUE(iqp, m);
  430: 
  431: 	NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len);
  432: 	
  433: 	if(m && m->m_len)
  434: 	{
  435: 		error = uiomove(m->m_data, m->m_len, uio);
  436: 	}
  437: 	else
  438: 	{
  439: 		NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error);
  440: 		error = EIO;
  441: 	}
  442: 		
  443: 	if(m)
  444: 		i4b_Bfreembuf(m);
  445: 
  446: 	CRIT_END;
  447: 
  448: 	return(error);
  449: }
  450: 
  451: /*---------------------------------------------------------------------------*
  452:  *	write to rbch device
  453:  *---------------------------------------------------------------------------*/
  454: PDEVSTATIC int
  455: i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
  456: {
  457: 	struct mbuf *m;
  458: 	int error = 0;
  459: 	int unit = minor(dev);
  460: 	struct rbch_softc *sc = &rbch_softc[unit];
  461: 
  462: 	CRIT_VAR;
  463: 	
  464: 	NDBGL4(L4_RBCHDBG, "unit %d, write", unit);	
  465: 
  466: 	CRIT_BEG;
  467: 	if(!(sc->sc_devstate & ST_ISOPEN))
  468: 	{
  469: 		NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit);
  470: 		CRIT_END;
  471: 		return(EIO);
  472: 	}
  473: 
  474: 	if((sc->sc_devstate & ST_NOBLOCK))
  475: 	{
  476: 		if(!(sc->sc_devstate & ST_CONNECTED)) {
  477: 			CRIT_END;
  478: 			return(EWOULDBLOCK);
  479: 		}
  480: 		if(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) {
  481: 			CRIT_END;
  482: 			return(EWOULDBLOCK);
  483: 	}
  484: 	}
  485: 	else
  486: 	{
  487: 		while(!(sc->sc_devstate & ST_CONNECTED))
  488: 		{
  489: 			NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit);
  490: 		
  491: 			error = tsleep((caddr_t) &rbch_softc[unit],
  492: 						   PCATCH, "wrrbch", 0 );
  493: 			if(error == ERESTART) {
  494: 				CRIT_END;
  495: 				return (ERESTART);
  496: 			}
  497: 			else if(error == EINTR)
  498: 			{
  499: 				CRIT_END;
  500: 				NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit);
  501: 				return(EINTR);
  502: 			}
  503: 			else if(error)
  504: 			{
  505: 				CRIT_END;
  506: 				NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error);
  507: 				return(error);
  508: 			}
  509: 			tsleep((caddr_t) &rbch_softc[unit], PCATCH, "xrbch", (hz*1));
  510: 		}
  511: 
  512: 		while(_IF_QFULL(isdn_linktab[unit]->tx_queue) && (sc->sc_devstate & ST_ISOPEN))
  513: 		{
  514: 			sc->sc_devstate |= ST_WRWAITEMPTY;
  515: 
  516: 			NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit);
  517: 		
  518: 			if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
  519: 					    PCATCH, "wrbch", 0)) != 0) {
  520: 				sc->sc_devstate &= ~ST_WRWAITEMPTY;
  521: 				if(error == ERESTART)
  522: 				{
  523: 					CRIT_END;
  524: 					return(ERESTART);
  525: 				}
  526: 				else if(error == EINTR)
  527: 				{
  528: 					CRIT_END;
  529: 					NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit);
  530: 					return(error);
  531: 				}
  532: 				else if(error)
  533: 				{
  534: 					CRIT_END;
  535: 					NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error);
  536: 					return(error);
  537: 				}
  538: 			}
  539: 		}
  540: 	}
  541: 
  542: 	if(!(sc->sc_devstate & ST_ISOPEN))
  543: 	{
  544: 		NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
  545: 		CRIT_END;
  546: 		return(EIO);
  547: 	}
  548: 
  549: 	if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
  550: 	{
  551: 		m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
  552: 
  553: 		NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len);
  554: 		
  555: 		error = uiomove(m->m_data, m->m_len, uio);
  556: 
  557: #if defined (__FreeBSD__) && __FreeBSD__ > 4		
  558: 		(void) IF_HANDOFF(isdn_linktab[unit]->tx_queue, m, NULL);
  559: #else
  560: 		if(IF_QFULL(isdn_linktab[unit]->tx_queue))
  561: 			m_freem(m);
  562: 		else
  563: 			IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
  564: #endif
  565: 		(*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
  566: 	}
  567: 
  568: 	CRIT_END;
  569: 	
  570: 	return(error);
  571: }
  572: 
  573: /*---------------------------------------------------------------------------*
  574:  *	rbch device ioctl handlibg
  575:  *---------------------------------------------------------------------------*/
  576: PDEVSTATIC int
  577: i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct thread *td)
  578: {
  579: 	int error = 0;
  580: 	int unit = minor(dev);
  581: 	struct rbch_softc *sc = &rbch_softc[unit];
  582: 	
  583: 	switch(cmd)
  584: 	{
  585: 		case FIOASYNC:	/* Set async mode */
  586: 			if (*(int *)data)
  587: 			{
  588: 				NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit);
  589: 			}
  590: 			else
  591: 			{
  592: 				NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit);
  593: 			}
  594: 			break;
  595: 
  596: 		case FIONBIO:
  597: 			if (*(int *)data)
  598: 			{
  599: 				NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit);
  600: 				sc->sc_devstate |= ST_NOBLOCK;
  601: 			}
  602: 			else
  603: 			{
  604: 				NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit);
  605: 				sc->sc_devstate &= ~ST_NOBLOCK;
  606: 			}
  607: 			break;
  608: 
  609: 		case TIOCCDTR:	/* Clear DTR */
  610: 			if(sc->sc_devstate & ST_CONNECTED)
  611: 			{
  612: 				NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit);
  613: 				i4b_l4_drvrdisc(BDRV_RBCH, unit);
  614: 			}
  615: 			break;
  616: 
  617: 		case I4B_RBCH_DIALOUT:
  618:                 {
  619: 			size_t l;
  620: 
  621: 			for (l = 0; l < TELNO_MAX && ((char *)data)[l]; l++)
  622: 				;
  623: 			if (l)
  624: 			{
  625: 				NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout to %s", unit, (char *)data);
  626: 				i4b_l4_dialoutnumber(BDRV_RBCH, unit, l, (char *)data);
  627: 				break;
  628: 			}
  629: 			/* fall through to SDTR */
  630: 		}
  631: 
  632: 		case TIOCSDTR:	/* Set DTR */
  633: 			NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit);
  634: 			i4b_l4_dialout(BDRV_RBCH, unit);
  635: 			break;
  636: 
  637: 		case TIOCSETA:	/* Set termios struct */
  638: 			break;
  639: 
  640: 		case TIOCGETA:	/* Get termios struct */
  641: 			*(struct termios *)data = sc->it_in;
  642: 			break;
  643: 
  644: 		case TIOCMGET:
  645: 			*(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
  646: 			if (sc->sc_devstate & ST_CONNECTED)
  647: 				*(int *)data |= TIOCM_CD;
  648: 			break;
  649: 
  650: 		case I4B_RBCH_VR_REQ:
  651:                 {
  652: 			msg_vr_req_t *mvr;
  653: 
  654: 			mvr = (msg_vr_req_t *)data;
  655: 
  656: 			mvr->version = VERSION;
  657: 			mvr->release = REL;
  658: 			mvr->step = STEP;			
  659: 			break;
  660: 		}
  661: 
  662: 		default:	/* Unknown stuff */
  663: 			NDBGL4(L4_RBCHDBG, "unit %d, ioctl, unknown cmd %lx", unit, (u_long)cmd);
  664: 			error = EINVAL;
  665: 			break;
  666: 	}
  667: 	return(error);
  668: }
  669: 
  670: #ifdef OS_USES_POLL
  671: 
  672: /*---------------------------------------------------------------------------*
  673:  *	device driver poll
  674:  *---------------------------------------------------------------------------*/
  675: PDEVSTATIC int
  676: i4brbchpoll(dev_t dev, int events, struct thread *td)
  677: {
  678: 	int revents = 0;	/* Events we found */
  679: 	int s;
  680: 	int unit = minor(dev);
  681: 	struct rbch_softc *sc = &rbch_softc[unit];
  682: 	
  683: 	/* We can't check for anything but IN or OUT */
  684: 
  685: 	s = splhigh();
  686: 
  687: 	if(!(sc->sc_devstate & ST_ISOPEN))
  688: 	{
  689: 		splx(s);
  690: 		return(POLLNVAL);
  691: 	}
  692: 
  693: 	/*
  694: 	 * Writes are OK if we are connected and the
  695:          * transmit queue can take them
  696: 	 */
  697: 	 
  698: 	if((events & (POLLOUT|POLLWRNORM)) &&
  699: 	   (sc->sc_devstate & ST_CONNECTED) &&
  700: 	   !_IF_QFULL(isdn_linktab[unit]->tx_queue))
  701: 	{
  702: 		revents |= (events & (POLLOUT|POLLWRNORM));
  703: 	}
  704: 	
  705: 	/* ... while reads are OK if we have any data */
  706: 
  707: 	if((events & (POLLIN|POLLRDNORM)) &&
  708: 	   (sc->sc_devstate & ST_CONNECTED))
  709: 	{
  710: 		struct ifqueue *iqp;
  711: 
  712: 		if(sc->sc_bprot == BPROT_RHDLC)
  713: 			iqp = &sc->sc_hdlcq;
  714: 		else
  715: 			iqp = isdn_linktab[unit]->rx_queue;	
  716: 
  717: 		if(!IF_QEMPTY(iqp))
  718: 			revents |= (events & (POLLIN|POLLRDNORM));
  719: 	}
  720: 		
  721: 	if(revents == 0)
  722: 		selrecord(td, &sc->selp);
  723: 
  724: 	splx(s);
  725: 	return(revents);
  726: }
  727: 
  728: #else /* OS_USES_POLL */
  729: 
  730: /*---------------------------------------------------------------------------*
  731:  *	device driver select
  732:  *---------------------------------------------------------------------------*/
  733: PDEVSTATIC int
  734: i4brbchselect(dev_t dev, int rw, struct thread *td)
  735: {
  736: 	int unit = minor(dev);
  737: 	struct rbch_softc *sc = &rbch_softc[unit];
  738:         int s;
  739: 
  740: 	s = splhigh();
  741: 
  742: 	if(!(sc->sc_devstate & ST_ISOPEN))
  743: 	{
  744: 		splx(s);
  745: 		NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit);
  746: 		return(1);
  747: 	}
  748: 	
  749: 	if(sc->sc_devstate & ST_CONNECTED)
  750: 	{
  751: 		struct ifqueue *iqp;
  752: 
  753: 		switch(rw)
  754: 		{
  755: 			case FREAD:
  756: 				if(sc->sc_bprot == BPROT_RHDLC)
  757: 					iqp = &sc->sc_hdlcq;
  758: 				else
  759: 					iqp = isdn_linktab[unit]->rx_queue;	
  760: 
  761: 				if(!IF_QEMPTY(iqp))
  762: 				{
  763: 					splx(s);
  764: 					return(1);
  765: 				}
  766: 				break;
  767: 
  768: 			case FWRITE:
  769: 				if(!_IF_QFULL(isdn_linktab[unit]->rx_queue))
  770: 				{
  771: 					splx(s);
  772: 					return(1);
  773: 				}
  774: 				break;
  775: 
  776: 			default:
  777: 				splx(s);
  778: 				return 0;
  779: 		}
  780: 	}
  781: 	selrecord(p, &sc->selp);
  782: 	splx(s);
  783: 	return(0);
  784: }
  785: 
  786: #endif /* OS_USES_POLL */
  787: 
  788: #if I4BRBCHACCT
  789: /*---------------------------------------------------------------------------*
  790:  *	watchdog routine
  791:  *---------------------------------------------------------------------------*/
  792: static void
  793: rbch_timeout(struct rbch_softc *sc)
  794: {
  795: 	bchan_statistics_t bs;
  796: 	int unit = sc->sc_unit;
  797: 
  798: 	/* get # of bytes in and out from the HSCX driver */ 
  799: 	
  800: 	(*isdn_linktab[unit]->bch_stat)
  801: 		(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
  802: 
  803: 	sc->sc_ioutb += bs.outbytes;
  804: 	sc->sc_iinb += bs.inbytes;
  805: 	
  806: 	if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
  807: 	{
  808: 		int ri = (sc->sc_iinb - sc->sc_linb)/I4BRBCHACCTINTVL;
  809: 		int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BRBCHACCTINTVL;
  810: 
  811: 		if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
  812: 			sc->sc_fn = 0;
  813: 		else
  814: 			sc->sc_fn = 1;
  815: 			
  816: 		sc->sc_linb = sc->sc_iinb;
  817: 		sc->sc_loutb = sc->sc_ioutb;
  818: 
  819: 		i4b_l4_accounting(BDRV_RBCH, unit, ACCT_DURING,
  820: 			 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
  821:  	}
  822: 	START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
  823: }
  824: #endif /* I4BRBCHACCT */
  825: 
  826: /*===========================================================================*
  827:  *			ISDN INTERFACE ROUTINES
  828:  *===========================================================================*/
  829: 
  830: /*---------------------------------------------------------------------------*
  831:  *	this routine is called from L4 handler at connect time
  832:  *---------------------------------------------------------------------------*/
  833: static void
  834: rbch_connect(int unit, void *cdp)
  835: {
  836: 	call_desc_t *cd = (call_desc_t *)cdp;
  837: 	struct rbch_softc *sc = &rbch_softc[unit];
  838: 
  839: 	sc->sc_bprot = cd->bprot;
  840: 
  841: #if I4BRBCHACCT
  842: 	if(sc->sc_bprot == BPROT_RHDLC)
  843: 	{	
  844: 		sc->sc_iinb = 0;
  845: 		sc->sc_ioutb = 0;
  846: 		sc->sc_linb = 0;
  847: 		sc->sc_loutb = 0;
  848: 
  849: 		START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz);
  850: 	}
  851: #endif		
  852: 	if(!(sc->sc_devstate & ST_CONNECTED))
  853: 	{
  854: 		NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
  855: 		sc->sc_devstate |= ST_CONNECTED;
  856: 		sc->sc_cd = cdp;
  857: 		wakeup((caddr_t)sc);
  858: 	}
  859: }
  860: 
  861: /*---------------------------------------------------------------------------*
  862:  *	this routine is called from L4 handler at disconnect time
  863:  *---------------------------------------------------------------------------*/
  864: static void
  865: rbch_disconnect(int unit, void *cdp)
  866: {
  867: 	call_desc_t *cd = (call_desc_t *)cdp;
  868: 	struct rbch_softc *sc = &rbch_softc[unit];
  869: 
  870: 	CRIT_VAR;
  871: 	
  872:         if(cd != sc->sc_cd)
  873: 	{
  874: 		NDBGL4(L4_RBCHDBG, "rbch%d: channel %d not active",
  875: 			cd->driver_unit, cd->channelid);
  876: 		return;
  877: 	}
  878: 
  879: 	CRIT_BEG;
  880: 	
  881: 	NDBGL4(L4_RBCHDBG, "unit %d, disconnect", unit);
  882: 
  883: 	sc->sc_devstate &= ~ST_CONNECTED;
  884: 
  885: 	sc->sc_cd = NULL;
  886: 	
  887: #if I4BRBCHACCT
  888: 	i4b_l4_accounting(BDRV_RBCH, unit, ACCT_FINAL,
  889: 		 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb);
  890: 
  891: 	STOP_TIMER(sc->sc_callout, rbch_timeout, sc);
  892: #endif		
  893: 	CRIT_END;
  894: }
  895: 	
  896: /*---------------------------------------------------------------------------*
  897:  *	feedback from daemon in case of dial problems
  898:  *---------------------------------------------------------------------------*/
  899: static void
  900: rbch_dialresponse(int unit, int status, cause_t cause)
  901: {
  902: }
  903: 	
  904: /*---------------------------------------------------------------------------*
  905:  *	interface up/down
  906:  *---------------------------------------------------------------------------*/
  907: static void
  908: rbch_updown(int unit, int updown)
  909: {
  910: }
  911: 	
  912: /*---------------------------------------------------------------------------*
  913:  *	this routine is called from the HSCX interrupt handler
  914:  *	when a new frame (mbuf) has been received and is to be put on
  915:  *	the rx queue.
  916:  *---------------------------------------------------------------------------*/
  917: static void
  918: rbch_rx_data_rdy(int unit)
  919: {
  920: 	if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
  921: 	{
  922: 		struct mbuf *m;
  923: 		
  924: 		if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
  925: 			return;
  926: 
  927: 		m->m_pkthdr.len = m->m_len;
  928: 
  929: #if defined (__FreeBSD__) && __FreeBSD__ > 4
  930: 		if (! IF_HANDOFF(&(rbch_softc[unit].sc_hdlcq), m, NULL))
  931: 		{
  932: 			NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
  933: 		}
  934: #else
  935:                 if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
  936: 		{
  937: 			NDBGL4(L4_RBCHDBG, "unit %d: hdlc rx queue full!", unit);
  938: 			m_freem(m);
  939: 		}			
  940: 		else
  941: 		{
  942: 			IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
  943: 		}
  944: #endif		
  945: 	}
  946: 
  947: 	if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
  948: 	{
  949: 		NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
  950: 		rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
  951: 		wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
  952: 	}
  953: 	else
  954: 	{
  955: 		NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
  956: 	}
  957: 	selwakeup(&rbch_softc[unit].selp);
  958: }
  959: 
  960: /*---------------------------------------------------------------------------*
  961:  *	this routine is called from the HSCX interrupt handler
  962:  *	when the last frame has been sent out and there is no
  963:  *	further frame (mbuf) in the tx queue.
  964:  *---------------------------------------------------------------------------*/
  965: static void
  966: rbch_tx_queue_empty(int unit)
  967: {
  968: 	if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
  969: 	{
  970: 		NDBGL4(L4_RBCHDBG, "unit %d, wakeup", unit);
  971: 		rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
  972: 		wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
  973: 	}
  974: 	else
  975: 	{
  976: 		NDBGL4(L4_RBCHDBG, "unit %d, NO wakeup", unit);
  977: 	}
  978: 	selwakeup(&rbch_softc[unit].selp);
  979: }
  980: 
  981: /*---------------------------------------------------------------------------*
  982:  *	this routine is called from the HSCX interrupt handler
  983:  *	each time a packet is received or transmitted
  984:  *---------------------------------------------------------------------------*/
  985: static void
  986: rbch_activity(int unit, int rxtx)
  987: {
  988: 	if (rbch_softc[unit].sc_cd)
  989: 		rbch_softc[unit].sc_cd->last_active_time = SECOND;
  990: 	selwakeup(&rbch_softc[unit].selp);
  991: }
  992: 
  993: /*---------------------------------------------------------------------------*
  994:  *	clear an hdlc rx queue for a rbch unit
  995:  *---------------------------------------------------------------------------*/
  996: static void
  997: rbch_clrq(int unit)
  998: {
  999: 	CRIT_VAR;
 1000: 
 1001: #if defined (__FreeBSD__) && __FreeBSD__ > 4
 1002: 	CRIT_BEG;
 1003: 	IF_DRAIN(&rbch_softc[unit].sc_hdlcq);
 1004: 	CRIT_END;
 1005: #else
 1006: 	struct mbuf *m;
 1007:         for(;;)
 1008:         {
 1009:                 CRIT_BEG;
 1010:                 IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m);
 1011:                 CRIT_END;
 1012: 
 1013:                 if(m)
 1014:                         m_freem(m);
 1015:                 else
 1016:                         break;
 1017:         }
 1018: #endif	
 1019: }
 1020: 				
 1021: /*---------------------------------------------------------------------------*
 1022:  *	return this drivers linktab address
 1023:  *---------------------------------------------------------------------------*/
 1024: drvr_link_t *
 1025: rbch_ret_linktab(int unit)
 1026: {
 1027: 	rbch_init_linktab(unit);
 1028: 	return(&rbch_drvr_linktab[unit]);
 1029: }
 1030: 
 1031: /*---------------------------------------------------------------------------*
 1032:  *	setup the isdn_linktab for this driver
 1033:  *---------------------------------------------------------------------------*/
 1034: void
 1035: rbch_set_linktab(int unit, isdn_link_t *ilt)
 1036: {
 1037: 	isdn_linktab[unit] = ilt;
 1038: }
 1039: 
 1040: /*---------------------------------------------------------------------------*
 1041:  *	initialize this drivers linktab
 1042:  *---------------------------------------------------------------------------*/
 1043: static void
 1044: rbch_init_linktab(int unit)
 1045: {
 1046: 	rbch_drvr_linktab[unit].unit = unit;
 1047: 	rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
 1048: 	rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
 1049: 	rbch_drvr_linktab[unit].bch_activity = rbch_activity;	
 1050: 	rbch_drvr_linktab[unit].line_connected = rbch_connect;
 1051: 	rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
 1052: 	rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
 1053: 	rbch_drvr_linktab[unit].updown_ind = rbch_updown;	
 1054: }
 1055: 
 1056: /*===========================================================================*/
 1057: 
 1058: #endif /* NI4BRBCH > 0 */