xref: /netbsd-src/sys/arch/arc/dev/pccons.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: pccons.c,v 1.56 2008/09/13 17:13:57 tsutsui 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.56 2008/09/13 17:13:57 tsutsui 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 value.
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 		memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
775 		return 0;
776 	}
777 	case CONSOLE_GET_KEYMAP:
778 		if (!data)
779 			return EINVAL;
780 		memcpy(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 	struct clist *cl;
796 	int s, len;
797 	u_char buf[PCBURST];
798 
799 	s = spltty();
800 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
801 		goto out;
802 	tp->t_state |= TS_BUSY;
803 	splx(s);
804 	/*
805 	 * We need to do this outside spl since it could be fairly
806 	 * expensive and we don't want our serial ports to overflow.
807 	 */
808 	cl = &tp->t_outq;
809 	len = q_to_b(cl, buf, PCBURST);
810 	sput(buf, len);
811 	s = spltty();
812 	tp->t_state &= ~TS_BUSY;
813 	if (ttypull(tp)) {
814 		tp->t_state |= TS_TIMEOUT;
815 		callout_schedule(&tp->t_rstrt_ch, 1);
816 	}
817 out:
818 	splx(s);
819 }
820 
821 /* ARGSUSED */
822 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
823     bus_space_tag_t kbd_iot, struct pccons_config *config)
824 {
825 	int maj;
826 	static struct consdev pccons = {
827 		NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
828 		    NULL, NODEV, CN_NORMAL
829 	};
830 
831 	/*
832 	 * For now, don't screw with it.
833 	 */
834 	/* crtat = 0; */
835 
836 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
837 
838 	/* locate the major number */
839 	maj = cdevsw_lookup_major(&pc_cdevsw);
840 	pccons.cn_dev = makedev(maj, 0);
841 
842 	cn_tab = &pccons;
843 }
844 
845 /* ARGSUSED */
846 void
847 pccnputc(dev_t dev, int c)
848 {
849 	u_char cc, oldkernel = kernel;
850 
851 	kernel = 1;
852 	if (c == '\n') {
853 		sput("\r\n", 2);
854 	} else {
855 		cc = c;
856 		sput(&cc, 1);
857 	}
858 	kernel = oldkernel;
859 }
860 
861 /* ARGSUSED */
862 int
863 pccngetc(dev_t dev)
864 {
865 	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_t dev, int on)
883 {
884 
885 	polling = on;
886 	if (!on) {
887 		int unit;
888 		struct pc_softc *sc;
889 		int s;
890 
891 		/*
892 		 * If disabling polling on a device that's been configured,
893 		 * make sure there are no bytes left in the FIFO, holding up
894 		 * the interrupt line.  Otherwise we won't get any further
895 		 * interrupts.
896 		 */
897 		unit = PCUNIT(dev);
898 		if (pc_cd.cd_ndevs > unit) {
899 			sc = device_lookup_private(&pc_cd, unit);
900 			if (sc != NULL) {
901 				s = spltty();
902 				pcintr(sc);
903 				splx(s);
904 			}
905 		}
906 	}
907 }
908 
909 /*
910  * Set line parameters.
911  */
912 int
913 pcparam(struct tty *tp, struct termios *t)
914 {
915 
916 	tp->t_ispeed = t->c_ispeed;
917 	tp->t_ospeed = t->c_ospeed;
918 	tp->t_cflag = t->c_cflag;
919 	return 0;
920 }
921 
922 #define	wrtchar(c, at) do {\
923 	char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
924 } while (0)
925 
926 /* translate ANSI color codes to standard pc ones */
927 static char fgansitopc[] = {
928 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
929 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
930 };
931 
932 static char bgansitopc[] = {
933 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
934 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
935 };
936 
937 static u_char iso2ibm437[] =
938 {
939             0,     0,     0,     0,     0,     0,     0,     0,
940             0,     0,     0,     0,     0,     0,     0,     0,
941             0,     0,     0,     0,     0,     0,     0,     0,
942             0,     0,     0,     0,     0,     0,     0,     0,
943          0xff,  0xad,  0x9b,  0x9c,     0,  0x9d,     0,  0x40,
944          0x6f,  0x63,  0x61,  0xae,     0,     0,     0,     0,
945          0xf8,  0xf1,  0xfd,  0x33,     0,  0xe6,     0,  0xfa,
946             0,  0x31,  0x6f,  0xaf,  0xac,  0xab,     0,  0xa8,
947          0x41,  0x41,  0x41,  0x41,  0x8e,  0x8f,  0x92,  0x80,
948          0x45,  0x90,  0x45,  0x45,  0x49,  0x49,  0x49,  0x49,
949          0x81,  0xa5,  0x4f,  0x4f,  0x4f,  0x4f,  0x99,  0x4f,
950          0x4f,  0x55,  0x55,  0x55,  0x9a,  0x59,     0,  0xe1,
951          0x85,  0xa0,  0x83,  0x61,  0x84,  0x86,  0x91,  0x87,
952          0x8a,  0x82,  0x88,  0x89,  0x8d,  0xa1,  0x8c,  0x8b,
953             0,  0xa4,  0x95,  0xa2,  0x93,  0x6f,  0x94,  0x6f,
954          0x6f,  0x97,  0xa3,  0x96,  0x81,  0x98,     0,     0
955 };
956 
957 /*
958  * `pc3' termcap emulation.
959  */
960 void
961 sput(const u_char *cp, int n)
962 {
963 	struct pccons_context *pc = &pccons_console_context;
964 	u_char c, scroll = 0;
965 
966 	if (pc_xmode > 0)
967 		return;
968 
969 	if (crtat == 0) {
970 		volatile u_short *dp;
971 		u_short was;
972 		unsigned cursorat;
973 
974 		dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
975 		was = *dp;
976 		*dp = 0xA55A;
977 		if (*dp != 0xA55A) {
978 			dp = bus_space_vaddr(pc->pc_crt_memt,
979 			    pc->pc_mono_memh);
980 			pc->pc_6845_ioh = pc->pc_mono_ioh;
981 			pc->pc_crt_memh = pc->pc_mono_memh;
982 			vs.color = 0;
983 		} else {
984 			*dp = was;
985 			pc->pc_6845_ioh = pc->pc_cga_ioh;
986 			pc->pc_crt_memh = pc->pc_cga_memh;
987 			vs.color = 1;
988 		}
989 
990 #ifdef FAT_CURSOR
991 		cursor_shape = 0x0012;
992 #else
993 		get_cursor_shape();
994 #endif
995 
996 		bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
997 		vs.nchr = vs.ncol * vs.nrow;
998 		vs.col--;
999 		vs.row--;
1000 		cursorat = vs.ncol * vs.row + vs.col;
1001 		vs.at = FG_LIGHTGREY | BG_BLACK;
1002 
1003 		Crtat = (u_short *)__UNVOLATILE(dp);
1004 		crtat = Crtat + cursorat;
1005 
1006 		if (vs.color == 0)
1007 			vs.so_at = FG_BLACK | BG_LIGHTGREY;
1008 		else
1009 			vs.so_at = FG_YELLOW | BG_BLACK;
1010 
1011 		fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1012 	}
1013 
1014 	while (n--) {
1015 		if (!(c = *cp++))
1016 			continue;
1017 
1018 		switch (c) {
1019 		case 0x1B:
1020 			if (vs.state >= VSS_ESCAPE) {
1021 				wrtchar(c, vs.so_at);
1022 				vs.state = 0;
1023 				goto maybe_scroll;
1024 			} else
1025 				vs.state = VSS_ESCAPE;
1026 			break;
1027 
1028 		case 0x9B:	/* CSI */
1029 			vs.cx = vs.cy = 0;
1030 			vs.state = VSS_EBRACE;
1031 			break;
1032 
1033 		case '\t': {
1034 			int inccol = 8 - (vs.col & 7);
1035 			crtat += inccol;
1036 			vs.col += inccol;
1037 		}
1038 		maybe_scroll:
1039 			if (vs.col >= vs.ncol) {
1040 				vs.col -= vs.ncol;
1041 				scroll = 1;
1042 			}
1043 			break;
1044 
1045 		case '\b':
1046 			if (crtat <= Crtat)
1047 				break;
1048 			--crtat;
1049 			if (--vs.col < 0)
1050 				vs.col += vs.ncol;	/* non-destructive backspace */
1051 			break;
1052 
1053 		case '\r':
1054 			crtat -= vs.col;
1055 			vs.col = 0;
1056 			break;
1057 
1058 		case '\n':
1059 			crtat += vs.ncol;
1060 			scroll = 1;
1061 			break;
1062 
1063 		default:
1064 			switch (vs.state) {
1065 			case 0:
1066 				if (c == '\a')
1067 					sysbeep(BEEP_FREQ, BEEP_TIME);
1068 				else {
1069 					/*
1070 					 * If we're outputting multiple printed
1071 					 * characters, just blast them to the
1072 					 * screen until we reach the end of the
1073 					 * buffer or a control character.  This
1074 					 * saves time by short-circuiting the
1075 					 * switch.
1076 					 * If we reach the end of the line, we
1077 					 * break to do a scroll check.
1078 					 */
1079 					for (;;) {
1080 						if (c & 0x80)
1081 							c = iso2ibm437[c&0x7f];
1082 
1083 						if (vs.so)
1084 							wrtchar(c, vs.so_at);
1085 						else
1086 							wrtchar(c, vs.at);
1087 						if (vs.col >= vs.ncol) {
1088 							vs.col = 0;
1089 							scroll = 1;
1090 							break;
1091 						}
1092 						if (!n || (c = *cp) < ' ')
1093 							break;
1094 						n--, cp++;
1095 					}
1096 				}
1097 				break;
1098 			case VSS_ESCAPE:
1099 				switch (c) {
1100 					case '[': /* Start ESC [ sequence */
1101 						vs.cx = vs.cy = 0;
1102 						vs.state = VSS_EBRACE;
1103 						break;
1104 					case 'c': /* Create screen & home */
1105 						fillw((vs.at << 8) | ' ',
1106 						    Crtat, vs.nchr);
1107 						crtat = Crtat;
1108 						vs.col = 0;
1109 						vs.state = 0;
1110 						break;
1111 					case '7': /* save cursor pos */
1112 						vs.offset = crtat - Crtat;
1113 						vs.state = 0;
1114 						break;
1115 					case '8': /* restore cursor pos */
1116 						crtat = Crtat + vs.offset;
1117 						vs.row = vs.offset / vs.ncol;
1118 						vs.col = vs.offset % vs.ncol;
1119 						vs.state = 0;
1120 						break;
1121 					default: /* Invalid, clear state */
1122 						wrtchar(c, vs.so_at);
1123 						vs.state = 0;
1124 						goto maybe_scroll;
1125 				}
1126 				break;
1127 
1128 			default: /* VSS_EBRACE or VSS_EPARAM */
1129 				switch (c) {
1130 					int pos;
1131 				case 'm':
1132 					if (!vs.cx)
1133 						vs.so = 0;
1134 					else
1135 						vs.so = 1;
1136 					vs.state = 0;
1137 					break;
1138 				case 'A': { /* back cx rows */
1139 					int cx = vs.cx;
1140 					if (cx <= 0)
1141 						cx = 1;
1142 					else
1143 						cx %= vs.nrow;
1144 					pos = crtat - Crtat;
1145 					pos -= vs.ncol * cx;
1146 					if (pos < 0)
1147 						pos += vs.nchr;
1148 					crtat = Crtat + pos;
1149 					vs.state = 0;
1150 					break;
1151 				}
1152 				case 'B': { /* down cx rows */
1153 					int cx = vs.cx;
1154 					if (cx <= 0)
1155 						cx = 1;
1156 					else
1157 						cx %= vs.nrow;
1158 					pos = crtat - Crtat;
1159 					pos += vs.ncol * cx;
1160 					if (pos >= vs.nchr)
1161 						pos -= vs.nchr;
1162 					crtat = Crtat + pos;
1163 					vs.state = 0;
1164 					break;
1165 				}
1166 				case 'C': { /* right cursor */
1167 					int cx = vs.cx,
1168 					    col = vs.col;
1169 					if (cx <= 0)
1170 						cx = 1;
1171 					else
1172 						cx %= vs.ncol;
1173 					pos = crtat - Crtat;
1174 					pos += cx;
1175 					col += cx;
1176 					if (col >= vs.ncol) {
1177 						pos -= vs.ncol;
1178 						col -= vs.ncol;
1179 					}
1180 					vs.col = col;
1181 					crtat = Crtat + pos;
1182 					vs.state = 0;
1183 					break;
1184 				}
1185 				case 'D': { /* left cursor */
1186 					int cx = vs.cx,
1187 					    col = vs.col;
1188 					if (cx <= 0)
1189 						cx = 1;
1190 					else
1191 						cx %= vs.ncol;
1192 					pos = crtat - Crtat;
1193 					pos -= cx;
1194 					col -= cx;
1195 					if (col < 0) {
1196 						pos += vs.ncol;
1197 						col += vs.ncol;
1198 					}
1199 					vs.col = col;
1200 					crtat = Crtat + pos;
1201 					vs.state = 0;
1202 					break;
1203 				}
1204 				case 'J': /* Clear ... */
1205 					switch (vs.cx) {
1206 					case 0:
1207 						/* ... to end of display */
1208 						fillw((vs.at << 8) | ' ',
1209 						    crtat,
1210 						    Crtat + vs.nchr - crtat);
1211 						break;
1212 					case 1:
1213 						/* ... to next location */
1214 						fillw((vs.at << 8) | ' ',
1215 						    Crtat,
1216 						    crtat - Crtat + 1);
1217 						break;
1218 					case 2:
1219 						/* ... whole display */
1220 						fillw((vs.at << 8) | ' ',
1221 						    Crtat,
1222 						    vs.nchr);
1223 						break;
1224 					}
1225 					vs.state = 0;
1226 					break;
1227 				case 'K': /* Clear line ... */
1228 					switch (vs.cx) {
1229 					case 0:
1230 						/* ... current to EOL */
1231 						fillw((vs.at << 8) | ' ',
1232 						    crtat,
1233 						    vs.ncol - vs.col);
1234 						break;
1235 					case 1:
1236 						/* ... beginning to next */
1237 						fillw((vs.at << 8) | ' ',
1238 						    crtat - vs.col,
1239 						    vs.col + 1);
1240 						break;
1241 					case 2:
1242 						/* ... entire line */
1243 						fillw((vs.at << 8) | ' ',
1244 						    crtat - vs.col, vs.ncol);
1245 						break;
1246 					}
1247 					vs.state = 0;
1248 					break;
1249 				case 'f': /* in system V consoles */
1250 				case 'H': { /* Cursor move */
1251 					int cx = vs.cx,
1252 					    cy = vs.cy;
1253 					if (!cx || !cy) {
1254 						crtat = Crtat;
1255 						vs.col = 0;
1256 					} else {
1257 						if (cx > vs.nrow)
1258 							cx = vs.nrow;
1259 						if (cy > vs.ncol)
1260 							cy = vs.ncol;
1261 						crtat = Crtat +
1262 						    (cx - 1) * vs.ncol + cy - 1;
1263 						vs.col = cy - 1;
1264 					}
1265 					vs.state = 0;
1266 					break;
1267 				}
1268 				case 'M': { /* delete cx rows */
1269 					u_short *crtAt = crtat - vs.col;
1270 					int cx = vs.cx,
1271 					    row = (crtAt - Crtat) / vs.ncol,
1272 					    nrow = vs.nrow - row;
1273 					if (cx <= 0)
1274 						cx = 1;
1275 					else if (cx > nrow)
1276 						cx = nrow;
1277 					if (cx < nrow)
1278 #ifdef PCCONS_FORCE_WORD
1279 						wcopy(crtAt + vs.ncol * cx,
1280 						    crtAt, vs.ncol * (nrow -
1281 						    cx) * CHR);
1282 #else
1283 						memmove(crtAt,
1284 						    crtAt + vs.ncol * cx,
1285 						    vs.ncol * (nrow - cx) *
1286 						    CHR);
1287 #endif
1288 					fillw((vs.at << 8) | ' ',
1289 					    crtAt + vs.ncol * (nrow - cx),
1290 					    vs.ncol * cx);
1291 					vs.state = 0;
1292 					break;
1293 				}
1294 				case 'S': { /* scroll up cx lines */
1295 					int cx = vs.cx;
1296 					if (cx <= 0)
1297 						cx = 1;
1298 					else if (cx > vs.nrow)
1299 						cx = vs.nrow;
1300 					if (cx < vs.nrow)
1301 #ifdef PCCONS_FORCE_WORD
1302 						wcopy(Crtat + vs.ncol * cx,
1303 						    Crtat, vs.ncol * (vs.nrow -
1304 						    cx) * CHR);
1305 #else
1306 						memmove(Crtat,
1307 						    Crtat + vs.ncol * cx,
1308 						    vs.ncol * (vs.nrow - cx) *
1309 						    CHR);
1310 #endif
1311 					fillw((vs.at << 8) | ' ',
1312 					    Crtat + vs.ncol * (vs.nrow - cx),
1313 					    vs.ncol * cx);
1314 					/* crtat -= vs.ncol * cx; XXX */
1315 					vs.state = 0;
1316 					break;
1317 				}
1318 				case 'L': { /* insert cx rows */
1319 					u_short *crtAt = crtat - vs.col;
1320 					int cx = vs.cx,
1321 					    row = (crtAt - Crtat) / vs.ncol,
1322 					    nrow = vs.nrow - row;
1323 					if (cx <= 0)
1324 						cx = 1;
1325 					else if (cx > nrow)
1326 						cx = nrow;
1327 					if (cx < nrow)
1328 #ifdef PCCONS_FORCE_WORD
1329 						wcopy(crtAt,
1330 						    crtAt + vs.ncol * cx,
1331 						    vs.ncol * (nrow - cx) *
1332 						    CHR);
1333 #else
1334 						memmove(crtAt + vs.ncol * cx,
1335 						    crtAt,
1336 						    vs.ncol * (nrow - cx) *
1337 						    CHR);
1338 #endif
1339 					fillw((vs.at << 8) | ' ', crtAt,
1340 					    vs.ncol * cx);
1341 					vs.state = 0;
1342 					break;
1343 				}
1344 				case 'T': { /* scroll down cx lines */
1345 					int cx = vs.cx;
1346 					if (cx <= 0)
1347 						cx = 1;
1348 					else if (cx > vs.nrow)
1349 						cx = vs.nrow;
1350 					if (cx < vs.nrow)
1351 #ifdef PCCONS_FORCE_WORD
1352 						wcopy(Crtat,
1353 						    Crtat + vs.ncol * cx,
1354 						    vs.ncol * (vs.nrow - cx) *
1355 						    CHR);
1356 #else
1357 						memmove(Crtat + vs.ncol * cx,
1358 						    Crtat,
1359 						    vs.ncol * (vs.nrow - cx) *
1360 						    CHR);
1361 #endif
1362 					fillw((vs.at << 8) | ' ', Crtat,
1363 					    vs.ncol * cx);
1364 					/* crtat += vs.ncol * cx; XXX */
1365 					vs.state = 0;
1366 					break;
1367 				}
1368 				case ';': /* Switch params in cursor def */
1369 					vs.state = VSS_EPARAM;
1370 					break;
1371 				case 'r':
1372 					vs.so_at = (vs.cx & FG_MASK) |
1373 					    ((vs.cy << 4) & BG_MASK);
1374 					vs.state = 0;
1375 					break;
1376 				case 's': /* save cursor pos */
1377 					vs.offset = crtat - Crtat;
1378 					vs.state = 0;
1379 					break;
1380 				case 'u': /* restore cursor pos */
1381 					crtat = Crtat + vs.offset;
1382 					vs.row = vs.offset / vs.ncol;
1383 					vs.col = vs.offset % vs.ncol;
1384 					vs.state = 0;
1385 					break;
1386 				case 'x': /* set attributes */
1387 					switch (vs.cx) {
1388 					case 0:
1389 						vs.at = FG_LIGHTGREY | BG_BLACK;
1390 						break;
1391 					case 1:
1392 						/* ansi background */
1393 						if (!vs.color)
1394 							break;
1395 						vs.at &= FG_MASK;
1396 						vs.at |= bgansitopc[vs.cy & 7];
1397 						break;
1398 					case 2:
1399 						/* ansi foreground */
1400 						if (!vs.color)
1401 							break;
1402 						vs.at &= BG_MASK;
1403 						vs.at |= fgansitopc[vs.cy & 7];
1404 						break;
1405 					case 3:
1406 						/* pc text attribute */
1407 						if (vs.state >= VSS_EPARAM)
1408 							vs.at = vs.cy;
1409 						break;
1410 					}
1411 					vs.state = 0;
1412 					break;
1413 
1414 				default: /* Only numbers valid here */
1415 					if ((c >= '0') && (c <= '9')) {
1416 						if (vs.state >= VSS_EPARAM) {
1417 							vs.cy *= 10;
1418 							vs.cy += c - '0';
1419 						} else {
1420 							vs.cx *= 10;
1421 							vs.cx += c - '0';
1422 						}
1423 					} else
1424 						vs.state = 0;
1425 					break;
1426 				}
1427 				break;
1428 			}
1429 		}
1430 		if (scroll) {
1431 			scroll = 0;
1432 			/* scroll check */
1433 			if (crtat >= Crtat + vs.nchr) {
1434 				if (!kernel) {
1435 					int s = spltty();
1436 					if (lock_state & KB_SCROLL)
1437 						tsleep(&lock_state,
1438 						    PUSER, "pcputc", 0);
1439 					splx(s);
1440 				}
1441 #if PCCONS_FORCE_WORD
1442 				wcopy(Crtat + vs.ncol, Crtat,
1443 				    (vs.nchr - vs.ncol) * CHR);
1444 #else
1445 				memmove(Crtat, Crtat + vs.ncol,
1446 				    (vs.nchr - vs.ncol) * CHR);
1447 #endif
1448 				fillw((vs.at << 8) | ' ',
1449 				    Crtat + vs.nchr - vs.ncol,
1450 				    vs.ncol);
1451 				crtat -= vs.ncol;
1452 			}
1453 		}
1454 	}
1455 	async_update();
1456 }
1457 
1458 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1459    left and right shift when reading the keyboard map */
1460 static pccons_keymap_t	scan_codes[KB_NUM_KEYS] = {
1461 /*  type       unshift   shift     control   altgr     shift_altgr scancode */
1462   { KB_NONE,   "",       "",       "",       "",       ""}, /* 0 unused */
1463   { KB_ASCII,  "\033",   "\033",   "\033",   "",       ""}, /* 1 ESCape */
1464   { KB_ASCII,  "1",      "!",      "!",      "",       ""}, /* 2 1 */
1465   { KB_ASCII,  "2",      "@",      "\000",   "",       ""}, /* 3 2 */
1466   { KB_ASCII,  "3",      "#",      "#",      "",       ""}, /* 4 3 */
1467   { KB_ASCII,  "4",      "$",      "$",      "",       ""}, /* 5 4 */
1468   { KB_ASCII,  "5",      "%",      "%",      "",       ""}, /* 6 5 */
1469   { KB_ASCII,  "6",      "^",      "\036",   "",       ""}, /* 7 6 */
1470   { KB_ASCII,  "7",      "&",      "&",      "",       ""}, /* 8 7 */
1471   { KB_ASCII,  "8",      "*",      "\010",   "",       ""}, /* 9 8 */
1472   { KB_ASCII,  "9",      "(",      "(",      "",       ""}, /* 10 9 */
1473   { KB_ASCII,  "0",      ")",      ")",      "",       ""}, /* 11 0 */
1474   { KB_ASCII,  "-",      "_",      "\037",   "",       ""}, /* 12 - */
1475   { KB_ASCII,  "=",      "+",      "+",      "",       ""}, /* 13 = */
1476   { KB_ASCII,  "\177",   "\177",   "\010",   "",       ""}, /* 14 backspace */
1477   { KB_ASCII,  "\t",     "\t",     "\t",     "",       ""}, /* 15 tab */
1478   { KB_ASCII,  "q",      "Q",      "\021",   "",       ""}, /* 16 q */
1479   { KB_ASCII,  "w",      "W",      "\027",   "",       ""}, /* 17 w */
1480   { KB_ASCII,  "e",      "E",      "\005",   "",       ""}, /* 18 e */
1481   { KB_ASCII,  "r",      "R",      "\022",   "",       ""}, /* 19 r */
1482   { KB_ASCII,  "t",      "T",      "\024",   "",       ""}, /* 20 t */
1483   { KB_ASCII,  "y",      "Y",      "\031",   "",       ""}, /* 21 y */
1484   { KB_ASCII,  "u",      "U",      "\025",   "",       ""}, /* 22 u */
1485   { KB_ASCII,  "i",      "I",      "\011",   "",       ""}, /* 23 i */
1486   { KB_ASCII,  "o",      "O",      "\017",   "",       ""}, /* 24 o */
1487   { KB_ASCII,  "p",      "P",      "\020",   "",       ""}, /* 25 p */
1488   { KB_ASCII,  "[",      "{",      "\033",   "",       ""}, /* 26 [ */
1489   { KB_ASCII,  "]",      "}",      "\035",   "",       ""}, /* 27 ] */
1490   { KB_ASCII,  "\r",     "\r",     "\n",     "",       ""}, /* 28 return */
1491   { KB_CTL,    "",       "",       "",       "",       ""}, /* 29 control */
1492   { KB_ASCII,  "a",      "A",      "\001",   "",       ""}, /* 30 a */
1493   { KB_ASCII,  "s",      "S",      "\023",   "",       ""}, /* 31 s */
1494   { KB_ASCII,  "d",      "D",      "\004",   "",       ""}, /* 32 d */
1495   { KB_ASCII,  "f",      "F",      "\006",   "",       ""}, /* 33 f */
1496   { KB_ASCII,  "g",      "G",      "\007",   "",       ""}, /* 34 g */
1497   { KB_ASCII,  "h",      "H",      "\010",   "",       ""}, /* 35 h */
1498   { KB_ASCII,  "j",      "J",      "\n",     "",       ""}, /* 36 j */
1499   { KB_ASCII,  "k",      "K",      "\013",   "",       ""}, /* 37 k */
1500   { KB_ASCII,  "l",      "L",      "\014",   "",       ""}, /* 38 l */
1501   { KB_ASCII,  ";",      ":",      ";",      "",       ""}, /* 39 ; */
1502   { KB_ASCII,  "'",      "\"",     "'",      "",       ""}, /* 40 ' */
1503   { KB_ASCII,  "`",      "~",      "`",      "",       ""}, /* 41 ` */
1504   { KB_SHIFT,  "\001",   "",       "",       "",       ""}, /* 42 shift */
1505   { KB_ASCII,  "\\",     "|",      "\034",   "",       ""}, /* 43 \ */
1506   { KB_ASCII,  "z",      "Z",      "\032",   "",       ""}, /* 44 z */
1507   { KB_ASCII,  "x",      "X",      "\030",   "",       ""}, /* 45 x */
1508   { KB_ASCII,  "c",      "C",      "\003",   "",       ""}, /* 46 c */
1509   { KB_ASCII,  "v",      "V",      "\026",   "",       ""}, /* 47 v */
1510   { KB_ASCII,  "b",      "B",      "\002",   "",       ""}, /* 48 b */
1511   { KB_ASCII,  "n",      "N",      "\016",   "",       ""}, /* 49 n */
1512   { KB_ASCII,  "m",      "M",      "\r",     "",       ""}, /* 50 m */
1513   { KB_ASCII,  ",",      "<",      "<",      "",       ""}, /* 51 , */
1514   { KB_ASCII,  ".",      ">",      ">",      "",       ""}, /* 52 . */
1515   { KB_ASCII,  "/",      "?",      "\037",   "",       ""}, /* 53 / */
1516   { KB_SHIFT,  "\002",   "",       "",       "",       ""}, /* 54 shift */
1517   { KB_KP,     "*",      "*",      "*",      "",       ""}, /* 55 kp * */
1518   { KB_ALT,    "",       "",       "",       "",       ""}, /* 56 alt */
1519   { KB_ASCII,  " ",      " ",      "\000",   "",       ""}, /* 57 space */
1520   { KB_CAPS,   "",       "",       "",       "",       ""}, /* 58 caps */
1521   { KB_FUNC,   "\033[M", "\033[Y", "\033[k", "",       ""}, /* 59 f1 */
1522   { KB_FUNC,   "\033[N", "\033[Z", "\033[l", "",       ""}, /* 60 f2 */
1523   { KB_FUNC,   "\033[O", "\033[a", "\033[m", "",       ""}, /* 61 f3 */
1524   { KB_FUNC,   "\033[P", "\033[b", "\033[n", "",       ""}, /* 62 f4 */
1525   { KB_FUNC,   "\033[Q", "\033[c", "\033[o", "",       ""}, /* 63 f5 */
1526   { KB_FUNC,   "\033[R", "\033[d", "\033[p", "",       ""}, /* 64 f6 */
1527   { KB_FUNC,   "\033[S", "\033[e", "\033[q", "",       ""}, /* 65 f7 */
1528   { KB_FUNC,   "\033[T", "\033[f", "\033[r", "",       ""}, /* 66 f8 */
1529   { KB_FUNC,   "\033[U", "\033[g", "\033[s", "",       ""}, /* 67 f9 */
1530   { KB_FUNC,   "\033[V", "\033[h", "\033[t", "",       ""}, /* 68 f10 */
1531   { KB_NUM,    "",       "",       "",       "",       ""}, /* 69 num lock */
1532   { KB_SCROLL, "",       "",       "",       "",       ""}, /* 70 scroll lock */
1533   { KB_KP,     "7",      "\033[H", "7",      "",       ""}, /* 71 kp 7 */
1534   { KB_KP,     "8",      "\033[A", "8",      "",       ""}, /* 72 kp 8 */
1535   { KB_KP,     "9",      "\033[I", "9",      "",       ""}, /* 73 kp 9 */
1536   { KB_KP,     "-",      "-",      "-",      "",       ""}, /* 74 kp - */
1537   { KB_KP,     "4",      "\033[D", "4",      "",       ""}, /* 75 kp 4 */
1538   { KB_KP,     "5",      "\033[E", "5",      "",       ""}, /* 76 kp 5 */
1539   { KB_KP,     "6",      "\033[C", "6",      "",       ""}, /* 77 kp 6 */
1540   { KB_KP,     "+",      "+",      "+",      "",       ""}, /* 78 kp + */
1541   { KB_KP,     "1",      "\033[F", "1",      "",       ""}, /* 79 kp 1 */
1542   { KB_KP,     "2",      "\033[B", "2",      "",       ""}, /* 80 kp 2 */
1543   { KB_KP,     "3",      "\033[G", "3",      "",       ""}, /* 81 kp 3 */
1544   { KB_KP,     "0",      "\033[L", "0",      "",       ""}, /* 82 kp 0 */
1545   { KB_KP,     ",",      "\177",   ",",      "",       ""}, /* 83 kp , */
1546   { KB_NONE,   "",       "",       "",       "",       ""}, /* 84 0 */
1547   { KB_NONE,   "",       "",       "",       "",       ""}, /* 85 0 */
1548   { KB_NONE,   "",       "",       "",       "",       ""}, /* 86 0 */
1549   { KB_FUNC,   "\033[W", "\033[i", "\033[u", "",       ""}, /* 87 f11 */
1550   { KB_FUNC,   "\033[X", "\033[j", "\033[v", "",       ""}, /* 88 f12 */
1551   { KB_NONE,   "",       "",       "",       "",       ""}, /* 89 0 */
1552   { KB_NONE,   "",       "",       "",       "",       ""}, /* 90 0 */
1553   { KB_NONE,   "",       "",       "",       "",       ""}, /* 91 0 */
1554   { KB_NONE,   "",       "",       "",       "",       ""}, /* 92 0 */
1555   { KB_NONE,   "",       "",       "",       "",       ""}, /* 93 0 */
1556   { KB_NONE,   "",       "",       "",       "",       ""}, /* 94 0 */
1557   { KB_NONE,   "",       "",       "",       "",       ""}, /* 95 0 */
1558   { KB_NONE,   "",       "",       "",       "",       ""}, /* 96 0 */
1559   { KB_NONE,   "",       "",       "",       "",       ""}, /* 97 0 */
1560   { KB_NONE,   "",       "",       "",       "",       ""}, /* 98 0 */
1561   { KB_NONE,   "",       "",       "",       "",       ""}, /* 99 0 */
1562   { KB_NONE,   "",       "",       "",       "",       ""}, /* 100 */
1563   { KB_NONE,   "",       "",       "",       "",       ""}, /* 101 */
1564   { KB_NONE,   "",       "",       "",       "",       ""}, /* 102 */
1565   { KB_NONE,   "",       "",       "",       "",       ""}, /* 103 */
1566   { KB_NONE,   "",       "",       "",       "",       ""}, /* 104 */
1567   { KB_NONE,   "",       "",       "",       "",       ""}, /* 105 */
1568   { KB_NONE,   "",       "",       "",       "",       ""}, /* 106 */
1569   { KB_NONE,   "",       "",       "",       "",       ""}, /* 107 */
1570   { KB_NONE,   "",       "",       "",       "",       ""}, /* 108 */
1571   { KB_NONE,   "",       "",       "",       "",       ""}, /* 109 */
1572   { KB_NONE,   "",       "",       "",       "",       ""}, /* 110 */
1573   { KB_NONE,   "",       "",       "",       "",       ""}, /* 111 */
1574   { KB_NONE,   "",       "",       "",       "",       ""}, /* 112 */
1575   { KB_NONE,   "",       "",       "",       "",       ""}, /* 113 */
1576   { KB_NONE,   "",       "",       "",       "",       ""}, /* 114 */
1577   { KB_NONE,   "",       "",       "",       "",       ""}, /* 115 */
1578   { KB_NONE,   "",       "",       "",       "",       ""}, /* 116 */
1579   { KB_NONE,   "",       "",       "",       "",       ""}, /* 117 */
1580   { KB_NONE,   "",       "",       "",       "",       ""}, /* 118 */
1581   { KB_NONE,   "",       "",       "",       "",       ""}, /* 119 */
1582   { KB_NONE,   "",       "",       "",       "",       ""}, /* 120 */
1583   { KB_NONE,   "",       "",       "",       "",       ""}, /* 121 */
1584   { KB_NONE,   "",       "",       "",       "",       ""}, /* 122 */
1585   { KB_NONE,   "",       "",       "",       "",       ""}, /* 123 */
1586   { KB_NONE,   "",       "",       "",       "",       ""}, /* 124 */
1587   { KB_NONE,   "",       "",       "",       "",       ""}, /* 125 */
1588   { KB_NONE,   "",       "",       "",       "",       ""}, /* 126 */
1589   { KB_NONE,   "",       "",       "",       "",       ""}  /* 127 */
1590 };
1591 
1592 /*
1593  * Get characters from the keyboard.  If none are present, return NULL.
1594  */
1595 char *
1596 sget(void)
1597 {
1598 	u_char dt;
1599 	static u_char extended = 0, shift_state = 0;
1600 	static u_char capchar[2];
1601 
1602 top:
1603 	KBD_DELAY;
1604 	dt = kbd_data_read_1();
1605 
1606 	switch (dt) {
1607 	case KBR_ACK: case KBR_ECHO:
1608 		kb_oq_get = (kb_oq_get + 1) & 7;
1609 		if(kb_oq_get != kb_oq_put) {
1610 			kbd_data_write_1(kb_oq[kb_oq_get]);
1611 		}
1612 		goto loop;
1613 	case KBR_RESEND:
1614 		kbd_data_write_1(kb_oq[kb_oq_get]);
1615 		goto loop;
1616 	}
1617 
1618 	if (pc_xmode > 0) {
1619 #if defined(DDB) && defined(XSERVER_DDB)
1620 		/* F12 enters the debugger while in X mode */
1621 		if (dt == 88)
1622 			Debugger();
1623 #endif
1624 		capchar[0] = dt;
1625 		capchar[1] = 0;
1626 		/*
1627 		 * Check for locking keys.
1628 		 *
1629 		 * XXX Setting the LEDs this way is a bit bogus.  What if the
1630 		 * keyboard has been remapped in X?
1631 		 */
1632 		switch (scan_codes[dt & 0x7f].type) {
1633 		case KB_NUM:
1634 			if (dt & 0x80) {
1635 				shift_state &= ~KB_NUM;
1636 				break;
1637 			}
1638 			if (shift_state & KB_NUM)
1639 				break;
1640 			shift_state |= KB_NUM;
1641 			lock_state ^= KB_NUM;
1642 			async_update();
1643 			break;
1644 		case KB_CAPS:
1645 			if (dt & 0x80) {
1646 				shift_state &= ~KB_CAPS;
1647 				break;
1648 			}
1649 			if (shift_state & KB_CAPS)
1650 				break;
1651 			shift_state |= KB_CAPS;
1652 			lock_state ^= KB_CAPS;
1653 			async_update();
1654 			break;
1655 		case KB_SCROLL:
1656 			if (dt & 0x80) {
1657 				shift_state &= ~KB_SCROLL;
1658 				break;
1659 			}
1660 			if (shift_state & KB_SCROLL)
1661 				break;
1662 			shift_state |= KB_SCROLL;
1663 			lock_state ^= KB_SCROLL;
1664 			if ((lock_state & KB_SCROLL) == 0)
1665 				wakeup((void *)&lock_state);
1666 			async_update();
1667 			break;
1668 		}
1669 		return capchar;
1670 	}
1671 
1672 	switch (dt) {
1673 	case KBR_EXTENDED:
1674 		extended = 1;
1675 		goto loop;
1676 	}
1677 
1678 #ifdef DDB
1679 	/*
1680 	 * Check for cntl-alt-esc.
1681 	 */
1682 	if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1683 		/* XXX - check pccons_is_console */
1684 		Debugger();
1685 		dt |= 0x80;	/* discard esc (ddb discarded ctl-alt) */
1686 	}
1687 #endif
1688 
1689 	/*
1690 	 * Check for make/break.
1691 	 */
1692 	if (dt & 0x80) {
1693 		/*
1694 		 * break
1695 		 */
1696 		dt &= 0x7f;
1697 		switch (scan_codes[dt].type) {
1698 		case KB_NUM:
1699 			shift_state &= ~KB_NUM;
1700 			break;
1701 		case KB_CAPS:
1702 			shift_state &= ~KB_CAPS;
1703 			break;
1704 		case KB_SCROLL:
1705 			shift_state &= ~KB_SCROLL;
1706 			break;
1707 		case KB_SHIFT:
1708 			shift_state &= ~KB_SHIFT;
1709 			break;
1710 		case KB_ALT:
1711 			if (extended)
1712 				shift_state &= ~KB_ALTGR;
1713 			else
1714 				shift_state &= ~KB_ALT;
1715 			break;
1716 		case KB_CTL:
1717 			shift_state &= ~KB_CTL;
1718 			break;
1719 		}
1720 	} else {
1721 		/*
1722 		 * make
1723 		 */
1724 		switch (scan_codes[dt].type) {
1725 		/*
1726 		 * locking keys
1727 		 */
1728 		case KB_NUM:
1729 			if (shift_state & KB_NUM)
1730 				break;
1731 			shift_state |= KB_NUM;
1732 			lock_state ^= KB_NUM;
1733 			async_update();
1734 			break;
1735 		case KB_CAPS:
1736 			if (shift_state & KB_CAPS)
1737 				break;
1738 			shift_state |= KB_CAPS;
1739 			lock_state ^= KB_CAPS;
1740 			async_update();
1741 			break;
1742 		case KB_SCROLL:
1743 			if (shift_state & KB_SCROLL)
1744 				break;
1745 			shift_state |= KB_SCROLL;
1746 			lock_state ^= KB_SCROLL;
1747 			if ((lock_state & KB_SCROLL) == 0)
1748 				wakeup((void *)&lock_state);
1749 			async_update();
1750 			break;
1751 		/*
1752 		 * non-locking keys
1753 		 */
1754 		case KB_SHIFT:
1755 			shift_state |= KB_SHIFT;
1756 			break;
1757 		case KB_ALT:
1758 			if (extended)
1759 				shift_state |= KB_ALTGR;
1760 			else
1761 				shift_state |= KB_ALT;
1762 			break;
1763 		case KB_CTL:
1764 			shift_state |= KB_CTL;
1765 			break;
1766 		case KB_ASCII:
1767 			/* control has highest priority */
1768 			if (shift_state & KB_CTL)
1769 				capchar[0] = scan_codes[dt].ctl[0];
1770 			else if (shift_state & KB_ALTGR) {
1771 				if (shift_state & KB_SHIFT)
1772 					capchar[0] = scan_codes[dt].shift_altgr[0];
1773 				else
1774 					capchar[0] = scan_codes[dt].altgr[0];
1775 			}
1776 			else {
1777 				if (shift_state & KB_SHIFT)
1778 					capchar[0] = scan_codes[dt].shift[0];
1779 				else
1780 					capchar[0] = scan_codes[dt].unshift[0];
1781 			}
1782 			if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1783 			    capchar[0] <= 'z') {
1784 				capchar[0] -= ('a' - 'A');
1785 			}
1786 			capchar[0] |= (shift_state & KB_ALT);
1787 			extended = 0;
1788 			return capchar;
1789 		case KB_NONE:
1790 printf("keycode %d\n",dt);
1791 			break;
1792 		case KB_FUNC: {
1793 			char *more_chars;
1794 			if (shift_state & KB_SHIFT)
1795 				more_chars = scan_codes[dt].shift;
1796 			else if (shift_state & KB_CTL)
1797 				more_chars = scan_codes[dt].ctl;
1798 			else
1799 				more_chars = scan_codes[dt].unshift;
1800 			extended = 0;
1801 			return more_chars;
1802 		}
1803 		case KB_KP: {
1804 			char *more_chars;
1805 			if (shift_state & (KB_SHIFT | KB_CTL) ||
1806 			    (lock_state & KB_NUM) == 0 || extended)
1807 				more_chars = scan_codes[dt].shift;
1808 			else
1809 				more_chars = scan_codes[dt].unshift;
1810 			extended = 0;
1811 			return more_chars;
1812 		}
1813 		}
1814 	}
1815 
1816 	extended = 0;
1817 loop:
1818 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
1819 		return 0;
1820 	goto top;
1821 }
1822 
1823 paddr_t
1824 pcmmap(dev_t dev, off_t offset, int nprot)
1825 {
1826 	struct pccons_context *pc = &pccons_console_context;
1827 	paddr_t pa;
1828 
1829 	if (offset >= 0xa0000 && offset < 0xc0000) {
1830 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1831 			return -1;
1832 		pa += offset - pc->pc_config->pc_mono_memaddr;
1833 		return mips_btop(pa);
1834 	}
1835 	if (offset >= 0x0000 && offset < 0x10000) {
1836 		if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
1837 			return -1;
1838 		pa += offset - pc->pc_config->pc_mono_iobase;
1839 		return mips_btop(pa);
1840 	}
1841 	if (offset >= 0x40000000 && offset < 0x40800000) {
1842 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1843 			return (-1);
1844 		pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
1845 		return mips_btop(pa);
1846 	}
1847 	return -1;
1848 }
1849 
1850 void
1851 pc_xmode_on(void)
1852 {
1853 	if (pc_xmode)
1854 		return;
1855 	pc_xmode = 1;
1856 
1857 #ifdef XFREE86_BUG_COMPAT
1858 	/* If still unchanged, get current shape. */
1859 	if (cursor_shape == 0xffff)
1860 		get_cursor_shape();
1861 #endif
1862 }
1863 
1864 void
1865 pc_xmode_off(void)
1866 {
1867 	if (pc_xmode == 0)
1868 		return;
1869 	pc_xmode = 0;
1870 
1871 #ifdef XFREE86_BUG_COMPAT
1872 	/* XXX It would be hard to justify why the X server doesn't do this. */
1873 	set_cursor_shape();
1874 #endif
1875 	async_update();
1876 }
1877