156819Sralph /*-
263205Sbostic * Copyright (c) 1992, 1993
363205Sbostic * The Regents of the University of California. All rights reserved.
452130Smckusick *
552130Smckusick * This code is derived from software contributed to Berkeley by
656819Sralph * Ralph Campbell and Rick Macklem.
756819Sralph *
856819Sralph * %sccs.include.redist.c%
956819Sralph *
10*69799Sralph * @(#)dc.c 8.5 (Berkeley) 06/02/95
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
3156819Sralph #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>
5056819Sralph #include <machine/pmioctl.h>
5152130Smckusick
5256819Sralph #include <pmax/pmax/pmaxtype.h>
5356819Sralph #include <pmax/pmax/cons.h>
5456819Sralph
5556525Sbostic #include <pmax/dev/device.h>
5656525Sbostic #include <pmax/dev/pdma.h>
5756819Sralph #include <pmax/dev/fbreg.h>
5852130Smckusick
5956819Sralph extern int pmax_boardtype;
6056819Sralph extern struct consdev cn_tab;
6156819Sralph
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
7356819Sralph void dcstart __P((struct tty *));
7456819Sralph void dcxint __P((struct tty *));
7556819Sralph void dcPutc __P((dev_t, int));
7656819Sralph void dcscan __P((void *));
7756226Sralph extern void ttrstrt __P((void *));
7856819Sralph int dcGetc __P((dev_t));
7956819Sralph int dcparam __P((struct tty *, struct termios *));
8052130Smckusick
8152130Smckusick struct tty dc_tty[NDCLINE];
8252130Smckusick int dc_cnt = NDCLINE;
8352863Sralph void (*dcDivertXInput)(); /* X windows keyboard input routine */
8452863Sralph void (*dcMouseEvent)(); /* X windows mouse motion event routine */
8552863Sralph void (*dcMouseButtons)(); /* X windows mouse buttons event routine */
8652130Smckusick #ifdef DEBUG
8752130Smckusick int debugChar;
8852130Smckusick #endif
8952130Smckusick
9052130Smckusick /*
9152130Smckusick * Software copy of brk register since it isn't readable
9252130Smckusick */
9352130Smckusick int dc_brk[NDC];
9452130Smckusick char dcsoftCAR[NDC]; /* mask of dc's with carrier on (DSR) */
9552130Smckusick
9652130Smckusick /*
9752130Smckusick * The DC7085 doesn't interrupt on carrier transitions, so
9852130Smckusick * we have to use a timer to watch it.
9952130Smckusick */
10052130Smckusick int dc_timer; /* true if timer started */
10152130Smckusick
10252130Smckusick /*
10352130Smckusick * Pdma structures for fast output code
10452130Smckusick */
10552130Smckusick struct pdma dcpdma[NDCLINE];
10652130Smckusick
10752130Smckusick struct speedtab dcspeedtab[] = {
10852130Smckusick 0, 0,
10952130Smckusick 50, LPR_B50,
11052130Smckusick 75, LPR_B75,
11152130Smckusick 110, LPR_B110,
11252130Smckusick 134, LPR_B134,
11352130Smckusick 150, LPR_B150,
11452130Smckusick 300, LPR_B300,
11552130Smckusick 600, LPR_B600,
11652130Smckusick 1200, LPR_B1200,
11752130Smckusick 1800, LPR_B1800,
11852130Smckusick 2400, LPR_B2400,
11952130Smckusick 4800, LPR_B4800,
12052130Smckusick 9600, LPR_B9600,
12152693Sralph 19200, LPR_B19200,
12252130Smckusick -1, -1
12352130Smckusick };
12452130Smckusick
12552130Smckusick #ifndef PORTSELECTOR
12652130Smckusick #define ISPEED TTYDEF_SPEED
12752130Smckusick #define LFLAG TTYDEF_LFLAG
12852130Smckusick #else
12952130Smckusick #define ISPEED B4800
13052130Smckusick #define LFLAG (TTYDEF_LFLAG & ~ECHO)
13152130Smckusick #endif
13252130Smckusick
13352130Smckusick /*
13452130Smckusick * Test to see if device is present.
13552130Smckusick * Return true if found and initialized ok.
13652130Smckusick */
dcprobe(cp)13752130Smckusick dcprobe(cp)
13852130Smckusick register struct pmax_ctlr *cp;
13952130Smckusick {
14052130Smckusick register dcregs *dcaddr;
14152130Smckusick register struct pdma *pdp;
14252130Smckusick register struct tty *tp;
14352130Smckusick register int cntr;
14456819Sralph int s;
14552130Smckusick
14652130Smckusick if (cp->pmax_unit >= NDC)
14752130Smckusick return (0);
14852130Smckusick if (badaddr(cp->pmax_addr, 2))
14952130Smckusick return (0);
15052130Smckusick
15157234Sralph /*
15257234Sralph * For a remote console, wait a while for previous output to
15357234Sralph * complete.
15457234Sralph */
15557234Sralph if (major(cn_tab.cn_dev) == DCDEV && cp->pmax_unit == 0 &&
15657234Sralph cn_tab.cn_screen == 0)
15757234Sralph DELAY(10000);
15857234Sralph
15952130Smckusick /* reset chip */
16052130Smckusick dcaddr = (dcregs *)cp->pmax_addr;
16152130Smckusick dcaddr->dc_csr = CSR_CLR;
16252130Smckusick MachEmptyWriteBuffer();
16352130Smckusick while (dcaddr->dc_csr & CSR_CLR)
16452130Smckusick ;
16552130Smckusick dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE;
16652130Smckusick
16752130Smckusick /* init pseudo DMA structures */
16852130Smckusick pdp = &dcpdma[cp->pmax_unit * 4];
16952130Smckusick tp = &dc_tty[cp->pmax_unit * 4];
17052130Smckusick for (cntr = 0; cntr < 4; cntr++) {
17156819Sralph pdp->p_addr = (void *)dcaddr;
17252130Smckusick pdp->p_arg = (int)tp;
17352130Smckusick pdp->p_fcn = dcxint;
17452130Smckusick pdp++, tp++;
17552130Smckusick }
17652130Smckusick dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB;
17752130Smckusick
17852130Smckusick if (dc_timer == 0) {
17952130Smckusick dc_timer = 1;
18055744Sralph timeout(dcscan, (void *)0, hz);
18152130Smckusick }
18256819Sralph
18356819Sralph /*
18456819Sralph * Special handling for consoles.
18556819Sralph */
18652130Smckusick if (cp->pmax_unit == 0) {
18756819Sralph if (cn_tab.cn_screen) {
18856819Sralph s = spltty();
18956819Sralph dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
19056819Sralph LPR_B4800 | DCKBD_PORT;
19158975Sralph MachEmptyWriteBuffer();
19256819Sralph dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
19356819Sralph LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
19456819Sralph MachEmptyWriteBuffer();
19557234Sralph DELAY(1000);
19656819Sralph KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc);
19756819Sralph MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc);
19856819Sralph splx(s);
19956819Sralph } else if (major(cn_tab.cn_dev) == DCDEV) {
20056819Sralph s = spltty();
20156819Sralph dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
20256819Sralph LPR_B9600 | minor(cn_tab.cn_dev);
20356819Sralph MachEmptyWriteBuffer();
20457234Sralph DELAY(1000);
20556819Sralph cn_tab.cn_disabled = 0;
20656819Sralph splx(s);
20756819Sralph }
20852130Smckusick }
20957234Sralph printf("dc%d at nexus0 csr 0x%x priority %d\n",
21057234Sralph cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
21152130Smckusick return (1);
21252130Smckusick }
21352130Smckusick
dcopen(dev,flag,mode,p)21454146Sralph dcopen(dev, flag, mode, p)
21552130Smckusick dev_t dev;
21654146Sralph int flag, mode;
21754146Sralph struct proc *p;
21852130Smckusick {
21952130Smckusick register struct tty *tp;
22052130Smckusick register int unit;
22152130Smckusick int s, error = 0;
22252130Smckusick
22352130Smckusick unit = minor(dev);
22456819Sralph if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0)
22552130Smckusick return (ENXIO);
22652130Smckusick tp = &dc_tty[unit];
22752130Smckusick tp->t_oproc = dcstart;
22852130Smckusick tp->t_param = dcparam;
22952130Smckusick tp->t_dev = dev;
23052130Smckusick if ((tp->t_state & TS_ISOPEN) == 0) {
23152130Smckusick tp->t_state |= TS_WOPEN;
23252130Smckusick ttychars(tp);
23352130Smckusick #ifndef PORTSELECTOR
23452130Smckusick if (tp->t_ispeed == 0) {
23552130Smckusick #endif
23652130Smckusick tp->t_iflag = TTYDEF_IFLAG;
23752130Smckusick tp->t_oflag = TTYDEF_OFLAG;
23852130Smckusick tp->t_cflag = TTYDEF_CFLAG;
23952130Smckusick tp->t_lflag = LFLAG;
24052130Smckusick tp->t_ispeed = tp->t_ospeed = ISPEED;
24152130Smckusick #ifdef PORTSELECTOR
24252130Smckusick tp->t_cflag |= HUPCL;
24352130Smckusick #else
24452130Smckusick }
24552130Smckusick #endif
24652130Smckusick (void) dcparam(tp, &tp->t_termios);
24752130Smckusick ttsetwater(tp);
24852130Smckusick } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
24952130Smckusick return (EBUSY);
25067477Smckusick (void) dcmctl(dev, DML_DTR | DML_RTS, DMSET);
251*69799Sralph if ((dcsoftCAR[unit >> 2] & (1 << (unit & 03))) ||
252*69799Sralph (dcmctl(dev, 0, DMGET) & DML_CAR))
253*69799Sralph tp->t_state |= TS_CARR_ON;
25452130Smckusick s = spltty();
25552130Smckusick while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
25652130Smckusick !(tp->t_state & TS_CARR_ON)) {
25752130Smckusick tp->t_state |= TS_WOPEN;
25852130Smckusick if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
25952130Smckusick ttopen, 0))
26052130Smckusick break;
26152130Smckusick }
26252130Smckusick splx(s);
26352130Smckusick if (error)
26452130Smckusick return (error);
26552130Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp));
26652130Smckusick }
26752130Smckusick
26852130Smckusick /*ARGSUSED*/
dcclose(dev,flag,mode,p)26954146Sralph dcclose(dev, flag, mode, p)
27052130Smckusick dev_t dev;
27154146Sralph int flag, mode;
27254146Sralph struct proc *p;
27352130Smckusick {
27452130Smckusick register struct tty *tp;
27552130Smckusick register int unit, bit;
276*69799Sralph int s;
27752130Smckusick
27852130Smckusick unit = minor(dev);
27952130Smckusick tp = &dc_tty[unit];
28052130Smckusick bit = 1 << ((unit & 03) + 8);
281*69799Sralph s = spltty();
282*69799Sralph /* turn off the break bit if it is set */
28352130Smckusick if (dc_brk[unit >> 2] & bit) {
28452130Smckusick dc_brk[unit >> 2] &= ~bit;
28552130Smckusick ttyoutput(0, tp);
28652130Smckusick }
287*69799Sralph splx(s);
28854146Sralph (*linesw[tp->t_line].l_close)(tp, flag);
28952130Smckusick if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
29052130Smckusick !(tp->t_state & TS_ISOPEN))
29152130Smckusick (void) dcmctl(dev, 0, DMSET);
29252130Smckusick return (ttyclose(tp));
29352130Smckusick }
29452130Smckusick
dcread(dev,uio,flag)29552130Smckusick dcread(dev, uio, flag)
29652130Smckusick dev_t dev;
29752130Smckusick struct uio *uio;
29852130Smckusick {
29952130Smckusick register struct tty *tp;
30052130Smckusick
30152130Smckusick tp = &dc_tty[minor(dev)];
30267477Smckusick if ((tp->t_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK) &&
30367477Smckusick tp->t_rawq.c_cc < TTYHOG/5) {
30467477Smckusick tp->t_state &= ~TS_TBLOCK;
30567477Smckusick (void) dcmctl(dev, DML_RTS, DMBIS);
30667477Smckusick }
30752130Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
30852130Smckusick }
30952130Smckusick
dcwrite(dev,uio,flag)31052130Smckusick dcwrite(dev, uio, flag)
31152130Smckusick dev_t dev;
31252130Smckusick struct uio *uio;
31352130Smckusick {
31452130Smckusick register struct tty *tp;
31552130Smckusick
31652130Smckusick tp = &dc_tty[minor(dev)];
31752130Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
31852130Smckusick }
31952130Smckusick
32052130Smckusick /*ARGSUSED*/
dcioctl(dev,cmd,data,flag,p)32154146Sralph dcioctl(dev, cmd, data, flag, p)
32252130Smckusick dev_t dev;
323*69799Sralph u_long cmd;
32452130Smckusick caddr_t data;
32554146Sralph int flag;
32654146Sralph struct proc *p;
32752130Smckusick {
32852130Smckusick register struct tty *tp;
32952130Smckusick register int unit = minor(dev);
33052130Smckusick register int dc = unit >> 2;
33152130Smckusick int error;
33252130Smckusick
33352130Smckusick tp = &dc_tty[unit];
33454146Sralph error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
33552130Smckusick if (error >= 0)
33652130Smckusick return (error);
33752130Smckusick error = ttioctl(tp, cmd, data, flag);
33852130Smckusick if (error >= 0)
33952130Smckusick return (error);
34052130Smckusick
34152130Smckusick switch (cmd) {
34252130Smckusick
34352130Smckusick case TIOCSBRK:
34452130Smckusick dc_brk[dc] |= 1 << ((unit & 03) + 8);
34552130Smckusick ttyoutput(0, tp);
34652130Smckusick break;
34752130Smckusick
34852130Smckusick case TIOCCBRK:
34952130Smckusick dc_brk[dc] &= ~(1 << ((unit & 03) + 8));
35052130Smckusick ttyoutput(0, tp);
35152130Smckusick break;
35252130Smckusick
35352130Smckusick case TIOCSDTR:
35467477Smckusick (void) dcmctl(dev, DML_DTR | DML_RTS, DMBIS);
35552130Smckusick break;
35652130Smckusick
35752130Smckusick case TIOCCDTR:
35867477Smckusick (void) dcmctl(dev, DML_DTR | DML_RTS, DMBIC);
35952130Smckusick break;
36052130Smckusick
36152130Smckusick case TIOCMSET:
36252130Smckusick (void) dcmctl(dev, *(int *)data, DMSET);
36352130Smckusick break;
36452130Smckusick
36552130Smckusick case TIOCMBIS:
36652130Smckusick (void) dcmctl(dev, *(int *)data, DMBIS);
36752130Smckusick break;
36852130Smckusick
36952130Smckusick case TIOCMBIC:
37052130Smckusick (void) dcmctl(dev, *(int *)data, DMBIC);
37152130Smckusick break;
37252130Smckusick
37352130Smckusick case TIOCMGET:
37452130Smckusick *(int *)data = dcmctl(dev, 0, DMGET);
37552130Smckusick break;
37652130Smckusick
37752130Smckusick default:
37852130Smckusick return (ENOTTY);
37952130Smckusick }
38052130Smckusick return (0);
38152130Smckusick }
38252130Smckusick
dcparam(tp,t)38352130Smckusick dcparam(tp, t)
38452130Smckusick register struct tty *tp;
38552130Smckusick register struct termios *t;
38652130Smckusick {
38752130Smckusick register dcregs *dcaddr;
38852130Smckusick register int lpr;
38952130Smckusick register int cflag = t->c_cflag;
39052130Smckusick int unit = minor(tp->t_dev);
39152130Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab);
39267535Smckusick int s;
39352130Smckusick
39452130Smckusick /* check requested parameters */
39552130Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
39656819Sralph (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 ||
39756819Sralph (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200))
39852130Smckusick return (EINVAL);
39952130Smckusick /* and copy to tty */
40052130Smckusick tp->t_ispeed = t->c_ispeed;
40152130Smckusick tp->t_ospeed = t->c_ospeed;
40252130Smckusick tp->t_cflag = cflag;
40352130Smckusick
40456819Sralph /*
40556819Sralph * Handle console cases specially.
40656819Sralph */
40756819Sralph if (cn_tab.cn_screen) {
40856819Sralph if (unit == DCKBD_PORT) {
40967535Smckusick lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
41056819Sralph LPR_B4800 | DCKBD_PORT;
41167535Smckusick goto out;
41256819Sralph } else if (unit == DCMOUSE_PORT) {
41367535Smckusick lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
41456819Sralph LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
41567535Smckusick goto out;
41656819Sralph }
41756819Sralph } else if (tp->t_dev == cn_tab.cn_dev) {
41867535Smckusick lpr = LPR_RXENAB | LPR_8_BIT_CHAR | LPR_B9600 | unit;
41967535Smckusick goto out;
42052130Smckusick }
42152130Smckusick if (ospeed == 0) {
42252130Smckusick (void) dcmctl(unit, 0, DMSET); /* hang up line */
42352130Smckusick return (0);
42452130Smckusick }
42552130Smckusick lpr = LPR_RXENAB | ospeed | (unit & 03);
42652130Smckusick if ((cflag & CSIZE) == CS7)
42752130Smckusick lpr |= LPR_7_BIT_CHAR;
42852130Smckusick else
42952130Smckusick lpr |= LPR_8_BIT_CHAR;
43052130Smckusick if (cflag & PARENB)
43152130Smckusick lpr |= LPR_PARENB;
43252130Smckusick if (cflag & PARODD)
43352130Smckusick lpr |= LPR_OPAR;
43452130Smckusick if (cflag & CSTOPB)
43552130Smckusick lpr |= LPR_2_STOP;
43667535Smckusick out:
43767535Smckusick dcaddr = (dcregs *)dcpdma[unit].p_addr;
43867535Smckusick s = spltty();
43952130Smckusick dcaddr->dc_lpr = lpr;
44052130Smckusick MachEmptyWriteBuffer();
44167535Smckusick splx(s);
44258975Sralph DELAY(10);
44352130Smckusick return (0);
44452130Smckusick }
44552130Smckusick
44652693Sralph /*
44752693Sralph * Check for interrupts from all devices.
44852693Sralph */
44952693Sralph void
dcintr(unit)45052693Sralph dcintr(unit)
45152693Sralph register int unit;
45252693Sralph {
45352693Sralph register dcregs *dcaddr;
45452693Sralph register unsigned csr;
45552693Sralph
45652693Sralph unit <<= 2;
45756819Sralph dcaddr = (dcregs *)dcpdma[unit].p_addr;
45852693Sralph while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) {
45952693Sralph if (csr & CSR_RDONE)
46052693Sralph dcrint(unit);
46152693Sralph if (csr & CSR_TRDY)
46252693Sralph dcxint(&dc_tty[unit + ((csr >> 8) & 03)]);
46352693Sralph }
46452693Sralph }
46552693Sralph
dcrint(unit)46652693Sralph dcrint(unit)
46752693Sralph register int unit;
46852693Sralph {
46952693Sralph register dcregs *dcaddr;
47052693Sralph register struct tty *tp;
47152693Sralph register int c, cc;
47252693Sralph register struct tty *tp0;
47352693Sralph int overrun = 0;
47452693Sralph
47556819Sralph dcaddr = (dcregs *)dcpdma[unit].p_addr;
47652693Sralph tp0 = &dc_tty[unit];
47752693Sralph while ((c = dcaddr->dc_rbuf) < 0) { /* char present */
47852693Sralph cc = c & 0xff;
47952693Sralph tp = tp0 + ((c >> 8) & 03);
48052693Sralph if ((c & RBUF_OERR) && overrun == 0) {
48152693Sralph log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2,
48252693Sralph (c >> 8) & 03);
48352693Sralph overrun = 1;
48452693Sralph }
48552693Sralph /* the keyboard requires special translation */
48656819Sralph if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
48752693Sralph #ifdef KADB
48852693Sralph if (cc == LK_DO) {
48952693Sralph spl0();
49052693Sralph kdbpanic();
49152693Sralph return;
49252693Sralph }
49352693Sralph #endif
49452693Sralph #ifdef DEBUG
49552693Sralph debugChar = cc;
49652693Sralph #endif
49752693Sralph if (dcDivertXInput) {
49852863Sralph (*dcDivertXInput)(cc);
49952693Sralph return;
50052693Sralph }
50156819Sralph if ((cc = kbdMapChar(cc)) < 0)
50252693Sralph return;
50356819Sralph } else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) {
50452863Sralph register MouseReport *mrp;
50552693Sralph static MouseReport currentRep;
50652693Sralph
50752863Sralph mrp = ¤tRep;
50852863Sralph mrp->byteCount++;
50952693Sralph if (cc & MOUSE_START_FRAME) {
51052693Sralph /*
51152693Sralph * The first mouse report byte (button state).
51252693Sralph */
51352863Sralph mrp->state = cc;
51452863Sralph if (mrp->byteCount > 1)
51552863Sralph mrp->byteCount = 1;
51652863Sralph } else if (mrp->byteCount == 2) {
51752693Sralph /*
51852693Sralph * The second mouse report byte (delta x).
51952693Sralph */
52052863Sralph mrp->dx = cc;
52152863Sralph } else if (mrp->byteCount == 3) {
52252693Sralph /*
52352693Sralph * The final mouse report byte (delta y).
52452693Sralph */
52552863Sralph mrp->dy = cc;
52652863Sralph mrp->byteCount = 0;
52752863Sralph if (mrp->dx != 0 || mrp->dy != 0) {
52852693Sralph /*
52952693Sralph * If the mouse moved,
53052693Sralph * post a motion event.
53152693Sralph */
53252863Sralph (*dcMouseEvent)(mrp);
53352693Sralph }
53452863Sralph (*dcMouseButtons)(mrp);
53552693Sralph }
53652693Sralph return;
53752693Sralph }
53852693Sralph if (!(tp->t_state & TS_ISOPEN)) {
53952693Sralph wakeup((caddr_t)&tp->t_rawq);
54052693Sralph #ifdef PORTSELECTOR
54152693Sralph if (!(tp->t_state & TS_WOPEN))
54252693Sralph #endif
54352693Sralph return;
54452693Sralph }
54552693Sralph if (c & RBUF_FERR)
54652693Sralph cc |= TTY_FE;
54752693Sralph if (c & RBUF_PERR)
54852693Sralph cc |= TTY_PE;
54967477Smckusick if ((tp->t_cflag & CRTS_IFLOW) && !(tp->t_state & TS_TBLOCK) &&
55067477Smckusick tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
55167477Smckusick tp->t_state &= ~TS_TBLOCK;
55267477Smckusick (void) dcmctl(tp->t_dev, DML_RTS, DMBIC);
55367477Smckusick }
55452693Sralph (*linesw[tp->t_line].l_rint)(cc, tp);
55552693Sralph }
55652693Sralph DELAY(10);
55752693Sralph }
55852693Sralph
55952755Sralph void
dcxint(tp)56052130Smckusick dcxint(tp)
56152130Smckusick register struct tty *tp;
56252130Smckusick {
56352130Smckusick register struct pdma *dp;
56452130Smckusick register dcregs *dcaddr;
56567477Smckusick int unit;
56652130Smckusick
56767477Smckusick dp = &dcpdma[unit = minor(tp->t_dev)];
56852130Smckusick if (dp->p_mem < dp->p_end) {
56956819Sralph dcaddr = (dcregs *)dp->p_addr;
57067477Smckusick /* check for hardware flow control of output */
57167477Smckusick if ((tp->t_cflag & CCTS_OFLOW) && pmax_boardtype != DS_PMAX) {
57267477Smckusick switch (unit) {
57367477Smckusick case DCCOMM_PORT:
57467477Smckusick if (dcaddr->dc_msr & MSR_CTS2)
57567477Smckusick break;
57667477Smckusick goto stop;
57767477Smckusick
57867477Smckusick case DCPRINTER_PORT:
57967477Smckusick if (dcaddr->dc_msr & MSR_CTS3)
58067477Smckusick break;
58167477Smckusick stop:
58267477Smckusick tp->t_state &= ~TS_BUSY;
58367477Smckusick tp->t_state |= TS_TTSTOP;
58467477Smckusick ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
58567477Smckusick dp->p_end = dp->p_mem = tp->t_outq.c_cf;
58667477Smckusick dcaddr->dc_tcr &= ~(1 << unit);
58767477Smckusick MachEmptyWriteBuffer();
58867477Smckusick DELAY(10);
58967477Smckusick return;
59067477Smckusick }
59167477Smckusick }
59267535Smckusick dcaddr->dc_tdr = dc_brk[unit >> 2] | *(u_char *)dp->p_mem;
59367535Smckusick dp->p_mem++;
59452130Smckusick MachEmptyWriteBuffer();
59552130Smckusick DELAY(10);
59652130Smckusick return;
59752130Smckusick }
59852130Smckusick tp->t_state &= ~TS_BUSY;
59952130Smckusick if (tp->t_state & TS_FLUSH)
60052130Smckusick tp->t_state &= ~TS_FLUSH;
60152130Smckusick else {
60267477Smckusick ndflush(&tp->t_outq, dp->p_mem - tp->t_outq.c_cf);
60352130Smckusick dp->p_end = dp->p_mem = tp->t_outq.c_cf;
60452130Smckusick }
60552130Smckusick if (tp->t_line)
60652130Smckusick (*linesw[tp->t_line].l_start)(tp);
60752130Smckusick else
60852130Smckusick dcstart(tp);
60952130Smckusick if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
61058975Sralph dcaddr = (dcregs *)dp->p_addr;
61167477Smckusick dcaddr->dc_tcr &= ~(1 << (unit & 03));
61252130Smckusick MachEmptyWriteBuffer();
61352130Smckusick DELAY(10);
61452130Smckusick }
61552130Smckusick }
61652130Smckusick
61752755Sralph void
dcstart(tp)61852130Smckusick dcstart(tp)
61952130Smckusick register struct tty *tp;
62052130Smckusick {
62152130Smckusick register struct pdma *dp;
62252130Smckusick register dcregs *dcaddr;
62352130Smckusick register int cc;
62467477Smckusick int unit, s;
62552130Smckusick
62667477Smckusick dp = &dcpdma[unit = minor(tp->t_dev)];
62756819Sralph dcaddr = (dcregs *)dp->p_addr;
62852130Smckusick s = spltty();
62952130Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
63052130Smckusick goto out;
63152130Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) {
63252130Smckusick if (tp->t_state & TS_ASLEEP) {
63352130Smckusick tp->t_state &= ~TS_ASLEEP;
63452130Smckusick wakeup((caddr_t)&tp->t_outq);
63552130Smckusick }
63652674Smckusick selwakeup(&tp->t_wsel);
63752130Smckusick }
63852130Smckusick if (tp->t_outq.c_cc == 0)
63952130Smckusick goto out;
64052130Smckusick /* handle console specially */
64156819Sralph if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
64252130Smckusick while (tp->t_outq.c_cc > 0) {
64352130Smckusick cc = getc(&tp->t_outq) & 0x7f;
64452863Sralph cnputc(cc);
64552130Smckusick }
64652130Smckusick /*
64752130Smckusick * After we flush the output queue we may need to wake
64852130Smckusick * up the process that made the output.
64952130Smckusick */
65052130Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) {
65152130Smckusick if (tp->t_state & TS_ASLEEP) {
65252130Smckusick tp->t_state &= ~TS_ASLEEP;
65352130Smckusick wakeup((caddr_t)&tp->t_outq);
65452130Smckusick }
65552674Smckusick selwakeup(&tp->t_wsel);
65652130Smckusick }
65752130Smckusick goto out;
65852130Smckusick }
65967477Smckusick cc = ndqb(&tp->t_outq, 0);
66052130Smckusick tp->t_state |= TS_BUSY;
66152130Smckusick dp->p_end = dp->p_mem = tp->t_outq.c_cf;
66252130Smckusick dp->p_end += cc;
66367477Smckusick dcaddr->dc_tcr |= 1 << (unit & 03);
66452130Smckusick MachEmptyWriteBuffer();
66552130Smckusick out:
66652130Smckusick splx(s);
66752130Smckusick }
66852130Smckusick
66952130Smckusick /*
67052130Smckusick * Stop output on a line.
67152130Smckusick */
67252130Smckusick /*ARGSUSED*/
dcstop(tp,flag)67352130Smckusick dcstop(tp, flag)
67452130Smckusick register struct tty *tp;
67552130Smckusick {
67652130Smckusick register struct pdma *dp;
67752130Smckusick register int s;
67852130Smckusick
67964978Smckusick dp = &dcpdma[minor(tp->t_dev)];
68052130Smckusick s = spltty();
68152130Smckusick if (tp->t_state & TS_BUSY) {
68252130Smckusick dp->p_end = dp->p_mem;
68352130Smckusick if (!(tp->t_state & TS_TTSTOP))
68452130Smckusick tp->t_state |= TS_FLUSH;
68552130Smckusick }
68652130Smckusick splx(s);
68752130Smckusick }
68852130Smckusick
dcmctl(dev,bits,how)68952130Smckusick dcmctl(dev, bits, how)
69052130Smckusick dev_t dev;
69152130Smckusick int bits, how;
69252130Smckusick {
69352130Smckusick register dcregs *dcaddr;
69452130Smckusick register int unit, mbits;
69552130Smckusick int b, s;
69667477Smckusick register int tcr, msr;
69752130Smckusick
69852130Smckusick unit = minor(dev);
69952130Smckusick b = 1 << (unit & 03);
70056819Sralph dcaddr = (dcregs *)dcpdma[unit].p_addr;
70152130Smckusick s = spltty();
70267477Smckusick /* only channel 2 has modem control on a DECstation 2100/3100 */
70367477Smckusick mbits = DML_DTR | DML_RTS | DML_DSR | DML_CAR;
70452693Sralph switch (unit & 03) {
70552693Sralph case 2:
70652130Smckusick mbits = 0;
70767477Smckusick tcr = dcaddr->dc_tcr;
70867477Smckusick if (tcr & TCR_DTR2)
70952130Smckusick mbits |= DML_DTR;
71067477Smckusick if (pmax_boardtype != DS_PMAX && (tcr & TCR_RTS2))
71167477Smckusick mbits |= DML_RTS;
71252693Sralph msr = dcaddr->dc_msr;
71352693Sralph if (msr & MSR_CD2)
71452693Sralph mbits |= DML_CAR;
71556819Sralph if (msr & MSR_DSR2) {
71656819Sralph if (pmax_boardtype == DS_PMAX)
71756819Sralph mbits |= DML_CAR | DML_DSR;
71856819Sralph else
71956819Sralph mbits |= DML_DSR;
72056819Sralph }
72152693Sralph break;
72252693Sralph
72352693Sralph case 3:
72456819Sralph if (pmax_boardtype != DS_PMAX) {
72556819Sralph mbits = 0;
72667477Smckusick tcr = dcaddr->dc_tcr;
72767477Smckusick if (tcr & TCR_DTR3)
72856819Sralph mbits |= DML_DTR;
72967477Smckusick if (tcr & TCR_RTS3)
73067477Smckusick mbits |= DML_RTS;
73156819Sralph msr = dcaddr->dc_msr;
73256819Sralph if (msr & MSR_CD3)
73356819Sralph mbits |= DML_CAR;
73456819Sralph if (msr & MSR_DSR3)
73556819Sralph mbits |= DML_DSR;
73656819Sralph }
73752693Sralph }
73852130Smckusick switch (how) {
73952130Smckusick case DMSET:
74052130Smckusick mbits = bits;
74152130Smckusick break;
74252130Smckusick
74352130Smckusick case DMBIS:
74452130Smckusick mbits |= bits;
74552130Smckusick break;
74652130Smckusick
74752130Smckusick case DMBIC:
74852130Smckusick mbits &= ~bits;
74952130Smckusick break;
75052130Smckusick
75152130Smckusick case DMGET:
75252130Smckusick (void) splx(s);
75352130Smckusick return (mbits);
75452130Smckusick }
75552693Sralph switch (unit & 03) {
75652693Sralph case 2:
75767477Smckusick tcr = dcaddr->dc_tcr;
75852130Smckusick if (mbits & DML_DTR)
75967477Smckusick tcr |= TCR_DTR2;
76052130Smckusick else
76167477Smckusick tcr &= ~TCR_DTR2;
76267477Smckusick if (pmax_boardtype != DS_PMAX) {
76367477Smckusick if (mbits & DML_RTS)
76467477Smckusick tcr |= TCR_RTS2;
76567477Smckusick else
76667477Smckusick tcr &= ~TCR_RTS2;
76767477Smckusick }
76867477Smckusick dcaddr->dc_tcr = tcr;
76952693Sralph break;
77052693Sralph
77152693Sralph case 3:
77256819Sralph if (pmax_boardtype != DS_PMAX) {
77367477Smckusick tcr = dcaddr->dc_tcr;
77456819Sralph if (mbits & DML_DTR)
77567477Smckusick tcr |= TCR_DTR3;
77656819Sralph else
77767477Smckusick tcr &= ~TCR_DTR3;
77867477Smckusick if (mbits & DML_RTS)
77967477Smckusick tcr |= TCR_RTS3;
78067477Smckusick else
78167477Smckusick tcr &= ~TCR_RTS3;
78267477Smckusick dcaddr->dc_tcr = tcr;
78356819Sralph }
78452130Smckusick }
78552130Smckusick (void) splx(s);
78652130Smckusick return (mbits);
78752130Smckusick }
78852130Smckusick
78952130Smckusick /*
79052130Smckusick * This is called by timeout() periodically.
79152130Smckusick * Check to see if modem status bits have changed.
79252130Smckusick */
79356819Sralph void
dcscan(arg)79455744Sralph dcscan(arg)
79555744Sralph void *arg;
79652130Smckusick {
79752130Smckusick register dcregs *dcaddr;
79852130Smckusick register struct tty *tp;
79967477Smckusick register int unit, limit, dtr, dsr;
80052130Smckusick int s;
80152130Smckusick
80267477Smckusick /* only channel 2 has modem control on a DECstation 2100/3100 */
80367477Smckusick dtr = TCR_DTR2;
80467477Smckusick dsr = MSR_DSR2;
80567477Smckusick limit = (pmax_boardtype == DS_PMAX) ? 2 : 3;
80652130Smckusick s = spltty();
80767477Smckusick for (unit = 2; unit <= limit; unit++, dtr >>= 2, dsr >>= 8) {
80867477Smckusick tp = &dc_tty[unit];
80967477Smckusick dcaddr = (dcregs *)dcpdma[unit].p_addr;
810*69799Sralph if ((dcaddr->dc_msr & dsr) || (dcsoftCAR[0] & (1 << unit))) {
81167477Smckusick /* carrier present */
81267477Smckusick if (!(tp->t_state & TS_CARR_ON))
81367477Smckusick (void)(*linesw[tp->t_line].l_modem)(tp, 1);
81467477Smckusick } else if ((tp->t_state & TS_CARR_ON) &&
81567477Smckusick (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
81667477Smckusick dcaddr->dc_tcr &= ~dtr;
81767477Smckusick /*
81867477Smckusick * If we are using hardware flow control and output is stopped,
81967477Smckusick * then resume transmit.
82067477Smckusick */
82167477Smckusick if ((tp->t_cflag & CCTS_OFLOW) && (tp->t_state & TS_TTSTOP) &&
82267477Smckusick pmax_boardtype != DS_PMAX) {
82367477Smckusick switch (unit) {
82467477Smckusick case DCCOMM_PORT:
82567477Smckusick if (dcaddr->dc_msr & MSR_CTS2)
82667477Smckusick break;
82767477Smckusick continue;
82867477Smckusick
82967477Smckusick case DCPRINTER_PORT:
83067477Smckusick if (dcaddr->dc_msr & MSR_CTS3)
83167477Smckusick break;
83267477Smckusick continue;
83367477Smckusick }
83467477Smckusick tp->t_state &= ~TS_TTSTOP;
83567477Smckusick dcstart(tp);
83667477Smckusick }
83767477Smckusick }
83852130Smckusick splx(s);
83955744Sralph timeout(dcscan, (void *)0, hz);
84052130Smckusick }
84152130Smckusick
84252130Smckusick /*
84352130Smckusick * ----------------------------------------------------------------------------
84452130Smckusick *
84556819Sralph * dcGetc --
84652130Smckusick *
84756819Sralph * Read a character from a serial line.
84852130Smckusick *
84952130Smckusick * Results:
85056819Sralph * A character read from the serial port.
85152130Smckusick *
85252130Smckusick * Side effects:
85352130Smckusick * None.
85452130Smckusick *
85552130Smckusick * ----------------------------------------------------------------------------
85652130Smckusick */
85752130Smckusick int
dcGetc(dev)85856819Sralph dcGetc(dev)
85956819Sralph dev_t dev;
86052130Smckusick {
86152130Smckusick register dcregs *dcaddr;
86252130Smckusick register int c;
86354146Sralph int s;
86452130Smckusick
86556819Sralph dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
86652130Smckusick if (!dcaddr)
86752130Smckusick return (0);
86854146Sralph s = spltty();
86952693Sralph for (;;) {
87052693Sralph if (!(dcaddr->dc_csr & CSR_RDONE))
87152693Sralph continue;
87252693Sralph c = dcaddr->dc_rbuf;
87352693Sralph DELAY(10);
87456819Sralph if (((c >> 8) & 03) == (minor(dev) & 03))
87552693Sralph break;
87652693Sralph }
87752693Sralph splx(s);
87856819Sralph return (c & 0xff);
87952693Sralph }
88052693Sralph
88152693Sralph /*
88256819Sralph * Send a char on a port, non interrupt driven.
88352693Sralph */
88452130Smckusick void
dcPutc(dev,c)88556819Sralph dcPutc(dev, c)
88656819Sralph dev_t dev;
88752130Smckusick int c;
88852130Smckusick {
88952130Smckusick register dcregs *dcaddr;
89052130Smckusick register u_short tcr;
89152130Smckusick register int timeout;
89256819Sralph int s, line;
89352130Smckusick
89456819Sralph s = spltty();
89556819Sralph
89656819Sralph dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
89752130Smckusick tcr = dcaddr->dc_tcr;
89856819Sralph dcaddr->dc_tcr = tcr | (1 << minor(dev));
89952130Smckusick MachEmptyWriteBuffer();
90052130Smckusick DELAY(10);
90152130Smckusick while (1) {
90252130Smckusick /*
90352130Smckusick * Wait for transmitter to be not busy.
90452130Smckusick */
90552130Smckusick timeout = 1000000;
90652130Smckusick while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
90752130Smckusick timeout--;
90852130Smckusick if (timeout == 0) {
90956819Sralph printf("dcPutc: timeout waiting for CSR_TRDY\n");
91052130Smckusick break;
91152130Smckusick }
91252130Smckusick line = (dcaddr->dc_csr >> 8) & 3;
91352130Smckusick /*
91452130Smckusick * Check to be sure its the right port.
91552130Smckusick */
91656819Sralph if (line != minor(dev)) {
91752130Smckusick tcr |= 1 << line;
91852130Smckusick dcaddr->dc_tcr &= ~(1 << line);
91952130Smckusick MachEmptyWriteBuffer();
92052130Smckusick DELAY(10);
92152130Smckusick continue;
92252130Smckusick }
92352130Smckusick /*
92452130Smckusick * Start sending the character.
92552130Smckusick */
92652130Smckusick dcaddr->dc_tdr = dc_brk[0] | (c & 0xff);
92752130Smckusick MachEmptyWriteBuffer();
92852130Smckusick DELAY(10);
92952130Smckusick /*
93052130Smckusick * Wait for character to be sent.
93152130Smckusick */
93252130Smckusick while (1) {
93352130Smckusick /*
93452130Smckusick * cc -O bug: this code produces and infinite loop!
93552130Smckusick * while (!(dcaddr->dc_csr & CSR_TRDY))
93652130Smckusick * ;
93752130Smckusick */
93852130Smckusick timeout = 1000000;
93952130Smckusick while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
94052130Smckusick timeout--;
94152130Smckusick line = (dcaddr->dc_csr >> 8) & 3;
94256819Sralph if (line != minor(dev)) {
94352130Smckusick tcr |= 1 << line;
94452130Smckusick dcaddr->dc_tcr &= ~(1 << line);
94552130Smckusick MachEmptyWriteBuffer();
94652130Smckusick DELAY(10);
94752130Smckusick continue;
94852130Smckusick }
94956819Sralph dcaddr->dc_tcr &= ~(1 << minor(dev));
95052130Smckusick MachEmptyWriteBuffer();
95152130Smckusick DELAY(10);
95252130Smckusick break;
95352130Smckusick }
95452130Smckusick break;
95552130Smckusick }
95652130Smckusick /*
95752130Smckusick * Enable interrupts for other lines which became ready.
95852130Smckusick */
95952130Smckusick if (tcr & 0xF) {
96052130Smckusick dcaddr->dc_tcr = tcr;
96152130Smckusick MachEmptyWriteBuffer();
96252130Smckusick DELAY(10);
96352130Smckusick }
96452130Smckusick
96556819Sralph splx(s);
96652130Smckusick }
96752130Smckusick #endif /* NDC */
968