File:  [DragonFly] / src / sys / i386 / gnu / isa / Attic / dgb.c
Revision 1.10: download - view: text, annotated - select for diffs
Thu May 13 23:49:23 2004 UTC (10 years, 7 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:  *  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.10 2004/05/13 23:49:23 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: 	static int once;
  409: 
  410: 	if (!once++)
  411: 		cdevsw_add(&dgb_cdevsw);
  412: 	sc->unit=dev->id_unit;
  413: 	sc->port=dev->id_iobase;
  414: 
  415: 	if(dev->id_flags & DGBFLAG_ALTPIN)
  416: 		sc->altpin=1;
  417: 	else
  418: 		sc->altpin=0;
  419: 
  420: 	/* left 24 bits only (ISA address) */
  421: 	sc->pmem=((intptr_t)(void *)dev->id_maddr & 0xFFFFFF); 
  422: 	
  423: 	DPRINT4(DB_INFO,"dgb%d: port 0x%x mem 0x%lx\n",unit,sc->port,sc->pmem);
  424: 
  425: 	outb(sc->port, FEPRST);
  426: 	sc->status=DISABLED;
  427: 
  428: 	for(i=0; i< 1000; i++) {
  429: 		DELAY(1);
  430: 		if( (inb(sc->port) & FEPMASK) == FEPRST ) {
  431: 			sc->status=ENABLED;
  432: 			DPRINT3(DB_EXCEPT,"dgb%d: got reset after %d us\n",unit,i);
  433: 			break;
  434: 		}
  435: 	}
  436: 
  437: 	if(sc->status!=ENABLED) {
  438: 		DPRINT2(DB_EXCEPT,"dgb%d: failed to respond\n",dev->id_unit);
  439: 		return 0;
  440: 	}
  441: 
  442: 	/* check type of card and get internal memory characteristics */
  443: 
  444: 	v=inb(sc->port);
  445: 
  446: 	if( v & 0x1 ) {
  447: 		switch( v&0x30 ) {
  448: 		case 0:
  449: 			sc->mem_seg=0xF000;
  450: 			win_size=0x10000;
  451: 			printf("dgb%d: PC/Xi 64K\n",dev->id_unit);
  452: 			break;
  453: 		case 0x10:
  454: 			sc->mem_seg=0xE000;
  455: 			win_size=0x20000;
  456: 			printf("dgb%d: PC/Xi 128K\n",dev->id_unit);
  457: 			break;
  458: 		case 0x20:
  459: 			sc->mem_seg=0xC000;
  460: 			win_size=0x40000;
  461: 			printf("dgb%d: PC/Xi 256K\n",dev->id_unit);
  462: 			break;
  463: 		default: /* case 0x30: */
  464: 			sc->mem_seg=0x8000;
  465: 			win_size=0x80000;
  466: 			printf("dgb%d: PC/Xi 512K\n",dev->id_unit);
  467: 			break;
  468: 		}
  469: 		sc->type=PCXI;
  470: 	} else {
  471: 		outb(sc->port, 1);
  472: 		v=inb(sc->port);
  473: 
  474: 		if( v & 0x1 ) {
  475: 			printf("dgb%d: PC/Xm isn't supported\n",dev->id_unit);
  476: 			sc->status=DISABLED;
  477: 			return 0;
  478: 			}
  479: 
  480: 		sc->mem_seg=0xF000;
  481: 
  482: 		if(dev->id_flags==DGBFLAG_NOWIN || ( v&0xC0 )==0) {
  483: 			win_size=0x10000;
  484: 			printf("dgb%d: PC/Xe 64K\n",dev->id_unit);
  485: 			sc->type=PCXE;
  486: 		} else {
  487: 			win_size=0x2000;
  488: 			printf("dgb%d: PC/Xe 64/8K (windowed)\n",dev->id_unit);
  489: 			sc->type=PCXEVE;
  490: 			if((u_long)sc->pmem & ~0xFFE000) {
  491: 				printf("dgb%d: warning: address 0x%lx truncated to 0x%lx\n",
  492: 					dev->id_unit, sc->pmem,
  493: 					sc->pmem & 0xFFE000);
  494: 
  495: 				dev->id_maddr= (u_char *)(void *)(intptr_t)( sc->pmem & 0xFFE000 );
  496: 			}
  497: 		}
  498: 	}
  499: 
  500: 	/* save size of vizible memory segment */
  501: 	dev->id_msize=win_size;
  502: 
  503: 	/* map memory */
  504: 	dev->id_maddr=sc->vmem=pmap_mapdev(sc->pmem,dev->id_msize);
  505: 
  506: 	outb(sc->port, FEPCLR); /* drop RESET */
  507: 	hidewin(sc); /* Helg: to set initial bmws state */
  508: 
  509: 	return 4; /* we need I/O space of 4 ports */
  510: }
  511: 
  512: static int
  513: dgbattach(dev)
  514: 	struct isa_device	*dev;
  515: {
  516: 	int unit=dev->id_unit;
  517: 	struct dgb_softc *sc= &dgb_softc[dev->id_unit];
  518: 	int i, t;
  519: 	u_char volatile *mem;
  520: 	u_char volatile *ptr;
  521: 	int addr;
  522: 	struct dgb_p *port;
  523: 	volatile struct board_chan *bc;
  524: 	int shrinkmem;
  525: 	int nfails;
  526: 	const volatile ushort *pstat;
  527: 	int lowwater;
  528: 	static int nports=0;
  529: 	char suffix;
  530: 
  531: 	if(sc->status!=ENABLED) {
  532: 		DPRINT2(DB_EXCEPT,"dbg%d: try to attach a disabled card\n",unit);
  533: 		return 0;
  534: 		}
  535: 
  536: 	mem=sc->vmem;
  537: 
  538: 	DPRINT3(DB_INFO,"dgb%d: internal memory segment 0x%x\n",unit,sc->mem_seg);
  539: 
  540: 	outb(sc->port, FEPRST); DELAY(1);
  541: 
  542: 	for(i=0; (inb(sc->port) & FEPMASK) != FEPRST ; i++) {
  543: 		if(i>10000) {
  544: 			printf("dgb%d: 1st reset failed\n",dev->id_unit);
  545: 			sc->status=DISABLED;
  546: 			hidewin(sc);
  547: 			return 0;
  548: 		}
  549: 		DELAY(1);
  550: 	}
  551: 
  552: 	DPRINT3(DB_INFO,"dgb%d: got reset after %d us\n",unit,i);
  553: 
  554: 	/* for PCXEVE set up interrupt and base address */
  555: 
  556: 	if(sc->type==PCXEVE) {
  557: 		t=(((u_long)sc->pmem>>8) & 0xFFE0) | 0x10 /* enable windowing */;
  558: 		/* IRQ isn't used */
  559: 		outb(sc->port+2,t & 0xFF);
  560: 		outb(sc->port+3,t>>8);
  561: 	} else if(sc->type==PCXE) {
  562: 		t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */;
  563: 		outb(sc->port+2,t & 0xFF);
  564: 		outb(sc->port+3,t>>8);
  565: 	}
  566: 
  567: 
  568: 	if(sc->type==PCXI || sc->type==PCXE) {
  569: 		outb(sc->port, FEPRST|FEPMEM); DELAY(1);
  570: 
  571: 		for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) {
  572: 			if(i>10000) {
  573: 				printf("dgb%d: 2nd reset failed\n",dev->id_unit);
  574: 				sc->status=DISABLED;
  575: 				hidewin(sc);
  576: 				return 0;
  577: 			}
  578: 			DELAY(1);
  579: 		}
  580: 
  581: 		DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i);
  582: 	}
  583: 
  584: 	mem=sc->vmem;
  585: 
  586: 	/* very short memory test */
  587: 
  588: 	addr=setinitwin(sc,BOTWIN);
  589: 	*(u_long volatile *)(mem+addr) = 0xA55A3CC3;
  590: 	if(*(u_long volatile *)(mem+addr)!=0xA55A3CC3) {
  591: 		printf("dgb%d: 1st memory test failed\n",dev->id_unit);
  592: 		sc->status=DISABLED;
  593: 		hidewin(sc);
  594: 		return 0;
  595: 	}
  596: 		
  597: 	addr=setinitwin(sc,TOPWIN);
  598: 	*(u_long volatile *)(mem+addr) = 0x5AA5C33C;
  599: 	if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
  600: 		printf("dgb%d: 2nd memory test failed\n",dev->id_unit);
  601: 		sc->status=DISABLED;
  602: 		hidewin(sc);
  603: 		return 0;
  604: 	}
  605: 		
  606: 	addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4));
  607: 	*(u_long volatile *)(mem+addr) = 0x5AA5C33C;
  608: 	if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
  609: 		printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit);
  610: 	}
  611: 		
  612: 	addr=setinitwin(sc,MISCGLOBAL);
  613: 	for(i=0; i<16; i++) {
  614: 		mem[addr+i]=0;
  615: 	}
  616: 
  617: 	if(sc->type==PCXI || sc->type==PCXE) {
  618: 
  619: 		addr=BIOSCODE+((0xF000-sc->mem_seg)<<4);
  620: 
  621: 		DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr);
  622: 
  623: 		ptr= mem+addr;
  624: 
  625: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  626: 			*ptr = pcxx_bios[i];
  627: 
  628: 		ptr= mem+addr;
  629: 
  630: 		nfails=0;
  631: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  632: 			if( *ptr != pcxx_bios[i] ) {
  633: 				DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
  634: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
  635: 
  636: 				if(++nfails>=5) {
  637: 					printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
  638: 					break;
  639: 					}
  640: 				}
  641: 
  642: 		outb(sc->port,FEPMEM);
  643: 
  644: 		for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) {
  645: 			if(i>10000) {
  646: 				printf("dgb%d: BIOS start failed\n",dev->id_unit);
  647: 				sc->status=DISABLED;
  648: 				hidewin(sc);
  649: 				return 0;
  650: 			}
  651: 			DELAY(1);
  652: 		}
  653: 
  654: 		DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
  655: 
  656: 		for(i=0; i<200000; i++) {
  657: 			if( *((ushort volatile *)(mem+MISCGLOBAL)) == *((ushort *)"GD") )
  658: 				goto load_fep;
  659: 			DELAY(1);
  660: 		}
  661: 		printf("dgb%d: BIOS download failed\n",dev->id_unit);
  662: 		DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n",
  663: 			dev->id_unit,
  664: 			*((ushort volatile *)(mem+MISCGLOBAL)),
  665: 			*((ushort *)"GD"));
  666: 
  667: 		sc->status=DISABLED;
  668: 		hidewin(sc);
  669: 		return 0;
  670: 	}
  671: 
  672: 	if(sc->type==PCXEVE) {
  673: 		/* set window 7 */
  674: 		outb(sc->port+1,0xFF);
  675: 
  676: 		ptr= mem+(BIOSCODE & 0x1FFF);
  677: 
  678: 		for(i=0; i<pcxx_nbios; i++)
  679: 			*ptr++ = pcxx_bios[i];
  680: 
  681: 		ptr= mem+(BIOSCODE & 0x1FFF);
  682: 
  683: 		nfails=0;
  684: 		for(i=0; i<pcxx_nbios; i++, ptr++)
  685: 			if( *ptr != pcxx_bios[i] ) {
  686: 				DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
  687: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
  688: 
  689: 				if(++nfails>=5) {
  690: 					printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
  691: 					break;
  692: 					}
  693: 				}
  694: 
  695: 		outb(sc->port,FEPCLR);
  696: 
  697: 		setwin(sc,0);
  698: 
  699: 		for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) {
  700: 			if(i>10000) {
  701: 				printf("dgb%d: BIOS start failed\n",dev->id_unit);
  702: 				sc->status=DISABLED;
  703: 				hidewin(sc);
  704: 				return 0;
  705: 			}
  706: 			DELAY(1);
  707: 		}
  708: 
  709: 		DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
  710: 
  711: 		addr=setwin(sc,MISCGLOBAL);
  712: 
  713: 		for(i=0; i<200000; i++) {
  714: 			if(*(ushort volatile *)(mem+addr)== *(ushort *)"GD")
  715: 				goto load_fep;
  716: 			DELAY(1);
  717: 		}
  718: 		printf("dgb%d: BIOS download failed\n",dev->id_unit);
  719: 		DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n",
  720: 			dev->id_unit,
  721: 			*(ushort volatile *)(mem+0xC12),
  722: 			*(ushort volatile *)(mem+0xC14),
  723: 			*(ushort volatile *)(mem+MISCGLOBAL));
  724: 
  725: 		sc->status=DISABLED;
  726: 		hidewin(sc);
  727: 		return 0;
  728: 	}
  729: 
  730: load_fep:
  731: 	DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit);
  732: 
  733: 	addr=setwin(sc,FEPCODE);
  734: 
  735: 	ptr= mem+addr;
  736: 
  737: 	for(i=0; i<pcxx_ncook; i++)
  738: 		*ptr++ = pcxx_cook[i];
  739: 
  740: 	addr=setwin(sc,MBOX);
  741: 	*(ushort volatile *)(mem+addr+ 0)=2;
  742: 	*(ushort volatile *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG;
  743: 	*(ushort volatile *)(mem+addr+ 4)=0;
  744: 	*(ushort volatile *)(mem+addr+ 6)=FEPCODESEG;
  745: 	*(ushort volatile *)(mem+addr+ 8)=0;
  746: 	*(ushort volatile *)(mem+addr+10)=pcxx_ncook;
  747: 
  748: 	outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */
  749: 	outb(sc->port,FEPMEM);
  750: 
  751: 	for(i=0; *(ushort volatile *)(mem+addr)!=0; i++) {
  752: 		if(i>200000) {
  753: 			printf("dgb%d: FEP code download failed\n",unit);
  754: 			DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit,
  755: 				*(ushort volatile *)(mem+addr));
  756: 			sc->status=DISABLED;
  757: 			hidewin(sc);
  758: 			return 0;
  759: 		}
  760: 	}
  761: 
  762: 	DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit);
  763: 
  764: 	*(ushort volatile *)(mem+setwin(sc,FEPSTAT))=0;
  765: 	addr=setwin(sc,MBOX);
  766: 	*(ushort volatile *)(mem+addr+0)=1;
  767: 	*(ushort volatile *)(mem+addr+2)=FEPCODESEG;
  768: 	*(ushort volatile *)(mem+addr+4)=0x4;
  769: 
  770: 	outb(sc->port,FEPINT); /* send interrupt to BIOS */
  771: 	outb(sc->port,FEPCLR);
  772: 
  773: 	addr=setwin(sc,FEPSTAT);
  774: 	for(i=0; *(ushort volatile *)(mem+addr)!= *(ushort *)"OS"; i++) {
  775: 		if(i>200000) {
  776: 			printf("dgb%d: FEP/OS start failed\n",dev->id_unit);
  777: 			sc->status=DISABLED;
  778: 			hidewin(sc);
  779: 			return 0;
  780: 		}
  781: 	}
  782: 
  783: 	DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit);
  784: 
  785: 	sc->numports= *(ushort volatile *)(mem+setwin(sc,NPORT));
  786: 
  787: 	printf("dgb%d: %d ports\n",unit,sc->numports);
  788: 
  789: 	if(sc->numports > MAX_DGB_PORTS) {
  790: 		printf("dgb%d: too many ports\n",unit);
  791: 		sc->status=DISABLED;
  792: 		hidewin(sc);
  793: 		return 0;
  794: 	}
  795: 
  796: 	if(nports+sc->numports>NDGBPORTS) {
  797: 		printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports);
  798: 		sc->numports=NDGBPORTS-nports;
  799: 	}
  800: 
  801: 	/* allocate port and tty structures */
  802: 	sc->ports=&dgb_ports[nports];
  803: 	sc->ttys=&dgb_tty[nports];
  804: 	nports+=sc->numports;
  805: 
  806: 	addr=setwin(sc,PORTBASE);
  807: 	pstat=(const ushort volatile *)(mem+addr);
  808: 
  809: 	for(i=0; i<sc->numports && pstat[i]; i++)
  810: 		if(pstat[i])
  811: 			sc->ports[i].status=ENABLED;
  812: 		else {
  813: 			sc->ports[i].status=DISABLED;
  814: 			printf("dgb%d: port%d is broken\n", unit, i);
  815: 		}
  816: 
  817: 	/* We should now init per-port structures */
  818: 	bc=(volatile struct board_chan *)(mem + CHANSTRUCT);
  819: 	sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL);
  820: 
  821: 	if(sc->numports<3)
  822: 		shrinkmem=1;
  823: 	else
  824: 		shrinkmem=0;
  825: 
  826: 	for(i=0; i<sc->numports; i++, bc++) {
  827: 		port= &sc->ports[i];
  828: 
  829: 		port->tty=&sc->ttys[i];
  830: 		port->unit=unit;
  831: 
  832: 		port->brdchan=bc;
  833: 
  834: 		if(sc->altpin) {
  835: 			port->dsr=CD;
  836: 			port->dcd=DSR;
  837: 		} else {
  838: 			port->dcd=CD;
  839: 			port->dsr=DSR;
  840: 		}
  841: 
  842: 		port->pnum=i;
  843: 
  844: 		if(shrinkmem) {
  845: 			DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit);
  846: 			fepcmd(port, SETBUFFER, 32, 0, 0, 0);
  847: 			shrinkmem=0;
  848: 			}
  849: 
  850: 		if(sc->type!=PCXEVE) {
  851: 			port->txptr=mem+((bc->tseg-sc->mem_seg)<<4);
  852: 			port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4);
  853: 			port->txwin=port->rxwin=0;
  854: 		} else {
  855: 			port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF );
  856: 			port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF );
  857: 			port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9);
  858: 			port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9);
  859: 		}
  860: 
  861: 		port->txbufhead=0;
  862: 		port->rxbufhead=0;
  863: 		port->txbufsize=bc->tmax+1;
  864: 		port->rxbufsize=bc->rmax+1;
  865: 
  866: 		lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2);
  867: 		setwin(sc,0);
  868: 		fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
  869: 		fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0);
  870: 		fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0);
  871: 
  872: 		bc->edelay=100;
  873: 		bc->idata=1;
  874: 
  875: 		port->startc=bc->startc;
  876: 		port->startca=bc->startca;
  877: 		port->stopc=bc->stopc;
  878: 		port->stopca=bc->stopca;
  879: 			
  880: 		/*port->close_delay=50;*/
  881: 		port->close_delay=3 * hz;
  882: 		port->do_timestamp=0;
  883: 		port->do_dcd_timestamp=0;
  884: 
  885: 		/*
  886: 		 * We don't use all the flags from <sys/ttydefaults.h> since they
  887: 		 * are only relevant for logins.  It's important to have echo off
  888: 		 * initially so that the line doesn't start blathering before the
  889: 		 * echo flag can be turned off.
  890: 		 */
  891: 		port->it_in.c_iflag = TTYDEF_IFLAG;
  892: 		port->it_in.c_oflag = TTYDEF_OFLAG;
  893: 		port->it_in.c_cflag = TTYDEF_CFLAG;
  894: 		port->it_in.c_lflag = TTYDEF_LFLAG;
  895: 		termioschars(&port->it_in);
  896: 		port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate;
  897: 		port->it_out = port->it_in;
  898: 		/* MAX_DGB_PORTS is 32 => [0-9a-v] */
  899: 		suffix = i < 10 ? '0' + i : 'a' + i - 10;
  900: 		make_dev(&dgb_cdevsw, (unit*32)+i,
  901: 		    UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
  902: 
  903: 		make_dev(&dgb_cdevsw, (unit*32)+i+32,
  904: 		    UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
  905: 
  906: 		make_dev(&dgb_cdevsw, (unit*32)+i+64,
  907: 		    UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
  908: 
  909: 		make_dev(&dgb_cdevsw, (unit*32)+i+128,
  910: 		    UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
  911: 
  912: 		make_dev(&dgb_cdevsw, (unit*32)+i+160,
  913: 		    UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
  914: 
  915: 		make_dev(&dgb_cdevsw, (unit*32)+i+192,
  916: 		    UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
  917: 	}
  918: 
  919: 	hidewin(sc);
  920: 
  921: 	/* register the polling function */
  922: 	timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC);
  923: 
  924: 	return 1;
  925: }
  926: 
  927: /* ARGSUSED */
  928: static	int
  929: dgbopen(dev_t dev, int flag, int mode, struct thread *td)
  930: {
  931: 	struct dgb_softc *sc;
  932: 	struct tty *tp;
  933: 	int unit;
  934: 	int mynor;
  935: 	int pnum;
  936: 	struct dgb_p *port;
  937: 	int s,cs;
  938: 	int error;
  939: 	volatile struct board_chan *bc;
  940: 
  941: 	error=0;
  942: 
  943: 	mynor=minor(dev);
  944: 	unit=MINOR_TO_UNIT(mynor);
  945: 	pnum=MINOR_TO_PORT(mynor);
  946: 
  947: 	if(unit >= NDGB) {
  948: 		DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
  949: 		return ENXIO;
  950: 	}
  951: 
  952: 	sc=&dgb_softc[unit];
  953: 
  954: 	if(sc->status!=ENABLED) {
  955: 		DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
  956: 		return ENXIO;
  957: 	}
  958: 
  959: 	if(pnum>=sc->numports) {
  960: 		DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
  961: 		return ENXIO;
  962: 	}
  963: 
  964: 	if(mynor & CONTROL_MASK)
  965: 		return 0;
  966: 
  967: 	tp=&sc->ttys[pnum];
  968: 	dev->si_tty = tp;
  969: 	port=&sc->ports[pnum];
  970: 	bc=port->brdchan;
  971: 
  972: open_top:
  973: 	
  974: 	s=spltty();
  975: 
  976: 	while(port->closing) {
  977: 		error=tsleep(&port->closing, PCATCH, "dgocl", 0);
  978: 
  979: 		if(error) {
  980: 			DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
  981: 			goto out;
  982: 		}
  983: 	}
  984: 
  985: 	if (tp->t_state & TS_ISOPEN) {
  986: 		/*
  987: 		 * The device is open, so everything has been initialized.
  988: 		 * Handle conflicts.
  989: 		 */
  990: 		if (mynor & CALLOUT_MASK) {
  991: 			if (!port->active_out) {
  992: 				error = EBUSY;
  993: 				DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
  994: 				goto out;
  995: 			}
  996: 		} else {
  997: 			if (port->active_out) {
  998: 				if (flag & O_NONBLOCK) {
  999: 					error = EBUSY;
 1000: 					DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
 1001: 					goto out;
 1002: 				}
 1003: 				error =	tsleep(&port->active_out,
 1004: 					       PCATCH, "dgbi", 0);
 1005: 				if (error != 0) {
 1006: 					DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
 1007: 						unit,pnum,error);
 1008: 					goto out;
 1009: 				}
 1010: 				splx(s);
 1011: 				goto open_top;
 1012: 			}
 1013: 		}
 1014: 		if (tp->t_state & TS_XCLUDE && suser(td)) {
 1015: 			error = EBUSY;
 1016: 			goto out;
 1017: 		}
 1018: 	} else {
 1019: 		/*
 1020: 		 * The device isn't open, so there are no conflicts.
 1021: 		 * Initialize it.  Initialization is done twice in many
 1022: 		 * cases: to preempt sleeping callin opens if we are
 1023: 		 * callout, and to complete a callin open after DCD rises.
 1024: 		 */
 1025: 		tp->t_oproc=dgbstart;
 1026: 		tp->t_param=dgbparam;
 1027: 		tp->t_stop=dgbstop;
 1028: 		tp->t_dev=dev;
 1029: 		tp->t_termios= (mynor & CALLOUT_MASK) ?
 1030: 							port->it_out :
 1031: 							port->it_in;
 1032: 
 1033: 		cs=splclock();
 1034: 		setwin(sc,0);
 1035: 		port->imodem=bc->mstat;
 1036: 		bc->rout=bc->rin; /* clear input queue */
 1037: 		bc->idata=1;
 1038: #ifdef PRINT_BUFSIZE
 1039: 		printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
 1040: #endif
 1041: 
 1042: 		hidewin(sc);
 1043: 		splx(cs);
 1044: 
 1045: 		port->wopeners++;
 1046: 		error=dgbparam(tp, &tp->t_termios);
 1047: 		port->wopeners--;
 1048: 
 1049: 		if(error!=0) {
 1050: 			DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
 1051: 			goto out;
 1052: 		}
 1053: 
 1054: 		/* handle fake DCD for callout devices */
 1055: 		/* and initial DCD */
 1056: 
 1057: 		if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
 1058: 			linesw[tp->t_line].l_modem(tp,1);
 1059: 
 1060: 	}
 1061: 
 1062: 	/*
 1063: 	 * Wait for DCD if necessary.
 1064: 	 */
 1065: 	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
 1066: 	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
 1067: 		++port->wopeners;
 1068: 		error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
 1069: 		--port->wopeners;
 1070: 		if (error != 0) {
 1071: 			DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
 1072: 			goto out;
 1073: 		}
 1074: 		splx(s);
 1075: 		goto open_top;
 1076: 	}
 1077: 	error =	linesw[tp->t_line].l_open(dev, tp);
 1078: 	disc_optim(tp,&tp->t_termios);
 1079: 	DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
 1080: 
 1081: 	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
 1082: 		port->active_out = TRUE;
 1083: 
 1084: 	port->used=1;
 1085: 
 1086: 	/* If any port is open (i.e. the open() call is completed for it) 
 1087: 	 * the device is busy
 1088: 	 */
 1089: 
 1090: out:
 1091: 	disc_optim(tp,&tp->t_termios);
 1092: 	splx(s);
 1093: 
 1094: 	if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
 1095: 		dgbhardclose(port);
 1096: 
 1097: 	DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
 1098: 
 1099: 	return error;
 1100: }
 1101: 
 1102: /*ARGSUSED*/
 1103: static	int
 1104: dgbclose(dev_t dev, int flag, int mode, struct thread *td)
 1105: {
 1106: 	struct tty *tp;
 1107: 	int unit, pnum;
 1108: 	struct dgb_softc *sc;
 1109: 	struct dgb_p *port;
 1110: 	int mynor;
 1111: 	int s;
 1112: 	int i;
 1113: 
 1114: 	mynor=minor(dev);
 1115: 	if(mynor & CONTROL_MASK)
 1116: 		return 0;
 1117: 	unit=MINOR_TO_UNIT(mynor);
 1118: 	pnum=MINOR_TO_PORT(mynor);
 1119: 
 1120: 	sc=&dgb_softc[unit];
 1121: 	tp=&sc->ttys[pnum];
 1122: 	port=sc->ports+pnum;
 1123: 
 1124: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
 1125: 
 1126: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
 1127:         dgb_drain_or_flush(port);
 1128: 
 1129: 	s=spltty();
 1130: 
 1131: 	port->closing=1;
 1132: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
 1133: 	linesw[tp->t_line].l_close(tp,flag);
 1134: 	disc_optim(tp,&tp->t_termios);
 1135: 
 1136: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
 1137: 	dgbhardclose(port);
 1138: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
 1139: 	ttyclose(tp);
 1140: 	port->closing=0;
 1141: 	wakeup(&port->closing);
 1142: 	port->used=0;
 1143: 
 1144: 	/* mark the card idle when all ports are closed */
 1145: 
 1146: 	for(i=0; i<sc->numports; i++)
 1147: 		if(sc->ports[i].used)
 1148: 			break;
 1149: 
 1150: 	splx(s);
 1151: 
 1152: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
 1153: 
 1154: 	wakeup(TSA_CARR_ON(tp));
 1155: 	wakeup(&port->active_out);
 1156: 	port->active_out=0;
 1157: 
 1158: 	DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
 1159: 
 1160: 	return 0;
 1161: }
 1162: 
 1163: static void
 1164: dgbhardclose(port)
 1165: 	struct dgb_p *port;
 1166: {
 1167: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1168: 	volatile struct board_chan *bc=port->brdchan;
 1169: 	int cs;
 1170: 
 1171: 	cs=splclock();
 1172: 	port->do_timestamp = 0;
 1173: 	setwin(sc,0);
 1174: 
 1175: 	bc->idata=0; bc->iempty=0; bc->ilow=0;
 1176: 	if(port->tty->t_cflag & HUPCL) {
 1177: 		port->omodem &= ~(RTS|DTR);
 1178: 		fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
 1179: 	}
 1180: 
 1181: 	hidewin(sc);
 1182: 	splx(cs);
 1183: 
 1184: 	timeout(dgb_pause, &port->brdchan, hz/2);
 1185: 	tsleep(&port->brdchan, PCATCH, "dgclo", 0);
 1186: }
 1187: 
 1188: static void 
 1189: dgb_pause(chan)
 1190: 	void *chan;
 1191: {
 1192: 	wakeup((caddr_t)chan);
 1193: }
 1194: 
 1195: static void
 1196: dgbpoll(unit_c)
 1197: 	void *unit_c;
 1198: {
 1199: 	int unit=(int)unit_c;
 1200: 	int pnum;
 1201: 	struct dgb_p *port;
 1202: 	struct dgb_softc *sc=&dgb_softc[unit];
 1203: 	int head, tail;
 1204: 	u_char *eventbuf;
 1205: 	int event, mstat, lstat;
 1206: 	volatile struct board_chan *bc;
 1207: 	struct tty *tp;
 1208: 	int rhead, rtail;
 1209: 	int whead, wtail;
 1210: 	int size;
 1211: 	u_char *ptr;
 1212: 	int ocount;
 1213: 	int ibuf_full,obuf_full;
 1214: 
 1215: 	BoardMemWinState ws=bmws_get();
 1216: 
 1217: 	if(sc->status==DISABLED) {
 1218: 		printf("dgb%d: polling of disabled board stopped\n",unit);
 1219: 		return;
 1220: 	}
 1221: 	
 1222: 	setwin(sc,0);
 1223: 
 1224: 	head=sc->mailbox->ein;
 1225: 	tail=sc->mailbox->eout;
 1226: 
 1227: 	while(head!=tail) {
 1228: 		if(head >= FEP_IMAX-FEP_ISTART 
 1229: 		|| tail >= FEP_IMAX-FEP_ISTART 
 1230: 		|| (head|tail) & 03 ) {
 1231: 			printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
 1232: 			break;
 1233: 		}
 1234: 
 1235: 		eventbuf=sc->vmem+tail+FEP_ISTART;
 1236: 		pnum=eventbuf[0];
 1237: 		event=eventbuf[1];
 1238: 		mstat=eventbuf[2];
 1239: 		lstat=eventbuf[3];
 1240: 
 1241: 		port=&sc->ports[pnum];
 1242: 		bc=port->brdchan;
 1243: 		tp=&sc->ttys[pnum];
 1244: 
 1245: 		if(pnum>=sc->numports || port->status==DISABLED) {
 1246: 			printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
 1247: 		} else if(port->used || port->wopeners>0 ) {
 1248: 
 1249: 			int wrapmask=port->rxbufsize-1;
 1250: 
 1251: 			if( !(event & ALL_IND) ) 
 1252: 				printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
 1253: 					unit, pnum, event, mstat, lstat);
 1254: 
 1255: 			if(event & DATA_IND) {
 1256: 				DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
 1257: 
 1258: 				rhead=bc->rin & wrapmask; 
 1259: 				rtail=bc->rout & wrapmask;
 1260: 
 1261: 				if( !(tp->t_cflag & CREAD) || !port->used ) {
 1262: 					bc->rout=rhead;
 1263: 					goto end_of_data;
 1264: 				}
 1265: 
 1266: 				if(bc->orun) {
 1267: 					printf("dgb%d: port%d: overrun\n", unit, pnum);
 1268: 					bc->orun=0;
 1269: 				}
 1270: 
 1271: 				if(!(tp->t_state & TS_ISOPEN))
 1272: 					goto end_of_data;
 1273: 
 1274: 				for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
 1275: 					DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
 1276: 						unit,pnum,rhead,rtail);
 1277: 
 1278: 					if(rhead>rtail)
 1279: 						size=rhead-rtail;
 1280: 					else
 1281: 						size=port->rxbufsize-rtail;
 1282: 
 1283: 					ptr=port->rxptr+rtail;
 1284: 
 1285: /* Helg: */
 1286: 					if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
 1287: 						size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
 1288: 						DPRINT1(DB_RXDATA,"*");
 1289: 						ibuf_full=TRUE;
 1290: 					}
 1291: 
 1292: 					if(size) {
 1293: 						if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1294: 							DPRINT1(DB_RXDATA,"!");
 1295: 							towin(sc,port->rxwin);
 1296: 							tk_nin += size;
 1297: 							tk_rawcc += size;
 1298: 							tp->t_rawcc += size;
 1299: 							b_to_q(ptr,size,&tp->t_rawq);
 1300: 							setwin(sc,0);
 1301: 						} else {
 1302: 							int i=size;
 1303: 							unsigned char chr;
 1304: 							do {
 1305: 								towin(sc,port->rxwin);
 1306: 								chr= *ptr++;
 1307: 								hidewin(sc);
 1308: 							       (*linesw[tp->t_line].l_rint)(chr, tp);
 1309: 							} while (--i > 0 );
 1310: 							setwin(sc,0);
 1311: 						}
 1312: 	 				}
 1313: 					rtail= (rtail + size) & wrapmask;
 1314: 					bc->rout=rtail;
 1315: 					rhead=bc->rin & wrapmask;
 1316: 					hidewin(sc);
 1317: 					ttwakeup(tp);
 1318: 					setwin(sc,0);
 1319: 				}
 1320: 			end_of_data: ;
 1321: 			}
 1322: 
 1323: 			if(event & MODEMCHG_IND) {
 1324: 				DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
 1325: 				port->imodem=mstat;
 1326: 				if(mstat & port->dcd) {
 1327: 					hidewin(sc);
 1328: 					linesw[tp->t_line].l_modem(tp,1);
 1329: 					setwin(sc,0);
 1330: 					wakeup(TSA_CARR_ON(tp));
 1331: 				} else {
 1332: 					hidewin(sc);
 1333: 					linesw[tp->t_line].l_modem(tp,0);
 1334: 					setwin(sc,0);
 1335: 					if( port->draining) {
 1336: 						port->draining=0;
 1337: 						wakeup(&port->draining);
 1338: 					}
 1339: 				}
 1340: 			}
 1341: 
 1342: 			if(event & BREAK_IND) {
 1343: 				if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK))	{
 1344: 				        DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
 1345: 				        hidewin(sc);
 1346: 				        linesw[tp->t_line].l_rint(TTY_BI, tp);
 1347: 				        setwin(sc,0);
 1348: 			        }
 1349: 			}
 1350: 
 1351: /* Helg: with output flow control */
 1352: 
 1353: 			if(event & (LOWTX_IND | EMPTYTX_IND) ) {
 1354: 				DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
 1355: 
 1356: 				if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
 1357: 				&& port->draining) {
 1358: 					port->draining=0;
 1359: 					wakeup(&port->draining);
 1360: 					bc->ilow=0; bc->iempty=0;
 1361: 				} else {
 1362: 
 1363: 					int wrapmask=port->txbufsize-1;
 1364: 
 1365: 					for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
 1366: 						int s;
 1367: 						/* add "last-minute" data to write buffer */
 1368: 						if(!(tp->t_state & TS_BUSY)) {
 1369: 							hidewin(sc);
 1370: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1371: 					                ttwwakeup(tp);
 1372: #else
 1373: 					                if(tp->t_outq.c_cc <= tp->t_lowat) {
 1374: 						                if(tp->t_state & TS_ASLEEP) {
 1375: 							                tp->t_state &= ~TS_ASLEEP;
 1376: 							                wakeup(TSA_OLOWAT(tp));
 1377: 						                }
 1378: 						                /* selwakeup(&tp->t_wsel); */
 1379: 					                }
 1380: #endif
 1381: 					                setwin(sc,0);
 1382: 				                }
 1383: 						s=spltty();
 1384: 
 1385: 					whead=bc->tin & wrapmask;
 1386: 					wtail=bc->tout & wrapmask;
 1387: 
 1388: 					if(whead<wtail)
 1389: 						size=wtail-whead-1;
 1390: 					else {
 1391: 						size=port->txbufsize-whead;
 1392: 						if(wtail==0)
 1393: 							size--;
 1394: 					}
 1395: 
 1396: 					if(size==0) {
 1397: 						DPRINT5(DB_WR,"dgb: head=%d tail=%d size=%d full=%d\n",
 1398: 							whead,wtail,size,obuf_full);
 1399: 						bc->iempty=1; bc->ilow=1;
 1400: 						obuf_full=TRUE;
 1401: 						splx(s);
 1402: 						break;
 1403: 					}
 1404: 
 1405: 					towin(sc,port->txwin);
 1406: 
 1407: 					ocount=q_to_b(&tp->t_outq, port->txptr+whead, size);
 1408: 					whead+=ocount;
 1409: 
 1410: 					setwin(sc,0);
 1411: 					bc->tin=whead;
 1412: 					bc->tin=whead & wrapmask;
 1413: 					splx(s);
 1414: 				}
 1415: 
 1416: 				if(obuf_full) {
 1417: 					DPRINT1(DB_WR," +BUSY\n");
 1418: 					tp->t_state|=TS_BUSY;
 1419: 				} else {
 1420: 					DPRINT1(DB_WR," -BUSY\n");
 1421: 					hidewin(sc);
 1422: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1423: 					/* should clear TS_BUSY before ttwwakeup */
 1424: 					if(tp->t_state & TS_BUSY)	{
 1425: 						tp->t_state &= ~TS_BUSY;
 1426: 						linesw[tp->t_line].l_start(tp);
 1427: 				                ttwwakeup(tp);
 1428: 					}
 1429: #else
 1430: 				if(tp->t_state & TS_ASLEEP) {
 1431: 					tp->t_state &= ~TS_ASLEEP;
 1432: 					wakeup(TSA_OLOWAT(tp));
 1433: 				}
 1434: 				tp->t_state &= ~TS_BUSY;
 1435: #endif
 1436: 				        setwin(sc,0);
 1437: 				        }
 1438: 			        }
 1439: 			}
 1440: 			bc->idata=1;   /* require event on incoming data */ 
 1441: 
 1442: 		} else {
 1443: 			bc=port->brdchan;
 1444: 			DPRINT4(DB_EXCEPT,"dgb%d: port%d: got event 0x%x on closed port\n",
 1445: 				unit,pnum,event);
 1446: 			bc->rout=bc->rin;
 1447: 			bc->idata=bc->iempty=bc->ilow=0;
 1448: 		}
 1449: 
 1450: 		tail= (tail+4) & (FEP_IMAX-FEP_ISTART-4);
 1451: 	}
 1452: 
 1453: 	sc->mailbox->eout=tail;
 1454: 	bmws_set(ws);
 1455: 
 1456: 	timeout(dgbpoll, unit_c, hz/POLLSPERSEC);
 1457: }
 1458: 
 1459: static	int
 1460: dgbioctl(dev_t dev, u_long cmd, caddr_t	data, int flag, struct thread *td)
 1461: {
 1462: 	struct dgb_softc *sc;
 1463: 	int unit, pnum;
 1464: 	struct dgb_p *port;
 1465: 	int mynor;
 1466: 	struct tty *tp;
 1467: 	volatile struct board_chan *bc;
 1468: 	int error;
 1469: 	int s,cs;
 1470: 	int tiocm_xxx;
 1471: 
 1472: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1473: 	u_long		oldcmd;
 1474: 	struct termios	term;
 1475: #endif
 1476: 
 1477: 	BoardMemWinState ws=bmws_get();
 1478: 
 1479: 	mynor=minor(dev);
 1480: 	unit=MINOR_TO_UNIT(mynor);
 1481: 	pnum=MINOR_TO_PORT(mynor);
 1482: 
 1483: 	sc=&dgb_softc[unit];
 1484: 	port=&sc->ports[pnum];
 1485: 	tp=&sc->ttys[pnum];
 1486: 	bc=port->brdchan;
 1487: 
 1488: 	if (mynor & CONTROL_MASK) {
 1489: 		struct termios *ct;
 1490: 
 1491: 		switch (mynor & CONTROL_MASK) {
 1492: 		case CONTROL_INIT_STATE:
 1493: 			ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
 1494: 			break;
 1495: 		case CONTROL_LOCK_STATE:
 1496: 			ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
 1497: 			break;
 1498: 		default:
 1499: 			return (ENODEV);	/* /dev/nodev */
 1500: 		}
 1501: 		switch (cmd) {
 1502: 		case TIOCSETA:
 1503: 			error = suser(td);
 1504: 			if (error != 0)
 1505: 				return (error);
 1506: 			*ct = *(struct termios *)data;
 1507: 			return (0);
 1508: 		case TIOCGETA:
 1509: 			*(struct termios *)data = *ct;
 1510: 			return (0);
 1511: 		case TIOCGETD:
 1512: 			*(int *)data = TTYDISC;
 1513: 			return (0);
 1514: 		case TIOCGWINSZ:
 1515: 			bzero(data, sizeof(struct winsize));
 1516: 			return (0);
 1517: 		default:
 1518: 			return (ENOTTY);
 1519: 		}
 1520: 	}
 1521: 
 1522: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1523: 	term = tp->t_termios;
 1524: 	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1525: 	  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);
 1526: 	}
 1527: 	oldcmd = cmd;
 1528: 	error = ttsetcompat(tp, &cmd, data, &term);
 1529: 	if (error != 0)
 1530: 		return (error);
 1531: 	if (cmd != oldcmd)
 1532: 		data = (caddr_t)&term;
 1533: #endif
 1534: 
 1535: 	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1536: 		int	cc;
 1537: 		struct termios *dt = (struct termios *)data;
 1538: 		struct termios *lt = mynor & CALLOUT_MASK
 1539: 				     ? &port->lt_out : &port->lt_in;
 1540: 
 1541: 		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);
 1542: 		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
 1543: 			      | (dt->c_iflag & ~lt->c_iflag);
 1544: 		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
 1545: 			      | (dt->c_oflag & ~lt->c_oflag);
 1546: 		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
 1547: 			      | (dt->c_cflag & ~lt->c_cflag);
 1548: 		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
 1549: 			      | (dt->c_lflag & ~lt->c_lflag);
 1550: 		for (cc = 0; cc < NCCS; ++cc)
 1551: 			if (lt->c_cc[cc] != 0)
 1552: 				dt->c_cc[cc] = tp->t_cc[cc];
 1553: 		if (lt->c_ispeed != 0)
 1554: 			dt->c_ispeed = tp->t_ispeed;
 1555: 		if (lt->c_ospeed != 0)
 1556: 			dt->c_ospeed = tp->t_ospeed;
 1557: 	}
 1558: 
 1559: 	if(cmd==TIOCSTOP) {
 1560: 		cs=splclock();
 1561: 		setwin(sc,0);
 1562: 		fepcmd(port, PAUSETX, 0, 0, 0, 0);
 1563: 		bmws_set(ws);
 1564: 		splx(cs);
 1565: 		return 0;
 1566: 	} else if(cmd==TIOCSTART) {
 1567: 		cs=splclock();
 1568: 		setwin(sc,0);
 1569: 		fepcmd(port, RESUMETX, 0, 0, 0, 0);
 1570: 		bmws_set(ws);
 1571: 		splx(cs);
 1572: 		return 0;
 1573: 	}
 1574: 
 1575: 	if(cmd==TIOCSETAW || cmd==TIOCSETAF)
 1576: 		port->mustdrain=1;
 1577: 
 1578: 	error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
 1579: 	if (error != ENOIOCTL)
 1580: 		return error;
 1581: 	s = spltty();
 1582: 	error = ttioctl(tp, cmd, data, flag);
 1583: 	disc_optim(tp,&tp->t_termios);
 1584: 	port->mustdrain=0;
 1585: 	if (error != ENOIOCTL) {
 1586: 		splx(s);
 1587: 		if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1588: 			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);
 1589: 		}
 1590: 		return error;
 1591: 	}
 1592: 
 1593: 	switch (cmd) {
 1594: 	case TIOCSBRK:
 1595: /* Helg: commented */
 1596: /*		error=dgbdrain(port);*/
 1597: 
 1598: 		if(error!=0) {
 1599: 			splx(s);
 1600: 			return error;
 1601: 		}
 1602: 
 1603: 		cs=splclock();
 1604: 		setwin(sc,0);
 1605: 	
 1606: 		/* now it sends 250 millisecond break because I don't know */
 1607: 		/* how to send an infinite break */
 1608: 
 1609: 		fepcmd(port, SENDBREAK, 250, 0, 10, 0);
 1610: 		hidewin(sc);
 1611: 		splx(cs);
 1612: 		break;
 1613: 	case TIOCCBRK:
 1614: 		/* now it's empty */
 1615: 		break;
 1616: 	case TIOCSDTR:
 1617: 		DPRINT3(DB_MODEM,"dgb%d: port%d: set DTR\n",unit,pnum);
 1618: 		port->omodem |= DTR;
 1619: 		cs=splclock();
 1620: 		setwin(sc,0);
 1621: 		fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
 1622: 
 1623: 		if( !(bc->mstat & DTR) ) {
 1624: 			DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is off\n",unit,pnum);
 1625: 		}
 1626: 
 1627: 		hidewin(sc);
 1628: 		splx(cs);
 1629: 		break;
 1630: 	case TIOCCDTR:
 1631: 		DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
 1632: 		port->omodem &= ~DTR;
 1633: 		cs=splclock();
 1634: 		setwin(sc,0);
 1635: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1636: 
 1637: 		if( bc->mstat & DTR ) {
 1638: 			DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is on\n",unit,pnum);
 1639: 		}
 1640: 
 1641: 		hidewin(sc);
 1642: 		splx(cs);
 1643: 		break;
 1644: 	case TIOCMSET:
 1645: 		if(*(int *)data & TIOCM_DTR)
 1646: 			port->omodem |=DTR;
 1647: 		else
 1648: 			port->omodem &=~DTR;
 1649: 
 1650: 		if(*(int *)data & TIOCM_RTS)
 1651: 			port->omodem |=RTS;
 1652: 		else
 1653: 			port->omodem &=~RTS;
 1654: 
 1655: 		cs=splclock();
 1656: 		setwin(sc,0);
 1657: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1658: 		hidewin(sc);
 1659: 		splx(cs);
 1660: 		break;
 1661: 	case TIOCMBIS:
 1662: 		if(*(int *)data & TIOCM_DTR)
 1663: 			port->omodem |=DTR;
 1664: 
 1665: 		if(*(int *)data & TIOCM_RTS)
 1666: 			port->omodem |=RTS;
 1667: 
 1668: 		cs=splclock();
 1669: 		setwin(sc,0);
 1670: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1671: 		hidewin(sc);
 1672: 		splx(cs);
 1673: 		break;
 1674: 	case TIOCMBIC:
 1675: 		if(*(int *)data & TIOCM_DTR)
 1676: 			port->omodem &=~DTR;
 1677: 
 1678: 		if(*(int *)data & TIOCM_RTS)
 1679: 			port->omodem &=~RTS;
 1680: 
 1681: 		cs=splclock();
 1682: 		setwin(sc,0);
 1683: 		fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
 1684: 		hidewin(sc);
 1685: 		splx(cs);
 1686: 		break;
 1687: 	case TIOCMGET:
 1688: 		setwin(sc,0);
 1689: 		port->imodem=bc->mstat;
 1690: 		hidewin(sc);
 1691: 
 1692: 		tiocm_xxx = TIOCM_LE;	/* XXX - always enabled while open */
 1693: 
 1694: 		DPRINT3(DB_MODEM,"dgb%d: port%d: modem stat -- ",unit,pnum);
 1695: 
 1696: 		if (port->imodem & DTR) {
 1697: 			DPRINT1(DB_MODEM,"DTR ");
 1698: 			tiocm_xxx |= TIOCM_DTR;
 1699: 		}
 1700: 		if (port->imodem & RTS) {
 1701: 			DPRINT1(DB_MODEM,"RTS ");
 1702: 			tiocm_xxx |= TIOCM_RTS;
 1703: 		}
 1704: 		if (port->imodem & CTS) {
 1705: 			DPRINT1(DB_MODEM,"CTS ");
 1706: 			tiocm_xxx |= TIOCM_CTS;
 1707: 		}
 1708: 		if (port->imodem & port->dcd) {
 1709: 			DPRINT1(DB_MODEM,"DCD ");
 1710: 			tiocm_xxx |= TIOCM_CD;
 1711: 		}
 1712: 		if (port->imodem & port->dsr) {
 1713: 			DPRINT1(DB_MODEM,"DSR ");
 1714: 			tiocm_xxx |= TIOCM_DSR;
 1715: 		}
 1716: 		if (port->imodem & RI) {
 1717: 			DPRINT1(DB_MODEM,"RI ");
 1718: 			tiocm_xxx |= TIOCM_RI;
 1719: 		}
 1720: 		*(int *)data = tiocm_xxx;
 1721: 		DPRINT1(DB_MODEM,"--\n");
 1722: 		break;
 1723: 	case TIOCMSDTRWAIT:
 1724: 		/* must be root since the wait applies to following logins */
 1725: 		error = suser(td);
 1726: 		if (error != 0) {
 1727: 			splx(s);
 1728: 			return (error);
 1729: 		}
 1730: 		port->close_delay = *(int *)data * hz / 100;
 1731: 		break;
 1732: 	case TIOCMGDTRWAIT:
 1733: 		*(int *)data = port->close_delay * 100 / hz;
 1734: 		break;
 1735: 	case TIOCTIMESTAMP:
 1736: 		port->do_timestamp = TRUE;
 1737: 		*(struct timeval *)data = port->timestamp;
 1738: 		break;
 1739: 	case TIOCDCDTIMESTAMP:
 1740: 		port->do_dcd_timestamp = TRUE;
 1741: 		*(struct timeval *)data = port->dcd_timestamp;
 1742: 		break;
 1743: 	default:
 1744: 		bmws_set(ws);
 1745: 		splx(s);
 1746: 		return ENOTTY;
 1747: 	}
 1748: 	bmws_set(ws);
 1749: 	splx(s);
 1750: 
 1751: 	return 0;
 1752: }
 1753: 
 1754: static void 
 1755: wakeflush(p)
 1756: 	void *p;
 1757: {
 1758: 	struct dgb_p *port=p;
 1759: 
 1760: 	wakeup(&port->draining);
 1761: }
 1762: 
 1763: /* wait for the output to drain */
 1764: 
 1765: static int
 1766: dgbdrain(port)
 1767: 	struct dgb_p	*port;
 1768: {
 1769: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1770: 	volatile struct board_chan *bc=port->brdchan;
 1771: 	int error;
 1772: 	int head, tail;
 1773: 
 1774: 	BoardMemWinState ws=bmws_get();
 1775: 
 1776: 	setwin(sc,0);
 1777: 
 1778: 	bc->iempty=1;
 1779: 	tail=bc->tout;
 1780: 	head=bc->tin;
 1781: 
 1782: 	while(tail!=head) {
 1783: 		DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
 1784: 			port->unit, port->pnum, head, tail);
 1785: 
 1786: 		hidewin(sc);
 1787: 		port->draining=1;
 1788: 		timeout(wakeflush,port, hz);
 1789: 		error=tsleep(&port->draining, PCATCH, "dgdrn", 0);
 1790: 		port->draining=0;
 1791: 		setwin(sc,0);
 1792: 
 1793: 		if (error != 0) {
 1794: 			DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgdrn) error=%d\n",
 1795: 				port->unit,port->pnum,error);
 1796: 
 1797: 			bc->iempty=0;
 1798: 			bmws_set(ws);
 1799: 			return error;
 1800: 		}
 1801: 
 1802: 		tail=bc->tout;
 1803: 		head=bc->tin;
 1804: 	}
 1805: 	DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
 1806: 		port->unit, port->pnum, head, tail);
 1807: 	bmws_set(ws);
 1808: 	return 0;
 1809: }
 1810: 
 1811: /* wait for the output to drain */
 1812: /* or simply clear the buffer it it's stopped */
 1813: 
 1814: static void
 1815: dgb_drain_or_flush(port)
 1816: 	struct dgb_p	*port;
 1817: {
 1818: 	struct tty *tp=port->tty;
 1819: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 1820: 	volatile struct board_chan *bc=port->brdchan;
 1821: 	int error;
 1822: 	int lasttail;
 1823: 	int head, tail;
 1824: 
 1825: 	setwin(sc,0);
 1826: 
 1827: 	lasttail=-1;
 1828: 	bc->iempty=1;
 1829: 	tail=bc->tout;
 1830: 	head=bc->tin;
 1831: 
 1832: 	while(tail!=head /* && tail!=lasttail */ ) {
 1833: 		DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
 1834: 			port->unit, port->pnum, head, tail);
 1835: 
 1836: 		/* if there is no carrier simply clean the buffer */
 1837: 		if( !(tp->t_state & TS_CARR_ON) ) {
 1838: 			bc->tout=bc->tin=0;
 1839: 			bc->iempty=0;
 1840: 			hidewin(sc);
 1841: 			return;
 1842: 		}
 1843: 
 1844: 		hidewin(sc);
 1845: 		port->draining=1;
 1846: 		timeout(wakeflush,port, hz);
 1847: 		error=tsleep(&port->draining, PCATCH, "dgfls", 0);
 1848: 		port->draining=0;
 1849: 		setwin(sc,0);
 1850: 
 1851: 		if (error != 0) {
 1852: 			DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgfls) error=%d\n",
 1853: 				port->unit,port->pnum,error);
 1854: 
 1855: 			/* silently clean the buffer */
 1856: 
 1857: 			bc->tout=bc->tin=0;
 1858: 			bc->iempty=0;
 1859: 			hidewin(sc);
 1860: 			return;
 1861: 		}
 1862: 
 1863: 		lasttail=tail;
 1864: 		tail=bc->tout;
 1865: 		head=bc->tin;
 1866: 	}
 1867: 	hidewin(sc);
 1868: 	DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
 1869: 			port->unit, port->pnum, head, tail);
 1870: }
 1871: 
 1872: static int
 1873: dgbparam(tp, t)
 1874: 	struct tty	*tp;
 1875: 	struct termios	*t;
 1876: {
 1877: 	int unit=MINOR_TO_UNIT(minor(tp->t_dev));
 1878: 	int pnum=MINOR_TO_PORT(minor(tp->t_dev));
 1879: 	struct dgb_softc *sc=&dgb_softc[unit];
 1880: 	struct dgb_p *port=&sc->ports[pnum];
 1881: 	volatile struct board_chan *bc=port->brdchan;
 1882: 	int cflag;
 1883: 	int head;
 1884: 	int mval;
 1885: 	int iflag;
 1886: 	int hflow;
 1887: 	int cs;
 1888: 
 1889: 	BoardMemWinState ws=bmws_get();
 1890: 
 1891: 	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);
 1892: 
 1893: 	if(port->mustdrain) {
 1894: 		DPRINT3(DB_PARAM,"dgb%d: port%d: must call dgbdrain()\n",unit,pnum);
 1895: 		dgbdrain(port);
 1896: 	}
 1897: 
 1898: 	cflag=ttspeedtab(t->c_ospeed, dgbspeedtab);
 1899: 
 1900: 	if (t->c_ispeed == 0)
 1901: 		t->c_ispeed = t->c_ospeed;
 1902: 
 1903: 	if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
 1904: 		DPRINT4(DB_PARAM,"dgb%d: port%d: invalid cflag=0%o\n",unit,pnum,cflag);
 1905: 		return (EINVAL);
 1906: 	}
 1907: 
 1908: 	cs=splclock();
 1909: 	setwin(sc,0);
 1910: 
 1911: 	if(cflag==0) { /* hangup */
 1912: 		DPRINT3(DB_PARAM,"dgb%d: port%d: hangup\n",unit,pnum);
 1913: 		head=bc->rin;
 1914: 		bc->rout=head;
 1915: 		head=bc->tin;
 1916: 		fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
 1917: 		mval= port->omodem & ~(DTR|RTS);
 1918: 	} else {
 1919: 		cflag |= dgbflags(dgb_cflags, t->c_cflag);
 1920: 
 1921: 		if(cflag!=port->fepcflag) {
 1922: 			port->fepcflag=cflag;
 1923: 			DPRINT5(DB_PARAM,"dgb%d: port%d: set cflag=0x%x c=0x%x\n",
 1924: 					unit,pnum,cflag,t->c_cflag&~CRTSCTS);
 1925: 			fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
 1926: 		}
 1927: 		mval= port->omodem | (DTR|RTS);
 1928: 	}
 1929: 
 1930: 	iflag=dgbflags(dgb_iflags, t->c_iflag);
 1931: 	if(iflag!=port->fepiflag) {
 1932: 		port->fepiflag=iflag;
 1933: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set iflag=0x%x c=0x%x\n",unit,pnum,iflag,t->c_iflag);
 1934: 		fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
 1935: 	}
 1936: 
 1937: 	bc->mint=port->dcd;
 1938: 
 1939: 	hflow=dgbflags(dgb_flow, t->c_cflag);
 1940: 	if(hflow!=port->hflow) {
 1941: 		port->hflow=hflow;
 1942: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set hflow=0x%x f=0x%x\n",unit,pnum,hflow,t->c_cflag&CRTSCTS);
 1943: 		fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
 1944: 	}
 1945: 	
 1946: 	if(port->omodem != mval) {
 1947: 		DPRINT5(DB_PARAM,"dgb%d: port%d: setting modem parameters 0x%x was 0x%x\n",
 1948: 			unit,pnum,mval,port->omodem);
 1949: 		port->omodem=mval;
 1950: 		fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
 1951: 	}
 1952: 
 1953: 	if(port->fepstartc!=t->c_cc[VSTART] || port->fepstopc!=t->c_cc[VSTOP]) {
 1954: 		DPRINT5(DB_PARAM,"dgb%d: port%d: set startc=%d, stopc=%d\n",unit,pnum,t->c_cc[VSTART],t->c_cc[VSTOP]);
 1955: 		port->fepstartc=t->c_cc[VSTART];
 1956: 		port->fepstopc=t->c_cc[VSTOP];
 1957: 		fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
 1958: 	}
 1959: 
 1960: 	bmws_set(ws);
 1961: 	splx(cs);
 1962: 
 1963: 	return 0;
 1964: 
 1965: }
 1966: 
 1967: static void
 1968: dgbstart(tp)
 1969: 	struct tty	*tp;
 1970: {
 1971: 	int unit;
 1972: 	int pnum;
 1973: 	struct dgb_p *port;
 1974: 	struct dgb_softc *sc;
 1975: 	volatile struct board_chan *bc;
 1976: 	int head, tail;
 1977: 	int size, ocount;
 1978: 	int s;
 1979: 	int wmask;
 1980: 
 1981: 	BoardMemWinState ws=bmws_get();
 1982: 
 1983: 	unit=MINOR_TO_UNIT(minor(tp->t_dev));
 1984: 	pnum=MINOR_TO_PORT(minor(tp->t_dev));
 1985: 	sc=&dgb_softc[unit];
 1986: 	port=&sc->ports[pnum];
 1987: 	bc=port->brdchan;
 1988: 
 1989: 	wmask=port->txbufsize-1;
 1990: 
 1991: 	s=spltty();
 1992: 
 1993: 	while( tp->t_outq.c_cc!=0 ) {
 1994: 		int cs;
 1995: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 1996: 		ttwwakeup(tp);
 1997: #else
 1998: 		if(tp->t_outq.c_cc <= tp->t_lowat) {
 1999: 			if(tp->t_state & TS_ASLEEP) {
 2000: 				tp->t_state &= ~TS_ASLEEP;
 2001: 				wakeup(TSA_OLOWAT(tp));
 2002: 			}
 2003: 			/*selwakeup(&tp->t_wsel);*/
 2004: 		}
 2005: #endif
 2006: 		cs=splclock();
 2007: 		setwin(sc,0);
 2008: 
 2009: 		head=bc->tin & wmask;
 2010: 
 2011: 		do { tail=bc->tout; } while (tail != bc->tout);
 2012: 		tail=bc->tout & wmask;
 2013: 
 2014: 		DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
 2015: 
 2016: #ifdef LEAVE_FREE_CHARS 
 2017: 		if(tail>head) {
 2018: 			size=tail-head-LEAVE_FREE_CHARS;
 2019: 			if (size <0)
 2020: 			        size=0;
 2021: 		        } else {
 2022: 			        size=port->txbufsize-head;
 2023: 			        if(tail+port->txbufsize < head)
 2024: 				        size=0;
 2025: 		        }
 2026: 		}
 2027: #else
 2028: 		if(tail>head)
 2029: 			size=tail-head-1;
 2030: 		else {
 2031: 			size=port->txbufsize-head/*-1*/;
 2032: 			if(tail==0)
 2033: 				size--;
 2034: 		}
 2035: #endif
 2036: 
 2037: 		if(size==0) {
 2038: 			bc->iempty=1; bc->ilow=1;
 2039: 			splx(cs);
 2040: 			bmws_set(ws);
 2041: 			tp->t_state|=TS_BUSY;
 2042: 			splx(s);
 2043: 			return;
 2044: 		}
 2045: 
 2046: 		towin(sc,port->txwin);
 2047: 
 2048: 		ocount=q_to_b(&tp->t_outq, port->txptr+head, size);
 2049: 		head+=ocount;
 2050: 		if(head>=port->txbufsize)
 2051: 			head-=port->txbufsize;
 2052: 
 2053: 		setwin(sc,0);
 2054: 		bc->tin=head;
 2055: 
 2056: 		DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
 2057: 		hidewin(sc);
 2058: 		splx(cs);
 2059: 	}
 2060: 
 2061: 	bmws_set(ws);
 2062: 	splx(s);
 2063: 
 2064: #ifndef TS_ASLEEP	/* post 2.0.5 FreeBSD */
 2065: 	if(tp->t_state & TS_BUSY) {	
 2066: 		tp->t_state&=~TS_BUSY;
 2067: 		linesw[tp->t_line].l_start(tp);
 2068: 		ttwwakeup(tp);
 2069: 	}
 2070: #else
 2071: 	if(tp->t_state & TS_ASLEEP) {
 2072: 		tp->t_state &= ~TS_ASLEEP;
 2073: 		wakeup(TSA_OLOWAT(tp));
 2074: 	}
 2075: 	tp->t_state&=~TS_BUSY;
 2076: #endif
 2077: }
 2078: 
 2079: void
 2080: dgbstop(tp, rw)
 2081: 	struct tty	*tp;
 2082: 	int		rw;
 2083: {
 2084: 	int unit;
 2085: 	int pnum;
 2086: 	struct dgb_p *port;
 2087: 	struct dgb_softc *sc;
 2088: 	volatile struct board_chan *bc;
 2089: 	int s;
 2090: 
 2091: 	BoardMemWinState ws=bmws_get();
 2092: 
 2093: 	unit=MINOR_TO_UNIT(minor(tp->t_dev));
 2094: 	pnum=MINOR_TO_PORT(minor(tp->t_dev));
 2095: 
 2096: 	sc=&dgb_softc[unit];
 2097: 	port=&sc->ports[pnum];
 2098: 	bc=port->brdchan;
 2099: 
 2100: 	DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
 2101: 
 2102: 	s = spltty();
 2103: 	setwin(sc,0);
 2104: 
 2105: 	if (rw & FWRITE) {
 2106: 		/* clear output queue */
 2107: 		bc->tout=bc->tin=0;
 2108: 		bc->ilow=0;bc->iempty=0;
 2109: 	}
 2110: 	if (rw & FREAD) {
 2111: 		/* clear input queue */
 2112: 		bc->rout=bc->rin;
 2113: 		bc->idata=1;
 2114: 	}
 2115: 	hidewin(sc);
 2116: 	bmws_set(ws);
 2117: 	splx(s);
 2118: 	dgbstart(tp);
 2119: }
 2120: 
 2121: static void 
 2122: fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
 2123: 	struct dgb_p *port;
 2124: 	unsigned cmd, op1, op2, ncmds, bytecmd;
 2125: {
 2126: 	struct dgb_softc *sc=&dgb_softc[port->unit];
 2127: 	u_char *mem=sc->vmem;
 2128: 	unsigned tail, head;
 2129: 	int count, n;
 2130: 
 2131: 	if(port->status==DISABLED) {
 2132: 		printf("dgb%d: port%d: FEP command on disabled port\n", 
 2133: 			port->unit, port->pnum);
 2134: 		return;
 2135: 	}
 2136: 
 2137: 	/* setwin(sc,0); Require this to be set by caller */
 2138: 	head=sc->mailbox->cin;
 2139: 
 2140: 	if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
 2141: 		printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
 2142: 			port->unit, port->pnum, head);
 2143: 		return;
 2144: 	}
 2145: 
 2146: 	mem[head+FEP_CSTART+0]=cmd;
 2147: 	mem[head+FEP_CSTART+1]=port->pnum;
 2148: 	if(bytecmd) {
 2149: 		mem[head+FEP_CSTART+2]=op1;
 2150: 		mem[head+FEP_CSTART+3]=op2;
 2151: 	} else {
 2152: 		mem[head+FEP_CSTART+2]=op1&0xff;
 2153: 		mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
 2154: 	}
 2155: 
 2156: 	DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
 2157: 			(bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
 2158: 
 2159: 	head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
 2160: 	sc->mailbox->cin=head;
 2161: 
 2162: 	count=FEPTIMEOUT;
 2163: 
 2164: 	while (count-- != 0) {
 2165: 		head=sc->mailbox->cin;
 2166: 		tail=sc->mailbox->cout;
 2167: 
 2168: 		n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
 2169: 		if(n <= ncmds * (sizeof(ushort)*4))
 2170: 			return;
 2171: 	}
 2172: 	printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
 2173: }
 2174: 
 2175: static void 
 2176: disc_optim(tp, t)
 2177: 	struct tty	*tp;
 2178: 	struct termios	*t;
 2179: {
 2180: 	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 2181: 	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 2182: 	    && (!(t->c_iflag & PARMRK)
 2183: 		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 2184: 	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 2185: 	    && linesw[tp->t_line].l_rint == ttyinput)
 2186: 		tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2187: 	else
 2188: 		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2189: }