xref: /netbsd-src/sys/arch/sun3/dev/kd.c (revision 07bae7edddbb1ce4c926b2e8db425804589074c9)
1 /*	$NetBSD: kd.c,v 1.13 1995/04/26 23:20:15 gwr Exp $	*/
2 
3 /*
4  * Copyright (c) 1994, 1995 Gordon W. Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon Ross
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Keyboard/Display device.
35  *
36  * This driver exists simply to provide a tty device that
37  * the indirect console driver can point to.
38  * The kbd driver sends its input here.
39  * Output goes to the screen via PROM printf.
40  */
41 
42 #include <sys/param.h>
43 #include <sys/proc.h>
44 #include <sys/systm.h>
45 #include <sys/ioctl.h>
46 #include <sys/tty.h>
47 #include <sys/file.h>
48 #include <sys/conf.h>
49 #include <sys/device.h>
50 
51 #include <machine/autoconf.h>
52 #include <machine/mon.h>
53 #include <machine/psl.h>
54 
55 #include <dev/cons.h>
56 
57 #define BURST	64
58 
59 /*
60  * There is no point in pretending there might be
61  * more than one keyboard/display device.
62  */
63 struct tty *kd_tty[1];
64 
65 int kdopen(dev_t, int, int, struct proc *);
66 int kdclose(dev_t, int, int, struct proc *);
67 int kdread(dev_t, struct uio *, int);
68 int kdwrite(dev_t, struct uio *, int);
69 int kdioctl(dev_t, int, caddr_t, int, struct proc *);
70 
71 static int kdparam(struct tty *, struct termios *);
72 static void kdstart(struct tty *);
73 
74 int kd_is_console;
75 
76 /* This is called by kbd_serial() like a pseudo-device. */
77 void
78 kd_attach(n)
79 	int n;
80 {
81 	kd_tty[0] = ttymalloc();
82 
83 	/* Tell keyboard module where to send read data. */
84 	kbd_ascii(kd_tty[0]);
85 }
86 
87 struct tty *
88 kdtty(dev)
89 	dev_t dev;
90 {
91 	return kd_tty[0];
92 }
93 
94 int
95 kdopen(dev, flag, mode, p)
96 	dev_t dev;
97 	int flag, mode;
98 	struct proc *p;
99 {
100 	int error, unit;
101 	struct tty *tp;
102 
103 	unit = minor(dev);
104 	if (unit) return ENXIO;
105 
106 	tp = kd_tty[unit];
107 	if (tp == NULL)
108 		return ENXIO;
109 
110 	if ((error = kbd_iopen()) != 0) {
111 #ifdef	DIAGNOSTIC
112 		printf("kd: kbd_iopen, error=%d\n", error);
113 #endif
114 		return (error);
115 	}
116 
117 	tp->t_oproc = kdstart;
118 	tp->t_param = kdparam;
119 	tp->t_dev = dev;
120 	if ((tp->t_state & TS_ISOPEN) == 0) {
121 		tp->t_state |= TS_WOPEN;
122 		ttychars(tp);
123 		tp->t_iflag = TTYDEF_IFLAG;
124 		tp->t_oflag = TTYDEF_OFLAG;
125 		tp->t_cflag = TTYDEF_CFLAG;
126 		tp->t_lflag = TTYDEF_LFLAG;
127 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
128 		kdparam(tp, &tp->t_termios);
129 		ttsetwater(tp);
130 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
131 		return EBUSY;
132 	tp->t_state |= TS_CARR_ON;
133 
134 	return ((*linesw[tp->t_line].l_open)(dev, tp));
135 }
136 
137 int
138 kdclose(dev, flag, mode, p)
139 	dev_t dev;
140 	int flag, mode;
141 	struct proc *p;
142 {
143 	int unit = minor(dev);
144 	struct tty *tp = kd_tty[unit];
145 
146 	(*linesw[tp->t_line].l_close)(tp, flag);
147 	ttyclose(tp);
148 	return (0);
149 }
150 
151 int
152 kdread(dev, uio, flag)
153 	dev_t dev;
154 	struct uio *uio;
155 	int flag;
156 {
157 	int unit = minor(dev);
158 	struct tty *tp = kd_tty[unit];
159 
160 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
161 }
162 
163 int
164 kdwrite(dev, uio, flag)
165 	dev_t dev;
166 	struct uio *uio;
167 	int flag;
168 {
169 	int unit = minor(dev);
170 	struct tty *tp = kd_tty[unit];
171 
172 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
173 }
174 
175 int
176 kdstop(tp, flag)
177 	struct tty *tp;
178 	int flag;
179 {
180 
181 }
182 
183 int
184 kdioctl(dev, cmd, data, flag, p)
185 	dev_t dev;
186 	int cmd;
187 	caddr_t data;
188 	int flag;
189 	struct proc *p;
190 {
191 	int error;
192 	int unit = minor(dev);
193 	struct tty *tp = kd_tty[unit];
194 
195 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
196 	if (error >= 0)
197 		return error;
198 	error = ttioctl(tp, cmd, data, flag, p);
199 	if (error >= 0)
200 		return error;
201 
202 	/* Handle any ioctl commands specific to kbd/display. */
203 	/* XXX - Send KB* ioctls to kbd module? */
204 	/* XXX - Send FB* ioctls to fb module?  */
205 
206 	return ENOTTY;
207 }
208 
209 static void kd_later(void*);
210 static void kd_putfb(struct tty *);
211 
212 void
213 kdstart(tp)
214 	struct tty *tp;
215 {
216 	struct clist *cl;
217 	register int s;
218 
219 	s = spltty();
220 	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
221 		goto out;
222 
223 	cl = &tp->t_outq;
224 	if (cl->c_cc) {
225 		if (kd_is_console) {
226 			tp->t_state |= TS_BUSY;
227 			if ((s & PSL_IPL) == 0) {
228 				/* called at level zero - update screen now. */
229 				(void) splsoftclock();
230 				kd_putfb(tp);
231 				(void) spltty();
232 				tp->t_state &= ~TS_BUSY;
233 			} else {
234 				/* called at interrupt level - do it later */
235 				timeout(kd_later, (void*)tp, 0);
236 			}
237 		} else {
238 			/*
239 			 * This driver uses the PROM for writing the screen,
240 			 * and that only works if this is the console device.
241 			 * If this is not the console, just flush the output.
242 			 * Sorry.  (In that case, use xdm instead of getty.)
243 			 */
244 			ndflush(cl, cl->c_cc);
245 		}
246 	}
247 	if (cl->c_cc <= tp->t_lowat) {
248 		if (tp->t_state & TS_ASLEEP) {
249 			tp->t_state &= ~TS_ASLEEP;
250 			wakeup((caddr_t)cl);
251 		}
252 		selwakeup(&tp->t_wsel);
253 	}
254 out:
255 	splx(s);
256 }
257 
258 /*
259  * Timeout function to do delayed writes to the screen.
260  * Called at splsoftclock when requested by kdstart.
261  */
262 static void
263 kd_later(tpaddr)
264 	void *tpaddr;
265 {
266 	struct tty *tp = tpaddr;
267 	register int s;
268 
269 	kd_putfb(tp);
270 
271 	s = spltty();
272 	tp->t_state &= ~TS_BUSY;
273 	if (tp->t_line)
274 		(*linesw[tp->t_line].l_start)(tp);
275 	else
276 		kdstart(tp);
277 	splx(s);
278 }
279 
280 /*
281  * Put text on the screen using the PROM monitor.
282  * This can take a while, so to avoid missing
283  * interrupts, this is called at splsoftclock.
284  */
285 static void kd_putfb(tp)
286 	struct tty *tp;
287 {
288 	char buf[BURST];
289 	struct clist *cl = &tp->t_outq;
290 	char *p, *end;
291 	int len;
292 
293 	while ((len = q_to_b(cl, buf, BURST-1)) > 0) {
294 		/* PROM will barf if high bits are set. */
295 		p = buf;
296 		end = buf + len;
297 		while (p < end)
298 			*p++ &= 0x7f;
299 		(romVectorPtr->fbWriteStr)(buf, len);
300 	}
301 }
302 
303 
304 static int
305 kdparam(tp, t)
306 	struct tty *tp;
307 	struct termios *t;
308 {
309 	/* XXX - These are ignored... */
310 	tp->t_ispeed = t->c_ispeed;
311 	tp->t_ospeed = t->c_ospeed;
312 	tp->t_cflag = t->c_cflag;
313 	return 0;
314 }
315 
316 
317 /*
318  * kd console support
319  */
320 
321 extern int zscnprobe_kbd(), zscngetc(), kbd_translate();
322 
323 kdcnprobe(cp)
324 	struct consdev *cp;
325 {
326 	int maj;
327 
328 	/* locate the major number */
329 	for (maj = 0; maj < nchrdev; maj++)
330 		if (cdevsw[maj].d_open == (void*)kdopen)
331 			break;
332 
333 	/* initialize required fields */
334 	cp->cn_dev = makedev(maj, 0);
335 	cp->cn_pri = zscnprobe_kbd();
336 }
337 
338 kdcninit(cp)
339 	struct consdev *cp;
340 {
341 
342 	/* This prepares zscngetc() */
343 	zs_set_conschan(1, 0);
344 
345 	/* This prepares kbd_translate() */
346 	kbd_init_tables();
347 
348 	/* Indicate that it is OK to use the PROM fbwrite */
349 	kd_is_console = 1;
350 
351 	mon_printf("console on kd0 (keyboard/display)\n");
352 }
353 
354 kdcngetc(dev)
355 	dev_t dev;
356 {
357 	int c;
358 
359 	do {
360 		c = zscngetc(0);
361 		c = kbd_translate(c);
362 	} while (c == -1);
363 
364 	return (c);
365 }
366 
367 kdcnputc(dev, c)
368 	dev_t dev;
369 	int c;
370 {
371 	(romVectorPtr->fbWriteChar)(c & 0x7f);
372 }
373 
374 extern void fb_unblank();
375 void kdcnpollc(dev, on)
376 	dev_t dev;
377 	int on;
378 {
379 	if (on)
380 		fb_unblank();
381 }
382