File:  [DragonFly] / src / sys / i386 / gnu / isa / Attic / dgb.c
Revision 1.11: download - view: text, annotated - select for diffs
Wed May 19 22:52:57 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

    1: /*-
    2:  *  dgb.c $FreeBSD: src/sys/gnu/i386/isa/dgb.c,v 1.56.2.1 2001/02/26 04:23:09 jlemon Exp $
    3:  *  dgb.c $DragonFly: src/sys/i386/gnu/isa/dgb.c,v 1.11 2004/05/19 22:52:57 dillon Exp $
    4:  *
    5:  *  Digiboard driver.
    6:  *
    7:  *  Stage 1. "Better than nothing".
    8:  *  Stage 2. "Gee, it works!".
    9:  *
   10:  *  Based on sio driver by Bruce Evans and on Linux driver by Troy 
   11:  *  De Jongh <troyd@digibd.com> or <troyd@skypoint.com> 
   12:  *  which is under GNU General Public License version 2 so this driver 
   13:  *  is forced to be under GPL 2 too.
   14:  *
   15:  *  Written by Serge Babkin,
   16:  *      Joint Stock Commercial Bank "Chelindbank"
   17:  *      (Chelyabinsk, Russia)
   18:  *      babkin@hq.icb.chel.su
   19:  *
   20:  *  Assorted hacks to make it more functional and working under 3.0-current.
   21:  *  Fixed broken routines to prevent processes hanging on closed (thanks
   22:  *  to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
   23:  *  <max@run.net> for his patches which did most of the work to get this
   24:  *  running under 2.2/3.0-current.
   25:  *  Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
   26:  *  TIOCDCDTIMESTAMP.
   27:  *  Sysctl debug flag is now a bitflag, to filter noise during debugging.
   28:  *	David L. Nugent <davidn@blaze.net.au>
   29:  */
   30: 
   31: #include "opt_compat.h"
   32: #include "opt_dgb.h"
   33: 
   34: #include "use_dgb.h"
   35: 
   36: /* Helg: i.e.25 times per sec board will be polled */
   37: #define POLLSPERSEC 25
   38: /* How many charactes can we write to input tty rawq */
   39: #define DGB_IBUFSIZE (TTYHOG-100)
   40: 
   41: /* the overall number of ports controlled by this driver */
   42: 
   43: #ifndef NDGBPORTS
   44: #	define NDGBPORTS (NDGB*16)
   45: #endif
   46: 
   47: #include <sys/param.h>
   48: #include <sys/systm.h>
   49: #include <sys/tty.h>
   50: #include <sys/proc.h>
   51: #include <sys/conf.h>
   52: #include <sys/dkstat.h>
   53: #include <sys/fcntl.h>
   54: #include <sys/kernel.h>
   55: #include <sys/sysctl.h>
   56: 
   57: #include <machine/clock.h>
   58: 
   59: #include <vm/vm.h>
   60: #include <vm/pmap.h>
   61: 
   62: #include <bus/isa/i386/isa_device.h>
   63: 
   64: #include "dgbios.h"
   65: #include "dgfep.h"
   66: 
   67: #define DGB_DEBUG		/* Enable debugging info via sysctl */
   68: #include "dgreg.h"
   69: 
   70: #define	CALLOUT_MASK		0x80
   71: #define	CONTROL_MASK		0x60
   72: #define	CONTROL_INIT_STATE	0x20
   73: #define	CONTROL_LOCK_STATE	0x40
   74: #define UNIT_MASK			0x30000
   75: #define PORT_MASK			0x1F
   76: #define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
   77: #define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
   78: #define	MINOR_TO_UNIT(mynor)	(((mynor) & UNIT_MASK)>>16)
   79: #define MINOR_TO_PORT(mynor)	((mynor) & PORT_MASK)
   80: 
   81: /* types.  XXX - should be elsewhere */
   82: typedef u_char	bool_t;		/* boolean */
   83: 
   84: /* digiboard port structure */
   85: struct dgb_p {
   86: 	bool_t	status;
   87: 
   88: 	u_char unit;           /* board unit number */
   89: 	u_char pnum;           /* port number */
   90: 	u_char omodem;         /* FEP output modem status     */
   91: 	u_char imodem;         /* FEP input modem status      */
   92: 	u_char modemfake;      /* Modem values to be forced   */
   93: 	u_char modem;          /* Force values                */
   94: 	u_char hflow;
   95: 	u_char dsr;
   96: 	u_char dcd;
   97: 	u_char stopc;
   98: 	u_char startc;
   99: 	u_char stopca;
  100: 	u_char startca;
  101: 	u_char fepstopc;
  102: 	u_char fepstartc;
  103: 	u_char fepstopca;
  104: 	u_char fepstartca;
  105: 	u_char txwin;
  106: 	u_char rxwin;
  107: 	ushort fepiflag;
  108: 	ushort fepcflag;
  109: 	ushort fepoflag;
  110: 	ushort txbufhead;
  111: 	ushort txbufsize;
  112: 	ushort rxbufhead;
  113: 	ushort rxbufsize;
  114: 	int close_delay;
  115: 	int count;
  116: 	int blocked_open;
  117: 	int event;
  118: 	int asyncflags;
  119: 	u_long statusflags;
  120: 	u_char *txptr;
  121: 	u_char *rxptr;
  122: 	volatile struct board_chan *brdchan;
  123: 	struct tty *tty;
  124: 
  125: 	bool_t  active_out;	/* nonzero if the callout device is open */
  126: 	u_int	wopeners;	/* # processes waiting for DCD in open() */
  127: 
  128: 	/* Initial state. */
  129: 	struct termios	it_in;	/* should be in struct tty */
  130: 	struct termios	it_out;
  131: 
  132: 	/* Lock state. */
  133: 	struct termios	lt_in;	/* should be in struct tty */
  134: 	struct termios	lt_out;
  135: 
  136: 	bool_t	do_timestamp;
  137: 	bool_t	do_dcd_timestamp;
  138: 	struct timeval	timestamp;
  139: 	struct timeval	dcd_timestamp;
  140: 
  141: 	/* flags of state, are used in sleep() too */
  142: 	u_char closing;	/* port is being closed now */
  143: 	u_char draining; /* port is being drained now */
  144: 	u_char used;	/* port is being used now */
  145: 	u_char mustdrain; /* data must be waited to drain in dgbparam() */
  146: };
  147: 
  148: /* Digiboard per-board structure */
  149: struct dgb_softc {
  150: 	/* struct board_info */
  151: 	u_char status;	/* status: DISABLED/ENABLED */
  152: 	u_char unit;	/* unit number */
  153: 	u_char type;	/* type of card: PCXE, PCXI, PCXEVE */
  154: 	u_char altpin;	/* do we need alternate pin setting ? */
  155: 	int numports;	/* number of ports on card */
  156: 	int port;	/* I/O port */
  157: 	u_char *vmem; /* virtual memory address */
  158: 	long pmem; /* physical memory address */
  159: 	int mem_seg;  /* internal memory segment */
  160: 	struct dgb_p *ports;	/* pointer to array of port descriptors */
  161: 	struct tty *ttys;	/* pointer to array of TTY structures */
  162: 	volatile struct global_data *mailbox;
  163: 	};
  164: 	
  165: 
  166: static struct dgb_softc dgb_softc[NDGB];
  167: static struct dgb_p dgb_ports[NDGBPORTS];
  168: static struct tty dgb_tty[NDGBPORTS];
  169: 
  170: /*
  171:  * The public functions in the com module ought to be declared in a com-driver
  172:  * system header.
  173:  */
  174: 
  175: /* Interrupt handling entry points. */
  176: static void	dgbpoll		(void *unit_c);
  177: 
  178: /* Device switch entry points. */
  179: #define	dgbreset	noreset
  180: #define	dgbmmap		nommap
  181: #define	dgbstrategy	nostrategy
  182: 
  183: static	int	dgbattach	(struct isa_device *dev);
  184: static	int	dgbprobe	(struct isa_device *dev);
  185: 
  186: static void fepcmd(struct dgb_p *port, unsigned cmd, unsigned op1, unsigned op2,
  187: 	unsigned ncmds, unsigned bytecmd);
  188: 
  189: static	void	dgbstart	(struct tty *tp);
  190: static	void	dgbstop		(struct tty *tp, int rw);
  191: static	int	dgbparam	(struct tty *tp, struct termios *t);
  192: static	void	dgbhardclose	(struct dgb_p *port);
  193: static	void	dgb_drain_or_flush	(struct dgb_p *port);
  194: static	int	dgbdrain	(struct dgb_p *port);
  195: static	void	dgb_pause	(void *chan);
  196: static	void	wakeflush	(void *p);
  197: static	void	disc_optim	(struct tty	*tp, struct termios *t);
  198: 
  199: 
  200: struct isa_driver	dgbdriver = {
  201: 	dgbprobe, dgbattach, "dgb",0
  202: };
  203: 
  204: static	d_open_t	dgbopen;
  205: static	d_close_t	dgbclose;
  206: static	d_ioctl_t	dgbioctl;
  207: 
  208: #define	CDEV_MAJOR	58
  209: static struct cdevsw dgb_cdevsw = {
  210: 	/* name */	"dgb",
  211: 	/* maj */	CDEV_MAJOR,
  212: 	/* flags */	D_TTY | D_KQFILTER,
  213: 	/* port */	NULL,
  214: 	/* clone */	NULL,
  215: 
  216: 	/* open */	dgbopen,
  217: 	/* close */	dgbclose,
  218: 	/* read */	ttyread,
  219: 	/* write */	ttywrite,
  220: 	/* ioctl */	dgbioctl,
  221: 	/* poll */	ttypoll,
  222: 	/* mmap */	nommap,
  223: 	/* strategy */	nostrategy,
  224: 	/* dump */	nodump,
  225: 	/* psize */	nopsize,
  226: 	/* kqfilter */	ttykqfilter
  227: };
  228: 
  229: static	speed_t	dgbdefaultrate = TTYDEF_SPEED;
  230: 
  231: static	struct speedtab dgbspeedtab[] = {
  232: 	{ 0,		FEP_B0 }, /* old (sysV-like) Bx codes */
  233: 	{ 50,		FEP_B50 },
  234: 	{ 75,		FEP_B75 },
  235: 	{ 110,		FEP_B110 },
  236: 	{ 134,		FEP_B134 },
  237: 	{ 150,		FEP_B150 },
  238: 	{ 200,		FEP_B200 },
  239: 	{ 300,		FEP_B300 },
  240: 	{ 600,		FEP_B600 },
  241: 	{ 1200,		FEP_B1200 },
  242: 	{ 1800,		FEP_B1800 },
  243: 	{ 2400,		FEP_B2400 },
  244: 	{ 4800,		FEP_B4800 },
  245: 	{ 9600,		FEP_B9600 },
  246: 	{ 19200,	FEP_B19200 },
  247: 	{ 38400,	FEP_B38400 },
  248: 	{ 57600,	(FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
  249: 	{ 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
  250: 	{ -1,	-1 }
  251: };
  252: 
  253: static struct dbgflagtbl
  254: {
  255:   tcflag_t in_mask;
  256:   tcflag_t in_val;
  257:   tcflag_t out_val;
  258: } dgb_cflags[] =
  259: {
  260:   { PARODD,   PARODD,	  FEP_PARODD  },
  261:   { PARENB,   PARENB,	  FEP_PARENB  },
  262:   { CSTOPB,   CSTOPB,	  FEP_CSTOPB  },
  263:   { CSIZE,    CS5,	  FEP_CS6     },
  264:   { CSIZE,    CS6,	  FEP_CS6     },
  265:   { CSIZE,    CS7,	  FEP_CS7     },
  266:   { CSIZE,    CS8,	  FEP_CS8     },
  267:   { CLOCAL,   CLOCAL,	  FEP_CLOCAL  },
  268:   { (tcflag_t)-1 }
  269: }, dgb_iflags[] =
  270: {
  271:   { IGNBRK,   IGNBRK,     FEP_IGNBRK  },
  272:   { BRKINT,   BRKINT,	  FEP_BRKINT  },
  273:   { IGNPAR,   IGNPAR,	  FEP_IGNPAR  },
  274:   { PARMRK,   PARMRK,	  FEP_PARMRK  },
  275:   { INPCK,    INPCK,	  FEP_INPCK   },
  276:   { ISTRIP,   ISTRIP,	  FEP_ISTRIP  },
  277:   { IXON,     IXON,	  FEP_IXON    },
  278:   { IXOFF,    IXOFF,	  FEP_IXOFF   },
  279:   { IXANY,    IXANY,	  FEP_IXANY   },
  280:   { (tcflag_t)-1 }
  281: }, dgb_flow[] =
  282: {
  283:   { CRTSCTS,  CRTSCTS,	  CTS|RTS     },
  284:   { CRTSCTS,  CCTS_OFLOW, CTS	      },
  285:   { CRTSCTS,  CRTS_IFLOW, RTS	      },
  286:   { (tcflag_t)-1 }
  287: };
  288: 
  289: /* xlat bsd termios flags to dgb sys-v style */
  290: static tcflag_t
  291: dgbflags(struct dbgflagtbl *tbl, tcflag_t input)
  292: {
  293:   tcflag_t output = 0;
  294:   int i;
  295: 
  296:   for (i=0; tbl[i].in_mask != (tcflag_t)-1; i++)
  297:   {
  298:     if ((input & tbl[i].in_mask) == tbl[i].in_val)
  299:       output |= tbl[i].out_val;
  300:   }
  301:   return output;
  302: }
  303: 
  304: #ifdef DGB_DEBUG
  305: static int dgbdebug=0;
  306: SYSCTL_INT(_debug, OID_AUTO, dgb_debug, CTLFLAG_RW, &dgbdebug, 0, "");
  307: #endif
  308: 
  309: static __inline int setwin (struct dgb_softc *sc, unsigned addr);
  310: static __inline int setinitwin (struct dgb_softc *sc, unsigned addr);
  311: static __inline void hidewin (struct dgb_softc *sc);
  312: static __inline void towin (struct dgb_softc *sc, int win);
  313: 
  314: /*Helg: to allow recursive dgb...() calls */
  315: typedef struct
  316:   {                 /* If we were called and don't want to disturb we need: */
  317: 	int port;		/* write to this port */
  318: 	u_char data;		/* this data on exit */
  319: 	                  /* or DATA_WINOFF  to close memory window on entry */
  320:   } BoardMemWinState; /* so several channels and even boards can coexist */
  321: #define DATA_WINOFF 0
  322: static BoardMemWinState bmws;
  323: 
  324: /* return current memory window state and close window */
  325: static BoardMemWinState
  326: bmws_get(void)
  327: {
  328: 	BoardMemWinState bmwsRet=bmws;
  329: 	if(bmws.data!=DATA_WINOFF)
  330: 		outb(bmws.port, bmws.data=DATA_WINOFF);
  331: 	return bmwsRet;
  332: }
  333: 
  334: /* restore memory window state */
  335: static void
  336: bmws_set(BoardMemWinState ws)
  337: {
  338: 	if(ws.data != bmws.data || ws.port!=bmws.port ) {
  339: 		if(bmws.data!=DATA_WINOFF)
  340: 			outb(bmws.port,DATA_WINOFF);
  341: 		if(ws.data!=DATA_WINOFF)
  342: 			outb(ws.port, ws.data);
  343: 		bmws=ws;
  344: 	}
  345: }
  346: 
  347: static __inline int 
  348: setwin(sc,addr)
  349: 	struct dgb_softc *sc;
  350: 	unsigned int addr;
  351: {
  352: 	if(sc->type==PCXEVE) {
  353: 		outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
  354: 		DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
  355: 		return (addr & 0x1FFF);
  356: 	} else {
  357: 		outb(bmws.port=sc->port,bmws.data=FEPMEM);
  358: 		return addr;
  359: 	}
  360: }
  361: 
  362: static __inline int 
  363: setinitwin(sc,addr)
  364: 	struct dgb_softc *sc;
  365: 	unsigned int addr;
  366: {
  367: 	if(sc->type==PCXEVE) {
  368: 		outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
  369: 		DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
  370: 		return (addr & 0x1FFF);
  371: 	} else {
  372: 		outb(bmws.port=sc->port,bmws.data=inb(sc->port)|FEPMEM);
  373: 		return addr;
  374: 	}
  375: }
  376: 
  377: static __inline void
  378: hidewin(sc)
  379: 	struct dgb_softc *sc;
  380: {
  381: 	bmws.data=0;
  382: 	if(sc->type==PCXEVE)
  383: 		outb(bmws.port=sc->port+1, bmws.data);
  384: 	else
  385: 		outb(bmws.port=sc->port, bmws.data);
  386: }
  387: 
  388: static __inline void
  389: towin(sc,win)
  390: 	struct dgb_softc *sc;
  391: 	int win;
  392: {
  393: 	if(sc->type==PCXEVE) {
  394: 		outb(bmws.port=sc->port+1, bmws.data=win);
  395: 	} else {
  396: 		outb(bmws.port=sc->port,bmws.data=FEPMEM);
  397: 	}
  398: }
  399: 
  400: static int
  401: dgbprobe(dev)
  402: 	struct isa_device	*dev;
  403: {
  404: 	struct dgb_softc *sc= &dgb_softc[dev->id_unit];
  405: 	int i, v;
  406: 	u_long win_size;  /* size of vizible memory window */
  407: 	int unit=dev->id_unit;
  408: 
  409: 	sc->unit=dev->id_unit;
  410: 	sc->port=dev->id_iobase;
  411: 
  412: 	if(dev->id_flags & DGBFLAG_ALTPIN)
  413: 		sc->altpin=1;
  414: 	else
  415: 		sc->altpin=0;
  416: 
  417: 	/* left 24 bits only (ISA address) */
  418: 	sc->pmem=((intptr_t)(void *)dev->id_maddr & 0xFFFFFF); 
  419: 	
  420: 	DPRINT4(DB_INFO,"dgb%d: port 0x%x mem 0x%lx\n",unit,sc->port,sc->pmem);
  421: 
  422: 	outb(sc->port, FEPRST);
  423: 	sc->status=DISABLED;
  424: 
  425: 	for(i=0; i< 1000; i++) {
  426: 		DELAY(1);
  427: 		if( (inb(sc->port) & FEPMASK) == FEPRST ) {
  428: 			sc->status=ENABLED;
  429: 			DPRINT3(DB_EXCEPT,"dgb%d: got reset after %d us\n",unit,i);
  430: 			break;
  431: 		}
  432: 	}
  433: 
  434: 	if(sc->status!=ENABLED) {
  435: 		DPRINT2(DB_EXCEPT,"dgb%d: failed to respond\n",dev->id_unit);
  436: 		return 0;
  437: 	}
  438: 
  439: 	/* check type of card and get internal memory characteristics */
  440: 
  441: 	v=inb(sc->port);
  442: 
  443: 	if( v & 0x1 ) {
  444: 		switch( v&0x30 ) {
  445: 		case 0:
  446: 			sc->mem_seg=0xF000;
  447: 			win_size=0x10000;
  448: 			printf("dgb%d: PC/Xi 64K\n",dev->id_unit);
  449: 			break;
  450: 		case 0x10:
  451: 			sc->mem_seg=0xE000;
  452: 			win_size=0x20000;
  453: 			printf("dgb%d: PC/Xi 128K\n",dev->id_unit);
  454: 			break;
  455: 		case 0x20:
  456: 			sc->mem_seg=0xC000;
  457: 			win_size=0x40000;
  458: 			printf("dgb%d: PC/Xi 256K\n",dev->id_unit);
  459: 			break;
  460: 		default: /* case 0x30: */
  461: 			sc->mem_seg=0x8000;
  462: 			win_size=0x80000;
  463: 			printf("dgb%d: PC/Xi 512K\n",dev->id_unit);
  464: 			break;
  465: 		}
  466: 		sc->type=PCXI;
  467: 	} else {
  468: 		outb(sc->port, 1);
  469: 		v=inb(sc->port);
  470: 
  471: 		if( v & 0x1 ) {
  472: 			printf("dgb%d: PC/Xm isn't supported\n",dev->id_unit);
  473: 			sc->status=DISABLED;
  474: 			return 0;
  475: 			}
  476: 
  477: 		sc->mem_seg=0xF000;
  478: 
  479: 		if(dev->id_flags==DGBFLAG_NOWIN || ( v&0xC0 )==0) {
  480: 			win_size=0x10000;
  481: 			printf("dgb%d: PC/Xe 64K\n",dev->id_unit);
  482: 			sc->type=PCXE;
  483: 		} else {
  484: 			win_size=0x2000;
  485: 			printf("dgb%d: PC/Xe 64/8K (windowed)\n",dev->id_unit);
  486: 			sc->type=PCXEVE;
  487: 			if((u_long)sc->pmem & ~0xFFE000) {
  488: 				printf("dgb%d: warning: address 0x%lx truncated to 0x%lx\n",
  489: 					dev->id_unit, sc->pmem,
  490: 					sc->pmem & 0xFFE000);
  491: 
  492: 				dev->id_maddr= (u_char *)(void *)(intptr_t)( sc->pmem & 0xFFE000 );
  493: 			}
  494: 		}
  495: 	}
  496: 
  497: 	/* save size of vizible memory segment */
  498: 	dev->id_msize=win_size;
  499: 
  500: 	/* map memory */
  501: 	dev->id_maddr=sc->vmem=pmap_mapdev(sc->pmem,dev->id_msize);
  502: 
  503: 	outb(sc->port, FEPCLR); /* drop RESET */
  504: 	hidewin(sc); /* Helg: to set initial bmws state */
  505: 
  506: 	return 4; /* we need I/O space of 4 ports */
  507: }
  508: 
  509: static int
  510: dgbattach(dev)
  511: 	struct isa_device	*dev;
  512: {
  513: 	int unit=dev->id_unit;
  514: 	struct dgb_softc *sc= &dgb_softc[dev->id_unit];
  515: 	int i, t;
  516: 	u_char volatile *mem;
  517: 	u_char volatile *ptr;
  518: 	int addr;
  519: 	struct dgb_p *port;
  520: 	volatile struct board_chan *bc;
  521: 	int shrinkmem;
  522: 	int nfails;
  523: 	const volatile ushort *pstat;
  524: 	int lowwater;
  525: 	static int nports=0;
  526: 	char suffix;
  527: 
  528: 	if(sc->status!=ENABLED) {
  529: 		DPRINT2(DB_EXCEPT,"dbg%d: try to attach a disabled card\n",unit);
  530: 		return 0;
  531: 		}
  532: 
  533: 	mem=sc->vmem;
  534: 
  535: 	DPRINT3(DB_INFO,"dgb%d: internal memory segment 0x%x\n",unit,sc->mem_seg);
  536: 
  537: 	outb(sc->port, FEPRST); DELAY(1);
  538: 
  539: 	for(i=0; (inb(sc->port) & FEPMASK) != FEPRST ; i++) {
  540: 		if(i>10000) {
  541: 			printf("dgb%d: 1st reset failed\n",dev->id_unit);
  542: 			sc->status=DISABLED;
  543: 			hidewin(sc);
  544: 			return 0;
  545: 		}
  546: 		DELAY(1);
  547: 	}
  548: 
  549: 	DPRINT3(DB_INFO,"dgb%d: got reset after %d us\n",unit,i);
  550: 
  551: 	/* for PCXEVE set up interrupt and base address */
  552: 
  553: 	if(sc->type==PCXEVE) {
  554: 		t=(((u_long)sc->pmem>>8) & 0xFFE0) | 0x10 /* enable windowing */;
  555: 		/* IRQ isn't used */
  556: 		outb(sc->port+2,t & 0xFF);
  557: 		outb(sc->port+3,t>>8);
  558: 	} else if(sc->type==PCXE) {
  559: 		t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */;
  560: 		outb(sc->port+2,t & 0xFF);
  561: 		outb(sc->port+3,t>>8);
  562: 	}
  563: 
  564: 
  565: 	if(sc->type==PCXI || sc->type==PCXE) {
  566: 		outb(sc->port, FEPRST|FEPMEM); DELAY(1);
  567: 
  568: 		for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) {
  569: 			if(i>10000) {
  570: 				printf("dgb%d: 2nd reset failed\n",dev->id_unit);
  571: 				sc->status=DISABLED;
  572: 				hidewin(sc);
  573: 				return 0;
  574: 			}
  575: 			DELAY(1);
  576: 		}
  577: 
  578: 		DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i);
  579: 	}
  580: 
  581: 	mem=sc->vmem;
  582: 
  583: 	/* very short memory test */
  584: 
  585: 	addr=setinitwin(sc,BOTWIN);
  586: 	*(u_long volatile *)(mem+addr) = 0xA55A3CC3;
  587: 	if(*(u_long volatile *)(mem+addr)!=0xA55A3CC3) {
  588: 		printf("dgb%d: 1st memory test failed\n",dev->id_unit);
  589: 		sc->status=DISABLED;
  590: 		hidewin(sc);
  591: 		return 0;
  592: 	}
  593: 		
  594: 	addr=setinitwin(sc,TOPWIN);
  595: 	*(u_long volatile *)(mem+addr) = 0x5AA5C33C;
  596: 	if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
  597: 		printf("dgb%d: 2nd memory test failed\n",dev->id_unit);
  598: 		sc->status=DISABLED;
  599: 		hidewin(sc);
  600: 		return 0;
  601: 	}
  602: 		
  603: 	addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4));
  604: 	*(u_long volatile *)(mem+addr) = 0x5AA5C33C;
  605: 	if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
  606: 		printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit);
  607: 	}
  608: 		
  609: 	addr=setinitwin(sc,MISCGLOBAL);
  610: 	for(i=0; i<16; i++) {
  611: 		mem[addr+i]=0;
  612: 	}
  613: 
  614: 	if(sc->type==PCXI || sc->type==PCXE) {
  615: 
  616: 		addr=BIOSCODE+((0xF000-sc->mem_seg)<<4);
  617: 
  618: 		DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr);
  619: 
  620: 		ptr= mem+addr;
  621: 
  622: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  623: 			*ptr = pcxx_bios[i];
  624: 
  625: 		ptr= mem+addr;
  626: 
  627: 		nfails=0;
  628: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  629: 			if( *ptr != pcxx_bios[i] ) {
  630: 				DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
  631: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
  632: 
  633: 				if(++nfails>=5) {
  634: 					printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
  635: 					break;
  636: 					}
  637: 				}
  638: 
  639: 		outb(sc->port,FEPMEM);
  640: 
  641: 		for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) {
  642: 			if(i>10000) {
  643: 				printf("dgb%d: BIOS start failed\n",dev->id_unit);
  644: 				sc->status=DISABLED;
  645: 				hidewin(sc);
  646: 				return 0;
  647: 			}
  648: 			DELAY(1);
  649: 		}
  650: 
  651: 		DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
  652: 
  653: 		for(i=0; i<200000; i++) {
  654: 			if( *((ushort volatile *)(mem+MISCGLOBAL)) == *((ushort *)"GD") )
  655: 				goto load_fep;
  656: 			DELAY(1);
  657: 		}
  658: 		printf("dgb%d: BIOS download failed\n",dev->id_unit);
  659: 		DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n",
  660: 			dev->id_unit,
  661: 			*((ushort volatile *)(mem+MISCGLOBAL)),
  662: 			*((ushort *)"GD"));
  663: 
  664: 		sc->status=DISABLED;
  665: 		hidewin(sc);
  666: 		return 0;
  667: 	}
  668: 
  669: 	if(sc->type==PCXEVE) {
  670: 		/* set window 7 */
  671: 		outb(sc->port+1,0xFF);
  672: 
  673: 		ptr= mem+(BIOSCODE & 0x1FFF);
  674: 
  675: 		for(i=0; i<pcxx_nbios; i++)
  676: 			*ptr++ = pcxx_bios[i];
  677: 
  678: 		ptr= mem+(BIOSCODE & 0x1FFF);
  679: 
  680: 		nfails=0;
  681: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  682: 			if( *ptr != pcxx_bios[i] ) {
  683: 				DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
  684: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
  685: 
  686: 				if(++nfails>=5) {
  687: 					printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
  688: 					break;
  689: 					}
  690: 				}
  691: 
  692: 		outb(sc->port,FEPCLR);
  693: 
  694: 		setwin(sc,0);
  695: 
  696: 		for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) {
  697: 			if(i>10000) {
  698: 				printf("dgb%d: BIOS start failed\n",dev->id_unit);
  699: 				sc->status=DISABLED;
  700: 				hidewin(sc);
  701: 				return 0;
  702: 			}
  703: 			DELAY(1);
  704: 		}
  705: 
  706: 		DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
  707: 
  708: 		addr=setwin(sc,MISCGLOBAL);
  709: 
  710: 		for(i=0; i<200000; i++) {
  711: 			if(*(ushort volatile *)(mem+addr)== *(ushort *)"GD")
  712: 				goto load_fep;
  713: 			DELAY(1);
  714: 		}
  715: 		printf("dgb%d: BIOS download failed\n",dev->id_unit);
  716: 		DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n",
  717: 			dev->id_unit,
  718: 			*(ushort volatile *)(mem+0xC12),
  719: 			*(ushort volatile *)(mem+0xC14),
  720: 			*(ushort volatile *)(mem+MISCGLOBAL));
  721: 
  722: 		sc->status=DISABLED;
  723: 		hidewin(sc);
  724: 		return 0;
  725: 	}
  726: 
  727: load_fep:
  728: 	DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit);
  729: 
  730: 	addr=setwin(sc,FEPCODE);
  731: 
  732: 	ptr= mem+addr;
  733: 
  734: 	for(i=0; i<pcxx_ncook; i++)
  735: 		*ptr++ = pcxx_cook[i];
  736: 
  737: 	addr=setwin(sc,MBOX);
  738: 	*(ushort volatile *)(mem+addr+ 0)=2;
  739: 	*(ushort volatile *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG;
  740: 	*(ushort volatile *)(mem+addr+ 4)=0;
  741: 	*(ushort volatile *)(mem+addr+ 6)=FEPCODESEG;
  742: 	*(ushort volatile *)(mem+addr+ 8)=0;
  743: 	*(ushort volatile *)(mem+addr+10)=pcxx_ncook;
  744: 
  745: 	outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */
  746: 	outb(sc->port,FEPMEM);
  747: 
  748: 	for(i=0; *(ushort volatile *)(mem+addr)!=0; i++) {
  749: 		if(i>200000) {
  750: 			printf("dgb%d: FEP code download failed\n",unit);
  751: 			DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit,
  752: 				*(ushort volatile *)(mem+addr));
  753: 			sc->status=DISABLED;
  754: 			hidewin(sc);
  755: 			return 0;
  756: 		}
  757: 	}
  758: 
  759: 	DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit);
  760: 
  761: 	*(ushort volatile *)(mem+setwin(sc,FEPSTAT))=0;
  762: 	addr=setwin(sc,MBOX);
  763: 	*(ushort volatile *)(mem+addr+0)=1;
  764: 	*(ushort volatile *)(mem+addr+2)=FEPCODESEG;
  765: 	*(ushort volatile *)(mem+addr+4)=0x4;
  766: 
  767: 	outb(sc->port,FEPINT); /* send interrupt to BIOS */
  768: 	outb(sc->port,FEPCLR);
  769: 
  770: 	addr=setwin(sc,FEPSTAT);
  771: 	for(i=0; *(ushort volatile *)(mem+addr)!= *(ushort *)"OS"; i++) {
  772: 		if(i>200000) {
  773: 			printf("dgb%d: FEP/OS start failed\n",dev->id_unit);
  774: 			sc->status=DISABLED;
  775: 			hidewin(sc);
  776: 			return 0;
  777: 		}
  778: 	}
  779: 
  780: 	DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit);
  781: 
  782: 	sc->numports= *(ushort volatile *)(mem+setwin(sc,NPORT));
  783: 
  784: 	printf("dgb%d: %d ports\n",unit,sc->numports);
  785: 
  786: 	if(sc->numports > MAX_DGB_PORTS) {
  787: 		printf("dgb%d: too many ports\n",unit);
  788: 		sc->status=DISABLED;
  789: 		hidewin(sc);
  790: 		return 0;
  791: 	}
  792: 
  793: 	if(nports+sc->numports>NDGBPORTS) {
  794: 		printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports);
  795: 		sc->numports=NDGBPORTS-nports;
  796: 	}
  797: 
  798: 	/* allocate port and tty structures */
  799: 	sc->ports=&dgb_ports[nports];
  800: 	sc->ttys=&dgb_tty[nports];
  801: 	nports+=sc->numports;
  802: 
  803: 	addr=setwin(sc,PORTBASE);
  804: 	pstat=(const ushort volatile *)(mem+addr);
  805: 
  806: 	for(i=0; i<sc->numports && pstat[i]; i++)
  807: 		if(pstat[i])
  808: 			sc->ports[i].status=ENABLED;
  809: 		else {
  810: 			sc->ports[i].status=DISABLED;
  811: 			printf("dgb%d: port%d is broken\n", unit, i);
  812: 		}
  813: 
  814: 	/* We should now init per-port structures */
  815: 	bc=(volatile struct board_chan *)(mem + CHANSTRUCT);
  816: 	sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL);
  817: 
  818: 	if(sc->numports<3)
  819: 		shrinkmem=1;
  820: 	else
  821: 		shrinkmem=0;
  822: 
  823: 	for(i=0; i<sc->numports; i++, bc++) {
  824: 		port= &sc->ports[i];
  825: 
  826: 		port->tty=&sc->ttys[i];
  827: 		port->unit=unit;
  828: 
  829: 		port->brdchan=bc;
  830: 
  831: 		if(sc->altpin) {
  832: 			port->dsr=CD;
  833: 			port->dcd=DSR;
  834: 		} else {
  835: 			port->dcd=CD;
  836: 			port->dsr=DSR;
  837: 		}
  838: 
  839: 		port->pnum=i;
  840: 
  841: 		if(shrinkmem) {
  842: 			DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit);
  843: 			fepcmd(port, SETBUFFER, 32, 0, 0, 0);
  844: 			shrinkmem=0;
  845: 			}
  846: 
  847: 		if(sc->type!=PCXEVE) {
  848: 			port->txptr=mem+((bc->tseg-sc->mem_seg)<<4);
  849: 			port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4);
  850: 			port->txwin=port->rxwin=0;
  851: 		} else {
  852: 			port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF );
  853: 			port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF );
  854: 			port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9);
  855: 			port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9);
  856: 		}
  857: 
  858: 		port->txbufhead=0;
  859: 		port->rxbufhead=0;
  860: 		port->txbufsize=bc->tmax+1;
  861: 		port->rxbufsize=bc->rmax+1;
  862: 
  863: 		lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2);
  864: 		setwin(sc,0);
  865: 		fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
  866: 		fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0);
  867: 		fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0);
  868: 
  869: 		bc->edelay=100;
  870: 		bc->idata=1;
  871: 
  872: 		port->startc=bc->startc;
  873: 		port->startca=bc->startca;
  874: 		port->stopc=bc->stopc;
  875: 		port->stopca=bc->stopca;
  876: 			
  877: 		/*port->close_delay=50;*/
  878: 		port->close_delay=3 * hz;
  879: 		port->do_timestamp=0;
  880: 		port->do_dcd_timestamp=0;
  881: 
  882: 		/*
  883: 		 * We don't use all the flags from <sys/ttydefaults.h> since they
  884: 		 * are only relevant for logins.  It's important to have echo off
  885: 		 * initially so that the line doesn't start blathering before the
  886: 		 * echo flag can be turned off.
  887: 		 */
  888: 		port->it_in.c_iflag = TTYDEF_IFLAG;
  889: 		port->it_in.c_oflag = TTYDEF_OFLAG;
  890: 		port->it_in.c_cflag = TTYDEF_CFLAG;
  891: 		port->it_in.c_lflag = TTYDEF_LFLAG;
  892: 		termioschars(&port->it_in);
  893: 		port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate;
  894: 		port->it_out = port->it_in;
  895: 		/* MAX_DGB_PORTS is 32 => [0-9a-v] */
  896: 		suffix = i < 10 ? '0' + i : 'a' + i - 10;
  897: 		cdevsw_add(&dgb_cdevsw, 0xffff0000, unit << 16);
  898: 		make_dev(&dgb_cdevsw, (unit<<16)+i,
  899: 		    UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
  900: 
  901: 		make_dev(&dgb_cdevsw, (unit<<16)+i+32,
  902: 		    UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
  903: 
  904: 		make_dev(&dgb_cdevsw, (unit<<16)+i+64,
  905: 		    UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
  906: 
  907: 		make_dev(&dgb_cdevsw, (unit<<16)+i+128,
  908: 		    UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
  909: 
  910: 		make_dev(&dgb_cdevsw, (unit<<16)+i+160,
  911: 		    UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
  912: 
  913: 		make_dev(&dgb_cdevsw, (unit<<16)+i+192,
  914: 		    UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
  915: 	}
  916: 
  917: 	hidewin(sc);
  918: 
  919: 	/* register the polling function */
  920: 	timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC);
  921: 
  922: 	return 1;
  923: }
  924: 
  925: /* ARGSUSED */
  926: static	int
  927: dgbopen(dev_t dev, int flag, int mode, struct thread *td)
  928: {
  929: 	struct dgb_softc *sc;
  930: 	struct tty *tp;
  931: 	int unit;
  932: 	int mynor;
  933: 	int pnum;
  934: 	struct dgb_p *port;
  935: 	int s,cs;
  936: 	int error;
  937: 	volatile struct board_chan *bc;
  938: 
  939: 	error=0;
  940: 
  941: 	mynor=minor(dev);
  942: 	unit=MINOR_TO_UNIT(mynor);
  943: 	pnum=MINOR_TO_PORT(mynor);
  944: 
  945: 	if(unit >= NDGB) {
  946: 		DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
  947: 		return ENXIO;
  948: 	}
  949: 
  950: 	sc=&dgb_softc[unit];
  951: 
  952: 	if(sc->status!=ENABLED) {
  953: 		DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
  954: 		return ENXIO;
  955: 	}
  956: 
  957: 	if(pnum>=sc->numports) {
  958: 		DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
  959: 		return ENXIO;
  960: 	}
  961: 
  962: 	if(mynor & CONTROL_MASK)
  963: 		return 0;
  964: 
  965: 	tp=&sc->ttys[pnum];
  966: 	dev->si_tty = tp;
  967: 	port=&sc->ports[pnum];
  968: 	bc=port->brdchan;
  969: 
  970: open_top:
  971: 	
  972: 	s=spltty();
  973: 
  974: 	while(port->closing) {
  975: 		error=tsleep(&port->closing, PCATCH, "dgocl", 0);
  976: 
  977: 		if(error) {
  978: 			DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
  979: 			goto out;
  980: 		}
  981: 	}
  982: 
  983: 	if (tp->t_state & TS_ISOPEN) {
  984: 		/*
  985: 		 * The device is open, so everything has been initialized.
  986: 		 * Handle conflicts.
  987: 		 */
  988: 		if (mynor & CALLOUT_MASK) {
  989: 			if (!port->active_out) {
  990: 				error = EBUSY;
  991: 				DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
  992: 				goto out;
  993: 			}
  994: 		} else {
  995: 			if (port->active_out) {
  996: 				if (flag & O_NONBLOCK) {
  997: 					error = EBUSY;
  998: 					DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
  999: 					goto out;
 1000: 				}
 1001: 				error =	tsleep(&port->active_out,
 1002: 					       PCATCH, "dgbi", 0);
 1003: 				if (error != 0) {
 1004: 					DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
 1005: 						unit,pnum,error);
 1006: 					goto out;
 1007: 				}
 1008: 				splx(s);
 1009: 				goto open_top;
 1010: 			}
 1011: 		}
 1012: 		if (tp->t_state & TS_XCLUDE && suser(td)) {
 1013: 			error = EBUSY;
 1014: 			goto out;
 1015: 		}
 1016: 	} else {
 1017: 		/*
 1018: 		 * The device isn't open, so there are no conflicts.
 1019: 		 * Initialize it.  Initialization is done twice in many
 1020: 		 * cases: to preempt sleeping callin opens if we are
 1021: 		 * callout, and to complete a callin open after DCD rises.
 1022: 		 */
 1023: 		tp->t_oproc=dgbstart;
 1024: 		tp->t_param=dgbparam;
 1025: 		tp->t_stop=dgbstop;
 1026: 		tp->t_dev=dev;
 1027: 		tp->t_termios= (mynor & CALLOUT_MASK) ?
 1028: 							port->it_out :
 1029: 							port->it_in;
 1030: 
 1031: 		cs=splclock();
 1032: 		setwin(sc,0);
 1033: 		port->imodem=bc->mstat;
 1034: 		bc->rout=bc->rin; /* clear input queue */
 1035: 		bc->idata=1;
 1036: #ifdef PRINT_BUFSIZE
 1037: 		printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
 1038: #endif
 1039: 
 1040: 		hidewin(sc);
 1041: 		splx(cs);
 1042: 
 1043: 		port->wopeners++;
 1044: 		error=dgbparam(tp, &tp->t_termios);
 1045: 		port->wopeners--;
 1046: 
 1047: 		if(error!=0) {
 1048: 			DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
 1049: 			goto out;
 1050: 		}
 1051: 
 1052: 		/* handle fake DCD for callout devices */
 1053: 		/* and initial DCD */
 1054: 
 1055: 		if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
 1056: 			linesw[tp->t_line].l_modem(tp,1);
 1057: 
 1058: 	}
 1059: 
 1060: 	/*
 1061: 	 * Wait for DCD if necessary.
 1062: 	 */
 1063: 	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
 1064: 	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
 1065: 		++port->wopeners;
 1066: 		error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
 1067: 		--port->wopeners;
 1068: 		if (error != 0) {
 1069: 			DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
 1070: 			goto out;
 1071: 		}
 1072: 		splx(s);
 1073: 		goto open_top;
 1074: 	}
 1075: 	error =	linesw[tp->t_line].l_open(dev, tp);
 1076: 	disc_optim(tp,&tp->t_termios);
 1077: 	DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
 1078: 
 1079: 	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
 1080: 		port->active_out = TRUE;
 1081: 
 1082: 	port->used=1;
 1083: 
 1084: 	/* If any port is open (i.e. the open() call is completed for it) 
 1085: 	 * the device is busy
 1086: 	 */
 1087: 
 1088: out:
 1089: 	disc_optim(tp,&tp->t_termios);
 1090: 	splx(s);
 1091: 
 1092: 	if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
 1093: 		dgbhardclose(port);
 1094: 
 1095: 	DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
 1096: 
 1097: 	return error;
 1098: }
 1099: 
 1100: /*ARGSUSED*/
 1101: static	int
 1102: dgbclose(dev_t dev, int flag, int mode, struct thread *td)
 1103: {
 1104: 	struct tty *tp;
 1105: 	int unit, pnum;
 1106: 	struct dgb_softc *sc;
 1107: 	struct dgb_p *port;
 1108: 	int mynor;
 1109: 	int s;
 1110: 	int i;
 1111: 
 1112: 	mynor=minor(dev);
 1113: 	if(mynor & CONTROL_MASK)
 1114: 		return 0;
 1115: 	unit=MINOR_TO_UNIT(mynor);
 1116: 	pnum=MINOR_TO_PORT(mynor);
 1117: 
 1118: 	sc=&dgb_softc[unit];
 1119: 	tp=&sc->ttys[pnum];
 1120: 	port=sc->ports+pnum;
 1121: 
 1122: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
 1123: 
 1124: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
 1125:         dgb_drain_or_flush(port);
 1126: 
 1127: 	s=spltty();
 1128: 
 1129: 	port->closing=1;
 1130: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
 1131: 	linesw[tp->t_line].l_close(tp,flag);
 1132: 	disc_optim(tp,&tp->t_termios);
 1133: 
 1134: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
 1135: 	dgbhardclose(port);
 1136: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
 1137: 	ttyclose(tp);
 1138: 	port->closing=0;
 1139: 	wakeup(&port->closing);
 1140: 	port->used=0;
 1141: 
 1142: 	/* mark the card idle when all ports are closed */
 1143: 
 1144: 	for(i=0; i<sc->numports; i++)
 1145: 		if(sc->ports[i].used)
 1146: 			break;
 1147: 
 1148: 	splx(s);
 1149: 
 1150: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
 1151: 
 1152: 	wakeup(TSA_CARR_ON(tp));
 1153: 	wakeup(&port->active_out);
 1154: 	port->active_out=0;
 1155: 
 1156: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
 1157: 
 1158: 	return 0;
 1159: }
 1160: 
 1161: static void
 1162: dgbhardclose(port)
 1163: 	struct dgb_p *port;
 1164: {
 1165: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1166: 	volatile struct board_chan *bc=port->brdchan;
 1167: 	int cs;
 1168: 
 1169: 	cs=splclock();
 1170: 	port->do_timestamp = 0;
 1171: 	setwin(sc,0);
 1172: 
 1173: 	bc->idata=0; bc->iempty=0; bc->ilow=0;
 1174: 	if(port->tty->t_cflag & HUPCL) {
 1175: 		port->omodem &= ~(RTS|DTR);
 1176: 		fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
 1177: 	}
 1178: 
 1179: 	hidewin(sc);
 1180: 	splx(cs);
 1181: 
 1182: 	timeout(dgb_pause, &port->brdchan, hz/2);
 1183: 	tsleep(&port->brdchan, PCATCH, "dgclo", 0);
 1184: }
 1185: 
 1186: static void 
 1187: dgb_pause(chan)
 1188: 	void *chan;
 1189: {
 1190: 	wakeup((caddr_t)chan);
 1191: }
 1192: 
 1193: static void
 1194: dgbpoll(unit_c)
 1195: 	void *unit_c;
 1196: {
 1197: 	int unit=(int)unit_c;
 1198: 	int pnum;
 1199: 	struct dgb_p *port;
 1200: 	struct dgb_softc *sc=&dgb_softc[unit];
 1201: 	int head, tail;
 1202: 	u_char *eventbuf;
 1203: 	int event, mstat, lstat;
 1204: 	volatile struct board_chan *bc;
 1205: 	struct tty *tp;
 1206: 	int rhead, rtail;
 1207: 	int whead, wtail;
 1208: 	int size;
 1209: 	u_char *ptr;
 1210: 	int ocount;
 1211: 	int ibuf_full,obuf_full;
 1212: 
 1213: 	BoardMemWinState ws=bmws_get();
 1214: 
 1215: 	if(sc->status==DISABLED) {
 1216: 		printf("dgb%d: polling of disabled board stopped\n",unit);
 1217: 		return;
 1218: 	}
 1219: 	
 1220: 	setwin(sc,0);
 1221: 
 1222: 	head=sc->mailbox->ein;
 1223: 	tail=sc->mailbox->eout;
 1224: 
 1225: 	while(head!=tail) {
 1226: 		if(head >= FEP_IMAX-FEP_ISTART 
 1227: 		|| tail >= FEP_IMAX-FEP_ISTART 
 1228: 		|| (head|tail) & 03 ) {
 1229: 			printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
 1230: 			break;
 1231: 		}
 1232: 
 1233: 		eventbuf=sc->vmem+tail+FEP_ISTART;
 1234: 		pnum=eventbuf[0];
 1235: 		event=eventbuf[1];
 1236: 		mstat=eventbuf[2];
 1237: 		lstat=eventbuf[3];
 1238: 
 1239: 		port=&sc->ports[pnum];
 1240: 		bc=port->brdchan;
 1241: 		tp=&sc->ttys[pnum];
 1242: 
 1243: 		if(pnum>=sc->numports || port->status==DISABLED) {
 1244: 			printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
 1245: 		} else if(port->used || port->wopeners>0 ) {
 1246: 
 1247: 			int wrapmask=port->rxbufsize-1;
 1248: 
 1249: 			if( !(event & ALL_IND) ) 
 1250: 				printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
 1251: 					unit, pnum, event, mstat, lstat);
 1252: 
 1253: 			if(event & DATA_IND) {
 1254: 				DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
 1255: 
 1256: 				rhead=bc->rin & wrapmask; 
 1257: 				rtail=bc->rout & wrapmask;
 1258: 
 1259: 				if( !(tp->t_cflag & CREAD) || !port->used ) {
 1260: 					bc->rout=rhead;
 1261: 					goto end_of_data;
 1262: 				}
 1263: 
 1264: 				if(bc->orun) {
 1265: 					printf("dgb%d: port%d: overrun\n", unit, pnum);
 1266: 					bc->orun=0;
 1267: 				}
 1268: 
 1269: 				if(!(tp->t_state & TS_ISOPEN))
 1270: 					goto end_of_data;
 1271: 
 1272: 				for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
 1273: 					DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
 1274: 						unit,pnum,rhead,rtail);
 1275: 
 1276: 					if(rhead>rtail)
 1277: 						size=rhead-rtail;
 1278: 					else
 1279: 						size=port->rxbufsize-rtail;
 1280: 
 1281: 					ptr=port->rxptr+rtail;
 1282: 
 1283: /* Helg: */
 1284: 					if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
 1285: 						size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
 1286: 						DPRINT1(DB_RXDATA,"*");
 1287: 						ibuf_full=TRUE;
 1288: 					}
 1289: 
 1290: 					if(size) {
 1291: 						if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1292: 							DPRINT1(DB_RXDATA,"!");
 1293: 							towin(sc,port->rxwin);
 1294: 							tk_nin += size;
 1295: 							tk_rawcc += size;
 1296: 							tp->t_rawcc += size;
 1297: 							b_to_q(ptr,size,&tp->t_rawq);
 1298: 							setwin(sc,0);
 1299: 						} else {
 1300: 							int i=size;
 1301: 							unsigned char chr;
 1302: 							do {
 1303: 								towin(sc,port->rxwin);
 1304: 								chr= *ptr++;
 1305: 								hidewin(sc);
 1306: 							       (*linesw[tp->t_line].l_rint)(chr, tp);
 1307: 							} while (--i > 0 );
 1308: 							setwin(sc,0);
 1309: 						}
 1310: 	 				}
 1311: 					rtail= (rtail + size) & wrapmask;
 1312: 					bc->rout=rtail;
 1313: 					rhead=bc->rin & wrapmask;
 1314: 					hidewin(sc);
 1315: 					ttwakeup(tp);
 1316: 					setwin(sc,0);
 1317: 				}
 1318: 			end_of_data: ;
 1319: 			}
 1320: 
 1321: 			if(event & MODEMCHG_IND) {
 1322: 				DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
 1323: 				port->imodem=mstat;
 1324: 				if(mstat & port->dcd) {
 1325: 					hidewin(sc);
 1326: 					linesw[tp->t_line].l_modem(tp,1);
 1327: 					setwin(sc,0);
 1328: 					wakeup(TSA_CARR_ON(tp));
 1329: 				} else {
 1330: 					hidewin(sc);
 1331: 					linesw[tp->t_line].l_modem(tp,0);
 1332: 					setwin(sc,0);
 1333: 					if( port->draining) {
 1334: 						port->draining=0;
 1335: 						wakeup(&port->draining);
 1336: 					}
 1337: 				}
 1338: 			}
 1339: 
 1340: 			if(event & BREAK_IND) {
 1341: 				if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK))	{
 1342: 				        DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
 1343: 				        hidewin(sc);
 1344: 				        linesw[tp->t_line].l_rint(TTY_BI, tp);
 1345: 				        setwin(sc,0);
 1346: 			        }
 1347: 			}
 1348: 
 1349: /* Helg: with output flow control */
 1350: 
 1351: 			if(event & (LOWTX_IND | EMPTYTX_IND) ) {
 1352: 				DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
 1353: 
 1354: 				if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
 1355: 				&& port->draining) {
 1356: 					port->draining=0;
 1357: 					wakeup(&port->draining);
 1358: 					bc->ilow=0; bc->iempty=0;
 1359: 				} else {
 1360: 
 1361: 					int wrapmask=port->txbufsize-1;
 1362: 
 1363: 					for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
 1364: 						int s;
 1365: 						/* add "last-minute" data to write buffer */
 1366: 						if(!(tp->t_state & TS_BUSY)) {
 1367: 							hidewin(sc);
 1368: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1369: 					                ttwwakeup(tp);
 1370: #else
 1371: 					                if(tp->t_outq.c_cc <= tp->t_lowat) {
 1372: 						                if(tp->t_state & TS_ASLEEP) {
 1373: 							                tp->t_state &= ~TS_ASLEEP;
 1374: 							                wakeup(TSA_OLOWAT(tp));
 1375: 						                }
 1376: 						                /* selwakeup(&tp->t_wsel); */
 1377: 					                }
 1378: #endif
 1379: 					                setwin(sc,0);
 1380: 				                }
 1381: 						s=spltty();
 1382: 
 1383: 					whead=bc->tin & wrapmask;
 1384: 					wtail=bc->tout & wrapmask;
 1385: 
 1386: 					if(whead<wtail)
 1387: 						size=wtail-whead-1;
 1388: 					else {
 1389: 						size=port->txbufsize-whead;
 1390: 						if(wtail==0)
 1391: 							size--;
 1392: 					}
 1393: 
 1394: 					if(size==0) {
 1395: 						DPRINT5(DB_WR,"dgb: head=%d tail=%d size=%d full=%d\n",
 1396: 							whead,wtail,size,obuf_full);
 1397: 						bc->iempty=1; bc->ilow=1;
 1398: 						obuf_full=TRUE;
 1399: 						splx(s);
 1400: 						break;
 1401: 					}
 1402: 
 1403: 					towin(sc,port->txwin);
 1404: 
 1405: 					ocount=q_to_b(&tp->t_outq, port->txptr+whead, size);
 1406: 					whead+=ocount;
 1407: 
 1408: 					setwin(sc,0);
 1409: 					bc->tin=whead;
 1410: 					bc->tin=whead & wrapmask;
 1411: 					splx(s);
 1412: 				}
 1413: 
 1414: 				if(obuf_full) {
 1415: 					DPRINT1(DB_WR," +BUSY\n");
 1416: 					tp->t_state|=TS_BUSY;
 1417: 				} else {
 1418: 					DPRINT1(DB_WR," -BUSY\n");
 1419: 					hidewin(sc);
 1420: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1421: 					/* should clear TS_BUSY before ttwwakeup */
 1422: 					if(tp->t_state & TS_BUSY)	{
 1423: 						tp->t_state &= ~TS_BUSY;
 1424: 						linesw[tp->t_line].l_start(tp);
 1425: 				                ttwwakeup(tp);
 1426: 					}
 1427: #else
 1428: 				if(tp->t_state & TS_ASLEEP) {
 1429: 					tp->t_state &= ~TS_ASLEEP;
 1430: 					wakeup(TSA_OLOWAT(tp));
 1431: 				}
 1432: 				tp->t_state &= ~TS_BUSY;
 1433: #endif
 1434: 				        setwin(sc,0);
 1435: 				        }
 1436: 			        }
 1437: 			}
 1438: 			bc->idata=1;   /* require event on incoming data */ 
 1439: 
 1440: 		} else {
 1441: 			bc=port->brdchan;
 1442: 			DPRINT4(DB_EXCEPT,"dgb%d: port%d: got event 0x%x on closed port\n",
 1443: 				unit,pnum,event);
 1444: 			bc->rout=bc->rin;
 1445: 			bc->idata=bc->iempty=bc->ilow=0;
 1446: 		}
 1447: 
 1448: 		tail= (tail+4) & (FEP_IMAX-FEP_ISTART-4);
 1449: 	}
 1450: 
 1451: 	sc->mailbox->eout=tail;
 1452: 	bmws_set(ws);
 1453: 
 1454: 	timeout(dgbpoll, unit_c, hz/POLLSPERSEC);
 1455: }
 1456: 
 1457: static	int
 1458: dgbioctl(dev_t dev, u_long cmd, caddr_t	data, int flag, struct thread *td)
 1459: {
 1460: 	struct dgb_softc *sc;
 1461: 	int unit, pnum;
 1462: 	struct dgb_p *port;
 1463: 	int mynor;
 1464: 	struct tty *tp;
 1465: 	volatile struct board_chan *bc;
 1466: 	int error;
 1467: 	int s,cs;
 1468: 	int tiocm_xxx;
 1469: 
 1470: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1471: 	u_long		oldcmd;
 1472: 	struct termios	term;
 1473: #endif
 1474: 
 1475: 	BoardMemWinState ws=bmws_get();
 1476: 
 1477: 	mynor=minor(dev);
 1478: 	unit=MINOR_TO_UNIT(mynor);
 1479: 	pnum=MINOR_TO_PORT(mynor);
 1480: 
 1481: 	sc=&dgb_softc[unit];
 1482: 	port=&sc->ports[pnum];
 1483: 	tp=&sc->ttys[pnum];
 1484: 	bc=port->brdchan;
 1485: 
 1486: 	if (mynor & CONTROL_MASK) {
 1487: 		struct termios *ct;
 1488: 
 1489: 		switch (mynor & CONTROL_MASK) {
 1490: 		case CONTROL_INIT_STATE:
 1491: 			ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
 1492: 			break;
 1493: 		case CONTROL_LOCK_STATE:
 1494: 			ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
 1495: 			break;
 1496: 		default:
 1497: 			return (ENODEV);	/* /dev/nodev */
 1498: 		}
 1499: 		switch (cmd) {
 1500: 		case TIOCSETA:
 1501: 			error = suser(td);
 1502: 			if (error != 0)
 1503: 				return (error);
 1504: 			*ct = *(struct termios *)data;
 1505: 			return (0);
 1506: 		case TIOCGETA:
 1507: 			*(struct termios *)data = *ct;
 1508: 			return (0);
 1509: 		case TIOCGETD:
 1510: 			*(int *)data = TTYDISC;
 1511: 			return (0);
 1512: 		case TIOCGWINSZ:
 1513: 			bzero(data, sizeof(struct winsize));
 1514: 			return (0);
 1515: 		default:
 1516: 			return (ENOTTY);
 1517: 		}
 1518: 	}
 1519: 
 1520: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1521: 	term = tp->t_termios;
 1522: 	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1523: 	  DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-ISNOW c=0x%x i=0x%x l=0x%x\n",unit,pnum,term.c_cflag,term.c_iflag,term.c_lflag);
 1524: 	}
 1525: 	oldcmd = cmd;
 1526: 	error = ttsetcompat(tp, &cmd, data, &term);
 1527: 	if (error != 0)
 1528: 		return (error);
 1529: 	if (cmd != oldcmd)
 1530: 		data = (caddr_t)&term;
 1531: #endif
 1532: 
 1533: 	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1534: 		int	cc;
 1535: 		struct termios *dt = (struct termios *)data;
 1536: 		struct termios *lt = mynor & CALLOUT_MASK
 1537: 				     ? &port->lt_out : &port->lt_in;
 1538: 
 1539: 		DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-TOSET c=0x%x i=0x%x l=0x%x\n",unit,pnum,dt->c_cflag,dt->c_iflag,dt->c_lflag);
 1540: 		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
 1541: 			      | (dt->c_iflag & ~lt->c_iflag);
 1542: 		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
 1543: 			      | (dt->c_oflag & ~lt->c_oflag);
 1544: 		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
 1545: 			      | (dt->c_cflag & ~lt->c_cflag);
 1546: 		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
 1547: 			      | (dt->c_lflag & ~lt->c_lflag);
 1548: 		for (cc = 0; cc < NCCS; ++cc)
 1549: 			if (lt->c_cc[cc] != 0)
 1550: 				dt->c_cc[cc] = tp->t_cc[cc];
 1551: 		if (lt->c_ispeed != 0)
 1552: 			dt->c_ispeed = tp->t_ispeed;
 1553: 		if (lt->c_ospeed != 0)
 1554: 			dt->c_ospeed = tp->t_ospeed;
 1555: 	}
 1556: 
 1557: 	if(cmd==TIOCSTOP) {
 1558: 		cs=splclock();
 1559: 		setwin(sc,0);
 1560: 		fepcmd(port, PAUSETX, 0, 0, 0, 0);
 1561: 		bmws_set(ws);
 1562: 		splx(cs);
 1563: 		return 0;
 1564: 	} else if(cmd==TIOCSTART) {
 1565: 		cs=splclock();
 1566: 		setwin(sc,0);
 1567: 		fepcmd(port, RESUMETX, 0, 0, 0, 0);
 1568: 		bmws_set(ws);
 1569: 		splx(cs);
 1570: 		return 0;
 1571: 	}
 1572: 
 1573: 	if(cmd==TIOCSETAW || cmd==TIOCSETAF)
 1574: 		port->mustdrain=1;
 1575: 
 1576: 	error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
 1577: 	if (error != ENOIOCTL)
 1578: 		return error;
 1579: 	s = spltty();
 1580: 	error = ttioctl(tp, cmd, data, flag);
 1581: 	disc_optim(tp,&tp->t_termios);
 1582: 	port->mustdrain=0;
 1583: 	if (error != ENOIOCTL) {
 1584: 		splx(s);
 1585: 		if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1586: 			DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-RES c=0x%x i=0x%x l=0x%x\n",unit,pnum,tp->t_cflag,tp->t_iflag,tp->t_lflag);
 1587: 		}
 1588: 		return error;
 1589: 	}
 1590: 
 1591: 	switch (cmd) {
 1592: 	case TIOCSBRK:
 1593: /* Helg: commented */
 1594: /*		error=dgbdrain(port);*/
 1595: 
 1596: 		if(error!=0) {
 1597: 			splx(s);
 1598: 			return error;
 1599: 		}
 1600: 
 1601: 		cs=splclock();
 1602: 		setwin(sc,0);
 1603: 	
 1604: 		/* now it sends 250 millisecond break because I don't know */
 1605: 		/* how to send an infinite break */
 1606: 
 1607: 		fepcmd(port, SENDBREAK, 250, 0, 10, 0);
 1608: 		hidewin(sc);
 1609: 		splx(cs);
 1610: 		break;
 1611: 	case TIOCCBRK:
 1612: 		/* now it's empty */
 1613: 		break;
 1614: 	case TIOCSDTR:
 1615: 		DPRINT3(DB_MODEM,"dgb%d: port%d: set DTR\n",unit,pnum);
 1616: 		port->omodem |= DTR;
 1617: 		cs=splclock();
 1618: 		setwin(sc,0);
 1619: 		fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
 1620: 
 1621: 		if( !(bc->mstat & DTR) ) {
 1622: 			DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is off\n",unit,pnum);
 1623: 		}
 1624: 
 1625: 		hidewin(sc);
 1626: 		splx(cs);
 1627: 		break;
 1628: 	case TIOCCDTR:
 1629: 		DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
 1630: 		port->omodem &= ~DTR;
 1631: 		cs=splclock();
 1632: 		setwin(sc,0);
 1633: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1634: 
 1635: 		if( bc->mstat & DTR ) {
 1636: 			DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is on\n",unit,pnum);
 1637: 		}
 1638: 
 1639: 		hidewin(sc);
 1640: 		splx(cs);
 1641: 		break;
 1642: 	case TIOCMSET:
 1643: 		if(*(int *)data & TIOCM_DTR)
 1644: 			port->omodem |=DTR;
 1645: 		else
 1646: 			port->omodem &=~DTR;
 1647: 
 1648: 		if(*(int *)data & TIOCM_RTS)
 1649: 			port->omodem |=RTS;
 1650: 		else
 1651: 			port->omodem &=~RTS;
 1652: 
 1653: 		cs=splclock();
 1654: 		setwin(sc,0);
 1655: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1656: 		hidewin(sc);
 1657: 		splx(cs);
 1658: 		break;
 1659: 	case TIOCMBIS:
 1660: 		if(*(int *)data & TIOCM_DTR)
 1661: 			port->omodem |=DTR;
 1662: 
 1663: 		if(*(int *)data & TIOCM_RTS)
 1664: 			port->omodem |=RTS;
 1665: 
 1666: 		cs=splclock();
 1667: 		setwin(sc,0);
 1668: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1669: 		hidewin(sc);
 1670: 		splx(cs);
 1671: 		break;
 1672: 	case TIOCMBIC:
 1673: 		if(*(int *)data & TIOCM_DTR)
 1674: 			port->omodem &=~DTR;
 1675: 
 1676: 		if(*(int *)data & TIOCM_RTS)
 1677: 			port->omodem &=~RTS;
 1678: 
 1679: 		cs=splclock();
 1680: 		setwin(sc,0);
 1681: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1682: 		hidewin(sc);
 1683: 		splx(cs);
 1684: 		break;
 1685: 	case TIOCMGET:
 1686: 		setwin(sc,0);
 1687: 		port->imodem=bc->mstat;
 1688: 		hidewin(sc);
 1689: 
 1690: 		tiocm_xxx = TIOCM_LE;	/* XXX - always enabled while open */
 1691: 
 1692: 		DPRINT3(DB_MODEM,"dgb%d: port%d: modem stat -- ",unit,pnum);
 1693: 
 1694: 		if (port->imodem & DTR) {
 1695: 			DPRINT1(DB_MODEM,"DTR ");
 1696: 			tiocm_xxx |= TIOCM_DTR;
 1697: 		}
 1698: 		if (port->imodem & RTS) {
 1699: 			DPRINT1(DB_MODEM,"RTS ");
 1700: 			tiocm_xxx |= TIOCM_RTS;
 1701: 		}
 1702: 		if (port->imodem & CTS) {
 1703: 			DPRINT1(DB_MODEM,"CTS ");
 1704: 			tiocm_xxx |= TIOCM_CTS;
 1705: 		}
 1706: 		if (port->imodem & port->dcd) {
 1707: 			DPRINT1(DB_MODEM,"DCD ");
 1708: 			tiocm_xxx |= TIOCM_CD;
 1709: 		}
 1710: 		if (port->imodem & port->dsr) {
 1711: 			DPRINT1(DB_MODEM,"DSR ");
 1712: 			tiocm_xxx |= TIOCM_DSR;
 1713: 		}
 1714: 		if (port->imodem & RI) {
 1715: 			DPRINT1(DB_MODEM,"RI ");
 1716: 			tiocm_xxx |= TIOCM_RI;
 1717: 		}
 1718: 		*(int *)data = tiocm_xxx;
 1719: 		DPRINT1(DB_MODEM,"--\n");
 1720: 		break;
 1721: 	case TIOCMSDTRWAIT:
 1722: 		/* must be root since the wait applies to following logins */
 1723: 		error = suser(td);
 1724: 		if (error != 0) {
 1725: 			splx(s);
 1726: 			return (error);
 1727: 		}
 1728: 		port->close_delay = *(int *)data * hz / 100;
 1729: 		break;
 1730: 	case TIOCMGDTRWAIT:
 1731: 		*(int *)data = port->close_delay * 100 / hz;
 1732: 		break;
 1733: 	case TIOCTIMESTAMP:
 1734: 		port->do_timestamp = TRUE;
 1735: 		*(struct timeval *)data = port->timestamp;
 1736: 		break;
 1737: 	case TIOCDCDTIMESTAMP:
 1738: 		port->do_dcd_timestamp = TRUE;
 1739: 		*(struct timeval *)data = port->dcd_timestamp;
 1740: 		break;
 1741: 	default:
 1742: 		bmws_set(ws);
 1743: 		splx(s);
 1744: 		return ENOTTY;
 1745: 	}
 1746: 	bmws_set(ws);
 1747: 	splx(s);
 1748: 
 1749: 	return 0;
 1750: }
 1751: 
 1752: static void 
 1753: wakeflush(p)
 1754: 	void *p;
 1755: {
 1756: 	struct dgb_p *port=p;
 1757: 
 1758: 	wakeup(&port->draining);
 1759: }
 1760: 
 1761: /* wait for the output to drain */
 1762: 
 1763: static int
 1764: dgbdrain(port)
 1765: 	struct dgb_p	*port;
 1766: {
 1767: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1768: 	volatile struct board_chan *bc=port->brdchan;
 1769: 	int error;
 1770: 	int head, tail;
 1771: 
 1772: 	BoardMemWinState ws=bmws_get();
 1773: 
 1774: 	setwin(sc,0);
 1775: 
 1776: 	bc->iempty=1;
 1777: 	tail=bc->tout;
 1778: 	head=bc->tin;
 1779: 
 1780: 	while(tail!=head) {
 1781: 		DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
 1782: 			port->unit, port->pnum, head, tail);
 1783: 
 1784: 		hidewin(sc);
 1785: 		port->draining=1;
 1786: 		timeout(wakeflush,port, hz);
 1787: 		error=tsleep(&port->draining, PCATCH, "dgdrn", 0);
 1788: 		port->draining=0;
 1789: 		setwin(sc,0);
 1790: 
 1791: 		if (error != 0) {
 1792: 			DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgdrn) error=%d\n",
 1793: 				port->unit,port->pnum,error);
 1794: 
 1795: 			bc->iempty=0;
 1796: 			bmws_set(ws);
 1797: 			return error;
 1798: 		}
 1799: 
 1800: 		tail=bc->tout;
 1801: 		head=bc->tin;
 1802: 	}
 1803: 	DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
 1804: 		port->unit, port->pnum, head, tail);
 1805: 	bmws_set(ws);
 1806: 	return 0;
 1807: }
 1808: 
 1809: /* wait for the output to drain */
 1810: /* or simply clear the buffer it it's stopped */
 1811: 
 1812: static void
 1813: dgb_drain_or_flush(port)
 1814: 	struct dgb_p	*port;
 1815: {
 1816: 	struct tty *tp=port->tty;
 1817: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1818: 	volatile struct board_chan *bc=port->brdchan;
 1819: 	int error;
 1820: 	int lasttail;
 1821: 	int head, tail;
 1822: 
 1823: 	setwin(sc,0);
 1824: 
 1825: 	lasttail=-1;
 1826: 	bc->iempty=1;
 1827: 	tail=bc->tout;
 1828: 	head=bc->tin;
 1829: 
 1830: 	while(tail!=head /* && tail!=lasttail */ ) {
 1831: 		DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
 1832: 			port->unit, port->pnum, head, tail);
 1833: 
 1834: 		/* if there is no carrier simply clean the buffer */
 1835: 		if( !(tp->t_state & TS_CARR_ON) ) {
 1836: 			bc->tout=bc->tin=0;
 1837: 			bc->iempty=0;
 1838: 			hidewin(sc);
 1839: 			return;
 1840: 		}
 1841: 
 1842: 		hidewin(sc);
 1843: 		port->draining=1;
 1844: 		timeout(wakeflush,port, hz);
 1845: 		error=tsleep(&port->draining, PCATCH, "dgfls", 0);
 1846: 		port->draining=0;
 1847: 		setwin(sc,0);
 1848: 
 1849: 		if (error != 0) {
 1850: 			DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgfls) error=%d\n",
 1851: 				port->unit,port->pnum,error);
 1852: 
 1853: 			/* silently clean the buffer */
 1854: 
 1855: 			bc->tout=bc->tin=0;
 1856: 			bc->iempty=0;
 1857: 			hidewin(sc);
 1858: 			return;
 1859: 		}
 1860: 
 1861: 		lasttail=tail;
 1862: 		tail=bc->tout;
 1863: 		head=bc->tin;
 1864: 	}
 1865: 	hidewin(sc);
 1866: 	DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
 1867: 			port->unit, port->pnum, head, tail);
 1868: }
 1869: 
 1870: static int
 1871: dgbparam(tp, t)
 1872: 	struct tty	*tp;
 1873: 	struct termios	*t;
 1874: {
 1875: 	int unit=MINOR_TO_UNIT(minor(tp->t_dev));
 1876: 	int pnum=MINOR_TO_PORT(minor(tp->t_dev));
 1877: 	struct dgb_softc *sc=&dgb_softc[unit];
 1878: 	struct dgb_p *port=&sc->ports[pnum];
 1879: 	volatile struct board_chan *bc=port->brdchan;
 1880: 	int cflag;
 1881: 	int head;
 1882: 	int mval;
 1883: 	int iflag;
 1884: 	int hflow;
 1885: 	int cs;
 1886: 
 1887: 	BoardMemWinState ws=bmws_get();
 1888: 
 1889: 	DPRINT6(DB_PARAM,"dgb%d: port%d: dgbparm c=0x%x i=0x%x l=0x%x\n",unit,pnum,t->c_cflag,t->c_iflag,t->c_lflag);
 1890: 
 1891: 	if(port->mustdrain) {
 1892: 		DPRINT3(DB_PARAM,"dgb%d: port%d: must call dgbdrain()\n",unit,pnum);
 1893: 		dgbdrain(port);
 1894: 	}
 1895: 
 1896: 	cflag=ttspeedtab(t->c_ospeed, dgbspeedtab);
 1897: 
 1898: 	if (t->c_ispeed == 0)
 1899: 		t->c_ispeed = t->c_ospeed;
 1900: 
 1901: 	if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
 1902: 		DPRINT4(DB_PARAM,"dgb%d: port%d: invalid cflag=0%o\n",unit,pnum,cflag);
 1903: 		return (EINVAL);
 1904: 	}
 1905: 
 1906: 	cs=splclock();
 1907: 	setwin(sc,0);
 1908: 
 1909: 	if(cflag==0) { /* hangup */
 1910: 		DPRINT3(DB_PARAM,"dgb%d: port%d: hangup\n",unit,pnum);
 1911: 		head=bc->rin;
 1912: 		bc->rout=head;
 1913: 		head=bc->tin;
 1914: 		fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
 1915: 		mval= port->omodem & ~(DTR|RTS);
 1916: 	} else {
 1917: 		cflag |= dgbflags(dgb_cflags, t->c_cflag);
 1918: 
 1919: 		if(cflag!=port->fepcflag) {
 1920: 			port->fepcflag=cflag;
 1921: 			DPRINT5(DB_PARAM,"dgb%d: port%d: set cflag=0x%x c=0x%x\n",
 1922: 					unit,pnum,cflag,t->c_cflag&~CRTSCTS);
 1923: 			fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
 1924: 		}
 1925: 		mval= port->omodem | (DTR|RTS);
 1926: 	}
 1927: 
 1928: 	iflag=dgbflags(dgb_iflags, t->c_iflag);
 1929: 	if(iflag!=port->fepiflag) {
 1930: 		port->fepiflag=iflag;
 1931: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set iflag=0x%x c=0x%x\n",unit,pnum,iflag,t->c_iflag);
 1932: 		fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
 1933: 	}
 1934: 
 1935: 	bc->mint=port->dcd;
 1936: 
 1937: 	hflow=dgbflags(dgb_flow, t->c_cflag);
 1938: 	if(hflow!=port->hflow) {
 1939: 		port->hflow=hflow;
 1940: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set hflow=0x%x f=0x%x\n",unit,pnum,hflow,t->c_cflag&CRTSCTS);
 1941: 		fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
 1942: 	}
 1943: 	
 1944: 	if(port->omodem != mval) {
 1945: 		DPRINT5(DB_PARAM,"dgb%d: port%d: setting modem parameters 0x%x was 0x%x\n",
 1946: 			unit,pnum,mval,port->omodem);
 1947: 		port->omodem=mval;
 1948: 		fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
 1949: 	}
 1950: 
 1951: 	if(port->fepstartc!=t->c_cc[VSTART] || port->fepstopc!=t->c_cc[VSTOP]) {
 1952: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set startc=%d, stopc=%d\n",unit,pnum,t->c_cc[VSTART],t->c_cc[VSTOP]);
 1953: 		port->fepstartc=t->c_cc[VSTART];
 1954: 		port->fepstopc=t->c_cc[VSTOP];
 1955: 		fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
 1956: 	}
 1957: 
 1958: 	bmws_set(ws);
 1959: 	splx(cs);
 1960: 
 1961: 	return 0;
 1962: 
 1963: }
 1964: 
 1965: static void
 1966: dgbstart(tp)
 1967: 	struct tty	*tp;
 1968: {
 1969: 	int unit;
 1970: 	int pnum;
 1971: 	struct dgb_p *port;
 1972: 	struct dgb_softc *sc;
 1973: 	volatile struct board_chan *bc;
 1974: 	int head, tail;
 1975: 	int size, ocount;
 1976: 	int s;
 1977: 	int wmask;
 1978: 
 1979: 	BoardMemWinState ws=bmws_get();
 1980: 
 1981: 	unit=MINOR_TO_UNIT(minor(tp->t_dev));
 1982: 	pnum=MINOR_TO_PORT(minor(tp->t_dev));
 1983: 	sc=&dgb_softc[unit];
 1984: 	port=&sc->ports[pnum];
 1985: 	bc=port->brdchan;
 1986: 
 1987: 	wmask=port->txbufsize-1;
 1988: 
 1989: 	s=spltty();
 1990: 
 1991: 	while( tp->t_outq.c_cc!=0 ) {
 1992: 		int cs;
 1993: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1994: 		ttwwakeup(tp);
 1995: #else
 1996: 		if(tp->t_outq.c_cc <= tp->t_lowat) {
 1997: 			if(tp->t_state & TS_ASLEEP) {
 1998: 				tp->t_state &= ~TS_ASLEEP;
 1999: 				wakeup(TSA_OLOWAT(tp));
 2000: 			}
 2001: 			/*selwakeup(&tp->t_wsel);*/
 2002: 		}
 2003: #endif
 2004: 		cs=splclock();
 2005: 		setwin(sc,0);
 2006: 
 2007: 		head=bc->tin & wmask;
 2008: 
 2009: 		do { tail=bc->tout; } while (tail != bc->tout);
 2010: 		tail=bc->tout & wmask;
 2011: 
 2012: 		DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
 2013: 
 2014: #ifdef LEAVE_FREE_CHARS 
 2015: 		if(tail>head) {
 2016: 			size=tail-head-LEAVE_FREE_CHARS;
 2017: 			if (size <0)
 2018: 			        size=0;
 2019: 		        } else {
 2020: 			        size=port->txbufsize-head;
 2021: 			        if(tail+port->txbufsize < head)
 2022: 				        size=0;
 2023: 		        }
 2024: 		}
 2025: #else
 2026: 		if(tail>head)
 2027: 			size=tail-head-1;
 2028: 		else {
 2029: 			size=port->txbufsize-head/*-1*/;
 2030: 			if(tail==0)
 2031: 				size--;
 2032: 		}
 2033: #endif
 2034: 
 2035: 		if(size==0) {
 2036: 			bc->iempty=1; bc->ilow=1;
 2037: 			splx(cs);
 2038: 			bmws_set(ws);
 2039: 			tp->t_state|=TS_BUSY;
 2040: 			splx(s);
 2041: 			return;
 2042: 		}
 2043: 
 2044: 		towin(sc,port->txwin);
 2045: 
 2046: 		ocount=q_to_b(&tp->t_outq, port->txptr+head, size);
 2047: 		head+=ocount;
 2048: 		if(head>=port->txbufsize)
 2049: 			head-=port->txbufsize;
 2050: 
 2051: 		setwin(sc,0);
 2052: 		bc->tin=head;
 2053: 
 2054: 		DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
 2055: 		hidewin(sc);
 2056: 		splx(cs);
 2057: 	}
 2058: 
 2059: 	bmws_set(ws);
 2060: 	splx(s);
 2061: 
 2062: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 2063: 	if(tp->t_state & TS_BUSY) {	
 2064: 		tp->t_state&=~TS_BUSY;
 2065: 		linesw[tp->t_line].l_start(tp);
 2066: 		ttwwakeup(tp);
 2067: 	}
 2068: #else
 2069: 	if(tp->t_state & TS_ASLEEP) {
 2070: 		tp->t_state &= ~TS_ASLEEP;
 2071: 		wakeup(TSA_OLOWAT(tp));
 2072: 	}
 2073: 	tp->t_state&=~TS_BUSY;
 2074: #endif
 2075: }
 2076: 
 2077: void
 2078: dgbstop(tp, rw)
 2079: 	struct tty	*tp;
 2080: 	int		rw;
 2081: {
 2082: 	int unit;
 2083: 	int pnum;
 2084: 	struct dgb_p *port;
 2085: 	struct dgb_softc *sc;
 2086: 	volatile struct board_chan *bc;
 2087: 	int s;
 2088: 
 2089: 	BoardMemWinState ws=bmws_get();
 2090: 
 2091: 	unit=MINOR_TO_UNIT(minor(tp->t_dev));
 2092: 	pnum=MINOR_TO_PORT(minor(tp->t_dev));
 2093: 
 2094: 	sc=&dgb_softc[unit];
 2095: 	port=&sc->ports[pnum];
 2096: 	bc=port->brdchan;
 2097: 
 2098: 	DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
 2099: 
 2100: 	s = spltty();
 2101: 	setwin(sc,0);
 2102: 
 2103: 	if (rw & FWRITE) {
 2104: 		/* clear output queue */
 2105: 		bc->tout=bc->tin=0;
 2106: 		bc->ilow=0;bc->iempty=0;
 2107: 	}
 2108: 	if (rw & FREAD) {
 2109: 		/* clear input queue */
 2110: 		bc->rout=bc->rin;
 2111: 		bc->idata=1;
 2112: 	}
 2113: 	hidewin(sc);
 2114: 	bmws_set(ws);
 2115: 	splx(s);
 2116: 	dgbstart(tp);
 2117: }
 2118: 
 2119: static void 
 2120: fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
 2121: 	struct dgb_p *port;
 2122: 	unsigned cmd, op1, op2, ncmds, bytecmd;
 2123: {
 2124: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 2125: 	u_char *mem=sc->vmem;
 2126: 	unsigned tail, head;
 2127: 	int count, n;
 2128: 
 2129: 	if(port->status==DISABLED) {
 2130: 		printf("dgb%d: port%d: FEP command on disabled port\n", 
 2131: 			port->unit, port->pnum);
 2132: 		return;
 2133: 	}
 2134: 
 2135: 	/* setwin(sc,0); Require this to be set by caller */
 2136: 	head=sc->mailbox->cin;
 2137: 
 2138: 	if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
 2139: 		printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
 2140: 			port->unit, port->pnum, head);
 2141: 		return;
 2142: 	}
 2143: 
 2144: 	mem[head+FEP_CSTART+0]=cmd;
 2145: 	mem[head+FEP_CSTART+1]=port->pnum;
 2146: 	if(bytecmd) {
 2147: 		mem[head+FEP_CSTART+2]=op1;
 2148: 		mem[head+FEP_CSTART+3]=op2;
 2149: 	} else {
 2150: 		mem[head+FEP_CSTART+2]=op1&0xff;
 2151: 		mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
 2152: 	}
 2153: 
 2154: 	DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
 2155: 			(bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
 2156: 
 2157: 	head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
 2158: 	sc->mailbox->cin=head;
 2159: 
 2160: 	count=FEPTIMEOUT;
 2161: 
 2162: 	while (count-- != 0) {
 2163: 		head=sc->mailbox->cin;
 2164: 		tail=sc->mailbox->cout;
 2165: 
 2166: 		n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
 2167: 		if(n <= ncmds * (sizeof(ushort)*4))
 2168: 			return;
 2169: 	}
 2170: 	printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
 2171: }
 2172: 
 2173: static void 
 2174: disc_optim(tp, t)
 2175: 	struct tty	*tp;
 2176: 	struct termios	*t;
 2177: {
 2178: 	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 2179: 	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 2180: 	    && (!(t->c_iflag & PARMRK)
 2181: 		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 2182: 	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 2183: 	    && linesw[tp->t_line].l_rint == ttyinput)
 2184: 		tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2185: 	else
 2186: 		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2187: }