update the contribution notice; LBL requires acknowledgement
[unix-history] / usr / src / sys / sparc / dev / cons.c
CommitLineData
287650c6
CT
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 *
b480239a
KB
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 *
287650c6
CT
14 * %sccs.include.redist.c%
15 *
b480239a 16 * @(#)cons.c 7.2 (Berkeley) %G%
287650c6
CT
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
38struct tty *constty = 0; /* virtual console output device */
39struct tty *fbconstty = 0; /* tty structure for frame buffer console */
40int rom_console_input; /* when set, hardclock calls cnrom() */
41
42int cons_ocount; /* output byte count */
43
44extern struct promvec *promvec;
45
46/*
47 * The output driver may munge the minor number in cons.t_dev.
48 */
49struct tty cons; /* rom console tty device */
50static void cnstart __P((struct tty *));
51static void cnfbstart __P((struct tty *));
52static void cnfbstop __P((struct tty *, int));
53static void cnfbdma __P((void *));
54
55extern char partab[];
56
57consinit()
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 */
119cnopen(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 */
143cnclose(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 */
156cnread(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 */
167cnwrite(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
180cnioctl(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
209cnselect(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 */
225static void
226cnstart(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 */
262static void
263cnfbstart(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 */
298static void
299cnfbstop(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 */
313static void
314cnfbdma(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 */
347volatile int cn_rxc; /* XXX receive `silo' */
348
349/* called from hardclock, which is above spltty, so no tty calls! */
350cnrom()
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 */
363cnrint()
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
387cngetc()
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
399cnputc(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}