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