syscons.c revision 32633
162587Sitojun/*-
267455Sitojun * Copyright (c) 1992-1997 S�ren Schmidt
362587Sitojun * All rights reserved.
456723Sshin *
556723Sshin * Redistribution and use in source and binary forms, with or without
656723Sshin * modification, are permitted provided that the following conditions
756723Sshin * are met:
856723Sshin * 1. Redistributions of source code must retain the above copyright
956723Sshin *    notice, this list of conditions and the following disclaimer
1056723Sshin *    in this position and unchanged.
1156723Sshin * 2. Redistributions in binary form must reproduce the above copyright
1256723Sshin *    notice, this list of conditions and the following disclaimer in the
1356723Sshin *    documentation and/or other materials provided with the distribution.
1456723Sshin * 3. The name of the author may not be used to endorse or promote products
1556723Sshin *    derived from this software withough specific prior written permission
1656723Sshin *
1756723Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1856723Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1956723Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2056723Sshin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2156723Sshin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2256723Sshin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2356723Sshin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2456723Sshin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2556723Sshin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2656723Sshin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2756723Sshin *
2856723Sshin *  $Id: syscons.c,v 1.245 1998/01/12 03:28:36 julian Exp $
2956723Sshin */
3056723Sshin
3156723Sshin#include "sc.h"
3256723Sshin#include "apm.h"
3356723Sshin#include "opt_ddb.h"
3456723Sshin#include "opt_syscons.h"
3556723Sshin
3656723Sshin#if NSC > 0
3756723Sshin#include <sys/param.h>
3856723Sshin#include <sys/systm.h>
3956723Sshin#include <sys/conf.h>
4056723Sshin#include <sys/proc.h>
4156723Sshin#include <sys/signalvar.h>
4256723Sshin#include <sys/tty.h>
4356723Sshin#include <sys/kernel.h>
4456723Sshin#include <sys/malloc.h>
4556723Sshin#ifdef	DEVFS
4656723Sshin#include <sys/devfsext.h>
4756723Sshin#endif
4856723Sshin
4962587Sitojun#include <machine/clock.h>
5056723Sshin#include <machine/cons.h>
5156723Sshin#include <machine/console.h>
5256723Sshin#include <machine/mouse.h>
5356723Sshin#include <machine/md_var.h>
5456723Sshin#include <machine/psl.h>
5556723Sshin#include <machine/frame.h>
5656723Sshin#include <machine/pc/display.h>
5756723Sshin#include <machine/apm_bios.h>
5856723Sshin#include <machine/random.h>
5956723Sshin
6056723Sshin#include <vm/vm.h>
6156723Sshin#include <vm/vm_param.h>
6256723Sshin#include <vm/pmap.h>
6356723Sshin
6456723Sshin#include <i386/isa/isa.h>
6556723Sshin#include <i386/isa/isa_device.h>
6656723Sshin#include <i386/isa/timerreg.h>
6756723Sshin#include <i386/isa/kbdtables.h>
6856723Sshin#include <i386/isa/kbdio.h>
6956723Sshin#include <i386/isa/syscons.h>
7056723Sshin
7162587Sitojun#if !defined(MAXCONS)
7256723Sshin#define MAXCONS 16
7356723Sshin#endif
7456723Sshin
7556723Sshin#if !defined(SC_MAX_HISTORY_SIZE)
7656723Sshin#define SC_MAX_HISTORY_SIZE	(1000 * MAXCONS)
7767455Sitojun#endif
7867455Sitojun
7956723Sshin#if !defined(SC_HISTORY_SIZE)
8056723Sshin#define SC_HISTORY_SIZE		(ROW * 4)
8162587Sitojun#endif
8256723Sshin
8362587Sitojun#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
8462587Sitojun#undef SC_MAX_HISTORY_SIZE
8556723Sshin#define SC_MAX_HISTORY_SIZE	(SC_HISTORY_SIZE * MAXCONS)
8662587Sitojun#endif
8762587Sitojun
8862587Sitojun#define COLD 0
8962587Sitojun#define WARM 1
9062587Sitojun
9156723Sshin#define MODE_MAP_SIZE		(M_VGA_CG320 + 1)
9256723Sshin#define MODE_PARAM_SIZE		64
9356723Sshin
9456723Sshin/* for backward compatibility */
9556723Sshin#define OLD_CONS_MOUSECTL	_IOWR('c', 10, old_mouse_info_t)
9662587Sitojun
9762587Sitojuntypedef struct old_mouse_data {
9862587Sitojun    int x;
9962587Sitojun    int y;
10056723Sshin    int buttons;
10162587Sitojun} old_mouse_data_t;
10262587Sitojun
10356723Sshintypedef struct old_mouse_info {
10462587Sitojun    int operation;
10562587Sitojun    union {
10662587Sitojun	struct old_mouse_data data;
10756723Sshin	struct mouse_mode mode;
10856723Sshin    } u;
10962587Sitojun} old_mouse_info_t;
11062587Sitojun
11162587Sitojun/* XXX use sc_bcopy where video memory is concerned */
11262587Sitojun#define sc_bcopy generic_bcopy
11362587Sitojunextern void generic_bcopy(const void *, void *, size_t);
11462587Sitojun
11556723Sshinstatic default_attr user_default = {
11656723Sshin    (FG_LIGHTGREY | BG_BLACK) << 8,
11756723Sshin    (FG_BLACK | BG_LIGHTGREY) << 8
11862587Sitojun};
11962587Sitojun
12056723Sshinstatic default_attr kernel_default = {
12156723Sshin    (FG_WHITE | BG_BLACK) << 8,
12256723Sshin    (FG_BLACK | BG_LIGHTGREY) << 8
12356723Sshin};
12456723Sshin
12556723Sshinstatic  scr_stat    	main_console;
12656723Sshinstatic  scr_stat    	*console[MAXCONS];
12756723Sshin#ifdef DEVFS
12856723Sshinstatic	void		*sc_devfs_token[MAXCONS];
12956723Sshinstatic	void		*sc_mouse_devfs_token;
13056723Sshinstatic	void		*sc_console_devfs_token;
13156723Sshin#endif
13256723Sshin	scr_stat    	*cur_console;
13356723Sshinstatic  scr_stat    	*new_scp, *old_scp;
13456723Sshinstatic  term_stat   	kernel_console;
13556723Sshinstatic  default_attr    *current_default;
13656723Sshinstatic  int     	flags = 0;
13762587Sitojunstatic  int		sc_port = IO_KBD;
13856723Sshinstatic  KBDC		sc_kbdc = NULL;
13956723Sshinstatic  char        	init_done = COLD;
14056723Sshinstatic  u_short		sc_buffer[ROW*COL];
14156723Sshinstatic  char        	switch_in_progress = FALSE;
14256723Sshinstatic  char        	write_in_progress = FALSE;
14356723Sshinstatic  char        	blink_in_progress = FALSE;
14456723Sshinstatic  int        	blinkrate = 0;
14556723Sshin	u_int       	crtc_addr = MONO_BASE;
14656723Sshin	char		crtc_type = KD_MONO;
14756723Sshin	char        	crtc_vga = FALSE;
14856723Sshinstatic  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
14956723Sshinstatic  u_char		accents = 0;
15056723Sshinstatic  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
15156723Sshinstatic  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
15256723Sshinstatic  int     	delayed_next_scr = FALSE;
15356723Sshinstatic  long        	scrn_blank_time = 0;    /* screen saver timeout value */
15456723Sshin	int     	scrn_blanked = 0;       /* screen saver active flag */
15556723Sshinstatic  long       	scrn_time_stamp;
15656723Sshin	u_char      	scr_map[256];
15762587Sitojun	u_char      	scr_rmap[256];
15856723Sshin	char        	*video_mode_ptr = NULL;
15956723Sshin	int     	fonts_loaded = 0
16056723Sshin#ifdef STD8X16FONT
16156723Sshin	| FONT_16
16256723Sshin#endif
16356723Sshin	;
16456723Sshin
16556723Sshin	char        	font_8[256*8];
16656723Sshin	char		font_14[256*14];
16762587Sitojun#ifdef STD8X16FONT
16856723Sshinextern
16956723Sshin#endif
17056723Sshin	unsigned char	font_16[256*16];
17156723Sshin	char        	palette[256*3];
17256723Sshinstatic  char		*mode_map[MODE_MAP_SIZE];
17356723Sshinstatic  char		vgaregs[MODE_PARAM_SIZE];
17456723Sshinstatic  char		vgaregs2[MODE_PARAM_SIZE];
17556723Sshinstatic  int		rows_offset = 1;
17656723Sshinstatic	char 		*cut_buffer;
17756723Sshinstatic	int		mouse_level = 0;	/* sysmouse protocol level */
17856723Sshinstatic	mousestatus_t	mouse_status = { 0, 0, 0, 0, 0, 0 };
17956723Sshinstatic  u_short 	mouse_and_mask[16] = {
18056723Sshin				0xc000, 0xe000, 0xf000, 0xf800,
18156723Sshin				0xfc00, 0xfe00, 0xff00, 0xff80,
18256723Sshin				0xfe00, 0x1e00, 0x1f00, 0x0f00,
18362587Sitojun				0x0f00, 0x0000, 0x0000, 0x0000
18456723Sshin			};
18556723Sshinstatic  u_short 	mouse_or_mask[16] = {
18656723Sshin				0x0000, 0x4000, 0x6000, 0x7000,
18756723Sshin				0x7800, 0x7c00, 0x7e00, 0x6800,
18856723Sshin				0x0c00, 0x0c00, 0x0600, 0x0600,
18962587Sitojun				0x0000, 0x0000, 0x0000, 0x0000
19056723Sshin			};
19156723Sshin
19256723Sshinstatic int		extra_history_size =
19356723Sshin			    SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
19456723Sshin
19556723Sshinstatic void    		none_saver(int blank) { }
19656723Sshinstatic void    		(*current_saver)(int blank) = none_saver;
19756723Sshinint  			(*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data,
19856723Sshin					 int flag, struct proc *p) = NULL;
19956723Sshin
20056723Sshin/* OS specific stuff */
20156723Sshin#ifdef not_yet_done
20256723Sshin#define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
20356723Sshinstruct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
20456723Sshinstruct  MOUSE_TTY 	(sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
20562587Sitojunstruct  tty         	*sccons[MAXCONS+2];
20656723Sshin#else
20762587Sitojun#define VIRTUAL_TTY(x)  &sccons[x]
20856723Sshin#define CONSOLE_TTY 	&sccons[MAXCONS]
20956723Sshin#define MOUSE_TTY 	&sccons[MAXCONS+1]
21056723Sshinstatic struct tty     	sccons[MAXCONS+2];
21162587Sitojun#endif
21256723Sshin#define SC_MOUSE 	128
21356723Sshin#define SC_CONSOLE	255
21456723Sshin#define MONO_BUF    	pa_to_va(0xB0000)
21556723Sshin#define CGA_BUF     	pa_to_va(0xB8000)
21656723Sshinu_short         	*Crtat;
21756723Sshinstatic const int	nsccons = MAXCONS+2;
21862587Sitojun
21956723Sshin#define WRAPHIST(scp, pointer, offset)\
22056723Sshin    ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
22156723Sshin    + (offset)) % (scp->history_size)))
22256723Sshin#define ISSIGVALID(sig)	((sig) > 0 && (sig) < NSIG)
22356723Sshin
22456723Sshin/* this should really be in `rtc.h' */
22556723Sshin#define RTC_EQUIPMENT		0x14
22656723Sshin
22756723Sshin/* prototypes */
22856723Sshinstatic int scattach(struct isa_device *dev);
22956723Sshinstatic int scparam(struct tty *tp, struct termios *t);
23056723Sshinstatic int scprobe(struct isa_device *dev);
23156723Sshinstatic int scvidprobe(int unit, int flags);
23256723Sshinstatic int sckbdprobe(int unit, int flags);
23356723Sshinstatic void scstart(struct tty *tp);
23456723Sshinstatic void scmousestart(struct tty *tp);
23556723Sshinstatic void scinit(void);
23656723Sshinstatic void map_mode_table(char *map[], char *table, int max);
23756723Sshinstatic u_char map_mode_num(u_char mode);
23856723Sshinstatic char *get_mode_param(scr_stat *scp, u_char mode);
23956723Sshinstatic u_int scgetc(u_int flags);
24056723Sshin#define SCGETC_CN	1
24156723Sshin#define SCGETC_NONBLOCK	2
24256723Sshinstatic scr_stat *get_scr_stat(dev_t dev);
24356723Sshinstatic scr_stat *alloc_scp(void);
24456723Sshinstatic void init_scp(scr_stat *scp);
24562587Sitojunstatic int get_scr_num(void);
24662587Sitojunstatic timeout_t scrn_timer;
24762587Sitojunstatic void stop_scrn_saver(void (*saver)(int));
24862587Sitojunstatic void clear_screen(scr_stat *scp);
24956723Sshinstatic int switch_scr(scr_stat *scp, u_int next_scr);
25056723Sshinstatic void exchange_scr(void);
25156723Sshinstatic inline void move_crsr(scr_stat *scp, int x, int y);
25256723Sshinstatic void scan_esc(scr_stat *scp, u_char c);
25356723Sshinstatic void draw_cursor_image(scr_stat *scp);
25456723Sshinstatic void remove_cursor_image(scr_stat *scp);
25556723Sshinstatic void ansi_put(scr_stat *scp, u_char *buf, int len);
25656723Sshinstatic u_char *get_fstr(u_int c, u_int *len);
25756723Sshinstatic void history_to_screen(scr_stat *scp);
25856723Sshinstatic int history_up_line(scr_stat *scp);
25956723Sshinstatic int history_down_line(scr_stat *scp);
26056723Sshinstatic int mask2attr(struct term_stat *term);
26156723Sshinstatic void set_keyboard(int command, int data);
26256723Sshinstatic void update_leds(int which);
26356723Sshinstatic void set_vgaregs(char *modetable);
26456723Sshinstatic void read_vgaregs(char *buf);
26556723Sshin#define COMP_IDENTICAL	0
26656723Sshin#define COMP_SIMILAR	1
26756723Sshin#define COMP_DIFFERENT	2
26856723Sshinstatic int comp_vgaregs(u_char *buf1, u_char *buf2);
26956723Sshinstatic void dump_vgaregs(u_char *buf);
27056723Sshin#define PARAM_BUFSIZE	6
27156723Sshinstatic void set_font_mode(u_char *buf);
27256723Sshinstatic void set_normal_mode(u_char *buf);
27356723Sshinstatic void set_destructive_cursor(scr_stat *scp);
27456723Sshinstatic void set_mouse_pos(scr_stat *scp);
27556723Sshinstatic int skip_spc_right(scr_stat *scp, u_short *p);
27656723Sshinstatic int skip_spc_left(scr_stat *scp, u_short *p);
27756723Sshinstatic void mouse_cut(scr_stat *scp);
27856723Sshinstatic void mouse_cut_start(scr_stat *scp);
27956723Sshinstatic void mouse_cut_end(scr_stat *scp);
28056723Sshinstatic void mouse_cut_word(scr_stat *scp);
28156723Sshinstatic void mouse_cut_line(scr_stat *scp);
28256723Sshinstatic void mouse_cut_extend(scr_stat *scp);
28356723Sshinstatic void mouse_paste(scr_stat *scp);
28456723Sshinstatic void draw_mouse_image(scr_stat *scp);
28556723Sshinstatic void remove_mouse_image(scr_stat *scp);
28656723Sshinstatic void draw_cutmarking(scr_stat *scp);
28756723Sshinstatic void remove_cutmarking(scr_stat *scp);
28856723Sshinstatic void save_palette(void);
28956723Sshinstatic void do_bell(scr_stat *scp, int pitch, int duration);
29056723Sshinstatic timeout_t blink_screen;
29156723Sshin#ifdef SC_SPLASH_SCREEN
29256723Sshinstatic void toggle_splash_screen(scr_stat *scp);
29356723Sshin#endif
29456723Sshin
29556723Sshinstruct  isa_driver scdriver = {
29656723Sshin    scprobe, scattach, "sc", 1
29756723Sshin};
29856723Sshin
29956723Sshinstatic	d_open_t	scopen;
30056723Sshinstatic	d_close_t	scclose;
30156723Sshinstatic	d_read_t	scread;
30256723Sshinstatic	d_write_t	scwrite;
30356723Sshinstatic	d_ioctl_t	scioctl;
30456723Sshinstatic	d_devtotty_t	scdevtotty;
30556723Sshinstatic	d_mmap_t	scmmap;
30656723Sshin
30756723Sshin#define CDEV_MAJOR 12
30856723Sshinstatic	struct cdevsw	scdevsw = {
30956723Sshin	scopen,		scclose,	scread,		scwrite,
31056723Sshin	scioctl,	nullstop,	noreset,	scdevtotty,
31156723Sshin	ttpoll,		scmmap,		nostrategy,	"sc",	NULL,	-1 };
31256723Sshin
31356723Sshin/*
31456723Sshin * These functions need to be before calls to them so they can be inlined.
31556723Sshin */
31656723Sshinstatic inline void
31756723Sshindraw_cursor_image(scr_stat *scp)
31856723Sshin{
31956723Sshin    u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf);
32056723Sshin    u_short prev_image;
32156723Sshin
32256723Sshin    /* do we have a destructive cursor ? */
32356723Sshin    if (flags & CHAR_CURSOR) {
32456723Sshin	prev_image = scp->cursor_saveunder;
32556723Sshin	cursor_image = *ptr & 0x00ff;
32656723Sshin	if (cursor_image == DEAD_CHAR)
32756723Sshin	    cursor_image = prev_image & 0x00ff;
32856723Sshin	cursor_image |= *(scp->cursor_pos) & 0xff00;
32956723Sshin	scp->cursor_saveunder = cursor_image;
33056723Sshin	/* update the cursor bitmap if the char under the cursor has changed */
33156723Sshin	if (prev_image != cursor_image)
33256723Sshin	    set_destructive_cursor(scp);
33356723Sshin	/* modify cursor_image */
33456723Sshin	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
33556723Sshin	    /*
33656723Sshin	     * When the mouse pointer is at the same position as the cursor,
33756723Sshin	     * the cursor bitmap needs to be updated even if the char under
33856723Sshin	     * the cursor hasn't changed, because the mouse pionter may
33956723Sshin	     * have moved by a few dots within the cursor cel.
34062587Sitojun	     */
34162587Sitojun	    if ((prev_image == cursor_image)
34262587Sitojun		    && (cursor_image != *(scp->cursor_pos)))
34356723Sshin	        set_destructive_cursor(scp);
34456723Sshin	    cursor_image &= 0xff00;
34556723Sshin	    cursor_image |= DEAD_CHAR;
34656723Sshin	}
34756723Sshin    }
34856723Sshin    else {
34956723Sshin	cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
35056723Sshin	scp->cursor_saveunder = cursor_image;
35156723Sshin	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
35256723Sshin	    if ((cursor_image & 0x7000) == 0x7000) {
35356723Sshin		cursor_image &= 0x8fff;
35456723Sshin		if(!(cursor_image & 0x0700))
35556723Sshin		    cursor_image |= 0x0700;
35656723Sshin	    } else {
35756723Sshin		cursor_image |= 0x7000;
35856723Sshin		if ((cursor_image & 0x0700) == 0x0700)
35956723Sshin		    cursor_image &= 0xf0ff;
36056723Sshin	    }
36156723Sshin	}
36256723Sshin    }
36356723Sshin    *ptr = cursor_image;
36456723Sshin}
36556723Sshin
36656723Sshinstatic inline void
36756723Sshinremove_cursor_image(scr_stat *scp)
36856723Sshin{
36956723Sshin    *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder;
37056723Sshin}
37156723Sshin
37256723Sshinstatic inline void
37356723Sshinmove_crsr(scr_stat *scp, int x, int y)
37456723Sshin{
37556723Sshin    if (x < 0)
37656723Sshin	x = 0;
37756723Sshin    if (y < 0)
37856723Sshin	y = 0;
37956723Sshin    if (x >= scp->xsize)
38056723Sshin	x = scp->xsize-1;
38156723Sshin    if (y >= scp->ysize)
38256723Sshin	y = scp->ysize-1;
38362587Sitojun    scp->xpos = x;
38456723Sshin    scp->ypos = y;
38556723Sshin    scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
38662587Sitojun}
38756723Sshin
38856723Sshinstatic int
38956723Sshinscprobe(struct isa_device *dev)
39056723Sshin{
39156723Sshin    if (!scvidprobe(dev->id_unit, dev->id_flags)) {
39256723Sshin	if (bootverbose)
39356723Sshin	    printf("sc%d: no video adapter is found.\n", dev->id_unit);
39456723Sshin	return (0);
39556723Sshin    }
39656723Sshin
39756723Sshin    sc_port = dev->id_iobase;
39856723Sshin    if (sckbdprobe(dev->id_unit, dev->id_flags))
39956723Sshin	return (IO_KBDSIZE);
40056723Sshin    else
40156723Sshin        return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
40256723Sshin}
40356723Sshin
40456723Sshin/* probe video adapters, return TRUE if found */
40556723Sshinstatic int
40656723Sshinscvidprobe(int unit, int flags)
40756723Sshin{
40856723Sshin    /*
40956723Sshin     * XXX don't try to `printf' anything here, the console may not have
41056723Sshin     * been configured yet.
41162587Sitojun     */
41256723Sshin    u_short volatile *cp;
41356723Sshin    u_short was;
41456723Sshin    u_long  pa;
41556723Sshin    u_long  segoff;
41656723Sshin
41756723Sshin    /* do this test only once */
41856723Sshin    if (init_done != COLD)
41956723Sshin	return (Crtat != 0);
42056723Sshin
42156723Sshin    /*
42256723Sshin     * Finish defaulting crtc variables for a mono screen.  Crtat is a
42356723Sshin     * bogus common variable so that it can be shared with pcvt, so it
42456723Sshin     * can't be statically initialized.  XXX.
42556723Sshin     */
42656723Sshin    Crtat = (u_short *)MONO_BUF;
42756723Sshin    crtc_type = KD_MONO;
42856723Sshin    /* If CGA memory seems to work, switch to color.  */
42956723Sshin    cp = (u_short *)CGA_BUF;
43056723Sshin    was = *cp;
43156723Sshin    *cp = (u_short) 0xA55A;
43256723Sshin    if (*cp == 0xA55A) {
43356723Sshin	Crtat = (u_short *)CGA_BUF;
43456723Sshin	crtc_addr = COLOR_BASE;
43556723Sshin	crtc_type = KD_CGA;
43656723Sshin    } else {
43756723Sshin        cp = Crtat;
43856723Sshin	was = *cp;
43956723Sshin	*cp = (u_short) 0xA55A;
44056723Sshin	if (*cp != 0xA55A) {
44156723Sshin	    /* no screen at all, bail out */
44256723Sshin	    Crtat = 0;
44356723Sshin	    return FALSE;
44456723Sshin	}
44556723Sshin    }
44656723Sshin    *cp = was;
44756723Sshin
44856723Sshin    /*
44956723Sshin     * Check rtc and BIOS date area.
45056723Sshin     * XXX: don't use BIOSDATA_EQUIPMENT, it is not a dead copy
45156723Sshin     * of RTC_EQUIPMENT. The bit 4 and 5 of the ETC_EQUIPMENT are
45256723Sshin     * zeros for EGA and VGA. However, the EGA/VGA BIOS will set
45356723Sshin     * these bits in BIOSDATA_EQUIPMENT according to the monitor
45456723Sshin     * type detected.
45556723Sshin     */
45656723Sshin    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
45756723Sshin    case 0: /* EGA/VGA, or nothing */
45856723Sshin	crtc_type = KD_EGA;
45956723Sshin	/* the color adapter may be in the 40x25 mode... XXX */
46056723Sshin	break;
46156723Sshin    case 1: /* CGA 40x25 */
46256723Sshin	/* switch to the 80x25 mode? XXX */
46356723Sshin	/* FALL THROUGH */
46456723Sshin    case 2: /* CGA 80x25 */
46556723Sshin	/* `crtc_type' has already been set... */
46656723Sshin	/* crtc_type = KD_CGA; */
46756723Sshin	break;
46856723Sshin    case 3: /* MDA */
46956723Sshin	/* `crtc_type' has already been set... */
47056723Sshin	/* crtc_type = KD_MONO; */
47156723Sshin	break;
47262587Sitojun    }
47362587Sitojun
47462587Sitojun    /* is this a VGA or higher ? */
47562587Sitojun    outb(crtc_addr, 7);
47656723Sshin    if (inb(crtc_addr) == 7) {
47756723Sshin
47856723Sshin        crtc_type = KD_VGA;
47956723Sshin	crtc_vga = TRUE;
48056723Sshin	read_vgaregs(vgaregs);
48156723Sshin
48256723Sshin	/* Get the BIOS video mode pointer */
48356723Sshin	segoff = *(u_long *)pa_to_va(0x4a8);
48456723Sshin	pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
48556723Sshin	if (ISMAPPED(pa, sizeof(u_long))) {
48656723Sshin	    segoff = *(u_long *)pa_to_va(pa);
48756723Sshin	    pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
48856723Sshin	    if (ISMAPPED(pa, MODE_PARAM_SIZE))
48956723Sshin		video_mode_ptr = (char *)pa_to_va(pa);
49056723Sshin	}
49156723Sshin    }
49256723Sshin
49356723Sshin    return TRUE;
49456723Sshin}
49556723Sshin
49656723Sshin/* probe the keyboard, return TRUE if found */
49756723Sshinstatic int
49856723Sshinsckbdprobe(int unit, int flags)
49956723Sshin{
50056723Sshin    int codeset;
50156723Sshin    int c = -1;
50256723Sshin    int m;
50356723Sshin
50456723Sshin    sc_kbdc = kbdc_open(sc_port);
50556723Sshin
50656723Sshin    if (!kbdc_lock(sc_kbdc, TRUE)) {
50756723Sshin	/* driver error? */
50856723Sshin	printf("sc%d: unable to lock the controller.\n", unit);
50956723Sshin        return ((flags & DETECT_KBD) ? FALSE : TRUE);
51056723Sshin    }
51156723Sshin
51262587Sitojun    /* discard anything left after UserConfig */
51356723Sshin    empty_both_buffers(sc_kbdc, 10);
51456723Sshin
51556723Sshin    /* save the current keyboard controller command byte */
51656723Sshin    m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
51756723Sshin    c = get_controller_command_byte(sc_kbdc);
51856723Sshin    if (c == -1) {
51956723Sshin	/* CONTROLLER ERROR */
52056723Sshin	printf("sc%d: unable to get the current command byte value.\n", unit);
52156723Sshin	goto fail;
52256723Sshin    }
52356723Sshin    if (bootverbose)
52456723Sshin	printf("sc%d: the current keyboard controller command byte %04x\n",
52556723Sshin	    unit, c);
52656723Sshin#if 0
52756723Sshin    /* override the keyboard lock switch */
52856723Sshin    c |= KBD_OVERRIDE_KBD_LOCK;
52956723Sshin#endif
53056723Sshin
53156723Sshin    /*
53256723Sshin     * The keyboard may have been screwed up by the boot block.
53356723Sshin     * We may just be able to recover from error by testing the controller
53456723Sshin     * and the keyboard port. The controller command byte needs to be saved
53556723Sshin     * before this recovery operation, as some controllers seem to set
53662587Sitojun     * the command byte to particular values.
53762587Sitojun     */
53862587Sitojun    test_controller(sc_kbdc);
53956723Sshin    test_kbd_port(sc_kbdc);
54056723Sshin
54156723Sshin    /* enable the keyboard port, but disable the keyboard intr. */
54256723Sshin    if (!set_controller_command_byte(sc_kbdc,
54356723Sshin            KBD_KBD_CONTROL_BITS,
54456723Sshin            KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
54556723Sshin	/* CONTROLLER ERROR
54656723Sshin	 * there is very little we can do...
54756723Sshin	 */
54856723Sshin	printf("sc%d: unable to set the command byte.\n", unit);
54956723Sshin	goto fail;
55056723Sshin     }
55156723Sshin
55256723Sshin     /*
55356723Sshin      * Check if we have an XT keyboard before we attempt to reset it.
55456723Sshin      * The procedure assumes that the keyboard and the controller have
55556723Sshin      * been set up properly by BIOS and have not been messed up
55656723Sshin      * during the boot process.
55756723Sshin      */
55856723Sshin     codeset = -1;
55956723Sshin     if (flags & XT_KEYBD)
56056723Sshin	 /* the user says there is a XT keyboard */
56156723Sshin	 codeset = 1;
56256723Sshin#ifdef DETECT_XT_KEYBOARD
56356723Sshin     else if ((c & KBD_TRANSLATION) == 0) {
56456723Sshin	 /* SET_SCANCODE_SET is not always supported; ignore error */
56556723Sshin	 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
56656723Sshin		 == KBD_ACK)
56756723Sshin	     codeset = read_kbd_data(sc_kbdc);
56856723Sshin     }
56956723Sshin     if (bootverbose)
57056723Sshin         printf("sc%d: keyboard scancode set %d\n", unit, codeset);
57156723Sshin#endif /* DETECT_XT_KEYBOARD */
57256723Sshin
57356723Sshin    if (flags & KBD_NORESET) {
57456723Sshin        write_kbd_command(sc_kbdc, KBDC_ECHO);
57562587Sitojun        if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
57662587Sitojun            empty_both_buffers(sc_kbdc, 10);
57762587Sitojun            test_controller(sc_kbdc);
57862587Sitojun            test_kbd_port(sc_kbdc);
57956723Sshin            if (bootverbose)
58056723Sshin                printf("sc%d: failed to get response from the keyboard.\n",
58156723Sshin		    unit);
58256723Sshin	    goto fail;
58356723Sshin	}
58456723Sshin    } else {
58556723Sshin        /* reset keyboard hardware */
58656723Sshin        if (!reset_kbd(sc_kbdc)) {
58756723Sshin            /* KEYBOARD ERROR
58856723Sshin             * Keyboard reset may fail either because the keyboard doen't
58956723Sshin             * exist, or because the keyboard doesn't pass the self-test,
59056723Sshin             * or the keyboard controller on the motherboard and the keyboard
59156723Sshin             * somehow fail to shake hands. It is just possible, particularly
59256723Sshin             * in the last case, that the keyoard controller may be left
59356723Sshin             * in a hung state. test_controller() and test_kbd_port() appear
59456723Sshin             * to bring the keyboard controller back (I don't know why and
59556723Sshin             * how, though.)
59656723Sshin             */
59756723Sshin            empty_both_buffers(sc_kbdc, 10);
59856723Sshin            test_controller(sc_kbdc);
59956723Sshin            test_kbd_port(sc_kbdc);
60056723Sshin            /* We could disable the keyboard port and interrupt... but,
60156723Sshin             * the keyboard may still exist (see above).
60256723Sshin             */
60356723Sshin            if (bootverbose)
60456723Sshin                printf("sc%d: failed to reset the keyboard.\n", unit);
60556723Sshin            goto fail;
60656723Sshin        }
60756723Sshin    }
60856723Sshin
60956723Sshin    /*
61056723Sshin     * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
61156723Sshin     * such as those on the IBM ThinkPad laptop computers can be used
61256723Sshin     * with the standard console driver.
61356723Sshin     */
61456723Sshin    if (codeset == 1) {
61556723Sshin	if (send_kbd_command_and_data(
61656723Sshin	        sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
61756723Sshin	    /* XT kbd doesn't need scan code translation */
61856723Sshin	    c &= ~KBD_TRANSLATION;
61956723Sshin	} else {
62056723Sshin	    /* KEYBOARD ERROR
62156723Sshin	     * The XT kbd isn't usable unless the proper scan code set
62256723Sshin	     * is selected.
62356723Sshin	     */
62456723Sshin	    printf("sc%d: unable to set the XT keyboard mode.\n", unit);
62556723Sshin	    goto fail;
62656723Sshin	}
62756723Sshin    }
62856723Sshin    /* enable the keyboard port and intr. */
62956723Sshin    if (!set_controller_command_byte(sc_kbdc,
63062587Sitojun            KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
63162587Sitojun	    (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
63262587Sitojun	        | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
63362587Sitojun	/* CONTROLLER ERROR
63456723Sshin	 * This is serious; we are left with the disabled keyboard intr.
63556723Sshin	 */
63656723Sshin	printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
63756723Sshin	goto fail;
63856723Sshin    }
63956723Sshin
64056723Sshin    kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
64156723Sshin    kbdc_lock(sc_kbdc, FALSE);
64256723Sshin    return TRUE;
64356723Sshin
64456723Sshinfail:
64556723Sshin    if (c != -1)
64656723Sshin        /* try to restore the command byte as before, if possible */
64756723Sshin        set_controller_command_byte(sc_kbdc, 0xff, c);
64856723Sshin    kbdc_set_device_mask(sc_kbdc,
64956723Sshin        (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
65056723Sshin    kbdc_lock(sc_kbdc, FALSE);
65156723Sshin    return FALSE;
65256723Sshin}
65356723Sshin
65456723Sshin#if NAPM > 0
65556723Sshinstatic int
65656723Sshinscresume(void *dummy)
65756723Sshin{
65856723Sshin	shfts = ctls = alts = agrs = metas = accents = 0;
65956723Sshin	return 0;
66056723Sshin}
66156723Sshin#endif
66256723Sshin
66356723Sshinstatic int
66456723Sshinscattach(struct isa_device *dev)
66556723Sshin{
66656723Sshin    scr_stat *scp;
66756723Sshin    dev_t cdev = makedev(CDEV_MAJOR, 0);
66856723Sshin    char *p;
66956723Sshin#ifdef DEVFS
67056723Sshin    int vc;
67156723Sshin#endif
67256723Sshin
67356723Sshin    scinit();
67456723Sshin    flags = dev->id_flags;
67556723Sshin    if (!crtc_vga)
67656723Sshin	flags &= ~CHAR_CURSOR;
67756723Sshin
67856723Sshin    scp = console[0];
67956723Sshin
68056723Sshin    if (crtc_vga) {
68156723Sshin    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
68256723Sshin    }
68356723Sshin
68456723Sshin    scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
68556723Sshin				     M_DEVBUF, M_NOWAIT);
68656723Sshin
68756723Sshin    /* copy temporary buffer to final buffer */
68856723Sshin    bcopy(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
68956723Sshin
69056723Sshin    scp->cursor_pos = scp->cursor_oldpos =
69156723Sshin	scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
69256723Sshin    scp->mouse_pos = scp->mouse_oldpos =
69356723Sshin	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
69456723Sshin	    		scp->mouse_xpos/8);
69556723Sshin
69656723Sshin    /* initialize history buffer & pointers */
69756723Sshin    scp->history_head = scp->history_pos =
69856723Sshin	(u_short *)malloc(scp->history_size*sizeof(u_short),
69956723Sshin			  M_DEVBUF, M_NOWAIT);
70056723Sshin    if (scp->history_head != NULL)
70156723Sshin        bzero(scp->history_head, scp->history_size*sizeof(u_short));
70256723Sshin    scp->history = scp->history_head;
70356723Sshin
70456723Sshin    /* initialize cursor stuff */
70556723Sshin    if (!(scp->status & UNKNOWN_MODE))
70656723Sshin    	draw_cursor_image(scp);
70756723Sshin
70856723Sshin    /* get screen update going */
70956723Sshin    scrn_timer(NULL);
71056723Sshin
71156723Sshin    update_leds(scp->status);
71256723Sshin
71356723Sshin    if ((crtc_type == KD_VGA) && bootverbose) {
71456723Sshin        printf("sc%d: BIOS video mode:%d\n",
71556723Sshin	    dev->id_unit, *(u_char *)pa_to_va(0x449));
71656723Sshin        printf("sc%d: VGA registers upon power-up\n", dev->id_unit);
71756723Sshin        dump_vgaregs(vgaregs);
71856723Sshin        printf("sc%d: video mode:%d\n", dev->id_unit, scp->mode);
71956723Sshin        printf("sc%d: VGA registers in BIOS for mode:%d\n",
72056723Sshin		dev->id_unit, scp->mode);
72156723Sshin        dump_vgaregs(vgaregs2);
72256723Sshin	p = get_mode_param(scp, scp->mode);
72356723Sshin        if (p != NULL) {
72456723Sshin            printf("sc%d: VGA registers to be used for mode:%d\n",
72556723Sshin		dev->id_unit, scp->mode);
72656723Sshin            dump_vgaregs(p);
72756723Sshin        }
72856723Sshin        printf("sc%d: rows_offset:%d\n", dev->id_unit, rows_offset);
72956723Sshin    }
73056723Sshin    if ((crtc_type == KD_VGA) && (video_mode_ptr == NULL))
73156723Sshin        printf("sc%d: WARNING: video mode switching is only partially supported\n",
73256723Sshin	        dev->id_unit);
73356723Sshin
73456723Sshin    printf("sc%d: ", dev->id_unit);
73556723Sshin    switch(crtc_type) {
73656723Sshin    case KD_VGA:
73756723Sshin	if (crtc_addr == MONO_BASE)
73856723Sshin	    printf("VGA mono");
73956723Sshin	else
74056723Sshin	    printf("VGA color");
74156723Sshin	break;
74256723Sshin    case KD_EGA:
74356723Sshin	if (crtc_addr == MONO_BASE)
74456723Sshin	    printf("EGA mono");
74556723Sshin	else
74656723Sshin	    printf("EGA color");
74756723Sshin	break;
74856723Sshin    case KD_CGA:
74956723Sshin	printf("CGA");
75056723Sshin	break;
75156723Sshin    case KD_MONO:
75256723Sshin    case KD_HERCULES:
75356723Sshin    default:
75456723Sshin	printf("MDA/hercules");
75556723Sshin	break;
75662587Sitojun    }
75756723Sshin    printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags);
75856723Sshin
75956723Sshin#if NAPM > 0
76056723Sshin    scp->r_hook.ah_fun = scresume;
76156723Sshin    scp->r_hook.ah_arg = NULL;
76256723Sshin    scp->r_hook.ah_name = "system keyboard";
76356723Sshin    scp->r_hook.ah_order = APM_MID_ORDER;
76456723Sshin    apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
76567455Sitojun#endif
76656723Sshin
76756723Sshin    cdevsw_add(&cdev, &scdevsw, NULL);
76856723Sshin
76956723Sshin#ifdef DEVFS
77056723Sshin    for (vc = 0; vc < MAXCONS; vc++)
77156723Sshin        sc_devfs_token[vc] = devfs_add_devswf(&scdevsw, vc, DV_CHR,
77256723Sshin				UID_ROOT, GID_WHEEL, 0600, "ttyv%n", vc);
77356723Sshin    sc_mouse_devfs_token = devfs_add_devswf(&scdevsw, SC_MOUSE, DV_CHR,
77456723Sshin				UID_ROOT, GID_WHEEL, 0600, "sysmouse");
77556723Sshin    sc_console_devfs_token = devfs_add_devswf(&scdevsw, SC_CONSOLE, DV_CHR,
77656723Sshin				UID_ROOT, GID_WHEEL, 0600, "consolectl");
77756723Sshin#endif
77856723Sshin    return 0;
77956723Sshin}
78056723Sshin
78156723Sshinstruct tty
78256723Sshin*scdevtotty(dev_t dev)
78356723Sshin{
78462587Sitojun    int unit = minor(dev);
78556723Sshin
78656723Sshin    if (init_done == COLD)
78756723Sshin	return(NULL);
78856723Sshin    if (unit == SC_CONSOLE)
78967455Sitojun	return CONSOLE_TTY;
79056723Sshin    if (unit == SC_MOUSE)
79156723Sshin	return MOUSE_TTY;
79256723Sshin    if (unit >= MAXCONS || unit < 0)
79356723Sshin	return(NULL);
79456723Sshin    return VIRTUAL_TTY(unit);
79556723Sshin}
79662587Sitojun
79756723Sshinint
79856723Sshinscopen(dev_t dev, int flag, int mode, struct proc *p)
79956723Sshin{
80056723Sshin    struct tty *tp = scdevtotty(dev);
80156723Sshin
80256723Sshin    if (!tp)
80356723Sshin	return(ENXIO);
80456723Sshin
80556723Sshin    tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
80656723Sshin    tp->t_param = scparam;
80756723Sshin    tp->t_dev = dev;
80856723Sshin    if (!(tp->t_state & TS_ISOPEN)) {
80956723Sshin	ttychars(tp);
81056723Sshin        /* Use the current setting of the <-- key as default VERASE. */
81156723Sshin        /* If the Delete key is preferable, an stty is necessary     */
81256723Sshin        tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
81356723Sshin	tp->t_iflag = TTYDEF_IFLAG;
81456723Sshin	tp->t_oflag = TTYDEF_OFLAG;
81556723Sshin	tp->t_cflag = TTYDEF_CFLAG;
81656723Sshin	tp->t_lflag = TTYDEF_LFLAG;
81756723Sshin	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
81856723Sshin	scparam(tp, &tp->t_termios);
81956723Sshin	ttsetwater(tp);
82056723Sshin	(*linesw[tp->t_line].l_modem)(tp, 1);
82156723Sshin    	if (minor(dev) == SC_MOUSE)
82256723Sshin	    mouse_level = 0;		/* XXX */
82362587Sitojun    }
82456723Sshin    else
82556723Sshin	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
82656723Sshin	    return(EBUSY);
82762587Sitojun    if (minor(dev) < MAXCONS && !console[minor(dev)]) {
82856723Sshin	console[minor(dev)] = alloc_scp();
82956723Sshin    }
83056723Sshin    if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
83156723Sshin	tp->t_winsize.ws_col = console[minor(dev)]->xsize;
83256723Sshin	tp->t_winsize.ws_row = console[minor(dev)]->ysize;
83356723Sshin    }
83456723Sshin    return ((*linesw[tp->t_line].l_open)(dev, tp));
83556723Sshin}
83656723Sshin
83756723Sshinint
83856723Sshinscclose(dev_t dev, int flag, int mode, struct proc *p)
83956723Sshin{
84056723Sshin    struct tty *tp = scdevtotty(dev);
84156723Sshin    struct scr_stat *scp;
84256723Sshin
84356723Sshin    if (!tp)
84456723Sshin	return(ENXIO);
84556723Sshin    if (minor(dev) < MAXCONS) {
84656723Sshin	scp = get_scr_stat(tp->t_dev);
84756723Sshin	if (scp->status & SWITCH_WAIT_ACQ)
84856723Sshin	    wakeup((caddr_t)&scp->smode);
84956723Sshin#if not_yet_done
85056723Sshin	if (scp == &main_console) {
85156723Sshin	    scp->pid = 0;
85256723Sshin	    scp->proc = NULL;
85356723Sshin	    scp->smode.mode = VT_AUTO;
85456723Sshin	}
85556723Sshin	else {
85656723Sshin	    free(scp->scr_buf, M_DEVBUF);
85756723Sshin	    if (scp->history != NULL) {
85856723Sshin		free(scp->history, M_DEVBUF);
85956723Sshin		if (scp->history_size / scp->xsize
86056723Sshin			> imax(SC_HISTORY_SIZE, scp->ysize))
86156723Sshin		    extra_history_size += scp->history_size / scp->xsize
86256723Sshin			- imax(SC_HISTORY_SIZE, scp->ysize);
86356723Sshin	    }
86456723Sshin	    free(scp, M_DEVBUF);
86556723Sshin	    console[minor(dev)] = NULL;
86656723Sshin	}
86756723Sshin#else
86856723Sshin	scp->pid = 0;
86956723Sshin	scp->proc = NULL;
87056723Sshin	scp->smode.mode = VT_AUTO;
87156723Sshin#endif
87256723Sshin    }
87356723Sshin    spltty();
87456723Sshin    (*linesw[tp->t_line].l_close)(tp, flag);
87556723Sshin    ttyclose(tp);
87656723Sshin    spl0();
87756723Sshin    return(0);
87856723Sshin}
87956723Sshin
88056723Sshinint
88156723Sshinscread(dev_t dev, struct uio *uio, int flag)
88256723Sshin{
88356723Sshin    struct tty *tp = scdevtotty(dev);
88456723Sshin
88556723Sshin    if (!tp)
88656723Sshin	return(ENXIO);
88756723Sshin    return((*linesw[tp->t_line].l_read)(tp, uio, flag));
88856723Sshin}
88956723Sshin
89056723Sshinint
89156723Sshinscwrite(dev_t dev, struct uio *uio, int flag)
89256723Sshin{
89356723Sshin    struct tty *tp = scdevtotty(dev);
89456723Sshin
89556723Sshin    if (!tp)
89656723Sshin	return(ENXIO);
89756723Sshin    return((*linesw[tp->t_line].l_write)(tp, uio, flag));
89856723Sshin}
89956723Sshin
90056723Sshinvoid
90156723Sshinscintr(int unit)
90256723Sshin{
90356723Sshin    static struct tty *cur_tty;
90456723Sshin    int c, len;
90556723Sshin    u_char *cp;
90656723Sshin
90756723Sshin    /* make screensaver happy */
90856723Sshin    scrn_time_stamp = mono_time.tv_sec;
90956723Sshin
91056723Sshin    /*
91156723Sshin     * Loop while there is still input to get from the keyboard.
91256723Sshin     * I don't think this is nessesary, and it doesn't fix
91356723Sshin     * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
91456723Sshin     */
91556723Sshin    while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
91656723Sshin
91756723Sshin	cur_tty = VIRTUAL_TTY(get_scr_num());
91856723Sshin	if (!(cur_tty->t_state & TS_ISOPEN))
91956723Sshin	    if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
92056723Sshin		continue;
92156723Sshin
92256723Sshin	switch (c & 0xff00) {
92356723Sshin	case 0x0000: /* normal key */
92456723Sshin	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
92556723Sshin	    break;
92656723Sshin	case FKEY:  /* function key, return string */
92756723Sshin	    if (cp = get_fstr((u_int)c, (u_int *)&len)) {
92856723Sshin	    	while (len-- >  0)
92956723Sshin		    (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
93056723Sshin	    }
93156723Sshin	    break;
93256723Sshin	case MKEY:  /* meta is active, prepend ESC */
93356723Sshin	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
93456723Sshin	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
93556723Sshin	    break;
93656723Sshin	case BKEY:  /* backtab fixed sequence (esc [ Z) */
93756723Sshin	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
93856723Sshin	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
93956723Sshin	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
94056723Sshin	    break;
94156723Sshin	}
94267455Sitojun    }
94367455Sitojun
94467455Sitojun    if (cur_console->status & MOUSE_ENABLED) {
94567455Sitojun	cur_console->status &= ~MOUSE_VISIBLE;
94667455Sitojun	remove_mouse_image(cur_console);
94767455Sitojun    }
94867455Sitojun}
94967455Sitojun
95067455Sitojunstatic int
95167455Sitojunscparam(struct tty *tp, struct termios *t)
95267455Sitojun{
95367455Sitojun    tp->t_ispeed = t->c_ispeed;
95467455Sitojun    tp->t_ospeed = t->c_ospeed;
95567455Sitojun    tp->t_cflag = t->c_cflag;
95667455Sitojun    return 0;
95767455Sitojun}
95867455Sitojun
95967455Sitojunint
96067455Sitojunscioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
96167455Sitojun{
96267455Sitojun    int error;
96367455Sitojun    u_int i;
96456723Sshin    struct tty *tp;
96556723Sshin    scr_stat *scp;
96656723Sshin    u_short *usp;
96756723Sshin    char *mp;
96856723Sshin    int s;
96956723Sshin
97056723Sshin    tp = scdevtotty(dev);
97156723Sshin    if (!tp)
97256723Sshin	return ENXIO;
97356723Sshin    scp = get_scr_stat(tp->t_dev);
97456723Sshin
97556723Sshin    /* If there is a user_ioctl function call that first */
97656723Sshin    if (sc_user_ioctl) {
97756723Sshin	if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p))
97856723Sshin	    return error;
97956723Sshin    }
98056723Sshin
98156723Sshin    switch (cmd) {  		/* process console hardware related ioctl's */
98256723Sshin
98356723Sshin    case GIO_ATTR:      	/* get current attributes */
98456723Sshin	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
98556723Sshin	return 0;
98656723Sshin
98756723Sshin    case GIO_COLOR:     	/* is this a color console ? */
98856723Sshin	if (crtc_addr == COLOR_BASE)
98956723Sshin	    *(int*)data = 1;
99056723Sshin	else
99156723Sshin	    *(int*)data = 0;
99256723Sshin	return 0;
99356723Sshin
99456723Sshin    case CONS_CURRENT:  	/* get current adapter type */
99556723Sshin	*(int *)data = crtc_type;
99656723Sshin	return 0;
99756723Sshin
99856723Sshin    case CONS_GET:      	/* get current video mode */
99956723Sshin	*(int*)data = scp->mode;
100056723Sshin	return 0;
100156723Sshin
100256723Sshin    case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
100356723Sshin	if (*(int *)data < 0)
100456723Sshin            return EINVAL;
100556723Sshin	scrn_blank_time = *(int *)data;
100656723Sshin	if (scrn_blank_time == 0)
100756723Sshin	    scrn_time_stamp = mono_time.tv_sec;
100856723Sshin	return 0;
100956723Sshin
101056723Sshin    case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
101156723Sshin	if ((*(int*)data) & 0x01)
101256723Sshin	    flags |= BLINK_CURSOR;
101356723Sshin	else
101456723Sshin	    flags &= ~BLINK_CURSOR;
101556723Sshin	if ((*(int*)data) & 0x02) {
101656723Sshin	    if (!crtc_vga)
101756723Sshin		return ENXIO;
101856723Sshin	    flags |= CHAR_CURSOR;
101956723Sshin	} else
102056723Sshin	    flags &= ~CHAR_CURSOR;
102162587Sitojun	/*
102256723Sshin	 * The cursor shape is global property; all virtual consoles
102356723Sshin	 * are affected. Update the cursor in the current console...
102456723Sshin	 */
102556723Sshin	if (!(cur_console->status & UNKNOWN_MODE)) {
102656723Sshin            remove_cursor_image(cur_console);
102756723Sshin	    if (flags & CHAR_CURSOR)
102856723Sshin	        set_destructive_cursor(cur_console);
102956723Sshin	    draw_cursor_image(cur_console);
103056723Sshin	}
103156723Sshin	return 0;
103256723Sshin
103356723Sshin    case CONS_BELLTYPE: 	/* set bell type sound/visual */
103456723Sshin	if (*data)
103562587Sitojun	    flags |= VISUAL_BELL;
103662587Sitojun	else
103762587Sitojun	    flags &= ~VISUAL_BELL;
103856723Sshin	return 0;
103956723Sshin
104056723Sshin    case CONS_HISTORY:  	/* set history size */
104156723Sshin	if (*(int *)data > 0) {
104256723Sshin	    int lines;	/* buffer size to allocate */
104356723Sshin	    int lines0;	/* current buffer size */
104456723Sshin
104556723Sshin	    lines = imax(*(int *)data, scp->ysize);
104656723Sshin	    lines0 = (scp->history != NULL) ?
104756723Sshin		      scp->history_size / scp->xsize : scp->ysize;
104856723Sshin	    /*
104956723Sshin	     * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
105056723Sshin	     * lines or scp->ysize lines, whichever is larger. A value
105156723Sshin	     * greater than that is allowed, subject to extra_history_size.
105256723Sshin	     */
105356723Sshin	    if (lines > imax(lines0, SC_HISTORY_SIZE) + extra_history_size)
105456723Sshin                return EINVAL;
105556723Sshin            if (cur_console->status & BUFFER_SAVED)
105656723Sshin                return EBUSY;
105756723Sshin	    usp = scp->history;
105856723Sshin	    scp->history = NULL;
105956723Sshin	    if (usp != NULL)
106056723Sshin		free(usp, M_DEVBUF);
106156723Sshin	    scp->history_size = lines * scp->xsize;
106256723Sshin	    /*
106356723Sshin	     * extra_history_size +=
106456723Sshin	     *    (lines0 > imax(SC_HISTORY_SIZE, scp->ysize)) ?
106556723Sshin	     *     lines0 - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
106662587Sitojun	     * extra_history_size -=
106762587Sitojun	     *    (lines > imax(SC_HISTORY_SIZE, scp->ysize)) ?
106862587Sitojun	     *	   lines - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
106962587Sitojun	     * lines0 >= ysize && lines >= ysize... Hey, the above can be
107062587Sitojun	     * reduced to the following...
107162587Sitojun	     */
107262587Sitojun	    extra_history_size +=
107362587Sitojun		imax(lines0, SC_HISTORY_SIZE) - imax(lines, SC_HISTORY_SIZE);
107462587Sitojun	    usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
107562587Sitojun				    M_DEVBUF, M_WAITOK);
107662587Sitojun	    bzero(usp, scp->history_size * sizeof(u_short));
107762587Sitojun	    scp->history_head = scp->history_pos = usp;
107862587Sitojun	    scp->history = usp;
107962587Sitojun	    return 0;
108062587Sitojun	}
108162587Sitojun	else
108262587Sitojun	    return EINVAL;
108362587Sitojun
108462587Sitojun    case CONS_MOUSECTL:		/* control mouse arrow */
108562587Sitojun    case OLD_CONS_MOUSECTL:
108662587Sitojun    {
108762587Sitojun	/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
108862587Sitojun	static butmap[8] = {
108962587Sitojun            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP
109062587Sitojun		| MOUSE_MSC_BUTTON3UP,
109156723Sshin            MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
109256723Sshin            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
109356723Sshin            MOUSE_MSC_BUTTON3UP,
109456723Sshin            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
109556723Sshin            MOUSE_MSC_BUTTON2UP,
109656723Sshin            MOUSE_MSC_BUTTON1UP,
109756723Sshin            0,
109856723Sshin	};
109956723Sshin	mouse_info_t *mouse = (mouse_info_t*)data;
110056723Sshin	mouse_info_t buf;
110156723Sshin
110256723Sshin	if (!crtc_vga)
110362587Sitojun	    return ENODEV;
110462587Sitojun
110562587Sitojun	if (cmd == OLD_CONS_MOUSECTL) {
110662587Sitojun	    static unsigned char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
110762587Sitojun	    old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
110862587Sitojun
110962587Sitojun	    mouse = &buf;
111062587Sitojun	    mouse->operation = old_mouse->operation;
111162587Sitojun	    switch (mouse->operation) {
111262587Sitojun	    case MOUSE_MODE:
111356723Sshin		mouse->u.mode = old_mouse->u.mode;
111456723Sshin		break;
111556723Sshin	    case MOUSE_SHOW:
111656723Sshin	    case MOUSE_HIDE:
111756723Sshin		break;
111856723Sshin	    case MOUSE_MOVEABS:
111956723Sshin	    case MOUSE_MOVEREL:
112056723Sshin	    case MOUSE_ACTION:
112156723Sshin		mouse->u.data.x = old_mouse->u.data.x;
112256723Sshin		mouse->u.data.y = old_mouse->u.data.y;
112356723Sshin		mouse->u.data.z = 0;
112456723Sshin		mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
112556723Sshin		break;
112656723Sshin	    case MOUSE_GETINFO:
112756723Sshin		old_mouse->u.data.x = scp->mouse_xpos;
112856723Sshin		old_mouse->u.data.y = scp->mouse_ypos;
112956723Sshin		old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
113056723Sshin		break;
113156723Sshin	    default:
113256723Sshin		return EINVAL;
113356723Sshin	    }
113456723Sshin	}
113556723Sshin
113656723Sshin	switch (mouse->operation) {
113756723Sshin	case MOUSE_MODE:
113856723Sshin	    if (ISSIGVALID(mouse->u.mode.signal)) {
113956723Sshin		scp->mouse_signal = mouse->u.mode.signal;
114056723Sshin		scp->mouse_proc = p;
114156723Sshin		scp->mouse_pid = p->p_pid;
114256723Sshin	    }
114356723Sshin	    else {
114456723Sshin		scp->mouse_signal = 0;
114556723Sshin		scp->mouse_proc = NULL;
114656723Sshin		scp->mouse_pid = 0;
114756723Sshin	    }
114856723Sshin	    break;
114956723Sshin
115056723Sshin	case MOUSE_SHOW:
115156723Sshin	    if (!(scp->status & MOUSE_ENABLED)) {
115256723Sshin		scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
115356723Sshin		scp->mouse_oldpos = scp->mouse_pos;
115456723Sshin		mark_all(scp);
115556723Sshin	    }
115656723Sshin	    else
115756723Sshin		return EINVAL;
115856723Sshin	    break;
115956723Sshin
116056723Sshin	case MOUSE_HIDE:
116156723Sshin	    if (scp->status & MOUSE_ENABLED) {
116256723Sshin		scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
116356723Sshin		mark_all(scp);
116456723Sshin	    }
116556723Sshin	    else
116656723Sshin		return EINVAL;
116756723Sshin	    break;
116856723Sshin
116956723Sshin	case MOUSE_MOVEABS:
117056723Sshin	    scp->mouse_xpos = mouse->u.data.x;
117156723Sshin	    scp->mouse_ypos = mouse->u.data.y;
117256723Sshin	    set_mouse_pos(scp);
117356723Sshin	    break;
117456723Sshin
117556723Sshin	case MOUSE_MOVEREL:
117656723Sshin	    scp->mouse_xpos += mouse->u.data.x;
117756723Sshin	    scp->mouse_ypos += mouse->u.data.y;
117856723Sshin	    set_mouse_pos(scp);
117956723Sshin	    break;
118056723Sshin
118156723Sshin	case MOUSE_GETINFO:
118256723Sshin	    mouse->u.data.x = scp->mouse_xpos;
118356723Sshin	    mouse->u.data.y = scp->mouse_ypos;
118456723Sshin	    mouse->u.data.z = 0;
118556723Sshin	    mouse->u.data.buttons = scp->mouse_buttons;
118656723Sshin	    break;
118756723Sshin
118856723Sshin	case MOUSE_ACTION:
118956723Sshin	case MOUSE_MOTION_EVENT:
119056723Sshin	    /* this should maybe only be settable from /dev/consolectl SOS */
119156723Sshin	    /* send out mouse event on /dev/sysmouse */
119256723Sshin
119356723Sshin	    mouse_status.dx += mouse->u.data.x;
119456723Sshin	    mouse_status.dy += mouse->u.data.y;
119556723Sshin	    mouse_status.dz += mouse->u.data.z;
119656723Sshin	    if (mouse->operation == MOUSE_ACTION)
119756723Sshin	        mouse_status.button = mouse->u.data.buttons;
119856723Sshin	    mouse_status.flags |=
119956723Sshin		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
120056723Sshin		    MOUSE_POSCHANGED : 0)
120156723Sshin		| (mouse_status.obutton ^ mouse_status.button);
120256723Sshin
120356723Sshin	    if (cur_console->status & MOUSE_ENABLED)
120456723Sshin	    	cur_console->status |= MOUSE_VISIBLE;
120556723Sshin
120656723Sshin	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
120756723Sshin		u_char buf[MOUSE_SYS_PACKETSIZE];
120856723Sshin		int j;
120956723Sshin
121056723Sshin		/* the first five bytes are compatible with MouseSystems' */
121156723Sshin		buf[0] = MOUSE_MSC_SYNC
121256723Sshin		    | butmap[mouse_status.button & MOUSE_STDBUTTONS];
121356723Sshin		j = imax(imin(mouse->u.data.x, 255), -256);
121456723Sshin		buf[1] = j >> 1;
121556723Sshin		buf[3] = j - buf[1];
121656723Sshin		j = -imax(imin(mouse->u.data.y, 255), -256);
121756723Sshin		buf[2] = j >> 1;
121856723Sshin		buf[4] = j - buf[2];
121956723Sshin		for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
122056723Sshin	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
122156723Sshin		if (mouse_level >= 1) { 	/* extended part */
122256723Sshin		    j = imax(imin(mouse->u.data.z, 127), -128);
122356723Sshin		    buf[5] = (j >> 1) & 0x7f;
122456723Sshin		    buf[6] = (j - (j >> 1)) & 0x7f;
122556723Sshin		    /* buttons 4-10 */
122656723Sshin		    buf[7] = (~mouse_status.button >> 3) & 0x7f;
122756723Sshin		    for (j = MOUSE_MSC_PACKETSIZE;
122856723Sshin			 j < MOUSE_SYS_PACKETSIZE; j++)
122956723Sshin	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
123056723Sshin		}
123162587Sitojun	    }
123256723Sshin
123356723Sshin	    if (cur_console->mouse_signal) {
123456723Sshin		cur_console->mouse_buttons = mouse->u.data.buttons;
123556723Sshin    		/* has controlling process died? */
123656723Sshin		if (cur_console->mouse_proc &&
123756723Sshin		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
123856723Sshin		    	cur_console->mouse_signal = 0;
123956723Sshin			cur_console->mouse_proc = NULL;
124056723Sshin			cur_console->mouse_pid = 0;
124156723Sshin		}
124256723Sshin		else
124356723Sshin		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
124456723Sshin	    }
124556723Sshin	    else if (mouse->operation == MOUSE_ACTION) {
124656723Sshin		/* process button presses */
124756723Sshin		if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
124856723Sshin		    !(cur_console->status & UNKNOWN_MODE)) {
124956723Sshin		    cur_console->mouse_buttons = mouse->u.data.buttons;
125056723Sshin		    if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
125156723Sshin			mouse_cut_start(cur_console);
125256723Sshin		    else
125356723Sshin			mouse_cut_end(cur_console);
125462587Sitojun		    if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
125562587Sitojun			cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
125662587Sitojun			mouse_paste(cur_console);
125762587Sitojun		}
125862587Sitojun	    }
125962587Sitojun
126056723Sshin	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
126156723Sshin		cur_console->mouse_xpos += mouse->u.data.x;
126256723Sshin		cur_console->mouse_ypos += mouse->u.data.y;
126356723Sshin		set_mouse_pos(cur_console);
126456723Sshin	    }
126556723Sshin
126656723Sshin	    break;
126756723Sshin
126856723Sshin	case MOUSE_BUTTON_EVENT:
126956723Sshin	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
127056723Sshin		return EINVAL;
127156723Sshin	    if (mouse->u.event.value < 0)
127256723Sshin		return EINVAL;
127356723Sshin
127456723Sshin	    if (mouse->u.event.value > 0) {
127556723Sshin	        cur_console->mouse_buttons |= mouse->u.event.id;
127656723Sshin	        mouse_status.button |= mouse->u.event.id;
127756723Sshin	    } else {
127856723Sshin	        cur_console->mouse_buttons &= ~mouse->u.event.id;
127956723Sshin	        mouse_status.button &= ~mouse->u.event.id;
128056723Sshin	    }
128156723Sshin	    mouse_status.flags |=
128262587Sitojun		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
128362587Sitojun		    MOUSE_POSCHANGED : 0)
128462587Sitojun		| (mouse_status.obutton ^ mouse_status.button);
128562587Sitojun
128662587Sitojun	    if (cur_console->status & MOUSE_ENABLED)
128762587Sitojun	    	cur_console->status |= MOUSE_VISIBLE;
128862587Sitojun
128962587Sitojun	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
129062587Sitojun		u_char buf[8];
129162587Sitojun		int i;
129256723Sshin
129362587Sitojun		buf[0] = MOUSE_MSC_SYNC
129462587Sitojun			 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
129562587Sitojun		buf[7] = (~mouse_status.button >> 3) & 0x7f;
129662587Sitojun		buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
129762587Sitojun		for (i = 0;
129856723Sshin		     i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
129962587Sitojun					     : MOUSE_MSC_PACKETSIZE); i++)
130062587Sitojun	    	    (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
130162587Sitojun	    }
130262587Sitojun
130362587Sitojun	    if (cur_console->mouse_signal) {
130462587Sitojun		if (cur_console->mouse_proc &&
130562587Sitojun		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
130662587Sitojun		    	cur_console->mouse_signal = 0;
130762587Sitojun			cur_console->mouse_proc = NULL;
130862587Sitojun			cur_console->mouse_pid = 0;
130962587Sitojun		}
131062587Sitojun		else
131162587Sitojun		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
131262587Sitojun		break;
131362587Sitojun	    }
131462587Sitojun
131562587Sitojun	    if (cur_console->status & UNKNOWN_MODE)
131662587Sitojun		break;
131762587Sitojun
131862587Sitojun	    switch (mouse->u.event.id) {
131962587Sitojun	    case MOUSE_BUTTON1DOWN:
132056723Sshin	        switch (mouse->u.event.value % 4) {
132162587Sitojun		case 0:	/* up */
132262587Sitojun		    mouse_cut_end(cur_console);
132362587Sitojun		    break;
132462587Sitojun		case 1:
132562587Sitojun		    mouse_cut_start(cur_console);
132662587Sitojun		    break;
132756723Sshin		case 2:
132862587Sitojun		    mouse_cut_word(cur_console);
132962587Sitojun		    break;
133062587Sitojun		case 3:
133162587Sitojun		    mouse_cut_line(cur_console);
133262587Sitojun		    break;
133356723Sshin		}
133462587Sitojun		break;
133562587Sitojun	    case MOUSE_BUTTON2DOWN:
133662587Sitojun	        switch (mouse->u.event.value) {
133762587Sitojun		case 0:	/* up */
133862587Sitojun		    break;
133962587Sitojun		default:
134062587Sitojun		    mouse_paste(cur_console);
134162587Sitojun		    break;
134262587Sitojun		}
134356723Sshin		break;
134462587Sitojun	    case MOUSE_BUTTON3DOWN:
134562587Sitojun	        switch (mouse->u.event.value) {
134656723Sshin		case 0:	/* up */
134762587Sitojun		    if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
134856723Sshin		        mouse_cut_end(cur_console);
134962587Sitojun		    break;
135056723Sshin		default:
135162587Sitojun		    mouse_cut_extend(cur_console);
135262587Sitojun		    break;
135356723Sshin		}
135462587Sitojun		break;
135562587Sitojun	    }
135662587Sitojun	    break;
135762587Sitojun
135856723Sshin	default:
135956723Sshin	    return EINVAL;
136056723Sshin	}
136156723Sshin	/* make screensaver happy */
136256723Sshin	scrn_time_stamp = mono_time.tv_sec;
136356723Sshin	return 0;
136456723Sshin    }
136556723Sshin
136656723Sshin    /* MOUSE_XXX: /dev/sysmouse ioctls */
136756723Sshin    case MOUSE_GETHWINFO:	/* get device information */
136856723Sshin    {
136956723Sshin	mousehw_t *hw = (mousehw_t *)data;
137056723Sshin
137156723Sshin	if (tp != MOUSE_TTY)
137256723Sshin	    return ENOTTY;
137356723Sshin	hw->buttons = 10;		/* XXX unknown */
137456723Sshin	hw->iftype = MOUSE_IF_SYSMOUSE;
137556723Sshin	hw->type = MOUSE_MOUSE;
137656723Sshin	hw->model = MOUSE_MODEL_GENERIC;
137756723Sshin	hw->hwid = 0;
137856723Sshin	return 0;
137962587Sitojun    }
138062587Sitojun
138162587Sitojun    case MOUSE_GETMODE:		/* get protocol/mode */
138262587Sitojun    {
138362587Sitojun	mousemode_t *mode = (mousemode_t *)data;
138462587Sitojun
138562587Sitojun	if (tp != MOUSE_TTY)
138662587Sitojun	    return ENOTTY;
138762587Sitojun	mode->level = mouse_level;
138862587Sitojun	switch (mode->level) {
138962587Sitojun	case 0:
139062587Sitojun	    /* at this level, sysmouse emulates MouseSystems protocol */
139162587Sitojun	    mode->protocol = MOUSE_PROTO_MSC;
139262587Sitojun	    mode->rate = -1;		/* unknown */
139362587Sitojun	    mode->resolution = -1;	/* unknown */
139462587Sitojun	    mode->accelfactor = 0;	/* disabled */
139562587Sitojun	    mode->packetsize = MOUSE_MSC_PACKETSIZE;
139662587Sitojun	    mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
139762587Sitojun	    mode->syncmask[1] = MOUSE_MSC_SYNC;
139856723Sshin	    break;
139956723Sshin
140056723Sshin	case 1:
140156723Sshin	    /* at this level, sysmouse uses its own protocol */
140256723Sshin	    mode->protocol = MOUSE_PROTO_SYSMOUSE;
140356723Sshin	    mode->rate = -1;
140456723Sshin	    mode->resolution = -1;
140556723Sshin	    mode->accelfactor = 0;
140656723Sshin	    mode->packetsize = MOUSE_SYS_PACKETSIZE;
140756723Sshin	    mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
140856723Sshin	    mode->syncmask[1] = MOUSE_SYS_SYNC;
140956723Sshin	    break;
141056723Sshin	}
141156723Sshin	return 0;
141256723Sshin    }
141356723Sshin
141456723Sshin    case MOUSE_SETMODE:		/* set protocol/mode */
141556723Sshin    {
141656723Sshin	mousemode_t *mode = (mousemode_t *)data;
141756723Sshin
141856723Sshin	if (tp != MOUSE_TTY)
141956723Sshin	    return ENOTTY;
142056723Sshin	if ((mode->level < 0) || (mode->level > 1))
142156723Sshin	    return EINVAL;
142256723Sshin	mouse_level = mode->level;
142356723Sshin	return 0;
142456723Sshin    }
142556723Sshin
142656723Sshin    case MOUSE_GETLEVEL:	/* get operation level */
142756723Sshin	if (tp != MOUSE_TTY)
142856723Sshin	    return ENOTTY;
142956723Sshin	*(int *)data = mouse_level;
143056723Sshin	return 0;
143156723Sshin
143256723Sshin    case MOUSE_SETLEVEL:	/* set operation level */
143356723Sshin	if (tp != MOUSE_TTY)
143456723Sshin	    return ENOTTY;
143556723Sshin	if ((*(int *)data  < 0) || (*(int *)data > 1))
143656723Sshin	    return EINVAL;
143756723Sshin	mouse_level = *(int *)data;
143856723Sshin	return 0;
143956723Sshin
144056723Sshin    case MOUSE_GETSTATUS:	/* get accumulated mouse events */
144156723Sshin	if (tp != MOUSE_TTY)
144256723Sshin	    return ENOTTY;
144356723Sshin	s = spltty();
144456723Sshin	*(mousestatus_t *)data = mouse_status;
144556723Sshin	mouse_status.flags = 0;
144656723Sshin	mouse_status.obutton = mouse_status.button;
144756723Sshin	mouse_status.dx = 0;
144856723Sshin	mouse_status.dy = 0;
144956723Sshin	mouse_status.dz = 0;
145056723Sshin	splx(s);
145156723Sshin	return 0;
145256723Sshin
145356723Sshin#if notyet
145456723Sshin    case MOUSE_GETVARS:		/* get internal mouse variables */
145556723Sshin    case MOUSE_SETVARS:		/* set internal mouse variables */
145656723Sshin	if (tp != MOUSE_TTY)
145756723Sshin	    return ENOTTY;
145856723Sshin	return ENODEV;
145956723Sshin#endif
146056723Sshin
146156723Sshin    case MOUSE_READSTATE:	/* read status from the device */
146256723Sshin    case MOUSE_READDATA:	/* read data from the device */
146356723Sshin	if (tp != MOUSE_TTY)
146456723Sshin	    return ENOTTY;
146556723Sshin	return ENODEV;
146656723Sshin
146756723Sshin    case CONS_GETINFO:  	/* get current (virtual) console info */
146856723Sshin    {
146956723Sshin	vid_info_t *ptr = (vid_info_t*)data;
147056723Sshin	if (ptr->size == sizeof(struct vid_info)) {
147156723Sshin	    ptr->m_num = get_scr_num();
147256723Sshin	    ptr->mv_col = scp->xpos;
147356723Sshin	    ptr->mv_row = scp->ypos;
147456723Sshin	    ptr->mv_csz = scp->xsize;
147556723Sshin	    ptr->mv_rsz = scp->ysize;
147656723Sshin	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
147756723Sshin	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
147856723Sshin	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
147956723Sshin	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
148056723Sshin	    ptr->mv_grfc.fore = 0;      /* not supported */
148156723Sshin	    ptr->mv_grfc.back = 0;      /* not supported */
148256723Sshin	    ptr->mv_ovscan = scp->border;
148356723Sshin	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
148456723Sshin	    return 0;
148556723Sshin	}
148656723Sshin	return EINVAL;
148756723Sshin    }
148856723Sshin
148956723Sshin    case CONS_GETVERS:  	/* get version number */
149056723Sshin	*(int*)data = 0x200;    /* version 2.0 */
149156723Sshin	return 0;
149256723Sshin
149356723Sshin    /* VGA TEXT MODES */
149456723Sshin    case SW_VGA_C40x25:
149556723Sshin    case SW_VGA_C80x25: case SW_VGA_M80x25:
149656723Sshin    case SW_VGA_C80x30: case SW_VGA_M80x30:
149756723Sshin    case SW_VGA_C80x50: case SW_VGA_M80x50:
149856723Sshin    case SW_VGA_C80x60: case SW_VGA_M80x60:
149956723Sshin    case SW_B40x25:     case SW_C40x25:
150056723Sshin    case SW_B80x25:     case SW_C80x25:
150156723Sshin    case SW_ENH_B40x25: case SW_ENH_C40x25:
150256723Sshin    case SW_ENH_B80x25: case SW_ENH_C80x25:
150356723Sshin    case SW_ENH_B80x43: case SW_ENH_C80x43:
150456723Sshin    case SW_EGAMONO80x25:
150556723Sshin
150656723Sshin	if (!crtc_vga)
150756723Sshin 	    return ENODEV;
150856723Sshin 	mp = get_mode_param(scp, cmd & 0xff);
150956723Sshin 	if (mp == NULL)
151056723Sshin 	    return ENODEV;
151156723Sshin
151256723Sshin	if (scp->history != NULL)
151356723Sshin	    i = imax(scp->history_size / scp->xsize
151456723Sshin		     - imax(SC_HISTORY_SIZE, scp->ysize), 0);
151556723Sshin	else
151656723Sshin	    i = 0;
151756723Sshin	switch (cmd & 0xff) {
151856723Sshin	case M_VGA_C80x60: case M_VGA_M80x60:
151956723Sshin	    if (!(fonts_loaded & FONT_8))
152056723Sshin		return EINVAL;
152156723Sshin	    scp->xsize = 80;
152256723Sshin	    scp->ysize = 60;
152356723Sshin	    break;
152456723Sshin	case M_VGA_C80x50: case M_VGA_M80x50:
152556723Sshin	    if (!(fonts_loaded & FONT_8))
152656723Sshin		return EINVAL;
152756723Sshin	    scp->xsize = 80;
152856723Sshin	    scp->ysize = 50;
152956723Sshin	    break;
153056723Sshin	case M_ENH_B80x43: case M_ENH_C80x43:
153156723Sshin	    if (!(fonts_loaded & FONT_8))
153256723Sshin		return EINVAL;
153356723Sshin	    scp->xsize = 80;
153456723Sshin	    scp->ysize = 43;
153556723Sshin	    break;
153656723Sshin	case M_VGA_C80x30: case M_VGA_M80x30:
153756723Sshin	    scp->xsize = 80;
153856723Sshin	    scp->ysize = 30;
153956723Sshin	    break;
154056723Sshin	case M_ENH_C40x25: case M_ENH_B40x25:
154156723Sshin	case M_ENH_C80x25: case M_ENH_B80x25:
154256723Sshin	case M_EGAMONO80x25:
154356723Sshin	    if (!(fonts_loaded & FONT_14))
154456723Sshin		return EINVAL;
154556723Sshin	    /* FALL THROUGH */
154656723Sshin	default:
154756723Sshin	    if ((cmd & 0xff) > M_VGA_CG320)
154856723Sshin		return EINVAL;
154956723Sshin            scp->xsize = mp[0];
155056723Sshin            scp->ysize = mp[1] + rows_offset;
155156723Sshin	    break;
155256723Sshin	}
155356723Sshin	scp->mode = cmd & 0xff;
155456723Sshin	free(scp->scr_buf, M_DEVBUF);
155556723Sshin	scp->scr_buf = (u_short *)
155656723Sshin	    malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK);
155756723Sshin    	scp->cursor_pos = scp->cursor_oldpos =
155856723Sshin	    scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
155956723Sshin    	scp->mouse_pos = scp->mouse_oldpos =
156056723Sshin	    scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
156156723Sshin	    scp->mouse_xpos/8);
156256723Sshin	free(cut_buffer, M_DEVBUF);
156356723Sshin    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
156456723Sshin	cut_buffer[0] = 0x00;
156556723Sshin	usp = scp->history;
156656723Sshin	scp->history = NULL;
156756723Sshin	if (usp != NULL) {
156856723Sshin	    free(usp, M_DEVBUF);
156956723Sshin	    extra_history_size += i;
157056723Sshin	}
157156723Sshin	scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
157256723Sshin	usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
157356723Sshin				M_DEVBUF, M_NOWAIT);
157456723Sshin	if (usp != NULL)
157556723Sshin	    bzero(usp, scp->history_size * sizeof(u_short));
157656723Sshin	scp->history_head = scp->history_pos = usp;
157756723Sshin	scp->history = usp;
157856723Sshin	if (scp == cur_console)
157956723Sshin	    set_mode(scp);
158056723Sshin	scp->status &= ~UNKNOWN_MODE;
158156723Sshin	clear_screen(scp);
158256723Sshin
158356723Sshin	if (tp->t_winsize.ws_col != scp->xsize
158456723Sshin	    || tp->t_winsize.ws_row != scp->ysize) {
158556723Sshin	    tp->t_winsize.ws_col = scp->xsize;
158656723Sshin	    tp->t_winsize.ws_row = scp->ysize;
158756723Sshin	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
158856723Sshin	}
158956723Sshin	return 0;
159056723Sshin
159156723Sshin    /* GRAPHICS MODES */
159256723Sshin    case SW_BG320:     case SW_BG640:
159356723Sshin    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
159456723Sshin    case SW_CG640x350: case SW_ENH_CG640:
159556723Sshin    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
159656723Sshin
159756723Sshin	if (!crtc_vga)
159856723Sshin	    return ENODEV;
159956723Sshin	mp = get_mode_param(scp, cmd & 0xff);
160056723Sshin	if (mp == NULL)
160156723Sshin	    return ENODEV;
160256723Sshin
160356723Sshin	scp->mode = cmd & 0xFF;
160456723Sshin	scp->xpixel = mp[0] * 8;
160556723Sshin	scp->ypixel = (mp[1] + rows_offset) * mp[2];
160656723Sshin	if (scp == cur_console)
160756723Sshin	    set_mode(scp);
160856723Sshin	scp->status |= UNKNOWN_MODE;    /* graphics mode */
160956723Sshin	/* clear_graphics();*/
161056723Sshin
161156723Sshin	if (tp->t_winsize.ws_xpixel != scp->xpixel
161256723Sshin	    || tp->t_winsize.ws_ypixel != scp->ypixel) {
161356723Sshin	    tp->t_winsize.ws_xpixel = scp->xpixel;
161456723Sshin	    tp->t_winsize.ws_ypixel = scp->ypixel;
161556723Sshin	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
161656723Sshin	}
161756723Sshin	return 0;
161856723Sshin
161956723Sshin    case SW_VGA_MODEX:
162056723Sshin	if (!crtc_vga)
162156723Sshin	    return ENODEV;
162256723Sshin	mp = get_mode_param(scp, cmd & 0xff);
162356723Sshin	if (mp == NULL)
162456723Sshin	    return ENODEV;
162556723Sshin
162656723Sshin	scp->mode = cmd & 0xFF;
162756723Sshin	if (scp == cur_console)
162862587Sitojun	    set_mode(scp);
162956723Sshin	scp->status |= UNKNOWN_MODE;    /* graphics mode */
163056723Sshin	/* clear_graphics();*/
163156723Sshin	scp->xpixel = 320;
163256723Sshin	scp->ypixel = 240;
163356723Sshin	if (tp->t_winsize.ws_xpixel != scp->xpixel
163456723Sshin	    || tp->t_winsize.ws_ypixel != scp->ypixel) {
163562587Sitojun	    tp->t_winsize.ws_xpixel = scp->xpixel;
163662587Sitojun	    tp->t_winsize.ws_ypixel = scp->ypixel;
163762587Sitojun	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
163862587Sitojun	}
163962587Sitojun	return 0;
164062587Sitojun
164162587Sitojun    case VT_SETMODE:    	/* set screen switcher mode */
164256723Sshin    {
164362587Sitojun	struct vt_mode *mode;
164456723Sshin
164556723Sshin	mode = (struct vt_mode *)data;
164656723Sshin	if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
164756723Sshin	    ISSIGVALID(mode->frsig)) {
164856723Sshin	    bcopy(data, &scp->smode, sizeof(struct vt_mode));
164956723Sshin	    if (scp->smode.mode == VT_PROCESS) {
165056723Sshin		scp->proc = p;
165156723Sshin		scp->pid = scp->proc->p_pid;
165256723Sshin	    }
165356723Sshin	    return 0;
165456723Sshin	} else
165556723Sshin	    return EINVAL;
165656723Sshin    }
165756723Sshin
165856723Sshin    case VT_GETMODE:    	/* get screen switcher mode */
165956723Sshin	bcopy(&scp->smode, data, sizeof(struct vt_mode));
166056723Sshin	return 0;
166156723Sshin
166256723Sshin    case VT_RELDISP:    	/* screen switcher ioctl */
166356723Sshin	switch(*data) {
166456723Sshin	case VT_FALSE:  	/* user refuses to release screen, abort */
166556723Sshin	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
166656723Sshin		old_scp->status &= ~SWITCH_WAIT_REL;
166756723Sshin		switch_in_progress = FALSE;
166856723Sshin		return 0;
166956723Sshin	    }
167056723Sshin	    return EINVAL;
167156723Sshin
167256723Sshin	case VT_TRUE:   	/* user has released screen, go on */
167356723Sshin	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
167456723Sshin		scp->status &= ~SWITCH_WAIT_REL;
167556723Sshin		exchange_scr();
167656723Sshin		if (new_scp->smode.mode == VT_PROCESS) {
167756723Sshin		    new_scp->status |= SWITCH_WAIT_ACQ;
167856723Sshin		    psignal(new_scp->proc, new_scp->smode.acqsig);
167956723Sshin		}
168056723Sshin		else
168156723Sshin		    switch_in_progress = FALSE;
168256723Sshin		return 0;
168356723Sshin	    }
168456723Sshin	    return EINVAL;
168556723Sshin
168656723Sshin	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
168756723Sshin	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
168856723Sshin		scp->status &= ~SWITCH_WAIT_ACQ;
168956723Sshin		switch_in_progress = FALSE;
169056723Sshin		return 0;
169156723Sshin	    }
169256723Sshin	    return EINVAL;
169356723Sshin
169462587Sitojun	default:
169556723Sshin	    return EINVAL;
169656723Sshin	}
169756723Sshin	/* NOT REACHED */
169856723Sshin
169956723Sshin    case VT_OPENQRY:    	/* return free virtual console */
170056723Sshin	for (i = 0; i < MAXCONS; i++) {
170156723Sshin	    tp = VIRTUAL_TTY(i);
170256723Sshin	    if (!(tp->t_state & TS_ISOPEN)) {
170356723Sshin		*data = i + 1;
170456723Sshin		return 0;
170556723Sshin	    }
170656723Sshin	}
170762587Sitojun	return EINVAL;
170856723Sshin
170962587Sitojun    case VT_ACTIVATE:   	/* switch to screen *data */
171056723Sshin	return switch_scr(scp, (*data) - 1);
171156723Sshin
171256723Sshin    case VT_WAITACTIVE: 	/* wait for switch to occur */
171356723Sshin	if (*data > MAXCONS || *data < 0)
171456723Sshin	    return EINVAL;
171556723Sshin	if (minor(dev) == (*data) - 1)
171656723Sshin	    return 0;
171756723Sshin	if (*data == 0) {
171856723Sshin	    if (scp == cur_console)
171956723Sshin		return 0;
172056723Sshin	}
172156723Sshin	else
172256723Sshin	    scp = console[(*data) - 1];
172356723Sshin	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
172456723Sshin			     "waitvt", 0)) == ERESTART) ;
172556723Sshin	return error;
172656723Sshin
172756723Sshin    case VT_GETACTIVE:
172862587Sitojun	*data = get_scr_num()+1;
172956723Sshin	return 0;
173062587Sitojun
173156723Sshin    case KDENABIO:      	/* allow io operations */
173256723Sshin	error = suser(p->p_ucred, &p->p_acflag);
173356723Sshin	if (error != 0)
173456723Sshin	    return error;
173556723Sshin	if (securelevel > 0)
173656723Sshin	    return EPERM;
173756723Sshin	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
173856723Sshin	return 0;
173962587Sitojun
174056723Sshin    case KDDISABIO:     	/* disallow io operations (default) */
174156723Sshin	p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
174256723Sshin	return 0;
174356723Sshin
174456723Sshin    case KDSETMODE:     	/* set current mode of this (virtual) console */
174556723Sshin	switch (*data) {
174656723Sshin	case KD_TEXT:   	/* switch to TEXT (known) mode */
174756723Sshin	    /* restore fonts & palette ! */
174856723Sshin	    if (crtc_vga) {
174956723Sshin		if (fonts_loaded & FONT_8)
175056723Sshin		    copy_font(LOAD, FONT_8, font_8);
175156723Sshin		if (fonts_loaded & FONT_14)
175256723Sshin		    copy_font(LOAD, FONT_14, font_14);
175362587Sitojun		if (fonts_loaded & FONT_16)
175456723Sshin		    copy_font(LOAD, FONT_16, font_16);
175556723Sshin		load_palette(palette);
175656723Sshin	    }
175756723Sshin
175856723Sshin	    /* move hardware cursor out of the way */
175956723Sshin	    outb(crtc_addr, 14);
176056723Sshin	    outb(crtc_addr + 1, 0xff);
176156723Sshin	    outb(crtc_addr, 15);
176256723Sshin	    outb(crtc_addr + 1, 0xff);
176356723Sshin
176456723Sshin	    /* FALL THROUGH */
176556723Sshin
176656723Sshin	case KD_TEXT1:  	/* switch to TEXT (known) mode */
176762587Sitojun	    /* no restore fonts & palette */
176856723Sshin	    if (crtc_vga)
176956723Sshin		set_mode(scp);
177056723Sshin	    scp->status &= ~UNKNOWN_MODE;
177156723Sshin	    clear_screen(scp);
177256723Sshin	    return 0;
177356723Sshin
177456723Sshin	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
177556723Sshin	    scp->status |= UNKNOWN_MODE;
177656723Sshin	    return 0;
177756723Sshin	default:
177856723Sshin	    return EINVAL;
177956723Sshin	}
178056723Sshin	/* NOT REACHED */
178156723Sshin
178256723Sshin    case KDGETMODE:     	/* get current mode of this (virtual) console */
178356723Sshin	*data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
178462587Sitojun	return 0;
178562587Sitojun
178656723Sshin    case KDSBORDER:     	/* set border color of this (virtual) console */
178756723Sshin	scp->border = *data;
178856723Sshin	if (scp == cur_console)
178956723Sshin	    set_border(scp->border);
179056723Sshin	return 0;
179156723Sshin
179256723Sshin    case KDSKBSTATE:    	/* set keyboard state (locks) */
179356723Sshin	if (*data >= 0 && *data <= LOCK_KEY_MASK) {
179456723Sshin	    scp->status &= ~LOCK_KEY_MASK;
179556723Sshin	    scp->status |= *data;
179656723Sshin	    if (scp == cur_console)
179756723Sshin		update_leds(scp->status);
179856723Sshin	    return 0;
179956723Sshin	}
1800	return EINVAL;
1801
1802    case KDGKBSTATE:    	/* get keyboard state (locks) */
1803	*data = scp->status & LOCK_KEY_MASK;
1804	return 0;
1805
1806    case KDSETRAD:      	/* set keyboard repeat & delay rates */
1807	if (*data & 0x80)
1808	    return EINVAL;
1809	if (sc_kbdc != NULL)
1810	    set_keyboard(KBDC_SET_TYPEMATIC, *data);
1811	return 0;
1812
1813    case KDSKBMODE:     	/* set keyboard mode */
1814	switch (*data) {
1815	case K_RAW: 		/* switch to RAW scancode mode */
1816	    scp->status &= ~KBD_CODE_MODE;
1817	    scp->status |= KBD_RAW_MODE;
1818	    return 0;
1819
1820	case K_CODE: 		/* switch to CODE mode */
1821	    scp->status &= ~KBD_RAW_MODE;
1822	    scp->status |= KBD_CODE_MODE;
1823	    return 0;
1824
1825	case K_XLATE:   	/* switch to XLT ascii mode */
1826	    if (scp == cur_console && scp->status & KBD_RAW_MODE)
1827		shfts = ctls = alts = agrs = metas = accents = 0;
1828	    scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
1829	    return 0;
1830	default:
1831	    return EINVAL;
1832	}
1833	/* NOT REACHED */
1834
1835    case KDGKBMODE:     	/* get keyboard mode */
1836	*data = (scp->status & KBD_RAW_MODE) ? K_RAW :
1837		((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
1838	return 0;
1839
1840    case KDMKTONE:      	/* sound the bell */
1841	if (*(int*)data)
1842	    do_bell(scp, (*(int*)data)&0xffff,
1843		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1844	else
1845	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1846	return 0;
1847
1848    case KIOCSOUND:     	/* make tone (*data) hz */
1849	if (scp == cur_console) {
1850	    if (*(int*)data) {
1851		int pitch = timer_freq / *(int*)data;
1852
1853		/* set command for counter 2, 2 byte write */
1854		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1855		    return EBUSY;
1856
1857		/* set pitch */
1858		outb(TIMER_CNTR2, pitch);
1859		outb(TIMER_CNTR2, (pitch>>8));
1860
1861		/* enable counter 2 output to speaker */
1862		outb(IO_PPI, inb(IO_PPI) | 3);
1863	    }
1864	    else {
1865		/* disable counter 2 output to speaker */
1866		outb(IO_PPI, inb(IO_PPI) & 0xFC);
1867		release_timer2();
1868	    }
1869	}
1870	return 0;
1871
1872    case KDGKBTYPE:     	/* get keyboard type */
1873	*data = 0;  		/* type not known (yet) */
1874	return 0;
1875
1876    case KDSETLED:      	/* set keyboard LED status */
1877	if (*data >= 0 && *data <= LED_MASK) {
1878	    scp->status &= ~LED_MASK;
1879	    scp->status |= *data;
1880	    if (scp == cur_console)
1881		update_leds(scp->status);
1882	    return 0;
1883	}
1884	return EINVAL;
1885
1886    case KDGETLED:      	/* get keyboard LED status */
1887	*data = scp->status & LED_MASK;
1888	return 0;
1889
1890    case GETFKEY:       	/* get functionkey string */
1891	if (*(u_short*)data < n_fkey_tab) {
1892	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1893	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1894		  fkey_tab[ptr->keynum].len);
1895	    ptr->flen = fkey_tab[ptr->keynum].len;
1896	    return 0;
1897	}
1898	else
1899	    return EINVAL;
1900
1901    case SETFKEY:       	/* set functionkey string */
1902	if (*(u_short*)data < n_fkey_tab) {
1903	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1904	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1905		  min(ptr->flen, MAXFK));
1906	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1907	    return 0;
1908	}
1909	else
1910	    return EINVAL;
1911
1912    case GIO_SCRNMAP:   	/* get output translation table */
1913	bcopy(&scr_map, data, sizeof(scr_map));
1914	return 0;
1915
1916    case PIO_SCRNMAP:   	/* set output translation table */
1917	bcopy(data, &scr_map, sizeof(scr_map));
1918	for (i=0; i<sizeof(scr_map); i++)
1919	    scr_rmap[scr_map[i]] = i;
1920	return 0;
1921
1922    case GIO_KEYMAP:    	/* get keyboard translation table */
1923	bcopy(&key_map, data, sizeof(key_map));
1924	return 0;
1925
1926    case PIO_KEYMAP:    	/* set keyboard translation table */
1927	accents = 0;
1928	bzero(&accent_map, sizeof(accent_map));
1929	bcopy(data, &key_map, sizeof(key_map));
1930	return 0;
1931
1932    case GIO_DEADKEYMAP:    	/* get accent key translation table */
1933	bcopy(&accent_map, data, sizeof(accent_map));
1934	return 0;
1935
1936    case PIO_DEADKEYMAP:    	/* set accent key translation table */
1937	accents = 0;
1938	bcopy(data, &accent_map, sizeof(accent_map));
1939	return 0;
1940
1941    case PIO_FONT8x8:   	/* set 8x8 dot font */
1942	if (!crtc_vga)
1943	    return ENXIO;
1944	bcopy(data, font_8, 8*256);
1945	fonts_loaded |= FONT_8;
1946	if (!(cur_console->status & UNKNOWN_MODE)) {
1947	    copy_font(LOAD, FONT_8, font_8);
1948	    if (flags & CHAR_CURSOR)
1949	        set_destructive_cursor(cur_console);
1950	}
1951	return 0;
1952
1953    case GIO_FONT8x8:   	/* get 8x8 dot font */
1954	if (!crtc_vga)
1955	    return ENXIO;
1956	if (fonts_loaded & FONT_8) {
1957	    bcopy(font_8, data, 8*256);
1958	    return 0;
1959	}
1960	else
1961	    return ENXIO;
1962
1963    case PIO_FONT8x14:  	/* set 8x14 dot font */
1964	if (!crtc_vga)
1965	    return ENXIO;
1966	bcopy(data, font_14, 14*256);
1967	fonts_loaded |= FONT_14;
1968	if (!(cur_console->status & UNKNOWN_MODE)) {
1969	    copy_font(LOAD, FONT_14, font_14);
1970	    if (flags & CHAR_CURSOR)
1971	        set_destructive_cursor(cur_console);
1972	}
1973	return 0;
1974
1975    case GIO_FONT8x14:  	/* get 8x14 dot font */
1976	if (!crtc_vga)
1977	    return ENXIO;
1978	if (fonts_loaded & FONT_14) {
1979	    bcopy(font_14, data, 14*256);
1980	    return 0;
1981	}
1982	else
1983	    return ENXIO;
1984
1985    case PIO_FONT8x16:  	/* set 8x16 dot font */
1986	if (!crtc_vga)
1987	    return ENXIO;
1988	bcopy(data, font_16, 16*256);
1989	fonts_loaded |= FONT_16;
1990	if (!(cur_console->status & UNKNOWN_MODE)) {
1991	    copy_font(LOAD, FONT_16, font_16);
1992	    if (flags & CHAR_CURSOR)
1993	        set_destructive_cursor(cur_console);
1994	}
1995	return 0;
1996
1997    case GIO_FONT8x16:  	/* get 8x16 dot font */
1998	if (!crtc_vga)
1999	    return ENXIO;
2000	if (fonts_loaded & FONT_16) {
2001	    bcopy(font_16, data, 16*256);
2002	    return 0;
2003	}
2004	else
2005	    return ENXIO;
2006    default:
2007	break;
2008    }
2009
2010    error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2011    if (error != ENOIOCTL)
2012	return(error);
2013    error = ttioctl(tp, cmd, data, flag);
2014    if (error != ENOIOCTL)
2015	return(error);
2016    return(ENOTTY);
2017}
2018
2019static void
2020scstart(struct tty *tp)
2021{
2022    struct clist *rbp;
2023    int s, len;
2024    u_char buf[PCBURST];
2025    scr_stat *scp = get_scr_stat(tp->t_dev);
2026
2027    if (scp->status & SLKED || blink_in_progress)
2028	return; /* XXX who repeats the call when the above flags are cleared? */
2029    s = spltty();
2030    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2031	tp->t_state |= TS_BUSY;
2032	rbp = &tp->t_outq;
2033	while (rbp->c_cc) {
2034	    len = q_to_b(rbp, buf, PCBURST);
2035	    splx(s);
2036	    ansi_put(scp, buf, len);
2037	    s = spltty();
2038	}
2039	tp->t_state &= ~TS_BUSY;
2040	ttwwakeup(tp);
2041    }
2042    splx(s);
2043}
2044
2045static void
2046scmousestart(struct tty *tp)
2047{
2048    struct clist *rbp;
2049    int s;
2050    u_char buf[PCBURST];
2051
2052    s = spltty();
2053    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2054	tp->t_state |= TS_BUSY;
2055	rbp = &tp->t_outq;
2056	while (rbp->c_cc) {
2057	    q_to_b(rbp, buf, PCBURST);
2058	}
2059	tp->t_state &= ~TS_BUSY;
2060	ttwwakeup(tp);
2061    }
2062    splx(s);
2063}
2064
2065void
2066sccnprobe(struct consdev *cp)
2067{
2068    struct isa_device *dvp;
2069
2070    /*
2071     * Take control if we are the highest priority enabled display device.
2072     */
2073    dvp = find_display();
2074    if (dvp == NULL || dvp->id_driver != &scdriver) {
2075	cp->cn_pri = CN_DEAD;
2076	return;
2077    }
2078
2079    if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
2080	cp->cn_pri = CN_DEAD;
2081	return;
2082    }
2083
2084    /* initialize required fields */
2085    cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
2086    cp->cn_pri = CN_INTERNAL;
2087
2088    sc_kbdc = kbdc_open(sc_port);
2089}
2090
2091void
2092sccninit(struct consdev *cp)
2093{
2094    scinit();
2095}
2096
2097void
2098sccnputc(dev_t dev, int c)
2099{
2100    u_char buf[1];
2101    int s;
2102    scr_stat *scp = console[0];
2103    term_stat save = scp->term;
2104
2105    scp->term = kernel_console;
2106    current_default = &kernel_default;
2107    if (scp == cur_console && !(scp->status & UNKNOWN_MODE))
2108	remove_cursor_image(scp);
2109    buf[0] = c;
2110    ansi_put(scp, buf, 1);
2111    kernel_console = scp->term;
2112    current_default = &user_default;
2113    scp->term = save;
2114    s = splclock();
2115    if (scp == cur_console && !(scp->status & UNKNOWN_MODE)) {
2116	if (/* timer not running && */ (scp->start <= scp->end)) {
2117	    sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start,
2118		   (1 + scp->end - scp->start) * sizeof(u_short));
2119	    scp->start = scp->xsize * scp->ysize;
2120	    scp->end = 0;
2121	}
2122    	scp->cursor_oldpos = scp->cursor_pos;
2123	draw_cursor_image(scp);
2124    }
2125    splx(s);
2126}
2127
2128int
2129sccngetc(dev_t dev)
2130{
2131    int s = spltty();	/* block scintr and scrn_timer while we poll */
2132    int c;
2133
2134    /*
2135     * Stop the screen saver if necessary.
2136     * What if we have been running in the screen saver code... XXX
2137     */
2138    if (scrn_blanked > 0)
2139        stop_scrn_saver(current_saver);
2140
2141    c = scgetc(SCGETC_CN);
2142
2143    /* make sure the screen saver won't be activated soon */
2144    scrn_time_stamp = mono_time.tv_sec;
2145    splx(s);
2146    return(c);
2147}
2148
2149int
2150sccncheckc(dev_t dev)
2151{
2152    int c, s;
2153
2154    s = spltty();
2155    if (scrn_blanked > 0)
2156        stop_scrn_saver(current_saver);
2157    c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
2158    if (c != NOKEY)
2159        scrn_time_stamp = mono_time.tv_sec;
2160    splx(s);
2161    return(c == NOKEY ? -1 : c);	/* c == -1 can't happen */
2162}
2163
2164static scr_stat
2165*get_scr_stat(dev_t dev)
2166{
2167    int unit = minor(dev);
2168
2169    if (unit == SC_CONSOLE)
2170	return console[0];
2171    if (unit >= MAXCONS || unit < 0)
2172	return(NULL);
2173    return console[unit];
2174}
2175
2176static int
2177get_scr_num()
2178{
2179    int i = 0;
2180
2181    while ((i < MAXCONS) && (cur_console != console[i]))
2182	i++;
2183    return i < MAXCONS ? i : 0;
2184}
2185
2186static void
2187scrn_timer(void *arg)
2188{
2189    scr_stat *scp = cur_console;
2190    int s = spltty();
2191
2192    /*
2193     * With release 2.1 of the Xaccel server, the keyboard is left
2194     * hanging pretty often. Apparently an interrupt from the
2195     * keyboard is lost, and I don't know why (yet).
2196     * This ugly hack calls scintr if input is ready for the keyboard
2197     * and conveniently hides the problem.			XXX
2198     */
2199    /* Try removing anything stuck in the keyboard controller; whether
2200     * it's a keyboard scan code or mouse data. `scintr()' doesn't
2201     * read the mouse data directly, but `kbdio' routines will, as a
2202     * side effect.
2203     */
2204    if (kbdc_lock(sc_kbdc, TRUE)) {
2205	/*
2206	 * We have seen the lock flag is not set. Let's reset the flag early;
2207	 * otherwise `update_led()' failes which may want the lock
2208	 * during `scintr()'.
2209	 */
2210	kbdc_lock(sc_kbdc, FALSE);
2211	if (kbdc_data_ready(sc_kbdc))
2212	    scintr(0);
2213    }
2214
2215    /* should we just return ? */
2216    if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
2217	timeout(scrn_timer, NULL, hz / 10);
2218	splx(s);
2219	return;
2220    }
2221
2222    /* should we stop the screen saver? */
2223    if (mono_time.tv_sec <= scrn_time_stamp + scrn_blank_time)
2224	if (scrn_blanked > 0)
2225            stop_scrn_saver(current_saver);
2226
2227    if (scrn_blanked <= 0) {
2228	/* update screen image */
2229	if (scp->start <= scp->end) {
2230	    sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start,
2231		   (1 + scp->end - scp->start) * sizeof(u_short));
2232	}
2233
2234	/* update "pseudo" mouse pointer image */
2235	if ((scp->status & MOUSE_VISIBLE) && crtc_vga) {
2236	    /* did mouse move since last time ? */
2237	    if (scp->status & MOUSE_MOVED) {
2238		/* do we need to remove old mouse pointer image ? */
2239		if (scp->mouse_cut_start != NULL ||
2240		    (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2241		    (scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->end) {
2242		    remove_mouse_image(scp);
2243		}
2244		scp->status &= ~MOUSE_MOVED;
2245		draw_mouse_image(scp);
2246	    }
2247	    else {
2248		/* mouse didn't move, has it been overwritten ? */
2249		if ((scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->start &&
2250		    (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2251		    draw_mouse_image(scp);
2252		}
2253	    }
2254	}
2255
2256	/* update cursor image */
2257	if (scp->status & CURSOR_ENABLED) {
2258	    /* did cursor move since last time ? */
2259	    if (scp->cursor_pos != scp->cursor_oldpos) {
2260		/* do we need to remove old cursor image ? */
2261		if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2262		    ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2263		    remove_cursor_image(scp);
2264		}
2265    		scp->cursor_oldpos = scp->cursor_pos;
2266		draw_cursor_image(scp);
2267	    }
2268	    else {
2269		/* cursor didn't move, has it been overwritten ? */
2270		if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2271		    scp->cursor_pos - scp->scr_buf <= scp->end) {
2272		    	draw_cursor_image(scp);
2273		} else {
2274		    /* if its a blinking cursor, we may have to update it */
2275		    if (flags & BLINK_CURSOR)
2276			draw_cursor_image(scp);
2277		}
2278	    }
2279	    blinkrate++;
2280	}
2281
2282	if (scp->mouse_cut_start != NULL)
2283	    draw_cutmarking(scp);
2284
2285	scp->end = 0;
2286	scp->start = scp->xsize*scp->ysize;
2287    }
2288
2289    /* should we activate the screen saver? */
2290    if ((scrn_blank_time != 0)
2291	    && (mono_time.tv_sec > scrn_time_stamp + scrn_blank_time))
2292	(*current_saver)(TRUE);
2293
2294    timeout(scrn_timer, NULL, hz / 25);
2295    splx(s);
2296}
2297
2298int
2299add_scrn_saver(void (*this_saver)(int))
2300{
2301    if (current_saver != none_saver)
2302	return EBUSY;
2303    current_saver = this_saver;
2304    return 0;
2305}
2306
2307int
2308remove_scrn_saver(void (*this_saver)(int))
2309{
2310    if (current_saver != this_saver)
2311	return EINVAL;
2312
2313    /*
2314     * In order to prevent `current_saver' from being called by
2315     * the timeout routine `scrn_timer()' while we manipulate
2316     * the saver list, we shall set `current_saver' to `none_saver'
2317     * before stopping the current saver, rather than blocking by `splXX()'.
2318     */
2319    current_saver = none_saver;
2320    if (scrn_blanked > 0)
2321        stop_scrn_saver(this_saver);
2322
2323    return 0;
2324}
2325
2326static void
2327stop_scrn_saver(void (*saver)(int))
2328{
2329    (*saver)(FALSE);
2330    scrn_time_stamp = mono_time.tv_sec;
2331    mark_all(cur_console);
2332}
2333
2334static void
2335clear_screen(scr_stat *scp)
2336{
2337    move_crsr(scp, 0, 0);
2338    scp->cursor_oldpos = scp->cursor_pos;
2339    fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2340	  scp->xsize * scp->ysize);
2341    mark_all(scp);
2342    remove_cutmarking(scp);
2343}
2344
2345static int
2346switch_scr(scr_stat *scp, u_int next_scr)
2347{
2348    if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2349	switch_in_progress = FALSE;
2350
2351    if (next_scr >= MAXCONS || switch_in_progress ||
2352	(cur_console->smode.mode == VT_AUTO
2353	 && cur_console->status & UNKNOWN_MODE)) {
2354	do_bell(scp, BELL_PITCH, BELL_DURATION);
2355	return EINVAL;
2356    }
2357
2358    /* is the wanted virtual console open ? */
2359    if (next_scr) {
2360	struct tty *tp = VIRTUAL_TTY(next_scr);
2361	if (!(tp->t_state & TS_ISOPEN)) {
2362	    do_bell(scp, BELL_PITCH, BELL_DURATION);
2363	    return EINVAL;
2364	}
2365    }
2366    /* delay switch if actively updating screen */
2367    if (write_in_progress || blink_in_progress) {
2368	delayed_next_scr = next_scr+1;
2369	return 0;
2370    }
2371    switch_in_progress = TRUE;
2372    old_scp = cur_console;
2373    new_scp = console[next_scr];
2374    wakeup((caddr_t)&new_scp->smode);
2375    if (new_scp == old_scp) {
2376	switch_in_progress = FALSE;
2377	delayed_next_scr = FALSE;
2378	return 0;
2379    }
2380
2381    /* has controlling process died? */
2382    if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2383	old_scp->smode.mode = VT_AUTO;
2384    if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2385	new_scp->smode.mode = VT_AUTO;
2386
2387    /* check the modes and switch appropriately */
2388    if (old_scp->smode.mode == VT_PROCESS) {
2389	old_scp->status |= SWITCH_WAIT_REL;
2390	psignal(old_scp->proc, old_scp->smode.relsig);
2391    }
2392    else {
2393	exchange_scr();
2394	if (new_scp->smode.mode == VT_PROCESS) {
2395	    new_scp->status |= SWITCH_WAIT_ACQ;
2396	    psignal(new_scp->proc, new_scp->smode.acqsig);
2397	}
2398	else
2399	    switch_in_progress = FALSE;
2400    }
2401    return 0;
2402}
2403
2404static void
2405exchange_scr(void)
2406{
2407    move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2408    cur_console = new_scp;
2409    if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
2410	if (crtc_vga)
2411	    set_mode(new_scp);
2412    }
2413    move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2414    if (!(new_scp->status & UNKNOWN_MODE) && (flags & CHAR_CURSOR))
2415	set_destructive_cursor(new_scp);
2416    if ((old_scp->status & UNKNOWN_MODE) && crtc_vga)
2417	load_palette(palette);
2418    if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2419        old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2420	shfts = ctls = alts = agrs = metas = accents = 0;
2421    set_border(new_scp->border);
2422    update_leds(new_scp->status);
2423    delayed_next_scr = FALSE;
2424    mark_all(new_scp);
2425}
2426
2427static void
2428scan_esc(scr_stat *scp, u_char c)
2429{
2430    static u_char ansi_col[16] =
2431	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2432    int i, n;
2433    u_short *src, *dst, count;
2434
2435    if (scp->term.esc == 1) {	/* seen ESC */
2436	switch (c) {
2437
2438	case '7':   /* Save cursor position */
2439	    scp->saved_xpos = scp->xpos;
2440	    scp->saved_ypos = scp->ypos;
2441	    break;
2442
2443	case '8':   /* Restore saved cursor position */
2444	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2445		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2446	    break;
2447
2448	case '[':   /* Start ESC [ sequence */
2449	    scp->term.esc = 2;
2450	    scp->term.last_param = -1;
2451	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2452		scp->term.param[i] = 1;
2453	    scp->term.num_param = 0;
2454	    return;
2455
2456	case 'M':   /* Move cursor up 1 line, scroll if at top */
2457	    if (scp->ypos > 0)
2458		move_crsr(scp, scp->xpos, scp->ypos - 1);
2459	    else {
2460		bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2461		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2462		fillw(scp->term.cur_color | scr_map[0x20],
2463		      scp->scr_buf, scp->xsize);
2464    		mark_all(scp);
2465	    }
2466	    break;
2467#if notyet
2468	case 'Q':
2469	    scp->term.esc = 4;
2470	    return;
2471#endif
2472	case 'c':   /* Clear screen & home */
2473	    clear_screen(scp);
2474	    break;
2475
2476	case '(':   /* iso-2022: designate 94 character set to G0 */
2477	    scp->term.esc = 5;
2478	    return;
2479	}
2480    }
2481    else if (scp->term.esc == 2) {	/* seen ESC [ */
2482	if (c >= '0' && c <= '9') {
2483	    if (scp->term.num_param < MAX_ESC_PAR) {
2484	    if (scp->term.last_param != scp->term.num_param) {
2485		scp->term.last_param = scp->term.num_param;
2486		scp->term.param[scp->term.num_param] = 0;
2487	    }
2488	    else
2489		scp->term.param[scp->term.num_param] *= 10;
2490	    scp->term.param[scp->term.num_param] += c - '0';
2491	    return;
2492	    }
2493	}
2494	scp->term.num_param = scp->term.last_param + 1;
2495	switch (c) {
2496
2497	case ';':
2498	    if (scp->term.num_param < MAX_ESC_PAR)
2499		return;
2500	    break;
2501
2502	case '=':
2503	    scp->term.esc = 3;
2504	    scp->term.last_param = -1;
2505	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2506		scp->term.param[i] = 1;
2507	    scp->term.num_param = 0;
2508	    return;
2509
2510	case 'A':   /* up n rows */
2511	    n = scp->term.param[0]; if (n < 1) n = 1;
2512	    move_crsr(scp, scp->xpos, scp->ypos - n);
2513	    break;
2514
2515	case 'B':   /* down n rows */
2516	    n = scp->term.param[0]; if (n < 1) n = 1;
2517	    move_crsr(scp, scp->xpos, scp->ypos + n);
2518	    break;
2519
2520	case 'C':   /* right n columns */
2521	    n = scp->term.param[0]; if (n < 1) n = 1;
2522	    move_crsr(scp, scp->xpos + n, scp->ypos);
2523	    break;
2524
2525	case 'D':   /* left n columns */
2526	    n = scp->term.param[0]; if (n < 1) n = 1;
2527	    move_crsr(scp, scp->xpos - n, scp->ypos);
2528	    break;
2529
2530	case 'E':   /* cursor to start of line n lines down */
2531	    n = scp->term.param[0]; if (n < 1) n = 1;
2532	    move_crsr(scp, 0, scp->ypos + n);
2533	    break;
2534
2535	case 'F':   /* cursor to start of line n lines up */
2536	    n = scp->term.param[0]; if (n < 1) n = 1;
2537	    move_crsr(scp, 0, scp->ypos - n);
2538	    break;
2539
2540	case 'f':   /* Cursor move */
2541	case 'H':
2542	    if (scp->term.num_param == 0)
2543		move_crsr(scp, 0, 0);
2544	    else if (scp->term.num_param == 2)
2545		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2546	    break;
2547
2548	case 'J':   /* Clear all or part of display */
2549	    if (scp->term.num_param == 0)
2550		n = 0;
2551	    else
2552		n = scp->term.param[0];
2553	    switch (n) {
2554	    case 0: /* clear form cursor to end of display */
2555		fillw(scp->term.cur_color | scr_map[0x20],
2556		      scp->cursor_pos,
2557		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2558    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2559    		mark_for_update(scp, scp->xsize * scp->ysize);
2560		remove_cutmarking(scp);
2561		break;
2562	    case 1: /* clear from beginning of display to cursor */
2563		fillw(scp->term.cur_color | scr_map[0x20],
2564		      scp->scr_buf,
2565		      scp->cursor_pos - scp->scr_buf);
2566    		mark_for_update(scp, 0);
2567    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2568		remove_cutmarking(scp);
2569		break;
2570	    case 2: /* clear entire display */
2571		fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2572		      scp->xsize * scp->ysize);
2573		mark_all(scp);
2574		remove_cutmarking(scp);
2575		break;
2576	    }
2577	    break;
2578
2579	case 'K':   /* Clear all or part of line */
2580	    if (scp->term.num_param == 0)
2581		n = 0;
2582	    else
2583		n = scp->term.param[0];
2584	    switch (n) {
2585	    case 0: /* clear form cursor to end of line */
2586		fillw(scp->term.cur_color | scr_map[0x20],
2587		      scp->cursor_pos,
2588		      scp->xsize - scp->xpos);
2589    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2590    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2591				scp->xsize - scp->xpos);
2592		break;
2593	    case 1: /* clear from beginning of line to cursor */
2594		fillw(scp->term.cur_color | scr_map[0x20],
2595		      scp->cursor_pos - scp->xpos,
2596		      scp->xpos + 1);
2597    		mark_for_update(scp, scp->ypos * scp->xsize);
2598    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2599		break;
2600	    case 2: /* clear entire line */
2601		fillw(scp->term.cur_color | scr_map[0x20],
2602		      scp->cursor_pos - scp->xpos,
2603		      scp->xsize);
2604    		mark_for_update(scp, scp->ypos * scp->xsize);
2605    		mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
2606		break;
2607	    }
2608	    break;
2609
2610	case 'L':   /* Insert n lines */
2611	    n = scp->term.param[0]; if (n < 1) n = 1;
2612	    if (n > scp->ysize - scp->ypos)
2613		n = scp->ysize - scp->ypos;
2614	    src = scp->scr_buf + scp->ypos * scp->xsize;
2615	    dst = src + n * scp->xsize;
2616	    count = scp->ysize - (scp->ypos + n);
2617	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2618	    fillw(scp->term.cur_color | scr_map[0x20], src,
2619		  n * scp->xsize);
2620	    mark_for_update(scp, scp->ypos * scp->xsize);
2621	    mark_for_update(scp, scp->xsize * scp->ysize);
2622	    break;
2623
2624	case 'M':   /* Delete n lines */
2625	    n = scp->term.param[0]; if (n < 1) n = 1;
2626	    if (n > scp->ysize - scp->ypos)
2627		n = scp->ysize - scp->ypos;
2628	    dst = scp->scr_buf + scp->ypos * scp->xsize;
2629	    src = dst + n * scp->xsize;
2630	    count = scp->ysize - (scp->ypos + n);
2631	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2632	    src = dst + count * scp->xsize;
2633	    fillw(scp->term.cur_color | scr_map[0x20], src,
2634		  n * scp->xsize);
2635	    mark_for_update(scp, scp->ypos * scp->xsize);
2636	    mark_for_update(scp, scp->xsize * scp->ysize);
2637	    break;
2638
2639	case 'P':   /* Delete n chars */
2640	    n = scp->term.param[0]; if (n < 1) n = 1;
2641	    if (n > scp->xsize - scp->xpos)
2642		n = scp->xsize - scp->xpos;
2643	    dst = scp->cursor_pos;
2644	    src = dst + n;
2645	    count = scp->xsize - (scp->xpos + n);
2646	    bcopy(src, dst, count * sizeof(u_short));
2647	    src = dst + count;
2648	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2649	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2650	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2651	    break;
2652
2653	case '@':   /* Insert n chars */
2654	    n = scp->term.param[0]; if (n < 1) n = 1;
2655	    if (n > scp->xsize - scp->xpos)
2656		n = scp->xsize - scp->xpos;
2657	    src = scp->cursor_pos;
2658	    dst = src + n;
2659	    count = scp->xsize - (scp->xpos + n);
2660	    bcopy(src, dst, count * sizeof(u_short));
2661	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2662	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2663	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2664	    break;
2665
2666	case 'S':   /* scroll up n lines */
2667	    n = scp->term.param[0]; if (n < 1)  n = 1;
2668	    if (n > scp->ysize)
2669		n = scp->ysize;
2670	    bcopy(scp->scr_buf + (scp->xsize * n),
2671		   scp->scr_buf,
2672		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
2673	    fillw(scp->term.cur_color | scr_map[0x20],
2674		  scp->scr_buf + scp->xsize * (scp->ysize - n),
2675		  scp->xsize * n);
2676    	    mark_all(scp);
2677	    break;
2678
2679	case 'T':   /* scroll down n lines */
2680	    n = scp->term.param[0]; if (n < 1)  n = 1;
2681	    if (n > scp->ysize)
2682		n = scp->ysize;
2683	    bcopy(scp->scr_buf,
2684		  scp->scr_buf + (scp->xsize * n),
2685		  scp->xsize * (scp->ysize - n) *
2686		  sizeof(u_short));
2687	    fillw(scp->term.cur_color | scr_map[0x20],
2688		  scp->scr_buf, scp->xsize * n);
2689    	    mark_all(scp);
2690	    break;
2691
2692	case 'X':   /* erase n characters in line */
2693	    n = scp->term.param[0]; if (n < 1)  n = 1;
2694	    if (n > scp->xsize - scp->xpos)
2695		n = scp->xsize - scp->xpos;
2696	    fillw(scp->term.cur_color | scr_map[0x20],
2697		  scp->cursor_pos, n);
2698	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2699	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
2700	    break;
2701
2702	case 'Z':   /* move n tabs backwards */
2703	    n = scp->term.param[0]; if (n < 1)  n = 1;
2704	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2705		i -= 8*n;
2706	    else
2707		i -= 8*(n-1);
2708	    if (i < 0)
2709		i = 0;
2710	    move_crsr(scp, i, scp->ypos);
2711	    break;
2712
2713	case '`':   /* move cursor to column n */
2714	    n = scp->term.param[0]; if (n < 1)  n = 1;
2715	    move_crsr(scp, n - 1, scp->ypos);
2716	    break;
2717
2718	case 'a':   /* move cursor n columns to the right */
2719	    n = scp->term.param[0]; if (n < 1)  n = 1;
2720	    move_crsr(scp, scp->xpos + n, scp->ypos);
2721	    break;
2722
2723	case 'd':   /* move cursor to row n */
2724	    n = scp->term.param[0]; if (n < 1)  n = 1;
2725	    move_crsr(scp, scp->xpos, n - 1);
2726	    break;
2727
2728	case 'e':   /* move cursor n rows down */
2729	    n = scp->term.param[0]; if (n < 1)  n = 1;
2730	    move_crsr(scp, scp->xpos, scp->ypos + n);
2731	    break;
2732
2733	case 'm':   /* change attribute */
2734	    if (scp->term.num_param == 0) {
2735		scp->term.attr_mask = NORMAL_ATTR;
2736		scp->term.cur_attr =
2737		    scp->term.cur_color = scp->term.std_color;
2738		break;
2739	    }
2740	    for (i = 0; i < scp->term.num_param; i++) {
2741		switch (n = scp->term.param[i]) {
2742		case 0: /* back to normal */
2743		    scp->term.attr_mask = NORMAL_ATTR;
2744		    scp->term.cur_attr =
2745			scp->term.cur_color = scp->term.std_color;
2746		    break;
2747		case 1: /* bold */
2748		    scp->term.attr_mask |= BOLD_ATTR;
2749		    scp->term.cur_attr = mask2attr(&scp->term);
2750		    break;
2751		case 4: /* underline */
2752		    scp->term.attr_mask |= UNDERLINE_ATTR;
2753		    scp->term.cur_attr = mask2attr(&scp->term);
2754		    break;
2755		case 5: /* blink */
2756		    scp->term.attr_mask |= BLINK_ATTR;
2757		    scp->term.cur_attr = mask2attr(&scp->term);
2758		    break;
2759		case 7: /* reverse video */
2760		    scp->term.attr_mask |= REVERSE_ATTR;
2761		    scp->term.cur_attr = mask2attr(&scp->term);
2762		    break;
2763		case 30: case 31: /* set fg color */
2764		case 32: case 33: case 34:
2765		case 35: case 36: case 37:
2766		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2767		    scp->term.cur_color =
2768			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2769		    scp->term.cur_attr = mask2attr(&scp->term);
2770		    break;
2771		case 40: case 41: /* set bg color */
2772		case 42: case 43: case 44:
2773		case 45: case 46: case 47:
2774		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2775		    scp->term.cur_color =
2776			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2777		    scp->term.cur_attr = mask2attr(&scp->term);
2778		    break;
2779		}
2780	    }
2781	    break;
2782
2783	case 's':   /* Save cursor position */
2784	    scp->saved_xpos = scp->xpos;
2785	    scp->saved_ypos = scp->ypos;
2786	    break;
2787
2788	case 'u':   /* Restore saved cursor position */
2789	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2790		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2791	    break;
2792
2793	case 'x':
2794	    if (scp->term.num_param == 0)
2795		n = 0;
2796	    else
2797		n = scp->term.param[0];
2798	    switch (n) {
2799	    case 0:     /* reset attributes */
2800		scp->term.attr_mask = NORMAL_ATTR;
2801		scp->term.cur_attr =
2802		    scp->term.cur_color = scp->term.std_color =
2803		    current_default->std_color;
2804		scp->term.rev_color = current_default->rev_color;
2805		break;
2806	    case 1:     /* set ansi background */
2807		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2808		scp->term.cur_color = scp->term.std_color =
2809		    (scp->term.std_color & 0x0F00) |
2810		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2811		scp->term.cur_attr = mask2attr(&scp->term);
2812		break;
2813	    case 2:     /* set ansi foreground */
2814		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2815		scp->term.cur_color = scp->term.std_color =
2816		    (scp->term.std_color & 0xF000) |
2817		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2818		scp->term.cur_attr = mask2attr(&scp->term);
2819		break;
2820	    case 3:     /* set ansi attribute directly */
2821		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2822		scp->term.cur_color = scp->term.std_color =
2823		    (scp->term.param[1]&0xFF)<<8;
2824		scp->term.cur_attr = mask2attr(&scp->term);
2825		break;
2826	    case 5:     /* set ansi reverse video background */
2827		scp->term.rev_color =
2828		    (scp->term.rev_color & 0x0F00) |
2829		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2830		scp->term.cur_attr = mask2attr(&scp->term);
2831		break;
2832	    case 6:     /* set ansi reverse video foreground */
2833		scp->term.rev_color =
2834		    (scp->term.rev_color & 0xF000) |
2835		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2836		scp->term.cur_attr = mask2attr(&scp->term);
2837		break;
2838	    case 7:     /* set ansi reverse video directly */
2839		scp->term.rev_color =
2840		    (scp->term.param[1]&0xFF)<<8;
2841		scp->term.cur_attr = mask2attr(&scp->term);
2842		break;
2843	    }
2844	    break;
2845
2846	case 'z':   /* switch to (virtual) console n */
2847	    if (scp->term.num_param == 1)
2848		switch_scr(scp, scp->term.param[0]);
2849	    break;
2850	}
2851    }
2852    else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2853	if (c >= '0' && c <= '9') {
2854	    if (scp->term.num_param < MAX_ESC_PAR) {
2855	    if (scp->term.last_param != scp->term.num_param) {
2856		scp->term.last_param = scp->term.num_param;
2857		scp->term.param[scp->term.num_param] = 0;
2858	    }
2859	    else
2860		scp->term.param[scp->term.num_param] *= 10;
2861	    scp->term.param[scp->term.num_param] += c - '0';
2862	    return;
2863	    }
2864	}
2865	scp->term.num_param = scp->term.last_param + 1;
2866	switch (c) {
2867
2868	case ';':
2869	    if (scp->term.num_param < MAX_ESC_PAR)
2870		return;
2871	    break;
2872
2873	case 'A':   /* set display border color */
2874	    if (scp->term.num_param == 1) {
2875		scp->border=scp->term.param[0] & 0xff;
2876		if (scp == cur_console)
2877		    set_border(scp->border);
2878            }
2879	    break;
2880
2881	case 'B':   /* set bell pitch and duration */
2882	    if (scp->term.num_param == 2) {
2883		scp->bell_pitch = scp->term.param[0];
2884		scp->bell_duration = scp->term.param[1]*10;
2885	    }
2886	    break;
2887
2888	case 'C':   /* set cursor type & shape */
2889	    if (scp->term.num_param == 1) {
2890		if (scp->term.param[0] & 0x01)
2891		    flags |= BLINK_CURSOR;
2892		else
2893		    flags &= ~BLINK_CURSOR;
2894		if ((scp->term.param[0] & 0x02) && crtc_vga)
2895		    flags |= CHAR_CURSOR;
2896		else
2897		    flags &= ~CHAR_CURSOR;
2898	    }
2899	    else if (scp->term.num_param == 2) {
2900		scp->cursor_start = scp->term.param[0] & 0x1F;
2901		scp->cursor_end = scp->term.param[1] & 0x1F;
2902	    }
2903	    /*
2904	     * The cursor shape is global property; all virtual consoles
2905	     * are affected. Update the cursor in the current console...
2906	     */
2907	    if (!(cur_console->status & UNKNOWN_MODE)) {
2908		remove_cursor_image(cur_console);
2909		if (crtc_vga && (flags & CHAR_CURSOR))
2910	            set_destructive_cursor(cur_console);
2911		draw_cursor_image(cur_console);
2912	    }
2913	    break;
2914
2915	case 'F':   /* set ansi foreground */
2916	    if (scp->term.num_param == 1) {
2917		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2918		scp->term.cur_color = scp->term.std_color =
2919		    (scp->term.std_color & 0xF000)
2920		    | ((scp->term.param[0] & 0x0F) << 8);
2921		scp->term.cur_attr = mask2attr(&scp->term);
2922	    }
2923	    break;
2924
2925	case 'G':   /* set ansi background */
2926	    if (scp->term.num_param == 1) {
2927		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2928		scp->term.cur_color = scp->term.std_color =
2929		    (scp->term.std_color & 0x0F00)
2930		    | ((scp->term.param[0] & 0x0F) << 12);
2931		scp->term.cur_attr = mask2attr(&scp->term);
2932	    }
2933	    break;
2934
2935	case 'H':   /* set ansi reverse video foreground */
2936	    if (scp->term.num_param == 1) {
2937		scp->term.rev_color =
2938		    (scp->term.rev_color & 0xF000)
2939		    | ((scp->term.param[0] & 0x0F) << 8);
2940		scp->term.cur_attr = mask2attr(&scp->term);
2941	    }
2942	    break;
2943
2944	case 'I':   /* set ansi reverse video background */
2945	    if (scp->term.num_param == 1) {
2946		scp->term.rev_color =
2947		    (scp->term.rev_color & 0x0F00)
2948		    | ((scp->term.param[0] & 0x0F) << 12);
2949		scp->term.cur_attr = mask2attr(&scp->term);
2950	    }
2951	    break;
2952	}
2953    }
2954#if notyet
2955    else if (scp->term.esc == 4) {	/* seen ESC Q */
2956	/* to be filled */
2957    }
2958#endif
2959    else if (scp->term.esc == 5) {	/* seen ESC ( */
2960	switch (c) {
2961	case 'B':   /* iso-2022: desginate ASCII into G0 */
2962	    break;
2963	/* other items to be filled */
2964	default:
2965	    break;
2966	}
2967    }
2968    scp->term.esc = 0;
2969}
2970
2971static void
2972ansi_put(scr_stat *scp, u_char *buf, int len)
2973{
2974    u_char *ptr = buf;
2975
2976    /* make screensaver happy */
2977    if (scp == cur_console)
2978	scrn_time_stamp = mono_time.tv_sec;
2979
2980    write_in_progress++;
2981outloop:
2982    if (scp->term.esc) {
2983	scan_esc(scp, *ptr++);
2984	len--;
2985    }
2986    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2987 	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
2988 	u_short cur_attr = scp->term.cur_attr;
2989 	u_short *cursor_pos = scp->cursor_pos;
2990	do {
2991	    /*
2992	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2993	     * pointers in the following to volatile should have no effect,
2994	     * but in fact speeds up this inner loop from 26 to 18 cycles
2995	     * (+ cache misses) on i486's.
2996	     */
2997#define	UCVP(ucp)	((u_char volatile *)(ucp))
2998	    *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
2999	    ptr++;
3000	    cnt--;
3001	} while (cnt && PRINTABLE(*ptr));
3002	len -= (cursor_pos - scp->cursor_pos);
3003	scp->xpos += (cursor_pos - scp->cursor_pos);
3004	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3005	mark_for_update(scp, cursor_pos - scp->scr_buf);
3006	scp->cursor_pos = cursor_pos;
3007	if (scp->xpos >= scp->xsize) {
3008	    scp->xpos = 0;
3009	    scp->ypos++;
3010	}
3011    }
3012    else  {
3013	switch(*ptr) {
3014	case 0x07:
3015	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
3016	    break;
3017
3018	case 0x08:      /* non-destructive backspace */
3019	    if (scp->cursor_pos > scp->scr_buf) {
3020	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3021		scp->cursor_pos--;
3022	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3023		if (scp->xpos > 0)
3024		    scp->xpos--;
3025		else {
3026		    scp->xpos += scp->xsize - 1;
3027		    scp->ypos--;
3028		}
3029	    }
3030	    break;
3031
3032	case 0x09:  /* non-destructive tab */
3033	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3034	    scp->cursor_pos += (8 - scp->xpos % 8u);
3035	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3036	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
3037	        scp->xpos = 0;
3038	        scp->ypos++;
3039	    }
3040	    break;
3041
3042	case 0x0a:  /* newline, same pos */
3043	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3044	    scp->cursor_pos += scp->xsize;
3045	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3046	    scp->ypos++;
3047	    break;
3048
3049	case 0x0c:  /* form feed, clears screen */
3050	    clear_screen(scp);
3051	    break;
3052
3053	case 0x0d:  /* return, return to pos 0 */
3054	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3055	    scp->cursor_pos -= scp->xpos;
3056	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3057	    scp->xpos = 0;
3058	    break;
3059
3060	case 0x1b:  /* start escape sequence */
3061	    scp->term.esc = 1;
3062	    scp->term.num_param = 0;
3063	    break;
3064	}
3065	ptr++; len--;
3066    }
3067    /* do we have to scroll ?? */
3068    if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
3069	remove_cutmarking(scp);
3070	if (scp->history) {
3071	    bcopy(scp->scr_buf, scp->history_head,
3072		   scp->xsize * sizeof(u_short));
3073	    scp->history_head += scp->xsize;
3074	    if (scp->history_head + scp->xsize >
3075		scp->history + scp->history_size)
3076		scp->history_head = scp->history;
3077	}
3078	bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
3079	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
3080	fillw(scp->term.cur_color | scr_map[0x20],
3081	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
3082	      scp->xsize);
3083	scp->cursor_pos -= scp->xsize;
3084	scp->ypos--;
3085    	mark_all(scp);
3086    }
3087    if (len)
3088	goto outloop;
3089    write_in_progress--;
3090    if (delayed_next_scr)
3091	switch_scr(scp, delayed_next_scr - 1);
3092}
3093
3094static void
3095scinit(void)
3096{
3097    u_int hw_cursor;
3098    u_int i;
3099
3100    if (init_done != COLD)
3101	return;
3102    init_done = WARM;
3103
3104    /*
3105     * Ensure a zero start address.  This is mainly to recover after
3106     * switching from pcvt using userconfig().  The registers are w/o
3107     * for old hardware so it's too hard to relocate the active screen
3108     * memory.
3109     */
3110    outb(crtc_addr, 12);
3111    outb(crtc_addr + 1, 0);
3112    outb(crtc_addr, 13);
3113    outb(crtc_addr + 1, 0);
3114
3115    /* extract cursor location */
3116    outb(crtc_addr, 14);
3117    hw_cursor = inb(crtc_addr + 1) << 8;
3118    outb(crtc_addr, 15);
3119    hw_cursor |= inb(crtc_addr + 1);
3120
3121    /*
3122     * Validate cursor location.  It may be off the screen.  Then we must
3123     * not use it for the initial buffer offset.
3124     */
3125    if (hw_cursor >= ROW * COL)
3126	hw_cursor = (ROW - 1) * COL;
3127
3128    /* move hardware cursor out of the way */
3129    outb(crtc_addr, 14);
3130    outb(crtc_addr + 1, 0xff);
3131    outb(crtc_addr, 15);
3132    outb(crtc_addr + 1, 0xff);
3133
3134    /* set up the first console */
3135    current_default = &user_default;
3136    console[0] = &main_console;
3137    init_scp(console[0]);
3138    cur_console = console[0];
3139
3140    /* discard the video mode table if we are not familiar with it... */
3141    if (video_mode_ptr) {
3142        bzero(mode_map, sizeof(mode_map));
3143	bcopy(video_mode_ptr + MODE_PARAM_SIZE*console[0]->mode,
3144	      vgaregs2, sizeof(vgaregs2));
3145        switch (comp_vgaregs(vgaregs, video_mode_ptr
3146                    + MODE_PARAM_SIZE*console[0]->mode)) {
3147        case COMP_IDENTICAL:
3148            map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3149            /*
3150             * This is a kludge for Toshiba DynaBook SS433 whose BIOS video
3151             * mode table entry has the actual # of rows at the offset 1;
3152	     * BIOSes from other manufacturers store the # of rows - 1 there.
3153	     * XXX
3154             */
3155	    rows_offset = vgaregs[1] + 1
3156		- video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3157            break;
3158        case COMP_SIMILAR:
3159            map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3160            mode_map[console[0]->mode] = vgaregs;
3161	    rows_offset = vgaregs[1] + 1
3162		- video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3163            vgaregs[1] -= rows_offset - 1;
3164            break;
3165        case COMP_DIFFERENT:
3166        default:
3167            video_mode_ptr = NULL;
3168            mode_map[console[0]->mode] = vgaregs;
3169	    rows_offset = 1;
3170            break;
3171        }
3172    }
3173
3174    /* copy screen to temporary buffer */
3175    sc_bcopy(Crtat, sc_buffer,
3176	   console[0]->xsize * console[0]->ysize * sizeof(u_short));
3177
3178    console[0]->scr_buf = console[0]->mouse_pos = sc_buffer;
3179    console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor;
3180    console[0]->cursor_saveunder = *console[0]->cursor_pos;
3181    console[0]->xpos = hw_cursor % COL;
3182    console[0]->ypos = hw_cursor / COL;
3183    for (i=1; i<MAXCONS; i++)
3184	console[i] = NULL;
3185    kernel_console.esc = 0;
3186    kernel_console.attr_mask = NORMAL_ATTR;
3187    kernel_console.cur_attr =
3188	kernel_console.cur_color = kernel_console.std_color =
3189	kernel_default.std_color;
3190    kernel_console.rev_color = kernel_default.rev_color;
3191
3192    /* initialize mapscrn arrays to a one to one map */
3193    for (i=0; i<sizeof(scr_map); i++) {
3194	scr_map[i] = scr_rmap[i] = i;
3195    }
3196
3197    /* Save font and palette if VGA */
3198    if (crtc_vga) {
3199	if (fonts_loaded & FONT_16) {
3200		copy_font(LOAD, FONT_16, font_16);
3201	} else {
3202		copy_font(SAVE, FONT_16, font_16);
3203		fonts_loaded = FONT_16;
3204	}
3205	save_palette();
3206	set_destructive_cursor(console[0]);
3207    }
3208
3209#ifdef SC_SPLASH_SCREEN
3210    /*
3211     * Now put up a graphics image, and maybe cycle a
3212     * couble of palette entries for simple animation.
3213     */
3214    toggle_splash_screen(cur_console);
3215#endif
3216}
3217
3218static void
3219map_mode_table(char *map[], char *table, int max)
3220{
3221    int i;
3222
3223    for(i = 0; i < max; ++i)
3224	map[i] = table + i*MODE_PARAM_SIZE;
3225    for(; i < MODE_MAP_SIZE; ++i)
3226	map[i] = NULL;
3227}
3228
3229static u_char
3230map_mode_num(u_char mode)
3231{
3232    static struct {
3233        u_char from;
3234        u_char to;
3235    } mode_map[] = {
3236        { M_ENH_B80x43, M_ENH_B80x25 },
3237        { M_ENH_C80x43, M_ENH_C80x25 },
3238        { M_VGA_M80x30, M_VGA_M80x25 },
3239        { M_VGA_C80x30, M_VGA_C80x25 },
3240        { M_VGA_M80x50, M_VGA_M80x25 },
3241        { M_VGA_C80x50, M_VGA_C80x25 },
3242        { M_VGA_M80x60, M_VGA_M80x25 },
3243        { M_VGA_C80x60, M_VGA_C80x25 },
3244        { M_VGA_MODEX,  M_VGA_CG320 },
3245    };
3246    int i;
3247
3248    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
3249        if (mode_map[i].from == mode)
3250            return mode_map[i].to;
3251    }
3252    return mode;
3253}
3254
3255static char
3256*get_mode_param(scr_stat *scp, u_char mode)
3257{
3258    if (mode >= MODE_MAP_SIZE)
3259	mode = map_mode_num(mode);
3260    if (mode < MODE_MAP_SIZE)
3261	return mode_map[mode];
3262    else
3263	return NULL;
3264}
3265
3266static scr_stat
3267*alloc_scp()
3268{
3269    scr_stat *scp;
3270
3271    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3272    init_scp(scp);
3273    scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos =
3274	(u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3275			  M_DEVBUF, M_WAITOK);
3276    scp->mouse_pos = scp->mouse_oldpos =
3277	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
3278			scp->mouse_xpos/8);
3279    scp->history_head = scp->history_pos =
3280	(u_short *)malloc(scp->history_size*sizeof(u_short),
3281			  M_DEVBUF, M_WAITOK);
3282    bzero(scp->history_head, scp->history_size*sizeof(u_short));
3283    scp->history = scp->history_head;
3284/* SOS
3285    if (crtc_vga && video_mode_ptr)
3286	set_mode(scp);
3287*/
3288    clear_screen(scp);
3289    scp->cursor_saveunder = *scp->cursor_pos;
3290    return scp;
3291}
3292
3293static void
3294init_scp(scr_stat *scp)
3295{
3296    if (crtc_vga)
3297	if (crtc_addr == MONO_BASE)
3298	    scp->mode = M_VGA_M80x25;
3299	else
3300	    scp->mode = M_VGA_C80x25;
3301    else
3302	if (crtc_addr == MONO_BASE)
3303	    scp->mode = M_B80x25;
3304	else
3305	    scp->mode = M_C80x25;
3306    scp->initial_mode = scp->mode;
3307
3308    scp->font_size = 16;
3309    scp->xsize = COL;
3310    scp->ysize = ROW;
3311    scp->xpos = scp->ypos = 0;
3312    scp->saved_xpos = scp->saved_ypos = -1;
3313    scp->start = scp->xsize * scp->ysize;
3314    scp->end = 0;
3315    scp->term.esc = 0;
3316    scp->term.attr_mask = NORMAL_ATTR;
3317    scp->term.cur_attr =
3318	scp->term.cur_color = scp->term.std_color =
3319	current_default->std_color;
3320    scp->term.rev_color = current_default->rev_color;
3321    scp->border = BG_BLACK;
3322    scp->cursor_start = *(char *)pa_to_va(0x461);
3323    scp->cursor_end = *(char *)pa_to_va(0x460);
3324    scp->mouse_xpos = scp->xsize*8/2;
3325    scp->mouse_ypos = scp->ysize*scp->font_size/2;
3326    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3327    scp->mouse_signal = 0;
3328    scp->mouse_pid = 0;
3329    scp->mouse_proc = NULL;
3330    scp->bell_pitch = BELL_PITCH;
3331    scp->bell_duration = BELL_DURATION;
3332    scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3333    scp->status |= CURSOR_ENABLED;
3334    scp->pid = 0;
3335    scp->proc = NULL;
3336    scp->smode.mode = VT_AUTO;
3337    scp->history_head = scp->history_pos = scp->history = NULL;
3338    scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
3339}
3340
3341static u_char
3342*get_fstr(u_int c, u_int *len)
3343{
3344    u_int i;
3345
3346    if (!(c & FKEY))
3347	return(NULL);
3348    i = (c & 0xFF) - F_FN;
3349    if (i > n_fkey_tab)
3350	return(NULL);
3351    *len = fkey_tab[i].len;
3352    return(fkey_tab[i].str);
3353}
3354
3355static void
3356history_to_screen(scr_stat *scp)
3357{
3358    int i;
3359
3360    for (i=0; i<scp->ysize; i++)
3361	bcopy(scp->history + (((scp->history_pos - scp->history) +
3362	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3363	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3364	       scp->xsize * sizeof(u_short));
3365    mark_all(scp);
3366}
3367
3368static int
3369history_up_line(scr_stat *scp)
3370{
3371    if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3372	scp->history_head) {
3373	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3374	history_to_screen(scp);
3375	return 0;
3376    }
3377    else
3378	return -1;
3379}
3380
3381static int
3382history_down_line(scr_stat *scp)
3383{
3384    if (scp->history_pos != scp->history_head) {
3385	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3386	history_to_screen(scp);
3387	return 0;
3388    }
3389    else
3390	return -1;
3391}
3392
3393/*
3394 * scgetc(flags) - get character from keyboard.
3395 * If flags & SCGETC_CN, then avoid harmful side effects.
3396 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3397 * return NOKEY if there is nothing there.
3398 */
3399static u_int
3400scgetc(u_int flags)
3401{
3402    struct key_t *key;
3403    u_char scancode, keycode;
3404    u_int state, action;
3405    int c;
3406    static u_char esc_flag = 0, compose = 0;
3407    static u_int chr = 0;
3408
3409next_code:
3410    /* first see if there is something in the keyboard port */
3411    if (flags & SCGETC_NONBLOCK) {
3412	c = read_kbd_data_no_wait(sc_kbdc);
3413	if (c == -1)
3414	    return(NOKEY);
3415    } else {
3416	do {
3417	    c = read_kbd_data(sc_kbdc);
3418	} while(c == -1);
3419    }
3420    scancode = (u_char)c;
3421
3422    /* do the /dev/random device a favour */
3423    if (!(flags & SCGETC_CN))
3424	add_keyboard_randomness(scancode);
3425
3426    if (cur_console->status & KBD_RAW_MODE)
3427	return scancode;
3428
3429    keycode = scancode & 0x7F;
3430    switch (esc_flag) {
3431    case 0x00:      /* normal scancode */
3432	switch(scancode) {
3433	case 0xB8:  /* left alt (compose key) */
3434	    if (compose) {
3435		compose = 0;
3436		if (chr > 255) {
3437		    do_bell(cur_console,
3438			BELL_PITCH, BELL_DURATION);
3439		    chr = 0;
3440		}
3441	    }
3442	    break;
3443	case 0x38:
3444	    if (!compose) {
3445		compose = 1;
3446		chr = 0;
3447	    }
3448	    break;
3449	case 0xE0:
3450	case 0xE1:
3451	    esc_flag = scancode;
3452	    goto next_code;
3453	}
3454	break;
3455    case 0xE0:      /* 0xE0 prefix */
3456	esc_flag = 0;
3457	switch (keycode) {
3458	case 0x1C:  /* right enter key */
3459	    keycode = 0x59;
3460	    break;
3461	case 0x1D:  /* right ctrl key */
3462	    keycode = 0x5A;
3463	    break;
3464	case 0x35:  /* keypad divide key */
3465	    keycode = 0x5B;
3466	    break;
3467	case 0x37:  /* print scrn key */
3468	    keycode = 0x5C;
3469	    break;
3470	case 0x38:  /* right alt key (alt gr) */
3471	    keycode = 0x5D;
3472	    break;
3473	case 0x47:  /* grey home key */
3474	    keycode = 0x5E;
3475	    break;
3476	case 0x48:  /* grey up arrow key */
3477	    keycode = 0x5F;
3478	    break;
3479	case 0x49:  /* grey page up key */
3480	    keycode = 0x60;
3481	    break;
3482	case 0x4B:  /* grey left arrow key */
3483	    keycode = 0x61;
3484	    break;
3485	case 0x4D:  /* grey right arrow key */
3486	    keycode = 0x62;
3487	    break;
3488	case 0x4F:  /* grey end key */
3489	    keycode = 0x63;
3490	    break;
3491	case 0x50:  /* grey down arrow key */
3492	    keycode = 0x64;
3493	    break;
3494	case 0x51:  /* grey page down key */
3495	    keycode = 0x65;
3496	    break;
3497	case 0x52:  /* grey insert key */
3498	    keycode = 0x66;
3499	    break;
3500	case 0x53:  /* grey delete key */
3501	    keycode = 0x67;
3502	    break;
3503
3504	/* the following 3 are only used on the MS "Natural" keyboard */
3505	case 0x5b:  /* left Window key */
3506	    keycode = 0x69;
3507	    break;
3508	case 0x5c:  /* right Window key */
3509	    keycode = 0x6a;
3510	    break;
3511	case 0x5d:  /* menu key */
3512	    keycode = 0x6b;
3513	    break;
3514	default:    /* ignore everything else */
3515	    goto next_code;
3516	}
3517	break;
3518    case 0xE1:      /* 0xE1 prefix */
3519	esc_flag = 0;
3520	if (keycode == 0x1D)
3521	    esc_flag = 0x1D;
3522	goto next_code;
3523	/* NOT REACHED */
3524    case 0x1D:      /* pause / break */
3525	esc_flag = 0;
3526	if (keycode != 0x45)
3527	    goto next_code;
3528	keycode = 0x68;
3529	break;
3530    }
3531
3532    if (cur_console->status & KBD_CODE_MODE)
3533	return (keycode | (scancode & 0x80));
3534
3535    /* if scroll-lock pressed allow history browsing */
3536    if (cur_console->history && cur_console->status & SLKED) {
3537	int i;
3538
3539	cur_console->status &= ~CURSOR_ENABLED;
3540	if (!(cur_console->status & BUFFER_SAVED)) {
3541	    cur_console->status |= BUFFER_SAVED;
3542	    cur_console->history_save = cur_console->history_head;
3543
3544	    /* copy screen into top of history buffer */
3545	    for (i=0; i<cur_console->ysize; i++) {
3546		bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3547		       cur_console->history_head,
3548		       cur_console->xsize * sizeof(u_short));
3549		cur_console->history_head += cur_console->xsize;
3550		if (cur_console->history_head + cur_console->xsize >
3551		    cur_console->history + cur_console->history_size)
3552		    cur_console->history_head=cur_console->history;
3553	    }
3554	    cur_console->history_pos = cur_console->history_head;
3555	    history_to_screen(cur_console);
3556	}
3557	switch (scancode) {
3558	case 0x47:  /* home key */
3559	    cur_console->history_pos = cur_console->history_head;
3560	    history_to_screen(cur_console);
3561	    goto next_code;
3562
3563	case 0x4F:  /* end key */
3564	    cur_console->history_pos =
3565		WRAPHIST(cur_console, cur_console->history_head,
3566			 cur_console->xsize*cur_console->ysize);
3567	    history_to_screen(cur_console);
3568	    goto next_code;
3569
3570	case 0x48:  /* up arrow key */
3571	    if (history_up_line(cur_console))
3572		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3573	    goto next_code;
3574
3575	case 0x50:  /* down arrow key */
3576	    if (history_down_line(cur_console))
3577		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3578	    goto next_code;
3579
3580	case 0x49:  /* page up key */
3581	    for (i=0; i<cur_console->ysize; i++)
3582	    if (history_up_line(cur_console)) {
3583		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3584		break;
3585	    }
3586	    goto next_code;
3587
3588	case 0x51:  /* page down key */
3589	    for (i=0; i<cur_console->ysize; i++)
3590	    if (history_down_line(cur_console)) {
3591		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3592		break;
3593	    }
3594	    goto next_code;
3595	}
3596    }
3597
3598    if (compose) {
3599	switch (scancode) {
3600	/* key pressed process it */
3601	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
3602	    chr = (scancode - 0x40) + chr*10;
3603	    goto next_code;
3604	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
3605	    chr = (scancode - 0x47) + chr*10;
3606	    goto next_code;
3607	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
3608	    chr = (scancode - 0x4E) + chr*10;
3609	    goto next_code;
3610	case 0x52:              /* keypad 0 */
3611	    chr *= 10;
3612	    goto next_code;
3613
3614	/* key release, no interest here */
3615	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
3616	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
3617	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
3618	case 0xD2:              /* keypad 0 */
3619	    goto next_code;
3620
3621	case 0x38:              /* left alt key */
3622	    break;
3623	default:
3624	    if (chr) {
3625		compose = chr = 0;
3626		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3627		goto next_code;
3628	    }
3629	    break;
3630	}
3631    }
3632
3633    state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
3634    if ((!agrs && (cur_console->status & ALKED))
3635	|| (agrs && !(cur_console->status & ALKED)))
3636	keycode += ALTGR_OFFSET;
3637    key = &key_map.key[keycode];
3638    if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
3639	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
3640	state ^= 1;
3641
3642    /* Check for make/break */
3643    action = key->map[state];
3644    if (scancode & 0x80) {      /* key released */
3645	if (key->spcl & (0x80>>state)) {
3646	    switch (action) {
3647	    case LSH:
3648		shfts &= ~1;
3649		break;
3650	    case RSH:
3651		shfts &= ~2;
3652		break;
3653	    case LCTR:
3654		ctls &= ~1;
3655		break;
3656	    case RCTR:
3657		ctls &= ~2;
3658		break;
3659	    case LALT:
3660		alts &= ~1;
3661		break;
3662	    case RALT:
3663		alts &= ~2;
3664		break;
3665	    case NLK:
3666		nlkcnt = 0;
3667		break;
3668	    case CLK:
3669		clkcnt = 0;
3670		break;
3671	    case SLK:
3672		slkcnt = 0;
3673		break;
3674	    case ASH:
3675		agrs = 0;
3676		break;
3677	    case ALK:
3678		alkcnt = 0;
3679		break;
3680	    case META:
3681		metas = 0;
3682		break;
3683	    }
3684	}
3685	if (chr && !compose) {
3686	    action = chr;
3687	    chr = 0;
3688	    return(action);
3689	}
3690    } else {
3691	/* key pressed */
3692	if (key->spcl & (0x80>>state)) {
3693	    switch (action) {
3694	    /* LOCKING KEYS */
3695	    case NLK:
3696#ifdef SC_SPLASH_SCREEN
3697		toggle_splash_screen(cur_console); /* SOS XXX */
3698#endif
3699		if (!nlkcnt) {
3700		    nlkcnt++;
3701		    if (cur_console->status & NLKED)
3702			cur_console->status &= ~NLKED;
3703		    else
3704			cur_console->status |= NLKED;
3705		    update_leds(cur_console->status);
3706		}
3707		break;
3708	    case CLK:
3709		if (!clkcnt) {
3710		    clkcnt++;
3711		    if (cur_console->status & CLKED)
3712			cur_console->status &= ~CLKED;
3713		    else
3714			cur_console->status |= CLKED;
3715		    update_leds(cur_console->status);
3716		}
3717		break;
3718	    case SLK:
3719		if (!slkcnt) {
3720		    slkcnt++;
3721		    if (cur_console->status & SLKED) {
3722			cur_console->status &= ~SLKED;
3723			if (cur_console->status & BUFFER_SAVED){
3724			    int i;
3725			    u_short *ptr = cur_console->history_save;
3726
3727			    for (i=0; i<cur_console->ysize; i++) {
3728				bcopy(ptr,
3729				       cur_console->scr_buf +
3730				       (cur_console->xsize*i),
3731				       cur_console->xsize * sizeof(u_short));
3732				ptr += cur_console->xsize;
3733				if (ptr + cur_console->xsize >
3734				    cur_console->history +
3735				    cur_console->history_size)
3736				    ptr = cur_console->history;
3737			    }
3738			    cur_console->status &= ~BUFFER_SAVED;
3739			    cur_console->history_head=cur_console->history_save;
3740			    cur_console->status |= CURSOR_ENABLED;
3741			    mark_all(cur_console);
3742			}
3743			scstart(VIRTUAL_TTY(get_scr_num()));
3744		    }
3745		    else
3746			cur_console->status |= SLKED;
3747		    update_leds(cur_console->status);
3748		}
3749		break;
3750	    case ALK:
3751		if (!alkcnt) {
3752		    alkcnt++;
3753		    if (cur_console->status & ALKED)
3754			cur_console->status &= ~ALKED;
3755		    else
3756			cur_console->status |= ALKED;
3757		    update_leds(cur_console->status);
3758		}
3759		break;
3760
3761	    /* NON-LOCKING KEYS */
3762	    case NOP:
3763		break;
3764	    case SPSC:
3765#ifdef SC_SPLASH_SCREEN
3766		accents = 0;
3767		toggle_splash_screen(cur_console);
3768#endif
3769		break;
3770	    case RBT:
3771		accents = 0;
3772		shutdown_nice();
3773		break;
3774	    case SUSP:
3775#if NAPM > 0
3776		accents = 0;
3777		apm_suspend();
3778#endif
3779		break;
3780
3781	    case DBG:
3782#ifdef DDB          /* try to switch to console 0 */
3783		accents = 0;
3784		if (cur_console->smode.mode == VT_AUTO &&
3785		    console[0]->smode.mode == VT_AUTO)
3786		    switch_scr(cur_console, 0);
3787		Debugger("manual escape to debugger");
3788#else
3789		printf("No debugger in kernel\n");
3790#endif
3791		break;
3792	    case LSH:
3793		shfts |= 1;
3794		break;
3795	    case RSH:
3796		shfts |= 2;
3797		break;
3798	    case LCTR:
3799		ctls |= 1;
3800		break;
3801	    case RCTR:
3802		ctls |= 2;
3803		break;
3804	    case LALT:
3805		alts |= 1;
3806		break;
3807	    case RALT:
3808		alts |= 2;
3809		break;
3810	    case ASH:
3811		agrs = 1;
3812		break;
3813	    case META:
3814		metas = 1;
3815		break;
3816	    case NEXT:
3817		{
3818		int next, this = get_scr_num();
3819		accents = 0;
3820		for (next = this+1; next != this; next = (next+1)%MAXCONS) {
3821		    struct tty *tp = VIRTUAL_TTY(next);
3822		    if (tp->t_state & TS_ISOPEN) {
3823			switch_scr(cur_console, next);
3824			break;
3825		    }
3826		}
3827		}
3828		break;
3829	    case BTAB:
3830		accents = 0;
3831		return(BKEY);
3832	    default:
3833		if (action >= F_ACC && action <= L_ACC) {
3834		    /* turn it into an index */
3835		    action -= F_ACC - 1;
3836		    if ((action > accent_map.n_accs)
3837			|| (accent_map.acc[action - 1].accchar == 0)) {
3838			/*
3839			 * The index is out of range or pointing to an
3840			 * empty entry.
3841			 */
3842			accents = 0;
3843			do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3844		    }
3845		    /*
3846		     * If the same accent key has been hit twice,
3847		     * produce the accent char itself.
3848		     */
3849		    if (action == accents) {
3850			action = accent_map.acc[accents - 1].accchar;
3851			accents = 0;
3852			if (metas)
3853			    action |= MKEY;
3854			return (action);
3855		    }
3856		    /* remember the index and wait for the next key stroke */
3857		    accents = action;
3858		    break;
3859		}
3860		if (accents > 0) {
3861		    accents = 0;
3862		    do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3863		}
3864		if (action >= F_SCR && action <= L_SCR) {
3865		    switch_scr(cur_console, action - F_SCR);
3866		    break;
3867		}
3868		if (action >= F_FN && action <= L_FN)
3869		    action |= FKEY;
3870		return(action);
3871	    }
3872	}
3873	else {
3874	    if (accents) {
3875		struct acc_t *acc;
3876		int i;
3877
3878		acc = &accent_map.acc[accents - 1];
3879		accents = 0;
3880		/*
3881		 * If the accent key is followed by the space key,
3882		 * produce the accent char itself.
3883		 */
3884		if (action == ' ') {
3885		    action = acc->accchar;
3886		    if (metas)
3887			action |= MKEY;
3888		    return (action);
3889		}
3890		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
3891		    if (acc->map[i][0] == 0)	/* end of the map entry */
3892			break;
3893		    if (acc->map[i][0] == action) {
3894			action = acc->map[i][1];
3895			if (metas)
3896			    action |= MKEY;
3897			return (action);
3898		    }
3899		}
3900		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3901		goto next_code;
3902	    }
3903	    if (metas)
3904		action |= MKEY;
3905	    return(action);
3906	}
3907    }
3908    goto next_code;
3909}
3910
3911int
3912scmmap(dev_t dev, int offset, int nprot)
3913{
3914    if (offset > 0x20000 - PAGE_SIZE)
3915	return -1;
3916    return i386_btop((VIDEOMEM + offset));
3917}
3918
3919/*
3920 * Calculate hardware attributes word using logical attributes mask and
3921 * hardware colors
3922 */
3923
3924static int
3925mask2attr(struct term_stat *term)
3926{
3927    int attr, mask = term->attr_mask;
3928
3929    if (mask & REVERSE_ATTR) {
3930	attr = ((mask & FOREGROUND_CHANGED) ?
3931		((term->cur_color & 0xF000) >> 4) :
3932		(term->rev_color & 0x0F00)) |
3933	       ((mask & BACKGROUND_CHANGED) ?
3934		((term->cur_color & 0x0F00) << 4) :
3935		(term->rev_color & 0xF000));
3936    } else
3937	attr = term->cur_color;
3938
3939    /* XXX: underline mapping for Hercules adapter can be better */
3940    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3941	attr ^= 0x0800;
3942    if (mask & BLINK_ATTR)
3943	attr ^= 0x8000;
3944
3945    return attr;
3946}
3947
3948static void
3949set_keyboard(int command, int data)
3950{
3951    int s;
3952
3953    if (sc_kbdc == NULL)
3954	return;
3955
3956    /* prevent the timeout routine from polling the keyboard */
3957    if (!kbdc_lock(sc_kbdc, TRUE))
3958	return;
3959
3960    /* disable the keyboard and mouse interrupt */
3961    s = spltty();
3962#if 0
3963    c = get_controller_command_byte(sc_kbdc);
3964    if ((c == -1)
3965	|| !set_controller_command_byte(sc_kbdc,
3966            kbdc_get_device_mask(sc_kbdc),
3967            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
3968                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
3969	/* CONTROLLER ERROR */
3970        kbdc_lock(sc_kbdc, FALSE);
3971	splx(s);
3972	return;
3973    }
3974    /*
3975     * Now that the keyboard controller is told not to generate
3976     * the keyboard and mouse interrupts, call `splx()' to allow
3977     * the other tty interrupts. The clock interrupt may also occur,
3978     * but the timeout routine (`scrn_timer()') will be blocked
3979     * by the lock flag set via `kbdc_lock()'
3980     */
3981    splx(s);
3982#endif
3983
3984    if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
3985        send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
3986
3987#if 0
3988    /* restore the interrupts */
3989    if (!set_controller_command_byte(sc_kbdc,
3990            kbdc_get_device_mask(sc_kbdc),
3991	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
3992	/* CONTROLLER ERROR */
3993    }
3994#else
3995    splx(s);
3996#endif
3997    kbdc_lock(sc_kbdc, FALSE);
3998}
3999
4000static void
4001update_leds(int which)
4002{
4003    static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
4004
4005    /* replace CAPS led with ALTGR led for ALTGR keyboards */
4006    if (key_map.n_keys > ALTGR_OFFSET) {
4007	if (which & ALKED)
4008	    which |= CLKED;
4009	else
4010	    which &= ~CLKED;
4011    }
4012
4013    set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
4014}
4015
4016void
4017set_mode(scr_stat *scp)
4018{
4019    char special_modetable[MODE_PARAM_SIZE];
4020    char *mp;
4021
4022    if (scp != cur_console)
4023	return;
4024
4025    /*
4026     * even if mode switching is disabled, we can change back
4027     * to the initial mode or the custom mode based on the initial
4028     * mode if we have saved register values upon start-up.
4029     */
4030    mp = get_mode_param(scp, scp->mode);
4031    if (mp == NULL)
4032	return;
4033    bcopy(mp, &special_modetable, sizeof(special_modetable));
4034
4035    /* setup video hardware for the given mode */
4036    switch (scp->mode) {
4037    case M_VGA_C80x60: case M_VGA_M80x60:
4038	special_modetable[2]  = 0x08;
4039	special_modetable[19] = 0x47;
4040	goto special_480l;
4041
4042    case M_VGA_C80x30: case M_VGA_M80x30:
4043	special_modetable[19] = 0x4f;
4044special_480l:
4045	special_modetable[9] |= 0xc0;
4046	special_modetable[16] = 0x08;
4047	special_modetable[17] = 0x3e;
4048	special_modetable[26] = 0xea;
4049	special_modetable[28] = 0xdf;
4050	special_modetable[31] = 0xe7;
4051	special_modetable[32] = 0x04;
4052	goto setup_mode;
4053
4054    case M_ENH_C80x43: case M_ENH_B80x43:
4055	special_modetable[28] = 87;
4056	goto special_80x50;
4057
4058    case M_VGA_C80x50: case M_VGA_M80x50:
4059special_80x50:
4060	special_modetable[2] = 8;
4061	special_modetable[19] = 7;
4062	goto setup_mode;
4063
4064    case M_VGA_C40x25: case M_VGA_C80x25:
4065    case M_VGA_M80x25:
4066    case M_B40x25:     case M_C40x25:
4067    case M_B80x25:     case M_C80x25:
4068    case M_ENH_B40x25: case M_ENH_C40x25:
4069    case M_ENH_B80x25: case M_ENH_C80x25:
4070    case M_EGAMONO80x25:
4071
4072setup_mode:
4073	set_vgaregs(special_modetable);
4074	scp->font_size = special_modetable[2];
4075
4076	/* set font type (size) */
4077	if (scp->font_size < 14) {
4078	    if (fonts_loaded & FONT_8)
4079		copy_font(LOAD, FONT_8, font_8);
4080	    outb(TSIDX, 0x03); outb(TSREG, 0x0A);   /* font 2 */
4081	} else if (scp->font_size >= 16) {
4082	    if (fonts_loaded & FONT_16)
4083		copy_font(LOAD, FONT_16, font_16);
4084	    outb(TSIDX, 0x03); outb(TSREG, 0x00);   /* font 0 */
4085	} else {
4086	    if (fonts_loaded & FONT_14)
4087		copy_font(LOAD, FONT_14, font_14);
4088	    outb(TSIDX, 0x03); outb(TSREG, 0x05);   /* font 1 */
4089	}
4090	if (flags & CHAR_CURSOR)
4091	    set_destructive_cursor(scp);
4092	mark_all(scp);
4093	break;
4094
4095    case M_VGA_MODEX:
4096	/* "unchain" the VGA mode */
4097	special_modetable[5-1+0x04] &= 0xf7;
4098	special_modetable[5-1+0x04] |= 0x04;
4099	/* turn off doubleword mode */
4100	special_modetable[10+0x14] &= 0xbf;
4101	/* turn off word adressing */
4102	special_modetable[10+0x17] |= 0x40;
4103	/* set logical screen width */
4104	special_modetable[10+0x13] = 80;
4105	/* set 240 lines */
4106	special_modetable[10+0x11] = 0x2c;
4107	special_modetable[10+0x06] = 0x0d;
4108	special_modetable[10+0x07] = 0x3e;
4109	special_modetable[10+0x10] = 0xea;
4110	special_modetable[10+0x11] = 0xac;
4111	special_modetable[10+0x12] = 0xdf;
4112	special_modetable[10+0x15] = 0xe7;
4113	special_modetable[10+0x16] = 0x06;
4114	/* set vertical sync polarity to reflect aspect ratio */
4115	special_modetable[9] = 0xe3;
4116	goto setup_grmode;
4117
4118    case M_BG320:     case M_CG320:     case M_BG640:
4119    case M_CG320_D:   case M_CG640_E:
4120    case M_CG640x350: case M_ENH_CG640:
4121    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
4122
4123setup_grmode:
4124	set_vgaregs(special_modetable);
4125	scp->font_size = FONT_NONE;
4126	break;
4127
4128    default:
4129	/* call user defined function XXX */
4130	break;
4131    }
4132
4133    /* set border color for this (virtual) console */
4134    set_border(scp->border);
4135    return;
4136}
4137
4138void
4139set_border(u_char color)
4140{
4141    switch (crtc_type) {
4142    case KD_EGA:
4143    case KD_VGA:
4144        inb(crtc_addr + 6);		/* reset flip-flop */
4145        outb(ATC, 0x31); outb(ATC, color);
4146	break;
4147    case KD_CGA:
4148	outb(crtc_addr + 5, color & 0x0f); /* color select register */
4149	break;
4150    case KD_MONO:
4151    case KD_HERCULES:
4152    default:
4153	break;
4154    }
4155}
4156
4157static void
4158set_vgaregs(char *modetable)
4159{
4160    int i, s = splhigh();
4161
4162    outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
4163    outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
4164    for (i=0; i<4; i++) {           		/* program sequencer */
4165	outb(TSIDX, i+1);
4166	outb(TSREG, modetable[i+5]);
4167    }
4168    outb(MISC, modetable[9]);       		/* set dot-clock */
4169    outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
4170    outb(crtc_addr, 0x11);
4171    outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
4172    for (i=0; i<25; i++) {          		/* program crtc */
4173	outb(crtc_addr, i);
4174	if (i == 14 || i == 15)     		/* no hardware cursor */
4175	    outb(crtc_addr+1, 0xff);
4176	else
4177	    outb(crtc_addr+1, modetable[i+10]);
4178    }
4179    inb(crtc_addr+6);           		/* reset flip-flop */
4180    for (i=0; i<20; i++) {          		/* program attribute ctrl */
4181	outb(ATC, i);
4182	outb(ATC, modetable[i+35]);
4183    }
4184    for (i=0; i<9; i++) {           		/* program graph data ctrl */
4185	outb(GDCIDX, i);
4186	outb(GDCREG, modetable[i+55]);
4187    }
4188    inb(crtc_addr+6);           		/* reset flip-flop */
4189    outb(ATC, 0x20);            		/* enable palette */
4190    splx(s);
4191}
4192
4193static void
4194read_vgaregs(char *buf)
4195{
4196    int i, j;
4197    int s;
4198
4199    bzero(buf, MODE_PARAM_SIZE);
4200
4201    s = splhigh();
4202
4203    outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
4204    outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
4205    for (i=0, j=5; i<4; i++) {
4206	outb(TSIDX, i+1);
4207	buf[j++] = inb(TSREG);
4208    }
4209    buf[9] = inb(MISC + 10);      		/* dot-clock */
4210    outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
4211
4212    for (i=0, j=10; i<25; i++) {       		/* crtc */
4213	outb(crtc_addr, i);
4214	buf[j++] = inb(crtc_addr+1);
4215    }
4216    for (i=0, j=35; i<20; i++) {          	/* attribute ctrl */
4217        inb(crtc_addr+6);           		/* reset flip-flop */
4218	outb(ATC, i);
4219	buf[j++] = inb(ATC + 1);
4220    }
4221    for (i=0, j=55; i<9; i++) {           	/* graph data ctrl */
4222	outb(GDCIDX, i);
4223	buf[j++] = inb(GDCREG);
4224    }
4225    inb(crtc_addr+6);           		/* reset flip-flop */
4226    outb(ATC, 0x20);            		/* enable palette */
4227
4228    buf[0] = *(char *)pa_to_va(0x44a);		/* COLS */
4229    buf[1] = *(char *)pa_to_va(0x484);		/* ROWS */
4230    buf[2] = *(char *)pa_to_va(0x485);		/* POINTS */
4231    buf[3] = *(char *)pa_to_va(0x44c);
4232    buf[4] = *(char *)pa_to_va(0x44d);
4233
4234    splx(s);
4235}
4236
4237static int
4238comp_vgaregs(u_char *buf1, u_char *buf2)
4239{
4240    static struct {
4241        u_char mask;
4242    } params[MODE_PARAM_SIZE] = {
4243	0xff, 0x00, 0xff, 		/* COLS, ROWS, POINTS */
4244	0xff, 0xff, 			/* page length */
4245	0xfe, 0xff, 0xff, 0xff,		/* sequencer registers */
4246	0xf3,				/* misc register */
4247	0xff, 0xff, 0xff, 0x7f, 0xff,	/* CRTC */
4248	0xff, 0xff, 0xff, 0x7f, 0xff,
4249	0x00, 0x00, 0x00, 0x00, 0x00,
4250	0x00, 0xff, 0x7f, 0xff, 0xff,
4251	0x7f, 0xff, 0xff, 0xef, 0xff,
4252	0xff, 0xff, 0xff, 0xff, 0xff,	/* attribute controller registers */
4253	0xff, 0xff, 0xff, 0xff, 0xff,
4254	0xff, 0xff, 0xff, 0xff, 0xff,
4255	0xff, 0xff, 0xff, 0xff, 0xf0,
4256	0xff, 0xff, 0xff, 0xff, 0xff,	/* GDC register */
4257	0xff, 0xff, 0xff, 0xff,
4258    };
4259    int identical = TRUE;
4260    int i;
4261
4262    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
4263	if (params[i].mask == 0)	/* don't care */
4264	    continue;
4265	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
4266	    return COMP_DIFFERENT;
4267	if (buf1[i] != buf2[i])
4268	    identical = FALSE;
4269    }
4270    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
4271
4272#if 0
4273    for(i = 0; i < 20; ++i) {
4274	if (*buf1++ != *buf2++)
4275	    return COMP_DIFFERENT;
4276    }
4277    buf1 += 2;  /* skip the cursor shape */
4278    buf2 += 2;
4279    for(i = 22; i < 24; ++i) {
4280	if (*buf1++ != *buf2++)
4281	    return COMP_DIFFERENT;
4282    }
4283    buf1 += 2;  /* skip the cursor position */
4284    buf2 += 2;
4285    for(i = 26; i < MODE_PARAM_SIZE; ++i) {
4286	if (*buf1++ != *buf2++)
4287	    return COMP_DIFFERENT;
4288    }
4289    return COMP_IDENTICAL;
4290#endif
4291}
4292
4293static void
4294dump_vgaregs(u_char *buf)
4295{
4296    int i;
4297
4298    for(i = 0; i < MODE_PARAM_SIZE;) {
4299	printf("%02x ", buf[i]);
4300	if ((++i % 16) == 0)
4301	    printf("\n");
4302    }
4303}
4304
4305static void
4306set_font_mode(u_char *buf)
4307{
4308    int s = splhigh();
4309
4310    /* save register values */
4311    outb(TSIDX, 0x02); buf[0] = inb(TSREG);
4312    outb(TSIDX, 0x04); buf[1] = inb(TSREG);
4313    outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
4314    outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
4315    outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
4316    inb(crtc_addr + 6);
4317    outb(ATC, 0x10); buf[5] = inb(ATC + 1);
4318
4319    /* setup vga for loading fonts (graphics plane mode) */
4320    inb(crtc_addr+6);           		/* reset flip-flop */
4321    outb(ATC, 0x10); outb(ATC, 0x01);
4322    inb(crtc_addr+6);               		/* reset flip-flop */
4323    outb(ATC, 0x20);            		/* enable palette */
4324
4325#if SLOW_VGA
4326    outb(TSIDX, 0x02); outb(TSREG, 0x04);
4327    outb(TSIDX, 0x04); outb(TSREG, 0x06);
4328    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
4329    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
4330    outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
4331#else
4332    outw(TSIDX, 0x0402);
4333    outw(TSIDX, 0x0604);
4334    outw(GDCIDX, 0x0204);
4335    outw(GDCIDX, 0x0005);
4336    outw(GDCIDX, 0x0506);               /* addr = a0000, 64kb */
4337#endif
4338    splx(s);
4339}
4340
4341static void
4342set_normal_mode(u_char *buf)
4343{
4344    char *modetable;
4345    int s = splhigh();
4346
4347    /* setup vga for normal operation mode again */
4348    inb(crtc_addr+6);           		/* reset flip-flop */
4349    outb(ATC, 0x10); outb(ATC, buf[5]);
4350    inb(crtc_addr+6);               		/* reset flip-flop */
4351    outb(ATC, 0x20);            		/* enable palette */
4352
4353#if SLOW_VGA
4354    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
4355    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
4356    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
4357    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
4358    if (crtc_addr == MONO_BASE) {
4359	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
4360    } else {
4361	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
4362    }
4363#else
4364    outw(TSIDX, 0x0002 | (buf[0] << 8));
4365    outw(TSIDX, 0x0004 | (buf[1] << 8));
4366    outw(GDCIDX, 0x0004 | (buf[2] << 8));
4367    outw(GDCIDX, 0x0005 | (buf[3] << 8));
4368    if (crtc_addr == MONO_BASE)
4369        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
4370    else
4371        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
4372#endif
4373    splx(s);
4374}
4375
4376void
4377copy_font(int operation, int font_type, char* font_image)
4378{
4379    int ch, line, segment, fontsize;
4380    u_char buf[PARAM_BUFSIZE];
4381    u_char val;
4382
4383    switch (font_type) {
4384    default:
4385    case FONT_8:
4386	segment = 0x8000;
4387	fontsize = 8;
4388	break;
4389    case FONT_14:
4390	segment = 0x4000;
4391	fontsize = 14;
4392	break;
4393    case FONT_16:
4394	segment = 0x0000;
4395	fontsize = 16;
4396	break;
4397    }
4398    outb(TSIDX, 0x01); val = inb(TSREG);        /* disable screen */
4399    outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
4400    set_font_mode(buf);
4401    for (ch=0; ch < 256; ch++)
4402	for (line=0; line < fontsize; line++)
4403	if (operation)
4404	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
4405		    font_image[(ch*fontsize)+line];
4406	else
4407	    font_image[(ch*fontsize)+line] =
4408	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
4409    set_normal_mode(buf);
4410    outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
4411}
4412
4413static void
4414set_destructive_cursor(scr_stat *scp)
4415{
4416    u_char buf[PARAM_BUFSIZE];
4417    u_char cursor[32];
4418    caddr_t address;
4419    int i;
4420    char *font_buffer;
4421
4422    if (scp->font_size < 14) {
4423	font_buffer = font_8;
4424	address = (caddr_t)VIDEOMEM + 0x8000;
4425    }
4426    else if (scp->font_size >= 16) {
4427	font_buffer = font_16;
4428	address = (caddr_t)VIDEOMEM;
4429    }
4430    else {
4431	font_buffer = font_14;
4432	address = (caddr_t)VIDEOMEM + 0x4000;
4433    }
4434
4435    if (scp->status & MOUSE_VISIBLE) {
4436	if ((scp->cursor_saveunder & 0xff) == 0xd0)
4437    	    bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4438	else if ((scp->cursor_saveunder & 0xff) == 0xd1)
4439    	    bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4440	else if ((scp->cursor_saveunder & 0xff) == 0xd2)
4441    	    bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4442	else if ((scp->cursor_saveunder & 0xff) == 0xd3)
4443    	    bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4444	else
4445	    bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4446 	       	   cursor, scp->font_size);
4447    }
4448    else
4449    	bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4450 	       cursor, scp->font_size);
4451    for (i=0; i<32; i++)
4452	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4453	    (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4454	    cursor[i] |= 0xff;
4455#if 1
4456    while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4457#endif
4458    set_font_mode(buf);
4459    sc_bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
4460    set_normal_mode(buf);
4461}
4462
4463static void
4464set_mouse_pos(scr_stat *scp)
4465{
4466    static int last_xpos = -1, last_ypos = -1;
4467
4468    if (scp->mouse_xpos < 0)
4469	scp->mouse_xpos = 0;
4470    if (scp->mouse_ypos < 0)
4471	scp->mouse_ypos = 0;
4472    if (scp->status & UNKNOWN_MODE) {
4473        if (scp->mouse_xpos > scp->xpixel-1)
4474	    scp->mouse_xpos = scp->xpixel-1;
4475        if (scp->mouse_ypos > scp->ypixel-1)
4476	    scp->mouse_ypos = scp->ypixel-1;
4477	return;
4478    }
4479    if (scp->mouse_xpos > (scp->xsize*8)-1)
4480	scp->mouse_xpos = (scp->xsize*8)-1;
4481    if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4482	scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4483
4484    if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4485	scp->status |= MOUSE_MOVED;
4486
4487    	scp->mouse_pos = scp->scr_buf +
4488	    ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4489
4490	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4491	    mouse_cut(scp);
4492    }
4493}
4494
4495#define isspace(c)	(((c) & 0xff) == ' ')
4496
4497static int
4498skip_spc_right(scr_stat *scp, u_short *p)
4499{
4500    int i;
4501
4502    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4503	if (!isspace(*p))
4504	    break;
4505	++p;
4506    }
4507    return i;
4508}
4509
4510static int
4511skip_spc_left(scr_stat *scp, u_short *p)
4512{
4513    int i;
4514
4515    for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4516	if (!isspace(*p))
4517	    break;
4518	--p;
4519    }
4520    return i;
4521}
4522
4523static void
4524mouse_cut(scr_stat *scp)
4525{
4526    u_short *end;
4527    u_short *p;
4528    int i = 0;
4529    int j = 0;
4530
4531    scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4532	scp->mouse_pos + 1 : scp->mouse_pos;
4533    end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4534	scp->mouse_cut_start : scp->mouse_cut_end;
4535    for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4536	    scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4537	cut_buffer[i] = *p & 0xff;
4538	/* remember the position of the last non-space char */
4539	if (!isspace(cut_buffer[i++]))
4540	    j = i;
4541	/* trim trailing blank when crossing lines */
4542	if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4543	    cut_buffer[j++] = '\n';
4544	    i = j;
4545	}
4546    }
4547    cut_buffer[i] = '\0';
4548
4549    /* scan towards the end of the last line */
4550    --p;
4551    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4552	if (!isspace(*p))
4553	    break;
4554	++p;
4555    }
4556    /* if there is nothing but blank chars, trim them, but mark towards eol */
4557    if (i >= scp->xsize) {
4558	if (scp->mouse_cut_start > scp->mouse_cut_end)
4559	    scp->mouse_cut_start = p;
4560	else
4561	    scp->mouse_cut_end = p;
4562	cut_buffer[j++] = '\n';
4563	cut_buffer[j] = '\0';
4564    }
4565
4566    mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
4567    mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
4568}
4569
4570static void
4571mouse_cut_start(scr_stat *scp)
4572{
4573    int i;
4574
4575    if (scp->status & MOUSE_VISIBLE) {
4576	if (scp->mouse_pos == scp->mouse_cut_start &&
4577	    scp->mouse_cut_start == scp->mouse_cut_end - 1) {
4578	    cut_buffer[0] = '\0';
4579	    remove_cutmarking(scp);
4580	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
4581	    /* if the pointer is on trailing blank chars, mark towards eol */
4582	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
4583	    scp->mouse_cut_start = scp->scr_buf +
4584	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
4585	    scp->mouse_cut_end = scp->scr_buf +
4586	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
4587	    cut_buffer[0] = '\n';
4588	    cut_buffer[1] = '\0';
4589	    scp->status |= MOUSE_CUTTING;
4590	} else {
4591	    scp->mouse_cut_start = scp->mouse_pos;
4592	    scp->mouse_cut_end = scp->mouse_cut_start + 1;
4593	    cut_buffer[0] = *scp->mouse_cut_start & 0xff;
4594	    cut_buffer[1] = '\0';
4595	    scp->status |= MOUSE_CUTTING;
4596	}
4597    	mark_all(scp);
4598	/* delete all other screens cut markings */
4599	for (i=0; i<MAXCONS; i++) {
4600	    if (console[i] == NULL || console[i] == scp)
4601		continue;
4602	    remove_cutmarking(console[i]);
4603	}
4604    }
4605}
4606
4607static void
4608mouse_cut_end(scr_stat *scp)
4609{
4610    if (scp->status & MOUSE_VISIBLE) {
4611	scp->status &= ~MOUSE_CUTTING;
4612    }
4613}
4614
4615static void
4616mouse_cut_word(scr_stat *scp)
4617{
4618    u_short *p;
4619    u_short *sol;
4620    u_short *eol;
4621    int i;
4622
4623    /*
4624     * Because we don't have locale information in the kernel,
4625     * we only distinguish space char and non-space chars.  Punctuation
4626     * chars, symbols and other regular chars are all treated alike.
4627     */
4628    if (scp->status & MOUSE_VISIBLE) {
4629	sol = scp->scr_buf
4630	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4631	eol = sol + scp->xsize;
4632	if (isspace(*scp->mouse_pos)) {
4633	    for (p = scp->mouse_pos; p >= sol; --p)
4634	        if (!isspace(*p))
4635		    break;
4636	    scp->mouse_cut_start = ++p;
4637	    for (p = scp->mouse_pos; p < eol; ++p)
4638	        if (!isspace(*p))
4639		    break;
4640	    scp->mouse_cut_end = p;
4641	} else {
4642	    for (p = scp->mouse_pos; p >= sol; --p)
4643	        if (isspace(*p))
4644		    break;
4645	    scp->mouse_cut_start = ++p;
4646	    for (p = scp->mouse_pos; p < eol; ++p)
4647	        if (isspace(*p))
4648		    break;
4649	    scp->mouse_cut_end = p;
4650	}
4651	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4652	    cut_buffer[i++] = *p & 0xff;
4653	cut_buffer[i] = '\0';
4654	scp->status |= MOUSE_CUTTING;
4655    }
4656}
4657
4658static void
4659mouse_cut_line(scr_stat *scp)
4660{
4661    u_short *p;
4662    int i;
4663
4664    if (scp->status & MOUSE_VISIBLE) {
4665	scp->mouse_cut_start = scp->scr_buf
4666	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4667	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
4668	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4669	    cut_buffer[i++] = *p & 0xff;
4670	cut_buffer[i++] = '\n';
4671	cut_buffer[i] = '\0';
4672	scp->status |= MOUSE_CUTTING;
4673    }
4674}
4675
4676static void
4677mouse_cut_extend(scr_stat *scp)
4678{
4679    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
4680	&& (scp->mouse_cut_start != NULL)) {
4681	mouse_cut(scp);
4682	scp->status |= MOUSE_CUTTING;
4683    }
4684}
4685
4686static void
4687mouse_paste(scr_stat *scp)
4688{
4689    if (scp->status & MOUSE_VISIBLE) {
4690	struct tty *tp;
4691	u_char *ptr = cut_buffer;
4692
4693	tp = VIRTUAL_TTY(get_scr_num());
4694	while (*ptr)
4695	    (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
4696    }
4697}
4698
4699static void
4700draw_mouse_image(scr_stat *scp)
4701{
4702    caddr_t address;
4703    int i;
4704    char *font_buffer;
4705    u_char buf[PARAM_BUFSIZE];
4706    u_short buffer[32];
4707    u_short xoffset, yoffset;
4708    u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
4709    int font_size = scp->font_size;
4710
4711    if (font_size < 14) {
4712	font_buffer = font_8;
4713	address = (caddr_t)VIDEOMEM + 0x8000;
4714    }
4715    else if (font_size >= 16) {
4716	font_buffer = font_16;
4717	address = (caddr_t)VIDEOMEM;
4718    }
4719    else {
4720	font_buffer = font_14;
4721	address = (caddr_t)VIDEOMEM + 0x4000;
4722    }
4723    xoffset = scp->mouse_xpos % 8;
4724    yoffset = scp->mouse_ypos % font_size;
4725
4726    /* prepare mousepointer char's bitmaps */
4727    bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
4728	   &scp->mouse_cursor[0], font_size);
4729    bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
4730	   &scp->mouse_cursor[32], font_size);
4731    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
4732	   &scp->mouse_cursor[64], font_size);
4733    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
4734	   &scp->mouse_cursor[96], font_size);
4735    for (i=0; i<font_size; i++) {
4736	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
4737	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
4738    }
4739
4740    /* now and-or in the mousepointer image */
4741    for (i=0; i<16; i++) {
4742	buffer[i+yoffset] =
4743	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
4744	    | (mouse_or_mask[i] >> xoffset);
4745    }
4746    for (i=0; i<font_size; i++) {
4747	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
4748	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
4749	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
4750	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
4751    }
4752
4753    scp->mouse_oldpos = scp->mouse_pos;
4754
4755#if 1
4756    /* wait for vertical retrace to avoid jitter on some videocards */
4757    while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
4758#endif
4759    set_font_mode(buf);
4760    sc_bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
4761    set_normal_mode(buf);
4762    *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0;
4763    *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2;
4764    if (scp->mouse_xpos < (scp->xsize-1)*8) {
4765    	*(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1;
4766    	*(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3;
4767    }
4768    mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
4769    mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
4770}
4771
4772static void
4773remove_mouse_image(scr_stat *scp)
4774{
4775    u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf);
4776
4777    *(crt_pos) = *(scp->mouse_oldpos);
4778    *(crt_pos+1) = *(scp->mouse_oldpos+1);
4779    *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
4780    *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
4781    mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
4782    mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
4783}
4784
4785static void
4786draw_cutmarking(scr_stat *scp)
4787{
4788    u_short *ptr;
4789    u_short och, nch;
4790
4791    for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
4792	nch = och = *(Crtat + (ptr - scp->scr_buf));
4793	/* are we outside the selected area ? */
4794	if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
4795	            scp->mouse_cut_end : scp->mouse_cut_start) ||
4796	     ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
4797	            scp->mouse_cut_start : scp->mouse_cut_end)) {
4798	    if (ptr != scp->cursor_pos)
4799		nch = (och & 0xff) | (*ptr & 0xff00);
4800	}
4801	else {
4802	    /* are we clear of the cursor image ? */
4803	    if (ptr != scp->cursor_pos)
4804		nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
4805	    else {
4806		if (flags & CHAR_CURSOR)
4807		    nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
4808		else
4809		    if (!(flags & BLINK_CURSOR))
4810		        nch = (och & 0xff) | (*ptr & 0xff00);
4811	    }
4812	}
4813	if (nch != och)
4814	    *(Crtat + (ptr - scp->scr_buf)) = nch;
4815    }
4816}
4817
4818static void
4819remove_cutmarking(scr_stat *scp)
4820{
4821    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
4822    scp->status &= ~MOUSE_CUTTING;
4823    mark_all(scp);
4824}
4825
4826static void
4827save_palette(void)
4828{
4829    int i;
4830
4831    outb(PALRADR, 0x00);
4832    for (i=0x00; i<0x300; i++)
4833	palette[i] = inb(PALDATA);
4834    inb(crtc_addr+6);           /* reset flip/flop */
4835}
4836
4837void
4838load_palette(char *palette)
4839{
4840    int i;
4841
4842    outb(PIXMASK, 0xFF);            /* no pixelmask */
4843    outb(PALWADR, 0x00);
4844    for (i=0x00; i<0x300; i++)
4845	 outb(PALDATA, palette[i]);
4846    inb(crtc_addr+6);           /* reset flip/flop */
4847    outb(ATC, 0x20);            /* enable palette */
4848}
4849
4850static void
4851do_bell(scr_stat *scp, int pitch, int duration)
4852{
4853    if (flags & VISUAL_BELL) {
4854	if (blink_in_progress)
4855	    return;
4856	blink_in_progress = 4;
4857	if (scp != cur_console)
4858	    blink_in_progress += 2;
4859	blink_screen(cur_console);
4860    } else {
4861	if (scp != cur_console)
4862	    pitch *= 2;
4863	sysbeep(pitch, duration);
4864    }
4865}
4866
4867static void
4868blink_screen(void *arg)
4869{
4870    scr_stat *scp = arg;
4871
4872    if ((scp->status & UNKNOWN_MODE) || (blink_in_progress <= 1)) {
4873	blink_in_progress = FALSE;
4874    	mark_all(scp);
4875	if (delayed_next_scr)
4876	    switch_scr(scp, delayed_next_scr - 1);
4877    }
4878    else {
4879	if (blink_in_progress & 1)
4880	    fillw(kernel_default.std_color | scr_map[0x20],
4881		  Crtat, scp->xsize * scp->ysize);
4882	else
4883	    fillw(kernel_default.rev_color | scr_map[0x20],
4884		  Crtat, scp->xsize * scp->ysize);
4885	blink_in_progress--;
4886	timeout(blink_screen, scp, hz / 10);
4887    }
4888}
4889
4890#ifdef SC_SPLASH_SCREEN
4891static void
4892toggle_splash_screen(scr_stat *scp)
4893{
4894    static int toggle = 0;
4895    static u_char save_mode;
4896    int s;
4897
4898    if (video_mode_ptr == NULL)
4899	return;
4900
4901    s = splhigh();
4902    if (toggle) {
4903	scp->mode = save_mode;
4904	scp->status &= ~UNKNOWN_MODE;
4905	set_mode(scp);
4906	load_palette(palette);
4907	toggle = 0;
4908    }
4909    else {
4910	save_mode = scp->mode;
4911	scp->mode = M_VGA_CG320;
4912	scp->status |= UNKNOWN_MODE;
4913	set_mode(scp);
4914	/* load image */
4915	toggle = 1;
4916    }
4917    splx(s);
4918}
4919#endif
4920#endif /* NSC */
4921