xref: /netbsd-src/sys/arch/arc/dev/pccons.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: pccons.c,v 1.57 2009/03/14 21:04:04 dsl 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.57 2009/03/14 21:04:04 dsl 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(uint8_t val)
353 {
354 
355 	if (!kbd_wait_output())
356 		return 0;
357 	kbd_cmd_write_1(K_LDCMDBYTE);
358 	if (!kbd_wait_output())
359 		return 0;
360 	kbd_data_write_1(val);
361 	return 1;
362 }
363 
364 /*
365  * Pass command to keyboard itself
366  */
367 int
368 kbd_cmd(uint8_t val, uint8_t polled)
369 {
370 	u_int retries = 3;
371 	u_int i;
372 
373 	if (!polled) {
374 		i = spltty();
375 		if (kb_oq_get == kb_oq_put) {
376 			kbd_data_write_1(val);
377 		}
378 		kb_oq[kb_oq_put] = val;
379 		kb_oq_put = (kb_oq_put + 1) & 7;
380 		splx(i);
381 		return 1;
382 	}
383 
384 	do {
385 		if (!kbd_wait_output())
386 			return 0;
387 		kbd_data_write_1(val);
388 		for (i = 100000; i; i--) {
389 			if (kbd_cmd_read_1() & KBS_DIB) {
390 				uint8_t c;
391 
392 				KBD_DELAY;
393 				c = kbd_data_read_1();
394 				if (c == KBR_ACK || c == KBR_ECHO) {
395 					return 1;
396 				}
397 				if (c == KBR_RESEND) {
398 					break;
399 				}
400 #ifdef DIAGNOSTIC
401 				printf("kbd_cmd: input char %x lost\n", c);
402 #endif
403 			}
404 		}
405 	} while (--retries);
406 	return 0;
407 }
408 
409 void
410 set_cursor_shape(void)
411 {
412 
413 	crtc_write_1(0, 10);
414 	crtc_write_1(1, cursor_shape >> 8);
415 	crtc_write_1(0, 11);
416 	crtc_write_1(1, cursor_shape);
417 	old_cursor_shape = cursor_shape;
418 }
419 
420 void
421 get_cursor_shape(void)
422 {
423 
424 	crtc_write_1(0, 10);
425 	cursor_shape = crtc_read_1(1) << 8;
426 	crtc_write_1(0, 11);
427 	cursor_shape |= crtc_read_1(1);
428 
429 	/*
430 	 * real 6845's, as found on, MDA, Hercules or CGA cards, do
431 	 * not support reading the cursor shape registers. the 6845
432 	 * tri-states it's data bus. This is _normally_ read by the
433 	 * CPU as either 0x00 or 0xff.. in which case we just use
434 	 * a line cursor.
435 	 */
436 	if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
437 		cursor_shape = 0x0b10;
438 	else
439 		cursor_shape &= 0x1f1f;
440 }
441 
442 void
443 do_async_update(uint8_t poll)
444 {
445 	int pos;
446 	static int old_pos = -1;
447 
448 	async = 0;
449 
450 	if (lock_state != old_lock_state) {
451 		old_lock_state = lock_state;
452 		if (!kbd_cmd(KBC_MODEIND, poll) ||
453 		    !kbd_cmd(lock_state, poll)) {
454 			printf("pc: timeout updating leds\n");
455 			(void) kbd_cmd(KBC_ENABLE, poll);
456 		}
457 	}
458 	if (typematic_rate != old_typematic_rate) {
459 		old_typematic_rate = typematic_rate;
460 		if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
461 		    !kbd_cmd(typematic_rate, poll)) {
462 			printf("pc: timeout updating typematic rate\n");
463 			(void) kbd_cmd(KBC_ENABLE, poll);
464 		}
465 	}
466 
467 	if (pc_xmode > 0)
468 		return;
469 
470 	pos = crtat - Crtat;
471 	if (pos != old_pos) {
472 		crtc_write_1(0, 14);
473 		crtc_write_1(1, pos >> 8);
474 		crtc_write_1(0, 15);
475 		crtc_write_1(1, pos);
476 		old_pos = pos;
477 	}
478 	if (cursor_shape != old_cursor_shape)
479 		set_cursor_shape();
480 }
481 
482 void
483 async_update(void)
484 {
485 
486 	if (kernel || polling) {
487 		if (async)
488 			callout_stop(&async_update_ch);
489 		do_async_update(1);
490 	} else {
491 		if (async)
492 			return;
493 		async = 1;
494 		callout_reset(&async_update_ch, 1,
495 		    (void(*)(void *))do_async_update, NULL);
496 	}
497 }
498 
499 /*
500  * these are both bad jokes
501  */
502 int
503 pccons_common_match(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
504     bus_space_tag_t kbd_iot, struct pccons_config *config)
505 {
506 	int i;
507 
508 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
509 
510 	/* Enable interrupts and keyboard, etc. */
511 	if (!kbc_put8042cmd(CMDBYTE)) {
512 		printf("pcprobe: command error\n");
513 		return 0;
514 	}
515 
516 #if 1
517 	/* Flush any garbage. */
518 	kbd_flush_input();
519 	/* Reset the keyboard. */
520 	if (!kbd_cmd(KBC_RESET, 1)) {
521 		printf("pcprobe: reset error %d\n", 1);
522 		goto lose;
523 	}
524 	for (i = 600000; i; i--)
525 		if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
526 			KBD_DELAY;
527 			break;
528 		}
529 	if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) {
530 		printf("pcprobe: reset error %d\n", 2);
531 		goto lose;
532 	}
533 	/*
534 	 * Some keyboards seem to leave a second ack byte after the reset.
535 	 * This is kind of stupid, but we account for them anyway by just
536 	 * flushing the buffer.
537 	 */
538 	kbd_flush_input();
539 	/* Just to be sure. */
540 	if (!kbd_cmd(KBC_ENABLE, 1)) {
541 		printf("pcprobe: reset error %d\n", 3);
542 		goto lose;
543 	}
544 
545 	/*
546 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
547 	 * is set to table 1; in fact, it would appear that some keyboards just
548 	 * ignore the command altogether.  So by default, we use the AT scan
549 	 * codes and have the 8042 translate them.  Unfortunately, this is
550 	 * known to not work on some PS/2 machines.  We try desparately to deal
551 	 * with this by checking the (lack of a) translate bit in the 8042 and
552 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
553 	 * tough luck.
554 	 *
555 	 * XXX It would perhaps be a better choice to just use AT scan codes
556 	 * and not bother with this.
557 	 */
558 	if (kbc_get8042cmd() & KC8_TRANS) {
559 		/* The 8042 is translating for us; use AT codes. */
560 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
561 			printf("pcprobe: reset error %d\n", 4);
562 			goto lose;
563 		}
564 	} else {
565 		/* Stupid 8042; set keyboard to XT codes. */
566 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
567 			printf("pcprobe: reset error %d\n", 5);
568 			goto lose;
569 		}
570 	}
571 
572 lose:
573 	/*
574 	 * Technically, we should probably fail the probe.  But we'll be nice
575 	 * and allow keyboard-less machines to boot with the console.
576 	 */
577 #endif
578 
579 	return 1;
580 }
581 
582 void pccons_common_attach(struct pc_softc *sc, bus_space_tag_t crt_iot,
583     bus_space_tag_t crt_memt, bus_space_tag_t kbd_iot,
584     struct pccons_config *config)
585 {
586 
587 	printf(": %s\n", vs.color ? "color" : "mono");
588 	callout_init(&async_update_ch, 0);
589 	do_async_update(1);
590 }
591 
592 int
593 pcopen(dev_t dev, int flag, int mode, struct lwp *l)
594 {
595 	struct pc_softc *sc;
596 	struct tty *tp;
597 
598 	sc = device_lookup_private(&pc_cd, PCUNIT(dev));
599 	if (sc == NULL)
600 		return ENXIO;
601 
602 	if (!sc->sc_tty) {
603 		tp = sc->sc_tty = ttymalloc();
604 	}
605 	else {
606 		tp = sc->sc_tty;
607 	}
608 
609 	tp->t_oproc = pcstart;
610 	tp->t_param = pcparam;
611 	tp->t_dev = dev;
612 
613 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
614 		return (EBUSY);
615 
616 	if ((tp->t_state & TS_ISOPEN) == 0) {
617 		ttychars(tp);
618 		tp->t_iflag = TTYDEF_IFLAG;
619 		tp->t_oflag = TTYDEF_OFLAG;
620 		tp->t_cflag = TTYDEF_CFLAG;
621 		tp->t_lflag = TTYDEF_LFLAG;
622 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
623 		pcparam(tp, &tp->t_termios);
624 		ttsetwater(tp);
625 	}
626 
627 	tp->t_state |= TS_CARR_ON;
628 
629 	return (*tp->t_linesw->l_open)(dev, tp);
630 }
631 
632 int
633 pcclose(dev_t dev, int flag, int mode, struct lwp *l)
634 {
635 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
636 	struct tty *tp = sc->sc_tty;
637 
638 	(*tp->t_linesw->l_close)(tp, flag);
639 	ttyclose(tp);
640 #ifdef notyet /* XXX */
641 	ttyfree(tp);
642 #endif
643 	return 0;
644 }
645 
646 int
647 pcread(dev_t dev, struct uio *uio, int flag)
648 {
649 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
650 	struct tty *tp = sc->sc_tty;
651 
652 	return (*tp->t_linesw->l_read)(tp, uio, flag);
653 }
654 
655 int
656 pcwrite(dev_t dev, struct uio *uio, int flag)
657 {
658 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
659 	struct tty *tp = sc->sc_tty;
660 
661 	return (*tp->t_linesw->l_write)(tp, uio, flag);
662 }
663 
664 int
665 pcpoll(dev_t dev, int events, struct lwp *l)
666 {
667 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
668 	struct tty *tp = sc->sc_tty;
669 
670 	return (*tp->t_linesw->l_poll)(tp, events, l);
671 }
672 
673 struct tty *
674 pctty(dev_t dev)
675 {
676 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
677 	struct tty *tp = sc->sc_tty;
678 
679 	return tp;
680 }
681 
682 /*
683  * Got a console receive interrupt -
684  * the console processor wants to give us a character.
685  * Catch the character, and see who it goes to.
686  */
687 int
688 pcintr(void *arg)
689 {
690 	struct pc_softc *sc = arg;
691 	struct tty *tp = sc->sc_tty;
692 	uint8_t *cp;
693 
694 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
695 		return 0;
696 	if (polling)
697 		return 1;
698 	do {
699 		cp = sget();
700 		if (!tp || (tp->t_state & TS_ISOPEN) == 0)
701 			return 1;
702 		if (cp)
703 			do
704 				(*tp->t_linesw->l_rint)(*cp++, tp);
705 			while (*cp);
706 	} while (kbd_cmd_read_1() & KBS_DIB);
707 	return 1;
708 }
709 
710 int
711 pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
712 {
713 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
714 	struct tty *tp = sc->sc_tty;
715 	int error;
716 
717 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
718 	if (error != EPASSTHROUGH)
719 		return error;
720 	error = ttioctl(tp, cmd, data, flag, l);
721 	if (error != EPASSTHROUGH)
722 		return error;
723 
724 	switch (cmd) {
725 	case CONSOLE_X_MODE_ON:
726 		pc_xmode_on();
727 		return 0;
728 	case CONSOLE_X_MODE_OFF:
729 		pc_xmode_off();
730 		return 0;
731 	case CONSOLE_X_BELL:
732 		/*
733 		 * If set, data is a pointer to a length 2 array of
734 		 * integers.  data[0] is the pitch in Hz and data[1]
735 		 * is the duration in msec.
736 		 */
737 		if (data)
738 			sysbeep(((int*)data)[0],
739 				(((int*)data)[1] * hz) / 1000);
740 		else
741 			sysbeep(BEEP_FREQ, BEEP_TIME);
742 		return 0;
743 	case CONSOLE_SET_TYPEMATIC_RATE: {
744  		u_char	rate;
745 
746  		if (!data)
747 			return EINVAL;
748 		rate = *((u_char *)data);
749 		/*
750 		 * Check that it isn't too big (which would cause it to be
751 		 * confused with a command).
752 		 */
753 		if (rate & 0x80)
754 			return EINVAL;
755 		typematic_rate = rate;
756 		async_update();
757 		return 0;
758  	}
759 	case CONSOLE_SET_KEYMAP: {
760 		pccons_keymap_t *map = (pccons_keymap_t *) data;
761 		int i;
762 
763 		if (!data)
764 			return EINVAL;
765 		for (i = 0; i < KB_NUM_KEYS; i++)
766 			if (map[i].unshift[KB_CODE_SIZE-1] ||
767 			    map[i].shift[KB_CODE_SIZE-1] ||
768 			    map[i].ctl[KB_CODE_SIZE-1] ||
769 			    map[i].altgr[KB_CODE_SIZE-1] ||
770 			    map[i].shift_altgr[KB_CODE_SIZE-1])
771 				return EINVAL;
772 
773 		memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
774 		return 0;
775 	}
776 	case CONSOLE_GET_KEYMAP:
777 		if (!data)
778 			return EINVAL;
779 		memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
780 		return 0;
781 
782 	default:
783 		return EPASSTHROUGH;
784 	}
785 
786 #ifdef DIAGNOSTIC
787 	panic("pcioctl: impossible");
788 #endif
789 }
790 
791 void
792 pcstart(struct tty *tp)
793 {
794 	struct clist *cl;
795 	int s, len;
796 	u_char buf[PCBURST];
797 
798 	s = spltty();
799 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
800 		goto out;
801 	tp->t_state |= TS_BUSY;
802 	splx(s);
803 	/*
804 	 * We need to do this outside spl since it could be fairly
805 	 * expensive and we don't want our serial ports to overflow.
806 	 */
807 	cl = &tp->t_outq;
808 	len = q_to_b(cl, buf, PCBURST);
809 	sput(buf, len);
810 	s = spltty();
811 	tp->t_state &= ~TS_BUSY;
812 	if (ttypull(tp)) {
813 		tp->t_state |= TS_TIMEOUT;
814 		callout_schedule(&tp->t_rstrt_ch, 1);
815 	}
816 out:
817 	splx(s);
818 }
819 
820 /* ARGSUSED */
821 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
822     bus_space_tag_t kbd_iot, struct pccons_config *config)
823 {
824 	int maj;
825 	static struct consdev pccons = {
826 		NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
827 		    NULL, NODEV, CN_NORMAL
828 	};
829 
830 	/*
831 	 * For now, don't screw with it.
832 	 */
833 	/* crtat = 0; */
834 
835 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
836 
837 	/* locate the major number */
838 	maj = cdevsw_lookup_major(&pc_cdevsw);
839 	pccons.cn_dev = makedev(maj, 0);
840 
841 	cn_tab = &pccons;
842 }
843 
844 /* ARGSUSED */
845 void
846 pccnputc(dev_t dev, int c)
847 {
848 	u_char cc, oldkernel = kernel;
849 
850 	kernel = 1;
851 	if (c == '\n') {
852 		sput("\r\n", 2);
853 	} else {
854 		cc = c;
855 		sput(&cc, 1);
856 	}
857 	kernel = oldkernel;
858 }
859 
860 /* ARGSUSED */
861 int
862 pccngetc(dev_t dev)
863 {
864 	char *cp;
865 
866 	if (pc_xmode > 0)
867 		return 0;
868 
869 	do {
870 		/* wait for byte */
871 		while ((kbd_cmd_read_1() & KBS_DIB) == 0);
872 		/* see if it's worthwhile */
873 		cp = sget();
874 	} while (!cp);
875 	if (*cp == '\r')
876 		return '\n';
877 	return *cp;
878 }
879 
880 void
881 pccnpollc(dev_t dev, int on)
882 {
883 
884 	polling = on;
885 	if (!on) {
886 		int unit;
887 		struct pc_softc *sc;
888 		int s;
889 
890 		/*
891 		 * If disabling polling on a device that's been configured,
892 		 * make sure there are no bytes left in the FIFO, holding up
893 		 * the interrupt line.  Otherwise we won't get any further
894 		 * interrupts.
895 		 */
896 		unit = PCUNIT(dev);
897 		if (pc_cd.cd_ndevs > unit) {
898 			sc = device_lookup_private(&pc_cd, unit);
899 			if (sc != NULL) {
900 				s = spltty();
901 				pcintr(sc);
902 				splx(s);
903 			}
904 		}
905 	}
906 }
907 
908 /*
909  * Set line parameters.
910  */
911 int
912 pcparam(struct tty *tp, struct termios *t)
913 {
914 
915 	tp->t_ispeed = t->c_ispeed;
916 	tp->t_ospeed = t->c_ospeed;
917 	tp->t_cflag = t->c_cflag;
918 	return 0;
919 }
920 
921 #define	wrtchar(c, at) do {\
922 	char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
923 } while (0)
924 
925 /* translate ANSI color codes to standard pc ones */
926 static char fgansitopc[] = {
927 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
928 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
929 };
930 
931 static char bgansitopc[] = {
932 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
933 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
934 };
935 
936 static u_char iso2ibm437[] =
937 {
938             0,     0,     0,     0,     0,     0,     0,     0,
939             0,     0,     0,     0,     0,     0,     0,     0,
940             0,     0,     0,     0,     0,     0,     0,     0,
941             0,     0,     0,     0,     0,     0,     0,     0,
942          0xff,  0xad,  0x9b,  0x9c,     0,  0x9d,     0,  0x40,
943          0x6f,  0x63,  0x61,  0xae,     0,     0,     0,     0,
944          0xf8,  0xf1,  0xfd,  0x33,     0,  0xe6,     0,  0xfa,
945             0,  0x31,  0x6f,  0xaf,  0xac,  0xab,     0,  0xa8,
946          0x41,  0x41,  0x41,  0x41,  0x8e,  0x8f,  0x92,  0x80,
947          0x45,  0x90,  0x45,  0x45,  0x49,  0x49,  0x49,  0x49,
948          0x81,  0xa5,  0x4f,  0x4f,  0x4f,  0x4f,  0x99,  0x4f,
949          0x4f,  0x55,  0x55,  0x55,  0x9a,  0x59,     0,  0xe1,
950          0x85,  0xa0,  0x83,  0x61,  0x84,  0x86,  0x91,  0x87,
951          0x8a,  0x82,  0x88,  0x89,  0x8d,  0xa1,  0x8c,  0x8b,
952             0,  0xa4,  0x95,  0xa2,  0x93,  0x6f,  0x94,  0x6f,
953          0x6f,  0x97,  0xa3,  0x96,  0x81,  0x98,     0,     0
954 };
955 
956 /*
957  * `pc3' termcap emulation.
958  */
959 void
960 sput(const u_char *cp, int n)
961 {
962 	struct pccons_context *pc = &pccons_console_context;
963 	u_char c, scroll = 0;
964 
965 	if (pc_xmode > 0)
966 		return;
967 
968 	if (crtat == 0) {
969 		volatile u_short *dp;
970 		u_short was;
971 		unsigned cursorat;
972 
973 		dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
974 		was = *dp;
975 		*dp = 0xA55A;
976 		if (*dp != 0xA55A) {
977 			dp = bus_space_vaddr(pc->pc_crt_memt,
978 			    pc->pc_mono_memh);
979 			pc->pc_6845_ioh = pc->pc_mono_ioh;
980 			pc->pc_crt_memh = pc->pc_mono_memh;
981 			vs.color = 0;
982 		} else {
983 			*dp = was;
984 			pc->pc_6845_ioh = pc->pc_cga_ioh;
985 			pc->pc_crt_memh = pc->pc_cga_memh;
986 			vs.color = 1;
987 		}
988 
989 #ifdef FAT_CURSOR
990 		cursor_shape = 0x0012;
991 #else
992 		get_cursor_shape();
993 #endif
994 
995 		bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
996 		vs.nchr = vs.ncol * vs.nrow;
997 		vs.col--;
998 		vs.row--;
999 		cursorat = vs.ncol * vs.row + vs.col;
1000 		vs.at = FG_LIGHTGREY | BG_BLACK;
1001 
1002 		Crtat = (u_short *)__UNVOLATILE(dp);
1003 		crtat = Crtat + cursorat;
1004 
1005 		if (vs.color == 0)
1006 			vs.so_at = FG_BLACK | BG_LIGHTGREY;
1007 		else
1008 			vs.so_at = FG_YELLOW | BG_BLACK;
1009 
1010 		fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1011 	}
1012 
1013 	while (n--) {
1014 		if (!(c = *cp++))
1015 			continue;
1016 
1017 		switch (c) {
1018 		case 0x1B:
1019 			if (vs.state >= VSS_ESCAPE) {
1020 				wrtchar(c, vs.so_at);
1021 				vs.state = 0;
1022 				goto maybe_scroll;
1023 			} else
1024 				vs.state = VSS_ESCAPE;
1025 			break;
1026 
1027 		case 0x9B:	/* CSI */
1028 			vs.cx = vs.cy = 0;
1029 			vs.state = VSS_EBRACE;
1030 			break;
1031 
1032 		case '\t': {
1033 			int inccol = 8 - (vs.col & 7);
1034 			crtat += inccol;
1035 			vs.col += inccol;
1036 		}
1037 		maybe_scroll:
1038 			if (vs.col >= vs.ncol) {
1039 				vs.col -= vs.ncol;
1040 				scroll = 1;
1041 			}
1042 			break;
1043 
1044 		case '\b':
1045 			if (crtat <= Crtat)
1046 				break;
1047 			--crtat;
1048 			if (--vs.col < 0)
1049 				vs.col += vs.ncol;	/* non-destructive backspace */
1050 			break;
1051 
1052 		case '\r':
1053 			crtat -= vs.col;
1054 			vs.col = 0;
1055 			break;
1056 
1057 		case '\n':
1058 			crtat += vs.ncol;
1059 			scroll = 1;
1060 			break;
1061 
1062 		default:
1063 			switch (vs.state) {
1064 			case 0:
1065 				if (c == '\a')
1066 					sysbeep(BEEP_FREQ, BEEP_TIME);
1067 				else {
1068 					/*
1069 					 * If we're outputting multiple printed
1070 					 * characters, just blast them to the
1071 					 * screen until we reach the end of the
1072 					 * buffer or a control character.  This
1073 					 * saves time by short-circuiting the
1074 					 * switch.
1075 					 * If we reach the end of the line, we
1076 					 * break to do a scroll check.
1077 					 */
1078 					for (;;) {
1079 						if (c & 0x80)
1080 							c = iso2ibm437[c&0x7f];
1081 
1082 						if (vs.so)
1083 							wrtchar(c, vs.so_at);
1084 						else
1085 							wrtchar(c, vs.at);
1086 						if (vs.col >= vs.ncol) {
1087 							vs.col = 0;
1088 							scroll = 1;
1089 							break;
1090 						}
1091 						if (!n || (c = *cp) < ' ')
1092 							break;
1093 						n--, cp++;
1094 					}
1095 				}
1096 				break;
1097 			case VSS_ESCAPE:
1098 				switch (c) {
1099 					case '[': /* Start ESC [ sequence */
1100 						vs.cx = vs.cy = 0;
1101 						vs.state = VSS_EBRACE;
1102 						break;
1103 					case 'c': /* Create screen & home */
1104 						fillw((vs.at << 8) | ' ',
1105 						    Crtat, vs.nchr);
1106 						crtat = Crtat;
1107 						vs.col = 0;
1108 						vs.state = 0;
1109 						break;
1110 					case '7': /* save cursor pos */
1111 						vs.offset = crtat - Crtat;
1112 						vs.state = 0;
1113 						break;
1114 					case '8': /* restore cursor pos */
1115 						crtat = Crtat + vs.offset;
1116 						vs.row = vs.offset / vs.ncol;
1117 						vs.col = vs.offset % vs.ncol;
1118 						vs.state = 0;
1119 						break;
1120 					default: /* Invalid, clear state */
1121 						wrtchar(c, vs.so_at);
1122 						vs.state = 0;
1123 						goto maybe_scroll;
1124 				}
1125 				break;
1126 
1127 			default: /* VSS_EBRACE or VSS_EPARAM */
1128 				switch (c) {
1129 					int pos;
1130 				case 'm':
1131 					if (!vs.cx)
1132 						vs.so = 0;
1133 					else
1134 						vs.so = 1;
1135 					vs.state = 0;
1136 					break;
1137 				case 'A': { /* back cx rows */
1138 					int cx = vs.cx;
1139 					if (cx <= 0)
1140 						cx = 1;
1141 					else
1142 						cx %= vs.nrow;
1143 					pos = crtat - Crtat;
1144 					pos -= vs.ncol * cx;
1145 					if (pos < 0)
1146 						pos += vs.nchr;
1147 					crtat = Crtat + pos;
1148 					vs.state = 0;
1149 					break;
1150 				}
1151 				case 'B': { /* down cx rows */
1152 					int cx = vs.cx;
1153 					if (cx <= 0)
1154 						cx = 1;
1155 					else
1156 						cx %= vs.nrow;
1157 					pos = crtat - Crtat;
1158 					pos += vs.ncol * cx;
1159 					if (pos >= vs.nchr)
1160 						pos -= vs.nchr;
1161 					crtat = Crtat + pos;
1162 					vs.state = 0;
1163 					break;
1164 				}
1165 				case 'C': { /* right cursor */
1166 					int cx = vs.cx,
1167 					    col = vs.col;
1168 					if (cx <= 0)
1169 						cx = 1;
1170 					else
1171 						cx %= vs.ncol;
1172 					pos = crtat - Crtat;
1173 					pos += cx;
1174 					col += cx;
1175 					if (col >= vs.ncol) {
1176 						pos -= vs.ncol;
1177 						col -= vs.ncol;
1178 					}
1179 					vs.col = col;
1180 					crtat = Crtat + pos;
1181 					vs.state = 0;
1182 					break;
1183 				}
1184 				case 'D': { /* left cursor */
1185 					int cx = vs.cx,
1186 					    col = vs.col;
1187 					if (cx <= 0)
1188 						cx = 1;
1189 					else
1190 						cx %= vs.ncol;
1191 					pos = crtat - Crtat;
1192 					pos -= cx;
1193 					col -= cx;
1194 					if (col < 0) {
1195 						pos += vs.ncol;
1196 						col += vs.ncol;
1197 					}
1198 					vs.col = col;
1199 					crtat = Crtat + pos;
1200 					vs.state = 0;
1201 					break;
1202 				}
1203 				case 'J': /* Clear ... */
1204 					switch (vs.cx) {
1205 					case 0:
1206 						/* ... to end of display */
1207 						fillw((vs.at << 8) | ' ',
1208 						    crtat,
1209 						    Crtat + vs.nchr - crtat);
1210 						break;
1211 					case 1:
1212 						/* ... to next location */
1213 						fillw((vs.at << 8) | ' ',
1214 						    Crtat,
1215 						    crtat - Crtat + 1);
1216 						break;
1217 					case 2:
1218 						/* ... whole display */
1219 						fillw((vs.at << 8) | ' ',
1220 						    Crtat,
1221 						    vs.nchr);
1222 						break;
1223 					}
1224 					vs.state = 0;
1225 					break;
1226 				case 'K': /* Clear line ... */
1227 					switch (vs.cx) {
1228 					case 0:
1229 						/* ... current to EOL */
1230 						fillw((vs.at << 8) | ' ',
1231 						    crtat,
1232 						    vs.ncol - vs.col);
1233 						break;
1234 					case 1:
1235 						/* ... beginning to next */
1236 						fillw((vs.at << 8) | ' ',
1237 						    crtat - vs.col,
1238 						    vs.col + 1);
1239 						break;
1240 					case 2:
1241 						/* ... entire line */
1242 						fillw((vs.at << 8) | ' ',
1243 						    crtat - vs.col, vs.ncol);
1244 						break;
1245 					}
1246 					vs.state = 0;
1247 					break;
1248 				case 'f': /* in system V consoles */
1249 				case 'H': { /* Cursor move */
1250 					int cx = vs.cx,
1251 					    cy = vs.cy;
1252 					if (!cx || !cy) {
1253 						crtat = Crtat;
1254 						vs.col = 0;
1255 					} else {
1256 						if (cx > vs.nrow)
1257 							cx = vs.nrow;
1258 						if (cy > vs.ncol)
1259 							cy = vs.ncol;
1260 						crtat = Crtat +
1261 						    (cx - 1) * vs.ncol + cy - 1;
1262 						vs.col = cy - 1;
1263 					}
1264 					vs.state = 0;
1265 					break;
1266 				}
1267 				case 'M': { /* delete cx rows */
1268 					u_short *crtAt = crtat - vs.col;
1269 					int cx = vs.cx,
1270 					    row = (crtAt - Crtat) / vs.ncol,
1271 					    nrow = vs.nrow - row;
1272 					if (cx <= 0)
1273 						cx = 1;
1274 					else if (cx > nrow)
1275 						cx = nrow;
1276 					if (cx < nrow)
1277 #ifdef PCCONS_FORCE_WORD
1278 						wcopy(crtAt + vs.ncol * cx,
1279 						    crtAt, vs.ncol * (nrow -
1280 						    cx) * CHR);
1281 #else
1282 						memmove(crtAt,
1283 						    crtAt + vs.ncol * cx,
1284 						    vs.ncol * (nrow - cx) *
1285 						    CHR);
1286 #endif
1287 					fillw((vs.at << 8) | ' ',
1288 					    crtAt + vs.ncol * (nrow - cx),
1289 					    vs.ncol * cx);
1290 					vs.state = 0;
1291 					break;
1292 				}
1293 				case 'S': { /* scroll up cx lines */
1294 					int cx = vs.cx;
1295 					if (cx <= 0)
1296 						cx = 1;
1297 					else if (cx > vs.nrow)
1298 						cx = vs.nrow;
1299 					if (cx < vs.nrow)
1300 #ifdef PCCONS_FORCE_WORD
1301 						wcopy(Crtat + vs.ncol * cx,
1302 						    Crtat, vs.ncol * (vs.nrow -
1303 						    cx) * CHR);
1304 #else
1305 						memmove(Crtat,
1306 						    Crtat + vs.ncol * cx,
1307 						    vs.ncol * (vs.nrow - cx) *
1308 						    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 						memmove(crtAt + vs.ncol * cx,
1334 						    crtAt,
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 						memmove(Crtat + vs.ncol * cx,
1357 						    Crtat,
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 				memmove(Crtat, Crtat + vs.ncol,
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