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