xref: /csrg-svn/sys/sparc/dev/cons.c (revision 55104)
1*55104Storek /*
2*55104Storek  * Copyright (c) 1992 The Regents of the University of California.
3*55104Storek  * All rights reserved.
4*55104Storek  *
5*55104Storek  * This software was developed by the Computer Systems Engineering group
6*55104Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7*55104Storek  * contributed to Berkeley.
8*55104Storek  *
9*55104Storek  * %sccs.include.redist.c%
10*55104Storek  *
11*55104Storek  *	@(#)cons.c	7.1 (Berkeley) 07/13/92
12*55104Storek  *
13*55104Storek  * from: $Header: cons.c,v 1.10 92/07/10 00:02:42 torek Exp $
14*55104Storek  */
15*55104Storek 
16*55104Storek /*
17*55104Storek  * Console (indirect) driver.
18*55104Storek  */
19*55104Storek 
20*55104Storek #include "sys/param.h"
21*55104Storek #include "sys/proc.h"
22*55104Storek #include "sys/systm.h"
23*55104Storek #include "sys/ioctl.h"
24*55104Storek #include "sys/tty.h"
25*55104Storek #include "sys/file.h"
26*55104Storek #include "sys/conf.h"
27*55104Storek 
28*55104Storek #include "machine/bsd_openprom.h"
29*55104Storek #include "machine/psl.h"
30*55104Storek 
31*55104Storek #include "zs.h"
32*55104Storek 
33*55104Storek struct	tty *constty = 0;	/* virtual console output device */
34*55104Storek struct	tty *fbconstty = 0;	/* tty structure for frame buffer console */
35*55104Storek int	rom_console_input;	/* when set, hardclock calls cnrom() */
36*55104Storek 
37*55104Storek int	cons_ocount;		/* output byte count */
38*55104Storek 
39*55104Storek extern struct promvec *promvec;
40*55104Storek 
41*55104Storek /*
42*55104Storek  * The output driver may munge the minor number in cons.t_dev.
43*55104Storek  */
44*55104Storek struct tty cons;		/* rom console tty device */
45*55104Storek static void cnstart __P((struct tty *));
46*55104Storek static void cnfbstart __P((struct tty *));
47*55104Storek static void cnfbstop __P((struct tty *, int));
48*55104Storek static void cnfbdma __P((void *));
49*55104Storek 
50*55104Storek extern char partab[];
51*55104Storek 
52*55104Storek consinit()
53*55104Storek {
54*55104Storek 	register struct tty *tp = &cons;
55*55104Storek 	register int in, out;
56*55104Storek 	void zsconsole(), bwtwoconsole();
57*55104Storek 
58*55104Storek 	tp->t_dev = makedev(0, 0);	/* /dev/console */
59*55104Storek 	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
60*55104Storek 	tp->t_param = (int (*)(struct tty *, struct termios *))nullop;
61*55104Storek 	in = *promvec->pv_stdin;
62*55104Storek 	out = *promvec->pv_stdout;
63*55104Storek 	switch (in) {
64*55104Storek 
65*55104Storek #if NZS > 0
66*55104Storek 	case PROMDEV_TTYA:
67*55104Storek 		zsconsole(tp, 0, 0);
68*55104Storek 		break;
69*55104Storek 
70*55104Storek 	case PROMDEV_TTYB:
71*55104Storek 		zsconsole(tp, 1, 0);
72*55104Storek 		break;
73*55104Storek #endif
74*55104Storek 
75*55104Storek 	case PROMDEV_KBD:
76*55104Storek 		/*
77*55104Storek 		 * Tell the keyboard driver to direct ASCII input here.
78*55104Storek 		 */
79*55104Storek 		kbd_ascii(tp);
80*55104Storek 		break;
81*55104Storek 
82*55104Storek 	default:
83*55104Storek 		rom_console_input = 1;
84*55104Storek 		printf("unknown console input source %d; using rom\n", in);
85*55104Storek 		break;
86*55104Storek 	}
87*55104Storek 	switch (out) {
88*55104Storek 
89*55104Storek #if NZS > 0
90*55104Storek 	case PROMDEV_TTYA:
91*55104Storek 		zsconsole(tp, 0, 1);
92*55104Storek 		break;
93*55104Storek 
94*55104Storek 	case PROMDEV_TTYB:
95*55104Storek 		zsconsole(tp, 1, 1);
96*55104Storek 		break;
97*55104Storek #endif
98*55104Storek 
99*55104Storek 	case PROMDEV_SCREEN:
100*55104Storek 		fbconstty = tp;
101*55104Storek 		tp->t_oproc = cnfbstart;
102*55104Storek 		tp->t_stop = cnfbstop;
103*55104Storek 		break;
104*55104Storek 
105*55104Storek 	default:
106*55104Storek 		printf("unknown console output sink %d; using rom\n", out);
107*55104Storek 		tp->t_oproc = cnstart;
108*55104Storek 		tp->t_stop = (void (*)(struct tty *, int))nullop;
109*55104Storek 		break;
110*55104Storek 	}
111*55104Storek }
112*55104Storek 
113*55104Storek /* ARGSUSED */
114*55104Storek cnopen(dev, flag, mode, p)
115*55104Storek 	dev_t dev;
116*55104Storek 	int flag, mode;
117*55104Storek 	struct proc *p;
118*55104Storek {
119*55104Storek 	register struct tty *tp = &cons;
120*55104Storek 
121*55104Storek 	if ((tp->t_state & TS_ISOPEN) == 0) {
122*55104Storek 		/*
123*55104Storek 		 * Leave baud rate alone!
124*55104Storek 		 */
125*55104Storek 		ttychars(tp);
126*55104Storek 		tp->t_iflag = TTYDEF_IFLAG;
127*55104Storek 		tp->t_oflag = TTYDEF_OFLAG;
128*55104Storek 		tp->t_lflag = TTYDEF_LFLAG;
129*55104Storek 		tp->t_cflag = TTYDEF_CFLAG;
130*55104Storek 		tp->t_state = TS_ISOPEN | TS_CARR_ON;
131*55104Storek 		ttsetwater(tp);
132*55104Storek 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
133*55104Storek 		return (EBUSY);
134*55104Storek 	return ((*linesw[tp->t_line].l_open)(dev, tp));
135*55104Storek }
136*55104Storek 
137*55104Storek /* ARGSUSED */
138*55104Storek cnclose(dev, flag, mode, p)
139*55104Storek 	dev_t dev;
140*55104Storek 	int flag, mode;
141*55104Storek 	struct proc *p;
142*55104Storek {
143*55104Storek 	register struct tty *tp = &cons;
144*55104Storek 
145*55104Storek 	(*linesw[tp->t_line].l_close)(tp, flag);
146*55104Storek 	ttyclose(tp);
147*55104Storek 	return (0);
148*55104Storek }
149*55104Storek 
150*55104Storek /* ARGSUSED */
151*55104Storek cnread(dev, uio, flag)
152*55104Storek 	dev_t dev;
153*55104Storek 	struct uio *uio;
154*55104Storek 	int flag;
155*55104Storek {
156*55104Storek 	register struct tty *tp = &cons;
157*55104Storek 
158*55104Storek 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
159*55104Storek }
160*55104Storek 
161*55104Storek /* ARGSUSED */
162*55104Storek cnwrite(dev, uio, flag)
163*55104Storek 	dev_t dev;
164*55104Storek 	struct uio *uio;
165*55104Storek 	int flag;
166*55104Storek {
167*55104Storek 	register struct tty *tp;
168*55104Storek 
169*55104Storek 	if ((tp = constty) == NULL ||
170*55104Storek 	    (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
171*55104Storek 		tp = &cons;
172*55104Storek 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
173*55104Storek }
174*55104Storek 
175*55104Storek cnioctl(dev, cmd, data, flag, p)
176*55104Storek 	dev_t dev;
177*55104Storek 	int cmd;
178*55104Storek 	caddr_t data;
179*55104Storek 	int flag;
180*55104Storek 	struct proc *p;
181*55104Storek {
182*55104Storek 	register struct tty *tp;
183*55104Storek 	int error;
184*55104Storek 
185*55104Storek 	/*
186*55104Storek 	 * Superuser can always use this to wrest control of console
187*55104Storek 	 * output from the "virtual" console.
188*55104Storek 	 */
189*55104Storek 	if (cmd == TIOCCONS && constty) {
190*55104Storek 		error = suser(p->p_ucred, (u_short *)NULL);
191*55104Storek 		if (error)
192*55104Storek 			return (error);
193*55104Storek 		constty = NULL;
194*55104Storek 		return (0);
195*55104Storek 	}
196*55104Storek 	tp = &cons;
197*55104Storek 	if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0)
198*55104Storek 		return (error);
199*55104Storek 	if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
200*55104Storek 		return (error);
201*55104Storek 	return (ENOTTY);
202*55104Storek }
203*55104Storek 
204*55104Storek cnselect(dev, which, p)
205*55104Storek 	dev_t dev;
206*55104Storek 	int which;
207*55104Storek 	struct proc *p;
208*55104Storek {
209*55104Storek 
210*55104Storek 	return (ttselect(makedev(major(dev), 0), which, p));
211*55104Storek }
212*55104Storek 
213*55104Storek /*
214*55104Storek  * The rest of this code is run only when we are using the ROM vectors.
215*55104Storek  */
216*55104Storek 
217*55104Storek /*
218*55104Storek  * Generic output.  We just call putchar.  (Very bad for performance.)
219*55104Storek  */
220*55104Storek static void
221*55104Storek cnstart(tp)
222*55104Storek 	register struct tty *tp;
223*55104Storek {
224*55104Storek 	register int c, s;
225*55104Storek 	register void (*putc)(int);
226*55104Storek 
227*55104Storek 	s = spltty();
228*55104Storek 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
229*55104Storek 		splx(s);
230*55104Storek 		return;
231*55104Storek 	}
232*55104Storek 	putc = promvec->pv_putchar;
233*55104Storek 	while (tp->t_outq.c_cc) {
234*55104Storek 		c = getc(&tp->t_outq);
235*55104Storek 		/*
236*55104Storek 		 * *%&!*& ROM monitor console putchar is not reentrant!
237*55104Storek 		 * splhigh/tty around it so as not to run so long with
238*55104Storek 		 * clock interrupts blocked.
239*55104Storek 		 */
240*55104Storek 		(void) splhigh();
241*55104Storek 		(*putc)(c & 0177);
242*55104Storek 		(void) spltty();
243*55104Storek 	}
244*55104Storek 	if (tp->t_state & TS_ASLEEP) {		/* can't happen? */
245*55104Storek 		tp->t_state &= ~TS_ASLEEP;
246*55104Storek 		wakeup((caddr_t)&tp->t_outq);
247*55104Storek 	}
248*55104Storek 	selwakeup(&tp->t_wsel);
249*55104Storek 	splx(s);
250*55104Storek }
251*55104Storek 
252*55104Storek /*
253*55104Storek  * Frame buffer output.
254*55104Storek  * We use pseudo-DMA, via the ROM `write string' function, called from
255*55104Storek  * software clock interrupts.
256*55104Storek  */
257*55104Storek static void
258*55104Storek cnfbstart(tp)
259*55104Storek 	register struct tty *tp;
260*55104Storek {
261*55104Storek 	register int s;
262*55104Storek 
263*55104Storek 	s = spltty();		/* paranoid: splsoftclock should suffice */
264*55104Storek 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
265*55104Storek 		splx(s);
266*55104Storek 		return;
267*55104Storek 	}
268*55104Storek 	/*
269*55104Storek 	 * If there are sleepers, and output has drained below low
270*55104Storek 	 * water mark, awaken.
271*55104Storek 	 */
272*55104Storek 	if (tp->t_outq.c_cc <= tp->t_lowat) {
273*55104Storek 		if (tp->t_state & TS_ASLEEP) {
274*55104Storek 			tp->t_state &= ~TS_ASLEEP;
275*55104Storek 			wakeup((caddr_t)&tp->t_outq);
276*55104Storek 		}
277*55104Storek 		selwakeup(&tp->t_wsel);
278*55104Storek 	}
279*55104Storek 	if (tp->t_outq.c_cc) {
280*55104Storek 		tp->t_state |= TS_BUSY;
281*55104Storek 		if (s == 0) {
282*55104Storek 			(void) splsoftclock();
283*55104Storek 			cnfbdma((void *)tp);
284*55104Storek 		} else
285*55104Storek 			timeout(cnfbdma, tp, 1);
286*55104Storek 	}
287*55104Storek 	splx(s);
288*55104Storek }
289*55104Storek 
290*55104Storek /*
291*55104Storek  * Stop frame buffer output: just assert TS_FLUSH if necessary.
292*55104Storek  */
293*55104Storek static void
294*55104Storek cnfbstop(tp, flag)
295*55104Storek 	register struct tty *tp;
296*55104Storek 	int flag;
297*55104Storek {
298*55104Storek 	register int s = spltty();	/* paranoid */
299*55104Storek 
300*55104Storek 	if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
301*55104Storek 		tp->t_state |= TS_FLUSH;
302*55104Storek 	splx(s);
303*55104Storek }
304*55104Storek 
305*55104Storek /*
306*55104Storek  * Do pseudo-dma (called from software interrupt).
307*55104Storek  */
308*55104Storek static void
309*55104Storek cnfbdma(tpaddr)
310*55104Storek 	void *tpaddr;
311*55104Storek {
312*55104Storek 	register struct tty *tp = tpaddr;
313*55104Storek 	register char *p, *q;
314*55104Storek 	register int n, c, s;
315*55104Storek 
316*55104Storek 	s = spltty();			/* paranoid */
317*55104Storek 	if (tp->t_state & TS_FLUSH) {
318*55104Storek 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
319*55104Storek 		splx(s);
320*55104Storek 	} else {
321*55104Storek 		tp->t_state &= ~TS_BUSY;
322*55104Storek 		splx(s);
323*55104Storek 		p = tp->t_outq.c_cf;
324*55104Storek 		n = ndqb(&tp->t_outq, 0);
325*55104Storek 		for (q = p, c = n; --c >= 0; q++)
326*55104Storek 			if (*q & 0200)	/* high bits seem to be bad */
327*55104Storek 				*q &= ~0200;
328*55104Storek 		(*promvec->pv_putstr)(p, n);
329*55104Storek 		ndflush(&tp->t_outq, n);
330*55104Storek 	}
331*55104Storek 	if (tp->t_line)
332*55104Storek 		(*linesw[tp->t_line].l_start)(tp);
333*55104Storek 	else
334*55104Storek 		cnfbstart(tp);
335*55104Storek }
336*55104Storek 
337*55104Storek /*
338*55104Storek  * The following is for rom console input.  The rom will not call
339*55104Storek  * an `interrupt' routine on console input ready, so we must poll.
340*55104Storek  * This is all rather sad.
341*55104Storek  */
342*55104Storek volatile int	cn_rxc;			/* XXX receive `silo' */
343*55104Storek 
344*55104Storek /* called from hardclock, which is above spltty, so no tty calls! */
345*55104Storek cnrom()
346*55104Storek {
347*55104Storek 	register int c;
348*55104Storek 
349*55104Storek 	if (cn_rxc >= 0)
350*55104Storek 		return (1);
351*55104Storek 	if ((c = (*promvec->pv_nbgetchar)()) < 0)
352*55104Storek 		return (0);
353*55104Storek 	cn_rxc = c;
354*55104Storek 	return (1);
355*55104Storek }
356*55104Storek 
357*55104Storek /* pseudo console software interrupt scheduled when cnrom() returns 1 */
358*55104Storek cnrint()
359*55104Storek {
360*55104Storek 	register struct tty *tp;
361*55104Storek 	register int c, s;
362*55104Storek 
363*55104Storek 	s = splclock();
364*55104Storek 	c = cn_rxc;
365*55104Storek 	cn_rxc = -1;
366*55104Storek 	splx(s);
367*55104Storek 	if (c < 0)
368*55104Storek 		return;
369*55104Storek 	tp = &cons;
370*55104Storek 	if ((tp->t_cflag & CSIZE) == CS7) {
371*55104Storek 		/* XXX this should be done elsewhere, if at all */
372*55104Storek 		if (tp->t_cflag & PARENB)
373*55104Storek 			if (tp->t_cflag & PARODD ?
374*55104Storek 			    (partab[c & 0177] & 0200) == (c & 0200) :
375*55104Storek 			    (partab[c & 0177] & 0200) != (c & 0200))
376*55104Storek 				c |= TTY_PE;
377*55104Storek 		c &= ~0200;
378*55104Storek 	}
379*55104Storek 	(*linesw[tp->t_line].l_rint)(c, tp);
380*55104Storek }
381*55104Storek 
382*55104Storek cngetc()
383*55104Storek {
384*55104Storek 	register int s, c;
385*55104Storek 
386*55104Storek 	s = splhigh();
387*55104Storek 	c = (*promvec->pv_getchar)();
388*55104Storek 	splx(s);
389*55104Storek 	if (c == '\r')
390*55104Storek 		c = '\n';
391*55104Storek 	return (c);
392*55104Storek }
393*55104Storek 
394*55104Storek cnputc(c)
395*55104Storek 	register int c;
396*55104Storek {
397*55104Storek 	register int s = splhigh();
398*55104Storek 
399*55104Storek 	if (c == '\n')
400*55104Storek 		(*promvec->pv_putchar)('\r');
401*55104Storek 	(*promvec->pv_putchar)(c);
402*55104Storek 	splx(s);
403*55104Storek }
404