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