xref: /csrg-svn/sys/sparc/dev/cons.c (revision 65143)
155104Storek /*
263927Sbostic  * Copyright (c) 1992, 1993
363927Sbostic  *	The Regents of the University of California.  All rights reserved.
455104Storek  *
555104Storek  * This software was developed by the Computer Systems Engineering group
655104Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755104Storek  * contributed to Berkeley.
855104Storek  *
955499Sbostic  * All advertising materials mentioning features or use of this software
1055499Sbostic  * must display the following acknowledgement:
1155499Sbostic  *	This product includes software developed by the University of
1259185Storek  *	California, Lawrence Berkeley Laboratory.
1355499Sbostic  *
1455104Storek  * %sccs.include.redist.c%
1555104Storek  *
16*65143Storek  *	@(#)cons.c	8.3 (Berkeley) 12/14/93
1755104Storek  *
1863921Storek  * from: $Header: cons.c,v 1.12 93/07/20 00:49:45 torek Exp $
1955104Storek  */
2055104Storek 
2155104Storek /*
2255104Storek  * Console (indirect) driver.
2355104Storek  */
2455104Storek 
2556536Sbostic #include <sys/param.h>
2656536Sbostic #include <sys/proc.h>
2756536Sbostic #include <sys/systm.h>
2856536Sbostic #include <sys/ioctl.h>
2956536Sbostic #include <sys/tty.h>
3056536Sbostic #include <sys/file.h>
3156536Sbostic #include <sys/conf.h>
3255104Storek 
3356536Sbostic #include <machine/bsd_openprom.h>
3456536Sbostic #include <machine/psl.h>
3555104Storek 
3655104Storek #include "zs.h"
3755104Storek 
3855104Storek struct	tty *constty = 0;	/* virtual console output device */
3955104Storek struct	tty *fbconstty = 0;	/* tty structure for frame buffer console */
4055104Storek int	rom_console_input;	/* when set, hardclock calls cnrom() */
4155104Storek 
4255104Storek int	cons_ocount;		/* output byte count */
4355104Storek 
4455104Storek extern struct promvec *promvec;
4555104Storek 
4655104Storek /*
4755104Storek  * The output driver may munge the minor number in cons.t_dev.
4855104Storek  */
4955104Storek struct tty cons;		/* rom console tty device */
5055104Storek static void cnstart __P((struct tty *));
5155104Storek static void cnfbstart __P((struct tty *));
5255104Storek static void cnfbstop __P((struct tty *, int));
5355104Storek static void cnfbdma __P((void *));
5455104Storek 
55*65143Storek extern const char char_type[];
5655104Storek 
consinit()5755104Storek consinit()
5855104Storek {
5955104Storek 	register struct tty *tp = &cons;
6055104Storek 	register int in, out;
6155104Storek 	void zsconsole(), bwtwoconsole();
6255104Storek 
6355104Storek 	tp->t_dev = makedev(0, 0);	/* /dev/console */
6455104Storek 	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
6555104Storek 	tp->t_param = (int (*)(struct tty *, struct termios *))nullop;
6655104Storek 	in = *promvec->pv_stdin;
6755104Storek 	out = *promvec->pv_stdout;
6855104Storek 	switch (in) {
6955104Storek 
7055104Storek #if NZS > 0
7155104Storek 	case PROMDEV_TTYA:
7255104Storek 		zsconsole(tp, 0, 0);
7355104Storek 		break;
7455104Storek 
7555104Storek 	case PROMDEV_TTYB:
7655104Storek 		zsconsole(tp, 1, 0);
7755104Storek 		break;
7855104Storek #endif
7955104Storek 
8055104Storek 	case PROMDEV_KBD:
8155104Storek 		/*
8255104Storek 		 * Tell the keyboard driver to direct ASCII input here.
8355104Storek 		 */
8455104Storek 		kbd_ascii(tp);
8555104Storek 		break;
8655104Storek 
8755104Storek 	default:
8855104Storek 		rom_console_input = 1;
8955104Storek 		printf("unknown console input source %d; using rom\n", in);
9055104Storek 		break;
9155104Storek 	}
9255104Storek 	switch (out) {
9355104Storek 
9455104Storek #if NZS > 0
9555104Storek 	case PROMDEV_TTYA:
9655104Storek 		zsconsole(tp, 0, 1);
9755104Storek 		break;
9855104Storek 
9955104Storek 	case PROMDEV_TTYB:
10055104Storek 		zsconsole(tp, 1, 1);
10155104Storek 		break;
10255104Storek #endif
10355104Storek 
10455104Storek 	case PROMDEV_SCREEN:
10555104Storek 		fbconstty = tp;
10655104Storek 		tp->t_oproc = cnfbstart;
10755104Storek 		tp->t_stop = cnfbstop;
10855104Storek 		break;
10955104Storek 
11055104Storek 	default:
11155104Storek 		printf("unknown console output sink %d; using rom\n", out);
11255104Storek 		tp->t_oproc = cnstart;
11355104Storek 		tp->t_stop = (void (*)(struct tty *, int))nullop;
11455104Storek 		break;
11555104Storek 	}
11655104Storek }
11755104Storek 
11855104Storek /* ARGSUSED */
cnopen(dev,flag,mode,p)11955104Storek cnopen(dev, flag, mode, p)
12055104Storek 	dev_t dev;
12155104Storek 	int flag, mode;
12255104Storek 	struct proc *p;
12355104Storek {
12455104Storek 	register struct tty *tp = &cons;
12555104Storek 
12655104Storek 	if ((tp->t_state & TS_ISOPEN) == 0) {
12755104Storek 		/*
12855104Storek 		 * Leave baud rate alone!
12955104Storek 		 */
13055104Storek 		ttychars(tp);
13155104Storek 		tp->t_iflag = TTYDEF_IFLAG;
13255104Storek 		tp->t_oflag = TTYDEF_OFLAG;
13355104Storek 		tp->t_lflag = TTYDEF_LFLAG;
13455104Storek 		tp->t_cflag = TTYDEF_CFLAG;
13555104Storek 		tp->t_state = TS_ISOPEN | TS_CARR_ON;
13663921Storek 		(void)(*tp->t_param)(tp, &tp->t_termios);
13755104Storek 		ttsetwater(tp);
13855104Storek 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
13955104Storek 		return (EBUSY);
14055104Storek 	return ((*linesw[tp->t_line].l_open)(dev, tp));
14155104Storek }
14255104Storek 
14355104Storek /* ARGSUSED */
cnclose(dev,flag,mode,p)14455104Storek cnclose(dev, flag, mode, p)
14555104Storek 	dev_t dev;
14655104Storek 	int flag, mode;
14755104Storek 	struct proc *p;
14855104Storek {
14955104Storek 	register struct tty *tp = &cons;
15055104Storek 
15155104Storek 	(*linesw[tp->t_line].l_close)(tp, flag);
15255104Storek 	ttyclose(tp);
15355104Storek 	return (0);
15455104Storek }
15555104Storek 
15655104Storek /* ARGSUSED */
cnread(dev,uio,flag)15755104Storek cnread(dev, uio, flag)
15855104Storek 	dev_t dev;
15955104Storek 	struct uio *uio;
16055104Storek 	int flag;
16155104Storek {
16255104Storek 	register struct tty *tp = &cons;
16355104Storek 
16455104Storek 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
16555104Storek }
16655104Storek 
16755104Storek /* ARGSUSED */
cnwrite(dev,uio,flag)16855104Storek cnwrite(dev, uio, flag)
16955104Storek 	dev_t dev;
17055104Storek 	struct uio *uio;
17155104Storek 	int flag;
17255104Storek {
17355104Storek 	register struct tty *tp;
17455104Storek 
17555104Storek 	if ((tp = constty) == NULL ||
17655104Storek 	    (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
17755104Storek 		tp = &cons;
17855104Storek 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
17955104Storek }
18055104Storek 
cnioctl(dev,cmd,data,flag,p)18155104Storek cnioctl(dev, cmd, data, flag, p)
18255104Storek 	dev_t dev;
18355104Storek 	int cmd;
18455104Storek 	caddr_t data;
18555104Storek 	int flag;
18655104Storek 	struct proc *p;
18755104Storek {
18855104Storek 	register struct tty *tp;
18955104Storek 	int error;
19055104Storek 
19155104Storek 	/*
19255104Storek 	 * Superuser can always use this to wrest control of console
19355104Storek 	 * output from the "virtual" console.
19455104Storek 	 */
19555104Storek 	if (cmd == TIOCCONS && constty) {
19655104Storek 		error = suser(p->p_ucred, (u_short *)NULL);
19755104Storek 		if (error)
19855104Storek 			return (error);
19955104Storek 		constty = NULL;
20055104Storek 		return (0);
20155104Storek 	}
20255104Storek 	tp = &cons;
20355104Storek 	if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0)
20455104Storek 		return (error);
20555104Storek 	if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
20655104Storek 		return (error);
20755104Storek 	return (ENOTTY);
20855104Storek }
20955104Storek 
cnselect(dev,which,p)21055104Storek cnselect(dev, which, p)
21155104Storek 	dev_t dev;
21255104Storek 	int which;
21355104Storek 	struct proc *p;
21455104Storek {
21555104Storek 
21655104Storek 	return (ttselect(makedev(major(dev), 0), which, p));
21755104Storek }
21855104Storek 
21955104Storek /*
22055104Storek  * The rest of this code is run only when we are using the ROM vectors.
22155104Storek  */
22255104Storek 
22355104Storek /*
22455104Storek  * Generic output.  We just call putchar.  (Very bad for performance.)
22555104Storek  */
22655104Storek static void
cnstart(tp)22755104Storek cnstart(tp)
22855104Storek 	register struct tty *tp;
22955104Storek {
23055104Storek 	register int c, s;
23155104Storek 	register void (*putc)(int);
23255104Storek 
23355104Storek 	s = spltty();
23455104Storek 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
23555104Storek 		splx(s);
23655104Storek 		return;
23755104Storek 	}
23855104Storek 	putc = promvec->pv_putchar;
23955104Storek 	while (tp->t_outq.c_cc) {
24055104Storek 		c = getc(&tp->t_outq);
24155104Storek 		/*
24255104Storek 		 * *%&!*& ROM monitor console putchar is not reentrant!
24355104Storek 		 * splhigh/tty around it so as not to run so long with
24455104Storek 		 * clock interrupts blocked.
24555104Storek 		 */
24655104Storek 		(void) splhigh();
24755104Storek 		(*putc)(c & 0177);
24855104Storek 		(void) spltty();
24955104Storek 	}
25055104Storek 	if (tp->t_state & TS_ASLEEP) {		/* can't happen? */
25155104Storek 		tp->t_state &= ~TS_ASLEEP;
25255104Storek 		wakeup((caddr_t)&tp->t_outq);
25355104Storek 	}
25455104Storek 	selwakeup(&tp->t_wsel);
25555104Storek 	splx(s);
25655104Storek }
25755104Storek 
25855104Storek /*
25955104Storek  * Frame buffer output.
26055104Storek  * We use pseudo-DMA, via the ROM `write string' function, called from
26155104Storek  * software clock interrupts.
26255104Storek  */
26355104Storek static void
cnfbstart(tp)26455104Storek cnfbstart(tp)
26555104Storek 	register struct tty *tp;
26655104Storek {
26755104Storek 	register int s;
26855104Storek 
26955104Storek 	s = spltty();		/* paranoid: splsoftclock should suffice */
27055104Storek 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
27155104Storek 		splx(s);
27255104Storek 		return;
27355104Storek 	}
27455104Storek 	/*
27555104Storek 	 * If there are sleepers, and output has drained below low
27655104Storek 	 * water mark, awaken.
27755104Storek 	 */
27855104Storek 	if (tp->t_outq.c_cc <= tp->t_lowat) {
27955104Storek 		if (tp->t_state & TS_ASLEEP) {
28055104Storek 			tp->t_state &= ~TS_ASLEEP;
28155104Storek 			wakeup((caddr_t)&tp->t_outq);
28255104Storek 		}
28355104Storek 		selwakeup(&tp->t_wsel);
28455104Storek 	}
28555104Storek 	if (tp->t_outq.c_cc) {
28655104Storek 		tp->t_state |= TS_BUSY;
28755104Storek 		if (s == 0) {
28855104Storek 			(void) splsoftclock();
28955104Storek 			cnfbdma((void *)tp);
29055104Storek 		} else
29155104Storek 			timeout(cnfbdma, tp, 1);
29255104Storek 	}
29355104Storek 	splx(s);
29455104Storek }
29555104Storek 
29655104Storek /*
29755104Storek  * Stop frame buffer output: just assert TS_FLUSH if necessary.
29855104Storek  */
29955104Storek static void
cnfbstop(tp,flag)30055104Storek cnfbstop(tp, flag)
30155104Storek 	register struct tty *tp;
30255104Storek 	int flag;
30355104Storek {
30455104Storek 	register int s = spltty();	/* paranoid */
30555104Storek 
30655104Storek 	if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
30755104Storek 		tp->t_state |= TS_FLUSH;
30855104Storek 	splx(s);
30955104Storek }
31055104Storek 
31155104Storek /*
31255104Storek  * Do pseudo-dma (called from software interrupt).
31355104Storek  */
31455104Storek static void
cnfbdma(tpaddr)31555104Storek cnfbdma(tpaddr)
31655104Storek 	void *tpaddr;
31755104Storek {
31855104Storek 	register struct tty *tp = tpaddr;
31955104Storek 	register char *p, *q;
32055104Storek 	register int n, c, s;
32155104Storek 
32255104Storek 	s = spltty();			/* paranoid */
32355104Storek 	if (tp->t_state & TS_FLUSH) {
32455104Storek 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
32555104Storek 		splx(s);
32655104Storek 	} else {
32755104Storek 		tp->t_state &= ~TS_BUSY;
32855104Storek 		splx(s);
32955104Storek 		p = tp->t_outq.c_cf;
33055104Storek 		n = ndqb(&tp->t_outq, 0);
33155104Storek 		for (q = p, c = n; --c >= 0; q++)
33255104Storek 			if (*q & 0200)	/* high bits seem to be bad */
33355104Storek 				*q &= ~0200;
33455104Storek 		(*promvec->pv_putstr)(p, n);
33555104Storek 		ndflush(&tp->t_outq, n);
33655104Storek 	}
33755104Storek 	if (tp->t_line)
33855104Storek 		(*linesw[tp->t_line].l_start)(tp);
33955104Storek 	else
34055104Storek 		cnfbstart(tp);
34155104Storek }
34255104Storek 
34355104Storek /*
34455104Storek  * The following is for rom console input.  The rom will not call
34555104Storek  * an `interrupt' routine on console input ready, so we must poll.
34655104Storek  * This is all rather sad.
34755104Storek  */
34855104Storek volatile int	cn_rxc;			/* XXX receive `silo' */
34955104Storek 
35055104Storek /* called from hardclock, which is above spltty, so no tty calls! */
cnrom()35155104Storek cnrom()
35255104Storek {
35355104Storek 	register int c;
35455104Storek 
35555104Storek 	if (cn_rxc >= 0)
35655104Storek 		return (1);
35755104Storek 	if ((c = (*promvec->pv_nbgetchar)()) < 0)
35855104Storek 		return (0);
35955104Storek 	cn_rxc = c;
36055104Storek 	return (1);
36155104Storek }
36255104Storek 
36355104Storek /* pseudo console software interrupt scheduled when cnrom() returns 1 */
cnrint()36455104Storek cnrint()
36555104Storek {
36655104Storek 	register struct tty *tp;
36755104Storek 	register int c, s;
36855104Storek 
36955104Storek 	s = splclock();
37055104Storek 	c = cn_rxc;
37155104Storek 	cn_rxc = -1;
37255104Storek 	splx(s);
37355104Storek 	if (c < 0)
37455104Storek 		return;
37555104Storek 	tp = &cons;
37655104Storek 	if ((tp->t_cflag & CSIZE) == CS7) {
377*65143Storek #if 0
37855104Storek 		/* XXX this should be done elsewhere, if at all */
37955104Storek 		if (tp->t_cflag & PARENB)
38055104Storek 			if (tp->t_cflag & PARODD ?
38165080Smckusick 			    (char_type[c & 0177] & 0200) == (c & 0200) :
38265080Smckusick 			    (char_type[c & 0177] & 0200) != (c & 0200))
38355104Storek 				c |= TTY_PE;
384*65143Storek #endif
38555104Storek 		c &= ~0200;
38655104Storek 	}
38755104Storek 	(*linesw[tp->t_line].l_rint)(c, tp);
38855104Storek }
38955104Storek 
cngetc()39055104Storek cngetc()
39155104Storek {
39255104Storek 	register int s, c;
39355104Storek 
39455104Storek 	s = splhigh();
39555104Storek 	c = (*promvec->pv_getchar)();
39655104Storek 	splx(s);
39755104Storek 	if (c == '\r')
39855104Storek 		c = '\n';
39955104Storek 	return (c);
40055104Storek }
40155104Storek 
cnputc(c)40255104Storek cnputc(c)
40355104Storek 	register int c;
40455104Storek {
40555104Storek 	register int s = splhigh();
40655104Storek 
40755104Storek 	if (c == '\n')
40855104Storek 		(*promvec->pv_putchar)('\r');
40955104Storek 	(*promvec->pv_putchar)(c);
41055104Storek 	splx(s);
41155104Storek }
412