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