xref: /csrg-svn/sys/pmax/dev/dc.c (revision 56819)
1*56819Sralph /*-
2*56819Sralph  * Copyright (c) 1992 The Regents of the University of California.
352130Smckusick  * All rights reserved.
452130Smckusick  *
552130Smckusick  * This code is derived from software contributed to Berkeley by
6*56819Sralph  * Ralph Campbell and Rick Macklem.
7*56819Sralph  *
8*56819Sralph  * %sccs.include.redist.c%
9*56819Sralph  *
10*56819Sralph  *	@(#)dc.c	7.11 (Berkeley) 11/15/92
1152693Sralph  */
1252693Sralph 
1352693Sralph /*
1452130Smckusick  * devDC7085.c --
1552130Smckusick  *
1652130Smckusick  *     	This file contains machine-dependent routines that handle the
1752130Smckusick  *	output queue for the serial lines.
1852130Smckusick  *
1952130Smckusick  *	Copyright (C) 1989 Digital Equipment Corporation.
2052130Smckusick  *	Permission to use, copy, modify, and distribute this software and
2152130Smckusick  *	its documentation for any purpose and without fee is hereby granted,
2252130Smckusick  *	provided that the above copyright notice appears in all copies.
2352130Smckusick  *	Digital Equipment Corporation makes no representations about the
2452130Smckusick  *	suitability of this software for any purpose.  It is provided "as is"
2552130Smckusick  *	without express or implied warranty.
2652130Smckusick  *
2752130Smckusick  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devDC7085.c,
2852130Smckusick  *	v 1.4 89/08/29 11:55:30 nelson Exp $ SPRITE (DECWRL)";
2952130Smckusick  */
3052130Smckusick 
31*56819Sralph #include <dc.h>
3252130Smckusick #if NDC > 0
3352130Smckusick /*
3452130Smckusick  * DC7085 (DZ-11 look alike) Driver
3552130Smckusick  */
3656522Sbostic #include <sys/param.h>
3756522Sbostic #include <sys/systm.h>
3856522Sbostic #include <sys/ioctl.h>
3956522Sbostic #include <sys/tty.h>
4056522Sbostic #include <sys/proc.h>
4156522Sbostic #include <sys/map.h>
4256522Sbostic #include <sys/buf.h>
4356522Sbostic #include <sys/conf.h>
4456522Sbostic #include <sys/file.h>
4556522Sbostic #include <sys/uio.h>
4656522Sbostic #include <sys/kernel.h>
4756522Sbostic #include <sys/syslog.h>
4852130Smckusick 
4956522Sbostic #include <machine/dc7085cons.h>
50*56819Sralph #include <machine/pmioctl.h>
5152130Smckusick 
52*56819Sralph #include <pmax/pmax/pmaxtype.h>
53*56819Sralph #include <pmax/pmax/cons.h>
54*56819Sralph 
5556525Sbostic #include <pmax/dev/device.h>
5656525Sbostic #include <pmax/dev/pdma.h>
57*56819Sralph #include <pmax/dev/fbreg.h>
5852130Smckusick 
59*56819Sralph extern int pmax_boardtype;
60*56819Sralph extern struct consdev cn_tab;
61*56819Sralph 
6252130Smckusick /*
6352130Smckusick  * Driver information for auto-configuration stuff.
6452130Smckusick  */
6552130Smckusick int	dcprobe();
6652693Sralph void	dcintr();
6752130Smckusick struct	driver dcdriver = {
6852693Sralph 	"dc", dcprobe, 0, 0, dcintr,
6952130Smckusick };
7052130Smckusick 
7152130Smckusick #define	NDCLINE 	(NDC*4)
7252130Smckusick 
73*56819Sralph void dcstart	__P((struct tty *));
74*56819Sralph void dcxint	__P((struct tty *));
75*56819Sralph void dcPutc	__P((dev_t, int));
76*56819Sralph void dcscan	__P((void *));
7756226Sralph extern void ttrstrt __P((void *));
78*56819Sralph int dcGetc	__P((dev_t));
79*56819Sralph int dcparam	__P((struct tty *, struct termios *));
80*56819Sralph extern void KBDReset	__P((dev_t, void (*)()));
81*56819Sralph extern void MouseInit	__P((dev_t, void (*)(), int (*)()));
8252130Smckusick 
8352130Smckusick struct	tty dc_tty[NDCLINE];
8452130Smckusick int	dc_cnt = NDCLINE;
8552863Sralph void	(*dcDivertXInput)();	/* X windows keyboard input routine */
8652863Sralph void	(*dcMouseEvent)();	/* X windows mouse motion event routine */
8752863Sralph void	(*dcMouseButtons)();	/* X windows mouse buttons event routine */
8852130Smckusick #ifdef DEBUG
8952130Smckusick int	debugChar;
9052130Smckusick #endif
9152130Smckusick 
9252130Smckusick /*
9352130Smckusick  * Software copy of brk register since it isn't readable
9452130Smckusick  */
9552130Smckusick int	dc_brk[NDC];
9652130Smckusick char	dcsoftCAR[NDC];		/* mask of dc's with carrier on (DSR) */
9752130Smckusick 
9852130Smckusick /*
9952130Smckusick  * The DC7085 doesn't interrupt on carrier transitions, so
10052130Smckusick  * we have to use a timer to watch it.
10152130Smckusick  */
10252130Smckusick int	dc_timer;		/* true if timer started */
10352130Smckusick 
10452130Smckusick /*
10552130Smckusick  * Pdma structures for fast output code
10652130Smckusick  */
10752130Smckusick struct	pdma dcpdma[NDCLINE];
10852130Smckusick 
10952130Smckusick struct speedtab dcspeedtab[] = {
11052130Smckusick 	0,	0,
11152130Smckusick 	50,	LPR_B50,
11252130Smckusick 	75,	LPR_B75,
11352130Smckusick 	110,	LPR_B110,
11452130Smckusick 	134,	LPR_B134,
11552130Smckusick 	150,	LPR_B150,
11652130Smckusick 	300,	LPR_B300,
11752130Smckusick 	600,	LPR_B600,
11852130Smckusick 	1200,	LPR_B1200,
11952130Smckusick 	1800,	LPR_B1800,
12052130Smckusick 	2400,	LPR_B2400,
12152130Smckusick 	4800,	LPR_B4800,
12252130Smckusick 	9600,	LPR_B9600,
12352693Sralph 	19200,	LPR_B19200,
12452130Smckusick 	-1,	-1
12552130Smckusick };
12652130Smckusick 
12752130Smckusick #ifndef	PORTSELECTOR
12852130Smckusick #define	ISPEED	TTYDEF_SPEED
12952130Smckusick #define	LFLAG	TTYDEF_LFLAG
13052130Smckusick #else
13152130Smckusick #define	ISPEED	B4800
13252130Smckusick #define	LFLAG	(TTYDEF_LFLAG & ~ECHO)
13352130Smckusick #endif
13452130Smckusick 
13552130Smckusick /*
13652130Smckusick  * Test to see if device is present.
13752130Smckusick  * Return true if found and initialized ok.
13852130Smckusick  */
13952130Smckusick dcprobe(cp)
14052130Smckusick 	register struct pmax_ctlr *cp;
14152130Smckusick {
14252130Smckusick 	register dcregs *dcaddr;
14352130Smckusick 	register struct pdma *pdp;
14452130Smckusick 	register struct tty *tp;
14552130Smckusick 	register int cntr;
146*56819Sralph 	int s;
14752130Smckusick 
14852130Smckusick 	if (cp->pmax_unit >= NDC)
14952130Smckusick 		return (0);
15052130Smckusick 	if (badaddr(cp->pmax_addr, 2))
15152130Smckusick 		return (0);
15252130Smckusick 
15352130Smckusick 	/* reset chip */
15452130Smckusick 	dcaddr = (dcregs *)cp->pmax_addr;
15552130Smckusick 	dcaddr->dc_csr = CSR_CLR;
15652130Smckusick 	MachEmptyWriteBuffer();
15752130Smckusick 	while (dcaddr->dc_csr & CSR_CLR)
15852130Smckusick 		;
15952130Smckusick 	dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE;
16052130Smckusick 
16152130Smckusick 	/* init pseudo DMA structures */
16252130Smckusick 	pdp = &dcpdma[cp->pmax_unit * 4];
16352130Smckusick 	tp = &dc_tty[cp->pmax_unit * 4];
16452130Smckusick 	for (cntr = 0; cntr < 4; cntr++) {
165*56819Sralph 		pdp->p_addr = (void *)dcaddr;
16652130Smckusick 		pdp->p_arg = (int)tp;
16752130Smckusick 		pdp->p_fcn = dcxint;
16852130Smckusick 		tp->t_addr = (caddr_t)pdp;
16952130Smckusick 		pdp++, tp++;
17052130Smckusick 	}
17152130Smckusick 	dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB;
17252130Smckusick 
17352130Smckusick 	if (dc_timer == 0) {
17452130Smckusick 		dc_timer = 1;
17555744Sralph 		timeout(dcscan, (void *)0, hz);
17652130Smckusick 	}
17752693Sralph 	printf("dc%d at nexus0 csr 0x%x priority %d\n",
17852693Sralph 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
179*56819Sralph 
180*56819Sralph 	/*
181*56819Sralph 	 * Special handling for consoles.
182*56819Sralph 	 */
18352130Smckusick 	if (cp->pmax_unit == 0) {
184*56819Sralph 		if (cn_tab.cn_screen) {
185*56819Sralph 			s = spltty();
186*56819Sralph 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
187*56819Sralph 				LPR_B4800 | DCKBD_PORT;
188*56819Sralph 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
189*56819Sralph 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
190*56819Sralph 			MachEmptyWriteBuffer();
191*56819Sralph 			KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc);
192*56819Sralph 			MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc);
193*56819Sralph 			splx(s);
194*56819Sralph 		} else if (major(cn_tab.cn_dev) == DCDEV) {
195*56819Sralph 			s = spltty();
196*56819Sralph 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
197*56819Sralph 				LPR_B9600 | minor(cn_tab.cn_dev);
198*56819Sralph 			MachEmptyWriteBuffer();
199*56819Sralph 			cn_tab.cn_disabled = 0;
200*56819Sralph 			splx(s);
201*56819Sralph 		}
20252130Smckusick 	}
20352130Smckusick 	return (1);
20452130Smckusick }
20552130Smckusick 
20654146Sralph dcopen(dev, flag, mode, p)
20752130Smckusick 	dev_t dev;
20854146Sralph 	int flag, mode;
20954146Sralph 	struct proc *p;
21052130Smckusick {
21152130Smckusick 	register struct tty *tp;
21252130Smckusick 	register int unit;
21352130Smckusick 	int s, error = 0;
21452130Smckusick 
21552130Smckusick 	unit = minor(dev);
216*56819Sralph 	if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0)
21752130Smckusick 		return (ENXIO);
21852130Smckusick 	tp = &dc_tty[unit];
21952130Smckusick 	tp->t_addr = (caddr_t)&dcpdma[unit];
22052130Smckusick 	tp->t_oproc = dcstart;
22152130Smckusick 	tp->t_param = dcparam;
22252130Smckusick 	tp->t_dev = dev;
22352130Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
22452130Smckusick 		tp->t_state |= TS_WOPEN;
22552130Smckusick 		ttychars(tp);
22652130Smckusick #ifndef PORTSELECTOR
22752130Smckusick 		if (tp->t_ispeed == 0) {
22852130Smckusick #endif
22952130Smckusick 			tp->t_iflag = TTYDEF_IFLAG;
23052130Smckusick 			tp->t_oflag = TTYDEF_OFLAG;
23152130Smckusick 			tp->t_cflag = TTYDEF_CFLAG;
23252130Smckusick 			tp->t_lflag = LFLAG;
23352130Smckusick 			tp->t_ispeed = tp->t_ospeed = ISPEED;
23452130Smckusick #ifdef PORTSELECTOR
23552130Smckusick 			tp->t_cflag |= HUPCL;
23652130Smckusick #else
23752130Smckusick 		}
23852130Smckusick #endif
23952130Smckusick 		(void) dcparam(tp, &tp->t_termios);
24052130Smckusick 		ttsetwater(tp);
24152130Smckusick 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
24252130Smckusick 		return (EBUSY);
24352130Smckusick 	(void) dcmctl(dev, DML_DTR, DMSET);
24452130Smckusick 	s = spltty();
24552130Smckusick 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
24652130Smckusick 	       !(tp->t_state & TS_CARR_ON)) {
24752130Smckusick 		tp->t_state |= TS_WOPEN;
24852130Smckusick 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
24952130Smckusick 		    ttopen, 0))
25052130Smckusick 			break;
25152130Smckusick 	}
25252130Smckusick 	splx(s);
25352130Smckusick 	if (error)
25452130Smckusick 		return (error);
25552130Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
25652130Smckusick }
25752130Smckusick 
25852130Smckusick /*ARGSUSED*/
25954146Sralph dcclose(dev, flag, mode, p)
26052130Smckusick 	dev_t dev;
26154146Sralph 	int flag, mode;
26254146Sralph 	struct proc *p;
26352130Smckusick {
26452130Smckusick 	register struct tty *tp;
26552130Smckusick 	register int unit, bit;
26652130Smckusick 
26752130Smckusick 	unit = minor(dev);
26852130Smckusick 	tp = &dc_tty[unit];
26952130Smckusick 	bit = 1 << ((unit & 03) + 8);
27052130Smckusick 	if (dc_brk[unit >> 2] & bit) {
27152130Smckusick 		dc_brk[unit >> 2] &= ~bit;
27252130Smckusick 		ttyoutput(0, tp);
27352130Smckusick 	}
27454146Sralph 	(*linesw[tp->t_line].l_close)(tp, flag);
27552130Smckusick 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
27652130Smckusick 	    !(tp->t_state & TS_ISOPEN))
27752130Smckusick 		(void) dcmctl(dev, 0, DMSET);
27852130Smckusick 	return (ttyclose(tp));
27952130Smckusick }
28052130Smckusick 
28152130Smckusick dcread(dev, uio, flag)
28252130Smckusick 	dev_t dev;
28352130Smckusick 	struct uio *uio;
28452130Smckusick {
28552130Smckusick 	register struct tty *tp;
28652130Smckusick 
28752130Smckusick 	tp = &dc_tty[minor(dev)];
28852130Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
28952130Smckusick }
29052130Smckusick 
29152130Smckusick dcwrite(dev, uio, flag)
29252130Smckusick 	dev_t dev;
29352130Smckusick 	struct uio *uio;
29452130Smckusick {
29552130Smckusick 	register struct tty *tp;
29652130Smckusick 
29752130Smckusick 	tp = &dc_tty[minor(dev)];
29852130Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
29952130Smckusick }
30052130Smckusick 
30152130Smckusick /*ARGSUSED*/
30254146Sralph dcioctl(dev, cmd, data, flag, p)
30352130Smckusick 	dev_t dev;
304*56819Sralph 	int cmd;
30552130Smckusick 	caddr_t data;
30654146Sralph 	int flag;
30754146Sralph 	struct proc *p;
30852130Smckusick {
30952130Smckusick 	register struct tty *tp;
31052130Smckusick 	register int unit = minor(dev);
31152130Smckusick 	register int dc = unit >> 2;
31252130Smckusick 	int error;
31352130Smckusick 
31452130Smckusick 	tp = &dc_tty[unit];
31554146Sralph 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
31652130Smckusick 	if (error >= 0)
31752130Smckusick 		return (error);
31852130Smckusick 	error = ttioctl(tp, cmd, data, flag);
31952130Smckusick 	if (error >= 0)
32052130Smckusick 		return (error);
32152130Smckusick 
32252130Smckusick 	switch (cmd) {
32352130Smckusick 
32452130Smckusick 	case TIOCSBRK:
32552130Smckusick 		dc_brk[dc] |= 1 << ((unit & 03) + 8);
32652130Smckusick 		ttyoutput(0, tp);
32752130Smckusick 		break;
32852130Smckusick 
32952130Smckusick 	case TIOCCBRK:
33052130Smckusick 		dc_brk[dc] &= ~(1 << ((unit & 03) + 8));
33152130Smckusick 		ttyoutput(0, tp);
33252130Smckusick 		break;
33352130Smckusick 
33452130Smckusick 	case TIOCSDTR:
33552130Smckusick 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS);
33652130Smckusick 		break;
33752130Smckusick 
33852130Smckusick 	case TIOCCDTR:
33952130Smckusick 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC);
34052130Smckusick 		break;
34152130Smckusick 
34252130Smckusick 	case TIOCMSET:
34352130Smckusick 		(void) dcmctl(dev, *(int *)data, DMSET);
34452130Smckusick 		break;
34552130Smckusick 
34652130Smckusick 	case TIOCMBIS:
34752130Smckusick 		(void) dcmctl(dev, *(int *)data, DMBIS);
34852130Smckusick 		break;
34952130Smckusick 
35052130Smckusick 	case TIOCMBIC:
35152130Smckusick 		(void) dcmctl(dev, *(int *)data, DMBIC);
35252130Smckusick 		break;
35352130Smckusick 
35452130Smckusick 	case TIOCMGET:
35552130Smckusick 		*(int *)data = dcmctl(dev, 0, DMGET);
35652130Smckusick 		break;
35752130Smckusick 
35852130Smckusick 	default:
35952130Smckusick 		return (ENOTTY);
36052130Smckusick 	}
36152130Smckusick 	return (0);
36252130Smckusick }
36352130Smckusick 
36452130Smckusick dcparam(tp, t)
36552130Smckusick 	register struct tty *tp;
36652130Smckusick 	register struct termios *t;
36752130Smckusick {
36852130Smckusick 	register dcregs *dcaddr;
36952130Smckusick 	register int lpr;
37052130Smckusick 	register int cflag = t->c_cflag;
37152130Smckusick 	int unit = minor(tp->t_dev);
37252130Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab);
37352130Smckusick 
37452130Smckusick 	/* check requested parameters */
37552130Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
376*56819Sralph             (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 ||
377*56819Sralph 	    (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200))
37852130Smckusick                 return (EINVAL);
37952130Smckusick         /* and copy to tty */
38052130Smckusick         tp->t_ispeed = t->c_ispeed;
38152130Smckusick         tp->t_ospeed = t->c_ospeed;
38252130Smckusick         tp->t_cflag = cflag;
38352130Smckusick 
384*56819Sralph 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
385*56819Sralph 
386*56819Sralph 	/*
387*56819Sralph 	 * Handle console cases specially.
388*56819Sralph 	 */
389*56819Sralph 	if (cn_tab.cn_screen) {
390*56819Sralph 		if (unit == DCKBD_PORT) {
391*56819Sralph 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
392*56819Sralph 				LPR_B4800 | DCKBD_PORT;
393*56819Sralph 			MachEmptyWriteBuffer();
394*56819Sralph 			return (0);
395*56819Sralph 		} else if (unit == DCMOUSE_PORT) {
396*56819Sralph 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
397*56819Sralph 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
398*56819Sralph 			MachEmptyWriteBuffer();
399*56819Sralph 			return (0);
400*56819Sralph 		}
401*56819Sralph 	} else if (tp->t_dev == cn_tab.cn_dev) {
402*56819Sralph 		dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
403*56819Sralph 			LPR_B9600 | unit;
40452130Smckusick 		MachEmptyWriteBuffer();
40552130Smckusick 		return (0);
40652130Smckusick 	}
40752130Smckusick 	if (ospeed == 0) {
40852130Smckusick 		(void) dcmctl(unit, 0, DMSET);	/* hang up line */
40952130Smckusick 		return (0);
41052130Smckusick 	}
41152130Smckusick 	lpr = LPR_RXENAB | ospeed | (unit & 03);
41252130Smckusick 	if ((cflag & CSIZE) == CS7)
41352130Smckusick 		lpr |= LPR_7_BIT_CHAR;
41452130Smckusick 	else
41552130Smckusick 		lpr |= LPR_8_BIT_CHAR;
41652130Smckusick 	if (cflag & PARENB)
41752130Smckusick 		lpr |= LPR_PARENB;
41852130Smckusick 	if (cflag & PARODD)
41952130Smckusick 		lpr |= LPR_OPAR;
42052130Smckusick 	if (cflag & CSTOPB)
42152130Smckusick 		lpr |= LPR_2_STOP;
42252130Smckusick 	dcaddr->dc_lpr = lpr;
42352130Smckusick 	MachEmptyWriteBuffer();
42452130Smckusick 	return (0);
42552130Smckusick }
42652130Smckusick 
42752693Sralph /*
42852693Sralph  * Check for interrupts from all devices.
42952693Sralph  */
43052693Sralph void
43152693Sralph dcintr(unit)
43252693Sralph 	register int unit;
43352693Sralph {
43452693Sralph 	register dcregs *dcaddr;
43552693Sralph 	register unsigned csr;
43652693Sralph 
43752693Sralph 	unit <<= 2;
438*56819Sralph 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
43952693Sralph 	while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) {
44052693Sralph 		if (csr & CSR_RDONE)
44152693Sralph 			dcrint(unit);
44252693Sralph 		if (csr & CSR_TRDY)
44352693Sralph 			dcxint(&dc_tty[unit + ((csr >> 8) & 03)]);
44452693Sralph 	}
44552693Sralph }
44652693Sralph 
44752693Sralph dcrint(unit)
44852693Sralph 	register int unit;
44952693Sralph {
45052693Sralph 	register dcregs *dcaddr;
45152693Sralph 	register struct tty *tp;
45252693Sralph 	register int c, cc;
45352693Sralph 	register struct tty *tp0;
45452693Sralph 	int overrun = 0;
45552693Sralph 
456*56819Sralph 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
45752693Sralph 	tp0 = &dc_tty[unit];
45852693Sralph 	while ((c = dcaddr->dc_rbuf) < 0) {	/* char present */
45952693Sralph 		cc = c & 0xff;
46052693Sralph 		tp = tp0 + ((c >> 8) & 03);
46152693Sralph 		if ((c & RBUF_OERR) && overrun == 0) {
46252693Sralph 			log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2,
46352693Sralph 				(c >> 8) & 03);
46452693Sralph 			overrun = 1;
46552693Sralph 		}
46652693Sralph 		/* the keyboard requires special translation */
467*56819Sralph 		if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
46852693Sralph #ifdef KADB
46952693Sralph 			if (cc == LK_DO) {
47052693Sralph 				spl0();
47152693Sralph 				kdbpanic();
47252693Sralph 				return;
47352693Sralph 			}
47452693Sralph #endif
47552693Sralph #ifdef DEBUG
47652693Sralph 			debugChar = cc;
47752693Sralph #endif
47852693Sralph 			if (dcDivertXInput) {
47952863Sralph 				(*dcDivertXInput)(cc);
48052693Sralph 				return;
48152693Sralph 			}
482*56819Sralph 			if ((cc = kbdMapChar(cc)) < 0)
48352693Sralph 				return;
484*56819Sralph 		} else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) {
48552863Sralph 			register MouseReport *mrp;
48652693Sralph 			static MouseReport currentRep;
48752693Sralph 
48852863Sralph 			mrp = &currentRep;
48952863Sralph 			mrp->byteCount++;
49052693Sralph 			if (cc & MOUSE_START_FRAME) {
49152693Sralph 				/*
49252693Sralph 				 * The first mouse report byte (button state).
49352693Sralph 				 */
49452863Sralph 				mrp->state = cc;
49552863Sralph 				if (mrp->byteCount > 1)
49652863Sralph 					mrp->byteCount = 1;
49752863Sralph 			} else if (mrp->byteCount == 2) {
49852693Sralph 				/*
49952693Sralph 				 * The second mouse report byte (delta x).
50052693Sralph 				 */
50152863Sralph 				mrp->dx = cc;
50252863Sralph 			} else if (mrp->byteCount == 3) {
50352693Sralph 				/*
50452693Sralph 				 * The final mouse report byte (delta y).
50552693Sralph 				 */
50652863Sralph 				mrp->dy = cc;
50752863Sralph 				mrp->byteCount = 0;
50852863Sralph 				if (mrp->dx != 0 || mrp->dy != 0) {
50952693Sralph 					/*
51052693Sralph 					 * If the mouse moved,
51152693Sralph 					 * post a motion event.
51252693Sralph 					 */
51352863Sralph 					(*dcMouseEvent)(mrp);
51452693Sralph 				}
51552863Sralph 				(*dcMouseButtons)(mrp);
51652693Sralph 			}
51752693Sralph 			return;
51852693Sralph 		}
51952693Sralph 		if (!(tp->t_state & TS_ISOPEN)) {
52052693Sralph 			wakeup((caddr_t)&tp->t_rawq);
52152693Sralph #ifdef PORTSELECTOR
52252693Sralph 			if (!(tp->t_state & TS_WOPEN))
52352693Sralph #endif
52452693Sralph 				return;
52552693Sralph 		}
52652693Sralph 		if (c & RBUF_FERR)
52752693Sralph 			cc |= TTY_FE;
52852693Sralph 		if (c & RBUF_PERR)
52952693Sralph 			cc |= TTY_PE;
53052693Sralph 		(*linesw[tp->t_line].l_rint)(cc, tp);
53152693Sralph 	}
53252693Sralph 	DELAY(10);
53352693Sralph }
53452693Sralph 
53552755Sralph void
53652130Smckusick dcxint(tp)
53752130Smckusick 	register struct tty *tp;
53852130Smckusick {
53952130Smckusick 	register struct pdma *dp;
54052130Smckusick 	register dcregs *dcaddr;
54152130Smckusick 
54252130Smckusick 	dp = (struct pdma *)tp->t_addr;
54352130Smckusick 	if (dp->p_mem < dp->p_end) {
544*56819Sralph 		dcaddr = (dcregs *)dp->p_addr;
54552130Smckusick 		dcaddr->dc_tdr = dc_brk[(tp - dc_tty) >> 2] | *dp->p_mem++;
54652130Smckusick 		MachEmptyWriteBuffer();
54752130Smckusick 		DELAY(10);
54852130Smckusick 		return;
54952130Smckusick 	}
55052130Smckusick 	tp->t_state &= ~TS_BUSY;
55152130Smckusick 	if (tp->t_state & TS_FLUSH)
55252130Smckusick 		tp->t_state &= ~TS_FLUSH;
55352130Smckusick 	else {
55452130Smckusick 		ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
55552130Smckusick 		dp->p_end = dp->p_mem = tp->t_outq.c_cf;
55652130Smckusick 	}
55752130Smckusick 	if (tp->t_line)
55852130Smckusick 		(*linesw[tp->t_line].l_start)(tp);
55952130Smckusick 	else
56052130Smckusick 		dcstart(tp);
56152130Smckusick 	if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
562*56819Sralph 		((dcregs *)dp->p_addr)->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03));
56352130Smckusick 		MachEmptyWriteBuffer();
56452130Smckusick 		DELAY(10);
56552130Smckusick 	}
56652130Smckusick }
56752130Smckusick 
56852755Sralph void
56952130Smckusick dcstart(tp)
57052130Smckusick 	register struct tty *tp;
57152130Smckusick {
57252130Smckusick 	register struct pdma *dp;
57352130Smckusick 	register dcregs *dcaddr;
57452130Smckusick 	register int cc;
57552130Smckusick 	int s;
57652130Smckusick 
57752130Smckusick 	dp = (struct pdma *)tp->t_addr;
578*56819Sralph 	dcaddr = (dcregs *)dp->p_addr;
57952130Smckusick 	s = spltty();
58052130Smckusick 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
58152130Smckusick 		goto out;
58252130Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
58352130Smckusick 		if (tp->t_state & TS_ASLEEP) {
58452130Smckusick 			tp->t_state &= ~TS_ASLEEP;
58552130Smckusick 			wakeup((caddr_t)&tp->t_outq);
58652130Smckusick 		}
58752674Smckusick 		selwakeup(&tp->t_wsel);
58852130Smckusick 	}
58952130Smckusick 	if (tp->t_outq.c_cc == 0)
59052130Smckusick 		goto out;
59152130Smckusick 	/* handle console specially */
592*56819Sralph 	if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
59352130Smckusick 		while (tp->t_outq.c_cc > 0) {
59452130Smckusick 			cc = getc(&tp->t_outq) & 0x7f;
59552863Sralph 			cnputc(cc);
59652130Smckusick 		}
59752130Smckusick 		/*
59852130Smckusick 		 * After we flush the output queue we may need to wake
59952130Smckusick 		 * up the process that made the output.
60052130Smckusick 		 */
60152130Smckusick 		if (tp->t_outq.c_cc <= tp->t_lowat) {
60252130Smckusick 			if (tp->t_state & TS_ASLEEP) {
60352130Smckusick 				tp->t_state &= ~TS_ASLEEP;
60452130Smckusick 				wakeup((caddr_t)&tp->t_outq);
60552130Smckusick 			}
60652674Smckusick 			selwakeup(&tp->t_wsel);
60752130Smckusick 		}
60852130Smckusick 		goto out;
60952130Smckusick 	}
61052130Smckusick 	if (tp->t_flags & (RAW|LITOUT))
61152130Smckusick 		cc = ndqb(&tp->t_outq, 0);
61252130Smckusick 	else {
61352130Smckusick 		cc = ndqb(&tp->t_outq, 0200);
61452130Smckusick 		if (cc == 0) {
61552130Smckusick 			cc = getc(&tp->t_outq);
61655744Sralph 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
61752130Smckusick 			tp->t_state |= TS_TIMEOUT;
61852130Smckusick 			goto out;
61952130Smckusick 		}
62052130Smckusick 	}
62152130Smckusick 	tp->t_state |= TS_BUSY;
62252130Smckusick 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
62352130Smckusick 	dp->p_end += cc;
62452130Smckusick 	dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03);
62552130Smckusick 	MachEmptyWriteBuffer();
62652130Smckusick out:
62752130Smckusick 	splx(s);
62852130Smckusick }
62952130Smckusick 
63052130Smckusick /*
63152130Smckusick  * Stop output on a line.
63252130Smckusick  */
63352130Smckusick /*ARGSUSED*/
63452130Smckusick dcstop(tp, flag)
63552130Smckusick 	register struct tty *tp;
63652130Smckusick {
63752130Smckusick 	register struct pdma *dp;
63852130Smckusick 	register int s;
63952130Smckusick 
64052130Smckusick 	dp = (struct pdma *)tp->t_addr;
64152130Smckusick 	s = spltty();
64252130Smckusick 	if (tp->t_state & TS_BUSY) {
64352130Smckusick 		dp->p_end = dp->p_mem;
64452130Smckusick 		if (!(tp->t_state & TS_TTSTOP))
64552130Smckusick 			tp->t_state |= TS_FLUSH;
64652130Smckusick 	}
64752130Smckusick 	splx(s);
64852130Smckusick }
64952130Smckusick 
65052130Smckusick dcmctl(dev, bits, how)
65152130Smckusick 	dev_t dev;
65252130Smckusick 	int bits, how;
65352130Smckusick {
65452130Smckusick 	register dcregs *dcaddr;
65552130Smckusick 	register int unit, mbits;
65652130Smckusick 	int b, s;
65752693Sralph 	register int msr;
65852130Smckusick 
65952130Smckusick 	unit = minor(dev);
66052130Smckusick 	b = 1 << (unit & 03);
661*56819Sralph 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
66252130Smckusick 	s = spltty();
66352130Smckusick 	/* only channel 2 has modem control (what about line 3?) */
664*56819Sralph 	mbits = DML_DTR | DML_DSR | DML_CAR;
66552693Sralph 	switch (unit & 03) {
66652693Sralph 	case 2:
66752130Smckusick 		mbits = 0;
66852130Smckusick 		if (dcaddr->dc_tcr & TCR_DTR2)
66952130Smckusick 			mbits |= DML_DTR;
67052693Sralph 		msr = dcaddr->dc_msr;
67152693Sralph 		if (msr & MSR_CD2)
67252693Sralph 			mbits |= DML_CAR;
673*56819Sralph 		if (msr & MSR_DSR2) {
674*56819Sralph 			if (pmax_boardtype == DS_PMAX)
675*56819Sralph 				mbits |= DML_CAR | DML_DSR;
676*56819Sralph 			else
677*56819Sralph 				mbits |= DML_DSR;
678*56819Sralph 		}
67952693Sralph 		break;
68052693Sralph 
68152693Sralph 	case 3:
682*56819Sralph 		if (pmax_boardtype != DS_PMAX) {
683*56819Sralph 			mbits = 0;
684*56819Sralph 			if (dcaddr->dc_tcr & TCR_DTR3)
685*56819Sralph 				mbits |= DML_DTR;
686*56819Sralph 			msr = dcaddr->dc_msr;
687*56819Sralph 			if (msr & MSR_CD3)
688*56819Sralph 				mbits |= DML_CAR;
689*56819Sralph 			if (msr & MSR_DSR3)
690*56819Sralph 				mbits |= DML_DSR;
691*56819Sralph 		}
69252693Sralph 	}
69352130Smckusick 	switch (how) {
69452130Smckusick 	case DMSET:
69552130Smckusick 		mbits = bits;
69652130Smckusick 		break;
69752130Smckusick 
69852130Smckusick 	case DMBIS:
69952130Smckusick 		mbits |= bits;
70052130Smckusick 		break;
70152130Smckusick 
70252130Smckusick 	case DMBIC:
70352130Smckusick 		mbits &= ~bits;
70452130Smckusick 		break;
70552130Smckusick 
70652130Smckusick 	case DMGET:
70752130Smckusick 		(void) splx(s);
70852130Smckusick 		return (mbits);
70952130Smckusick 	}
71052693Sralph 	switch (unit & 03) {
71152693Sralph 	case 2:
71252130Smckusick 		if (mbits & DML_DTR)
71352130Smckusick 			dcaddr->dc_tcr |= TCR_DTR2;
71452130Smckusick 		else
71552130Smckusick 			dcaddr->dc_tcr &= ~TCR_DTR2;
71652693Sralph 		break;
71752693Sralph 
71852693Sralph 	case 3:
719*56819Sralph 		if (pmax_boardtype != DS_PMAX) {
720*56819Sralph 			if (mbits & DML_DTR)
721*56819Sralph 				dcaddr->dc_tcr |= TCR_DTR3;
722*56819Sralph 			else
723*56819Sralph 				dcaddr->dc_tcr &= ~TCR_DTR3;
724*56819Sralph 		}
72552130Smckusick 	}
72652130Smckusick 	if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b))
72752130Smckusick 		dc_tty[unit].t_state |= TS_CARR_ON;
72852130Smckusick 	(void) splx(s);
72952130Smckusick 	return (mbits);
73052130Smckusick }
73152130Smckusick 
73252130Smckusick /*
73352130Smckusick  * This is called by timeout() periodically.
73452130Smckusick  * Check to see if modem status bits have changed.
73552130Smckusick  */
736*56819Sralph void
73755744Sralph dcscan(arg)
73855744Sralph 	void *arg;
73952130Smckusick {
74052130Smckusick 	register dcregs *dcaddr;
74152130Smckusick 	register struct tty *tp;
74252130Smckusick 	register int i, bit, car;
74352130Smckusick 	int s;
74452130Smckusick 
74552130Smckusick 	s = spltty();
74652130Smckusick 	/* only channel 2 has modem control (what about line 3?) */
747*56819Sralph 	dcaddr = (dcregs *)dcpdma[i = 2].p_addr;
74852130Smckusick 	tp = &dc_tty[i];
74952130Smckusick 	bit = TCR_DTR2;
75052130Smckusick 	if (dcsoftCAR[i >> 2] & bit)
75152130Smckusick 		car = 1;
75252130Smckusick 	else
75352130Smckusick 		car = dcaddr->dc_msr & MSR_DSR2;
75452130Smckusick 	if (car) {
75552130Smckusick 		/* carrier present */
75652130Smckusick 		if (!(tp->t_state & TS_CARR_ON))
75752130Smckusick 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
75852130Smckusick 	} else if ((tp->t_state & TS_CARR_ON) &&
75952130Smckusick 	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
76052130Smckusick 		dcaddr->dc_tcr &= ~bit;
76152130Smckusick 	splx(s);
76255744Sralph 	timeout(dcscan, (void *)0, hz);
76352130Smckusick }
76452130Smckusick 
76552130Smckusick /*
76652130Smckusick  * ----------------------------------------------------------------------------
76752130Smckusick  *
768*56819Sralph  * dcGetc --
76952130Smckusick  *
770*56819Sralph  *	Read a character from a serial line.
77152130Smckusick  *
77252130Smckusick  * Results:
773*56819Sralph  *	A character read from the serial port.
77452130Smckusick  *
77552130Smckusick  * Side effects:
77652130Smckusick  *	None.
77752130Smckusick  *
77852130Smckusick  * ----------------------------------------------------------------------------
77952130Smckusick  */
78052130Smckusick int
781*56819Sralph dcGetc(dev)
782*56819Sralph 	dev_t dev;
78352130Smckusick {
78452130Smckusick 	register dcregs *dcaddr;
78552130Smckusick 	register int c;
78654146Sralph 	int s;
78752130Smckusick 
788*56819Sralph 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
78952130Smckusick 	if (!dcaddr)
79052130Smckusick 		return (0);
79154146Sralph 	s = spltty();
79252693Sralph 	for (;;) {
79352693Sralph 		if (!(dcaddr->dc_csr & CSR_RDONE))
79452693Sralph 			continue;
79552693Sralph 		c = dcaddr->dc_rbuf;
79652693Sralph 		DELAY(10);
797*56819Sralph 		if (((c >> 8) & 03) == (minor(dev) & 03))
79852693Sralph 			break;
79952693Sralph 	}
80052693Sralph 	splx(s);
801*56819Sralph 	return (c & 0xff);
80252693Sralph }
80352693Sralph 
80452693Sralph /*
805*56819Sralph  * Send a char on a port, non interrupt driven.
80652693Sralph  */
80752130Smckusick void
808*56819Sralph dcPutc(dev, c)
809*56819Sralph 	dev_t dev;
81052130Smckusick 	int c;
81152130Smckusick {
81252130Smckusick 	register dcregs *dcaddr;
81352130Smckusick 	register u_short tcr;
81452130Smckusick 	register int timeout;
815*56819Sralph 	int s, line;
81652130Smckusick 
817*56819Sralph 	s = spltty();
818*56819Sralph 
819*56819Sralph 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
82052130Smckusick 	tcr = dcaddr->dc_tcr;
821*56819Sralph 	dcaddr->dc_tcr = tcr | (1 << minor(dev));
82252130Smckusick 	MachEmptyWriteBuffer();
82352130Smckusick 	DELAY(10);
82452130Smckusick 	while (1) {
82552130Smckusick 		/*
82652130Smckusick 		 * Wait for transmitter to be not busy.
82752130Smckusick 		 */
82852130Smckusick 		timeout = 1000000;
82952130Smckusick 		while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
83052130Smckusick 			timeout--;
83152130Smckusick 		if (timeout == 0) {
832*56819Sralph 			printf("dcPutc: timeout waiting for CSR_TRDY\n");
83352130Smckusick 			break;
83452130Smckusick 		}
83552130Smckusick 		line = (dcaddr->dc_csr >> 8) & 3;
83652130Smckusick 		/*
83752130Smckusick 		 * Check to be sure its the right port.
83852130Smckusick 		 */
839*56819Sralph 		if (line != minor(dev)) {
84052130Smckusick 			tcr |= 1 << line;
84152130Smckusick 			dcaddr->dc_tcr &= ~(1 << line);
84252130Smckusick 			MachEmptyWriteBuffer();
84352130Smckusick 			DELAY(10);
84452130Smckusick 			continue;
84552130Smckusick 		}
84652130Smckusick 		/*
84752130Smckusick 		 * Start sending the character.
84852130Smckusick 		 */
84952130Smckusick 		dcaddr->dc_tdr = dc_brk[0] | (c & 0xff);
85052130Smckusick 		MachEmptyWriteBuffer();
85152130Smckusick 		DELAY(10);
85252130Smckusick 		/*
85352130Smckusick 		 * Wait for character to be sent.
85452130Smckusick 		 */
85552130Smckusick 		while (1) {
85652130Smckusick 			/*
85752130Smckusick 			 * cc -O bug: this code produces and infinite loop!
85852130Smckusick 			 * while (!(dcaddr->dc_csr & CSR_TRDY))
85952130Smckusick 			 *	;
86052130Smckusick 			 */
86152130Smckusick 			timeout = 1000000;
86252130Smckusick 			while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
86352130Smckusick 				timeout--;
86452130Smckusick 			line = (dcaddr->dc_csr >> 8) & 3;
865*56819Sralph 			if (line != minor(dev)) {
86652130Smckusick 				tcr |= 1 << line;
86752130Smckusick 				dcaddr->dc_tcr &= ~(1 << line);
86852130Smckusick 				MachEmptyWriteBuffer();
86952130Smckusick 				DELAY(10);
87052130Smckusick 				continue;
87152130Smckusick 			}
872*56819Sralph 			dcaddr->dc_tcr &= ~(1 << minor(dev));
87352130Smckusick 			MachEmptyWriteBuffer();
87452130Smckusick 			DELAY(10);
87552130Smckusick 			break;
87652130Smckusick 		}
87752130Smckusick 		break;
87852130Smckusick 	}
87952130Smckusick 	/*
88052130Smckusick 	 * Enable interrupts for other lines which became ready.
88152130Smckusick 	 */
88252130Smckusick 	if (tcr & 0xF) {
88352130Smckusick 		dcaddr->dc_tcr = tcr;
88452130Smckusick 		MachEmptyWriteBuffer();
88552130Smckusick 		DELAY(10);
88652130Smckusick 	}
88752130Smckusick 
888*56819Sralph 	splx(s);
88952130Smckusick }
89052130Smckusick #endif /* NDC */
891