xref: /netbsd-src/sys/arch/arc/dev/pccons.c (revision cdc507f0d27576e5c4f30629a5cfe9e1f5271dbe)
1*cdc507f0Sandvar /*	$NetBSD: pccons.c,v 1.63 2022/05/24 20:50:18 andvar Exp $	*/
271f6ef9eSsoda /*	$OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $	*/
3564df9b6Ssoda /*	NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp	*/
48519eaf8Ssoda 
58519eaf8Ssoda /*-
68519eaf8Ssoda  * Copyright (c) 1990 The Regents of the University of California.
78519eaf8Ssoda  * All rights reserved.
88519eaf8Ssoda  *
98519eaf8Ssoda  * This code is derived from software contributed to Berkeley by
108519eaf8Ssoda  * William Jolitz and Don Ahn.
118519eaf8Ssoda  *
12aad01611Sagc  * modification, are permitted provided that the following conditions
13aad01611Sagc  * are met:
14aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
15aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
16aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
17aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
18aad01611Sagc  *    documentation and/or other materials provided with the distribution.
19aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
20aad01611Sagc  *    may be used to endorse or promote products derived from this software
21aad01611Sagc  *    without specific prior written permission.
22aad01611Sagc  *
23aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33aad01611Sagc  * SUCH DAMAGE.
34aad01611Sagc  *
35aad01611Sagc  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
36aad01611Sagc  */
37aad01611Sagc 
38aad01611Sagc /*-
39aad01611Sagc  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
40aad01611Sagc  *
41aad01611Sagc  * This code is derived from software contributed to Berkeley by
42aad01611Sagc  * William Jolitz and Don Ahn.
43aad01611Sagc  *
448519eaf8Ssoda  * Copyright (c) 1994 Charles M. Hannum.
458519eaf8Ssoda  * Copyright (c) 1992, 1993 Erik Forsberg.
468519eaf8Ssoda  *
478519eaf8Ssoda  * Redistribution and use in source and binary forms, with or without
488519eaf8Ssoda  * modification, are permitted provided that the following conditions
498519eaf8Ssoda  * are met:
508519eaf8Ssoda  * 1. Redistributions of source code must retain the above copyright
518519eaf8Ssoda  *    notice, this list of conditions and the following disclaimer.
528519eaf8Ssoda  * 2. Redistributions in binary form must reproduce the above copyright
538519eaf8Ssoda  *    notice, this list of conditions and the following disclaimer in the
548519eaf8Ssoda  *    documentation and/or other materials provided with the distribution.
558519eaf8Ssoda  * 3. All advertising materials mentioning features or use of this software
568519eaf8Ssoda  *    must display the following acknowledgement:
578519eaf8Ssoda  *	This product includes software developed by the University of
588519eaf8Ssoda  *	California, Berkeley and its contributors.
598519eaf8Ssoda  * 4. Neither the name of the University nor the names of its contributors
608519eaf8Ssoda  *    may be used to endorse or promote products derived from this software
618519eaf8Ssoda  *    without specific prior written permission.
628519eaf8Ssoda  *
638519eaf8Ssoda  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
648519eaf8Ssoda  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
658519eaf8Ssoda  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
668519eaf8Ssoda  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
678519eaf8Ssoda  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
688519eaf8Ssoda  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
698519eaf8Ssoda  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
708519eaf8Ssoda  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
718519eaf8Ssoda  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
728519eaf8Ssoda  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
738519eaf8Ssoda  * SUCH DAMAGE.
748519eaf8Ssoda  *
758519eaf8Ssoda  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
768519eaf8Ssoda  */
778519eaf8Ssoda 
788519eaf8Ssoda /*
798519eaf8Ssoda  * code to work keyboard & display for PC-style console
808519eaf8Ssoda  */
818519eaf8Ssoda 
82a4183603Slukem #include <sys/cdefs.h>
83*cdc507f0Sandvar __KERNEL_RCSID(0, "$NetBSD: pccons.c,v 1.63 2022/05/24 20:50:18 andvar Exp $");
84a4183603Slukem 
8571f6ef9eSsoda #include "opt_ddb.h"
8671f6ef9eSsoda 
878519eaf8Ssoda #include <sys/param.h>
888519eaf8Ssoda #include <sys/systm.h>
898519eaf8Ssoda #include <sys/tty.h>
908519eaf8Ssoda #include <sys/callout.h>
918519eaf8Ssoda #include <sys/poll.h>
92564df9b6Ssoda #include <sys/conf.h>
93564df9b6Ssoda #include <sys/vnode.h>
94564df9b6Ssoda #include <sys/kernel.h>
95564df9b6Ssoda #include <sys/kcore.h>
96b7abba77Ssoda #include <sys/device.h>
9780373b7eSchs #include <sys/proc.h>
988ccb6c93Selad #include <sys/kauth.h>
998519eaf8Ssoda 
100cf10107dSdyoung #include <sys/bus.h>
101b7abba77Ssoda 
1020b60e690Stsutsui #include <dev/ic/pcdisplay.h>
1038519eaf8Ssoda #include <machine/pccons.h>
1048519eaf8Ssoda #include <machine/kbdreg.h>
1058519eaf8Ssoda 
106564df9b6Ssoda #include <dev/cons.h>
107b7abba77Ssoda #include <dev/isa/isavar.h>
108564df9b6Ssoda 
109b7abba77Ssoda #include <arc/arc/arcbios.h>
110b7abba77Ssoda #include <arc/dev/pcconsvar.h>
1115175a612Ssoda 
112c234c43aStsutsui #include "ioconf.h"
113c234c43aStsutsui 
1148519eaf8Ssoda #define	XFREE86_BUG_COMPAT
1158519eaf8Ssoda 
1168519eaf8Ssoda #ifndef BEEP_FREQ
1178519eaf8Ssoda #define BEEP_FREQ 1600
1188519eaf8Ssoda #endif
1198519eaf8Ssoda #ifndef BEEP_TIME
1208519eaf8Ssoda #define BEEP_TIME (hz/5)
1218519eaf8Ssoda #endif
1228519eaf8Ssoda 
1238519eaf8Ssoda #define PCBURST 128
1248519eaf8Ssoda 
1258519eaf8Ssoda static u_short *Crtat;			/* pointer to backing store */
1268519eaf8Ssoda static u_short *crtat;			/* pointer to current char */
1278519eaf8Ssoda static u_char async, kernel, polling;	/* Really, you don't want to know. */
1288519eaf8Ssoda static u_char lock_state = 0x00,	/* all off */
1298519eaf8Ssoda 	      old_lock_state = 0xff,
1308519eaf8Ssoda 	      typematic_rate = 0xff,	/* don't update until set by user */
1318519eaf8Ssoda 	      old_typematic_rate = 0xff;
1328519eaf8Ssoda static u_short cursor_shape = 0xffff,	/* don't update until set by user */
1338519eaf8Ssoda 	       old_cursor_shape = 0xffff;
134564df9b6Ssoda static pccons_keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */
1358519eaf8Ssoda int pc_xmode = 0;
1368519eaf8Ssoda 
1378519eaf8Ssoda /*
1388519eaf8Ssoda  *  Keyboard output queue.
1398519eaf8Ssoda  */
1408519eaf8Ssoda int	kb_oq_put = 0;
1418519eaf8Ssoda int	kb_oq_get = 0;
1428519eaf8Ssoda u_char	kb_oq[8];
1438519eaf8Ssoda 
1448519eaf8Ssoda #define	PCUNIT(x)	(minor(x))
1458519eaf8Ssoda 
1468519eaf8Ssoda static struct video_state {
1478519eaf8Ssoda 	int 	cx, cy;		/* escape parameters */
1488519eaf8Ssoda 	int 	row, col;	/* current cursor position */
1498519eaf8Ssoda 	int 	nrow, ncol, nchr;	/* current screen geometry */
150564df9b6Ssoda 	int	offset;		/* Saved cursor pos */
1518519eaf8Ssoda 	u_char	state;		/* parser state */
1528519eaf8Ssoda #define	VSS_ESCAPE	1
1538519eaf8Ssoda #define	VSS_EBRACE	2
1548519eaf8Ssoda #define	VSS_EPARAM	3
1558519eaf8Ssoda 	char	so;		/* in standout mode? */
1568519eaf8Ssoda 	char	color;		/* color or mono display */
1578519eaf8Ssoda 	char	at;		/* normal attributes */
1588519eaf8Ssoda 	char	so_at;		/* standout attributes */
1598519eaf8Ssoda } vs;
1608519eaf8Ssoda 
16188ab7da9Sad static callout_t async_update_ch;
162b667a5a3Sthorpej 
1637fe2a5a0Stsutsui void pc_xmode_on(void);
1647fe2a5a0Stsutsui void pc_xmode_off(void);
1657fe2a5a0Stsutsui static u_char kbc_get8042cmd(void);
1667fe2a5a0Stsutsui int kbd_cmd(u_char, u_char);
1675f1c88d7Sperry static inline int kbd_wait_output(void);
1685f1c88d7Sperry static inline int kbd_wait_input(void);
1697fe2a5a0Stsutsui void kbd_flush_input(void);
1707fe2a5a0Stsutsui void set_cursor_shape(void);
1717fe2a5a0Stsutsui void get_cursor_shape(void);
1727fe2a5a0Stsutsui void async_update(void);
1737fe2a5a0Stsutsui void do_async_update(u_char);
1748519eaf8Ssoda 
1757fe2a5a0Stsutsui void pccnputc(dev_t, int c);
1767fe2a5a0Stsutsui int pccngetc(dev_t);
1777fe2a5a0Stsutsui void pccnpollc(dev_t, int);
1788519eaf8Ssoda 
17977a6b82bSgehenna dev_type_open(pcopen);
18077a6b82bSgehenna dev_type_close(pcclose);
18177a6b82bSgehenna dev_type_read(pcread);
18277a6b82bSgehenna dev_type_write(pcwrite);
18377a6b82bSgehenna dev_type_ioctl(pcioctl);
18477a6b82bSgehenna dev_type_tty(pctty);
18577a6b82bSgehenna dev_type_poll(pcpoll);
18677a6b82bSgehenna dev_type_mmap(pcmmap);
18777a6b82bSgehenna 
18877a6b82bSgehenna const struct cdevsw pc_cdevsw = {
189a68f9396Sdholland 	.d_open = pcopen,
190a68f9396Sdholland 	.d_close = pcclose,
191a68f9396Sdholland 	.d_read = pcread,
192a68f9396Sdholland 	.d_write = pcwrite,
193a68f9396Sdholland 	.d_ioctl = pcioctl,
194a68f9396Sdholland 	.d_stop = nostop,
195a68f9396Sdholland 	.d_tty = pctty,
196a68f9396Sdholland 	.d_poll = pcpoll,
197a68f9396Sdholland 	.d_mmap = pcmmap,
198a68f9396Sdholland 	.d_kqfilter = ttykqfilter,
199f9228f42Sdholland 	.d_discard = nodiscard,
200a68f9396Sdholland 	.d_flag = D_TTY
20177a6b82bSgehenna };
20277a6b82bSgehenna 
2038519eaf8Ssoda #define	CHR		2
2048519eaf8Ssoda 
2057fe2a5a0Stsutsui char *sget(void);
20620751a78Smatt void sput(const u_char *, int);
2078519eaf8Ssoda 
2087fe2a5a0Stsutsui void	pcstart(struct tty *);
2097fe2a5a0Stsutsui int	pcparam(struct tty *, struct termios *);
2105f1c88d7Sperry static inline void wcopy(void *, void *, u_int);
2117fe2a5a0Stsutsui void	pc_context_init(bus_space_tag_t, bus_space_tag_t, bus_space_tag_t,
2127fe2a5a0Stsutsui 	    struct pccons_config *);
213564df9b6Ssoda 
2147fe2a5a0Stsutsui extern void fillw(int, uint16_t *, int);
2158519eaf8Ssoda 
2168519eaf8Ssoda #define	KBD_DELAY \
2178519eaf8Ssoda 		DELAY(10);
2188519eaf8Ssoda 
219b7abba77Ssoda #define crtc_read_1(reg) \
220b7abba77Ssoda 	bus_space_read_1(pccons_console_context.pc_crt_iot, \
221b7abba77Ssoda 	    pccons_console_context.pc_6845_ioh, reg)
222b7abba77Ssoda #define crtc_write_1(reg, data) \
223b7abba77Ssoda 	bus_space_write_1(pccons_console_context.pc_crt_iot, \
224b7abba77Ssoda 	    pccons_console_context.pc_6845_ioh, reg, data)
225b7abba77Ssoda 
226b7abba77Ssoda struct pccons_context pccons_console_context;
227b7abba77Ssoda 
2285175a612Ssoda void
kbd_context_init(bus_space_tag_t kbd_iot,struct pccons_config * config)2297fe2a5a0Stsutsui kbd_context_init(bus_space_tag_t kbd_iot, struct pccons_config *config)
2305175a612Ssoda {
231b7abba77Ssoda 	struct pccons_kbd_context *pkc = &pccons_console_context.pc_pkc;
2325175a612Ssoda 
233b7abba77Ssoda 	if (pkc->pkc_initialized)
2345175a612Ssoda 		return;
235b7abba77Ssoda 	pkc->pkc_initialized = 1;
2365175a612Ssoda 
237b7abba77Ssoda 	pkc->pkc_iot = kbd_iot;
2385175a612Ssoda 
239b7abba77Ssoda 	bus_space_map(kbd_iot, config->pc_kbd_cmdp, 1, 0,
240b7abba77Ssoda 	    &pkc->pkc_cmd_ioh);
241b7abba77Ssoda 	bus_space_map(kbd_iot, config->pc_kbd_datap, 1, 0,
242b7abba77Ssoda 	    &pkc->pkc_data_ioh);
2435175a612Ssoda }
244b7abba77Ssoda 
245b7abba77Ssoda void
pc_context_init(bus_space_tag_t crt_iot,bus_space_tag_t crt_memt,bus_space_tag_t kbd_iot,struct pccons_config * config)2467fe2a5a0Stsutsui pc_context_init(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
2477fe2a5a0Stsutsui     bus_space_tag_t kbd_iot, struct pccons_config *config)
248b7abba77Ssoda {
249b7abba77Ssoda 	struct pccons_context *pc = &pccons_console_context;
250b7abba77Ssoda 
251b7abba77Ssoda 	if (pc->pc_initialized)
252b7abba77Ssoda 		return;
253b7abba77Ssoda 	pc->pc_initialized = 1;
254b7abba77Ssoda 
255b7abba77Ssoda 	kbd_context_init(kbd_iot, config);
256b7abba77Ssoda 
257b7abba77Ssoda 	pc->pc_crt_iot = crt_iot;
258b7abba77Ssoda 	pc->pc_crt_memt = crt_memt;
259b7abba77Ssoda 
260b7abba77Ssoda 	bus_space_map(crt_iot, config->pc_mono_iobase, 2, 0,
261b7abba77Ssoda 	    &pc->pc_mono_ioh);
262b7abba77Ssoda 	bus_space_map(crt_memt, config->pc_mono_memaddr, 0x20000, 0,
263b7abba77Ssoda 	    &pc->pc_mono_memh);
264b7abba77Ssoda 	bus_space_map(crt_iot, config->pc_cga_iobase, 2, 0,
265b7abba77Ssoda 	    &pc->pc_cga_ioh);
266b7abba77Ssoda 	bus_space_map(crt_memt, config->pc_cga_memaddr, 0x20000, 0,
267b7abba77Ssoda 	    &pc->pc_cga_memh);
268b7abba77Ssoda 
269b7abba77Ssoda 	/*
270b7abba77Ssoda 	 * pc->pc_6845_ioh and pc->pc_crt_memh will be initialized later,
271b7abba77Ssoda 	 * when `Crtat' is initialized.
272b7abba77Ssoda 	 */
273b7abba77Ssoda 
274b7abba77Ssoda 	pc->pc_config = config;
275b7abba77Ssoda 
276b7abba77Ssoda 	(*config->pc_init)();
2775175a612Ssoda }
2785175a612Ssoda 
279564df9b6Ssoda /*
280564df9b6Ssoda  * bcopy variant that only moves word-aligned 16-bit entities,
281e9281952Stsutsui  * for stupid VGA cards.  cnt is required to be an even value.
282564df9b6Ssoda  */
2835f1c88d7Sperry static inline void
wcopy(void * src,void * tgt,u_int cnt)2847fe2a5a0Stsutsui wcopy(void *src, void *tgt, u_int cnt)
285564df9b6Ssoda {
2867fe2a5a0Stsutsui 	uint16_t *from = src;
2877fe2a5a0Stsutsui 	uint16_t *to = tgt;
288564df9b6Ssoda 
289564df9b6Ssoda 	cnt >>= 1;
290564df9b6Ssoda 	if (to < from || to >= from + cnt)
291564df9b6Ssoda 		while (cnt--)
292564df9b6Ssoda 			*to++ = *from++;
293564df9b6Ssoda 	else {
294564df9b6Ssoda 		to += cnt;
295564df9b6Ssoda 		from += cnt;
296564df9b6Ssoda 		while (cnt--)
297564df9b6Ssoda 			*--to = *--from;
298564df9b6Ssoda 	}
299564df9b6Ssoda }
300564df9b6Ssoda 
3015f1c88d7Sperry static inline int
kbd_wait_output(void)3027fe2a5a0Stsutsui kbd_wait_output(void)
3038519eaf8Ssoda {
3048519eaf8Ssoda 	u_int i;
3058519eaf8Ssoda 
3068519eaf8Ssoda 	for (i = 100000; i; i--)
307b7abba77Ssoda 		if ((kbd_cmd_read_1() & KBS_IBF) == 0) {
3088519eaf8Ssoda 			KBD_DELAY;
3098519eaf8Ssoda 			return 1;
3108519eaf8Ssoda 		}
3118519eaf8Ssoda 	return 0;
3128519eaf8Ssoda }
3138519eaf8Ssoda 
3145f1c88d7Sperry static inline int
kbd_wait_input(void)3157fe2a5a0Stsutsui kbd_wait_input(void)
3168519eaf8Ssoda {
3178519eaf8Ssoda 	u_int i;
3188519eaf8Ssoda 
3198519eaf8Ssoda 	for (i = 100000; i; i--)
320b7abba77Ssoda 		if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
3218519eaf8Ssoda 			KBD_DELAY;
3228519eaf8Ssoda 			return 1;
3238519eaf8Ssoda 		}
3248519eaf8Ssoda 	return 0;
3258519eaf8Ssoda }
3268519eaf8Ssoda 
327b7abba77Ssoda void
kbd_flush_input(void)3287fe2a5a0Stsutsui kbd_flush_input(void)
3298519eaf8Ssoda {
3307fe2a5a0Stsutsui 	uint8_t c;
3318519eaf8Ssoda 
332b7abba77Ssoda 	while ((c = kbd_cmd_read_1()) & 0x03)
3338519eaf8Ssoda 		if ((c & KBS_DIB) == KBS_DIB) {
3348519eaf8Ssoda 			/* XXX - delay is needed to prevent some keyboards from
3358519eaf8Ssoda 			   wedging when the system boots */
3368519eaf8Ssoda 			delay(6);
337b7abba77Ssoda 			(void)kbd_data_read_1();
3388519eaf8Ssoda 		}
3398519eaf8Ssoda }
3408519eaf8Ssoda 
3418519eaf8Ssoda #if 1
3428519eaf8Ssoda /*
3438519eaf8Ssoda  * Get the current command byte.
3448519eaf8Ssoda  */
3458519eaf8Ssoda static u_char
kbc_get8042cmd(void)3467fe2a5a0Stsutsui kbc_get8042cmd(void)
3478519eaf8Ssoda {
3488519eaf8Ssoda 
3498519eaf8Ssoda 	if (!kbd_wait_output())
3508519eaf8Ssoda 		return -1;
351b7abba77Ssoda 	kbd_cmd_write_1(K_RDCMDBYTE);
3528519eaf8Ssoda 	if (!kbd_wait_input())
3538519eaf8Ssoda 		return -1;
354b7abba77Ssoda 	return kbd_data_read_1();
3558519eaf8Ssoda }
3568519eaf8Ssoda #endif
3578519eaf8Ssoda 
3588519eaf8Ssoda /*
3598519eaf8Ssoda  * Pass command byte to keyboard controller (8042).
3608519eaf8Ssoda  */
361b7abba77Ssoda int
kbc_put8042cmd(uint8_t val)36282357f6dSdsl kbc_put8042cmd(uint8_t val)
3638519eaf8Ssoda {
3648519eaf8Ssoda 
3658519eaf8Ssoda 	if (!kbd_wait_output())
3668519eaf8Ssoda 		return 0;
367b7abba77Ssoda 	kbd_cmd_write_1(K_LDCMDBYTE);
3688519eaf8Ssoda 	if (!kbd_wait_output())
3698519eaf8Ssoda 		return 0;
370b7abba77Ssoda 	kbd_data_write_1(val);
3718519eaf8Ssoda 	return 1;
3728519eaf8Ssoda }
3738519eaf8Ssoda 
3748519eaf8Ssoda /*
3758519eaf8Ssoda  * Pass command to keyboard itself
3768519eaf8Ssoda  */
3778519eaf8Ssoda int
kbd_cmd(uint8_t val,uint8_t polled)37820751a78Smatt kbd_cmd(uint8_t val, uint8_t polled)
3798519eaf8Ssoda {
3808519eaf8Ssoda 	u_int retries = 3;
3818e19dfb2Stsutsui 	u_int i;
3828519eaf8Ssoda 
38320751a78Smatt 	if (!polled) {
3848519eaf8Ssoda 		i = spltty();
3858519eaf8Ssoda 		if (kb_oq_get == kb_oq_put) {
386b7abba77Ssoda 			kbd_data_write_1(val);
3878519eaf8Ssoda 		}
3888519eaf8Ssoda 		kb_oq[kb_oq_put] = val;
3898519eaf8Ssoda 		kb_oq_put = (kb_oq_put + 1) & 7;
3908519eaf8Ssoda 		splx(i);
3917fe2a5a0Stsutsui 		return 1;
3928519eaf8Ssoda 	}
39320751a78Smatt 
39420751a78Smatt 	do {
3958519eaf8Ssoda 		if (!kbd_wait_output())
3968519eaf8Ssoda 			return 0;
397b7abba77Ssoda 		kbd_data_write_1(val);
3988519eaf8Ssoda 		for (i = 100000; i; i--) {
399b7abba77Ssoda 			if (kbd_cmd_read_1() & KBS_DIB) {
4007fe2a5a0Stsutsui 				uint8_t c;
4018519eaf8Ssoda 
4028519eaf8Ssoda 				KBD_DELAY;
403b7abba77Ssoda 				c = kbd_data_read_1();
4048519eaf8Ssoda 				if (c == KBR_ACK || c == KBR_ECHO) {
4058519eaf8Ssoda 					return 1;
4068519eaf8Ssoda 				}
4078519eaf8Ssoda 				if (c == KBR_RESEND) {
4088519eaf8Ssoda 					break;
4098519eaf8Ssoda 				}
4108519eaf8Ssoda #ifdef DIAGNOSTIC
4118519eaf8Ssoda 				printf("kbd_cmd: input char %x lost\n", c);
4128519eaf8Ssoda #endif
4138519eaf8Ssoda 			}
4148519eaf8Ssoda 		}
4158519eaf8Ssoda 	} while (--retries);
4168519eaf8Ssoda 	return 0;
4178519eaf8Ssoda }
4188519eaf8Ssoda 
4198519eaf8Ssoda void
set_cursor_shape(void)4207fe2a5a0Stsutsui set_cursor_shape(void)
4218519eaf8Ssoda {
4227fe2a5a0Stsutsui 
423b7abba77Ssoda 	crtc_write_1(0, 10);
424b7abba77Ssoda 	crtc_write_1(1, cursor_shape >> 8);
425b7abba77Ssoda 	crtc_write_1(0, 11);
426b7abba77Ssoda 	crtc_write_1(1, cursor_shape);
4278519eaf8Ssoda 	old_cursor_shape = cursor_shape;
4288519eaf8Ssoda }
4298519eaf8Ssoda 
4308519eaf8Ssoda void
get_cursor_shape(void)4317fe2a5a0Stsutsui get_cursor_shape(void)
4328519eaf8Ssoda {
4337fe2a5a0Stsutsui 
434b7abba77Ssoda 	crtc_write_1(0, 10);
435b7abba77Ssoda 	cursor_shape = crtc_read_1(1) << 8;
436b7abba77Ssoda 	crtc_write_1(0, 11);
437b7abba77Ssoda 	cursor_shape |= crtc_read_1(1);
4388519eaf8Ssoda 
4398519eaf8Ssoda 	/*
4408519eaf8Ssoda 	 * real 6845's, as found on, MDA, Hercules or CGA cards, do
4418519eaf8Ssoda 	 * not support reading the cursor shape registers. the 6845
442f0a7346dSsnj 	 * tri-states its data bus. This is _normally_ read by the
443d20841bbSwiz 	 * CPU as either 0x00 or 0xff.. in which case we just use
4448519eaf8Ssoda 	 * a line cursor.
4458519eaf8Ssoda 	 */
4468519eaf8Ssoda 	if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
4478519eaf8Ssoda 		cursor_shape = 0x0b10;
4488519eaf8Ssoda 	else
4498519eaf8Ssoda 		cursor_shape &= 0x1f1f;
4508519eaf8Ssoda }
4518519eaf8Ssoda 
4528519eaf8Ssoda void
do_async_update(uint8_t poll)4537fe2a5a0Stsutsui do_async_update(uint8_t poll)
4548519eaf8Ssoda {
4558519eaf8Ssoda 	int pos;
4568519eaf8Ssoda 	static int old_pos = -1;
4578519eaf8Ssoda 
4588519eaf8Ssoda 	async = 0;
4598519eaf8Ssoda 
4608519eaf8Ssoda 	if (lock_state != old_lock_state) {
4618519eaf8Ssoda 		old_lock_state = lock_state;
4628519eaf8Ssoda 		if (!kbd_cmd(KBC_MODEIND, poll) ||
4638519eaf8Ssoda 		    !kbd_cmd(lock_state, poll)) {
4648519eaf8Ssoda 			printf("pc: timeout updating leds\n");
4658519eaf8Ssoda 			(void) kbd_cmd(KBC_ENABLE, poll);
4668519eaf8Ssoda 		}
4678519eaf8Ssoda 	}
4688519eaf8Ssoda 	if (typematic_rate != old_typematic_rate) {
4698519eaf8Ssoda 		old_typematic_rate = typematic_rate;
4708519eaf8Ssoda 		if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
4718519eaf8Ssoda 		    !kbd_cmd(typematic_rate, poll)) {
4728519eaf8Ssoda 			printf("pc: timeout updating typematic rate\n");
4738519eaf8Ssoda 			(void) kbd_cmd(KBC_ENABLE, poll);
4748519eaf8Ssoda 		}
4758519eaf8Ssoda 	}
4768519eaf8Ssoda 
4778519eaf8Ssoda 	if (pc_xmode > 0)
4788519eaf8Ssoda 		return;
4798519eaf8Ssoda 
4808519eaf8Ssoda 	pos = crtat - Crtat;
4818519eaf8Ssoda 	if (pos != old_pos) {
482b7abba77Ssoda 		crtc_write_1(0, 14);
483b7abba77Ssoda 		crtc_write_1(1, pos >> 8);
484b7abba77Ssoda 		crtc_write_1(0, 15);
485b7abba77Ssoda 		crtc_write_1(1, pos);
4868519eaf8Ssoda 		old_pos = pos;
4878519eaf8Ssoda 	}
4888519eaf8Ssoda 	if (cursor_shape != old_cursor_shape)
4898519eaf8Ssoda 		set_cursor_shape();
4908519eaf8Ssoda }
4918519eaf8Ssoda 
4928519eaf8Ssoda void
async_update(void)4937fe2a5a0Stsutsui async_update(void)
4948519eaf8Ssoda {
4958519eaf8Ssoda 
4968519eaf8Ssoda 	if (kernel || polling) {
4978519eaf8Ssoda 		if (async)
498b667a5a3Sthorpej 			callout_stop(&async_update_ch);
4998519eaf8Ssoda 		do_async_update(1);
5008519eaf8Ssoda 	} else {
5018519eaf8Ssoda 		if (async)
5028519eaf8Ssoda 			return;
5038519eaf8Ssoda 		async = 1;
504b667a5a3Sthorpej 		callout_reset(&async_update_ch, 1,
505b667a5a3Sthorpej 		    (void(*)(void *))do_async_update, NULL);
5068519eaf8Ssoda 	}
5078519eaf8Ssoda }
5088519eaf8Ssoda 
5098519eaf8Ssoda /*
5108519eaf8Ssoda  * these are both bad jokes
5118519eaf8Ssoda  */
5128519eaf8Ssoda int
pccons_common_match(bus_space_tag_t crt_iot,bus_space_tag_t crt_memt,bus_space_tag_t kbd_iot,struct pccons_config * config)5137fe2a5a0Stsutsui pccons_common_match(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
5147fe2a5a0Stsutsui     bus_space_tag_t kbd_iot, struct pccons_config *config)
5158519eaf8Ssoda {
516b7abba77Ssoda 	int i;
5178519eaf8Ssoda 
518b7abba77Ssoda 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
5198519eaf8Ssoda 
5208519eaf8Ssoda 	/* Enable interrupts and keyboard, etc. */
5218519eaf8Ssoda 	if (!kbc_put8042cmd(CMDBYTE)) {
522564df9b6Ssoda 		printf("pcprobe: command error\n");
5238519eaf8Ssoda 		return 0;
5248519eaf8Ssoda 	}
5258519eaf8Ssoda 
5268519eaf8Ssoda #if 1
5278519eaf8Ssoda 	/* Flush any garbage. */
5288519eaf8Ssoda 	kbd_flush_input();
5298519eaf8Ssoda 	/* Reset the keyboard. */
5308519eaf8Ssoda 	if (!kbd_cmd(KBC_RESET, 1)) {
531564df9b6Ssoda 		printf("pcprobe: reset error %d\n", 1);
5328519eaf8Ssoda 		goto lose;
5338519eaf8Ssoda 	}
5348519eaf8Ssoda 	for (i = 600000; i; i--)
535b7abba77Ssoda 		if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
5368519eaf8Ssoda 			KBD_DELAY;
5378519eaf8Ssoda 			break;
5388519eaf8Ssoda 		}
539b7abba77Ssoda 	if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) {
540564df9b6Ssoda 		printf("pcprobe: reset error %d\n", 2);
5418519eaf8Ssoda 		goto lose;
5428519eaf8Ssoda 	}
5438519eaf8Ssoda 	/*
5448519eaf8Ssoda 	 * Some keyboards seem to leave a second ack byte after the reset.
5458519eaf8Ssoda 	 * This is kind of stupid, but we account for them anyway by just
5468519eaf8Ssoda 	 * flushing the buffer.
5478519eaf8Ssoda 	 */
5488519eaf8Ssoda 	kbd_flush_input();
5498519eaf8Ssoda 	/* Just to be sure. */
5508519eaf8Ssoda 	if (!kbd_cmd(KBC_ENABLE, 1)) {
551564df9b6Ssoda 		printf("pcprobe: reset error %d\n", 3);
5528519eaf8Ssoda 		goto lose;
5538519eaf8Ssoda 	}
5548519eaf8Ssoda 
5558519eaf8Ssoda 	/*
5568519eaf8Ssoda 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
5578519eaf8Ssoda 	 * is set to table 1; in fact, it would appear that some keyboards just
5588519eaf8Ssoda 	 * ignore the command altogether.  So by default, we use the AT scan
5598519eaf8Ssoda 	 * codes and have the 8042 translate them.  Unfortunately, this is
560*cdc507f0Sandvar 	 * known to not work on some PS/2 machines.  We try desperately to deal
5618519eaf8Ssoda 	 * with this by checking the (lack of a) translate bit in the 8042 and
5628519eaf8Ssoda 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
5638519eaf8Ssoda 	 * tough luck.
5648519eaf8Ssoda 	 *
5658519eaf8Ssoda 	 * XXX It would perhaps be a better choice to just use AT scan codes
5668519eaf8Ssoda 	 * and not bother with this.
5678519eaf8Ssoda 	 */
5688519eaf8Ssoda 	if (kbc_get8042cmd() & KC8_TRANS) {
5698519eaf8Ssoda 		/* The 8042 is translating for us; use AT codes. */
5708519eaf8Ssoda 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
571564df9b6Ssoda 			printf("pcprobe: reset error %d\n", 4);
5728519eaf8Ssoda 			goto lose;
5738519eaf8Ssoda 		}
5748519eaf8Ssoda 	} else {
5758519eaf8Ssoda 		/* Stupid 8042; set keyboard to XT codes. */
5768519eaf8Ssoda 		if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
577564df9b6Ssoda 			printf("pcprobe: reset error %d\n", 5);
5788519eaf8Ssoda 			goto lose;
5798519eaf8Ssoda 		}
5808519eaf8Ssoda 	}
5818519eaf8Ssoda 
5828519eaf8Ssoda lose:
5838519eaf8Ssoda 	/*
584564df9b6Ssoda 	 * Technically, we should probably fail the probe.  But we'll be nice
5858519eaf8Ssoda 	 * and allow keyboard-less machines to boot with the console.
5868519eaf8Ssoda 	 */
5878519eaf8Ssoda #endif
5888519eaf8Ssoda 
5898519eaf8Ssoda 	return 1;
5908519eaf8Ssoda }
5918519eaf8Ssoda 
pccons_common_attach(struct pc_softc * sc,bus_space_tag_t crt_iot,bus_space_tag_t crt_memt,bus_space_tag_t kbd_iot,struct pccons_config * config)5927fe2a5a0Stsutsui void pccons_common_attach(struct pc_softc *sc, bus_space_tag_t crt_iot,
5937fe2a5a0Stsutsui     bus_space_tag_t crt_memt, bus_space_tag_t kbd_iot,
5947fe2a5a0Stsutsui     struct pccons_config *config)
5958519eaf8Ssoda {
5967fe2a5a0Stsutsui 
5978519eaf8Ssoda 	printf(": %s\n", vs.color ? "color" : "mono");
59888ab7da9Sad 	callout_init(&async_update_ch, 0);
5998519eaf8Ssoda 	do_async_update(1);
6008519eaf8Ssoda }
6018519eaf8Ssoda 
6028519eaf8Ssoda int
pcopen(dev_t dev,int flag,int mode,struct lwp * l)60395e1ffb1Schristos pcopen(dev_t dev, int flag, int mode, struct lwp *l)
6048519eaf8Ssoda {
6058519eaf8Ssoda 	struct pc_softc *sc;
6068519eaf8Ssoda 	struct tty *tp;
6078519eaf8Ssoda 
608fa11f9bfScegger 	sc = device_lookup_private(&pc_cd, PCUNIT(dev));
609fa11f9bfScegger 	if (sc == NULL)
6108519eaf8Ssoda 		return ENXIO;
6118519eaf8Ssoda 
6128519eaf8Ssoda 	if (!sc->sc_tty) {
6132626d576Srmind 		tp = sc->sc_tty = tty_alloc();
6148519eaf8Ssoda 	}
6158519eaf8Ssoda 	else {
6168519eaf8Ssoda 		tp = sc->sc_tty;
6178519eaf8Ssoda 	}
6188519eaf8Ssoda 
6198519eaf8Ssoda 	tp->t_oproc = pcstart;
6208519eaf8Ssoda 	tp->t_param = pcparam;
6218519eaf8Ssoda 	tp->t_dev = dev;
622e8373398Selad 
623e8373398Selad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
624e8373398Selad 		return (EBUSY);
625e8373398Selad 
6268519eaf8Ssoda 	if ((tp->t_state & TS_ISOPEN) == 0) {
6278519eaf8Ssoda 		ttychars(tp);
6288519eaf8Ssoda 		tp->t_iflag = TTYDEF_IFLAG;
6298519eaf8Ssoda 		tp->t_oflag = TTYDEF_OFLAG;
6308519eaf8Ssoda 		tp->t_cflag = TTYDEF_CFLAG;
6318519eaf8Ssoda 		tp->t_lflag = TTYDEF_LFLAG;
6328519eaf8Ssoda 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
6338519eaf8Ssoda 		pcparam(tp, &tp->t_termios);
6348519eaf8Ssoda 		ttsetwater(tp);
635e8373398Selad 	}
636e8373398Selad 
6378519eaf8Ssoda 	tp->t_state |= TS_CARR_ON;
6388519eaf8Ssoda 
6397fe2a5a0Stsutsui 	return (*tp->t_linesw->l_open)(dev, tp);
6408519eaf8Ssoda }
6418519eaf8Ssoda 
6428519eaf8Ssoda int
pcclose(dev_t dev,int flag,int mode,struct lwp * l)64395e1ffb1Schristos pcclose(dev_t dev, int flag, int mode, struct lwp *l)
6448519eaf8Ssoda {
645fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
6468519eaf8Ssoda 	struct tty *tp = sc->sc_tty;
6478519eaf8Ssoda 
648bc736332Seeh 	(*tp->t_linesw->l_close)(tp, flag);
6498519eaf8Ssoda 	ttyclose(tp);
6508519eaf8Ssoda #ifdef notyet /* XXX */
6512626d576Srmind 	tty_free(tp);
6528519eaf8Ssoda #endif
6537fe2a5a0Stsutsui 	return 0;
6548519eaf8Ssoda }
6558519eaf8Ssoda 
6568519eaf8Ssoda int
pcread(dev_t dev,struct uio * uio,int flag)6577fe2a5a0Stsutsui pcread(dev_t dev, struct uio *uio, int flag)
6588519eaf8Ssoda {
659fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
6608519eaf8Ssoda 	struct tty *tp = sc->sc_tty;
6618519eaf8Ssoda 
6627fe2a5a0Stsutsui 	return (*tp->t_linesw->l_read)(tp, uio, flag);
6638519eaf8Ssoda }
6648519eaf8Ssoda 
6658519eaf8Ssoda int
pcwrite(dev_t dev,struct uio * uio,int flag)6667fe2a5a0Stsutsui pcwrite(dev_t dev, struct uio *uio, int flag)
6678519eaf8Ssoda {
668fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
6698519eaf8Ssoda 	struct tty *tp = sc->sc_tty;
6708519eaf8Ssoda 
6717fe2a5a0Stsutsui 	return (*tp->t_linesw->l_write)(tp, uio, flag);
6728519eaf8Ssoda }
6738519eaf8Ssoda 
6742963ff5cSscw int
pcpoll(dev_t dev,int events,struct lwp * l)67595e1ffb1Schristos pcpoll(dev_t dev, int events, struct lwp *l)
6762963ff5cSscw {
677fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
6782963ff5cSscw 	struct tty *tp = sc->sc_tty;
6792963ff5cSscw 
68095e1ffb1Schristos 	return (*tp->t_linesw->l_poll)(tp, events, l);
6812963ff5cSscw }
6822963ff5cSscw 
6838519eaf8Ssoda struct tty *
pctty(dev_t dev)6847fe2a5a0Stsutsui pctty(dev_t dev)
6858519eaf8Ssoda {
686fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
6878519eaf8Ssoda 	struct tty *tp = sc->sc_tty;
6888519eaf8Ssoda 
6897fe2a5a0Stsutsui 	return tp;
6908519eaf8Ssoda }
6918519eaf8Ssoda 
6928519eaf8Ssoda /*
6938519eaf8Ssoda  * Got a console receive interrupt -
6948519eaf8Ssoda  * the console processor wants to give us a character.
6958519eaf8Ssoda  * Catch the character, and see who it goes to.
6968519eaf8Ssoda  */
6978519eaf8Ssoda int
pcintr(void * arg)6987fe2a5a0Stsutsui pcintr(void *arg)
6998519eaf8Ssoda {
7008519eaf8Ssoda 	struct pc_softc *sc = arg;
7018e19dfb2Stsutsui 	struct tty *tp = sc->sc_tty;
7027fe2a5a0Stsutsui 	uint8_t *cp;
7038519eaf8Ssoda 
704b7abba77Ssoda 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
7058519eaf8Ssoda 		return 0;
7068519eaf8Ssoda 	if (polling)
7078519eaf8Ssoda 		return 1;
7088519eaf8Ssoda 	do {
7098519eaf8Ssoda 		cp = sget();
7108519eaf8Ssoda 		if (!tp || (tp->t_state & TS_ISOPEN) == 0)
7118519eaf8Ssoda 			return 1;
7128519eaf8Ssoda 		if (cp)
7138519eaf8Ssoda 			do
714bc736332Seeh 				(*tp->t_linesw->l_rint)(*cp++, tp);
7158519eaf8Ssoda 			while (*cp);
716b7abba77Ssoda 	} while (kbd_cmd_read_1() & KBS_DIB);
7178519eaf8Ssoda 	return 1;
7188519eaf8Ssoda }
7198519eaf8Ssoda 
7208519eaf8Ssoda int
pcioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)72153524e44Schristos pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
7228519eaf8Ssoda {
723fa11f9bfScegger 	struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
7248519eaf8Ssoda 	struct tty *tp = sc->sc_tty;
7258519eaf8Ssoda 	int error;
7268519eaf8Ssoda 
72795e1ffb1Schristos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
72831144d99Satatat 	if (error != EPASSTHROUGH)
7298519eaf8Ssoda 		return error;
73095e1ffb1Schristos 	error = ttioctl(tp, cmd, data, flag, l);
73131144d99Satatat 	if (error != EPASSTHROUGH)
7328519eaf8Ssoda 		return error;
7338519eaf8Ssoda 
7348519eaf8Ssoda 	switch (cmd) {
7358519eaf8Ssoda 	case CONSOLE_X_MODE_ON:
7368519eaf8Ssoda 		pc_xmode_on();
7378519eaf8Ssoda 		return 0;
7388519eaf8Ssoda 	case CONSOLE_X_MODE_OFF:
7398519eaf8Ssoda 		pc_xmode_off();
7408519eaf8Ssoda 		return 0;
7418519eaf8Ssoda 	case CONSOLE_X_BELL:
7428519eaf8Ssoda 		/*
7438519eaf8Ssoda 		 * If set, data is a pointer to a length 2 array of
7448519eaf8Ssoda 		 * integers.  data[0] is the pitch in Hz and data[1]
7458519eaf8Ssoda 		 * is the duration in msec.
7468519eaf8Ssoda 		 */
7478519eaf8Ssoda 		if (data)
7488519eaf8Ssoda 			sysbeep(((int*)data)[0],
7498519eaf8Ssoda 				(((int*)data)[1] * hz) / 1000);
7508519eaf8Ssoda 		else
7518519eaf8Ssoda 			sysbeep(BEEP_FREQ, BEEP_TIME);
7528519eaf8Ssoda 		return 0;
7538519eaf8Ssoda 	case CONSOLE_SET_TYPEMATIC_RATE: {
7548519eaf8Ssoda  		u_char	rate;
7558519eaf8Ssoda 
7568519eaf8Ssoda  		if (!data)
7578519eaf8Ssoda 			return EINVAL;
7588519eaf8Ssoda 		rate = *((u_char *)data);
7598519eaf8Ssoda 		/*
7608519eaf8Ssoda 		 * Check that it isn't too big (which would cause it to be
7618519eaf8Ssoda 		 * confused with a command).
7628519eaf8Ssoda 		 */
7638519eaf8Ssoda 		if (rate & 0x80)
7648519eaf8Ssoda 			return EINVAL;
7658519eaf8Ssoda 		typematic_rate = rate;
7668519eaf8Ssoda 		async_update();
7678519eaf8Ssoda 		return 0;
7688519eaf8Ssoda  	}
769564df9b6Ssoda 	case CONSOLE_SET_KEYMAP: {
770564df9b6Ssoda 		pccons_keymap_t *map = (pccons_keymap_t *) data;
771564df9b6Ssoda 		int i;
772564df9b6Ssoda 
773564df9b6Ssoda 		if (!data)
774564df9b6Ssoda 			return EINVAL;
775564df9b6Ssoda 		for (i = 0; i < KB_NUM_KEYS; i++)
776564df9b6Ssoda 			if (map[i].unshift[KB_CODE_SIZE-1] ||
777564df9b6Ssoda 			    map[i].shift[KB_CODE_SIZE-1] ||
778564df9b6Ssoda 			    map[i].ctl[KB_CODE_SIZE-1] ||
779564df9b6Ssoda 			    map[i].altgr[KB_CODE_SIZE-1] ||
780564df9b6Ssoda 			    map[i].shift_altgr[KB_CODE_SIZE-1])
781564df9b6Ssoda 				return EINVAL;
782564df9b6Ssoda 
783e9281952Stsutsui 		memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
784564df9b6Ssoda 		return 0;
785564df9b6Ssoda 	}
786564df9b6Ssoda 	case CONSOLE_GET_KEYMAP:
787564df9b6Ssoda 		if (!data)
788564df9b6Ssoda 			return EINVAL;
789e9281952Stsutsui 		memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
790564df9b6Ssoda 		return 0;
791564df9b6Ssoda 
7928519eaf8Ssoda 	default:
79331144d99Satatat 		return EPASSTHROUGH;
7948519eaf8Ssoda 	}
7958519eaf8Ssoda 
7968519eaf8Ssoda #ifdef DIAGNOSTIC
7978519eaf8Ssoda 	panic("pcioctl: impossible");
7988519eaf8Ssoda #endif
7998519eaf8Ssoda }
8008519eaf8Ssoda 
8018519eaf8Ssoda void
pcstart(struct tty * tp)8027fe2a5a0Stsutsui pcstart(struct tty *tp)
8038519eaf8Ssoda {
804b93d54e0Stsutsui 	struct clist *cl;
805564df9b6Ssoda 	int s, len;
8068519eaf8Ssoda 	u_char buf[PCBURST];
8078519eaf8Ssoda 
8088519eaf8Ssoda 	s = spltty();
8098519eaf8Ssoda 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
8108519eaf8Ssoda 		goto out;
8118519eaf8Ssoda 	tp->t_state |= TS_BUSY;
8128519eaf8Ssoda 	splx(s);
8138519eaf8Ssoda 	/*
8148519eaf8Ssoda 	 * We need to do this outside spl since it could be fairly
8158519eaf8Ssoda 	 * expensive and we don't want our serial ports to overflow.
8168519eaf8Ssoda 	 */
817b93d54e0Stsutsui 	cl = &tp->t_outq;
8188519eaf8Ssoda 	len = q_to_b(cl, buf, PCBURST);
8198519eaf8Ssoda 	sput(buf, len);
8208519eaf8Ssoda 	s = spltty();
8218519eaf8Ssoda 	tp->t_state &= ~TS_BUSY;
822dc26833bSad 	if (ttypull(tp)) {
8238519eaf8Ssoda 		tp->t_state |= TS_TIMEOUT;
824d238692cSjoerg 		callout_schedule(&tp->t_rstrt_ch, 1);
8258519eaf8Ssoda 	}
8268519eaf8Ssoda out:
8278519eaf8Ssoda 	splx(s);
8288519eaf8Ssoda }
8298519eaf8Ssoda 
8308519eaf8Ssoda /* ARGSUSED */
pccons_common_cnattach(bus_space_tag_t crt_iot,bus_space_tag_t crt_memt,bus_space_tag_t kbd_iot,struct pccons_config * config)8317fe2a5a0Stsutsui void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
8327fe2a5a0Stsutsui     bus_space_tag_t kbd_iot, struct pccons_config *config)
8338519eaf8Ssoda {
834564df9b6Ssoda 	int maj;
835564df9b6Ssoda 	static struct consdev pccons = {
8361654f7e0Stsutsui 		NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
8371654f7e0Stsutsui 		    NULL, NODEV, CN_NORMAL
838564df9b6Ssoda 	};
8398519eaf8Ssoda 
8408519eaf8Ssoda 	/*
8418519eaf8Ssoda 	 * For now, don't screw with it.
8428519eaf8Ssoda 	 */
8438519eaf8Ssoda 	/* crtat = 0; */
8445175a612Ssoda 
845b7abba77Ssoda 	pc_context_init(crt_iot, crt_memt, kbd_iot, config);
846564df9b6Ssoda 
847564df9b6Ssoda 	/* locate the major number */
84877a6b82bSgehenna 	maj = cdevsw_lookup_major(&pc_cdevsw);
849564df9b6Ssoda 	pccons.cn_dev = makedev(maj, 0);
850564df9b6Ssoda 
851564df9b6Ssoda 	cn_tab = &pccons;
8528519eaf8Ssoda }
8538519eaf8Ssoda 
8548519eaf8Ssoda /* ARGSUSED */
8558519eaf8Ssoda void
pccnputc(dev_t dev,int c)8567fe2a5a0Stsutsui pccnputc(dev_t dev, int c)
8578519eaf8Ssoda {
85865102815Ssoda 	u_char cc, oldkernel = kernel;
8598519eaf8Ssoda 
8608519eaf8Ssoda 	kernel = 1;
86165102815Ssoda 	if (c == '\n') {
8628519eaf8Ssoda 		sput("\r\n", 2);
86365102815Ssoda 	} else {
86465102815Ssoda 		cc = c;
86565102815Ssoda 		sput(&cc, 1);
86665102815Ssoda 	}
8678519eaf8Ssoda 	kernel = oldkernel;
8688519eaf8Ssoda }
8698519eaf8Ssoda 
8708519eaf8Ssoda /* ARGSUSED */
871564df9b6Ssoda int
pccngetc(dev_t dev)8727fe2a5a0Stsutsui pccngetc(dev_t dev)
8738519eaf8Ssoda {
8748e19dfb2Stsutsui 	char *cp;
8758519eaf8Ssoda 
8768519eaf8Ssoda 	if (pc_xmode > 0)
8778519eaf8Ssoda 		return 0;
8788519eaf8Ssoda 
8798519eaf8Ssoda 	do {
8808519eaf8Ssoda 		/* wait for byte */
881b7abba77Ssoda 		while ((kbd_cmd_read_1() & KBS_DIB) == 0);
8828519eaf8Ssoda 		/* see if it's worthwhile */
8838519eaf8Ssoda 		cp = sget();
8848519eaf8Ssoda 	} while (!cp);
8858519eaf8Ssoda 	if (*cp == '\r')
8868519eaf8Ssoda 		return '\n';
8878519eaf8Ssoda 	return *cp;
8888519eaf8Ssoda }
8898519eaf8Ssoda 
8908519eaf8Ssoda void
pccnpollc(dev_t dev,int on)8917fe2a5a0Stsutsui pccnpollc(dev_t dev, int on)
8928519eaf8Ssoda {
8938519eaf8Ssoda 
8948519eaf8Ssoda 	polling = on;
8958519eaf8Ssoda 	if (!on) {
8968519eaf8Ssoda 		int unit;
8978519eaf8Ssoda 		struct pc_softc *sc;
8988519eaf8Ssoda 		int s;
8998519eaf8Ssoda 
9008519eaf8Ssoda 		/*
9018519eaf8Ssoda 		 * If disabling polling on a device that's been configured,
9028519eaf8Ssoda 		 * make sure there are no bytes left in the FIFO, holding up
9038519eaf8Ssoda 		 * the interrupt line.  Otherwise we won't get any further
9048519eaf8Ssoda 		 * interrupts.
9058519eaf8Ssoda 		 */
9068519eaf8Ssoda 		unit = PCUNIT(dev);
9078519eaf8Ssoda 		if (pc_cd.cd_ndevs > unit) {
908fa11f9bfScegger 			sc = device_lookup_private(&pc_cd, unit);
909fa11f9bfScegger 			if (sc != NULL) {
9108519eaf8Ssoda 				s = spltty();
9118519eaf8Ssoda 				pcintr(sc);
9128519eaf8Ssoda 				splx(s);
9138519eaf8Ssoda 			}
9148519eaf8Ssoda 		}
9158519eaf8Ssoda 	}
9168519eaf8Ssoda }
9178519eaf8Ssoda 
9188519eaf8Ssoda /*
9198519eaf8Ssoda  * Set line parameters.
9208519eaf8Ssoda  */
9218519eaf8Ssoda int
pcparam(struct tty * tp,struct termios * t)9227fe2a5a0Stsutsui pcparam(struct tty *tp, struct termios *t)
9238519eaf8Ssoda {
9248519eaf8Ssoda 
9258519eaf8Ssoda 	tp->t_ispeed = t->c_ispeed;
9268519eaf8Ssoda 	tp->t_ospeed = t->c_ospeed;
9278519eaf8Ssoda 	tp->t_cflag = t->c_cflag;
9288519eaf8Ssoda 	return 0;
9298519eaf8Ssoda }
9308519eaf8Ssoda 
9318519eaf8Ssoda #define	wrtchar(c, at) do {\
93220751a78Smatt 	char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
9338519eaf8Ssoda } while (0)
9348519eaf8Ssoda 
9358519eaf8Ssoda /* translate ANSI color codes to standard pc ones */
9368519eaf8Ssoda static char fgansitopc[] = {
9378519eaf8Ssoda 	FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
9388519eaf8Ssoda 	FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
9398519eaf8Ssoda };
9408519eaf8Ssoda 
9418519eaf8Ssoda static char bgansitopc[] = {
9428519eaf8Ssoda 	BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
9438519eaf8Ssoda 	BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
9448519eaf8Ssoda };
9458519eaf8Ssoda 
9468519eaf8Ssoda static u_char iso2ibm437[] =
9478519eaf8Ssoda {
9488519eaf8Ssoda             0,     0,     0,     0,     0,     0,     0,     0,
9498519eaf8Ssoda             0,     0,     0,     0,     0,     0,     0,     0,
9508519eaf8Ssoda             0,     0,     0,     0,     0,     0,     0,     0,
9518519eaf8Ssoda             0,     0,     0,     0,     0,     0,     0,     0,
9528519eaf8Ssoda          0xff,  0xad,  0x9b,  0x9c,     0,  0x9d,     0,  0x40,
9538519eaf8Ssoda          0x6f,  0x63,  0x61,  0xae,     0,     0,     0,     0,
9548519eaf8Ssoda          0xf8,  0xf1,  0xfd,  0x33,     0,  0xe6,     0,  0xfa,
9558519eaf8Ssoda             0,  0x31,  0x6f,  0xaf,  0xac,  0xab,     0,  0xa8,
9568519eaf8Ssoda          0x41,  0x41,  0x41,  0x41,  0x8e,  0x8f,  0x92,  0x80,
9578519eaf8Ssoda          0x45,  0x90,  0x45,  0x45,  0x49,  0x49,  0x49,  0x49,
9588519eaf8Ssoda          0x81,  0xa5,  0x4f,  0x4f,  0x4f,  0x4f,  0x99,  0x4f,
9598519eaf8Ssoda          0x4f,  0x55,  0x55,  0x55,  0x9a,  0x59,     0,  0xe1,
9608519eaf8Ssoda          0x85,  0xa0,  0x83,  0x61,  0x84,  0x86,  0x91,  0x87,
9618519eaf8Ssoda          0x8a,  0x82,  0x88,  0x89,  0x8d,  0xa1,  0x8c,  0x8b,
9628519eaf8Ssoda             0,  0xa4,  0x95,  0xa2,  0x93,  0x6f,  0x94,  0x6f,
9638519eaf8Ssoda          0x6f,  0x97,  0xa3,  0x96,  0x81,  0x98,     0,     0
9648519eaf8Ssoda };
9658519eaf8Ssoda 
9668519eaf8Ssoda /*
9678519eaf8Ssoda  * `pc3' termcap emulation.
9688519eaf8Ssoda  */
9698519eaf8Ssoda void
sput(const u_char * cp,int n)97020751a78Smatt sput(const u_char *cp, int n)
9718519eaf8Ssoda {
972b7abba77Ssoda 	struct pccons_context *pc = &pccons_console_context;
9738519eaf8Ssoda 	u_char c, scroll = 0;
9748519eaf8Ssoda 
9758519eaf8Ssoda 	if (pc_xmode > 0)
9768519eaf8Ssoda 		return;
9778519eaf8Ssoda 
9788519eaf8Ssoda 	if (crtat == 0) {
97920751a78Smatt 		volatile u_short *dp;
9808519eaf8Ssoda 		u_short was;
9818519eaf8Ssoda 		unsigned cursorat;
9828519eaf8Ssoda 
98320751a78Smatt 		dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
98420751a78Smatt 		was = *dp;
98520751a78Smatt 		*dp = 0xA55A;
98620751a78Smatt 		if (*dp != 0xA55A) {
98720751a78Smatt 			dp = bus_space_vaddr(pc->pc_crt_memt,
988b7abba77Ssoda 			    pc->pc_mono_memh);
989b7abba77Ssoda 			pc->pc_6845_ioh = pc->pc_mono_ioh;
990b7abba77Ssoda 			pc->pc_crt_memh = pc->pc_mono_memh;
9918519eaf8Ssoda 			vs.color = 0;
9928519eaf8Ssoda 		} else {
99320751a78Smatt 			*dp = was;
994b7abba77Ssoda 			pc->pc_6845_ioh = pc->pc_cga_ioh;
995b7abba77Ssoda 			pc->pc_crt_memh = pc->pc_cga_memh;
9968519eaf8Ssoda 			vs.color = 1;
9978519eaf8Ssoda 		}
9988519eaf8Ssoda 
9998519eaf8Ssoda #ifdef FAT_CURSOR
10008519eaf8Ssoda 		cursor_shape = 0x0012;
10018519eaf8Ssoda #else
10028519eaf8Ssoda 		get_cursor_shape();
10038519eaf8Ssoda #endif
10048519eaf8Ssoda 
1005564df9b6Ssoda 		bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
1006564df9b6Ssoda 		vs.nchr = vs.ncol * vs.nrow;
1007564df9b6Ssoda 		vs.col--;
1008564df9b6Ssoda 		vs.row--;
1009564df9b6Ssoda 		cursorat = vs.ncol * vs.row + vs.col;
10108519eaf8Ssoda 		vs.at = FG_LIGHTGREY | BG_BLACK;
10118519eaf8Ssoda 
101220751a78Smatt 		Crtat = (u_short *)__UNVOLATILE(dp);
1013564df9b6Ssoda 		crtat = Crtat + cursorat;
1014564df9b6Ssoda 
10158519eaf8Ssoda 		if (vs.color == 0)
10168519eaf8Ssoda 			vs.so_at = FG_BLACK | BG_LIGHTGREY;
10178519eaf8Ssoda 		else
10188519eaf8Ssoda 			vs.so_at = FG_YELLOW | BG_BLACK;
10198519eaf8Ssoda 
10208519eaf8Ssoda 		fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
10218519eaf8Ssoda 	}
10228519eaf8Ssoda 
10238519eaf8Ssoda 	while (n--) {
10248519eaf8Ssoda 		if (!(c = *cp++))
10258519eaf8Ssoda 			continue;
10268519eaf8Ssoda 
10278519eaf8Ssoda 		switch (c) {
10288519eaf8Ssoda 		case 0x1B:
10298519eaf8Ssoda 			if (vs.state >= VSS_ESCAPE) {
10308519eaf8Ssoda 				wrtchar(c, vs.so_at);
10318519eaf8Ssoda 				vs.state = 0;
10328519eaf8Ssoda 				goto maybe_scroll;
10338519eaf8Ssoda 			} else
10348519eaf8Ssoda 				vs.state = VSS_ESCAPE;
10358519eaf8Ssoda 			break;
10368519eaf8Ssoda 
1037564df9b6Ssoda 		case 0x9B:	/* CSI */
1038564df9b6Ssoda 			vs.cx = vs.cy = 0;
1039564df9b6Ssoda 			vs.state = VSS_EBRACE;
1040564df9b6Ssoda 			break;
1041564df9b6Ssoda 
10428519eaf8Ssoda 		case '\t': {
10438519eaf8Ssoda 			int inccol = 8 - (vs.col & 7);
10448519eaf8Ssoda 			crtat += inccol;
10458519eaf8Ssoda 			vs.col += inccol;
10468519eaf8Ssoda 		}
10478519eaf8Ssoda 		maybe_scroll:
1048564df9b6Ssoda 			if (vs.col >= vs.ncol) {
1049564df9b6Ssoda 				vs.col -= vs.ncol;
10508519eaf8Ssoda 				scroll = 1;
10518519eaf8Ssoda 			}
10528519eaf8Ssoda 			break;
10538519eaf8Ssoda 
1054564df9b6Ssoda 		case '\b':
10558519eaf8Ssoda 			if (crtat <= Crtat)
10568519eaf8Ssoda 				break;
10578519eaf8Ssoda 			--crtat;
10588519eaf8Ssoda 			if (--vs.col < 0)
1059564df9b6Ssoda 				vs.col += vs.ncol;	/* non-destructive backspace */
10608519eaf8Ssoda 			break;
10618519eaf8Ssoda 
10628519eaf8Ssoda 		case '\r':
10638519eaf8Ssoda 			crtat -= vs.col;
10648519eaf8Ssoda 			vs.col = 0;
10658519eaf8Ssoda 			break;
10668519eaf8Ssoda 
10678519eaf8Ssoda 		case '\n':
10688519eaf8Ssoda 			crtat += vs.ncol;
10698519eaf8Ssoda 			scroll = 1;
10708519eaf8Ssoda 			break;
10718519eaf8Ssoda 
10728519eaf8Ssoda 		default:
10738519eaf8Ssoda 			switch (vs.state) {
10748519eaf8Ssoda 			case 0:
10758519eaf8Ssoda 				if (c == '\a')
10768519eaf8Ssoda 					sysbeep(BEEP_FREQ, BEEP_TIME);
10778519eaf8Ssoda 				else {
10788519eaf8Ssoda 					/*
10798519eaf8Ssoda 					 * If we're outputting multiple printed
10808519eaf8Ssoda 					 * characters, just blast them to the
10818519eaf8Ssoda 					 * screen until we reach the end of the
10828519eaf8Ssoda 					 * buffer or a control character.  This
10838519eaf8Ssoda 					 * saves time by short-circuiting the
10848519eaf8Ssoda 					 * switch.
10858519eaf8Ssoda 					 * If we reach the end of the line, we
10868519eaf8Ssoda 					 * break to do a scroll check.
10878519eaf8Ssoda 					 */
10888519eaf8Ssoda 					for (;;) {
10898519eaf8Ssoda 						if (c & 0x80)
10908519eaf8Ssoda 							c = iso2ibm437[c&0x7f];
10918519eaf8Ssoda 
10928519eaf8Ssoda 						if (vs.so)
10938519eaf8Ssoda 							wrtchar(c, vs.so_at);
10948519eaf8Ssoda 						else
10958519eaf8Ssoda 							wrtchar(c, vs.at);
10968519eaf8Ssoda 						if (vs.col >= vs.ncol) {
10978519eaf8Ssoda 							vs.col = 0;
10988519eaf8Ssoda 							scroll = 1;
10998519eaf8Ssoda 							break;
11008519eaf8Ssoda 						}
11018519eaf8Ssoda 						if (!n || (c = *cp) < ' ')
11028519eaf8Ssoda 							break;
11038519eaf8Ssoda 						n--, cp++;
11048519eaf8Ssoda 					}
11058519eaf8Ssoda 				}
11068519eaf8Ssoda 				break;
11078519eaf8Ssoda 			case VSS_ESCAPE:
1108564df9b6Ssoda 				switch (c) {
1109564df9b6Ssoda 					case '[': /* Start ESC [ sequence */
11108519eaf8Ssoda 						vs.cx = vs.cy = 0;
11118519eaf8Ssoda 						vs.state = VSS_EBRACE;
1112564df9b6Ssoda 						break;
1113564df9b6Ssoda 					case 'c': /* Create screen & home */
1114564df9b6Ssoda 						fillw((vs.at << 8) | ' ',
1115564df9b6Ssoda 						    Crtat, vs.nchr);
11168519eaf8Ssoda 						crtat = Crtat;
11178519eaf8Ssoda 						vs.col = 0;
11188519eaf8Ssoda 						vs.state = 0;
1119564df9b6Ssoda 						break;
1120564df9b6Ssoda 					case '7': /* save cursor pos */
1121564df9b6Ssoda 						vs.offset = crtat - Crtat;
1122564df9b6Ssoda 						vs.state = 0;
1123564df9b6Ssoda 						break;
1124564df9b6Ssoda 					case '8': /* restore cursor pos */
1125564df9b6Ssoda 						crtat = Crtat + vs.offset;
1126564df9b6Ssoda 						vs.row = vs.offset / vs.ncol;
1127564df9b6Ssoda 						vs.col = vs.offset % vs.ncol;
1128564df9b6Ssoda 						vs.state = 0;
1129564df9b6Ssoda 						break;
1130564df9b6Ssoda 					default: /* Invalid, clear state */
11318519eaf8Ssoda 						wrtchar(c, vs.so_at);
11328519eaf8Ssoda 						vs.state = 0;
11338519eaf8Ssoda 						goto maybe_scroll;
11348519eaf8Ssoda 				}
11358519eaf8Ssoda 				break;
1136564df9b6Ssoda 
11378519eaf8Ssoda 			default: /* VSS_EBRACE or VSS_EPARAM */
11388519eaf8Ssoda 				switch (c) {
11398519eaf8Ssoda 					int pos;
11408519eaf8Ssoda 				case 'm':
11418519eaf8Ssoda 					if (!vs.cx)
11428519eaf8Ssoda 						vs.so = 0;
11438519eaf8Ssoda 					else
11448519eaf8Ssoda 						vs.so = 1;
11458519eaf8Ssoda 					vs.state = 0;
11468519eaf8Ssoda 					break;
11478519eaf8Ssoda 				case 'A': { /* back cx rows */
11488519eaf8Ssoda 					int cx = vs.cx;
11498519eaf8Ssoda 					if (cx <= 0)
11508519eaf8Ssoda 						cx = 1;
11518519eaf8Ssoda 					else
11528519eaf8Ssoda 						cx %= vs.nrow;
11538519eaf8Ssoda 					pos = crtat - Crtat;
11548519eaf8Ssoda 					pos -= vs.ncol * cx;
11558519eaf8Ssoda 					if (pos < 0)
11568519eaf8Ssoda 						pos += vs.nchr;
11578519eaf8Ssoda 					crtat = Crtat + pos;
11588519eaf8Ssoda 					vs.state = 0;
11598519eaf8Ssoda 					break;
11608519eaf8Ssoda 				}
11618519eaf8Ssoda 				case 'B': { /* down cx rows */
11628519eaf8Ssoda 					int cx = vs.cx;
11638519eaf8Ssoda 					if (cx <= 0)
11648519eaf8Ssoda 						cx = 1;
11658519eaf8Ssoda 					else
11668519eaf8Ssoda 						cx %= vs.nrow;
11678519eaf8Ssoda 					pos = crtat - Crtat;
11688519eaf8Ssoda 					pos += vs.ncol * cx;
11698519eaf8Ssoda 					if (pos >= vs.nchr)
11708519eaf8Ssoda 						pos -= vs.nchr;
11718519eaf8Ssoda 					crtat = Crtat + pos;
11728519eaf8Ssoda 					vs.state = 0;
11738519eaf8Ssoda 					break;
11748519eaf8Ssoda 				}
11758519eaf8Ssoda 				case 'C': { /* right cursor */
11768519eaf8Ssoda 					int cx = vs.cx,
11778519eaf8Ssoda 					    col = vs.col;
11788519eaf8Ssoda 					if (cx <= 0)
11798519eaf8Ssoda 						cx = 1;
11808519eaf8Ssoda 					else
11818519eaf8Ssoda 						cx %= vs.ncol;
11828519eaf8Ssoda 					pos = crtat - Crtat;
11838519eaf8Ssoda 					pos += cx;
11848519eaf8Ssoda 					col += cx;
11858519eaf8Ssoda 					if (col >= vs.ncol) {
11868519eaf8Ssoda 						pos -= vs.ncol;
11878519eaf8Ssoda 						col -= vs.ncol;
11888519eaf8Ssoda 					}
11898519eaf8Ssoda 					vs.col = col;
11908519eaf8Ssoda 					crtat = Crtat + pos;
11918519eaf8Ssoda 					vs.state = 0;
11928519eaf8Ssoda 					break;
11938519eaf8Ssoda 				}
11948519eaf8Ssoda 				case 'D': { /* left cursor */
11958519eaf8Ssoda 					int cx = vs.cx,
11968519eaf8Ssoda 					    col = vs.col;
11978519eaf8Ssoda 					if (cx <= 0)
11988519eaf8Ssoda 						cx = 1;
11998519eaf8Ssoda 					else
12008519eaf8Ssoda 						cx %= vs.ncol;
12018519eaf8Ssoda 					pos = crtat - Crtat;
12028519eaf8Ssoda 					pos -= cx;
12038519eaf8Ssoda 					col -= cx;
12048519eaf8Ssoda 					if (col < 0) {
12058519eaf8Ssoda 						pos += vs.ncol;
12068519eaf8Ssoda 						col += vs.ncol;
12078519eaf8Ssoda 					}
12088519eaf8Ssoda 					vs.col = col;
12098519eaf8Ssoda 					crtat = Crtat + pos;
12108519eaf8Ssoda 					vs.state = 0;
12118519eaf8Ssoda 					break;
12128519eaf8Ssoda 				}
12138519eaf8Ssoda 				case 'J': /* Clear ... */
12148519eaf8Ssoda 					switch (vs.cx) {
12158519eaf8Ssoda 					case 0:
12168519eaf8Ssoda 						/* ... to end of display */
1217564df9b6Ssoda 						fillw((vs.at << 8) | ' ',
1218564df9b6Ssoda 						    crtat,
12198519eaf8Ssoda 						    Crtat + vs.nchr - crtat);
12208519eaf8Ssoda 						break;
12218519eaf8Ssoda 					case 1:
12228519eaf8Ssoda 						/* ... to next location */
1223564df9b6Ssoda 						fillw((vs.at << 8) | ' ',
1224564df9b6Ssoda 						    Crtat,
12258519eaf8Ssoda 						    crtat - Crtat + 1);
12268519eaf8Ssoda 						break;
12278519eaf8Ssoda 					case 2:
12288519eaf8Ssoda 						/* ... whole display */
1229564df9b6Ssoda 						fillw((vs.at << 8) | ' ',
1230564df9b6Ssoda 						    Crtat,
12318519eaf8Ssoda 						    vs.nchr);
12328519eaf8Ssoda 						break;
12338519eaf8Ssoda 					}
12348519eaf8Ssoda 					vs.state = 0;
12358519eaf8Ssoda 					break;
12368519eaf8Ssoda 				case 'K': /* Clear line ... */
12378519eaf8Ssoda 					switch (vs.cx) {
12388519eaf8Ssoda 					case 0:
12398519eaf8Ssoda 						/* ... current to EOL */
1240564df9b6Ssoda 						fillw((vs.at << 8) | ' ',
1241564df9b6Ssoda 						    crtat,
12428519eaf8Ssoda 						    vs.ncol - vs.col);
12438519eaf8Ssoda 						break;
12448519eaf8Ssoda 					case 1:
12458519eaf8Ssoda 						/* ... beginning to next */
12468519eaf8Ssoda 						fillw((vs.at << 8) | ' ',
12478519eaf8Ssoda 						    crtat - vs.col,
12488519eaf8Ssoda 						    vs.col + 1);
12498519eaf8Ssoda 						break;
12508519eaf8Ssoda 					case 2:
12518519eaf8Ssoda 						/* ... entire line */
12528519eaf8Ssoda 						fillw((vs.at << 8) | ' ',
12538519eaf8Ssoda 						    crtat - vs.col, vs.ncol);
12548519eaf8Ssoda 						break;
12558519eaf8Ssoda 					}
12568519eaf8Ssoda 					vs.state = 0;
12578519eaf8Ssoda 					break;
12588519eaf8Ssoda 				case 'f': /* in system V consoles */
12598519eaf8Ssoda 				case 'H': { /* Cursor move */
12608519eaf8Ssoda 					int cx = vs.cx,
12618519eaf8Ssoda 					    cy = vs.cy;
12628519eaf8Ssoda 					if (!cx || !cy) {
12638519eaf8Ssoda 						crtat = Crtat;
12648519eaf8Ssoda 						vs.col = 0;
12658519eaf8Ssoda 					} else {
12668519eaf8Ssoda 						if (cx > vs.nrow)
12678519eaf8Ssoda 							cx = vs.nrow;
12688519eaf8Ssoda 						if (cy > vs.ncol)
12698519eaf8Ssoda 							cy = vs.ncol;
12708519eaf8Ssoda 						crtat = Crtat +
12718519eaf8Ssoda 						    (cx - 1) * vs.ncol + cy - 1;
12728519eaf8Ssoda 						vs.col = cy - 1;
12738519eaf8Ssoda 					}
12748519eaf8Ssoda 					vs.state = 0;
12758519eaf8Ssoda 					break;
12768519eaf8Ssoda 				}
12778519eaf8Ssoda 				case 'M': { /* delete cx rows */
12788519eaf8Ssoda 					u_short *crtAt = crtat - vs.col;
12798519eaf8Ssoda 					int cx = vs.cx,
12808519eaf8Ssoda 					    row = (crtAt - Crtat) / vs.ncol,
12818519eaf8Ssoda 					    nrow = vs.nrow - row;
12828519eaf8Ssoda 					if (cx <= 0)
12838519eaf8Ssoda 						cx = 1;
12848519eaf8Ssoda 					else if (cx > nrow)
12858519eaf8Ssoda 						cx = nrow;
12868519eaf8Ssoda 					if (cx < nrow)
1287564df9b6Ssoda #ifdef PCCONS_FORCE_WORD
1288564df9b6Ssoda 						wcopy(crtAt + vs.ncol * cx,
1289564df9b6Ssoda 						    crtAt, vs.ncol * (nrow -
1290564df9b6Ssoda 						    cx) * CHR);
1291564df9b6Ssoda #else
1292e9281952Stsutsui 						memmove(crtAt,
1293e9281952Stsutsui 						    crtAt + vs.ncol * cx,
1294e9281952Stsutsui 						    vs.ncol * (nrow - cx) *
1295e9281952Stsutsui 						    CHR);
1296564df9b6Ssoda #endif
12978519eaf8Ssoda 					fillw((vs.at << 8) | ' ',
12988519eaf8Ssoda 					    crtAt + vs.ncol * (nrow - cx),
12998519eaf8Ssoda 					    vs.ncol * cx);
13008519eaf8Ssoda 					vs.state = 0;
13018519eaf8Ssoda 					break;
13028519eaf8Ssoda 				}
13038519eaf8Ssoda 				case 'S': { /* scroll up cx lines */
13048519eaf8Ssoda 					int cx = vs.cx;
13058519eaf8Ssoda 					if (cx <= 0)
13068519eaf8Ssoda 						cx = 1;
13078519eaf8Ssoda 					else if (cx > vs.nrow)
13088519eaf8Ssoda 						cx = vs.nrow;
13098519eaf8Ssoda 					if (cx < vs.nrow)
1310564df9b6Ssoda #ifdef PCCONS_FORCE_WORD
1311564df9b6Ssoda 						wcopy(Crtat + vs.ncol * cx,
1312564df9b6Ssoda 						    Crtat, vs.ncol * (vs.nrow -
1313564df9b6Ssoda 						    cx) * CHR);
1314564df9b6Ssoda #else
1315e9281952Stsutsui 						memmove(Crtat,
1316e9281952Stsutsui 						    Crtat + vs.ncol * cx,
1317e9281952Stsutsui 						    vs.ncol * (vs.nrow - cx) *
1318e9281952Stsutsui 						    CHR);
1319564df9b6Ssoda #endif
13208519eaf8Ssoda 					fillw((vs.at << 8) | ' ',
13218519eaf8Ssoda 					    Crtat + vs.ncol * (vs.nrow - cx),
13228519eaf8Ssoda 					    vs.ncol * cx);
1323564df9b6Ssoda 					/* crtat -= vs.ncol * cx; XXX */
13248519eaf8Ssoda 					vs.state = 0;
13258519eaf8Ssoda 					break;
13268519eaf8Ssoda 				}
13278519eaf8Ssoda 				case 'L': { /* insert cx rows */
13288519eaf8Ssoda 					u_short *crtAt = crtat - vs.col;
13298519eaf8Ssoda 					int cx = vs.cx,
13308519eaf8Ssoda 					    row = (crtAt - Crtat) / vs.ncol,
13318519eaf8Ssoda 					    nrow = vs.nrow - row;
13328519eaf8Ssoda 					if (cx <= 0)
13338519eaf8Ssoda 						cx = 1;
13348519eaf8Ssoda 					else if (cx > nrow)
13358519eaf8Ssoda 						cx = nrow;
13368519eaf8Ssoda 					if (cx < nrow)
1337564df9b6Ssoda #ifdef PCCONS_FORCE_WORD
1338564df9b6Ssoda 						wcopy(crtAt,
1339564df9b6Ssoda 						    crtAt + vs.ncol * cx,
1340564df9b6Ssoda 						    vs.ncol * (nrow - cx) *
1341564df9b6Ssoda 						    CHR);
1342564df9b6Ssoda #else
1343e9281952Stsutsui 						memmove(crtAt + vs.ncol * cx,
1344e9281952Stsutsui 						    crtAt,
13458519eaf8Ssoda 						    vs.ncol * (nrow - cx) *
13468519eaf8Ssoda 						    CHR);
1347564df9b6Ssoda #endif
13488519eaf8Ssoda 					fillw((vs.at << 8) | ' ', crtAt,
13498519eaf8Ssoda 					    vs.ncol * cx);
13508519eaf8Ssoda 					vs.state = 0;
13518519eaf8Ssoda 					break;
13528519eaf8Ssoda 				}
13538519eaf8Ssoda 				case 'T': { /* scroll down cx lines */
13548519eaf8Ssoda 					int cx = vs.cx;
13558519eaf8Ssoda 					if (cx <= 0)
13568519eaf8Ssoda 						cx = 1;
13578519eaf8Ssoda 					else if (cx > vs.nrow)
13588519eaf8Ssoda 						cx = vs.nrow;
13598519eaf8Ssoda 					if (cx < vs.nrow)
1360564df9b6Ssoda #ifdef PCCONS_FORCE_WORD
1361564df9b6Ssoda 						wcopy(Crtat,
1362564df9b6Ssoda 						    Crtat + vs.ncol * cx,
1363564df9b6Ssoda 						    vs.ncol * (vs.nrow - cx) *
1364564df9b6Ssoda 						    CHR);
1365564df9b6Ssoda #else
1366e9281952Stsutsui 						memmove(Crtat + vs.ncol * cx,
1367e9281952Stsutsui 						    Crtat,
13688519eaf8Ssoda 						    vs.ncol * (vs.nrow - cx) *
13698519eaf8Ssoda 						    CHR);
1370564df9b6Ssoda #endif
13718519eaf8Ssoda 					fillw((vs.at << 8) | ' ', Crtat,
13728519eaf8Ssoda 					    vs.ncol * cx);
1373564df9b6Ssoda 					/* crtat += vs.ncol * cx; XXX */
13748519eaf8Ssoda 					vs.state = 0;
13758519eaf8Ssoda 					break;
13768519eaf8Ssoda 				}
13778519eaf8Ssoda 				case ';': /* Switch params in cursor def */
13788519eaf8Ssoda 					vs.state = VSS_EPARAM;
13798519eaf8Ssoda 					break;
13808519eaf8Ssoda 				case 'r':
13818519eaf8Ssoda 					vs.so_at = (vs.cx & FG_MASK) |
13828519eaf8Ssoda 					    ((vs.cy << 4) & BG_MASK);
13838519eaf8Ssoda 					vs.state = 0;
13848519eaf8Ssoda 					break;
1385564df9b6Ssoda 				case 's': /* save cursor pos */
1386564df9b6Ssoda 					vs.offset = crtat - Crtat;
1387564df9b6Ssoda 					vs.state = 0;
1388564df9b6Ssoda 					break;
1389564df9b6Ssoda 				case 'u': /* restore cursor pos */
1390564df9b6Ssoda 					crtat = Crtat + vs.offset;
1391564df9b6Ssoda 					vs.row = vs.offset / vs.ncol;
1392564df9b6Ssoda 					vs.col = vs.offset % vs.ncol;
1393564df9b6Ssoda 					vs.state = 0;
1394564df9b6Ssoda 					break;
13958519eaf8Ssoda 				case 'x': /* set attributes */
13968519eaf8Ssoda 					switch (vs.cx) {
13978519eaf8Ssoda 					case 0:
13988519eaf8Ssoda 						vs.at = FG_LIGHTGREY | BG_BLACK;
13998519eaf8Ssoda 						break;
14008519eaf8Ssoda 					case 1:
14018519eaf8Ssoda 						/* ansi background */
14028519eaf8Ssoda 						if (!vs.color)
14038519eaf8Ssoda 							break;
14048519eaf8Ssoda 						vs.at &= FG_MASK;
14058519eaf8Ssoda 						vs.at |= bgansitopc[vs.cy & 7];
14068519eaf8Ssoda 						break;
14078519eaf8Ssoda 					case 2:
14088519eaf8Ssoda 						/* ansi foreground */
14098519eaf8Ssoda 						if (!vs.color)
14108519eaf8Ssoda 							break;
14118519eaf8Ssoda 						vs.at &= BG_MASK;
14128519eaf8Ssoda 						vs.at |= fgansitopc[vs.cy & 7];
14138519eaf8Ssoda 						break;
14148519eaf8Ssoda 					case 3:
14158519eaf8Ssoda 						/* pc text attribute */
14168519eaf8Ssoda 						if (vs.state >= VSS_EPARAM)
14178519eaf8Ssoda 							vs.at = vs.cy;
14188519eaf8Ssoda 						break;
14198519eaf8Ssoda 					}
14208519eaf8Ssoda 					vs.state = 0;
14218519eaf8Ssoda 					break;
14228519eaf8Ssoda 
14238519eaf8Ssoda 				default: /* Only numbers valid here */
14248519eaf8Ssoda 					if ((c >= '0') && (c <= '9')) {
14258519eaf8Ssoda 						if (vs.state >= VSS_EPARAM) {
14268519eaf8Ssoda 							vs.cy *= 10;
14278519eaf8Ssoda 							vs.cy += c - '0';
14288519eaf8Ssoda 						} else {
14298519eaf8Ssoda 							vs.cx *= 10;
14308519eaf8Ssoda 							vs.cx += c - '0';
14318519eaf8Ssoda 						}
14328519eaf8Ssoda 					} else
14338519eaf8Ssoda 						vs.state = 0;
14348519eaf8Ssoda 					break;
14358519eaf8Ssoda 				}
14368519eaf8Ssoda 				break;
14378519eaf8Ssoda 			}
14388519eaf8Ssoda 		}
14398519eaf8Ssoda 		if (scroll) {
14408519eaf8Ssoda 			scroll = 0;
14418519eaf8Ssoda 			/* scroll check */
14428519eaf8Ssoda 			if (crtat >= Crtat + vs.nchr) {
14438519eaf8Ssoda 				if (!kernel) {
14448519eaf8Ssoda 					int s = spltty();
1445564df9b6Ssoda 					if (lock_state & KB_SCROLL)
1446564df9b6Ssoda 						tsleep(&lock_state,
14478519eaf8Ssoda 						    PUSER, "pcputc", 0);
14488519eaf8Ssoda 					splx(s);
14498519eaf8Ssoda 				}
1450564df9b6Ssoda #if PCCONS_FORCE_WORD
1451564df9b6Ssoda 				wcopy(Crtat + vs.ncol, Crtat,
1452564df9b6Ssoda 				    (vs.nchr - vs.ncol) * CHR);
1453564df9b6Ssoda #else
1454e9281952Stsutsui 				memmove(Crtat, Crtat + vs.ncol,
14558519eaf8Ssoda 				    (vs.nchr - vs.ncol) * CHR);
1456564df9b6Ssoda #endif
14578519eaf8Ssoda 				fillw((vs.at << 8) | ' ',
1458564df9b6Ssoda 				    Crtat + vs.nchr - vs.ncol,
1459564df9b6Ssoda 				    vs.ncol);
14608519eaf8Ssoda 				crtat -= vs.ncol;
14618519eaf8Ssoda 			}
14628519eaf8Ssoda 		}
14638519eaf8Ssoda 	}
14648519eaf8Ssoda 	async_update();
14658519eaf8Ssoda }
14668519eaf8Ssoda 
1467564df9b6Ssoda /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1468564df9b6Ssoda    left and right shift when reading the keyboard map */
1469564df9b6Ssoda static pccons_keymap_t	scan_codes[KB_NUM_KEYS] = {
1470564df9b6Ssoda /*  type       unshift   shift     control   altgr     shift_altgr scancode */
1471564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 0 unused */
1472564df9b6Ssoda   { KB_ASCII,  "\033",   "\033",   "\033",   "",       ""}, /* 1 ESCape */
1473564df9b6Ssoda   { KB_ASCII,  "1",      "!",      "!",      "",       ""}, /* 2 1 */
1474564df9b6Ssoda   { KB_ASCII,  "2",      "@",      "\000",   "",       ""}, /* 3 2 */
1475564df9b6Ssoda   { KB_ASCII,  "3",      "#",      "#",      "",       ""}, /* 4 3 */
1476564df9b6Ssoda   { KB_ASCII,  "4",      "$",      "$",      "",       ""}, /* 5 4 */
1477564df9b6Ssoda   { KB_ASCII,  "5",      "%",      "%",      "",       ""}, /* 6 5 */
1478564df9b6Ssoda   { KB_ASCII,  "6",      "^",      "\036",   "",       ""}, /* 7 6 */
1479564df9b6Ssoda   { KB_ASCII,  "7",      "&",      "&",      "",       ""}, /* 8 7 */
1480564df9b6Ssoda   { KB_ASCII,  "8",      "*",      "\010",   "",       ""}, /* 9 8 */
1481564df9b6Ssoda   { KB_ASCII,  "9",      "(",      "(",      "",       ""}, /* 10 9 */
1482564df9b6Ssoda   { KB_ASCII,  "0",      ")",      ")",      "",       ""}, /* 11 0 */
1483564df9b6Ssoda   { KB_ASCII,  "-",      "_",      "\037",   "",       ""}, /* 12 - */
1484564df9b6Ssoda   { KB_ASCII,  "=",      "+",      "+",      "",       ""}, /* 13 = */
1485564df9b6Ssoda   { KB_ASCII,  "\177",   "\177",   "\010",   "",       ""}, /* 14 backspace */
1486564df9b6Ssoda   { KB_ASCII,  "\t",     "\t",     "\t",     "",       ""}, /* 15 tab */
1487564df9b6Ssoda   { KB_ASCII,  "q",      "Q",      "\021",   "",       ""}, /* 16 q */
1488564df9b6Ssoda   { KB_ASCII,  "w",      "W",      "\027",   "",       ""}, /* 17 w */
1489564df9b6Ssoda   { KB_ASCII,  "e",      "E",      "\005",   "",       ""}, /* 18 e */
1490564df9b6Ssoda   { KB_ASCII,  "r",      "R",      "\022",   "",       ""}, /* 19 r */
1491564df9b6Ssoda   { KB_ASCII,  "t",      "T",      "\024",   "",       ""}, /* 20 t */
1492564df9b6Ssoda   { KB_ASCII,  "y",      "Y",      "\031",   "",       ""}, /* 21 y */
1493564df9b6Ssoda   { KB_ASCII,  "u",      "U",      "\025",   "",       ""}, /* 22 u */
1494564df9b6Ssoda   { KB_ASCII,  "i",      "I",      "\011",   "",       ""}, /* 23 i */
1495564df9b6Ssoda   { KB_ASCII,  "o",      "O",      "\017",   "",       ""}, /* 24 o */
1496564df9b6Ssoda   { KB_ASCII,  "p",      "P",      "\020",   "",       ""}, /* 25 p */
1497564df9b6Ssoda   { KB_ASCII,  "[",      "{",      "\033",   "",       ""}, /* 26 [ */
1498564df9b6Ssoda   { KB_ASCII,  "]",      "}",      "\035",   "",       ""}, /* 27 ] */
1499564df9b6Ssoda   { KB_ASCII,  "\r",     "\r",     "\n",     "",       ""}, /* 28 return */
1500564df9b6Ssoda   { KB_CTL,    "",       "",       "",       "",       ""}, /* 29 control */
1501564df9b6Ssoda   { KB_ASCII,  "a",      "A",      "\001",   "",       ""}, /* 30 a */
1502564df9b6Ssoda   { KB_ASCII,  "s",      "S",      "\023",   "",       ""}, /* 31 s */
1503564df9b6Ssoda   { KB_ASCII,  "d",      "D",      "\004",   "",       ""}, /* 32 d */
1504564df9b6Ssoda   { KB_ASCII,  "f",      "F",      "\006",   "",       ""}, /* 33 f */
1505564df9b6Ssoda   { KB_ASCII,  "g",      "G",      "\007",   "",       ""}, /* 34 g */
1506564df9b6Ssoda   { KB_ASCII,  "h",      "H",      "\010",   "",       ""}, /* 35 h */
1507564df9b6Ssoda   { KB_ASCII,  "j",      "J",      "\n",     "",       ""}, /* 36 j */
1508564df9b6Ssoda   { KB_ASCII,  "k",      "K",      "\013",   "",       ""}, /* 37 k */
1509564df9b6Ssoda   { KB_ASCII,  "l",      "L",      "\014",   "",       ""}, /* 38 l */
1510564df9b6Ssoda   { KB_ASCII,  ";",      ":",      ";",      "",       ""}, /* 39 ; */
1511564df9b6Ssoda   { KB_ASCII,  "'",      "\"",     "'",      "",       ""}, /* 40 ' */
1512564df9b6Ssoda   { KB_ASCII,  "`",      "~",      "`",      "",       ""}, /* 41 ` */
1513564df9b6Ssoda   { KB_SHIFT,  "\001",   "",       "",       "",       ""}, /* 42 shift */
1514564df9b6Ssoda   { KB_ASCII,  "\\",     "|",      "\034",   "",       ""}, /* 43 \ */
1515564df9b6Ssoda   { KB_ASCII,  "z",      "Z",      "\032",   "",       ""}, /* 44 z */
1516564df9b6Ssoda   { KB_ASCII,  "x",      "X",      "\030",   "",       ""}, /* 45 x */
1517564df9b6Ssoda   { KB_ASCII,  "c",      "C",      "\003",   "",       ""}, /* 46 c */
1518564df9b6Ssoda   { KB_ASCII,  "v",      "V",      "\026",   "",       ""}, /* 47 v */
1519564df9b6Ssoda   { KB_ASCII,  "b",      "B",      "\002",   "",       ""}, /* 48 b */
1520564df9b6Ssoda   { KB_ASCII,  "n",      "N",      "\016",   "",       ""}, /* 49 n */
1521564df9b6Ssoda   { KB_ASCII,  "m",      "M",      "\r",     "",       ""}, /* 50 m */
1522564df9b6Ssoda   { KB_ASCII,  ",",      "<",      "<",      "",       ""}, /* 51 , */
1523564df9b6Ssoda   { KB_ASCII,  ".",      ">",      ">",      "",       ""}, /* 52 . */
1524564df9b6Ssoda   { KB_ASCII,  "/",      "?",      "\037",   "",       ""}, /* 53 / */
1525564df9b6Ssoda   { KB_SHIFT,  "\002",   "",       "",       "",       ""}, /* 54 shift */
1526564df9b6Ssoda   { KB_KP,     "*",      "*",      "*",      "",       ""}, /* 55 kp * */
1527564df9b6Ssoda   { KB_ALT,    "",       "",       "",       "",       ""}, /* 56 alt */
1528564df9b6Ssoda   { KB_ASCII,  " ",      " ",      "\000",   "",       ""}, /* 57 space */
1529564df9b6Ssoda   { KB_CAPS,   "",       "",       "",       "",       ""}, /* 58 caps */
1530564df9b6Ssoda   { KB_FUNC,   "\033[M", "\033[Y", "\033[k", "",       ""}, /* 59 f1 */
1531564df9b6Ssoda   { KB_FUNC,   "\033[N", "\033[Z", "\033[l", "",       ""}, /* 60 f2 */
1532564df9b6Ssoda   { KB_FUNC,   "\033[O", "\033[a", "\033[m", "",       ""}, /* 61 f3 */
1533564df9b6Ssoda   { KB_FUNC,   "\033[P", "\033[b", "\033[n", "",       ""}, /* 62 f4 */
1534564df9b6Ssoda   { KB_FUNC,   "\033[Q", "\033[c", "\033[o", "",       ""}, /* 63 f5 */
1535564df9b6Ssoda   { KB_FUNC,   "\033[R", "\033[d", "\033[p", "",       ""}, /* 64 f6 */
1536564df9b6Ssoda   { KB_FUNC,   "\033[S", "\033[e", "\033[q", "",       ""}, /* 65 f7 */
1537564df9b6Ssoda   { KB_FUNC,   "\033[T", "\033[f", "\033[r", "",       ""}, /* 66 f8 */
1538564df9b6Ssoda   { KB_FUNC,   "\033[U", "\033[g", "\033[s", "",       ""}, /* 67 f9 */
1539564df9b6Ssoda   { KB_FUNC,   "\033[V", "\033[h", "\033[t", "",       ""}, /* 68 f10 */
1540564df9b6Ssoda   { KB_NUM,    "",       "",       "",       "",       ""}, /* 69 num lock */
1541564df9b6Ssoda   { KB_SCROLL, "",       "",       "",       "",       ""}, /* 70 scroll lock */
1542564df9b6Ssoda   { KB_KP,     "7",      "\033[H", "7",      "",       ""}, /* 71 kp 7 */
1543564df9b6Ssoda   { KB_KP,     "8",      "\033[A", "8",      "",       ""}, /* 72 kp 8 */
1544564df9b6Ssoda   { KB_KP,     "9",      "\033[I", "9",      "",       ""}, /* 73 kp 9 */
1545564df9b6Ssoda   { KB_KP,     "-",      "-",      "-",      "",       ""}, /* 74 kp - */
1546564df9b6Ssoda   { KB_KP,     "4",      "\033[D", "4",      "",       ""}, /* 75 kp 4 */
1547564df9b6Ssoda   { KB_KP,     "5",      "\033[E", "5",      "",       ""}, /* 76 kp 5 */
1548564df9b6Ssoda   { KB_KP,     "6",      "\033[C", "6",      "",       ""}, /* 77 kp 6 */
1549564df9b6Ssoda   { KB_KP,     "+",      "+",      "+",      "",       ""}, /* 78 kp + */
1550564df9b6Ssoda   { KB_KP,     "1",      "\033[F", "1",      "",       ""}, /* 79 kp 1 */
1551564df9b6Ssoda   { KB_KP,     "2",      "\033[B", "2",      "",       ""}, /* 80 kp 2 */
1552564df9b6Ssoda   { KB_KP,     "3",      "\033[G", "3",      "",       ""}, /* 81 kp 3 */
1553564df9b6Ssoda   { KB_KP,     "0",      "\033[L", "0",      "",       ""}, /* 82 kp 0 */
1554564df9b6Ssoda   { KB_KP,     ",",      "\177",   ",",      "",       ""}, /* 83 kp , */
1555564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 84 0 */
1556564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 85 0 */
1557564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 86 0 */
1558564df9b6Ssoda   { KB_FUNC,   "\033[W", "\033[i", "\033[u", "",       ""}, /* 87 f11 */
1559564df9b6Ssoda   { KB_FUNC,   "\033[X", "\033[j", "\033[v", "",       ""}, /* 88 f12 */
1560564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 89 0 */
1561564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 90 0 */
1562564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 91 0 */
1563564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 92 0 */
1564564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 93 0 */
1565564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 94 0 */
1566564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 95 0 */
1567564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 96 0 */
1568564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 97 0 */
1569564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 98 0 */
1570564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 99 0 */
1571564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 100 */
1572564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 101 */
1573564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 102 */
1574564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 103 */
1575564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 104 */
1576564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 105 */
1577564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 106 */
1578564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 107 */
1579564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 108 */
1580564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 109 */
1581564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 110 */
1582564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 111 */
1583564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 112 */
1584564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 113 */
1585564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 114 */
1586564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 115 */
1587564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 116 */
1588564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 117 */
1589564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 118 */
1590564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 119 */
1591564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 120 */
1592564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 121 */
1593564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 122 */
1594564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 123 */
1595564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 124 */
1596564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 125 */
1597564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}, /* 126 */
1598564df9b6Ssoda   { KB_NONE,   "",       "",       "",       "",       ""}  /* 127 */
15998519eaf8Ssoda };
16008519eaf8Ssoda 
16018519eaf8Ssoda /*
16028519eaf8Ssoda  * Get characters from the keyboard.  If none are present, return NULL.
16038519eaf8Ssoda  */
16048519eaf8Ssoda char *
sget(void)16057fe2a5a0Stsutsui sget(void)
16068519eaf8Ssoda {
16078519eaf8Ssoda 	u_char dt;
16088519eaf8Ssoda 	static u_char extended = 0, shift_state = 0;
16098519eaf8Ssoda 	static u_char capchar[2];
16108519eaf8Ssoda 
16118519eaf8Ssoda top:
16128519eaf8Ssoda 	KBD_DELAY;
1613b7abba77Ssoda 	dt = kbd_data_read_1();
16148519eaf8Ssoda 
16158519eaf8Ssoda 	switch (dt) {
16168519eaf8Ssoda 	case KBR_ACK: case KBR_ECHO:
16178519eaf8Ssoda 		kb_oq_get = (kb_oq_get + 1) & 7;
16188519eaf8Ssoda 		if(kb_oq_get != kb_oq_put) {
1619b7abba77Ssoda 			kbd_data_write_1(kb_oq[kb_oq_get]);
16208519eaf8Ssoda 		}
16218519eaf8Ssoda 		goto loop;
16228519eaf8Ssoda 	case KBR_RESEND:
1623b7abba77Ssoda 		kbd_data_write_1(kb_oq[kb_oq_get]);
16248519eaf8Ssoda 		goto loop;
16258519eaf8Ssoda 	}
16268519eaf8Ssoda 
16278519eaf8Ssoda 	if (pc_xmode > 0) {
16288519eaf8Ssoda #if defined(DDB) && defined(XSERVER_DDB)
16298519eaf8Ssoda 		/* F12 enters the debugger while in X mode */
16308519eaf8Ssoda 		if (dt == 88)
16318519eaf8Ssoda 			Debugger();
16328519eaf8Ssoda #endif
16338519eaf8Ssoda 		capchar[0] = dt;
16348519eaf8Ssoda 		capchar[1] = 0;
16358519eaf8Ssoda 		/*
16368519eaf8Ssoda 		 * Check for locking keys.
16378519eaf8Ssoda 		 *
16388519eaf8Ssoda 		 * XXX Setting the LEDs this way is a bit bogus.  What if the
16398519eaf8Ssoda 		 * keyboard has been remapped in X?
16408519eaf8Ssoda 		 */
1641564df9b6Ssoda 		switch (scan_codes[dt & 0x7f].type) {
1642564df9b6Ssoda 		case KB_NUM:
16438519eaf8Ssoda 			if (dt & 0x80) {
1644564df9b6Ssoda 				shift_state &= ~KB_NUM;
16458519eaf8Ssoda 				break;
16468519eaf8Ssoda 			}
1647564df9b6Ssoda 			if (shift_state & KB_NUM)
16488519eaf8Ssoda 				break;
1649564df9b6Ssoda 			shift_state |= KB_NUM;
1650564df9b6Ssoda 			lock_state ^= KB_NUM;
16518519eaf8Ssoda 			async_update();
16528519eaf8Ssoda 			break;
1653564df9b6Ssoda 		case KB_CAPS:
16548519eaf8Ssoda 			if (dt & 0x80) {
1655564df9b6Ssoda 				shift_state &= ~KB_CAPS;
16568519eaf8Ssoda 				break;
16578519eaf8Ssoda 			}
1658564df9b6Ssoda 			if (shift_state & KB_CAPS)
16598519eaf8Ssoda 				break;
1660564df9b6Ssoda 			shift_state |= KB_CAPS;
1661564df9b6Ssoda 			lock_state ^= KB_CAPS;
16628519eaf8Ssoda 			async_update();
16638519eaf8Ssoda 			break;
1664564df9b6Ssoda 		case KB_SCROLL:
16658519eaf8Ssoda 			if (dt & 0x80) {
1666564df9b6Ssoda 				shift_state &= ~KB_SCROLL;
16678519eaf8Ssoda 				break;
16688519eaf8Ssoda 			}
1669564df9b6Ssoda 			if (shift_state & KB_SCROLL)
16708519eaf8Ssoda 				break;
1671564df9b6Ssoda 			shift_state |= KB_SCROLL;
1672564df9b6Ssoda 			lock_state ^= KB_SCROLL;
1673564df9b6Ssoda 			if ((lock_state & KB_SCROLL) == 0)
167453524e44Schristos 				wakeup((void *)&lock_state);
16758519eaf8Ssoda 			async_update();
16768519eaf8Ssoda 			break;
16778519eaf8Ssoda 		}
16788519eaf8Ssoda 		return capchar;
16798519eaf8Ssoda 	}
16808519eaf8Ssoda 
16818519eaf8Ssoda 	switch (dt) {
16828519eaf8Ssoda 	case KBR_EXTENDED:
16838519eaf8Ssoda 		extended = 1;
16848519eaf8Ssoda 		goto loop;
16858519eaf8Ssoda 	}
16868519eaf8Ssoda 
1687564df9b6Ssoda #ifdef DDB
16888519eaf8Ssoda 	/*
16898519eaf8Ssoda 	 * Check for cntl-alt-esc.
16908519eaf8Ssoda 	 */
1691564df9b6Ssoda 	if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1692564df9b6Ssoda 		/* XXX - check pccons_is_console */
1693564df9b6Ssoda 		Debugger();
16948519eaf8Ssoda 		dt |= 0x80;	/* discard esc (ddb discarded ctl-alt) */
16958519eaf8Ssoda 	}
16968519eaf8Ssoda #endif
16978519eaf8Ssoda 
16988519eaf8Ssoda 	/*
16998519eaf8Ssoda 	 * Check for make/break.
17008519eaf8Ssoda 	 */
17018519eaf8Ssoda 	if (dt & 0x80) {
17028519eaf8Ssoda 		/*
17038519eaf8Ssoda 		 * break
17048519eaf8Ssoda 		 */
17058519eaf8Ssoda 		dt &= 0x7f;
1706564df9b6Ssoda 		switch (scan_codes[dt].type) {
1707564df9b6Ssoda 		case KB_NUM:
1708564df9b6Ssoda 			shift_state &= ~KB_NUM;
17098519eaf8Ssoda 			break;
1710564df9b6Ssoda 		case KB_CAPS:
1711564df9b6Ssoda 			shift_state &= ~KB_CAPS;
17128519eaf8Ssoda 			break;
1713564df9b6Ssoda 		case KB_SCROLL:
1714564df9b6Ssoda 			shift_state &= ~KB_SCROLL;
17158519eaf8Ssoda 			break;
1716564df9b6Ssoda 		case KB_SHIFT:
1717564df9b6Ssoda 			shift_state &= ~KB_SHIFT;
17188519eaf8Ssoda 			break;
1719564df9b6Ssoda 		case KB_ALT:
17208519eaf8Ssoda 			if (extended)
1721564df9b6Ssoda 				shift_state &= ~KB_ALTGR;
17228519eaf8Ssoda 			else
1723564df9b6Ssoda 				shift_state &= ~KB_ALT;
17248519eaf8Ssoda 			break;
1725564df9b6Ssoda 		case KB_CTL:
1726564df9b6Ssoda 			shift_state &= ~KB_CTL;
17278519eaf8Ssoda 			break;
17288519eaf8Ssoda 		}
17298519eaf8Ssoda 	} else {
17308519eaf8Ssoda 		/*
17318519eaf8Ssoda 		 * make
17328519eaf8Ssoda 		 */
1733564df9b6Ssoda 		switch (scan_codes[dt].type) {
17348519eaf8Ssoda 		/*
17358519eaf8Ssoda 		 * locking keys
17368519eaf8Ssoda 		 */
1737564df9b6Ssoda 		case KB_NUM:
1738564df9b6Ssoda 			if (shift_state & KB_NUM)
17398519eaf8Ssoda 				break;
1740564df9b6Ssoda 			shift_state |= KB_NUM;
1741564df9b6Ssoda 			lock_state ^= KB_NUM;
17428519eaf8Ssoda 			async_update();
17438519eaf8Ssoda 			break;
1744564df9b6Ssoda 		case KB_CAPS:
1745564df9b6Ssoda 			if (shift_state & KB_CAPS)
17468519eaf8Ssoda 				break;
1747564df9b6Ssoda 			shift_state |= KB_CAPS;
1748564df9b6Ssoda 			lock_state ^= KB_CAPS;
17498519eaf8Ssoda 			async_update();
17508519eaf8Ssoda 			break;
1751564df9b6Ssoda 		case KB_SCROLL:
1752564df9b6Ssoda 			if (shift_state & KB_SCROLL)
17538519eaf8Ssoda 				break;
1754564df9b6Ssoda 			shift_state |= KB_SCROLL;
1755564df9b6Ssoda 			lock_state ^= KB_SCROLL;
1756564df9b6Ssoda 			if ((lock_state & KB_SCROLL) == 0)
175753524e44Schristos 				wakeup((void *)&lock_state);
17588519eaf8Ssoda 			async_update();
17598519eaf8Ssoda 			break;
17608519eaf8Ssoda 		/*
17618519eaf8Ssoda 		 * non-locking keys
17628519eaf8Ssoda 		 */
1763564df9b6Ssoda 		case KB_SHIFT:
1764564df9b6Ssoda 			shift_state |= KB_SHIFT;
17658519eaf8Ssoda 			break;
1766564df9b6Ssoda 		case KB_ALT:
17678519eaf8Ssoda 			if (extended)
1768564df9b6Ssoda 				shift_state |= KB_ALTGR;
17698519eaf8Ssoda 			else
1770564df9b6Ssoda 				shift_state |= KB_ALT;
17718519eaf8Ssoda 			break;
1772564df9b6Ssoda 		case KB_CTL:
1773564df9b6Ssoda 			shift_state |= KB_CTL;
17748519eaf8Ssoda 			break;
1775564df9b6Ssoda 		case KB_ASCII:
1776564df9b6Ssoda 			/* control has highest priority */
1777564df9b6Ssoda 			if (shift_state & KB_CTL)
1778564df9b6Ssoda 				capchar[0] = scan_codes[dt].ctl[0];
1779564df9b6Ssoda 			else if (shift_state & KB_ALTGR) {
1780564df9b6Ssoda 				if (shift_state & KB_SHIFT)
1781564df9b6Ssoda 					capchar[0] = scan_codes[dt].shift_altgr[0];
1782564df9b6Ssoda 				else
1783564df9b6Ssoda 					capchar[0] = scan_codes[dt].altgr[0];
17848519eaf8Ssoda 			}
1785564df9b6Ssoda 			else {
1786564df9b6Ssoda 				if (shift_state & KB_SHIFT)
1787564df9b6Ssoda 					capchar[0] = scan_codes[dt].shift[0];
17888519eaf8Ssoda 				else
1789564df9b6Ssoda 					capchar[0] = scan_codes[dt].unshift[0];
1790564df9b6Ssoda 			}
1791564df9b6Ssoda 			if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
17928519eaf8Ssoda 			    capchar[0] <= 'z') {
17938519eaf8Ssoda 				capchar[0] -= ('a' - 'A');
17948519eaf8Ssoda 			}
1795564df9b6Ssoda 			capchar[0] |= (shift_state & KB_ALT);
17968519eaf8Ssoda 			extended = 0;
17978519eaf8Ssoda 			return capchar;
1798564df9b6Ssoda 		case KB_NONE:
17998519eaf8Ssoda printf("keycode %d\n",dt);
18008519eaf8Ssoda 			break;
1801564df9b6Ssoda 		case KB_FUNC: {
18028519eaf8Ssoda 			char *more_chars;
1803564df9b6Ssoda 			if (shift_state & KB_SHIFT)
1804564df9b6Ssoda 				more_chars = scan_codes[dt].shift;
1805564df9b6Ssoda 			else if (shift_state & KB_CTL)
1806564df9b6Ssoda 				more_chars = scan_codes[dt].ctl;
18078519eaf8Ssoda 			else
1808564df9b6Ssoda 				more_chars = scan_codes[dt].unshift;
18098519eaf8Ssoda 			extended = 0;
18108519eaf8Ssoda 			return more_chars;
18118519eaf8Ssoda 		}
1812564df9b6Ssoda 		case KB_KP: {
18138519eaf8Ssoda 			char *more_chars;
1814564df9b6Ssoda 			if (shift_state & (KB_SHIFT | KB_CTL) ||
1815564df9b6Ssoda 			    (lock_state & KB_NUM) == 0 || extended)
1816564df9b6Ssoda 				more_chars = scan_codes[dt].shift;
18178519eaf8Ssoda 			else
1818564df9b6Ssoda 				more_chars = scan_codes[dt].unshift;
18198519eaf8Ssoda 			extended = 0;
18208519eaf8Ssoda 			return more_chars;
18218519eaf8Ssoda 		}
18228519eaf8Ssoda 		}
18238519eaf8Ssoda 	}
18248519eaf8Ssoda 
18258519eaf8Ssoda 	extended = 0;
18268519eaf8Ssoda loop:
1827b7abba77Ssoda 	if ((kbd_cmd_read_1() & KBS_DIB) == 0)
18288519eaf8Ssoda 		return 0;
18298519eaf8Ssoda 	goto top;
18308519eaf8Ssoda }
18318519eaf8Ssoda 
1832889c658bSsimonb paddr_t
pcmmap(dev_t dev,off_t offset,int nprot)18337fe2a5a0Stsutsui pcmmap(dev_t dev, off_t offset, int nprot)
18348519eaf8Ssoda {
1835b7abba77Ssoda 	struct pccons_context *pc = &pccons_console_context;
1836b7abba77Ssoda 	paddr_t pa;
18378519eaf8Ssoda 
1838b7abba77Ssoda 	if (offset >= 0xa0000 && offset < 0xc0000) {
1839b7abba77Ssoda 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
18407fe2a5a0Stsutsui 			return -1;
1841b7abba77Ssoda 		pa += offset - pc->pc_config->pc_mono_memaddr;
18427fe2a5a0Stsutsui 		return mips_btop(pa);
1843564df9b6Ssoda 	}
1844b7abba77Ssoda 	if (offset >= 0x0000 && offset < 0x10000) {
1845b7abba77Ssoda 		if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
18467fe2a5a0Stsutsui 			return -1;
1847b7abba77Ssoda 		pa += offset - pc->pc_config->pc_mono_iobase;
18487fe2a5a0Stsutsui 		return mips_btop(pa);
1849b7abba77Ssoda 	}
1850b7abba77Ssoda 	if (offset >= 0x40000000 && offset < 0x40800000) {
1851b7abba77Ssoda 		if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1852b7abba77Ssoda 			return (-1);
1853b7abba77Ssoda 		pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
18547fe2a5a0Stsutsui 		return mips_btop(pa);
1855b7abba77Ssoda 	}
18567fe2a5a0Stsutsui 	return -1;
18578519eaf8Ssoda }
18588519eaf8Ssoda 
1859564df9b6Ssoda void
pc_xmode_on(void)18607fe2a5a0Stsutsui pc_xmode_on(void)
18618519eaf8Ssoda {
18628519eaf8Ssoda 	if (pc_xmode)
18638519eaf8Ssoda 		return;
18648519eaf8Ssoda 	pc_xmode = 1;
18658519eaf8Ssoda 
18668519eaf8Ssoda #ifdef XFREE86_BUG_COMPAT
18678519eaf8Ssoda 	/* If still unchanged, get current shape. */
18688519eaf8Ssoda 	if (cursor_shape == 0xffff)
18698519eaf8Ssoda 		get_cursor_shape();
18708519eaf8Ssoda #endif
18718519eaf8Ssoda }
18728519eaf8Ssoda 
1873564df9b6Ssoda void
pc_xmode_off(void)18747fe2a5a0Stsutsui pc_xmode_off(void)
18758519eaf8Ssoda {
18768519eaf8Ssoda 	if (pc_xmode == 0)
18778519eaf8Ssoda 		return;
18788519eaf8Ssoda 	pc_xmode = 0;
18798519eaf8Ssoda 
18808519eaf8Ssoda #ifdef XFREE86_BUG_COMPAT
18818519eaf8Ssoda 	/* XXX It would be hard to justify why the X server doesn't do this. */
18828519eaf8Ssoda 	set_cursor_shape();
18838519eaf8Ssoda #endif
18848519eaf8Ssoda 	async_update();
18858519eaf8Ssoda }
1886