xref: /netbsd/sys/arch/arc/dev/pccons.c (revision c4a72b64)
1 /*	$NetBSD: pccons.c,v 1.31 2002/10/23 09:10:38 jdolecek Exp $	*/
2 /*	$OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $	*/
3 /*	NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp	*/
4 
5 /*-
6  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * William Jolitz and Don Ahn.
12  *
13  * Copyright (c) 1994 Charles M. Hannum.
14  * Copyright (c) 1992, 1993 Erik Forsberg.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
45  */
46 
47 /*
48  * code to work keyboard & display for PC-style console
49  */
50 
51 #include "opt_ddb.h"
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/tty.h>
56 #include <sys/callout.h>
57 #include <sys/poll.h>
58 #include <sys/conf.h>
59 #include <sys/vnode.h>
60 #include <sys/kernel.h>
61 #include <sys/kcore.h>
62 #include <sys/device.h>
63 #include <sys/proc.h>
64 
65 #include <machine/bus.h>
66 
67 #include <machine/display.h>
68 #include <machine/pccons.h>
69 #include <machine/kbdreg.h>
70 
71 #include <dev/cons.h>
72 #include <dev/isa/isavar.h>
73 
74 #include <arc/arc/arcbios.h>
75 #include <arc/dev/pcconsvar.h>
76 
77 #define	XFREE86_BUG_COMPAT
78 
79 #ifndef BEEP_FREQ
80 #define BEEP_FREQ 1600
81 #endif
82 #ifndef BEEP_TIME
83 #define BEEP_TIME (hz/5)
84 #endif
85 
86 #define PCBURST 128
87 
88 static u_short *Crtat;			/* pointer to backing store */
89 static u_short *crtat;			/* pointer to current char */
90 static u_char async, kernel, polling;	/* Really, you don't want to know. */
91 static u_char lock_state = 0x00,	/* all off */
92 	      old_lock_state = 0xff,
93 	      typematic_rate = 0xff,	/* don't update until set by user */
94 	      old_typematic_rate = 0xff;
95 static u_short cursor_shape = 0xffff,	/* don't update until set by user */
96 	       old_cursor_shape = 0xffff;
97 static pccons_keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */
98 int pc_xmode = 0;
99 
100 /*
101  *  Keyboard output queue.
102  */
103 int	kb_oq_put = 0;
104 int	kb_oq_get = 0;
105 u_char	kb_oq[8];
106 
107 #define	PCUNIT(x)	(minor(x))
108 
109 static struct video_state {
110 	int 	cx, cy;		/* escape parameters */
111 	int 	row, col;	/* current cursor position */
112 	int 	nrow, ncol, nchr;	/* current screen geometry */
113 	int	offset;		/* Saved cursor pos */
114 	u_char	state;		/* parser state */
115 #define	VSS_ESCAPE	1
116 #define	VSS_EBRACE	2
117 #define	VSS_EPARAM	3
118 	char	so;		/* in standout mode? */
119 	char	color;		/* color or mono display */
120 	char	at;		/* normal attributes */
121 	char	so_at;		/* standout attributes */
122 } vs;
123 
124 static struct callout async_update_ch = CALLOUT_INITIALIZER;
125 
126 void pc_xmode_on __P((void));
127 void pc_xmode_off __P((void));
128 static u_char kbc_get8042cmd __P((void));
129 int kbd_cmd __P((u_char, u_char));
130 static __inline int kbd_wait_output __P((void));
131 static __inline int kbd_wait_input __P((void));
132 void kbd_flush_input __P((void));
133 void set_cursor_shape __P((void));
134 void get_cursor_shape __P((void));
135 void async_update __P((void));
136 void do_async_update __P((u_char));;
137 
138 void pccnputc __P((dev_t, int c));
139 int pccngetc __P((dev_t));
140 void pccnpollc __P((dev_t, int));
141 
142 extern struct cfdriver pc_cd;
143 
144 dev_type_open(pcopen);
145 dev_type_close(pcclose);
146 dev_type_read(pcread);
147 dev_type_write(pcwrite);
148 dev_type_ioctl(pcioctl);
149 dev_type_tty(pctty);
150 dev_type_poll(pcpoll);
151 dev_type_mmap(pcmmap);
152 
153 const struct cdevsw pc_cdevsw = {
154 	pcopen, pcclose, pcread, pcwrite, pcioctl,
155 	nostop, pctty, pcpoll, pcmmap, ttykqfilter, D_TTY
156 };
157 
158 #define	CHR		2
159 
160 char *sget __P((void));
161 void sput __P((u_char *, int));
162 
163 void	pcstart __P((struct tty *));
164 int	pcparam __P((struct tty *, struct termios *));
165 static __inline void wcopy __P((void *, void *, u_int));
166 void	pc_context_init __P((bus_space_tag_t, bus_space_tag_t, bus_space_tag_t,
167 	    struct pccons_config *));
168 
169 extern void fillw __P((int, u_int16_t *, int));
170 
171 #define	KBD_DELAY \
172 		DELAY(10);
173 
174 #define crtc_read_1(reg) \
175 	bus_space_read_1(pccons_console_context.pc_crt_iot, \
176 	    pccons_console_context.pc_6845_ioh, reg)
177 #define crtc_write_1(reg, data) \
178 	bus_space_write_1(pccons_console_context.pc_crt_iot, \
179 	    pccons_console_context.pc_6845_ioh, reg, data)
180 
181 struct pccons_context pccons_console_context;
182 
183 void
184 kbd_context_init(kbd_iot, config)
185 	bus_space_tag_t kbd_iot;
186 	struct pccons_config *config;
187 {
188 	struct pccons_kbd_context *pkc = &pccons_console_context.pc_pkc;
189 
190 	if (pkc->pkc_initialized)
191 		return;
192 	pkc->pkc_initialized = 1;
193 
194 	pkc->pkc_iot = kbd_iot;
195 
196 	bus_space_map(kbd_iot, config->pc_kbd_cmdp, 1, 0,
197 	    &pkc->pkc_cmd_ioh);
198 	bus_space_map(kbd_iot, config->pc_kbd_datap, 1, 0,
199 	    &pkc->pkc_data_ioh);
200 }
201 
202 void
203 pc_context_init(crt_iot, crt_memt, kbd_iot, config)
204 	bus_space_tag_t crt_iot, crt_memt, kbd_iot;
205 	struct pccons_config *config;
206 {
207 	struct pccons_context *pc = &pccons_console_context;
208 
209 	if (pc->pc_initialized)
210 		return;
211 	pc->pc_initialized = 1;
212 
213 	kbd_context_init(kbd_iot, config);
214 
215 	pc->pc_crt_iot = crt_iot;
216 	pc->pc_crt_memt = crt_memt;
217 
218 	bus_space_map(crt_iot, config->pc_mono_iobase, 2, 0,
219 	    &pc->pc_mono_ioh);
220 	bus_space_map(crt_memt, config->pc_mono_memaddr, 0x20000, 0,
221 	    &pc->pc_mono_memh);
222 	bus_space_map(crt_iot, config->pc_cga_iobase, 2, 0,
223 	    &pc->pc_cga_ioh);
224 	bus_space_map(crt_memt, config->pc_cga_memaddr, 0x20000, 0,
225 	    &pc->pc_cga_memh);
226 
227 	/*
228 	 * pc->pc_6845_ioh and pc->pc_crt_memh will be initialized later,
229 	 * when `Crtat' is initialized.
230 	 */
231 
232 	pc->pc_config = config;
233 
234 	(*config->pc_init)();
235 }
236 
237 /*
238  * bcopy variant that only moves word-aligned 16-bit entities,
239  * for stupid VGA cards.  cnt is required to be an even vale.
240  */
241 static __inline void
242 wcopy(src, tgt, cnt)
243 	void *src, *tgt;
244 	u_int cnt;
245 {
246 	u_int16_t *from = src;
247 	u_int16_t *to = tgt;
248 
249 	cnt >>= 1;
250 	if (to < from || to >= from + cnt)
251 		while(cnt--)
252 			*to++ = *from++;
253 	else {
254 		to += cnt;
255 		from += cnt;
256 		while(cnt--)
257 			*--to = *--from;
258 	}
259 }
260 
261 static __inline int
262 kbd_wait_output()
263 {
264 	u_int i;
265 
266 	for (i = 100000; i; i--)
267 		if ((kbd_cmd_read_1() & KBS_IBF) == 0) {
268 			KBD_DELAY;
269 			return 1;
270 		}
271 	return 0;
272 }
273 
274 static __inline int
275 kbd_wait_input()
276 {
277 	u_int i;
278 
279 	for (i = 100000; i; i--)
280 		if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
281 			KBD_DELAY;
282 			return 1;
283 		}
284 	return 0;
285 }
286 
287 void
288 kbd_flush_input()
289 {
290 	u_char c;
291 
292 	while ((c = kbd_cmd_read_1()) & 0x03)
293 		if ((c & KBS_DIB) == KBS_DIB) {
294 			/* XXX - delay is needed to prevent some keyboards from
295 			   wedging when the system boots */
296 			delay(6);
297 			(void) kbd_data_read_1();
298 		}
299 }
300 
301 #if 1
302 /*
303  * Get the current command byte.
304  */
305 static u_char
306 kbc_get8042cmd()
307 {
308 
309 	if (!kbd_wait_output())
310 		return -1;
311 	kbd_cmd_write_1(K_RDCMDBYTE);
312 	if (!kbd_wait_input())
313 		return -1;
314 	return kbd_data_read_1();
315 }
316 #endif
317 
318 /*
319  * Pass command byte to keyboard controller (8042).
320  */
321 int
322 kbc_put8042cmd(val)
323 	u_char val;
324 {
325 
326 	if (!kbd_wait_output())
327 		return 0;
328 	kbd_cmd_write_1(K_LDCMDBYTE);
329 	if (!kbd_wait_output())
330 		return 0;
331 	kbd_data_write_1(val);
332 	return 1;
333 }
334 
335 /*
336  * Pass command to keyboard itself
337  */
338 int
339 kbd_cmd(val, polling)
340 	u_char val;
341 	u_char polling;
342 {
343 	u_int retries = 3;
344 	register u_int i;
345 
346 	if(!polling) {
347 		i = spltty();
348 		if(kb_oq_get == kb_oq_put) {
349 			kbd_data_write_1(val);
350 		}
351 		kb_oq[kb_oq_put] = val;
352 		kb_oq_put = (kb_oq_put + 1) & 7;
353 		splx(i);
354 		return(1);
355 	}
356 	else do {
357 		if (!kbd_wait_output())
358 			return 0;
359 		kbd_data_write_1(val);
360 		for (i = 100000; i; i--) {
361 			if (kbd_cmd_read_1() & KBS_DIB) {
362 				register u_char c;
363 
364 				KBD_DELAY;
365 				c = kbd_data_read_1();
366 				if (c == KBR_ACK || c == KBR_ECHO) {
367 					return 1;
368 				}
369 				if (c == KBR_RESEND) {
370 					break;
371 				}
372 #ifdef DIAGNOSTIC
373 				printf("kbd_cmd: input char %x lost\n", c);
374 #endif
375 			}
376 		}
377 	} while (--retries);
378 	return 0;
379 }
380 
381 void
382 set_cursor_shape()
383 {
384 	crtc_write_1(0, 10);
385 	crtc_write_1(1, cursor_shape >> 8);
386 	crtc_write_1(0, 11);
387 	crtc_write_1(1, cursor_shape);
388 	old_cursor_shape = cursor_shape;
389 }
390 
391 void
392 get_cursor_shape()
393 {
394 	crtc_write_1(0, 10);
395 	cursor_shape = crtc_read_1(1) << 8;
396 	crtc_write_1(0, 11);
397 	cursor_shape |= crtc_read_1(1);
398 
399 	/*
400 	 * real 6845's, as found on, MDA, Hercules or CGA cards, do
401 	 * not support reading the cursor shape registers. the 6845
402 	 * tri-states it's data bus. This is _normally_ read by the
403 	 * cpu as either 0x00 or 0xff.. in which case we just use
404 	 * a line cursor.
405 	 */
406 	if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
407 		cursor_shape = 0x0b10;
408 	else
409 		cursor_shape &= 0x1f1f;
410 }
411 
412 void
413 do_async_update(poll)
414 	u_char poll;
415 {
416 	int pos;
417 	static int old_pos = -1;
418 
419 	async = 0;
420 
421 	if (lock_state != old_lock_state) {
422 		old_lock_state = lock_state;
423 		if (!kbd_cmd(KBC_MODEIND, poll) ||
424 		    !kbd_cmd(lock_state, poll)) {
425 			printf("pc: timeout updating leds\n");
426 			(void) kbd_cmd(KBC_ENABLE, poll);
427 		}
428 	}
429 	if (typematic_rate != old_typematic_rate) {
430 		old_typematic_rate = typematic_rate;
431 		if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
432 		    !kbd_cmd(typematic_rate, poll)) {
433 			printf("pc: timeout updating typematic rate\n");
434 			(void) kbd_cmd(KBC_ENABLE, poll);
435 		}
436 	}
437 
438 	if (pc_xmode > 0)
439 		return;
440 
441 	pos = crtat - Crtat;
442 	if (pos != old_pos) {
443 		crtc_write_1(0, 14);
444 		crtc_write_1(1, pos >> 8);
445 		crtc_write_1(0, 15);
446 		crtc_write_1(1, pos);
447 		old_pos = pos;
448 	}
449 	if (cursor_shape != old_cursor_shape)
450 		set_cursor_shape();
451 }
452 
453 void
454 async_update()
455 {
456 
457 	if (kernel || polling) {
458 		if (async)
459 			callout_stop(&async_update_ch);
460 		do_async_update(1);
461 	} else {
462 		if (async)
463 			return;
464 		async = 1;
465 		callout_reset(&async_update_ch, 1,
466 		    (void(*)(void *))do_async_update, NULL);
467 	}
468 }
469 
470 /*
471  * these are both bad jokes
472  */
473 int
474 pccons_common_match(crt_iot, crt_memt, kbd_iot, config)
475 	bus_space_tag_t crt_iot, crt_memt, kbd_iot;
476 	struct pccons_config *config;
477 {
478 	int i;
479 
480 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
481 
482 	/* Enable interrupts and keyboard, etc. */
483 	if (!kbc_put8042cmd(CMDBYTE)) {
484 		printf("pcprobe: command error\n");
485 		return 0;
486 	}
487 
488 #if 1
489 	/* Flush any garbage. */
490 	kbd_flush_input();
491 	/* Reset the keyboard. */
492 	if (!kbd_cmd(KBC_RESET, 1)) {
493 		printf("pcprobe: reset error %d\n", 1);
494 		goto lose;
495 	}
496 	for (i = 600000; i; i--)
497 		if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
498 			KBD_DELAY;
499 			break;
500 		}
501 	if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) {
502 		printf("pcprobe: reset error %d\n", 2);
503 		goto lose;
504 	}
505 	/*
506 	 * Some keyboards seem to leave a second ack byte after the reset.
507 	 * This is kind of stupid, but we account for them anyway by just
508 	 * flushing the buffer.
509 	 */
510 	kbd_flush_input();
511 	/* Just to be sure. */
512 	if (!kbd_cmd(KBC_ENABLE, 1)) {
513 		printf("pcprobe: reset error %d\n", 3);
514 		goto lose;
515 	}
516 
517 	/*
518 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
519 	 * is set to table 1; in fact, it would appear that some keyboards just
520 	 * ignore the command altogether.  So by default, we use the AT scan
521 	 * codes and have the 8042 translate them.  Unfortunately, this is
522 	 * known to not work on some PS/2 machines.  We try desparately to deal
523 	 * with this by checking the (lack of a) translate bit in the 8042 and
524 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
525 	 * tough luck.
526 	 *
527 	 * XXX It would perhaps be a better choice to just use AT scan codes
528 	 * and not bother with this.
529 	 */
530 	if (kbc_get8042cmd() & KC8_TRANS) {
531 		/* The 8042 is translating for us; use AT codes. */
532 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
533 			printf("pcprobe: reset error %d\n", 4);
534 			goto lose;
535 		}
536 	} else {
537 		/* Stupid 8042; set keyboard to XT codes. */
538 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
539 			printf("pcprobe: reset error %d\n", 5);
540 			goto lose;
541 		}
542 	}
543 
544 lose:
545 	/*
546 	 * Technically, we should probably fail the probe.  But we'll be nice
547 	 * and allow keyboard-less machines to boot with the console.
548 	 */
549 #endif
550 
551 	return 1;
552 }
553 
554 void pccons_common_attach(sc, crt_iot, crt_memt, kbd_iot, config)
555 	struct pc_softc *sc;
556 	bus_space_tag_t crt_iot, crt_memt, kbd_iot;
557 	struct pccons_config *config;
558 {
559 	printf(": %s\n", vs.color ? "color" : "mono");
560 	do_async_update(1);
561 }
562 
563 int
564 pcopen(dev, flag, mode, p)
565 	dev_t dev;
566 	int flag, mode;
567 	struct proc *p;
568 {
569 	struct pc_softc *sc;
570 	int unit = PCUNIT(dev);
571 	struct tty *tp;
572 
573 	if (unit >= pc_cd.cd_ndevs)
574 		return ENXIO;
575 	sc = pc_cd.cd_devs[unit];
576 	if (sc == 0)
577 		return ENXIO;
578 
579 	if (!sc->sc_tty) {
580 		tp = sc->sc_tty = ttymalloc();
581 	}
582 	else {
583 		tp = sc->sc_tty;
584 	}
585 
586 	tp->t_oproc = pcstart;
587 	tp->t_param = pcparam;
588 	tp->t_dev = dev;
589 	if ((tp->t_state & TS_ISOPEN) == 0) {
590 		ttychars(tp);
591 		tp->t_iflag = TTYDEF_IFLAG;
592 		tp->t_oflag = TTYDEF_OFLAG;
593 		tp->t_cflag = TTYDEF_CFLAG;
594 		tp->t_lflag = TTYDEF_LFLAG;
595 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
596 		pcparam(tp, &tp->t_termios);
597 		ttsetwater(tp);
598 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
599 		return EBUSY;
600 	tp->t_state |= TS_CARR_ON;
601 
602 	return ((*tp->t_linesw->l_open)(dev, tp));
603 }
604 
605 int
606 pcclose(dev, flag, mode, p)
607 	dev_t dev;
608 	int flag, mode;
609 	struct proc *p;
610 {
611 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
612 	struct tty *tp = sc->sc_tty;
613 
614 	(*tp->t_linesw->l_close)(tp, flag);
615 	ttyclose(tp);
616 #ifdef notyet /* XXX */
617 	ttyfree(tp);
618 #endif
619 	return(0);
620 }
621 
622 int
623 pcread(dev, uio, flag)
624 	dev_t dev;
625 	struct uio *uio;
626 	int flag;
627 {
628 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
629 	struct tty *tp = sc->sc_tty;
630 
631 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
632 }
633 
634 int
635 pcwrite(dev, uio, flag)
636 	dev_t dev;
637 	struct uio *uio;
638 	int flag;
639 {
640 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
641 	struct tty *tp = sc->sc_tty;
642 
643 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
644 }
645 
646 int
647 pcpoll(dev, events, p)
648 	dev_t dev;
649 	int events;
650 	struct proc *p;
651 {
652 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
653 	struct tty *tp = sc->sc_tty;
654 
655 	return ((*tp->t_linesw->l_poll)(tp, events, p));
656 }
657 
658 struct tty *
659 pctty(dev)
660 	dev_t dev;
661 {
662 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
663 	struct tty *tp = sc->sc_tty;
664 
665 	return (tp);
666 }
667 
668 /*
669  * Got a console receive interrupt -
670  * the console processor wants to give us a character.
671  * Catch the character, and see who it goes to.
672  */
673 int
674 pcintr(arg)
675 	void *arg;
676 {
677 	struct pc_softc *sc = arg;
678 	register struct tty *tp = sc->sc_tty;
679 	u_char *cp;
680 
681 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
682 		return 0;
683 	if (polling)
684 		return 1;
685 	do {
686 		cp = sget();
687 		if (!tp || (tp->t_state & TS_ISOPEN) == 0)
688 			return 1;
689 		if (cp)
690 			do
691 				(*tp->t_linesw->l_rint)(*cp++, tp);
692 			while (*cp);
693 	} while (kbd_cmd_read_1() & KBS_DIB);
694 	return 1;
695 }
696 
697 int
698 pcioctl(dev, cmd, data, flag, p)
699 	dev_t dev;
700 	u_long cmd;
701 	caddr_t data;
702 	int flag;
703 	struct proc *p;
704 {
705 	struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
706 	struct tty *tp = sc->sc_tty;
707 	int error;
708 
709 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
710 	if (error != EPASSTHROUGH)
711 		return error;
712 	error = ttioctl(tp, cmd, data, flag, p);
713 	if (error != EPASSTHROUGH)
714 		return error;
715 
716 	switch (cmd) {
717 	case CONSOLE_X_MODE_ON:
718 		pc_xmode_on();
719 		return 0;
720 	case CONSOLE_X_MODE_OFF:
721 		pc_xmode_off();
722 		return 0;
723 	case CONSOLE_X_BELL:
724 		/*
725 		 * If set, data is a pointer to a length 2 array of
726 		 * integers.  data[0] is the pitch in Hz and data[1]
727 		 * is the duration in msec.
728 		 */
729 		if (data)
730 			sysbeep(((int*)data)[0],
731 				(((int*)data)[1] * hz) / 1000);
732 		else
733 			sysbeep(BEEP_FREQ, BEEP_TIME);
734 		return 0;
735 	case CONSOLE_SET_TYPEMATIC_RATE: {
736  		u_char	rate;
737 
738  		if (!data)
739 			return EINVAL;
740 		rate = *((u_char *)data);
741 		/*
742 		 * Check that it isn't too big (which would cause it to be
743 		 * confused with a command).
744 		 */
745 		if (rate & 0x80)
746 			return EINVAL;
747 		typematic_rate = rate;
748 		async_update();
749 		return 0;
750  	}
751 	case CONSOLE_SET_KEYMAP: {
752 		pccons_keymap_t *map = (pccons_keymap_t *) data;
753 		int i;
754 
755 		if (!data)
756 			return EINVAL;
757 		for (i = 0; i < KB_NUM_KEYS; i++)
758 			if (map[i].unshift[KB_CODE_SIZE-1] ||
759 			    map[i].shift[KB_CODE_SIZE-1] ||
760 			    map[i].ctl[KB_CODE_SIZE-1] ||
761 			    map[i].altgr[KB_CODE_SIZE-1] ||
762 			    map[i].shift_altgr[KB_CODE_SIZE-1])
763 				return EINVAL;
764 
765 		bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
766 		return 0;
767 	}
768 	case CONSOLE_GET_KEYMAP:
769 		if (!data)
770 			return EINVAL;
771 		bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
772 		return 0;
773 
774 	default:
775 		return EPASSTHROUGH;
776 	}
777 
778 #ifdef DIAGNOSTIC
779 	panic("pcioctl: impossible");
780 #endif
781 }
782 
783 void
784 pcstart(tp)
785 	struct tty *tp;
786 {
787 	struct clist *cl;
788 	int s, len;
789 	u_char buf[PCBURST];
790 
791 	s = spltty();
792 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
793 		goto out;
794 	tp->t_state |= TS_BUSY;
795 	splx(s);
796 	/*
797 	 * We need to do this outside spl since it could be fairly
798 	 * expensive and we don't want our serial ports to overflow.
799 	 */
800 	cl = &tp->t_outq;
801 	len = q_to_b(cl, buf, PCBURST);
802 	sput(buf, len);
803 	s = spltty();
804 	tp->t_state &= ~TS_BUSY;
805 	if (cl->c_cc) {
806 		tp->t_state |= TS_TIMEOUT;
807 		callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
808 	}
809 	if (cl->c_cc <= tp->t_lowat) {
810 		if (tp->t_state & TS_ASLEEP) {
811 			tp->t_state &= ~TS_ASLEEP;
812 			wakeup(cl);
813 		}
814 		selwakeup(&tp->t_wsel);
815 	}
816 out:
817 	splx(s);
818 }
819 
820 /* ARGSUSED */
821 void pccons_common_cnattach(crt_iot, crt_memt, kbd_iot, config)
822 	bus_space_tag_t crt_iot, crt_memt, kbd_iot;
823 	struct pccons_config *config;
824 {
825 	int maj;
826 	static struct consdev pccons = {
827 		NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL,
828 		    NODEV, CN_NORMAL
829 	};
830 
831 	/*
832 	 * For now, don't screw with it.
833 	 */
834 	/* crtat = 0; */
835 
836 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
837 
838 	/* locate the major number */
839 	maj = cdevsw_lookup_major(&pc_cdevsw);
840 	pccons.cn_dev = makedev(maj, 0);
841 
842 	cn_tab = &pccons;
843 }
844 
845 /* ARGSUSED */
846 void
847 pccnputc(dev, c)
848 	dev_t dev;
849 	int c;
850 {
851 	u_char cc, oldkernel = kernel;
852 
853 	kernel = 1;
854 	if (c == '\n') {
855 		sput("\r\n", 2);
856 	} else {
857 		cc = c;
858 		sput(&cc, 1);
859 	}
860 	kernel = oldkernel;
861 }
862 
863 /* ARGSUSED */
864 int
865 pccngetc(dev)
866 	dev_t dev;
867 {
868 	register char *cp;
869 
870 	if (pc_xmode > 0)
871 		return 0;
872 
873 	do {
874 		/* wait for byte */
875 		while ((kbd_cmd_read_1() & KBS_DIB) == 0);
876 		/* see if it's worthwhile */
877 		cp = sget();
878 	} while (!cp);
879 	if (*cp == '\r')
880 		return '\n';
881 	return *cp;
882 }
883 
884 void
885 pccnpollc(dev, on)
886 	dev_t dev;
887 	int on;
888 {
889 
890 	polling = on;
891 	if (!on) {
892 		int unit;
893 		struct pc_softc *sc;
894 		int s;
895 
896 		/*
897 		 * If disabling polling on a device that's been configured,
898 		 * make sure there are no bytes left in the FIFO, holding up
899 		 * the interrupt line.  Otherwise we won't get any further
900 		 * interrupts.
901 		 */
902 		unit = PCUNIT(dev);
903 		if (pc_cd.cd_ndevs > unit) {
904 			sc = pc_cd.cd_devs[unit];
905 			if (sc != 0) {
906 				s = spltty();
907 				pcintr(sc);
908 				splx(s);
909 			}
910 		}
911 	}
912 }
913 
914 /*
915  * Set line parameters.
916  */
917 int
918 pcparam(tp, t)
919 	struct tty *tp;
920 	struct termios *t;
921 {
922 
923 	tp->t_ispeed = t->c_ispeed;
924 	tp->t_ospeed = t->c_ospeed;
925 	tp->t_cflag = t->c_cflag;
926 	return 0;
927 }
928 
929 #define	wrtchar(c, at) do {\
930 	char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \
931 } while (0)
932 
933 /* translate ANSI color codes to standard pc ones */
934 static char fgansitopc[] = {
935 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
936 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
937 };
938 
939 static char bgansitopc[] = {
940 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
941 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
942 };
943 
944 static u_char iso2ibm437[] =
945 {
946             0,     0,     0,     0,     0,     0,     0,     0,
947             0,     0,     0,     0,     0,     0,     0,     0,
948             0,     0,     0,     0,     0,     0,     0,     0,
949             0,     0,     0,     0,     0,     0,     0,     0,
950          0xff,  0xad,  0x9b,  0x9c,     0,  0x9d,     0,  0x40,
951          0x6f,  0x63,  0x61,  0xae,     0,     0,     0,     0,
952          0xf8,  0xf1,  0xfd,  0x33,     0,  0xe6,     0,  0xfa,
953             0,  0x31,  0x6f,  0xaf,  0xac,  0xab,     0,  0xa8,
954          0x41,  0x41,  0x41,  0x41,  0x8e,  0x8f,  0x92,  0x80,
955          0x45,  0x90,  0x45,  0x45,  0x49,  0x49,  0x49,  0x49,
956          0x81,  0xa5,  0x4f,  0x4f,  0x4f,  0x4f,  0x99,  0x4f,
957          0x4f,  0x55,  0x55,  0x55,  0x9a,  0x59,     0,  0xe1,
958          0x85,  0xa0,  0x83,  0x61,  0x84,  0x86,  0x91,  0x87,
959          0x8a,  0x82,  0x88,  0x89,  0x8d,  0xa1,  0x8c,  0x8b,
960             0,  0xa4,  0x95,  0xa2,  0x93,  0x6f,  0x94,  0x6f,
961          0x6f,  0x97,  0xa3,  0x96,  0x81,  0x98,     0,     0
962 };
963 
964 /*
965  * `pc3' termcap emulation.
966  */
967 void
968 sput(cp, n)
969 	u_char *cp;
970 	int n;
971 {
972 	struct pccons_context *pc = &pccons_console_context;
973 	u_char c, scroll = 0;
974 
975 	if (pc_xmode > 0)
976 		return;
977 
978 	if (crtat == 0) {
979 		volatile u_short *cp;
980 		u_short was;
981 		unsigned cursorat;
982 
983 		cp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
984 		was = *cp;
985 		*cp = 0xA55A;
986 		if (*cp != 0xA55A) {
987 			cp = bus_space_vaddr(pc->pc_crt_memt,
988 			    pc->pc_mono_memh);
989 			pc->pc_6845_ioh = pc->pc_mono_ioh;
990 			pc->pc_crt_memh = pc->pc_mono_memh;
991 			vs.color = 0;
992 		} else {
993 			*cp = was;
994 			pc->pc_6845_ioh = pc->pc_cga_ioh;
995 			pc->pc_crt_memh = pc->pc_cga_memh;
996 			vs.color = 1;
997 		}
998 
999 #ifdef FAT_CURSOR
1000 		cursor_shape = 0x0012;
1001 #else
1002 		get_cursor_shape();
1003 #endif
1004 
1005 		bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
1006 		vs.nchr = vs.ncol * vs.nrow;
1007 		vs.col--;
1008 		vs.row--;
1009 		cursorat = vs.ncol * vs.row + vs.col;
1010 		vs.at = FG_LIGHTGREY | BG_BLACK;
1011 
1012 		Crtat = (u_short *)cp;
1013 		crtat = Crtat + cursorat;
1014 
1015 		if (vs.color == 0)
1016 			vs.so_at = FG_BLACK | BG_LIGHTGREY;
1017 		else
1018 			vs.so_at = FG_YELLOW | BG_BLACK;
1019 
1020 		fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1021 	}
1022 
1023 	while (n--) {
1024 		if (!(c = *cp++))
1025 			continue;
1026 
1027 		switch (c) {
1028 		case 0x1B:
1029 			if (vs.state >= VSS_ESCAPE) {
1030 				wrtchar(c, vs.so_at);
1031 				vs.state = 0;
1032 				goto maybe_scroll;
1033 			} else
1034 				vs.state = VSS_ESCAPE;
1035 			break;
1036 
1037 		case 0x9B:	/* CSI */
1038 			vs.cx = vs.cy = 0;
1039 			vs.state = VSS_EBRACE;
1040 			break;
1041 
1042 		case '\t': {
1043 			int inccol = 8 - (vs.col & 7);
1044 			crtat += inccol;
1045 			vs.col += inccol;
1046 		}
1047 		maybe_scroll:
1048 			if (vs.col >= vs.ncol) {
1049 				vs.col -= vs.ncol;
1050 				scroll = 1;
1051 			}
1052 			break;
1053 
1054 		case '\b':
1055 			if (crtat <= Crtat)
1056 				break;
1057 			--crtat;
1058 			if (--vs.col < 0)
1059 				vs.col += vs.ncol;	/* non-destructive backspace */
1060 			break;
1061 
1062 		case '\r':
1063 			crtat -= vs.col;
1064 			vs.col = 0;
1065 			break;
1066 
1067 		case '\n':
1068 			crtat += vs.ncol;
1069 			scroll = 1;
1070 			break;
1071 
1072 		default:
1073 			switch (vs.state) {
1074 			case 0:
1075 				if (c == '\a')
1076 					sysbeep(BEEP_FREQ, BEEP_TIME);
1077 				else {
1078 					/*
1079 					 * If we're outputting multiple printed
1080 					 * characters, just blast them to the
1081 					 * screen until we reach the end of the
1082 					 * buffer or a control character.  This
1083 					 * saves time by short-circuiting the
1084 					 * switch.
1085 					 * If we reach the end of the line, we
1086 					 * break to do a scroll check.
1087 					 */
1088 					for (;;) {
1089 						if (c & 0x80)
1090 							c = iso2ibm437[c&0x7f];
1091 
1092 						if (vs.so)
1093 							wrtchar(c, vs.so_at);
1094 						else
1095 							wrtchar(c, vs.at);
1096 						if (vs.col >= vs.ncol) {
1097 							vs.col = 0;
1098 							scroll = 1;
1099 							break;
1100 						}
1101 						if (!n || (c = *cp) < ' ')
1102 							break;
1103 						n--, cp++;
1104 					}
1105 				}
1106 				break;
1107 			case VSS_ESCAPE:
1108 				switch (c) {
1109 					case '[': /* Start ESC [ sequence */
1110 						vs.cx = vs.cy = 0;
1111 						vs.state = VSS_EBRACE;
1112 						break;
1113 					case 'c': /* Create screen & home */
1114 						fillw((vs.at << 8) | ' ',
1115 						    Crtat, vs.nchr);
1116 						crtat = Crtat;
1117 						vs.col = 0;
1118 						vs.state = 0;
1119 						break;
1120 					case '7': /* save cursor pos */
1121 						vs.offset = crtat - Crtat;
1122 						vs.state = 0;
1123 						break;
1124 					case '8': /* restore cursor pos */
1125 						crtat = Crtat + vs.offset;
1126 						vs.row = vs.offset / vs.ncol;
1127 						vs.col = vs.offset % vs.ncol;
1128 						vs.state = 0;
1129 						break;
1130 					default: /* Invalid, clear state */
1131 						wrtchar(c, vs.so_at);
1132 						vs.state = 0;
1133 						goto maybe_scroll;
1134 				}
1135 				break;
1136 
1137 			default: /* VSS_EBRACE or VSS_EPARAM */
1138 				switch (c) {
1139 					int pos;
1140 				case 'm':
1141 					if (!vs.cx)
1142 						vs.so = 0;
1143 					else
1144 						vs.so = 1;
1145 					vs.state = 0;
1146 					break;
1147 				case 'A': { /* back cx rows */
1148 					int cx = vs.cx;
1149 					if (cx <= 0)
1150 						cx = 1;
1151 					else
1152 						cx %= vs.nrow;
1153 					pos = crtat - Crtat;
1154 					pos -= vs.ncol * cx;
1155 					if (pos < 0)
1156 						pos += vs.nchr;
1157 					crtat = Crtat + pos;
1158 					vs.state = 0;
1159 					break;
1160 				}
1161 				case 'B': { /* down cx rows */
1162 					int cx = vs.cx;
1163 					if (cx <= 0)
1164 						cx = 1;
1165 					else
1166 						cx %= vs.nrow;
1167 					pos = crtat - Crtat;
1168 					pos += vs.ncol * cx;
1169 					if (pos >= vs.nchr)
1170 						pos -= vs.nchr;
1171 					crtat = Crtat + pos;
1172 					vs.state = 0;
1173 					break;
1174 				}
1175 				case 'C': { /* right cursor */
1176 					int cx = vs.cx,
1177 					    col = vs.col;
1178 					if (cx <= 0)
1179 						cx = 1;
1180 					else
1181 						cx %= vs.ncol;
1182 					pos = crtat - Crtat;
1183 					pos += cx;
1184 					col += cx;
1185 					if (col >= vs.ncol) {
1186 						pos -= vs.ncol;
1187 						col -= vs.ncol;
1188 					}
1189 					vs.col = col;
1190 					crtat = Crtat + pos;
1191 					vs.state = 0;
1192 					break;
1193 				}
1194 				case 'D': { /* left cursor */
1195 					int cx = vs.cx,
1196 					    col = vs.col;
1197 					if (cx <= 0)
1198 						cx = 1;
1199 					else
1200 						cx %= vs.ncol;
1201 					pos = crtat - Crtat;
1202 					pos -= cx;
1203 					col -= cx;
1204 					if (col < 0) {
1205 						pos += vs.ncol;
1206 						col += vs.ncol;
1207 					}
1208 					vs.col = col;
1209 					crtat = Crtat + pos;
1210 					vs.state = 0;
1211 					break;
1212 				}
1213 				case 'J': /* Clear ... */
1214 					switch (vs.cx) {
1215 					case 0:
1216 						/* ... to end of display */
1217 						fillw((vs.at << 8) | ' ',
1218 						    crtat,
1219 						    Crtat + vs.nchr - crtat);
1220 						break;
1221 					case 1:
1222 						/* ... to next location */
1223 						fillw((vs.at << 8) | ' ',
1224 						    Crtat,
1225 						    crtat - Crtat + 1);
1226 						break;
1227 					case 2:
1228 						/* ... whole display */
1229 						fillw((vs.at << 8) | ' ',
1230 						    Crtat,
1231 						    vs.nchr);
1232 						break;
1233 					}
1234 					vs.state = 0;
1235 					break;
1236 				case 'K': /* Clear line ... */
1237 					switch (vs.cx) {
1238 					case 0:
1239 						/* ... current to EOL */
1240 						fillw((vs.at << 8) | ' ',
1241 						    crtat,
1242 						    vs.ncol - vs.col);
1243 						break;
1244 					case 1:
1245 						/* ... beginning to next */
1246 						fillw((vs.at << 8) | ' ',
1247 						    crtat - vs.col,
1248 						    vs.col + 1);
1249 						break;
1250 					case 2:
1251 						/* ... entire line */
1252 						fillw((vs.at << 8) | ' ',
1253 						    crtat - vs.col, vs.ncol);
1254 						break;
1255 					}
1256 					vs.state = 0;
1257 					break;
1258 				case 'f': /* in system V consoles */
1259 				case 'H': { /* Cursor move */
1260 					int cx = vs.cx,
1261 					    cy = vs.cy;
1262 					if (!cx || !cy) {
1263 						crtat = Crtat;
1264 						vs.col = 0;
1265 					} else {
1266 						if (cx > vs.nrow)
1267 							cx = vs.nrow;
1268 						if (cy > vs.ncol)
1269 							cy = vs.ncol;
1270 						crtat = Crtat +
1271 						    (cx - 1) * vs.ncol + cy - 1;
1272 						vs.col = cy - 1;
1273 					}
1274 					vs.state = 0;
1275 					break;
1276 				}
1277 				case 'M': { /* delete cx rows */
1278 					u_short *crtAt = crtat - vs.col;
1279 					int cx = vs.cx,
1280 					    row = (crtAt - Crtat) / vs.ncol,
1281 					    nrow = vs.nrow - row;
1282 					if (cx <= 0)
1283 						cx = 1;
1284 					else if (cx > nrow)
1285 						cx = nrow;
1286 					if (cx < nrow)
1287 #ifdef PCCONS_FORCE_WORD
1288 						wcopy(crtAt + vs.ncol * cx,
1289 						    crtAt, vs.ncol * (nrow -
1290 						    cx) * CHR);
1291 #else
1292 						bcopy(crtAt + vs.ncol * cx,
1293 						    crtAt, vs.ncol * (nrow -
1294 						    cx) * CHR);
1295 #endif
1296 					fillw((vs.at << 8) | ' ',
1297 					    crtAt + vs.ncol * (nrow - cx),
1298 					    vs.ncol * cx);
1299 					vs.state = 0;
1300 					break;
1301 				}
1302 				case 'S': { /* scroll up cx lines */
1303 					int cx = vs.cx;
1304 					if (cx <= 0)
1305 						cx = 1;
1306 					else if (cx > vs.nrow)
1307 						cx = vs.nrow;
1308 					if (cx < vs.nrow)
1309 #ifdef PCCONS_FORCE_WORD
1310 						wcopy(Crtat + vs.ncol * cx,
1311 						    Crtat, vs.ncol * (vs.nrow -
1312 						    cx) * CHR);
1313 #else
1314 						bcopy(Crtat + vs.ncol * cx,
1315 						    Crtat, vs.ncol * (vs.nrow -
1316 						    cx) * CHR);
1317 #endif
1318 					fillw((vs.at << 8) | ' ',
1319 					    Crtat + vs.ncol * (vs.nrow - cx),
1320 					    vs.ncol * cx);
1321 					/* crtat -= vs.ncol * cx; XXX */
1322 					vs.state = 0;
1323 					break;
1324 				}
1325 				case 'L': { /* insert cx rows */
1326 					u_short *crtAt = crtat - vs.col;
1327 					int cx = vs.cx,
1328 					    row = (crtAt - Crtat) / vs.ncol,
1329 					    nrow = vs.nrow - row;
1330 					if (cx <= 0)
1331 						cx = 1;
1332 					else if (cx > nrow)
1333 						cx = nrow;
1334 					if (cx < nrow)
1335 #ifdef PCCONS_FORCE_WORD
1336 						wcopy(crtAt,
1337 						    crtAt + vs.ncol * cx,
1338 						    vs.ncol * (nrow - cx) *
1339 						    CHR);
1340 #else
1341 						bcopy(crtAt,
1342 						    crtAt + vs.ncol * cx,
1343 						    vs.ncol * (nrow - cx) *
1344 						    CHR);
1345 #endif
1346 					fillw((vs.at << 8) | ' ', crtAt,
1347 					    vs.ncol * cx);
1348 					vs.state = 0;
1349 					break;
1350 				}
1351 				case 'T': { /* scroll down cx lines */
1352 					int cx = vs.cx;
1353 					if (cx <= 0)
1354 						cx = 1;
1355 					else if (cx > vs.nrow)
1356 						cx = vs.nrow;
1357 					if (cx < vs.nrow)
1358 #ifdef PCCONS_FORCE_WORD
1359 						wcopy(Crtat,
1360 						    Crtat + vs.ncol * cx,
1361 						    vs.ncol * (vs.nrow - cx) *
1362 						    CHR);
1363 #else
1364 						bcopy(Crtat,
1365 						    Crtat + vs.ncol * cx,
1366 						    vs.ncol * (vs.nrow - cx) *
1367 						    CHR);
1368 #endif
1369 					fillw((vs.at << 8) | ' ', Crtat,
1370 					    vs.ncol * cx);
1371 					/* crtat += vs.ncol * cx; XXX */
1372 					vs.state = 0;
1373 					break;
1374 				}
1375 				case ';': /* Switch params in cursor def */
1376 					vs.state = VSS_EPARAM;
1377 					break;
1378 				case 'r':
1379 					vs.so_at = (vs.cx & FG_MASK) |
1380 					    ((vs.cy << 4) & BG_MASK);
1381 					vs.state = 0;
1382 					break;
1383 				case 's': /* save cursor pos */
1384 					vs.offset = crtat - Crtat;
1385 					vs.state = 0;
1386 					break;
1387 				case 'u': /* restore cursor pos */
1388 					crtat = Crtat + vs.offset;
1389 					vs.row = vs.offset / vs.ncol;
1390 					vs.col = vs.offset % vs.ncol;
1391 					vs.state = 0;
1392 					break;
1393 				case 'x': /* set attributes */
1394 					switch (vs.cx) {
1395 					case 0:
1396 						vs.at = FG_LIGHTGREY | BG_BLACK;
1397 						break;
1398 					case 1:
1399 						/* ansi background */
1400 						if (!vs.color)
1401 							break;
1402 						vs.at &= FG_MASK;
1403 						vs.at |= bgansitopc[vs.cy & 7];
1404 						break;
1405 					case 2:
1406 						/* ansi foreground */
1407 						if (!vs.color)
1408 							break;
1409 						vs.at &= BG_MASK;
1410 						vs.at |= fgansitopc[vs.cy & 7];
1411 						break;
1412 					case 3:
1413 						/* pc text attribute */
1414 						if (vs.state >= VSS_EPARAM)
1415 							vs.at = vs.cy;
1416 						break;
1417 					}
1418 					vs.state = 0;
1419 					break;
1420 
1421 				default: /* Only numbers valid here */
1422 					if ((c >= '0') && (c <= '9')) {
1423 						if (vs.state >= VSS_EPARAM) {
1424 							vs.cy *= 10;
1425 							vs.cy += c - '0';
1426 						} else {
1427 							vs.cx *= 10;
1428 							vs.cx += c - '0';
1429 						}
1430 					} else
1431 						vs.state = 0;
1432 					break;
1433 				}
1434 				break;
1435 			}
1436 		}
1437 		if (scroll) {
1438 			scroll = 0;
1439 			/* scroll check */
1440 			if (crtat >= Crtat + vs.nchr) {
1441 				if (!kernel) {
1442 					int s = spltty();
1443 					if (lock_state & KB_SCROLL)
1444 						tsleep(&lock_state,
1445 						    PUSER, "pcputc", 0);
1446 					splx(s);
1447 				}
1448 #if PCCONS_FORCE_WORD
1449 				wcopy(Crtat + vs.ncol, Crtat,
1450 				    (vs.nchr - vs.ncol) * CHR);
1451 #else
1452 				bcopy(Crtat + vs.ncol, Crtat,
1453 				    (vs.nchr - vs.ncol) * CHR);
1454 #endif
1455 				fillw((vs.at << 8) | ' ',
1456 				    Crtat + vs.nchr - vs.ncol,
1457 				    vs.ncol);
1458 				crtat -= vs.ncol;
1459 			}
1460 		}
1461 	}
1462 	async_update();
1463 }
1464 
1465 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1466    left and right shift when reading the keyboard map */
1467 static pccons_keymap_t	scan_codes[KB_NUM_KEYS] = {
1468 /*  type       unshift   shift     control   altgr     shift_altgr scancode */
1469   { KB_NONE,   "",       "",       "",       "",       ""}, /* 0 unused */
1470   { KB_ASCII,  "\033",   "\033",   "\033",   "",       ""}, /* 1 ESCape */
1471   { KB_ASCII,  "1",      "!",      "!",      "",       ""}, /* 2 1 */
1472   { KB_ASCII,  "2",      "@",      "\000",   "",       ""}, /* 3 2 */
1473   { KB_ASCII,  "3",      "#",      "#",      "",       ""}, /* 4 3 */
1474   { KB_ASCII,  "4",      "$",      "$",      "",       ""}, /* 5 4 */
1475   { KB_ASCII,  "5",      "%",      "%",      "",       ""}, /* 6 5 */
1476   { KB_ASCII,  "6",      "^",      "\036",   "",       ""}, /* 7 6 */
1477   { KB_ASCII,  "7",      "&",      "&",      "",       ""}, /* 8 7 */
1478   { KB_ASCII,  "8",      "*",      "\010",   "",       ""}, /* 9 8 */
1479   { KB_ASCII,  "9",      "(",      "(",      "",       ""}, /* 10 9 */
1480   { KB_ASCII,  "0",      ")",      ")",      "",       ""}, /* 11 0 */
1481   { KB_ASCII,  "-",      "_",      "\037",   "",       ""}, /* 12 - */
1482   { KB_ASCII,  "=",      "+",      "+",      "",       ""}, /* 13 = */
1483   { KB_ASCII,  "\177",   "\177",   "\010",   "",       ""}, /* 14 backspace */
1484   { KB_ASCII,  "\t",     "\t",     "\t",     "",       ""}, /* 15 tab */
1485   { KB_ASCII,  "q",      "Q",      "\021",   "",       ""}, /* 16 q */
1486   { KB_ASCII,  "w",      "W",      "\027",   "",       ""}, /* 17 w */
1487   { KB_ASCII,  "e",      "E",      "\005",   "",       ""}, /* 18 e */
1488   { KB_ASCII,  "r",      "R",      "\022",   "",       ""}, /* 19 r */
1489   { KB_ASCII,  "t",      "T",      "\024",   "",       ""}, /* 20 t */
1490   { KB_ASCII,  "y",      "Y",      "\031",   "",       ""}, /* 21 y */
1491   { KB_ASCII,  "u",      "U",      "\025",   "",       ""}, /* 22 u */
1492   { KB_ASCII,  "i",      "I",      "\011",   "",       ""}, /* 23 i */
1493   { KB_ASCII,  "o",      "O",      "\017",   "",       ""}, /* 24 o */
1494   { KB_ASCII,  "p",      "P",      "\020",   "",       ""}, /* 25 p */
1495   { KB_ASCII,  "[",      "{",      "\033",   "",       ""}, /* 26 [ */
1496   { KB_ASCII,  "]",      "}",      "\035",   "",       ""}, /* 27 ] */
1497   { KB_ASCII,  "\r",     "\r",     "\n",     "",       ""}, /* 28 return */
1498   { KB_CTL,    "",       "",       "",       "",       ""}, /* 29 control */
1499   { KB_ASCII,  "a",      "A",      "\001",   "",       ""}, /* 30 a */
1500   { KB_ASCII,  "s",      "S",      "\023",   "",       ""}, /* 31 s */
1501   { KB_ASCII,  "d",      "D",      "\004",   "",       ""}, /* 32 d */
1502   { KB_ASCII,  "f",      "F",      "\006",   "",       ""}, /* 33 f */
1503   { KB_ASCII,  "g",      "G",      "\007",   "",       ""}, /* 34 g */
1504   { KB_ASCII,  "h",      "H",      "\010",   "",       ""}, /* 35 h */
1505   { KB_ASCII,  "j",      "J",      "\n",     "",       ""}, /* 36 j */
1506   { KB_ASCII,  "k",      "K",      "\013",   "",       ""}, /* 37 k */
1507   { KB_ASCII,  "l",      "L",      "\014",   "",       ""}, /* 38 l */
1508   { KB_ASCII,  ";",      ":",      ";",      "",       ""}, /* 39 ; */
1509   { KB_ASCII,  "'",      "\"",     "'",      "",       ""}, /* 40 ' */
1510   { KB_ASCII,  "`",      "~",      "`",      "",       ""}, /* 41 ` */
1511   { KB_SHIFT,  "\001",   "",       "",       "",       ""}, /* 42 shift */
1512   { KB_ASCII,  "\\",     "|",      "\034",   "",       ""}, /* 43 \ */
1513   { KB_ASCII,  "z",      "Z",      "\032",   "",       ""}, /* 44 z */
1514   { KB_ASCII,  "x",      "X",      "\030",   "",       ""}, /* 45 x */
1515   { KB_ASCII,  "c",      "C",      "\003",   "",       ""}, /* 46 c */
1516   { KB_ASCII,  "v",      "V",      "\026",   "",       ""}, /* 47 v */
1517   { KB_ASCII,  "b",      "B",      "\002",   "",       ""}, /* 48 b */
1518   { KB_ASCII,  "n",      "N",      "\016",   "",       ""}, /* 49 n */
1519   { KB_ASCII,  "m",      "M",      "\r",     "",       ""}, /* 50 m */
1520   { KB_ASCII,  ",",      "<",      "<",      "",       ""}, /* 51 , */
1521   { KB_ASCII,  ".",      ">",      ">",      "",       ""}, /* 52 . */
1522   { KB_ASCII,  "/",      "?",      "\037",   "",       ""}, /* 53 / */
1523   { KB_SHIFT,  "\002",   "",       "",       "",       ""}, /* 54 shift */
1524   { KB_KP,     "*",      "*",      "*",      "",       ""}, /* 55 kp * */
1525   { KB_ALT,    "",       "",       "",       "",       ""}, /* 56 alt */
1526   { KB_ASCII,  " ",      " ",      "\000",   "",       ""}, /* 57 space */
1527   { KB_CAPS,   "",       "",       "",       "",       ""}, /* 58 caps */
1528   { KB_FUNC,   "\033[M", "\033[Y", "\033[k", "",       ""}, /* 59 f1 */
1529   { KB_FUNC,   "\033[N", "\033[Z", "\033[l", "",       ""}, /* 60 f2 */
1530   { KB_FUNC,   "\033[O", "\033[a", "\033[m", "",       ""}, /* 61 f3 */
1531   { KB_FUNC,   "\033[P", "\033[b", "\033[n", "",       ""}, /* 62 f4 */
1532   { KB_FUNC,   "\033[Q", "\033[c", "\033[o", "",       ""}, /* 63 f5 */
1533   { KB_FUNC,   "\033[R", "\033[d", "\033[p", "",       ""}, /* 64 f6 */
1534   { KB_FUNC,   "\033[S", "\033[e", "\033[q", "",       ""}, /* 65 f7 */
1535   { KB_FUNC,   "\033[T", "\033[f", "\033[r", "",       ""}, /* 66 f8 */
1536   { KB_FUNC,   "\033[U", "\033[g", "\033[s", "",       ""}, /* 67 f9 */
1537   { KB_FUNC,   "\033[V", "\033[h", "\033[t", "",       ""}, /* 68 f10 */
1538   { KB_NUM,    "",       "",       "",       "",       ""}, /* 69 num lock */
1539   { KB_SCROLL, "",       "",       "",       "",       ""}, /* 70 scroll lock */
1540   { KB_KP,     "7",      "\033[H", "7",      "",       ""}, /* 71 kp 7 */
1541   { KB_KP,     "8",      "\033[A", "8",      "",       ""}, /* 72 kp 8 */
1542   { KB_KP,     "9",      "\033[I", "9",      "",       ""}, /* 73 kp 9 */
1543   { KB_KP,     "-",      "-",      "-",      "",       ""}, /* 74 kp - */
1544   { KB_KP,     "4",      "\033[D", "4",      "",       ""}, /* 75 kp 4 */
1545   { KB_KP,     "5",      "\033[E", "5",      "",       ""}, /* 76 kp 5 */
1546   { KB_KP,     "6",      "\033[C", "6",      "",       ""}, /* 77 kp 6 */
1547   { KB_KP,     "+",      "+",      "+",      "",       ""}, /* 78 kp + */
1548   { KB_KP,     "1",      "\033[F", "1",      "",       ""}, /* 79 kp 1 */
1549   { KB_KP,     "2",      "\033[B", "2",      "",       ""}, /* 80 kp 2 */
1550   { KB_KP,     "3",      "\033[G", "3",      "",       ""}, /* 81 kp 3 */
1551   { KB_KP,     "0",      "\033[L", "0",      "",       ""}, /* 82 kp 0 */
1552   { KB_KP,     ",",      "\177",   ",",      "",       ""}, /* 83 kp , */
1553   { KB_NONE,   "",       "",       "",       "",       ""}, /* 84 0 */
1554   { KB_NONE,   "",       "",       "",       "",       ""}, /* 85 0 */
1555   { KB_NONE,   "",       "",       "",       "",       ""}, /* 86 0 */
1556   { KB_FUNC,   "\033[W", "\033[i", "\033[u", "",       ""}, /* 87 f11 */
1557   { KB_FUNC,   "\033[X", "\033[j", "\033[v", "",       ""}, /* 88 f12 */
1558   { KB_NONE,   "",       "",       "",       "",       ""}, /* 89 0 */
1559   { KB_NONE,   "",       "",       "",       "",       ""}, /* 90 0 */
1560   { KB_NONE,   "",       "",       "",       "",       ""}, /* 91 0 */
1561   { KB_NONE,   "",       "",       "",       "",       ""}, /* 92 0 */
1562   { KB_NONE,   "",       "",       "",       "",       ""}, /* 93 0 */
1563   { KB_NONE,   "",       "",       "",       "",       ""}, /* 94 0 */
1564   { KB_NONE,   "",       "",       "",       "",       ""}, /* 95 0 */
1565   { KB_NONE,   "",       "",       "",       "",       ""}, /* 96 0 */
1566   { KB_NONE,   "",       "",       "",       "",       ""}, /* 97 0 */
1567   { KB_NONE,   "",       "",       "",       "",       ""}, /* 98 0 */
1568   { KB_NONE,   "",       "",       "",       "",       ""}, /* 99 0 */
1569   { KB_NONE,   "",       "",       "",       "",       ""}, /* 100 */
1570   { KB_NONE,   "",       "",       "",       "",       ""}, /* 101 */
1571   { KB_NONE,   "",       "",       "",       "",       ""}, /* 102 */
1572   { KB_NONE,   "",       "",       "",       "",       ""}, /* 103 */
1573   { KB_NONE,   "",       "",       "",       "",       ""}, /* 104 */
1574   { KB_NONE,   "",       "",       "",       "",       ""}, /* 105 */
1575   { KB_NONE,   "",       "",       "",       "",       ""}, /* 106 */
1576   { KB_NONE,   "",       "",       "",       "",       ""}, /* 107 */
1577   { KB_NONE,   "",       "",       "",       "",       ""}, /* 108 */
1578   { KB_NONE,   "",       "",       "",       "",       ""}, /* 109 */
1579   { KB_NONE,   "",       "",       "",       "",       ""}, /* 110 */
1580   { KB_NONE,   "",       "",       "",       "",       ""}, /* 111 */
1581   { KB_NONE,   "",       "",       "",       "",       ""}, /* 112 */
1582   { KB_NONE,   "",       "",       "",       "",       ""}, /* 113 */
1583   { KB_NONE,   "",       "",       "",       "",       ""}, /* 114 */
1584   { KB_NONE,   "",       "",       "",       "",       ""}, /* 115 */
1585   { KB_NONE,   "",       "",       "",       "",       ""}, /* 116 */
1586   { KB_NONE,   "",       "",       "",       "",       ""}, /* 117 */
1587   { KB_NONE,   "",       "",       "",       "",       ""}, /* 118 */
1588   { KB_NONE,   "",       "",       "",       "",       ""}, /* 119 */
1589   { KB_NONE,   "",       "",       "",       "",       ""}, /* 120 */
1590   { KB_NONE,   "",       "",       "",       "",       ""}, /* 121 */
1591   { KB_NONE,   "",       "",       "",       "",       ""}, /* 122 */
1592   { KB_NONE,   "",       "",       "",       "",       ""}, /* 123 */
1593   { KB_NONE,   "",       "",       "",       "",       ""}, /* 124 */
1594   { KB_NONE,   "",       "",       "",       "",       ""}, /* 125 */
1595   { KB_NONE,   "",       "",       "",       "",       ""}, /* 126 */
1596   { KB_NONE,   "",       "",       "",       "",       ""}  /* 127 */
1597 };
1598 
1599 /*
1600  * Get characters from the keyboard.  If none are present, return NULL.
1601  */
1602 char *
1603 sget()
1604 {
1605 	u_char dt;
1606 	static u_char extended = 0, shift_state = 0;
1607 	static u_char capchar[2];
1608 
1609 top:
1610 	KBD_DELAY;
1611 	dt = kbd_data_read_1();
1612 
1613 	switch (dt) {
1614 	case KBR_ACK: case KBR_ECHO:
1615 		kb_oq_get = (kb_oq_get + 1) & 7;
1616 		if(kb_oq_get != kb_oq_put) {
1617 			kbd_data_write_1(kb_oq[kb_oq_get]);
1618 		}
1619 		goto loop;
1620 	case KBR_RESEND:
1621 		kbd_data_write_1(kb_oq[kb_oq_get]);
1622 		goto loop;
1623 	}
1624 
1625 	if (pc_xmode > 0) {
1626 #if defined(DDB) && defined(XSERVER_DDB)
1627 		/* F12 enters the debugger while in X mode */
1628 		if (dt == 88)
1629 			Debugger();
1630 #endif
1631 		capchar[0] = dt;
1632 		capchar[1] = 0;
1633 		/*
1634 		 * Check for locking keys.
1635 		 *
1636 		 * XXX Setting the LEDs this way is a bit bogus.  What if the
1637 		 * keyboard has been remapped in X?
1638 		 */
1639 		switch (scan_codes[dt & 0x7f].type) {
1640 		case KB_NUM:
1641 			if (dt & 0x80) {
1642 				shift_state &= ~KB_NUM;
1643 				break;
1644 			}
1645 			if (shift_state & KB_NUM)
1646 				break;
1647 			shift_state |= KB_NUM;
1648 			lock_state ^= KB_NUM;
1649 			async_update();
1650 			break;
1651 		case KB_CAPS:
1652 			if (dt & 0x80) {
1653 				shift_state &= ~KB_CAPS;
1654 				break;
1655 			}
1656 			if (shift_state & KB_CAPS)
1657 				break;
1658 			shift_state |= KB_CAPS;
1659 			lock_state ^= KB_CAPS;
1660 			async_update();
1661 			break;
1662 		case KB_SCROLL:
1663 			if (dt & 0x80) {
1664 				shift_state &= ~KB_SCROLL;
1665 				break;
1666 			}
1667 			if (shift_state & KB_SCROLL)
1668 				break;
1669 			shift_state |= KB_SCROLL;
1670 			lock_state ^= KB_SCROLL;
1671 			if ((lock_state & KB_SCROLL) == 0)
1672 				wakeup((caddr_t)&lock_state);
1673 			async_update();
1674 			break;
1675 		}
1676 		return capchar;
1677 	}
1678 
1679 	switch (dt) {
1680 	case KBR_EXTENDED:
1681 		extended = 1;
1682 		goto loop;
1683 	}
1684 
1685 #ifdef DDB
1686 	/*
1687 	 * Check for cntl-alt-esc.
1688 	 */
1689 	if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1690 		/* XXX - check pccons_is_console */
1691 		Debugger();
1692 		dt |= 0x80;	/* discard esc (ddb discarded ctl-alt) */
1693 	}
1694 #endif
1695 
1696 	/*
1697 	 * Check for make/break.
1698 	 */
1699 	if (dt & 0x80) {
1700 		/*
1701 		 * break
1702 		 */
1703 		dt &= 0x7f;
1704 		switch (scan_codes[dt].type) {
1705 		case KB_NUM:
1706 			shift_state &= ~KB_NUM;
1707 			break;
1708 		case KB_CAPS:
1709 			shift_state &= ~KB_CAPS;
1710 			break;
1711 		case KB_SCROLL:
1712 			shift_state &= ~KB_SCROLL;
1713 			break;
1714 		case KB_SHIFT:
1715 			shift_state &= ~KB_SHIFT;
1716 			break;
1717 		case KB_ALT:
1718 			if (extended)
1719 				shift_state &= ~KB_ALTGR;
1720 			else
1721 				shift_state &= ~KB_ALT;
1722 			break;
1723 		case KB_CTL:
1724 			shift_state &= ~KB_CTL;
1725 			break;
1726 		}
1727 	} else {
1728 		/*
1729 		 * make
1730 		 */
1731 		switch (scan_codes[dt].type) {
1732 		/*
1733 		 * locking keys
1734 		 */
1735 		case KB_NUM:
1736 			if (shift_state & KB_NUM)
1737 				break;
1738 			shift_state |= KB_NUM;
1739 			lock_state ^= KB_NUM;
1740 			async_update();
1741 			break;
1742 		case KB_CAPS:
1743 			if (shift_state & KB_CAPS)
1744 				break;
1745 			shift_state |= KB_CAPS;
1746 			lock_state ^= KB_CAPS;
1747 			async_update();
1748 			break;
1749 		case KB_SCROLL:
1750 			if (shift_state & KB_SCROLL)
1751 				break;
1752 			shift_state |= KB_SCROLL;
1753 			lock_state ^= KB_SCROLL;
1754 			if ((lock_state & KB_SCROLL) == 0)
1755 				wakeup((caddr_t)&lock_state);
1756 			async_update();
1757 			break;
1758 		/*
1759 		 * non-locking keys
1760 		 */
1761 		case KB_SHIFT:
1762 			shift_state |= KB_SHIFT;
1763 			break;
1764 		case KB_ALT:
1765 			if (extended)
1766 				shift_state |= KB_ALTGR;
1767 			else
1768 				shift_state |= KB_ALT;
1769 			break;
1770 		case KB_CTL:
1771 			shift_state |= KB_CTL;
1772 			break;
1773 		case KB_ASCII:
1774 			/* control has highest priority */
1775 			if (shift_state & KB_CTL)
1776 				capchar[0] = scan_codes[dt].ctl[0];
1777 			else if (shift_state & KB_ALTGR) {
1778 				if (shift_state & KB_SHIFT)
1779 					capchar[0] = scan_codes[dt].shift_altgr[0];
1780 				else
1781 					capchar[0] = scan_codes[dt].altgr[0];
1782 			}
1783 			else {
1784 				if (shift_state & KB_SHIFT)
1785 					capchar[0] = scan_codes[dt].shift[0];
1786 				else
1787 					capchar[0] = scan_codes[dt].unshift[0];
1788 			}
1789 			if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1790 			    capchar[0] <= 'z') {
1791 				capchar[0] -= ('a' - 'A');
1792 			}
1793 			capchar[0] |= (shift_state & KB_ALT);
1794 			extended = 0;
1795 			return capchar;
1796 		case KB_NONE:
1797 printf("keycode %d\n",dt);
1798 			break;
1799 		case KB_FUNC: {
1800 			char *more_chars;
1801 			if (shift_state & KB_SHIFT)
1802 				more_chars = scan_codes[dt].shift;
1803 			else if (shift_state & KB_CTL)
1804 				more_chars = scan_codes[dt].ctl;
1805 			else
1806 				more_chars = scan_codes[dt].unshift;
1807 			extended = 0;
1808 			return more_chars;
1809 		}
1810 		case KB_KP: {
1811 			char *more_chars;
1812 			if (shift_state & (KB_SHIFT | KB_CTL) ||
1813 			    (lock_state & KB_NUM) == 0 || extended)
1814 				more_chars = scan_codes[dt].shift;
1815 			else
1816 				more_chars = scan_codes[dt].unshift;
1817 			extended = 0;
1818 			return more_chars;
1819 		}
1820 		}
1821 	}
1822 
1823 	extended = 0;
1824 loop:
1825 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
1826 		return 0;
1827 	goto top;
1828 }
1829 
1830 paddr_t
1831 pcmmap(dev, offset, nprot)
1832 	dev_t dev;
1833 	off_t offset;
1834 	int nprot;
1835 {
1836 	struct pccons_context *pc = &pccons_console_context;
1837 	paddr_t pa;
1838 
1839 	if (offset >= 0xa0000 && offset < 0xc0000) {
1840 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1841 			return (-1);
1842 		pa += offset - pc->pc_config->pc_mono_memaddr;
1843 		return (mips_btop(pa));
1844 	}
1845 	if (offset >= 0x0000 && offset < 0x10000) {
1846 		if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
1847 			return (-1);
1848 		pa += offset - pc->pc_config->pc_mono_iobase;
1849 		return (mips_btop(pa));
1850 	}
1851 	if (offset >= 0x40000000 && offset < 0x40800000) {
1852 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1853 			return (-1);
1854 		pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
1855 		return (mips_btop(pa));
1856 	}
1857 	return (-1);
1858 }
1859 
1860 void
1861 pc_xmode_on()
1862 {
1863 	if (pc_xmode)
1864 		return;
1865 	pc_xmode = 1;
1866 
1867 #ifdef XFREE86_BUG_COMPAT
1868 	/* If still unchanged, get current shape. */
1869 	if (cursor_shape == 0xffff)
1870 		get_cursor_shape();
1871 #endif
1872 }
1873 
1874 void
1875 pc_xmode_off()
1876 {
1877 	if (pc_xmode == 0)
1878 		return;
1879 	pc_xmode = 0;
1880 
1881 #ifdef XFREE86_BUG_COMPAT
1882 	/* XXX It would be hard to justify why the X server doesn't do this. */
1883 	set_cursor_shape();
1884 #endif
1885 	async_update();
1886 }
1887