xref: /original-bsd/sys/sparc/dev/cons.c (revision d4dfefc4)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * 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 Laboratories.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)cons.c	7.3 (Berkeley) 10/11/92
17  *
18  * from: $Header: cons.c,v 1.10 92/07/10 00:02:42 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 char partab[];
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 		ttsetwater(tp);
137 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
138 		return (EBUSY);
139 	return ((*linesw[tp->t_line].l_open)(dev, tp));
140 }
141 
142 /* ARGSUSED */
143 cnclose(dev, flag, mode, p)
144 	dev_t dev;
145 	int flag, mode;
146 	struct proc *p;
147 {
148 	register struct tty *tp = &cons;
149 
150 	(*linesw[tp->t_line].l_close)(tp, flag);
151 	ttyclose(tp);
152 	return (0);
153 }
154 
155 /* ARGSUSED */
156 cnread(dev, uio, flag)
157 	dev_t dev;
158 	struct uio *uio;
159 	int flag;
160 {
161 	register struct tty *tp = &cons;
162 
163 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
164 }
165 
166 /* ARGSUSED */
167 cnwrite(dev, uio, flag)
168 	dev_t dev;
169 	struct uio *uio;
170 	int flag;
171 {
172 	register struct tty *tp;
173 
174 	if ((tp = constty) == NULL ||
175 	    (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
176 		tp = &cons;
177 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
178 }
179 
180 cnioctl(dev, cmd, data, flag, p)
181 	dev_t dev;
182 	int cmd;
183 	caddr_t data;
184 	int flag;
185 	struct proc *p;
186 {
187 	register struct tty *tp;
188 	int error;
189 
190 	/*
191 	 * Superuser can always use this to wrest control of console
192 	 * output from the "virtual" console.
193 	 */
194 	if (cmd == TIOCCONS && constty) {
195 		error = suser(p->p_ucred, (u_short *)NULL);
196 		if (error)
197 			return (error);
198 		constty = NULL;
199 		return (0);
200 	}
201 	tp = &cons;
202 	if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0)
203 		return (error);
204 	if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
205 		return (error);
206 	return (ENOTTY);
207 }
208 
209 cnselect(dev, which, p)
210 	dev_t dev;
211 	int which;
212 	struct proc *p;
213 {
214 
215 	return (ttselect(makedev(major(dev), 0), which, p));
216 }
217 
218 /*
219  * The rest of this code is run only when we are using the ROM vectors.
220  */
221 
222 /*
223  * Generic output.  We just call putchar.  (Very bad for performance.)
224  */
225 static void
226 cnstart(tp)
227 	register struct tty *tp;
228 {
229 	register int c, s;
230 	register void (*putc)(int);
231 
232 	s = spltty();
233 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
234 		splx(s);
235 		return;
236 	}
237 	putc = promvec->pv_putchar;
238 	while (tp->t_outq.c_cc) {
239 		c = getc(&tp->t_outq);
240 		/*
241 		 * *%&!*& ROM monitor console putchar is not reentrant!
242 		 * splhigh/tty around it so as not to run so long with
243 		 * clock interrupts blocked.
244 		 */
245 		(void) splhigh();
246 		(*putc)(c & 0177);
247 		(void) spltty();
248 	}
249 	if (tp->t_state & TS_ASLEEP) {		/* can't happen? */
250 		tp->t_state &= ~TS_ASLEEP;
251 		wakeup((caddr_t)&tp->t_outq);
252 	}
253 	selwakeup(&tp->t_wsel);
254 	splx(s);
255 }
256 
257 /*
258  * Frame buffer output.
259  * We use pseudo-DMA, via the ROM `write string' function, called from
260  * software clock interrupts.
261  */
262 static void
263 cnfbstart(tp)
264 	register struct tty *tp;
265 {
266 	register int s;
267 
268 	s = spltty();		/* paranoid: splsoftclock should suffice */
269 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
270 		splx(s);
271 		return;
272 	}
273 	/*
274 	 * If there are sleepers, and output has drained below low
275 	 * water mark, awaken.
276 	 */
277 	if (tp->t_outq.c_cc <= tp->t_lowat) {
278 		if (tp->t_state & TS_ASLEEP) {
279 			tp->t_state &= ~TS_ASLEEP;
280 			wakeup((caddr_t)&tp->t_outq);
281 		}
282 		selwakeup(&tp->t_wsel);
283 	}
284 	if (tp->t_outq.c_cc) {
285 		tp->t_state |= TS_BUSY;
286 		if (s == 0) {
287 			(void) splsoftclock();
288 			cnfbdma((void *)tp);
289 		} else
290 			timeout(cnfbdma, tp, 1);
291 	}
292 	splx(s);
293 }
294 
295 /*
296  * Stop frame buffer output: just assert TS_FLUSH if necessary.
297  */
298 static void
299 cnfbstop(tp, flag)
300 	register struct tty *tp;
301 	int flag;
302 {
303 	register int s = spltty();	/* paranoid */
304 
305 	if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
306 		tp->t_state |= TS_FLUSH;
307 	splx(s);
308 }
309 
310 /*
311  * Do pseudo-dma (called from software interrupt).
312  */
313 static void
314 cnfbdma(tpaddr)
315 	void *tpaddr;
316 {
317 	register struct tty *tp = tpaddr;
318 	register char *p, *q;
319 	register int n, c, s;
320 
321 	s = spltty();			/* paranoid */
322 	if (tp->t_state & TS_FLUSH) {
323 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
324 		splx(s);
325 	} else {
326 		tp->t_state &= ~TS_BUSY;
327 		splx(s);
328 		p = tp->t_outq.c_cf;
329 		n = ndqb(&tp->t_outq, 0);
330 		for (q = p, c = n; --c >= 0; q++)
331 			if (*q & 0200)	/* high bits seem to be bad */
332 				*q &= ~0200;
333 		(*promvec->pv_putstr)(p, n);
334 		ndflush(&tp->t_outq, n);
335 	}
336 	if (tp->t_line)
337 		(*linesw[tp->t_line].l_start)(tp);
338 	else
339 		cnfbstart(tp);
340 }
341 
342 /*
343  * The following is for rom console input.  The rom will not call
344  * an `interrupt' routine on console input ready, so we must poll.
345  * This is all rather sad.
346  */
347 volatile int	cn_rxc;			/* XXX receive `silo' */
348 
349 /* called from hardclock, which is above spltty, so no tty calls! */
350 cnrom()
351 {
352 	register int c;
353 
354 	if (cn_rxc >= 0)
355 		return (1);
356 	if ((c = (*promvec->pv_nbgetchar)()) < 0)
357 		return (0);
358 	cn_rxc = c;
359 	return (1);
360 }
361 
362 /* pseudo console software interrupt scheduled when cnrom() returns 1 */
363 cnrint()
364 {
365 	register struct tty *tp;
366 	register int c, s;
367 
368 	s = splclock();
369 	c = cn_rxc;
370 	cn_rxc = -1;
371 	splx(s);
372 	if (c < 0)
373 		return;
374 	tp = &cons;
375 	if ((tp->t_cflag & CSIZE) == CS7) {
376 		/* XXX this should be done elsewhere, if at all */
377 		if (tp->t_cflag & PARENB)
378 			if (tp->t_cflag & PARODD ?
379 			    (partab[c & 0177] & 0200) == (c & 0200) :
380 			    (partab[c & 0177] & 0200) != (c & 0200))
381 				c |= TTY_PE;
382 		c &= ~0200;
383 	}
384 	(*linesw[tp->t_line].l_rint)(c, tp);
385 }
386 
387 cngetc()
388 {
389 	register int s, c;
390 
391 	s = splhigh();
392 	c = (*promvec->pv_getchar)();
393 	splx(s);
394 	if (c == '\r')
395 		c = '\n';
396 	return (c);
397 }
398 
399 cnputc(c)
400 	register int c;
401 {
402 	register int s = splhigh();
403 
404 	if (c == '\n')
405 		(*promvec->pv_putchar)('\r');
406 	(*promvec->pv_putchar)(c);
407 	splx(s);
408 }
409