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