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