syscons.c revision 32315
1/*-
2 * Copyright (c) 1992-1997 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *  $Id: syscons.c,v 1.242 1997/12/07 08:09:19 yokota Exp $
29 */
30
31#include "sc.h"
32#include "apm.h"
33#include "opt_ddb.h"
34#include "opt_syscons.h"
35
36#if NSC > 0
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/conf.h>
40#include <sys/proc.h>
41#include <sys/signalvar.h>
42#include <sys/tty.h>
43#include <sys/kernel.h>
44#include <sys/malloc.h>
45#ifdef	DEVFS
46#include <sys/devfsext.h>
47#endif
48
49#include <machine/clock.h>
50#include <machine/cons.h>
51#include <machine/console.h>
52#include <machine/mouse.h>
53#include <machine/md_var.h>
54#include <machine/psl.h>
55#include <machine/frame.h>
56#include <machine/pc/display.h>
57#include <machine/apm_bios.h>
58#include <machine/random.h>
59
60#include <vm/vm.h>
61#include <vm/vm_param.h>
62#include <vm/pmap.h>
63
64#include <i386/isa/isa.h>
65#include <i386/isa/isa_device.h>
66#include <i386/isa/timerreg.h>
67#include <i386/isa/kbdtables.h>
68#include <i386/isa/kbdio.h>
69#include <i386/isa/syscons.h>
70
71#if !defined(MAXCONS)
72#define MAXCONS 16
73#endif
74
75#if !defined(SC_MAX_HISTORY_SIZE)
76#define SC_MAX_HISTORY_SIZE	(1000 * MAXCONS)
77#endif
78
79#if !defined(SC_HISTORY_SIZE)
80#define SC_HISTORY_SIZE		(ROW * 4)
81#endif
82
83#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
84#undef SC_MAX_HISTORY_SIZE
85#define SC_MAX_HISTORY_SIZE	(SC_HISTORY_SIZE * MAXCONS)
86#endif
87
88#define COLD 0
89#define WARM 1
90
91#define MODE_MAP_SIZE		(M_VGA_CG320 + 1)
92#define MODE_PARAM_SIZE		64
93
94/* XXX use sc_bcopy where video memory is concerned */
95#define sc_bcopy generic_bcopy
96extern void generic_bcopy(const void *, void *, size_t);
97
98static default_attr user_default = {
99    (FG_LIGHTGREY | BG_BLACK) << 8,
100    (FG_BLACK | BG_LIGHTGREY) << 8
101};
102
103static default_attr kernel_default = {
104    (FG_WHITE | BG_BLACK) << 8,
105    (FG_BLACK | BG_LIGHTGREY) << 8
106};
107
108static  scr_stat    	main_console;
109static  scr_stat    	*console[MAXCONS];
110#ifdef DEVFS
111static	void		*sc_devfs_token[MAXCONS];
112#endif
113	scr_stat    	*cur_console;
114static  scr_stat    	*new_scp, *old_scp;
115static  term_stat   	kernel_console;
116static  default_attr    *current_default;
117static  int     	flags = 0;
118static  int		sc_port = IO_KBD;
119static  KBDC		sc_kbdc = NULL;
120static  char        	init_done = COLD;
121static  u_short		sc_buffer[ROW*COL];
122static  char        	switch_in_progress = FALSE;
123static  char        	write_in_progress = FALSE;
124static  char        	blink_in_progress = FALSE;
125static  int        	blinkrate = 0;
126	u_int       	crtc_addr = MONO_BASE;
127	char		crtc_type = KD_MONO;
128	char        	crtc_vga = FALSE;
129static  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
130static  u_char		accents = 0;
131static  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
132static  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
133static  int     	delayed_next_scr = FALSE;
134static  long        	scrn_blank_time = 0;    /* screen saver timeout value */
135	int     	scrn_blanked = 0;       /* screen saver active flag */
136static  long       	scrn_time_stamp;
137	u_char      	scr_map[256];
138	u_char      	scr_rmap[256];
139	char        	*video_mode_ptr = NULL;
140	int     	fonts_loaded = 0
141#ifdef STD8X16FONT
142	| FONT_16
143#endif
144	;
145
146	char        	font_8[256*8];
147	char		font_14[256*14];
148#ifdef STD8X16FONT
149extern
150#endif
151	unsigned char	font_16[256*16];
152	char        	palette[256*3];
153static  char		*mode_map[MODE_MAP_SIZE];
154static  char		vgaregs[MODE_PARAM_SIZE];
155static  char		vgaregs2[MODE_PARAM_SIZE];
156static  int		rows_offset = 1;
157static	char 		*cut_buffer;
158static	int		mouse_level = 0;	/* sysmouse protocol level */
159static	mousestatus_t	mouse_status = { 0, 0, 0, 0, 0, 0 };
160static  u_short 	mouse_and_mask[16] = {
161				0xc000, 0xe000, 0xf000, 0xf800,
162				0xfc00, 0xfe00, 0xff00, 0xff80,
163				0xfe00, 0x1e00, 0x1f00, 0x0f00,
164				0x0f00, 0x0000, 0x0000, 0x0000
165			};
166static  u_short 	mouse_or_mask[16] = {
167				0x0000, 0x4000, 0x6000, 0x7000,
168				0x7800, 0x7c00, 0x7e00, 0x6800,
169				0x0c00, 0x0c00, 0x0600, 0x0600,
170				0x0000, 0x0000, 0x0000, 0x0000
171			};
172
173static int		extra_history_size =
174			    SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
175
176static void    		none_saver(int blank) { }
177static void    		(*current_saver)(int blank) = none_saver;
178int  			(*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data,
179					 int flag, struct proc *p) = NULL;
180
181/* OS specific stuff */
182#ifdef not_yet_done
183#define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
184struct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
185struct  MOUSE_TTY 	(sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
186struct  tty         	*sccons[MAXCONS+2];
187#else
188#define VIRTUAL_TTY(x)  &sccons[x]
189#define CONSOLE_TTY 	&sccons[MAXCONS]
190#define MOUSE_TTY 	&sccons[MAXCONS+1]
191static struct tty     	sccons[MAXCONS+2];
192#endif
193#define SC_MOUSE 	128
194#define SC_CONSOLE	255
195#define MONO_BUF    	pa_to_va(0xB0000)
196#define CGA_BUF     	pa_to_va(0xB8000)
197u_short         	*Crtat;
198static const int	nsccons = MAXCONS+2;
199
200#define WRAPHIST(scp, pointer, offset)\
201    ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
202    + (offset)) % (scp->history_size)))
203#define ISSIGVALID(sig)	((sig) > 0 && (sig) < NSIG)
204
205/* this should really be in `rtc.h' */
206#define RTC_EQUIPMENT		0x14
207
208/* prototypes */
209static int scattach(struct isa_device *dev);
210static int scparam(struct tty *tp, struct termios *t);
211static int scprobe(struct isa_device *dev);
212static int scvidprobe(int unit, int flags);
213static int sckbdprobe(int unit, int flags);
214static void scstart(struct tty *tp);
215static void scmousestart(struct tty *tp);
216static void scinit(void);
217static void map_mode_table(char *map[], char *table, int max);
218static u_char map_mode_num(u_char mode);
219static char *get_mode_param(scr_stat *scp, u_char mode);
220static u_int scgetc(u_int flags);
221#define SCGETC_CN	1
222#define SCGETC_NONBLOCK	2
223static scr_stat *get_scr_stat(dev_t dev);
224static scr_stat *alloc_scp(void);
225static void init_scp(scr_stat *scp);
226static int get_scr_num(void);
227static timeout_t scrn_timer;
228static void stop_scrn_saver(void (*saver)(int));
229static void clear_screen(scr_stat *scp);
230static int switch_scr(scr_stat *scp, u_int next_scr);
231static void exchange_scr(void);
232static inline void move_crsr(scr_stat *scp, int x, int y);
233static void scan_esc(scr_stat *scp, u_char c);
234static void draw_cursor_image(scr_stat *scp);
235static void remove_cursor_image(scr_stat *scp);
236static void ansi_put(scr_stat *scp, u_char *buf, int len);
237static u_char *get_fstr(u_int c, u_int *len);
238static void history_to_screen(scr_stat *scp);
239static int history_up_line(scr_stat *scp);
240static int history_down_line(scr_stat *scp);
241static int mask2attr(struct term_stat *term);
242static void set_keyboard(int command, int data);
243static void update_leds(int which);
244static void set_vgaregs(char *modetable);
245static void read_vgaregs(char *buf);
246#define COMP_IDENTICAL	0
247#define COMP_SIMILAR	1
248#define COMP_DIFFERENT	2
249static int comp_vgaregs(u_char *buf1, u_char *buf2);
250static void dump_vgaregs(u_char *buf);
251#define PARAM_BUFSIZE	6
252static void set_font_mode(u_char *buf);
253static void set_normal_mode(u_char *buf);
254static void set_destructive_cursor(scr_stat *scp);
255static void set_mouse_pos(scr_stat *scp);
256static int skip_spc_right(scr_stat *scp, u_short *p);
257static int skip_spc_left(scr_stat *scp, u_short *p);
258static void mouse_cut(scr_stat *scp);
259static void mouse_cut_start(scr_stat *scp);
260static void mouse_cut_end(scr_stat *scp);
261static void mouse_cut_word(scr_stat *scp);
262static void mouse_cut_line(scr_stat *scp);
263static void mouse_cut_extend(scr_stat *scp);
264static void mouse_paste(scr_stat *scp);
265static void draw_mouse_image(scr_stat *scp);
266static void remove_mouse_image(scr_stat *scp);
267static void draw_cutmarking(scr_stat *scp);
268static void remove_cutmarking(scr_stat *scp);
269static void save_palette(void);
270static void do_bell(scr_stat *scp, int pitch, int duration);
271static timeout_t blink_screen;
272#ifdef SC_SPLASH_SCREEN
273static void toggle_splash_screen(scr_stat *scp);
274#endif
275
276struct  isa_driver scdriver = {
277    scprobe, scattach, "sc", 1
278};
279
280static	d_open_t	scopen;
281static	d_close_t	scclose;
282static	d_read_t	scread;
283static	d_write_t	scwrite;
284static	d_ioctl_t	scioctl;
285static	d_devtotty_t	scdevtotty;
286static	d_mmap_t	scmmap;
287
288#define CDEV_MAJOR 12
289static	struct cdevsw	scdevsw = {
290	scopen,		scclose,	scread,		scwrite,
291	scioctl,	nullstop,	noreset,	scdevtotty,
292	ttpoll,		scmmap,		nostrategy,	"sc",	NULL,	-1 };
293
294/*
295 * These functions need to be before calls to them so they can be inlined.
296 */
297static inline void
298draw_cursor_image(scr_stat *scp)
299{
300    u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf);
301    u_short prev_image;
302
303    /* do we have a destructive cursor ? */
304    if (flags & CHAR_CURSOR) {
305	prev_image = scp->cursor_saveunder;
306	cursor_image = *ptr & 0x00ff;
307	if (cursor_image == DEAD_CHAR)
308	    cursor_image = prev_image & 0x00ff;
309	cursor_image |= *(scp->cursor_pos) & 0xff00;
310	scp->cursor_saveunder = cursor_image;
311	/* update the cursor bitmap if the char under the cursor has changed */
312	if (prev_image != cursor_image)
313	    set_destructive_cursor(scp);
314	/* modify cursor_image */
315	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
316	    /*
317	     * When the mouse pointer is at the same position as the cursor,
318	     * the cursor bitmap needs to be updated even if the char under
319	     * the cursor hasn't changed, because the mouse pionter may
320	     * have moved by a few dots within the cursor cel.
321	     */
322	    if ((prev_image == cursor_image)
323		    && (cursor_image != *(scp->cursor_pos)))
324	        set_destructive_cursor(scp);
325	    cursor_image &= 0xff00;
326	    cursor_image |= DEAD_CHAR;
327	}
328    }
329    else {
330	cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
331	scp->cursor_saveunder = cursor_image;
332	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
333	    if ((cursor_image & 0x7000) == 0x7000) {
334		cursor_image &= 0x8fff;
335		if(!(cursor_image & 0x0700))
336		    cursor_image |= 0x0700;
337	    } else {
338		cursor_image |= 0x7000;
339		if ((cursor_image & 0x0700) == 0x0700)
340		    cursor_image &= 0xf0ff;
341	    }
342	}
343    }
344    *ptr = cursor_image;
345}
346
347static inline void
348remove_cursor_image(scr_stat *scp)
349{
350    *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder;
351}
352
353static inline void
354move_crsr(scr_stat *scp, int x, int y)
355{
356    if (x < 0)
357	x = 0;
358    if (y < 0)
359	y = 0;
360    if (x >= scp->xsize)
361	x = scp->xsize-1;
362    if (y >= scp->ysize)
363	y = scp->ysize-1;
364    scp->xpos = x;
365    scp->ypos = y;
366    scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
367}
368
369static int
370scprobe(struct isa_device *dev)
371{
372    if (!scvidprobe(dev->id_unit, dev->id_flags)) {
373	if (bootverbose)
374	    printf("sc%d: no video adapter is found.\n", dev->id_unit);
375	return (0);
376    }
377
378    sc_port = dev->id_iobase;
379    if (sckbdprobe(dev->id_unit, dev->id_flags))
380	return (IO_KBDSIZE);
381    else
382        return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
383}
384
385/* probe video adapters, return TRUE if found */
386static int
387scvidprobe(int unit, int flags)
388{
389    /*
390     * XXX don't try to `printf' anything here, the console may not have
391     * been configured yet.
392     */
393    u_short volatile *cp;
394    u_short was;
395    u_long  pa;
396    u_long  segoff;
397
398    /* do this test only once */
399    if (init_done != COLD)
400	return (Crtat != 0);
401
402    /*
403     * Finish defaulting crtc variables for a mono screen.  Crtat is a
404     * bogus common variable so that it can be shared with pcvt, so it
405     * can't be statically initialized.  XXX.
406     */
407    Crtat = (u_short *)MONO_BUF;
408    crtc_type = KD_MONO;
409    /* If CGA memory seems to work, switch to color.  */
410    cp = (u_short *)CGA_BUF;
411    was = *cp;
412    *cp = (u_short) 0xA55A;
413    if (*cp == 0xA55A) {
414	Crtat = (u_short *)CGA_BUF;
415	crtc_addr = COLOR_BASE;
416	crtc_type = KD_CGA;
417    } else {
418        cp = Crtat;
419	was = *cp;
420	*cp = (u_short) 0xA55A;
421	if (*cp != 0xA55A) {
422	    /* no screen at all, bail out */
423	    Crtat = 0;
424	    return FALSE;
425	}
426    }
427    *cp = was;
428
429    /*
430     * Check rtc and BIOS date area.
431     * XXX: don't use BIOSDATA_EQUIPMENT, it is not a dead copy
432     * of RTC_EQUIPMENT. The bit 4 and 5 of the ETC_EQUIPMENT are
433     * zeros for EGA and VGA. However, the EGA/VGA BIOS will set
434     * these bits in BIOSDATA_EQUIPMENT according to the monitor
435     * type detected.
436     */
437    switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) {	/* bit 4 and 5 */
438    case 0: /* EGA/VGA, or nothing */
439	crtc_type = KD_EGA;
440	/* the color adapter may be in the 40x25 mode... XXX */
441	break;
442    case 1: /* CGA 40x25 */
443	/* switch to the 80x25 mode? XXX */
444	/* FALL THROUGH */
445    case 2: /* CGA 80x25 */
446	/* `crtc_type' has already been set... */
447	/* crtc_type = KD_CGA; */
448	break;
449    case 3: /* MDA */
450	/* `crtc_type' has already been set... */
451	/* crtc_type = KD_MONO; */
452	break;
453    }
454
455    /* is this a VGA or higher ? */
456    outb(crtc_addr, 7);
457    if (inb(crtc_addr) == 7) {
458
459        crtc_type = KD_VGA;
460	crtc_vga = TRUE;
461	read_vgaregs(vgaregs);
462
463	/* Get the BIOS video mode pointer */
464	segoff = *(u_long *)pa_to_va(0x4a8);
465	pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
466	if (ISMAPPED(pa, sizeof(u_long))) {
467	    segoff = *(u_long *)pa_to_va(pa);
468	    pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
469	    if (ISMAPPED(pa, MODE_PARAM_SIZE))
470		video_mode_ptr = (char *)pa_to_va(pa);
471	}
472    }
473
474    return TRUE;
475}
476
477/* probe the keyboard, return TRUE if found */
478static int
479sckbdprobe(int unit, int flags)
480{
481    int codeset;
482    int c = -1;
483    int m;
484
485    sc_kbdc = kbdc_open(sc_port);
486
487    if (!kbdc_lock(sc_kbdc, TRUE)) {
488	/* driver error? */
489	printf("sc%d: unable to lock the controller.\n", unit);
490        return ((flags & DETECT_KBD) ? FALSE : TRUE);
491    }
492
493    /* discard anything left after UserConfig */
494    empty_both_buffers(sc_kbdc, 10);
495
496    /* save the current keyboard controller command byte */
497    m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
498    c = get_controller_command_byte(sc_kbdc);
499    if (c == -1) {
500	/* CONTROLLER ERROR */
501	printf("sc%d: unable to get the current command byte value.\n", unit);
502	goto fail;
503    }
504    if (bootverbose)
505	printf("sc%d: the current keyboard controller command byte %04x\n",
506	    unit, c);
507#if 0
508    /* override the keyboard lock switch */
509    c |= KBD_OVERRIDE_KBD_LOCK;
510#endif
511
512    /*
513     * The keyboard may have been screwed up by the boot block.
514     * We may just be able to recover from error by testing the controller
515     * and the keyboard port. The controller command byte needs to be saved
516     * before this recovery operation, as some controllers seem to set
517     * the command byte to particular values.
518     */
519    test_controller(sc_kbdc);
520    test_kbd_port(sc_kbdc);
521
522    /* enable the keyboard port, but disable the keyboard intr. */
523    if (!set_controller_command_byte(sc_kbdc,
524            KBD_KBD_CONTROL_BITS,
525            KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
526	/* CONTROLLER ERROR
527	 * there is very little we can do...
528	 */
529	printf("sc%d: unable to set the command byte.\n", unit);
530	goto fail;
531     }
532
533     /*
534      * Check if we have an XT keyboard before we attempt to reset it.
535      * The procedure assumes that the keyboard and the controller have
536      * been set up properly by BIOS and have not been messed up
537      * during the boot process.
538      */
539     codeset = -1;
540     if (flags & XT_KEYBD)
541	 /* the user says there is a XT keyboard */
542	 codeset = 1;
543#ifdef DETECT_XT_KEYBOARD
544     else if ((c & KBD_TRANSLATION) == 0) {
545	 /* SET_SCANCODE_SET is not always supported; ignore error */
546	 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
547		 == KBD_ACK)
548	     codeset = read_kbd_data(sc_kbdc);
549     }
550     if (bootverbose)
551         printf("sc%d: keyboard scancode set %d\n", unit, codeset);
552#endif /* DETECT_XT_KEYBOARD */
553
554    if (flags & KBD_NORESET) {
555        write_kbd_command(sc_kbdc, KBDC_ECHO);
556        if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
557            empty_both_buffers(sc_kbdc, 10);
558            test_controller(sc_kbdc);
559            test_kbd_port(sc_kbdc);
560            if (bootverbose)
561                printf("sc%d: failed to get response from the keyboard.\n",
562		    unit);
563	    goto fail;
564	}
565    } else {
566        /* reset keyboard hardware */
567        if (!reset_kbd(sc_kbdc)) {
568            /* KEYBOARD ERROR
569             * Keyboard reset may fail either because the keyboard doen't
570             * exist, or because the keyboard doesn't pass the self-test,
571             * or the keyboard controller on the motherboard and the keyboard
572             * somehow fail to shake hands. It is just possible, particularly
573             * in the last case, that the keyoard controller may be left
574             * in a hung state. test_controller() and test_kbd_port() appear
575             * to bring the keyboard controller back (I don't know why and
576             * how, though.)
577             */
578            empty_both_buffers(sc_kbdc, 10);
579            test_controller(sc_kbdc);
580            test_kbd_port(sc_kbdc);
581            /* We could disable the keyboard port and interrupt... but,
582             * the keyboard may still exist (see above).
583             */
584            if (bootverbose)
585                printf("sc%d: failed to reset the keyboard.\n", unit);
586            goto fail;
587        }
588    }
589
590    /*
591     * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
592     * such as those on the IBM ThinkPad laptop computers can be used
593     * with the standard console driver.
594     */
595    if (codeset == 1) {
596	if (send_kbd_command_and_data(
597	        sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
598	    /* XT kbd doesn't need scan code translation */
599	    c &= ~KBD_TRANSLATION;
600	} else {
601	    /* KEYBOARD ERROR
602	     * The XT kbd isn't usable unless the proper scan code set
603	     * is selected.
604	     */
605	    printf("sc%d: unable to set the XT keyboard mode.\n", unit);
606	    goto fail;
607	}
608    }
609    /* enable the keyboard port and intr. */
610    if (!set_controller_command_byte(sc_kbdc,
611            KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
612	    (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
613	        | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
614	/* CONTROLLER ERROR
615	 * This is serious; we are left with the disabled keyboard intr.
616	 */
617	printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
618	goto fail;
619    }
620
621    kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
622    kbdc_lock(sc_kbdc, FALSE);
623    return TRUE;
624
625fail:
626    if (c != -1)
627        /* try to restore the command byte as before, if possible */
628        set_controller_command_byte(sc_kbdc, 0xff, c);
629    kbdc_set_device_mask(sc_kbdc,
630        (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
631    kbdc_lock(sc_kbdc, FALSE);
632    return FALSE;
633}
634
635#if NAPM > 0
636static int
637scresume(void *dummy)
638{
639	shfts = ctls = alts = agrs = metas = accents = 0;
640	return 0;
641}
642#endif
643
644static int
645scattach(struct isa_device *dev)
646{
647    scr_stat *scp;
648    dev_t cdev = makedev(CDEV_MAJOR, 0);
649    char *p;
650#ifdef DEVFS
651    int vc;
652#endif
653
654    scinit();
655    flags = dev->id_flags;
656    if (!crtc_vga)
657	flags &= ~CHAR_CURSOR;
658
659    scp = console[0];
660
661    if (crtc_vga) {
662    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
663    }
664
665    scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
666				     M_DEVBUF, M_NOWAIT);
667
668    /* copy temporary buffer to final buffer */
669    bcopy(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
670
671    scp->cursor_pos = scp->cursor_oldpos =
672	scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
673    scp->mouse_pos = scp->mouse_oldpos =
674	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
675	    		scp->mouse_xpos/8);
676
677    /* initialize history buffer & pointers */
678    scp->history_head = scp->history_pos =
679	(u_short *)malloc(scp->history_size*sizeof(u_short),
680			  M_DEVBUF, M_NOWAIT);
681    if (scp->history_head != NULL)
682        bzero(scp->history_head, scp->history_size*sizeof(u_short));
683    scp->history = scp->history_head;
684
685    /* initialize cursor stuff */
686    if (!(scp->status & UNKNOWN_MODE))
687    	draw_cursor_image(scp);
688
689    /* get screen update going */
690    scrn_timer(NULL);
691
692    update_leds(scp->status);
693
694    if ((crtc_type == KD_VGA) && bootverbose) {
695        printf("sc%d: BIOS video mode:%d\n",
696	    dev->id_unit, *(u_char *)pa_to_va(0x449));
697        printf("sc%d: VGA registers upon power-up\n", dev->id_unit);
698        dump_vgaregs(vgaregs);
699        printf("sc%d: video mode:%d\n", dev->id_unit, scp->mode);
700        printf("sc%d: VGA registers in BIOS for mode:%d\n",
701		dev->id_unit, scp->mode);
702        dump_vgaregs(vgaregs2);
703	p = get_mode_param(scp, scp->mode);
704        if (p != NULL) {
705            printf("sc%d: VGA registers to be used for mode:%d\n",
706		dev->id_unit, scp->mode);
707            dump_vgaregs(p);
708        }
709        printf("sc%d: rows_offset:%d\n", dev->id_unit, rows_offset);
710    }
711    if ((crtc_type == KD_VGA) && (video_mode_ptr == NULL))
712        printf("sc%d: WARNING: video mode switching is only partially supported\n",
713	        dev->id_unit);
714
715    printf("sc%d: ", dev->id_unit);
716    switch(crtc_type) {
717    case KD_VGA:
718	if (crtc_addr == MONO_BASE)
719	    printf("VGA mono");
720	else
721	    printf("VGA color");
722	break;
723    case KD_EGA:
724	if (crtc_addr == MONO_BASE)
725	    printf("EGA mono");
726	else
727	    printf("EGA color");
728	break;
729    case KD_CGA:
730	printf("CGA");
731	break;
732    case KD_MONO:
733    case KD_HERCULES:
734    default:
735	printf("MDA/hercules");
736	break;
737    }
738    printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags);
739
740#if NAPM > 0
741    scp->r_hook.ah_fun = scresume;
742    scp->r_hook.ah_arg = NULL;
743    scp->r_hook.ah_name = "system keyboard";
744    scp->r_hook.ah_order = APM_MID_ORDER;
745    apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
746#endif
747
748    cdevsw_add(&cdev, &scdevsw, NULL);
749
750#ifdef DEVFS
751    for (vc = 0; vc < MAXCONS; vc++)
752        sc_devfs_token[vc] = devfs_add_devswf(&scdevsw, vc, DV_CHR, UID_ROOT,
753					      GID_WHEEL, 0600, "ttyv%n", vc);
754#endif
755    return 0;
756}
757
758struct tty
759*scdevtotty(dev_t dev)
760{
761    int unit = minor(dev);
762
763    if (init_done == COLD)
764	return(NULL);
765    if (unit == SC_CONSOLE)
766	return CONSOLE_TTY;
767    if (unit == SC_MOUSE)
768	return MOUSE_TTY;
769    if (unit >= MAXCONS || unit < 0)
770	return(NULL);
771    return VIRTUAL_TTY(unit);
772}
773
774int
775scopen(dev_t dev, int flag, int mode, struct proc *p)
776{
777    struct tty *tp = scdevtotty(dev);
778
779    if (!tp)
780	return(ENXIO);
781
782    tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
783    tp->t_param = scparam;
784    tp->t_dev = dev;
785    if (!(tp->t_state & TS_ISOPEN)) {
786	ttychars(tp);
787        /* Use the current setting of the <-- key as default VERASE. */
788        /* If the Delete key is preferable, an stty is necessary     */
789        tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
790	tp->t_iflag = TTYDEF_IFLAG;
791	tp->t_oflag = TTYDEF_OFLAG;
792	tp->t_cflag = TTYDEF_CFLAG;
793	tp->t_lflag = TTYDEF_LFLAG;
794	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
795	scparam(tp, &tp->t_termios);
796	ttsetwater(tp);
797	(*linesw[tp->t_line].l_modem)(tp, 1);
798    	if (minor(dev) == SC_MOUSE)
799	    mouse_level = 0;		/* XXX */
800    }
801    else
802	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
803	    return(EBUSY);
804    if (minor(dev) < MAXCONS && !console[minor(dev)]) {
805	console[minor(dev)] = alloc_scp();
806    }
807    if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
808	tp->t_winsize.ws_col = console[minor(dev)]->xsize;
809	tp->t_winsize.ws_row = console[minor(dev)]->ysize;
810    }
811    return ((*linesw[tp->t_line].l_open)(dev, tp));
812}
813
814int
815scclose(dev_t dev, int flag, int mode, struct proc *p)
816{
817    struct tty *tp = scdevtotty(dev);
818    struct scr_stat *scp;
819
820    if (!tp)
821	return(ENXIO);
822    if (minor(dev) < MAXCONS) {
823	scp = get_scr_stat(tp->t_dev);
824	if (scp->status & SWITCH_WAIT_ACQ)
825	    wakeup((caddr_t)&scp->smode);
826#if not_yet_done
827	if (scp == &main_console) {
828	    scp->pid = 0;
829	    scp->proc = NULL;
830	    scp->smode.mode = VT_AUTO;
831	}
832	else {
833	    free(scp->scr_buf, M_DEVBUF);
834	    if (scp->history != NULL) {
835		free(scp->history, M_DEVBUF);
836		if (scp->history_size / scp->xsize
837			> imax(SC_HISTORY_SIZE, scp->ysize))
838		    extra_history_size += scp->history_size / scp->xsize
839			- imax(SC_HISTORY_SIZE, scp->ysize);
840	    }
841	    free(scp, M_DEVBUF);
842	    console[minor(dev)] = NULL;
843	}
844#else
845	scp->pid = 0;
846	scp->proc = NULL;
847	scp->smode.mode = VT_AUTO;
848#endif
849    }
850    spltty();
851    (*linesw[tp->t_line].l_close)(tp, flag);
852    ttyclose(tp);
853    spl0();
854    return(0);
855}
856
857int
858scread(dev_t dev, struct uio *uio, int flag)
859{
860    struct tty *tp = scdevtotty(dev);
861
862    if (!tp)
863	return(ENXIO);
864    return((*linesw[tp->t_line].l_read)(tp, uio, flag));
865}
866
867int
868scwrite(dev_t dev, struct uio *uio, int flag)
869{
870    struct tty *tp = scdevtotty(dev);
871
872    if (!tp)
873	return(ENXIO);
874    return((*linesw[tp->t_line].l_write)(tp, uio, flag));
875}
876
877void
878scintr(int unit)
879{
880    static struct tty *cur_tty;
881    int c, len;
882    u_char *cp;
883
884    /* make screensaver happy */
885    scrn_time_stamp = mono_time.tv_sec;
886
887    /*
888     * Loop while there is still input to get from the keyboard.
889     * I don't think this is nessesary, and it doesn't fix
890     * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
891     */
892    while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
893
894	cur_tty = VIRTUAL_TTY(get_scr_num());
895	if (!(cur_tty->t_state & TS_ISOPEN))
896	    if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
897		continue;
898
899	switch (c & 0xff00) {
900	case 0x0000: /* normal key */
901	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
902	    break;
903	case FKEY:  /* function key, return string */
904	    if (cp = get_fstr((u_int)c, (u_int *)&len)) {
905	    	while (len-- >  0)
906		    (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
907	    }
908	    break;
909	case MKEY:  /* meta is active, prepend ESC */
910	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
911	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
912	    break;
913	case BKEY:  /* backtab fixed sequence (esc [ Z) */
914	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
915	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
916	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
917	    break;
918	}
919    }
920
921    if (cur_console->status & MOUSE_ENABLED) {
922	cur_console->status &= ~MOUSE_VISIBLE;
923	remove_mouse_image(cur_console);
924    }
925}
926
927static int
928scparam(struct tty *tp, struct termios *t)
929{
930    tp->t_ispeed = t->c_ispeed;
931    tp->t_ospeed = t->c_ospeed;
932    tp->t_cflag = t->c_cflag;
933    return 0;
934}
935
936int
937scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
938{
939    int error;
940    u_int i;
941    struct tty *tp;
942    scr_stat *scp;
943    u_short *usp;
944    char *mp;
945    int s;
946
947    tp = scdevtotty(dev);
948    if (!tp)
949	return ENXIO;
950    scp = get_scr_stat(tp->t_dev);
951
952    /* If there is a user_ioctl function call that first */
953    if (sc_user_ioctl) {
954	if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p))
955	    return error;
956    }
957
958    switch (cmd) {  		/* process console hardware related ioctl's */
959
960    case GIO_ATTR:      	/* get current attributes */
961	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
962	return 0;
963
964    case GIO_COLOR:     	/* is this a color console ? */
965	if (crtc_addr == COLOR_BASE)
966	    *(int*)data = 1;
967	else
968	    *(int*)data = 0;
969	return 0;
970
971    case CONS_CURRENT:  	/* get current adapter type */
972	*(int *)data = crtc_type;
973	return 0;
974
975    case CONS_GET:      	/* get current video mode */
976	*(int*)data = scp->mode;
977	return 0;
978
979    case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
980	if (*(int *)data < 0)
981            return EINVAL;
982	scrn_blank_time = *(int *)data;
983	if (scrn_blank_time == 0)
984	    scrn_time_stamp = mono_time.tv_sec;
985	return 0;
986
987    case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
988	if ((*(int*)data) & 0x01)
989	    flags |= BLINK_CURSOR;
990	else
991	    flags &= ~BLINK_CURSOR;
992	if ((*(int*)data) & 0x02) {
993	    if (!crtc_vga)
994		return ENXIO;
995	    flags |= CHAR_CURSOR;
996	} else
997	    flags &= ~CHAR_CURSOR;
998	/*
999	 * The cursor shape is global property; all virtual consoles
1000	 * are affected. Update the cursor in the current console...
1001	 */
1002	if (!(cur_console->status & UNKNOWN_MODE)) {
1003            remove_cursor_image(cur_console);
1004	    if (flags & CHAR_CURSOR)
1005	        set_destructive_cursor(cur_console);
1006	    draw_cursor_image(cur_console);
1007	}
1008	return 0;
1009
1010    case CONS_BELLTYPE: 	/* set bell type sound/visual */
1011	if (*data)
1012	    flags |= VISUAL_BELL;
1013	else
1014	    flags &= ~VISUAL_BELL;
1015	return 0;
1016
1017    case CONS_HISTORY:  	/* set history size */
1018	if (*(int *)data > 0) {
1019	    int lines;	/* buffer size to allocate */
1020	    int lines0;	/* current buffer size */
1021
1022	    lines = imax(*(int *)data, scp->ysize);
1023	    lines0 = (scp->history != NULL) ?
1024		      scp->history_size / scp->xsize : scp->ysize;
1025	    /*
1026	     * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
1027	     * lines or scp->ysize lines, whichever is larger. A value
1028	     * greater than that is allowed, subject to extra_history_size.
1029	     */
1030	    if (lines > imax(lines0, SC_HISTORY_SIZE) + extra_history_size)
1031                return EINVAL;
1032            if (cur_console->status & BUFFER_SAVED)
1033                return EBUSY;
1034	    usp = scp->history;
1035	    scp->history = NULL;
1036	    if (usp != NULL)
1037		free(usp, M_DEVBUF);
1038	    scp->history_size = lines * scp->xsize;
1039	    /*
1040	     * extra_history_size +=
1041	     *    (lines0 > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1042	     *     lines0 - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1043	     * extra_history_size -=
1044	     *    (lines > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1045	     *	   lines - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1046	     * lines0 >= ysize && lines >= ysize... Hey, the above can be
1047	     * reduced to the following...
1048	     */
1049	    extra_history_size +=
1050		imax(lines0, SC_HISTORY_SIZE) - imax(lines, SC_HISTORY_SIZE);
1051	    usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1052				    M_DEVBUF, M_WAITOK);
1053	    bzero(usp, scp->history_size * sizeof(u_short));
1054	    scp->history_head = scp->history_pos = usp;
1055	    scp->history = usp;
1056	    return 0;
1057	}
1058	else
1059	    return EINVAL;
1060
1061    case CONS_MOUSECTL:		/* control mouse arrow */
1062    {
1063	/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
1064	static butmap[8] = {
1065            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP
1066		| MOUSE_MSC_BUTTON3UP,
1067            MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1068            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1069            MOUSE_MSC_BUTTON3UP,
1070            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1071            MOUSE_MSC_BUTTON2UP,
1072            MOUSE_MSC_BUTTON1UP,
1073            0,
1074	};
1075	mouse_info_t *mouse = (mouse_info_t*)data;
1076
1077	if (!crtc_vga)
1078	    return ENODEV;
1079
1080	switch (mouse->operation) {
1081	case MOUSE_MODE:
1082	    if (ISSIGVALID(mouse->u.mode.signal)) {
1083		scp->mouse_signal = mouse->u.mode.signal;
1084		scp->mouse_proc = p;
1085		scp->mouse_pid = p->p_pid;
1086	    }
1087	    else {
1088		scp->mouse_signal = 0;
1089		scp->mouse_proc = NULL;
1090		scp->mouse_pid = 0;
1091	    }
1092	    break;
1093
1094	case MOUSE_SHOW:
1095	    if (!(scp->status & MOUSE_ENABLED)) {
1096		scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
1097		scp->mouse_oldpos = scp->mouse_pos;
1098		mark_all(scp);
1099	    }
1100	    else
1101		return EINVAL;
1102	    break;
1103
1104	case MOUSE_HIDE:
1105	    if (scp->status & MOUSE_ENABLED) {
1106		scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
1107		mark_all(scp);
1108	    }
1109	    else
1110		return EINVAL;
1111	    break;
1112
1113	case MOUSE_MOVEABS:
1114	    scp->mouse_xpos = mouse->u.data.x;
1115	    scp->mouse_ypos = mouse->u.data.y;
1116	    set_mouse_pos(scp);
1117	    break;
1118
1119	case MOUSE_MOVEREL:
1120	    scp->mouse_xpos += mouse->u.data.x;
1121	    scp->mouse_ypos += mouse->u.data.y;
1122	    set_mouse_pos(scp);
1123	    break;
1124
1125	case MOUSE_GETINFO:
1126	    mouse->u.data.x = scp->mouse_xpos;
1127	    mouse->u.data.y = scp->mouse_ypos;
1128	    mouse->u.data.z = 0;
1129	    mouse->u.data.buttons = scp->mouse_buttons;
1130	    break;
1131
1132	case MOUSE_ACTION:
1133	case MOUSE_MOTION_EVENT:
1134	    /* this should maybe only be settable from /dev/consolectl SOS */
1135	    /* send out mouse event on /dev/sysmouse */
1136
1137	    mouse_status.dx += mouse->u.data.x;
1138	    mouse_status.dy += mouse->u.data.y;
1139	    mouse_status.dz += mouse->u.data.z;
1140	    if (mouse->operation == MOUSE_ACTION)
1141	        mouse_status.button = mouse->u.data.buttons;
1142	    mouse_status.flags |=
1143		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1144		    MOUSE_POSCHANGED : 0)
1145		| (mouse_status.obutton ^ mouse_status.button);
1146
1147	    if (cur_console->status & MOUSE_ENABLED)
1148	    	cur_console->status |= MOUSE_VISIBLE;
1149
1150	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1151		u_char buf[MOUSE_SYS_PACKETSIZE];
1152		int j;
1153
1154		/* the first five bytes are compatible with MouseSystems' */
1155		buf[0] = MOUSE_MSC_SYNC
1156		    | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1157		j = imax(imin(mouse->u.data.x, 255), -256);
1158		buf[1] = j >> 1;
1159		buf[3] = j - buf[1];
1160		j = -imax(imin(mouse->u.data.y, 255), -256);
1161		buf[2] = j >> 1;
1162		buf[4] = j - buf[2];
1163		for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
1164	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1165		if (mouse_level >= 1) { 	/* extended part */
1166		    j = imax(imin(mouse->u.data.z, 127), -128);
1167		    buf[5] = (j >> 1) & 0x7f;
1168		    buf[6] = (j - (j >> 1)) & 0x7f;
1169		    /* buttons 4-10 */
1170		    buf[7] = (~mouse_status.button >> 3) & 0x7f;
1171		    for (j = MOUSE_MSC_PACKETSIZE;
1172			 j < MOUSE_SYS_PACKETSIZE; j++)
1173	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1174		}
1175	    }
1176
1177	    if (cur_console->mouse_signal) {
1178		cur_console->mouse_buttons = mouse->u.data.buttons;
1179    		/* has controlling process died? */
1180		if (cur_console->mouse_proc &&
1181		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1182		    	cur_console->mouse_signal = 0;
1183			cur_console->mouse_proc = NULL;
1184			cur_console->mouse_pid = 0;
1185		}
1186		else
1187		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1188	    }
1189	    else if (mouse->operation == MOUSE_ACTION) {
1190		/* process button presses */
1191		if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
1192		    !(cur_console->status & UNKNOWN_MODE)) {
1193		    cur_console->mouse_buttons = mouse->u.data.buttons;
1194		    if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
1195			mouse_cut_start(cur_console);
1196		    else
1197			mouse_cut_end(cur_console);
1198		    if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
1199			cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
1200			mouse_paste(cur_console);
1201		}
1202	    }
1203
1204	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
1205		cur_console->mouse_xpos += mouse->u.data.x;
1206		cur_console->mouse_ypos += mouse->u.data.y;
1207		set_mouse_pos(cur_console);
1208	    }
1209
1210	    break;
1211
1212	case MOUSE_BUTTON_EVENT:
1213	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
1214		return EINVAL;
1215	    if (mouse->u.event.value < 0)
1216		return EINVAL;
1217
1218	    if (mouse->u.event.value > 0) {
1219	        cur_console->mouse_buttons |= mouse->u.event.id;
1220	        mouse_status.button |= mouse->u.event.id;
1221	    } else {
1222	        cur_console->mouse_buttons &= ~mouse->u.event.id;
1223	        mouse_status.button &= ~mouse->u.event.id;
1224	    }
1225	    mouse_status.flags |=
1226		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1227		    MOUSE_POSCHANGED : 0)
1228		| (mouse_status.obutton ^ mouse_status.button);
1229
1230	    if (cur_console->status & MOUSE_ENABLED)
1231	    	cur_console->status |= MOUSE_VISIBLE;
1232
1233	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1234		u_char buf[8];
1235		int i;
1236
1237		buf[0] = MOUSE_MSC_SYNC
1238			 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1239		buf[7] = (~mouse_status.button >> 3) & 0x7f;
1240		buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
1241		for (i = 0;
1242		     i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
1243					     : MOUSE_MSC_PACKETSIZE); i++)
1244	    	    (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
1245	    }
1246
1247	    if (cur_console->mouse_signal) {
1248		if (cur_console->mouse_proc &&
1249		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1250		    	cur_console->mouse_signal = 0;
1251			cur_console->mouse_proc = NULL;
1252			cur_console->mouse_pid = 0;
1253		}
1254		else
1255		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1256		break;
1257	    }
1258
1259	    if (cur_console->status & UNKNOWN_MODE)
1260		break;
1261
1262	    switch (mouse->u.event.id) {
1263	    case MOUSE_BUTTON1DOWN:
1264	        switch (mouse->u.event.value % 4) {
1265		case 0:	/* up */
1266		    mouse_cut_end(cur_console);
1267		    break;
1268		case 1:
1269		    mouse_cut_start(cur_console);
1270		    break;
1271		case 2:
1272		    mouse_cut_word(cur_console);
1273		    break;
1274		case 3:
1275		    mouse_cut_line(cur_console);
1276		    break;
1277		}
1278		break;
1279	    case MOUSE_BUTTON2DOWN:
1280	        switch (mouse->u.event.value) {
1281		case 0:	/* up */
1282		    break;
1283		default:
1284		    mouse_paste(cur_console);
1285		    break;
1286		}
1287		break;
1288	    case MOUSE_BUTTON3DOWN:
1289	        switch (mouse->u.event.value) {
1290		case 0:	/* up */
1291		    if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
1292		        mouse_cut_end(cur_console);
1293		    break;
1294		default:
1295		    mouse_cut_extend(cur_console);
1296		    break;
1297		}
1298		break;
1299	    }
1300	    break;
1301
1302	default:
1303	    return EINVAL;
1304	}
1305	/* make screensaver happy */
1306	scrn_time_stamp = mono_time.tv_sec;
1307	return 0;
1308    }
1309
1310    /* MOUSE_XXX: /dev/sysmouse ioctls */
1311    case MOUSE_GETHWINFO:	/* get device information */
1312    {
1313	mousehw_t *hw = (mousehw_t *)data;
1314
1315	if (tp != MOUSE_TTY)
1316	    return ENOTTY;
1317	hw->buttons = 10;		/* XXX unknown */
1318	hw->iftype = MOUSE_IF_SYSMOUSE;
1319	hw->type = MOUSE_MOUSE;
1320	hw->model = MOUSE_MODEL_GENERIC;
1321	hw->hwid = 0;
1322	return 0;
1323    }
1324
1325    case MOUSE_GETMODE:		/* get protocol/mode */
1326    {
1327	mousemode_t *mode = (mousemode_t *)data;
1328
1329	if (tp != MOUSE_TTY)
1330	    return ENOTTY;
1331	mode->level = mouse_level;
1332	switch (mode->level) {
1333	case 0:
1334	    /* at this level, sysmouse emulates MouseSystems protocol */
1335	    mode->protocol = MOUSE_PROTO_MSC;
1336	    mode->rate = -1;		/* unknown */
1337	    mode->resolution = -1;	/* unknown */
1338	    mode->accelfactor = 0;	/* disabled */
1339	    mode->packetsize = MOUSE_MSC_PACKETSIZE;
1340	    mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
1341	    mode->syncmask[1] = MOUSE_MSC_SYNC;
1342	    break;
1343
1344	case 1:
1345	    /* at this level, sysmouse uses its own protocol */
1346	    mode->protocol = MOUSE_PROTO_SYSMOUSE;
1347	    mode->rate = -1;
1348	    mode->resolution = -1;
1349	    mode->accelfactor = 0;
1350	    mode->packetsize = MOUSE_SYS_PACKETSIZE;
1351	    mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
1352	    mode->syncmask[1] = MOUSE_SYS_SYNC;
1353	    break;
1354	}
1355	return 0;
1356    }
1357
1358    case MOUSE_SETMODE:		/* set protocol/mode */
1359    {
1360	mousemode_t *mode = (mousemode_t *)data;
1361
1362	if (tp != MOUSE_TTY)
1363	    return ENOTTY;
1364	if ((mode->level < 0) || (mode->level > 1))
1365	    return EINVAL;
1366	mouse_level = mode->level;
1367	return 0;
1368    }
1369
1370    case MOUSE_GETLEVEL:	/* get operation level */
1371	if (tp != MOUSE_TTY)
1372	    return ENOTTY;
1373	*(int *)data = mouse_level;
1374	return 0;
1375
1376    case MOUSE_SETLEVEL:	/* set operation level */
1377	if (tp != MOUSE_TTY)
1378	    return ENOTTY;
1379	if ((*(int *)data  < 0) || (*(int *)data > 1))
1380	    return EINVAL;
1381	mouse_level = *(int *)data;
1382	return 0;
1383
1384    case MOUSE_GETSTATUS:	/* get accumulated mouse events */
1385	if (tp != MOUSE_TTY)
1386	    return ENOTTY;
1387	s = spltty();
1388	*(mousestatus_t *)data = mouse_status;
1389	mouse_status.flags = 0;
1390	mouse_status.obutton = mouse_status.button;
1391	mouse_status.dx = 0;
1392	mouse_status.dy = 0;
1393	mouse_status.dz = 0;
1394	splx(s);
1395	return 0;
1396
1397#if notyet
1398    case MOUSE_GETVARS:		/* get internal mouse variables */
1399    case MOUSE_SETVARS:		/* set internal mouse variables */
1400	if (tp != MOUSE_TTY)
1401	    return ENOTTY;
1402	return ENODEV;
1403#endif
1404
1405    case MOUSE_READSTATE:	/* read status from the device */
1406    case MOUSE_READDATA:	/* read data from the device */
1407	if (tp != MOUSE_TTY)
1408	    return ENOTTY;
1409	return ENODEV;
1410
1411    case CONS_GETINFO:  	/* get current (virtual) console info */
1412    {
1413	vid_info_t *ptr = (vid_info_t*)data;
1414	if (ptr->size == sizeof(struct vid_info)) {
1415	    ptr->m_num = get_scr_num();
1416	    ptr->mv_col = scp->xpos;
1417	    ptr->mv_row = scp->ypos;
1418	    ptr->mv_csz = scp->xsize;
1419	    ptr->mv_rsz = scp->ysize;
1420	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
1421	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
1422	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
1423	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
1424	    ptr->mv_grfc.fore = 0;      /* not supported */
1425	    ptr->mv_grfc.back = 0;      /* not supported */
1426	    ptr->mv_ovscan = scp->border;
1427	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
1428	    return 0;
1429	}
1430	return EINVAL;
1431    }
1432
1433    case CONS_GETVERS:  	/* get version number */
1434	*(int*)data = 0x200;    /* version 2.0 */
1435	return 0;
1436
1437    /* VGA TEXT MODES */
1438    case SW_VGA_C40x25:
1439    case SW_VGA_C80x25: case SW_VGA_M80x25:
1440    case SW_VGA_C80x30: case SW_VGA_M80x30:
1441    case SW_VGA_C80x50: case SW_VGA_M80x50:
1442    case SW_VGA_C80x60: case SW_VGA_M80x60:
1443    case SW_B40x25:     case SW_C40x25:
1444    case SW_B80x25:     case SW_C80x25:
1445    case SW_ENH_B40x25: case SW_ENH_C40x25:
1446    case SW_ENH_B80x25: case SW_ENH_C80x25:
1447    case SW_ENH_B80x43: case SW_ENH_C80x43:
1448    case SW_EGAMONO80x25:
1449
1450	if (!crtc_vga)
1451 	    return ENODEV;
1452 	mp = get_mode_param(scp, cmd & 0xff);
1453 	if (mp == NULL)
1454 	    return ENODEV;
1455
1456	if (scp->history != NULL)
1457	    i = imax(scp->history_size / scp->xsize
1458		     - imax(SC_HISTORY_SIZE, scp->ysize), 0);
1459	else
1460	    i = 0;
1461	switch (cmd & 0xff) {
1462	case M_VGA_C80x60: case M_VGA_M80x60:
1463	    if (!(fonts_loaded & FONT_8))
1464		return EINVAL;
1465	    scp->xsize = 80;
1466	    scp->ysize = 60;
1467	    break;
1468	case M_VGA_C80x50: case M_VGA_M80x50:
1469	    if (!(fonts_loaded & FONT_8))
1470		return EINVAL;
1471	    scp->xsize = 80;
1472	    scp->ysize = 50;
1473	    break;
1474	case M_ENH_B80x43: case M_ENH_C80x43:
1475	    if (!(fonts_loaded & FONT_8))
1476		return EINVAL;
1477	    scp->xsize = 80;
1478	    scp->ysize = 43;
1479	    break;
1480	case M_VGA_C80x30: case M_VGA_M80x30:
1481	    scp->xsize = 80;
1482	    scp->ysize = 30;
1483	    break;
1484	case M_ENH_C40x25: case M_ENH_B40x25:
1485	case M_ENH_C80x25: case M_ENH_B80x25:
1486	case M_EGAMONO80x25:
1487	    if (!(fonts_loaded & FONT_14))
1488		return EINVAL;
1489	    /* FALL THROUGH */
1490	default:
1491	    if ((cmd & 0xff) > M_VGA_CG320)
1492		return EINVAL;
1493            scp->xsize = mp[0];
1494            scp->ysize = mp[1] + rows_offset;
1495	    break;
1496	}
1497	scp->mode = cmd & 0xff;
1498	free(scp->scr_buf, M_DEVBUF);
1499	scp->scr_buf = (u_short *)
1500	    malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK);
1501    	scp->cursor_pos = scp->cursor_oldpos =
1502	    scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
1503    	scp->mouse_pos = scp->mouse_oldpos =
1504	    scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
1505	    scp->mouse_xpos/8);
1506	free(cut_buffer, M_DEVBUF);
1507    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
1508	cut_buffer[0] = 0x00;
1509	usp = scp->history;
1510	scp->history = NULL;
1511	if (usp != NULL) {
1512	    free(usp, M_DEVBUF);
1513	    extra_history_size += i;
1514	}
1515	scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
1516	usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1517				M_DEVBUF, M_NOWAIT);
1518	if (usp != NULL)
1519	    bzero(usp, scp->history_size * sizeof(u_short));
1520	scp->history_head = scp->history_pos = usp;
1521	scp->history = usp;
1522	if (scp == cur_console)
1523	    set_mode(scp);
1524	scp->status &= ~UNKNOWN_MODE;
1525	clear_screen(scp);
1526
1527	if (tp->t_winsize.ws_col != scp->xsize
1528	    || tp->t_winsize.ws_row != scp->ysize) {
1529	    tp->t_winsize.ws_col = scp->xsize;
1530	    tp->t_winsize.ws_row = scp->ysize;
1531	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
1532	}
1533	return 0;
1534
1535    /* GRAPHICS MODES */
1536    case SW_BG320:     case SW_BG640:
1537    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
1538    case SW_CG640x350: case SW_ENH_CG640:
1539    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
1540
1541	if (!crtc_vga)
1542	    return ENODEV;
1543	mp = get_mode_param(scp, cmd & 0xff);
1544	if (mp == NULL)
1545	    return ENODEV;
1546
1547	scp->mode = cmd & 0xFF;
1548	scp->xpixel = mp[0] * 8;
1549	scp->ypixel = (mp[1] + rows_offset) * mp[2];
1550	if (scp == cur_console)
1551	    set_mode(scp);
1552	scp->status |= UNKNOWN_MODE;    /* graphics mode */
1553	/* clear_graphics();*/
1554
1555	if (tp->t_winsize.ws_xpixel != scp->xpixel
1556	    || tp->t_winsize.ws_ypixel != scp->ypixel) {
1557	    tp->t_winsize.ws_xpixel = scp->xpixel;
1558	    tp->t_winsize.ws_ypixel = scp->ypixel;
1559	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
1560	}
1561	return 0;
1562
1563    case SW_VGA_MODEX:
1564	if (!crtc_vga)
1565	    return ENODEV;
1566	mp = get_mode_param(scp, cmd & 0xff);
1567	if (mp == NULL)
1568	    return ENODEV;
1569
1570	scp->mode = cmd & 0xFF;
1571	if (scp == cur_console)
1572	    set_mode(scp);
1573	scp->status |= UNKNOWN_MODE;    /* graphics mode */
1574	/* clear_graphics();*/
1575	scp->xpixel = 320;
1576	scp->ypixel = 240;
1577	if (tp->t_winsize.ws_xpixel != scp->xpixel
1578	    || tp->t_winsize.ws_ypixel != scp->ypixel) {
1579	    tp->t_winsize.ws_xpixel = scp->xpixel;
1580	    tp->t_winsize.ws_ypixel = scp->ypixel;
1581	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
1582	}
1583	return 0;
1584
1585    case VT_SETMODE:    	/* set screen switcher mode */
1586    {
1587	struct vt_mode *mode;
1588
1589	mode = (struct vt_mode *)data;
1590	if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
1591	    ISSIGVALID(mode->frsig)) {
1592	    bcopy(data, &scp->smode, sizeof(struct vt_mode));
1593	    if (scp->smode.mode == VT_PROCESS) {
1594		scp->proc = p;
1595		scp->pid = scp->proc->p_pid;
1596	    }
1597	    return 0;
1598	} else
1599	    return EINVAL;
1600    }
1601
1602    case VT_GETMODE:    	/* get screen switcher mode */
1603	bcopy(&scp->smode, data, sizeof(struct vt_mode));
1604	return 0;
1605
1606    case VT_RELDISP:    	/* screen switcher ioctl */
1607	switch(*data) {
1608	case VT_FALSE:  	/* user refuses to release screen, abort */
1609	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1610		old_scp->status &= ~SWITCH_WAIT_REL;
1611		switch_in_progress = FALSE;
1612		return 0;
1613	    }
1614	    return EINVAL;
1615
1616	case VT_TRUE:   	/* user has released screen, go on */
1617	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1618		scp->status &= ~SWITCH_WAIT_REL;
1619		exchange_scr();
1620		if (new_scp->smode.mode == VT_PROCESS) {
1621		    new_scp->status |= SWITCH_WAIT_ACQ;
1622		    psignal(new_scp->proc, new_scp->smode.acqsig);
1623		}
1624		else
1625		    switch_in_progress = FALSE;
1626		return 0;
1627	    }
1628	    return EINVAL;
1629
1630	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
1631	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1632		scp->status &= ~SWITCH_WAIT_ACQ;
1633		switch_in_progress = FALSE;
1634		return 0;
1635	    }
1636	    return EINVAL;
1637
1638	default:
1639	    return EINVAL;
1640	}
1641	/* NOT REACHED */
1642
1643    case VT_OPENQRY:    	/* return free virtual console */
1644	for (i = 0; i < MAXCONS; i++) {
1645	    tp = VIRTUAL_TTY(i);
1646	    if (!(tp->t_state & TS_ISOPEN)) {
1647		*data = i + 1;
1648		return 0;
1649	    }
1650	}
1651	return EINVAL;
1652
1653    case VT_ACTIVATE:   	/* switch to screen *data */
1654	return switch_scr(scp, (*data) - 1);
1655
1656    case VT_WAITACTIVE: 	/* wait for switch to occur */
1657	if (*data > MAXCONS || *data < 0)
1658	    return EINVAL;
1659	if (minor(dev) == (*data) - 1)
1660	    return 0;
1661	if (*data == 0) {
1662	    if (scp == cur_console)
1663		return 0;
1664	}
1665	else
1666	    scp = console[(*data) - 1];
1667	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1668			     "waitvt", 0)) == ERESTART) ;
1669	return error;
1670
1671    case VT_GETACTIVE:
1672	*data = get_scr_num()+1;
1673	return 0;
1674
1675    case KDENABIO:      	/* allow io operations */
1676	error = suser(p->p_ucred, &p->p_acflag);
1677	if (error != 0)
1678	    return error;
1679	if (securelevel > 0)
1680	    return EPERM;
1681	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1682	return 0;
1683
1684    case KDDISABIO:     	/* disallow io operations (default) */
1685	p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1686	return 0;
1687
1688    case KDSETMODE:     	/* set current mode of this (virtual) console */
1689	switch (*data) {
1690	case KD_TEXT:   	/* switch to TEXT (known) mode */
1691	    /* restore fonts & palette ! */
1692	    if (crtc_vga) {
1693		if (fonts_loaded & FONT_8)
1694		    copy_font(LOAD, FONT_8, font_8);
1695		if (fonts_loaded & FONT_14)
1696		    copy_font(LOAD, FONT_14, font_14);
1697		if (fonts_loaded & FONT_16)
1698		    copy_font(LOAD, FONT_16, font_16);
1699		load_palette(palette);
1700	    }
1701
1702	    /* move hardware cursor out of the way */
1703	    outb(crtc_addr, 14);
1704	    outb(crtc_addr + 1, 0xff);
1705	    outb(crtc_addr, 15);
1706	    outb(crtc_addr + 1, 0xff);
1707
1708	    /* FALL THROUGH */
1709
1710	case KD_TEXT1:  	/* switch to TEXT (known) mode */
1711	    /* no restore fonts & palette */
1712	    if (crtc_vga)
1713		set_mode(scp);
1714	    scp->status &= ~UNKNOWN_MODE;
1715	    clear_screen(scp);
1716	    return 0;
1717
1718	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
1719	    scp->status |= UNKNOWN_MODE;
1720	    return 0;
1721	default:
1722	    return EINVAL;
1723	}
1724	/* NOT REACHED */
1725
1726    case KDGETMODE:     	/* get current mode of this (virtual) console */
1727	*data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
1728	return 0;
1729
1730    case KDSBORDER:     	/* set border color of this (virtual) console */
1731	scp->border = *data;
1732	if (scp == cur_console)
1733	    set_border(scp->border);
1734	return 0;
1735
1736    case KDSKBSTATE:    	/* set keyboard state (locks) */
1737	if (*data >= 0 && *data <= LOCK_KEY_MASK) {
1738	    scp->status &= ~LOCK_KEY_MASK;
1739	    scp->status |= *data;
1740	    if (scp == cur_console)
1741		update_leds(scp->status);
1742	    return 0;
1743	}
1744	return EINVAL;
1745
1746    case KDGKBSTATE:    	/* get keyboard state (locks) */
1747	*data = scp->status & LOCK_KEY_MASK;
1748	return 0;
1749
1750    case KDSETRAD:      	/* set keyboard repeat & delay rates */
1751	if (*data & 0x80)
1752	    return EINVAL;
1753	if (sc_kbdc != NULL)
1754	    set_keyboard(KBDC_SET_TYPEMATIC, *data);
1755	return 0;
1756
1757    case KDSKBMODE:     	/* set keyboard mode */
1758	switch (*data) {
1759	case K_RAW: 		/* switch to RAW scancode mode */
1760	    scp->status &= ~KBD_CODE_MODE;
1761	    scp->status |= KBD_RAW_MODE;
1762	    return 0;
1763
1764	case K_CODE: 		/* switch to CODE mode */
1765	    scp->status &= ~KBD_RAW_MODE;
1766	    scp->status |= KBD_CODE_MODE;
1767	    return 0;
1768
1769	case K_XLATE:   	/* switch to XLT ascii mode */
1770	    if (scp == cur_console && scp->status & KBD_RAW_MODE)
1771		shfts = ctls = alts = agrs = metas = accents = 0;
1772	    scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
1773	    return 0;
1774	default:
1775	    return EINVAL;
1776	}
1777	/* NOT REACHED */
1778
1779    case KDGKBMODE:     	/* get keyboard mode */
1780	*data = (scp->status & KBD_RAW_MODE) ? K_RAW :
1781		((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
1782	return 0;
1783
1784    case KDMKTONE:      	/* sound the bell */
1785	if (*(int*)data)
1786	    do_bell(scp, (*(int*)data)&0xffff,
1787		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1788	else
1789	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1790	return 0;
1791
1792    case KIOCSOUND:     	/* make tone (*data) hz */
1793	if (scp == cur_console) {
1794	    if (*(int*)data) {
1795		int pitch = timer_freq / *(int*)data;
1796
1797		/* set command for counter 2, 2 byte write */
1798		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1799		    return EBUSY;
1800
1801		/* set pitch */
1802		outb(TIMER_CNTR2, pitch);
1803		outb(TIMER_CNTR2, (pitch>>8));
1804
1805		/* enable counter 2 output to speaker */
1806		outb(IO_PPI, inb(IO_PPI) | 3);
1807	    }
1808	    else {
1809		/* disable counter 2 output to speaker */
1810		outb(IO_PPI, inb(IO_PPI) & 0xFC);
1811		release_timer2();
1812	    }
1813	}
1814	return 0;
1815
1816    case KDGKBTYPE:     	/* get keyboard type */
1817	*data = 0;  		/* type not known (yet) */
1818	return 0;
1819
1820    case KDSETLED:      	/* set keyboard LED status */
1821	if (*data >= 0 && *data <= LED_MASK) {
1822	    scp->status &= ~LED_MASK;
1823	    scp->status |= *data;
1824	    if (scp == cur_console)
1825		update_leds(scp->status);
1826	    return 0;
1827	}
1828	return EINVAL;
1829
1830    case KDGETLED:      	/* get keyboard LED status */
1831	*data = scp->status & LED_MASK;
1832	return 0;
1833
1834    case GETFKEY:       	/* get functionkey string */
1835	if (*(u_short*)data < n_fkey_tab) {
1836	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1837	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1838		  fkey_tab[ptr->keynum].len);
1839	    ptr->flen = fkey_tab[ptr->keynum].len;
1840	    return 0;
1841	}
1842	else
1843	    return EINVAL;
1844
1845    case SETFKEY:       	/* set functionkey string */
1846	if (*(u_short*)data < n_fkey_tab) {
1847	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1848	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1849		  min(ptr->flen, MAXFK));
1850	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1851	    return 0;
1852	}
1853	else
1854	    return EINVAL;
1855
1856    case GIO_SCRNMAP:   	/* get output translation table */
1857	bcopy(&scr_map, data, sizeof(scr_map));
1858	return 0;
1859
1860    case PIO_SCRNMAP:   	/* set output translation table */
1861	bcopy(data, &scr_map, sizeof(scr_map));
1862	for (i=0; i<sizeof(scr_map); i++)
1863	    scr_rmap[scr_map[i]] = i;
1864	return 0;
1865
1866    case GIO_KEYMAP:    	/* get keyboard translation table */
1867	bcopy(&key_map, data, sizeof(key_map));
1868	return 0;
1869
1870    case PIO_KEYMAP:    	/* set keyboard translation table */
1871	accents = 0;
1872	bzero(&accent_map, sizeof(accent_map));
1873	bcopy(data, &key_map, sizeof(key_map));
1874	return 0;
1875
1876    case GIO_DEADKEYMAP:    	/* get accent key translation table */
1877	bcopy(&accent_map, data, sizeof(accent_map));
1878	return 0;
1879
1880    case PIO_DEADKEYMAP:    	/* set accent key translation table */
1881	accents = 0;
1882	bcopy(data, &accent_map, sizeof(accent_map));
1883	return 0;
1884
1885    case PIO_FONT8x8:   	/* set 8x8 dot font */
1886	if (!crtc_vga)
1887	    return ENXIO;
1888	bcopy(data, font_8, 8*256);
1889	fonts_loaded |= FONT_8;
1890	if (!(cur_console->status & UNKNOWN_MODE)) {
1891	    copy_font(LOAD, FONT_8, font_8);
1892	    if (flags & CHAR_CURSOR)
1893	        set_destructive_cursor(cur_console);
1894	}
1895	return 0;
1896
1897    case GIO_FONT8x8:   	/* get 8x8 dot font */
1898	if (!crtc_vga)
1899	    return ENXIO;
1900	if (fonts_loaded & FONT_8) {
1901	    bcopy(font_8, data, 8*256);
1902	    return 0;
1903	}
1904	else
1905	    return ENXIO;
1906
1907    case PIO_FONT8x14:  	/* set 8x14 dot font */
1908	if (!crtc_vga)
1909	    return ENXIO;
1910	bcopy(data, font_14, 14*256);
1911	fonts_loaded |= FONT_14;
1912	if (!(cur_console->status & UNKNOWN_MODE)) {
1913	    copy_font(LOAD, FONT_14, font_14);
1914	    if (flags & CHAR_CURSOR)
1915	        set_destructive_cursor(cur_console);
1916	}
1917	return 0;
1918
1919    case GIO_FONT8x14:  	/* get 8x14 dot font */
1920	if (!crtc_vga)
1921	    return ENXIO;
1922	if (fonts_loaded & FONT_14) {
1923	    bcopy(font_14, data, 14*256);
1924	    return 0;
1925	}
1926	else
1927	    return ENXIO;
1928
1929    case PIO_FONT8x16:  	/* set 8x16 dot font */
1930	if (!crtc_vga)
1931	    return ENXIO;
1932	bcopy(data, font_16, 16*256);
1933	fonts_loaded |= FONT_16;
1934	if (!(cur_console->status & UNKNOWN_MODE)) {
1935	    copy_font(LOAD, FONT_16, font_16);
1936	    if (flags & CHAR_CURSOR)
1937	        set_destructive_cursor(cur_console);
1938	}
1939	return 0;
1940
1941    case GIO_FONT8x16:  	/* get 8x16 dot font */
1942	if (!crtc_vga)
1943	    return ENXIO;
1944	if (fonts_loaded & FONT_16) {
1945	    bcopy(font_16, data, 16*256);
1946	    return 0;
1947	}
1948	else
1949	    return ENXIO;
1950    default:
1951	break;
1952    }
1953
1954    error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1955    if (error != ENOIOCTL)
1956	return(error);
1957    error = ttioctl(tp, cmd, data, flag);
1958    if (error != ENOIOCTL)
1959	return(error);
1960    return(ENOTTY);
1961}
1962
1963static void
1964scstart(struct tty *tp)
1965{
1966    struct clist *rbp;
1967    int s, len;
1968    u_char buf[PCBURST];
1969    scr_stat *scp = get_scr_stat(tp->t_dev);
1970
1971    if (scp->status & SLKED || blink_in_progress)
1972	return; /* XXX who repeats the call when the above flags are cleared? */
1973    s = spltty();
1974    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1975	tp->t_state |= TS_BUSY;
1976	rbp = &tp->t_outq;
1977	while (rbp->c_cc) {
1978	    len = q_to_b(rbp, buf, PCBURST);
1979	    splx(s);
1980	    ansi_put(scp, buf, len);
1981	    s = spltty();
1982	}
1983	tp->t_state &= ~TS_BUSY;
1984	ttwwakeup(tp);
1985    }
1986    splx(s);
1987}
1988
1989static void
1990scmousestart(struct tty *tp)
1991{
1992    struct clist *rbp;
1993    int s;
1994    u_char buf[PCBURST];
1995
1996    s = spltty();
1997    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1998	tp->t_state |= TS_BUSY;
1999	rbp = &tp->t_outq;
2000	while (rbp->c_cc) {
2001	    q_to_b(rbp, buf, PCBURST);
2002	}
2003	tp->t_state &= ~TS_BUSY;
2004	ttwwakeup(tp);
2005    }
2006    splx(s);
2007}
2008
2009void
2010sccnprobe(struct consdev *cp)
2011{
2012    struct isa_device *dvp;
2013
2014    /*
2015     * Take control if we are the highest priority enabled display device.
2016     */
2017    dvp = find_display();
2018    if (dvp == NULL || dvp->id_driver != &scdriver) {
2019	cp->cn_pri = CN_DEAD;
2020	return;
2021    }
2022
2023    if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
2024	cp->cn_pri = CN_DEAD;
2025	return;
2026    }
2027
2028    /* initialize required fields */
2029    cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
2030    cp->cn_pri = CN_INTERNAL;
2031
2032    sc_kbdc = kbdc_open(sc_port);
2033}
2034
2035void
2036sccninit(struct consdev *cp)
2037{
2038    scinit();
2039}
2040
2041void
2042sccnputc(dev_t dev, int c)
2043{
2044    u_char buf[1];
2045    int s;
2046    scr_stat *scp = console[0];
2047    term_stat save = scp->term;
2048
2049    scp->term = kernel_console;
2050    current_default = &kernel_default;
2051    if (scp == cur_console && !(scp->status & UNKNOWN_MODE))
2052	remove_cursor_image(scp);
2053    buf[0] = c;
2054    ansi_put(scp, buf, 1);
2055    kernel_console = scp->term;
2056    current_default = &user_default;
2057    scp->term = save;
2058    s = splclock();
2059    if (scp == cur_console && !(scp->status & UNKNOWN_MODE)) {
2060	if (/* timer not running && */ (scp->start <= scp->end)) {
2061	    sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start,
2062		   (1 + scp->end - scp->start) * sizeof(u_short));
2063	    scp->start = scp->xsize * scp->ysize;
2064	    scp->end = 0;
2065	}
2066    	scp->cursor_oldpos = scp->cursor_pos;
2067	draw_cursor_image(scp);
2068    }
2069    splx(s);
2070}
2071
2072int
2073sccngetc(dev_t dev)
2074{
2075    int s = spltty();	/* block scintr and scrn_timer while we poll */
2076    int c;
2077
2078    /*
2079     * Stop the screen saver if necessary.
2080     * What if we have been running in the screen saver code... XXX
2081     */
2082    if (scrn_blanked > 0)
2083        stop_scrn_saver(current_saver);
2084
2085    c = scgetc(SCGETC_CN);
2086
2087    /* make sure the screen saver won't be activated soon */
2088    scrn_time_stamp = mono_time.tv_sec;
2089    splx(s);
2090    return(c);
2091}
2092
2093int
2094sccncheckc(dev_t dev)
2095{
2096    int c, s;
2097
2098    s = spltty();
2099    if (scrn_blanked > 0)
2100        stop_scrn_saver(current_saver);
2101    c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
2102    if (c != NOKEY)
2103        scrn_time_stamp = mono_time.tv_sec;
2104    splx(s);
2105    return(c == NOKEY ? -1 : c);	/* c == -1 can't happen */
2106}
2107
2108static scr_stat
2109*get_scr_stat(dev_t dev)
2110{
2111    int unit = minor(dev);
2112
2113    if (unit == SC_CONSOLE)
2114	return console[0];
2115    if (unit >= MAXCONS || unit < 0)
2116	return(NULL);
2117    return console[unit];
2118}
2119
2120static int
2121get_scr_num()
2122{
2123    int i = 0;
2124
2125    while ((i < MAXCONS) && (cur_console != console[i]))
2126	i++;
2127    return i < MAXCONS ? i : 0;
2128}
2129
2130static void
2131scrn_timer(void *arg)
2132{
2133    scr_stat *scp = cur_console;
2134    int s = spltty();
2135
2136    /*
2137     * With release 2.1 of the Xaccel server, the keyboard is left
2138     * hanging pretty often. Apparently an interrupt from the
2139     * keyboard is lost, and I don't know why (yet).
2140     * This ugly hack calls scintr if input is ready for the keyboard
2141     * and conveniently hides the problem.			XXX
2142     */
2143    /* Try removing anything stuck in the keyboard controller; whether
2144     * it's a keyboard scan code or mouse data. `scintr()' doesn't
2145     * read the mouse data directly, but `kbdio' routines will, as a
2146     * side effect.
2147     */
2148    if (kbdc_lock(sc_kbdc, TRUE)) {
2149	/*
2150	 * We have seen the lock flag is not set. Let's reset the flag early;
2151	 * otherwise `update_led()' failes which may want the lock
2152	 * during `scintr()'.
2153	 */
2154	kbdc_lock(sc_kbdc, FALSE);
2155	if (kbdc_data_ready(sc_kbdc))
2156	    scintr(0);
2157    }
2158
2159    /* should we just return ? */
2160    if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
2161	timeout(scrn_timer, NULL, hz / 10);
2162	splx(s);
2163	return;
2164    }
2165
2166    /* should we stop the screen saver? */
2167    if (mono_time.tv_sec <= scrn_time_stamp + scrn_blank_time)
2168	if (scrn_blanked > 0)
2169            stop_scrn_saver(current_saver);
2170
2171    if (scrn_blanked <= 0) {
2172	/* update screen image */
2173	if (scp->start <= scp->end) {
2174	    sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start,
2175		   (1 + scp->end - scp->start) * sizeof(u_short));
2176	}
2177
2178	/* update "pseudo" mouse pointer image */
2179	if ((scp->status & MOUSE_VISIBLE) && crtc_vga) {
2180	    /* did mouse move since last time ? */
2181	    if (scp->status & MOUSE_MOVED) {
2182		/* do we need to remove old mouse pointer image ? */
2183		if (scp->mouse_cut_start != NULL ||
2184		    (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2185		    (scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->end) {
2186		    remove_mouse_image(scp);
2187		}
2188		scp->status &= ~MOUSE_MOVED;
2189		draw_mouse_image(scp);
2190	    }
2191	    else {
2192		/* mouse didn't move, has it been overwritten ? */
2193		if ((scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->start &&
2194		    (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2195		    draw_mouse_image(scp);
2196		}
2197	    }
2198	}
2199
2200	/* update cursor image */
2201	if (scp->status & CURSOR_ENABLED) {
2202	    /* did cursor move since last time ? */
2203	    if (scp->cursor_pos != scp->cursor_oldpos) {
2204		/* do we need to remove old cursor image ? */
2205		if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2206		    ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2207		    remove_cursor_image(scp);
2208		}
2209    		scp->cursor_oldpos = scp->cursor_pos;
2210		draw_cursor_image(scp);
2211	    }
2212	    else {
2213		/* cursor didn't move, has it been overwritten ? */
2214		if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2215		    scp->cursor_pos - scp->scr_buf <= scp->end) {
2216		    	draw_cursor_image(scp);
2217		} else {
2218		    /* if its a blinking cursor, we may have to update it */
2219		    if (flags & BLINK_CURSOR)
2220			draw_cursor_image(scp);
2221		}
2222	    }
2223	    blinkrate++;
2224	}
2225
2226	if (scp->mouse_cut_start != NULL)
2227	    draw_cutmarking(scp);
2228
2229	scp->end = 0;
2230	scp->start = scp->xsize*scp->ysize;
2231    }
2232
2233    /* should we activate the screen saver? */
2234    if ((scrn_blank_time != 0)
2235	    && (mono_time.tv_sec > scrn_time_stamp + scrn_blank_time))
2236	(*current_saver)(TRUE);
2237
2238    timeout(scrn_timer, NULL, hz / 25);
2239    splx(s);
2240}
2241
2242int
2243add_scrn_saver(void (*this_saver)(int))
2244{
2245    if (current_saver != none_saver)
2246	return EBUSY;
2247    current_saver = this_saver;
2248    return 0;
2249}
2250
2251int
2252remove_scrn_saver(void (*this_saver)(int))
2253{
2254    if (current_saver != this_saver)
2255	return EINVAL;
2256
2257    /*
2258     * In order to prevent `current_saver' from being called by
2259     * the timeout routine `scrn_timer()' while we manipulate
2260     * the saver list, we shall set `current_saver' to `none_saver'
2261     * before stopping the current saver, rather than blocking by `splXX()'.
2262     */
2263    current_saver = none_saver;
2264    if (scrn_blanked > 0)
2265        stop_scrn_saver(this_saver);
2266
2267    return 0;
2268}
2269
2270static void
2271stop_scrn_saver(void (*saver)(int))
2272{
2273    (*saver)(FALSE);
2274    scrn_time_stamp = mono_time.tv_sec;
2275    mark_all(cur_console);
2276}
2277
2278static void
2279clear_screen(scr_stat *scp)
2280{
2281    move_crsr(scp, 0, 0);
2282    scp->cursor_oldpos = scp->cursor_pos;
2283    fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2284	  scp->xsize * scp->ysize);
2285    mark_all(scp);
2286    remove_cutmarking(scp);
2287}
2288
2289static int
2290switch_scr(scr_stat *scp, u_int next_scr)
2291{
2292    if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2293	switch_in_progress = FALSE;
2294
2295    if (next_scr >= MAXCONS || switch_in_progress ||
2296	(cur_console->smode.mode == VT_AUTO
2297	 && cur_console->status & UNKNOWN_MODE)) {
2298	do_bell(scp, BELL_PITCH, BELL_DURATION);
2299	return EINVAL;
2300    }
2301
2302    /* is the wanted virtual console open ? */
2303    if (next_scr) {
2304	struct tty *tp = VIRTUAL_TTY(next_scr);
2305	if (!(tp->t_state & TS_ISOPEN)) {
2306	    do_bell(scp, BELL_PITCH, BELL_DURATION);
2307	    return EINVAL;
2308	}
2309    }
2310    /* delay switch if actively updating screen */
2311    if (write_in_progress || blink_in_progress) {
2312	delayed_next_scr = next_scr+1;
2313	return 0;
2314    }
2315    switch_in_progress = TRUE;
2316    old_scp = cur_console;
2317    new_scp = console[next_scr];
2318    wakeup((caddr_t)&new_scp->smode);
2319    if (new_scp == old_scp) {
2320	switch_in_progress = FALSE;
2321	delayed_next_scr = FALSE;
2322	return 0;
2323    }
2324
2325    /* has controlling process died? */
2326    if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2327	old_scp->smode.mode = VT_AUTO;
2328    if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2329	new_scp->smode.mode = VT_AUTO;
2330
2331    /* check the modes and switch appropriately */
2332    if (old_scp->smode.mode == VT_PROCESS) {
2333	old_scp->status |= SWITCH_WAIT_REL;
2334	psignal(old_scp->proc, old_scp->smode.relsig);
2335    }
2336    else {
2337	exchange_scr();
2338	if (new_scp->smode.mode == VT_PROCESS) {
2339	    new_scp->status |= SWITCH_WAIT_ACQ;
2340	    psignal(new_scp->proc, new_scp->smode.acqsig);
2341	}
2342	else
2343	    switch_in_progress = FALSE;
2344    }
2345    return 0;
2346}
2347
2348static void
2349exchange_scr(void)
2350{
2351    move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2352    cur_console = new_scp;
2353    if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
2354	if (crtc_vga)
2355	    set_mode(new_scp);
2356    }
2357    move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2358    if (!(new_scp->status & UNKNOWN_MODE) && (flags & CHAR_CURSOR))
2359	set_destructive_cursor(new_scp);
2360    if ((old_scp->status & UNKNOWN_MODE) && crtc_vga)
2361	load_palette(palette);
2362    if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2363        old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2364	shfts = ctls = alts = agrs = metas = accents = 0;
2365    set_border(new_scp->border);
2366    update_leds(new_scp->status);
2367    delayed_next_scr = FALSE;
2368    mark_all(new_scp);
2369}
2370
2371static void
2372scan_esc(scr_stat *scp, u_char c)
2373{
2374    static u_char ansi_col[16] =
2375	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2376    int i, n;
2377    u_short *src, *dst, count;
2378
2379    if (scp->term.esc == 1) {	/* seen ESC */
2380	switch (c) {
2381
2382	case '7':   /* Save cursor position */
2383	    scp->saved_xpos = scp->xpos;
2384	    scp->saved_ypos = scp->ypos;
2385	    break;
2386
2387	case '8':   /* Restore saved cursor position */
2388	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2389		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2390	    break;
2391
2392	case '[':   /* Start ESC [ sequence */
2393	    scp->term.esc = 2;
2394	    scp->term.last_param = -1;
2395	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2396		scp->term.param[i] = 1;
2397	    scp->term.num_param = 0;
2398	    return;
2399
2400	case 'M':   /* Move cursor up 1 line, scroll if at top */
2401	    if (scp->ypos > 0)
2402		move_crsr(scp, scp->xpos, scp->ypos - 1);
2403	    else {
2404		bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2405		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2406		fillw(scp->term.cur_color | scr_map[0x20],
2407		      scp->scr_buf, scp->xsize);
2408    		mark_all(scp);
2409	    }
2410	    break;
2411#if notyet
2412	case 'Q':
2413	    scp->term.esc = 4;
2414	    return;
2415#endif
2416	case 'c':   /* Clear screen & home */
2417	    clear_screen(scp);
2418	    break;
2419
2420	case '(':   /* iso-2022: designate 94 character set to G0 */
2421	    scp->term.esc = 5;
2422	    return;
2423	}
2424    }
2425    else if (scp->term.esc == 2) {	/* seen ESC [ */
2426	if (c >= '0' && c <= '9') {
2427	    if (scp->term.num_param < MAX_ESC_PAR) {
2428	    if (scp->term.last_param != scp->term.num_param) {
2429		scp->term.last_param = scp->term.num_param;
2430		scp->term.param[scp->term.num_param] = 0;
2431	    }
2432	    else
2433		scp->term.param[scp->term.num_param] *= 10;
2434	    scp->term.param[scp->term.num_param] += c - '0';
2435	    return;
2436	    }
2437	}
2438	scp->term.num_param = scp->term.last_param + 1;
2439	switch (c) {
2440
2441	case ';':
2442	    if (scp->term.num_param < MAX_ESC_PAR)
2443		return;
2444	    break;
2445
2446	case '=':
2447	    scp->term.esc = 3;
2448	    scp->term.last_param = -1;
2449	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2450		scp->term.param[i] = 1;
2451	    scp->term.num_param = 0;
2452	    return;
2453
2454	case 'A':   /* up n rows */
2455	    n = scp->term.param[0]; if (n < 1) n = 1;
2456	    move_crsr(scp, scp->xpos, scp->ypos - n);
2457	    break;
2458
2459	case 'B':   /* down n rows */
2460	    n = scp->term.param[0]; if (n < 1) n = 1;
2461	    move_crsr(scp, scp->xpos, scp->ypos + n);
2462	    break;
2463
2464	case 'C':   /* right n columns */
2465	    n = scp->term.param[0]; if (n < 1) n = 1;
2466	    move_crsr(scp, scp->xpos + n, scp->ypos);
2467	    break;
2468
2469	case 'D':   /* left n columns */
2470	    n = scp->term.param[0]; if (n < 1) n = 1;
2471	    move_crsr(scp, scp->xpos - n, scp->ypos);
2472	    break;
2473
2474	case 'E':   /* cursor to start of line n lines down */
2475	    n = scp->term.param[0]; if (n < 1) n = 1;
2476	    move_crsr(scp, 0, scp->ypos + n);
2477	    break;
2478
2479	case 'F':   /* cursor to start of line n lines up */
2480	    n = scp->term.param[0]; if (n < 1) n = 1;
2481	    move_crsr(scp, 0, scp->ypos - n);
2482	    break;
2483
2484	case 'f':   /* Cursor move */
2485	case 'H':
2486	    if (scp->term.num_param == 0)
2487		move_crsr(scp, 0, 0);
2488	    else if (scp->term.num_param == 2)
2489		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2490	    break;
2491
2492	case 'J':   /* Clear all or part of display */
2493	    if (scp->term.num_param == 0)
2494		n = 0;
2495	    else
2496		n = scp->term.param[0];
2497	    switch (n) {
2498	    case 0: /* clear form cursor to end of display */
2499		fillw(scp->term.cur_color | scr_map[0x20],
2500		      scp->cursor_pos,
2501		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2502    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2503    		mark_for_update(scp, scp->xsize * scp->ysize);
2504		remove_cutmarking(scp);
2505		break;
2506	    case 1: /* clear from beginning of display to cursor */
2507		fillw(scp->term.cur_color | scr_map[0x20],
2508		      scp->scr_buf,
2509		      scp->cursor_pos - scp->scr_buf);
2510    		mark_for_update(scp, 0);
2511    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2512		remove_cutmarking(scp);
2513		break;
2514	    case 2: /* clear entire display */
2515		fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2516		      scp->xsize * scp->ysize);
2517		mark_all(scp);
2518		remove_cutmarking(scp);
2519		break;
2520	    }
2521	    break;
2522
2523	case 'K':   /* Clear all or part of line */
2524	    if (scp->term.num_param == 0)
2525		n = 0;
2526	    else
2527		n = scp->term.param[0];
2528	    switch (n) {
2529	    case 0: /* clear form cursor to end of line */
2530		fillw(scp->term.cur_color | scr_map[0x20],
2531		      scp->cursor_pos,
2532		      scp->xsize - scp->xpos);
2533    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2534    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2535				scp->xsize - scp->xpos);
2536		break;
2537	    case 1: /* clear from beginning of line to cursor */
2538		fillw(scp->term.cur_color | scr_map[0x20],
2539		      scp->cursor_pos - scp->xpos,
2540		      scp->xpos + 1);
2541    		mark_for_update(scp, scp->ypos * scp->xsize);
2542    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2543		break;
2544	    case 2: /* clear entire line */
2545		fillw(scp->term.cur_color | scr_map[0x20],
2546		      scp->cursor_pos - scp->xpos,
2547		      scp->xsize);
2548    		mark_for_update(scp, scp->ypos * scp->xsize);
2549    		mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
2550		break;
2551	    }
2552	    break;
2553
2554	case 'L':   /* Insert n lines */
2555	    n = scp->term.param[0]; if (n < 1) n = 1;
2556	    if (n > scp->ysize - scp->ypos)
2557		n = scp->ysize - scp->ypos;
2558	    src = scp->scr_buf + scp->ypos * scp->xsize;
2559	    dst = src + n * scp->xsize;
2560	    count = scp->ysize - (scp->ypos + n);
2561	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2562	    fillw(scp->term.cur_color | scr_map[0x20], src,
2563		  n * scp->xsize);
2564	    mark_for_update(scp, scp->ypos * scp->xsize);
2565	    mark_for_update(scp, scp->xsize * scp->ysize);
2566	    break;
2567
2568	case 'M':   /* Delete n lines */
2569	    n = scp->term.param[0]; if (n < 1) n = 1;
2570	    if (n > scp->ysize - scp->ypos)
2571		n = scp->ysize - scp->ypos;
2572	    dst = scp->scr_buf + scp->ypos * scp->xsize;
2573	    src = dst + n * scp->xsize;
2574	    count = scp->ysize - (scp->ypos + n);
2575	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2576	    src = dst + count * scp->xsize;
2577	    fillw(scp->term.cur_color | scr_map[0x20], src,
2578		  n * scp->xsize);
2579	    mark_for_update(scp, scp->ypos * scp->xsize);
2580	    mark_for_update(scp, scp->xsize * scp->ysize);
2581	    break;
2582
2583	case 'P':   /* Delete n chars */
2584	    n = scp->term.param[0]; if (n < 1) n = 1;
2585	    if (n > scp->xsize - scp->xpos)
2586		n = scp->xsize - scp->xpos;
2587	    dst = scp->cursor_pos;
2588	    src = dst + n;
2589	    count = scp->xsize - (scp->xpos + n);
2590	    bcopy(src, dst, count * sizeof(u_short));
2591	    src = dst + count;
2592	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2593	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2594	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2595	    break;
2596
2597	case '@':   /* Insert n chars */
2598	    n = scp->term.param[0]; if (n < 1) n = 1;
2599	    if (n > scp->xsize - scp->xpos)
2600		n = scp->xsize - scp->xpos;
2601	    src = scp->cursor_pos;
2602	    dst = src + n;
2603	    count = scp->xsize - (scp->xpos + n);
2604	    bcopy(src, dst, count * sizeof(u_short));
2605	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2606	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2607	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2608	    break;
2609
2610	case 'S':   /* scroll up n lines */
2611	    n = scp->term.param[0]; if (n < 1)  n = 1;
2612	    if (n > scp->ysize)
2613		n = scp->ysize;
2614	    bcopy(scp->scr_buf + (scp->xsize * n),
2615		   scp->scr_buf,
2616		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
2617	    fillw(scp->term.cur_color | scr_map[0x20],
2618		  scp->scr_buf + scp->xsize * (scp->ysize - n),
2619		  scp->xsize * n);
2620    	    mark_all(scp);
2621	    break;
2622
2623	case 'T':   /* scroll down n lines */
2624	    n = scp->term.param[0]; if (n < 1)  n = 1;
2625	    if (n > scp->ysize)
2626		n = scp->ysize;
2627	    bcopy(scp->scr_buf,
2628		  scp->scr_buf + (scp->xsize * n),
2629		  scp->xsize * (scp->ysize - n) *
2630		  sizeof(u_short));
2631	    fillw(scp->term.cur_color | scr_map[0x20],
2632		  scp->scr_buf, scp->xsize * n);
2633    	    mark_all(scp);
2634	    break;
2635
2636	case 'X':   /* erase n characters in line */
2637	    n = scp->term.param[0]; if (n < 1)  n = 1;
2638	    if (n > scp->xsize - scp->xpos)
2639		n = scp->xsize - scp->xpos;
2640	    fillw(scp->term.cur_color | scr_map[0x20],
2641		  scp->cursor_pos, n);
2642	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2643	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
2644	    break;
2645
2646	case 'Z':   /* move n tabs backwards */
2647	    n = scp->term.param[0]; if (n < 1)  n = 1;
2648	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2649		i -= 8*n;
2650	    else
2651		i -= 8*(n-1);
2652	    if (i < 0)
2653		i = 0;
2654	    move_crsr(scp, i, scp->ypos);
2655	    break;
2656
2657	case '`':   /* move cursor to column n */
2658	    n = scp->term.param[0]; if (n < 1)  n = 1;
2659	    move_crsr(scp, n - 1, scp->ypos);
2660	    break;
2661
2662	case 'a':   /* move cursor n columns to the right */
2663	    n = scp->term.param[0]; if (n < 1)  n = 1;
2664	    move_crsr(scp, scp->xpos + n, scp->ypos);
2665	    break;
2666
2667	case 'd':   /* move cursor to row n */
2668	    n = scp->term.param[0]; if (n < 1)  n = 1;
2669	    move_crsr(scp, scp->xpos, n - 1);
2670	    break;
2671
2672	case 'e':   /* move cursor n rows down */
2673	    n = scp->term.param[0]; if (n < 1)  n = 1;
2674	    move_crsr(scp, scp->xpos, scp->ypos + n);
2675	    break;
2676
2677	case 'm':   /* change attribute */
2678	    if (scp->term.num_param == 0) {
2679		scp->term.attr_mask = NORMAL_ATTR;
2680		scp->term.cur_attr =
2681		    scp->term.cur_color = scp->term.std_color;
2682		break;
2683	    }
2684	    for (i = 0; i < scp->term.num_param; i++) {
2685		switch (n = scp->term.param[i]) {
2686		case 0: /* back to normal */
2687		    scp->term.attr_mask = NORMAL_ATTR;
2688		    scp->term.cur_attr =
2689			scp->term.cur_color = scp->term.std_color;
2690		    break;
2691		case 1: /* bold */
2692		    scp->term.attr_mask |= BOLD_ATTR;
2693		    scp->term.cur_attr = mask2attr(&scp->term);
2694		    break;
2695		case 4: /* underline */
2696		    scp->term.attr_mask |= UNDERLINE_ATTR;
2697		    scp->term.cur_attr = mask2attr(&scp->term);
2698		    break;
2699		case 5: /* blink */
2700		    scp->term.attr_mask |= BLINK_ATTR;
2701		    scp->term.cur_attr = mask2attr(&scp->term);
2702		    break;
2703		case 7: /* reverse video */
2704		    scp->term.attr_mask |= REVERSE_ATTR;
2705		    scp->term.cur_attr = mask2attr(&scp->term);
2706		    break;
2707		case 30: case 31: /* set fg color */
2708		case 32: case 33: case 34:
2709		case 35: case 36: case 37:
2710		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2711		    scp->term.cur_color =
2712			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2713		    scp->term.cur_attr = mask2attr(&scp->term);
2714		    break;
2715		case 40: case 41: /* set bg color */
2716		case 42: case 43: case 44:
2717		case 45: case 46: case 47:
2718		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2719		    scp->term.cur_color =
2720			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2721		    scp->term.cur_attr = mask2attr(&scp->term);
2722		    break;
2723		}
2724	    }
2725	    break;
2726
2727	case 's':   /* Save cursor position */
2728	    scp->saved_xpos = scp->xpos;
2729	    scp->saved_ypos = scp->ypos;
2730	    break;
2731
2732	case 'u':   /* Restore saved cursor position */
2733	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2734		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2735	    break;
2736
2737	case 'x':
2738	    if (scp->term.num_param == 0)
2739		n = 0;
2740	    else
2741		n = scp->term.param[0];
2742	    switch (n) {
2743	    case 0:     /* reset attributes */
2744		scp->term.attr_mask = NORMAL_ATTR;
2745		scp->term.cur_attr =
2746		    scp->term.cur_color = scp->term.std_color =
2747		    current_default->std_color;
2748		scp->term.rev_color = current_default->rev_color;
2749		break;
2750	    case 1:     /* set ansi background */
2751		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2752		scp->term.cur_color = scp->term.std_color =
2753		    (scp->term.std_color & 0x0F00) |
2754		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2755		scp->term.cur_attr = mask2attr(&scp->term);
2756		break;
2757	    case 2:     /* set ansi foreground */
2758		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2759		scp->term.cur_color = scp->term.std_color =
2760		    (scp->term.std_color & 0xF000) |
2761		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2762		scp->term.cur_attr = mask2attr(&scp->term);
2763		break;
2764	    case 3:     /* set ansi attribute directly */
2765		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2766		scp->term.cur_color = scp->term.std_color =
2767		    (scp->term.param[1]&0xFF)<<8;
2768		scp->term.cur_attr = mask2attr(&scp->term);
2769		break;
2770	    case 5:     /* set ansi reverse video background */
2771		scp->term.rev_color =
2772		    (scp->term.rev_color & 0x0F00) |
2773		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2774		scp->term.cur_attr = mask2attr(&scp->term);
2775		break;
2776	    case 6:     /* set ansi reverse video foreground */
2777		scp->term.rev_color =
2778		    (scp->term.rev_color & 0xF000) |
2779		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2780		scp->term.cur_attr = mask2attr(&scp->term);
2781		break;
2782	    case 7:     /* set ansi reverse video directly */
2783		scp->term.rev_color =
2784		    (scp->term.param[1]&0xFF)<<8;
2785		scp->term.cur_attr = mask2attr(&scp->term);
2786		break;
2787	    }
2788	    break;
2789
2790	case 'z':   /* switch to (virtual) console n */
2791	    if (scp->term.num_param == 1)
2792		switch_scr(scp, scp->term.param[0]);
2793	    break;
2794	}
2795    }
2796    else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2797	if (c >= '0' && c <= '9') {
2798	    if (scp->term.num_param < MAX_ESC_PAR) {
2799	    if (scp->term.last_param != scp->term.num_param) {
2800		scp->term.last_param = scp->term.num_param;
2801		scp->term.param[scp->term.num_param] = 0;
2802	    }
2803	    else
2804		scp->term.param[scp->term.num_param] *= 10;
2805	    scp->term.param[scp->term.num_param] += c - '0';
2806	    return;
2807	    }
2808	}
2809	scp->term.num_param = scp->term.last_param + 1;
2810	switch (c) {
2811
2812	case ';':
2813	    if (scp->term.num_param < MAX_ESC_PAR)
2814		return;
2815	    break;
2816
2817	case 'A':   /* set display border color */
2818	    if (scp->term.num_param == 1) {
2819		scp->border=scp->term.param[0] & 0xff;
2820		if (scp == cur_console)
2821		    set_border(scp->border);
2822            }
2823	    break;
2824
2825	case 'B':   /* set bell pitch and duration */
2826	    if (scp->term.num_param == 2) {
2827		scp->bell_pitch = scp->term.param[0];
2828		scp->bell_duration = scp->term.param[1]*10;
2829	    }
2830	    break;
2831
2832	case 'C':   /* set cursor type & shape */
2833	    if (scp->term.num_param == 1) {
2834		if (scp->term.param[0] & 0x01)
2835		    flags |= BLINK_CURSOR;
2836		else
2837		    flags &= ~BLINK_CURSOR;
2838		if ((scp->term.param[0] & 0x02) && crtc_vga)
2839		    flags |= CHAR_CURSOR;
2840		else
2841		    flags &= ~CHAR_CURSOR;
2842	    }
2843	    else if (scp->term.num_param == 2) {
2844		scp->cursor_start = scp->term.param[0] & 0x1F;
2845		scp->cursor_end = scp->term.param[1] & 0x1F;
2846	    }
2847	    /*
2848	     * The cursor shape is global property; all virtual consoles
2849	     * are affected. Update the cursor in the current console...
2850	     */
2851	    if (!(cur_console->status & UNKNOWN_MODE)) {
2852		remove_cursor_image(cur_console);
2853		if (crtc_vga && (flags & CHAR_CURSOR))
2854	            set_destructive_cursor(cur_console);
2855		draw_cursor_image(cur_console);
2856	    }
2857	    break;
2858
2859	case 'F':   /* set ansi foreground */
2860	    if (scp->term.num_param == 1) {
2861		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2862		scp->term.cur_color = scp->term.std_color =
2863		    (scp->term.std_color & 0xF000)
2864		    | ((scp->term.param[0] & 0x0F) << 8);
2865		scp->term.cur_attr = mask2attr(&scp->term);
2866	    }
2867	    break;
2868
2869	case 'G':   /* set ansi background */
2870	    if (scp->term.num_param == 1) {
2871		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2872		scp->term.cur_color = scp->term.std_color =
2873		    (scp->term.std_color & 0x0F00)
2874		    | ((scp->term.param[0] & 0x0F) << 12);
2875		scp->term.cur_attr = mask2attr(&scp->term);
2876	    }
2877	    break;
2878
2879	case 'H':   /* set ansi reverse video foreground */
2880	    if (scp->term.num_param == 1) {
2881		scp->term.rev_color =
2882		    (scp->term.rev_color & 0xF000)
2883		    | ((scp->term.param[0] & 0x0F) << 8);
2884		scp->term.cur_attr = mask2attr(&scp->term);
2885	    }
2886	    break;
2887
2888	case 'I':   /* set ansi reverse video background */
2889	    if (scp->term.num_param == 1) {
2890		scp->term.rev_color =
2891		    (scp->term.rev_color & 0x0F00)
2892		    | ((scp->term.param[0] & 0x0F) << 12);
2893		scp->term.cur_attr = mask2attr(&scp->term);
2894	    }
2895	    break;
2896	}
2897    }
2898#if notyet
2899    else if (scp->term.esc == 4) {	/* seen ESC Q */
2900	/* to be filled */
2901    }
2902#endif
2903    else if (scp->term.esc == 5) {	/* seen ESC ( */
2904	switch (c) {
2905	case 'B':   /* iso-2022: desginate ASCII into G0 */
2906	    break;
2907	/* other items to be filled */
2908	default:
2909	    break;
2910	}
2911    }
2912    scp->term.esc = 0;
2913}
2914
2915static void
2916ansi_put(scr_stat *scp, u_char *buf, int len)
2917{
2918    u_char *ptr = buf;
2919
2920    /* make screensaver happy */
2921    if (scp == cur_console)
2922	scrn_time_stamp = mono_time.tv_sec;
2923
2924    write_in_progress++;
2925outloop:
2926    if (scp->term.esc) {
2927	scan_esc(scp, *ptr++);
2928	len--;
2929    }
2930    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2931 	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
2932 	u_short cur_attr = scp->term.cur_attr;
2933 	u_short *cursor_pos = scp->cursor_pos;
2934	do {
2935	    /*
2936	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2937	     * pointers in the following to volatile should have no effect,
2938	     * but in fact speeds up this inner loop from 26 to 18 cycles
2939	     * (+ cache misses) on i486's.
2940	     */
2941#define	UCVP(ucp)	((u_char volatile *)(ucp))
2942	    *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
2943	    ptr++;
2944	    cnt--;
2945	} while (cnt && PRINTABLE(*ptr));
2946	len -= (cursor_pos - scp->cursor_pos);
2947	scp->xpos += (cursor_pos - scp->cursor_pos);
2948	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2949	mark_for_update(scp, cursor_pos - scp->scr_buf);
2950	scp->cursor_pos = cursor_pos;
2951	if (scp->xpos >= scp->xsize) {
2952	    scp->xpos = 0;
2953	    scp->ypos++;
2954	}
2955    }
2956    else  {
2957	switch(*ptr) {
2958	case 0x07:
2959	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2960	    break;
2961
2962	case 0x08:      /* non-destructive backspace */
2963	    if (scp->cursor_pos > scp->scr_buf) {
2964	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2965		scp->cursor_pos--;
2966	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2967		if (scp->xpos > 0)
2968		    scp->xpos--;
2969		else {
2970		    scp->xpos += scp->xsize - 1;
2971		    scp->ypos--;
2972		}
2973	    }
2974	    break;
2975
2976	case 0x09:  /* non-destructive tab */
2977	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2978	    scp->cursor_pos += (8 - scp->xpos % 8u);
2979	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2980	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2981	        scp->xpos = 0;
2982	        scp->ypos++;
2983	    }
2984	    break;
2985
2986	case 0x0a:  /* newline, same pos */
2987	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2988	    scp->cursor_pos += scp->xsize;
2989	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2990	    scp->ypos++;
2991	    break;
2992
2993	case 0x0c:  /* form feed, clears screen */
2994	    clear_screen(scp);
2995	    break;
2996
2997	case 0x0d:  /* return, return to pos 0 */
2998	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2999	    scp->cursor_pos -= scp->xpos;
3000	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3001	    scp->xpos = 0;
3002	    break;
3003
3004	case 0x1b:  /* start escape sequence */
3005	    scp->term.esc = 1;
3006	    scp->term.num_param = 0;
3007	    break;
3008	}
3009	ptr++; len--;
3010    }
3011    /* do we have to scroll ?? */
3012    if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
3013	remove_cutmarking(scp);
3014	if (scp->history) {
3015	    bcopy(scp->scr_buf, scp->history_head,
3016		   scp->xsize * sizeof(u_short));
3017	    scp->history_head += scp->xsize;
3018	    if (scp->history_head + scp->xsize >
3019		scp->history + scp->history_size)
3020		scp->history_head = scp->history;
3021	}
3022	bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
3023	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
3024	fillw(scp->term.cur_color | scr_map[0x20],
3025	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
3026	      scp->xsize);
3027	scp->cursor_pos -= scp->xsize;
3028	scp->ypos--;
3029    	mark_all(scp);
3030    }
3031    if (len)
3032	goto outloop;
3033    write_in_progress--;
3034    if (delayed_next_scr)
3035	switch_scr(scp, delayed_next_scr - 1);
3036}
3037
3038static void
3039scinit(void)
3040{
3041    u_int hw_cursor;
3042    u_int i;
3043
3044    if (init_done != COLD)
3045	return;
3046    init_done = WARM;
3047
3048    /*
3049     * Ensure a zero start address.  This is mainly to recover after
3050     * switching from pcvt using userconfig().  The registers are w/o
3051     * for old hardware so it's too hard to relocate the active screen
3052     * memory.
3053     */
3054    outb(crtc_addr, 12);
3055    outb(crtc_addr + 1, 0);
3056    outb(crtc_addr, 13);
3057    outb(crtc_addr + 1, 0);
3058
3059    /* extract cursor location */
3060    outb(crtc_addr, 14);
3061    hw_cursor = inb(crtc_addr + 1) << 8;
3062    outb(crtc_addr, 15);
3063    hw_cursor |= inb(crtc_addr + 1);
3064
3065    /*
3066     * Validate cursor location.  It may be off the screen.  Then we must
3067     * not use it for the initial buffer offset.
3068     */
3069    if (hw_cursor >= ROW * COL)
3070	hw_cursor = (ROW - 1) * COL;
3071
3072    /* move hardware cursor out of the way */
3073    outb(crtc_addr, 14);
3074    outb(crtc_addr + 1, 0xff);
3075    outb(crtc_addr, 15);
3076    outb(crtc_addr + 1, 0xff);
3077
3078    /* set up the first console */
3079    current_default = &user_default;
3080    console[0] = &main_console;
3081    init_scp(console[0]);
3082    cur_console = console[0];
3083
3084    /* discard the video mode table if we are not familiar with it... */
3085    if (video_mode_ptr) {
3086        bzero(mode_map, sizeof(mode_map));
3087	bcopy(video_mode_ptr + MODE_PARAM_SIZE*console[0]->mode,
3088	      vgaregs2, sizeof(vgaregs2));
3089        switch (comp_vgaregs(vgaregs, video_mode_ptr
3090                    + MODE_PARAM_SIZE*console[0]->mode)) {
3091        case COMP_IDENTICAL:
3092            map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3093            /*
3094             * This is a kludge for Toshiba DynaBook SS433 whose BIOS video
3095             * mode table entry has the actual # of rows at the offset 1;
3096	     * BIOSes from other manufacturers store the # of rows - 1 there.
3097	     * XXX
3098             */
3099	    rows_offset = vgaregs[1] + 1
3100		- video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3101            break;
3102        case COMP_SIMILAR:
3103            map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3104            mode_map[console[0]->mode] = vgaregs;
3105	    rows_offset = vgaregs[1] + 1
3106		- video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3107            vgaregs[1] -= rows_offset - 1;
3108            break;
3109        case COMP_DIFFERENT:
3110        default:
3111            video_mode_ptr = NULL;
3112            mode_map[console[0]->mode] = vgaregs;
3113	    rows_offset = 1;
3114            break;
3115        }
3116    }
3117
3118    /* copy screen to temporary buffer */
3119    sc_bcopy(Crtat, sc_buffer,
3120	   console[0]->xsize * console[0]->ysize * sizeof(u_short));
3121
3122    console[0]->scr_buf = console[0]->mouse_pos = sc_buffer;
3123    console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor;
3124    console[0]->cursor_saveunder = *console[0]->cursor_pos;
3125    console[0]->xpos = hw_cursor % COL;
3126    console[0]->ypos = hw_cursor / COL;
3127    for (i=1; i<MAXCONS; i++)
3128	console[i] = NULL;
3129    kernel_console.esc = 0;
3130    kernel_console.attr_mask = NORMAL_ATTR;
3131    kernel_console.cur_attr =
3132	kernel_console.cur_color = kernel_console.std_color =
3133	kernel_default.std_color;
3134    kernel_console.rev_color = kernel_default.rev_color;
3135
3136    /* initialize mapscrn arrays to a one to one map */
3137    for (i=0; i<sizeof(scr_map); i++) {
3138	scr_map[i] = scr_rmap[i] = i;
3139    }
3140
3141    /* Save font and palette if VGA */
3142    if (crtc_vga) {
3143	if (fonts_loaded & FONT_16) {
3144		copy_font(LOAD, FONT_16, font_16);
3145	} else {
3146		copy_font(SAVE, FONT_16, font_16);
3147		fonts_loaded = FONT_16;
3148	}
3149	save_palette();
3150	set_destructive_cursor(console[0]);
3151    }
3152
3153#ifdef SC_SPLASH_SCREEN
3154    /*
3155     * Now put up a graphics image, and maybe cycle a
3156     * couble of palette entries for simple animation.
3157     */
3158    toggle_splash_screen(cur_console);
3159#endif
3160}
3161
3162static void
3163map_mode_table(char *map[], char *table, int max)
3164{
3165    int i;
3166
3167    for(i = 0; i < max; ++i)
3168	map[i] = table + i*MODE_PARAM_SIZE;
3169    for(; i < MODE_MAP_SIZE; ++i)
3170	map[i] = NULL;
3171}
3172
3173static u_char
3174map_mode_num(u_char mode)
3175{
3176    static struct {
3177        u_char from;
3178        u_char to;
3179    } mode_map[] = {
3180        { M_ENH_B80x43, M_ENH_B80x25 },
3181        { M_ENH_C80x43, M_ENH_C80x25 },
3182        { M_VGA_M80x30, M_VGA_M80x25 },
3183        { M_VGA_C80x30, M_VGA_C80x25 },
3184        { M_VGA_M80x50, M_VGA_M80x25 },
3185        { M_VGA_C80x50, M_VGA_C80x25 },
3186        { M_VGA_M80x60, M_VGA_M80x25 },
3187        { M_VGA_C80x60, M_VGA_C80x25 },
3188        { M_VGA_MODEX,  M_VGA_CG320 },
3189    };
3190    int i;
3191
3192    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
3193        if (mode_map[i].from == mode)
3194            return mode_map[i].to;
3195    }
3196    return mode;
3197}
3198
3199static char
3200*get_mode_param(scr_stat *scp, u_char mode)
3201{
3202    if (mode >= MODE_MAP_SIZE)
3203	mode = map_mode_num(mode);
3204    if (mode < MODE_MAP_SIZE)
3205	return mode_map[mode];
3206    else
3207	return NULL;
3208}
3209
3210static scr_stat
3211*alloc_scp()
3212{
3213    scr_stat *scp;
3214
3215    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3216    init_scp(scp);
3217    scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos =
3218	(u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3219			  M_DEVBUF, M_WAITOK);
3220    scp->mouse_pos = scp->mouse_oldpos =
3221	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
3222			scp->mouse_xpos/8);
3223    scp->history_head = scp->history_pos =
3224	(u_short *)malloc(scp->history_size*sizeof(u_short),
3225			  M_DEVBUF, M_WAITOK);
3226    bzero(scp->history_head, scp->history_size*sizeof(u_short));
3227    scp->history = scp->history_head;
3228/* SOS
3229    if (crtc_vga && video_mode_ptr)
3230	set_mode(scp);
3231*/
3232    clear_screen(scp);
3233    scp->cursor_saveunder = *scp->cursor_pos;
3234    return scp;
3235}
3236
3237static void
3238init_scp(scr_stat *scp)
3239{
3240    if (crtc_vga)
3241	if (crtc_addr == MONO_BASE)
3242	    scp->mode = M_VGA_M80x25;
3243	else
3244	    scp->mode = M_VGA_C80x25;
3245    else
3246	if (crtc_addr == MONO_BASE)
3247	    scp->mode = M_B80x25;
3248	else
3249	    scp->mode = M_C80x25;
3250    scp->initial_mode = scp->mode;
3251
3252    scp->font_size = 16;
3253    scp->xsize = COL;
3254    scp->ysize = ROW;
3255    scp->xpos = scp->ypos = 0;
3256    scp->saved_xpos = scp->saved_ypos = -1;
3257    scp->start = scp->xsize * scp->ysize;
3258    scp->end = 0;
3259    scp->term.esc = 0;
3260    scp->term.attr_mask = NORMAL_ATTR;
3261    scp->term.cur_attr =
3262	scp->term.cur_color = scp->term.std_color =
3263	current_default->std_color;
3264    scp->term.rev_color = current_default->rev_color;
3265    scp->border = BG_BLACK;
3266    scp->cursor_start = *(char *)pa_to_va(0x461);
3267    scp->cursor_end = *(char *)pa_to_va(0x460);
3268    scp->mouse_xpos = scp->xsize*8/2;
3269    scp->mouse_ypos = scp->ysize*scp->font_size/2;
3270    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3271    scp->mouse_signal = 0;
3272    scp->mouse_pid = 0;
3273    scp->mouse_proc = NULL;
3274    scp->bell_pitch = BELL_PITCH;
3275    scp->bell_duration = BELL_DURATION;
3276    scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3277    scp->status |= CURSOR_ENABLED;
3278    scp->pid = 0;
3279    scp->proc = NULL;
3280    scp->smode.mode = VT_AUTO;
3281    scp->history_head = scp->history_pos = scp->history = NULL;
3282    scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
3283}
3284
3285static u_char
3286*get_fstr(u_int c, u_int *len)
3287{
3288    u_int i;
3289
3290    if (!(c & FKEY))
3291	return(NULL);
3292    i = (c & 0xFF) - F_FN;
3293    if (i > n_fkey_tab)
3294	return(NULL);
3295    *len = fkey_tab[i].len;
3296    return(fkey_tab[i].str);
3297}
3298
3299static void
3300history_to_screen(scr_stat *scp)
3301{
3302    int i;
3303
3304    for (i=0; i<scp->ysize; i++)
3305	bcopy(scp->history + (((scp->history_pos - scp->history) +
3306	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3307	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3308	       scp->xsize * sizeof(u_short));
3309    mark_all(scp);
3310}
3311
3312static int
3313history_up_line(scr_stat *scp)
3314{
3315    if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3316	scp->history_head) {
3317	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3318	history_to_screen(scp);
3319	return 0;
3320    }
3321    else
3322	return -1;
3323}
3324
3325static int
3326history_down_line(scr_stat *scp)
3327{
3328    if (scp->history_pos != scp->history_head) {
3329	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3330	history_to_screen(scp);
3331	return 0;
3332    }
3333    else
3334	return -1;
3335}
3336
3337/*
3338 * scgetc(flags) - get character from keyboard.
3339 * If flags & SCGETC_CN, then avoid harmful side effects.
3340 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3341 * return NOKEY if there is nothing there.
3342 */
3343static u_int
3344scgetc(u_int flags)
3345{
3346    struct key_t *key;
3347    u_char scancode, keycode;
3348    u_int state, action;
3349    int c;
3350    static u_char esc_flag = 0, compose = 0;
3351    static u_int chr = 0;
3352
3353next_code:
3354    /* first see if there is something in the keyboard port */
3355    if (flags & SCGETC_NONBLOCK) {
3356	c = read_kbd_data_no_wait(sc_kbdc);
3357	if (c == -1)
3358	    return(NOKEY);
3359    } else {
3360	do {
3361	    c = read_kbd_data(sc_kbdc);
3362	} while(c == -1);
3363    }
3364    scancode = (u_char)c;
3365
3366    /* do the /dev/random device a favour */
3367    if (!(flags & SCGETC_CN))
3368	add_keyboard_randomness(scancode);
3369
3370    if (cur_console->status & KBD_RAW_MODE)
3371	return scancode;
3372
3373    keycode = scancode & 0x7F;
3374    switch (esc_flag) {
3375    case 0x00:      /* normal scancode */
3376	switch(scancode) {
3377	case 0xB8:  /* left alt (compose key) */
3378	    if (compose) {
3379		compose = 0;
3380		if (chr > 255) {
3381		    do_bell(cur_console,
3382			BELL_PITCH, BELL_DURATION);
3383		    chr = 0;
3384		}
3385	    }
3386	    break;
3387	case 0x38:
3388	    if (!compose) {
3389		compose = 1;
3390		chr = 0;
3391	    }
3392	    break;
3393	case 0xE0:
3394	case 0xE1:
3395	    esc_flag = scancode;
3396	    goto next_code;
3397	}
3398	break;
3399    case 0xE0:      /* 0xE0 prefix */
3400	esc_flag = 0;
3401	switch (keycode) {
3402	case 0x1C:  /* right enter key */
3403	    keycode = 0x59;
3404	    break;
3405	case 0x1D:  /* right ctrl key */
3406	    keycode = 0x5A;
3407	    break;
3408	case 0x35:  /* keypad divide key */
3409	    keycode = 0x5B;
3410	    break;
3411	case 0x37:  /* print scrn key */
3412	    keycode = 0x5C;
3413	    break;
3414	case 0x38:  /* right alt key (alt gr) */
3415	    keycode = 0x5D;
3416	    break;
3417	case 0x47:  /* grey home key */
3418	    keycode = 0x5E;
3419	    break;
3420	case 0x48:  /* grey up arrow key */
3421	    keycode = 0x5F;
3422	    break;
3423	case 0x49:  /* grey page up key */
3424	    keycode = 0x60;
3425	    break;
3426	case 0x4B:  /* grey left arrow key */
3427	    keycode = 0x61;
3428	    break;
3429	case 0x4D:  /* grey right arrow key */
3430	    keycode = 0x62;
3431	    break;
3432	case 0x4F:  /* grey end key */
3433	    keycode = 0x63;
3434	    break;
3435	case 0x50:  /* grey down arrow key */
3436	    keycode = 0x64;
3437	    break;
3438	case 0x51:  /* grey page down key */
3439	    keycode = 0x65;
3440	    break;
3441	case 0x52:  /* grey insert key */
3442	    keycode = 0x66;
3443	    break;
3444	case 0x53:  /* grey delete key */
3445	    keycode = 0x67;
3446	    break;
3447
3448	/* the following 3 are only used on the MS "Natural" keyboard */
3449	case 0x5b:  /* left Window key */
3450	    keycode = 0x69;
3451	    break;
3452	case 0x5c:  /* right Window key */
3453	    keycode = 0x6a;
3454	    break;
3455	case 0x5d:  /* menu key */
3456	    keycode = 0x6b;
3457	    break;
3458	default:    /* ignore everything else */
3459	    goto next_code;
3460	}
3461	break;
3462    case 0xE1:      /* 0xE1 prefix */
3463	esc_flag = 0;
3464	if (keycode == 0x1D)
3465	    esc_flag = 0x1D;
3466	goto next_code;
3467	/* NOT REACHED */
3468    case 0x1D:      /* pause / break */
3469	esc_flag = 0;
3470	if (keycode != 0x45)
3471	    goto next_code;
3472	keycode = 0x68;
3473	break;
3474    }
3475
3476    if (cur_console->status & KBD_CODE_MODE)
3477	return (keycode | (scancode & 0x80));
3478
3479    /* if scroll-lock pressed allow history browsing */
3480    if (cur_console->history && cur_console->status & SLKED) {
3481	int i;
3482
3483	cur_console->status &= ~CURSOR_ENABLED;
3484	if (!(cur_console->status & BUFFER_SAVED)) {
3485	    cur_console->status |= BUFFER_SAVED;
3486	    cur_console->history_save = cur_console->history_head;
3487
3488	    /* copy screen into top of history buffer */
3489	    for (i=0; i<cur_console->ysize; i++) {
3490		bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3491		       cur_console->history_head,
3492		       cur_console->xsize * sizeof(u_short));
3493		cur_console->history_head += cur_console->xsize;
3494		if (cur_console->history_head + cur_console->xsize >
3495		    cur_console->history + cur_console->history_size)
3496		    cur_console->history_head=cur_console->history;
3497	    }
3498	    cur_console->history_pos = cur_console->history_head;
3499	    history_to_screen(cur_console);
3500	}
3501	switch (scancode) {
3502	case 0x47:  /* home key */
3503	    cur_console->history_pos = cur_console->history_head;
3504	    history_to_screen(cur_console);
3505	    goto next_code;
3506
3507	case 0x4F:  /* end key */
3508	    cur_console->history_pos =
3509		WRAPHIST(cur_console, cur_console->history_head,
3510			 cur_console->xsize*cur_console->ysize);
3511	    history_to_screen(cur_console);
3512	    goto next_code;
3513
3514	case 0x48:  /* up arrow key */
3515	    if (history_up_line(cur_console))
3516		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3517	    goto next_code;
3518
3519	case 0x50:  /* down arrow key */
3520	    if (history_down_line(cur_console))
3521		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3522	    goto next_code;
3523
3524	case 0x49:  /* page up key */
3525	    for (i=0; i<cur_console->ysize; i++)
3526	    if (history_up_line(cur_console)) {
3527		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3528		break;
3529	    }
3530	    goto next_code;
3531
3532	case 0x51:  /* page down key */
3533	    for (i=0; i<cur_console->ysize; i++)
3534	    if (history_down_line(cur_console)) {
3535		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3536		break;
3537	    }
3538	    goto next_code;
3539	}
3540    }
3541
3542    if (compose) {
3543	switch (scancode) {
3544	/* key pressed process it */
3545	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
3546	    chr = (scancode - 0x40) + chr*10;
3547	    goto next_code;
3548	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
3549	    chr = (scancode - 0x47) + chr*10;
3550	    goto next_code;
3551	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
3552	    chr = (scancode - 0x4E) + chr*10;
3553	    goto next_code;
3554	case 0x52:              /* keypad 0 */
3555	    chr *= 10;
3556	    goto next_code;
3557
3558	/* key release, no interest here */
3559	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
3560	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
3561	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
3562	case 0xD2:              /* keypad 0 */
3563	    goto next_code;
3564
3565	case 0x38:              /* left alt key */
3566	    break;
3567	default:
3568	    if (chr) {
3569		compose = chr = 0;
3570		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3571		goto next_code;
3572	    }
3573	    break;
3574	}
3575    }
3576
3577    state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
3578    if ((!agrs && (cur_console->status & ALKED))
3579	|| (agrs && !(cur_console->status & ALKED)))
3580	keycode += ALTGR_OFFSET;
3581    key = &key_map.key[keycode];
3582    if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
3583	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
3584	state ^= 1;
3585
3586    /* Check for make/break */
3587    action = key->map[state];
3588    if (scancode & 0x80) {      /* key released */
3589	if (key->spcl & (0x80>>state)) {
3590	    switch (action) {
3591	    case LSH:
3592		shfts &= ~1;
3593		break;
3594	    case RSH:
3595		shfts &= ~2;
3596		break;
3597	    case LCTR:
3598		ctls &= ~1;
3599		break;
3600	    case RCTR:
3601		ctls &= ~2;
3602		break;
3603	    case LALT:
3604		alts &= ~1;
3605		break;
3606	    case RALT:
3607		alts &= ~2;
3608		break;
3609	    case NLK:
3610		nlkcnt = 0;
3611		break;
3612	    case CLK:
3613		clkcnt = 0;
3614		break;
3615	    case SLK:
3616		slkcnt = 0;
3617		break;
3618	    case ASH:
3619		agrs = 0;
3620		break;
3621	    case ALK:
3622		alkcnt = 0;
3623		break;
3624	    case META:
3625		metas = 0;
3626		break;
3627	    }
3628	}
3629	if (chr && !compose) {
3630	    action = chr;
3631	    chr = 0;
3632	    return(action);
3633	}
3634    } else {
3635	/* key pressed */
3636	if (key->spcl & (0x80>>state)) {
3637	    switch (action) {
3638	    /* LOCKING KEYS */
3639	    case NLK:
3640#ifdef SC_SPLASH_SCREEN
3641		toggle_splash_screen(cur_console); /* SOS XXX */
3642#endif
3643		if (!nlkcnt) {
3644		    nlkcnt++;
3645		    if (cur_console->status & NLKED)
3646			cur_console->status &= ~NLKED;
3647		    else
3648			cur_console->status |= NLKED;
3649		    update_leds(cur_console->status);
3650		}
3651		break;
3652	    case CLK:
3653		if (!clkcnt) {
3654		    clkcnt++;
3655		    if (cur_console->status & CLKED)
3656			cur_console->status &= ~CLKED;
3657		    else
3658			cur_console->status |= CLKED;
3659		    update_leds(cur_console->status);
3660		}
3661		break;
3662	    case SLK:
3663		if (!slkcnt) {
3664		    slkcnt++;
3665		    if (cur_console->status & SLKED) {
3666			cur_console->status &= ~SLKED;
3667			if (cur_console->status & BUFFER_SAVED){
3668			    int i;
3669			    u_short *ptr = cur_console->history_save;
3670
3671			    for (i=0; i<cur_console->ysize; i++) {
3672				bcopy(ptr,
3673				       cur_console->scr_buf +
3674				       (cur_console->xsize*i),
3675				       cur_console->xsize * sizeof(u_short));
3676				ptr += cur_console->xsize;
3677				if (ptr + cur_console->xsize >
3678				    cur_console->history +
3679				    cur_console->history_size)
3680				    ptr = cur_console->history;
3681			    }
3682			    cur_console->status &= ~BUFFER_SAVED;
3683			    cur_console->history_head=cur_console->history_save;
3684			    cur_console->status |= CURSOR_ENABLED;
3685			    mark_all(cur_console);
3686			}
3687			scstart(VIRTUAL_TTY(get_scr_num()));
3688		    }
3689		    else
3690			cur_console->status |= SLKED;
3691		    update_leds(cur_console->status);
3692		}
3693		break;
3694	    case ALK:
3695		if (!alkcnt) {
3696		    alkcnt++;
3697		    if (cur_console->status & ALKED)
3698			cur_console->status &= ~ALKED;
3699		    else
3700			cur_console->status |= ALKED;
3701		    update_leds(cur_console->status);
3702		}
3703		break;
3704
3705	    /* NON-LOCKING KEYS */
3706	    case NOP:
3707		break;
3708	    case SPSC:
3709#ifdef SC_SPLASH_SCREEN
3710		accents = 0;
3711		toggle_splash_screen(cur_console);
3712#endif
3713		break;
3714	    case RBT:
3715		accents = 0;
3716		shutdown_nice();
3717		break;
3718	    case SUSP:
3719#if NAPM > 0
3720		accents = 0;
3721		apm_suspend();
3722#endif
3723		break;
3724
3725	    case DBG:
3726#ifdef DDB          /* try to switch to console 0 */
3727		accents = 0;
3728		if (cur_console->smode.mode == VT_AUTO &&
3729		    console[0]->smode.mode == VT_AUTO)
3730		    switch_scr(cur_console, 0);
3731		Debugger("manual escape to debugger");
3732#else
3733		printf("No debugger in kernel\n");
3734#endif
3735		break;
3736	    case LSH:
3737		shfts |= 1;
3738		break;
3739	    case RSH:
3740		shfts |= 2;
3741		break;
3742	    case LCTR:
3743		ctls |= 1;
3744		break;
3745	    case RCTR:
3746		ctls |= 2;
3747		break;
3748	    case LALT:
3749		alts |= 1;
3750		break;
3751	    case RALT:
3752		alts |= 2;
3753		break;
3754	    case ASH:
3755		agrs = 1;
3756		break;
3757	    case META:
3758		metas = 1;
3759		break;
3760	    case NEXT:
3761		{
3762		int next, this = get_scr_num();
3763		for (next = this+1; next != this; next = (next+1)%MAXCONS) {
3764		    struct tty *tp = VIRTUAL_TTY(next);
3765		    if (tp->t_state & TS_ISOPEN) {
3766			switch_scr(cur_console, next);
3767			break;
3768		    }
3769		}
3770		}
3771		break;
3772	    case BTAB:
3773		accents = 0;
3774		return(BKEY);
3775	    default:
3776		if (action >= F_ACC && action <= L_ACC) {
3777		    accents = action - F_ACC + 1;
3778		    if (accent_map.acc[accents - 1].accchar == 0) {
3779			accents = 0;
3780			do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3781		    }
3782		    break;
3783		}
3784		if (accents > 0) {
3785		    accents = 0;
3786		    do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3787		}
3788		if (action >= F_SCR && action <= L_SCR) {
3789		    switch_scr(cur_console, action - F_SCR);
3790		    break;
3791		}
3792		if (action >= F_FN && action <= L_FN)
3793		    action |= FKEY;
3794		return(action);
3795	    }
3796	}
3797	else {
3798	    if (accents) {
3799		struct acc_t *acc;
3800		int i;
3801
3802		acc = &accent_map.acc[accents - 1];
3803		accents = 0;
3804		if (action == ' ') {
3805		    action = acc->accchar;
3806		    if (metas)
3807			action |= MKEY;
3808		    return (action);
3809		}
3810		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
3811		    if (acc->map[i][0] == 0)
3812			break;
3813		    if (acc->map[i][0] == action) {
3814			action = acc->map[i][1];
3815			if (metas)
3816			    action |= MKEY;
3817			return (action);
3818		    }
3819		}
3820		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3821		goto next_code;
3822	    }
3823	    if (metas)
3824		action |= MKEY;
3825	    return(action);
3826	}
3827    }
3828    goto next_code;
3829}
3830
3831int
3832scmmap(dev_t dev, int offset, int nprot)
3833{
3834    if (offset > 0x20000 - PAGE_SIZE)
3835	return -1;
3836    return i386_btop((VIDEOMEM + offset));
3837}
3838
3839/*
3840 * Calculate hardware attributes word using logical attributes mask and
3841 * hardware colors
3842 */
3843
3844static int
3845mask2attr(struct term_stat *term)
3846{
3847    int attr, mask = term->attr_mask;
3848
3849    if (mask & REVERSE_ATTR) {
3850	attr = ((mask & FOREGROUND_CHANGED) ?
3851		((term->cur_color & 0xF000) >> 4) :
3852		(term->rev_color & 0x0F00)) |
3853	       ((mask & BACKGROUND_CHANGED) ?
3854		((term->cur_color & 0x0F00) << 4) :
3855		(term->rev_color & 0xF000));
3856    } else
3857	attr = term->cur_color;
3858
3859    /* XXX: underline mapping for Hercules adapter can be better */
3860    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3861	attr ^= 0x0800;
3862    if (mask & BLINK_ATTR)
3863	attr ^= 0x8000;
3864
3865    return attr;
3866}
3867
3868static void
3869set_keyboard(int command, int data)
3870{
3871    int s;
3872
3873    if (sc_kbdc == NULL)
3874	return;
3875
3876    /* prevent the timeout routine from polling the keyboard */
3877    if (!kbdc_lock(sc_kbdc, TRUE))
3878	return;
3879
3880    /* disable the keyboard and mouse interrupt */
3881    s = spltty();
3882#if 0
3883    c = get_controller_command_byte(sc_kbdc);
3884    if ((c == -1)
3885	|| !set_controller_command_byte(sc_kbdc,
3886            kbdc_get_device_mask(sc_kbdc),
3887            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
3888                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
3889	/* CONTROLLER ERROR */
3890        kbdc_lock(sc_kbdc, FALSE);
3891	splx(s);
3892	return;
3893    }
3894    /*
3895     * Now that the keyboard controller is told not to generate
3896     * the keyboard and mouse interrupts, call `splx()' to allow
3897     * the other tty interrupts. The clock interrupt may also occur,
3898     * but the timeout routine (`scrn_timer()') will be blocked
3899     * by the lock flag set via `kbdc_lock()'
3900     */
3901    splx(s);
3902#endif
3903
3904    if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
3905        send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
3906
3907#if 0
3908    /* restore the interrupts */
3909    if (!set_controller_command_byte(sc_kbdc,
3910            kbdc_get_device_mask(sc_kbdc),
3911	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
3912	/* CONTROLLER ERROR */
3913    }
3914#else
3915    splx(s);
3916#endif
3917    kbdc_lock(sc_kbdc, FALSE);
3918}
3919
3920static void
3921update_leds(int which)
3922{
3923    static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
3924
3925    /* replace CAPS led with ALTGR led for ALTGR keyboards */
3926    if (key_map.n_keys > ALTGR_OFFSET) {
3927	if (which & ALKED)
3928	    which |= CLKED;
3929	else
3930	    which &= ~CLKED;
3931    }
3932
3933    set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
3934}
3935
3936void
3937set_mode(scr_stat *scp)
3938{
3939    char special_modetable[MODE_PARAM_SIZE];
3940    char *mp;
3941
3942    if (scp != cur_console)
3943	return;
3944
3945    /*
3946     * even if mode switching is disabled, we can change back
3947     * to the initial mode or the custom mode based on the initial
3948     * mode if we have saved register values upon start-up.
3949     */
3950    mp = get_mode_param(scp, scp->mode);
3951    if (mp == NULL)
3952	return;
3953    bcopy(mp, &special_modetable, sizeof(special_modetable));
3954
3955    /* setup video hardware for the given mode */
3956    switch (scp->mode) {
3957    case M_VGA_C80x60: case M_VGA_M80x60:
3958	special_modetable[2]  = 0x08;
3959	special_modetable[19] = 0x47;
3960	goto special_480l;
3961
3962    case M_VGA_C80x30: case M_VGA_M80x30:
3963	special_modetable[19] = 0x4f;
3964special_480l:
3965	special_modetable[9] |= 0xc0;
3966	special_modetable[16] = 0x08;
3967	special_modetable[17] = 0x3e;
3968	special_modetable[26] = 0xea;
3969	special_modetable[28] = 0xdf;
3970	special_modetable[31] = 0xe7;
3971	special_modetable[32] = 0x04;
3972	goto setup_mode;
3973
3974    case M_ENH_C80x43: case M_ENH_B80x43:
3975	special_modetable[28] = 87;
3976	goto special_80x50;
3977
3978    case M_VGA_C80x50: case M_VGA_M80x50:
3979special_80x50:
3980	special_modetable[2] = 8;
3981	special_modetable[19] = 7;
3982	goto setup_mode;
3983
3984    case M_VGA_C40x25: case M_VGA_C80x25:
3985    case M_VGA_M80x25:
3986    case M_B40x25:     case M_C40x25:
3987    case M_B80x25:     case M_C80x25:
3988    case M_ENH_B40x25: case M_ENH_C40x25:
3989    case M_ENH_B80x25: case M_ENH_C80x25:
3990    case M_EGAMONO80x25:
3991
3992setup_mode:
3993	set_vgaregs(special_modetable);
3994	scp->font_size = special_modetable[2];
3995
3996	/* set font type (size) */
3997	if (scp->font_size < 14) {
3998	    if (fonts_loaded & FONT_8)
3999		copy_font(LOAD, FONT_8, font_8);
4000	    outb(TSIDX, 0x03); outb(TSREG, 0x0A);   /* font 2 */
4001	} else if (scp->font_size >= 16) {
4002	    if (fonts_loaded & FONT_16)
4003		copy_font(LOAD, FONT_16, font_16);
4004	    outb(TSIDX, 0x03); outb(TSREG, 0x00);   /* font 0 */
4005	} else {
4006	    if (fonts_loaded & FONT_14)
4007		copy_font(LOAD, FONT_14, font_14);
4008	    outb(TSIDX, 0x03); outb(TSREG, 0x05);   /* font 1 */
4009	}
4010	if (flags & CHAR_CURSOR)
4011	    set_destructive_cursor(scp);
4012	mark_all(scp);
4013	break;
4014
4015    case M_VGA_MODEX:
4016	/* "unchain" the VGA mode */
4017	special_modetable[5-1+0x04] &= 0xf7;
4018	special_modetable[5-1+0x04] |= 0x04;
4019	/* turn off doubleword mode */
4020	special_modetable[10+0x14] &= 0xbf;
4021	/* turn off word adressing */
4022	special_modetable[10+0x17] |= 0x40;
4023	/* set logical screen width */
4024	special_modetable[10+0x13] = 80;
4025	/* set 240 lines */
4026	special_modetable[10+0x11] = 0x2c;
4027	special_modetable[10+0x06] = 0x0d;
4028	special_modetable[10+0x07] = 0x3e;
4029	special_modetable[10+0x10] = 0xea;
4030	special_modetable[10+0x11] = 0xac;
4031	special_modetable[10+0x12] = 0xdf;
4032	special_modetable[10+0x15] = 0xe7;
4033	special_modetable[10+0x16] = 0x06;
4034	/* set vertical sync polarity to reflect aspect ratio */
4035	special_modetable[9] = 0xe3;
4036	goto setup_grmode;
4037
4038    case M_BG320:     case M_CG320:     case M_BG640:
4039    case M_CG320_D:   case M_CG640_E:
4040    case M_CG640x350: case M_ENH_CG640:
4041    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
4042
4043setup_grmode:
4044	set_vgaregs(special_modetable);
4045	scp->font_size = FONT_NONE;
4046	break;
4047
4048    default:
4049	/* call user defined function XXX */
4050	break;
4051    }
4052
4053    /* set border color for this (virtual) console */
4054    set_border(scp->border);
4055    return;
4056}
4057
4058void
4059set_border(u_char color)
4060{
4061    switch (crtc_type) {
4062    case KD_EGA:
4063    case KD_VGA:
4064        inb(crtc_addr + 6);		/* reset flip-flop */
4065        outb(ATC, 0x31); outb(ATC, color);
4066	break;
4067    case KD_CGA:
4068	outb(crtc_addr + 5, color & 0x0f); /* color select register */
4069	break;
4070    case KD_MONO:
4071    case KD_HERCULES:
4072    default:
4073	break;
4074    }
4075}
4076
4077static void
4078set_vgaregs(char *modetable)
4079{
4080    int i, s = splhigh();
4081
4082    outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
4083    outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
4084    for (i=0; i<4; i++) {           		/* program sequencer */
4085	outb(TSIDX, i+1);
4086	outb(TSREG, modetable[i+5]);
4087    }
4088    outb(MISC, modetable[9]);       		/* set dot-clock */
4089    outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
4090    outb(crtc_addr, 0x11);
4091    outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
4092    for (i=0; i<25; i++) {          		/* program crtc */
4093	outb(crtc_addr, i);
4094	if (i == 14 || i == 15)     		/* no hardware cursor */
4095	    outb(crtc_addr+1, 0xff);
4096	else
4097	    outb(crtc_addr+1, modetable[i+10]);
4098    }
4099    inb(crtc_addr+6);           		/* reset flip-flop */
4100    for (i=0; i<20; i++) {          		/* program attribute ctrl */
4101	outb(ATC, i);
4102	outb(ATC, modetable[i+35]);
4103    }
4104    for (i=0; i<9; i++) {           		/* program graph data ctrl */
4105	outb(GDCIDX, i);
4106	outb(GDCREG, modetable[i+55]);
4107    }
4108    inb(crtc_addr+6);           		/* reset flip-flop */
4109    outb(ATC, 0x20);            		/* enable palette */
4110    splx(s);
4111}
4112
4113static void
4114read_vgaregs(char *buf)
4115{
4116    int i, j;
4117    int s;
4118
4119    bzero(buf, MODE_PARAM_SIZE);
4120
4121    s = splhigh();
4122
4123    outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
4124    outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
4125    for (i=0, j=5; i<4; i++) {
4126	outb(TSIDX, i+1);
4127	buf[j++] = inb(TSREG);
4128    }
4129    buf[9] = inb(MISC + 10);      		/* dot-clock */
4130    outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
4131
4132    for (i=0, j=10; i<25; i++) {       		/* crtc */
4133	outb(crtc_addr, i);
4134	buf[j++] = inb(crtc_addr+1);
4135    }
4136    for (i=0, j=35; i<20; i++) {          	/* attribute ctrl */
4137        inb(crtc_addr+6);           		/* reset flip-flop */
4138	outb(ATC, i);
4139	buf[j++] = inb(ATC + 1);
4140    }
4141    for (i=0, j=55; i<9; i++) {           	/* graph data ctrl */
4142	outb(GDCIDX, i);
4143	buf[j++] = inb(GDCREG);
4144    }
4145    inb(crtc_addr+6);           		/* reset flip-flop */
4146    outb(ATC, 0x20);            		/* enable palette */
4147
4148    buf[0] = *(char *)pa_to_va(0x44a);		/* COLS */
4149    buf[1] = *(char *)pa_to_va(0x484);		/* ROWS */
4150    buf[2] = *(char *)pa_to_va(0x485);		/* POINTS */
4151    buf[3] = *(char *)pa_to_va(0x44c);
4152    buf[4] = *(char *)pa_to_va(0x44d);
4153
4154    splx(s);
4155}
4156
4157static int
4158comp_vgaregs(u_char *buf1, u_char *buf2)
4159{
4160    static struct {
4161        u_char mask;
4162    } params[MODE_PARAM_SIZE] = {
4163	0xff, 0x00, 0xff, 		/* COLS, ROWS, POINTS */
4164	0xff, 0xff, 			/* page length */
4165	0xfe, 0xff, 0xff, 0xff,		/* sequencer registers */
4166	0xf3,				/* misc register */
4167	0xff, 0xff, 0xff, 0x7f, 0xff,	/* CRTC */
4168	0xff, 0xff, 0xff, 0x7f, 0xff,
4169	0x00, 0x00, 0x00, 0x00, 0x00,
4170	0x00, 0xff, 0x7f, 0xff, 0xff,
4171	0x7f, 0xff, 0xff, 0xef, 0xff,
4172	0xff, 0xff, 0xff, 0xff, 0xff,	/* attribute controller registers */
4173	0xff, 0xff, 0xff, 0xff, 0xff,
4174	0xff, 0xff, 0xff, 0xff, 0xff,
4175	0xff, 0xff, 0xff, 0xff, 0xf0,
4176	0xff, 0xff, 0xff, 0xff, 0xff,	/* GDC register */
4177	0xff, 0xff, 0xff, 0xff,
4178    };
4179    int identical = TRUE;
4180    int i;
4181
4182    for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
4183	if (params[i].mask == 0)	/* don't care */
4184	    continue;
4185	if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
4186	    return COMP_DIFFERENT;
4187	if (buf1[i] != buf2[i])
4188	    identical = FALSE;
4189    }
4190    return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
4191
4192#if 0
4193    for(i = 0; i < 20; ++i) {
4194	if (*buf1++ != *buf2++)
4195	    return COMP_DIFFERENT;
4196    }
4197    buf1 += 2;  /* skip the cursor shape */
4198    buf2 += 2;
4199    for(i = 22; i < 24; ++i) {
4200	if (*buf1++ != *buf2++)
4201	    return COMP_DIFFERENT;
4202    }
4203    buf1 += 2;  /* skip the cursor position */
4204    buf2 += 2;
4205    for(i = 26; i < MODE_PARAM_SIZE; ++i) {
4206	if (*buf1++ != *buf2++)
4207	    return COMP_DIFFERENT;
4208    }
4209    return COMP_IDENTICAL;
4210#endif
4211}
4212
4213static void
4214dump_vgaregs(u_char *buf)
4215{
4216    int i;
4217
4218    for(i = 0; i < MODE_PARAM_SIZE;) {
4219	printf("%02x ", buf[i]);
4220	if ((++i % 16) == 0)
4221	    printf("\n");
4222    }
4223}
4224
4225static void
4226set_font_mode(u_char *buf)
4227{
4228    int s = splhigh();
4229
4230    /* save register values */
4231    outb(TSIDX, 0x02); buf[0] = inb(TSREG);
4232    outb(TSIDX, 0x04); buf[1] = inb(TSREG);
4233    outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
4234    outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
4235    outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
4236    inb(crtc_addr + 6);
4237    outb(ATC, 0x10); buf[5] = inb(ATC + 1);
4238
4239    /* setup vga for loading fonts (graphics plane mode) */
4240    inb(crtc_addr+6);           		/* reset flip-flop */
4241    outb(ATC, 0x10); outb(ATC, 0x01);
4242    inb(crtc_addr+6);               		/* reset flip-flop */
4243    outb(ATC, 0x20);            		/* enable palette */
4244
4245#if SLOW_VGA
4246    outb(TSIDX, 0x02); outb(TSREG, 0x04);
4247    outb(TSIDX, 0x04); outb(TSREG, 0x06);
4248    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
4249    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
4250    outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
4251#else
4252    outw(TSIDX, 0x0402);
4253    outw(TSIDX, 0x0604);
4254    outw(GDCIDX, 0x0204);
4255    outw(GDCIDX, 0x0005);
4256    outw(GDCIDX, 0x0506);               /* addr = a0000, 64kb */
4257#endif
4258    splx(s);
4259}
4260
4261static void
4262set_normal_mode(u_char *buf)
4263{
4264    char *modetable;
4265    int s = splhigh();
4266
4267    /* setup vga for normal operation mode again */
4268    inb(crtc_addr+6);           		/* reset flip-flop */
4269    outb(ATC, 0x10); outb(ATC, buf[5]);
4270    inb(crtc_addr+6);               		/* reset flip-flop */
4271    outb(ATC, 0x20);            		/* enable palette */
4272
4273#if SLOW_VGA
4274    outb(TSIDX, 0x02); outb(TSREG, buf[0]);
4275    outb(TSIDX, 0x04); outb(TSREG, buf[1]);
4276    outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
4277    outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
4278    if (crtc_addr == MONO_BASE) {
4279	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
4280    } else {
4281	outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
4282    }
4283#else
4284    outw(TSIDX, 0x0002 | (buf[0] << 8));
4285    outw(TSIDX, 0x0004 | (buf[1] << 8));
4286    outw(GDCIDX, 0x0004 | (buf[2] << 8));
4287    outw(GDCIDX, 0x0005 | (buf[3] << 8));
4288    if (crtc_addr == MONO_BASE)
4289        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
4290    else
4291        outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
4292#endif
4293    splx(s);
4294}
4295
4296void
4297copy_font(int operation, int font_type, char* font_image)
4298{
4299    int ch, line, segment, fontsize;
4300    u_char buf[PARAM_BUFSIZE];
4301    u_char val;
4302
4303    switch (font_type) {
4304    default:
4305    case FONT_8:
4306	segment = 0x8000;
4307	fontsize = 8;
4308	break;
4309    case FONT_14:
4310	segment = 0x4000;
4311	fontsize = 14;
4312	break;
4313    case FONT_16:
4314	segment = 0x0000;
4315	fontsize = 16;
4316	break;
4317    }
4318    outb(TSIDX, 0x01); val = inb(TSREG);        /* disable screen */
4319    outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
4320    set_font_mode(buf);
4321    for (ch=0; ch < 256; ch++)
4322	for (line=0; line < fontsize; line++)
4323	if (operation)
4324	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
4325		    font_image[(ch*fontsize)+line];
4326	else
4327	    font_image[(ch*fontsize)+line] =
4328	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
4329    set_normal_mode(buf);
4330    outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
4331}
4332
4333static void
4334set_destructive_cursor(scr_stat *scp)
4335{
4336    u_char buf[PARAM_BUFSIZE];
4337    u_char cursor[32];
4338    caddr_t address;
4339    int i;
4340    char *font_buffer;
4341
4342    if (scp->font_size < 14) {
4343	font_buffer = font_8;
4344	address = (caddr_t)VIDEOMEM + 0x8000;
4345    }
4346    else if (scp->font_size >= 16) {
4347	font_buffer = font_16;
4348	address = (caddr_t)VIDEOMEM;
4349    }
4350    else {
4351	font_buffer = font_14;
4352	address = (caddr_t)VIDEOMEM + 0x4000;
4353    }
4354
4355    if (scp->status & MOUSE_VISIBLE) {
4356	if ((scp->cursor_saveunder & 0xff) == 0xd0)
4357    	    bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4358	else if ((scp->cursor_saveunder & 0xff) == 0xd1)
4359    	    bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4360	else if ((scp->cursor_saveunder & 0xff) == 0xd2)
4361    	    bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4362	else if ((scp->cursor_saveunder & 0xff) == 0xd3)
4363    	    bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4364	else
4365	    bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4366 	       	   cursor, scp->font_size);
4367    }
4368    else
4369    	bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4370 	       cursor, scp->font_size);
4371    for (i=0; i<32; i++)
4372	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4373	    (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4374	    cursor[i] |= 0xff;
4375#if 1
4376    while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4377#endif
4378    set_font_mode(buf);
4379    sc_bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
4380    set_normal_mode(buf);
4381}
4382
4383static void
4384set_mouse_pos(scr_stat *scp)
4385{
4386    static int last_xpos = -1, last_ypos = -1;
4387
4388    if (scp->mouse_xpos < 0)
4389	scp->mouse_xpos = 0;
4390    if (scp->mouse_ypos < 0)
4391	scp->mouse_ypos = 0;
4392    if (scp->status & UNKNOWN_MODE) {
4393        if (scp->mouse_xpos > scp->xpixel-1)
4394	    scp->mouse_xpos = scp->xpixel-1;
4395        if (scp->mouse_ypos > scp->ypixel-1)
4396	    scp->mouse_ypos = scp->ypixel-1;
4397	return;
4398    }
4399    if (scp->mouse_xpos > (scp->xsize*8)-1)
4400	scp->mouse_xpos = (scp->xsize*8)-1;
4401    if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4402	scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4403
4404    if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4405	scp->status |= MOUSE_MOVED;
4406
4407    	scp->mouse_pos = scp->scr_buf +
4408	    ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4409
4410	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4411	    mouse_cut(scp);
4412    }
4413}
4414
4415#define isspace(c)	(((c) & 0xff) == ' ')
4416
4417static int
4418skip_spc_right(scr_stat *scp, u_short *p)
4419{
4420    int i;
4421
4422    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4423	if (!isspace(*p))
4424	    break;
4425	++p;
4426    }
4427    return i;
4428}
4429
4430static int
4431skip_spc_left(scr_stat *scp, u_short *p)
4432{
4433    int i;
4434
4435    for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4436	if (!isspace(*p))
4437	    break;
4438	--p;
4439    }
4440    return i;
4441}
4442
4443static void
4444mouse_cut(scr_stat *scp)
4445{
4446    u_short *end;
4447    u_short *p;
4448    int i = 0;
4449    int j = 0;
4450
4451    scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4452	scp->mouse_pos + 1 : scp->mouse_pos;
4453    end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4454	scp->mouse_cut_start : scp->mouse_cut_end;
4455    for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4456	    scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4457	cut_buffer[i] = *p & 0xff;
4458	/* remember the position of the last non-space char */
4459	if (!isspace(cut_buffer[i++]))
4460	    j = i;
4461	/* trim trailing blank when crossing lines */
4462	if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4463	    cut_buffer[j++] = '\n';
4464	    i = j;
4465	}
4466    }
4467    cut_buffer[i] = '\0';
4468
4469    /* scan towards the end of the last line */
4470    --p;
4471    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4472	if (!isspace(*p))
4473	    break;
4474	++p;
4475    }
4476    /* if there is nothing but blank chars, trim them, but mark towards eol */
4477    if (i >= scp->xsize) {
4478	if (scp->mouse_cut_start > scp->mouse_cut_end)
4479	    scp->mouse_cut_start = p;
4480	else
4481	    scp->mouse_cut_end = p;
4482	cut_buffer[j++] = '\n';
4483	cut_buffer[j] = '\0';
4484    }
4485
4486    mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
4487    mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
4488}
4489
4490static void
4491mouse_cut_start(scr_stat *scp)
4492{
4493    int i;
4494
4495    if (scp->status & MOUSE_VISIBLE) {
4496	if (scp->mouse_pos == scp->mouse_cut_start &&
4497	    scp->mouse_cut_start == scp->mouse_cut_end - 1) {
4498	    cut_buffer[0] = '\0';
4499	    remove_cutmarking(scp);
4500	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
4501	    /* if the pointer is on trailing blank chars, mark towards eol */
4502	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
4503	    scp->mouse_cut_start = scp->scr_buf +
4504	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
4505	    scp->mouse_cut_end = scp->scr_buf +
4506	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
4507	    cut_buffer[0] = '\n';
4508	    cut_buffer[1] = '\0';
4509	    scp->status |= MOUSE_CUTTING;
4510	} else {
4511	    scp->mouse_cut_start = scp->mouse_pos;
4512	    scp->mouse_cut_end = scp->mouse_cut_start + 1;
4513	    cut_buffer[0] = *scp->mouse_cut_start & 0xff;
4514	    cut_buffer[1] = '\0';
4515	    scp->status |= MOUSE_CUTTING;
4516	}
4517    	mark_all(scp);
4518	/* delete all other screens cut markings */
4519	for (i=0; i<MAXCONS; i++) {
4520	    if (console[i] == NULL || console[i] == scp)
4521		continue;
4522	    remove_cutmarking(console[i]);
4523	}
4524    }
4525}
4526
4527static void
4528mouse_cut_end(scr_stat *scp)
4529{
4530    if (scp->status & MOUSE_VISIBLE) {
4531	scp->status &= ~MOUSE_CUTTING;
4532    }
4533}
4534
4535static void
4536mouse_cut_word(scr_stat *scp)
4537{
4538    u_short *p;
4539    u_short *sol;
4540    u_short *eol;
4541    int i;
4542
4543    /*
4544     * Because we don't have locale information in the kernel,
4545     * we only distinguish space char and non-space chars.  Punctuation
4546     * chars, symbols and other regular chars are all treated alike.
4547     */
4548    if (scp->status & MOUSE_VISIBLE) {
4549	sol = scp->scr_buf
4550	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4551	eol = sol + scp->xsize;
4552	if (isspace(*scp->mouse_pos)) {
4553	    for (p = scp->mouse_pos; p >= sol; --p)
4554	        if (!isspace(*p))
4555		    break;
4556	    scp->mouse_cut_start = ++p;
4557	    for (p = scp->mouse_pos; p < eol; ++p)
4558	        if (!isspace(*p))
4559		    break;
4560	    scp->mouse_cut_end = p;
4561	} else {
4562	    for (p = scp->mouse_pos; p >= sol; --p)
4563	        if (isspace(*p))
4564		    break;
4565	    scp->mouse_cut_start = ++p;
4566	    for (p = scp->mouse_pos; p < eol; ++p)
4567	        if (isspace(*p))
4568		    break;
4569	    scp->mouse_cut_end = p;
4570	}
4571	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4572	    cut_buffer[i++] = *p & 0xff;
4573	cut_buffer[i] = '\0';
4574	scp->status |= MOUSE_CUTTING;
4575    }
4576}
4577
4578static void
4579mouse_cut_line(scr_stat *scp)
4580{
4581    u_short *p;
4582    int i;
4583
4584    if (scp->status & MOUSE_VISIBLE) {
4585	scp->mouse_cut_start = scp->scr_buf
4586	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4587	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
4588	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4589	    cut_buffer[i++] = *p & 0xff;
4590	cut_buffer[i++] = '\n';
4591	cut_buffer[i] = '\0';
4592	scp->status |= MOUSE_CUTTING;
4593    }
4594}
4595
4596static void
4597mouse_cut_extend(scr_stat *scp)
4598{
4599    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
4600	&& (scp->mouse_cut_start != NULL)) {
4601	mouse_cut(scp);
4602	scp->status |= MOUSE_CUTTING;
4603    }
4604}
4605
4606static void
4607mouse_paste(scr_stat *scp)
4608{
4609    if (scp->status & MOUSE_VISIBLE) {
4610	struct tty *tp;
4611	u_char *ptr = cut_buffer;
4612
4613	tp = VIRTUAL_TTY(get_scr_num());
4614	while (*ptr)
4615	    (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
4616    }
4617}
4618
4619static void
4620draw_mouse_image(scr_stat *scp)
4621{
4622    caddr_t address;
4623    int i;
4624    char *font_buffer;
4625    u_char buf[PARAM_BUFSIZE];
4626    u_short buffer[32];
4627    u_short xoffset, yoffset;
4628    u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
4629    int font_size = scp->font_size;
4630
4631    if (font_size < 14) {
4632	font_buffer = font_8;
4633	address = (caddr_t)VIDEOMEM + 0x8000;
4634    }
4635    else if (font_size >= 16) {
4636	font_buffer = font_16;
4637	address = (caddr_t)VIDEOMEM;
4638    }
4639    else {
4640	font_buffer = font_14;
4641	address = (caddr_t)VIDEOMEM + 0x4000;
4642    }
4643    xoffset = scp->mouse_xpos % 8;
4644    yoffset = scp->mouse_ypos % font_size;
4645
4646    /* prepare mousepointer char's bitmaps */
4647    bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
4648	   &scp->mouse_cursor[0], font_size);
4649    bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
4650	   &scp->mouse_cursor[32], font_size);
4651    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
4652	   &scp->mouse_cursor[64], font_size);
4653    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
4654	   &scp->mouse_cursor[96], font_size);
4655    for (i=0; i<font_size; i++) {
4656	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
4657	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
4658    }
4659
4660    /* now and-or in the mousepointer image */
4661    for (i=0; i<16; i++) {
4662	buffer[i+yoffset] =
4663	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
4664	    | (mouse_or_mask[i] >> xoffset);
4665    }
4666    for (i=0; i<font_size; i++) {
4667	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
4668	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
4669	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
4670	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
4671    }
4672
4673    scp->mouse_oldpos = scp->mouse_pos;
4674
4675#if 1
4676    /* wait for vertical retrace to avoid jitter on some videocards */
4677    while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
4678#endif
4679    set_font_mode(buf);
4680    sc_bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
4681    set_normal_mode(buf);
4682    *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0;
4683    *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2;
4684    if (scp->mouse_xpos < (scp->xsize-1)*8) {
4685    	*(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1;
4686    	*(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3;
4687    }
4688    mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
4689    mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
4690}
4691
4692static void
4693remove_mouse_image(scr_stat *scp)
4694{
4695    u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf);
4696
4697    *(crt_pos) = *(scp->mouse_oldpos);
4698    *(crt_pos+1) = *(scp->mouse_oldpos+1);
4699    *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
4700    *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
4701    mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
4702    mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
4703}
4704
4705static void
4706draw_cutmarking(scr_stat *scp)
4707{
4708    u_short *ptr;
4709    u_short och, nch;
4710
4711    for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
4712	nch = och = *(Crtat + (ptr - scp->scr_buf));
4713	/* are we outside the selected area ? */
4714	if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
4715	            scp->mouse_cut_end : scp->mouse_cut_start) ||
4716	     ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
4717	            scp->mouse_cut_start : scp->mouse_cut_end)) {
4718	    if (ptr != scp->cursor_pos)
4719		nch = (och & 0xff) | (*ptr & 0xff00);
4720	}
4721	else {
4722	    /* are we clear of the cursor image ? */
4723	    if (ptr != scp->cursor_pos)
4724		nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
4725	    else {
4726		if (flags & CHAR_CURSOR)
4727		    nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
4728		else
4729		    if (!(flags & BLINK_CURSOR))
4730		        nch = (och & 0xff) | (*ptr & 0xff00);
4731	    }
4732	}
4733	if (nch != och)
4734	    *(Crtat + (ptr - scp->scr_buf)) = nch;
4735    }
4736}
4737
4738static void
4739remove_cutmarking(scr_stat *scp)
4740{
4741    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
4742    scp->status &= ~MOUSE_CUTTING;
4743    mark_all(scp);
4744}
4745
4746static void
4747save_palette(void)
4748{
4749    int i;
4750
4751    outb(PALRADR, 0x00);
4752    for (i=0x00; i<0x300; i++)
4753	palette[i] = inb(PALDATA);
4754    inb(crtc_addr+6);           /* reset flip/flop */
4755}
4756
4757void
4758load_palette(char *palette)
4759{
4760    int i;
4761
4762    outb(PIXMASK, 0xFF);            /* no pixelmask */
4763    outb(PALWADR, 0x00);
4764    for (i=0x00; i<0x300; i++)
4765	 outb(PALDATA, palette[i]);
4766    inb(crtc_addr+6);           /* reset flip/flop */
4767    outb(ATC, 0x20);            /* enable palette */
4768}
4769
4770static void
4771do_bell(scr_stat *scp, int pitch, int duration)
4772{
4773    if (flags & VISUAL_BELL) {
4774	if (blink_in_progress)
4775	    return;
4776	blink_in_progress = 4;
4777	if (scp != cur_console)
4778	    blink_in_progress += 2;
4779	blink_screen(cur_console);
4780    } else {
4781	if (scp != cur_console)
4782	    pitch *= 2;
4783	sysbeep(pitch, duration);
4784    }
4785}
4786
4787static void
4788blink_screen(void *arg)
4789{
4790    scr_stat *scp = arg;
4791
4792    if ((scp->status & UNKNOWN_MODE) || (blink_in_progress <= 1)) {
4793	blink_in_progress = FALSE;
4794    	mark_all(scp);
4795	if (delayed_next_scr)
4796	    switch_scr(scp, delayed_next_scr - 1);
4797    }
4798    else {
4799	if (blink_in_progress & 1)
4800	    fillw(kernel_default.std_color | scr_map[0x20],
4801		  Crtat, scp->xsize * scp->ysize);
4802	else
4803	    fillw(kernel_default.rev_color | scr_map[0x20],
4804		  Crtat, scp->xsize * scp->ysize);
4805	blink_in_progress--;
4806	timeout(blink_screen, scp, hz / 10);
4807    }
4808}
4809
4810#ifdef SC_SPLASH_SCREEN
4811static void
4812toggle_splash_screen(scr_stat *scp)
4813{
4814    static int toggle = 0;
4815    static u_char save_mode;
4816    int s;
4817
4818    if (video_mode_ptr == NULL)
4819	return;
4820
4821    s = splhigh();
4822    if (toggle) {
4823	scp->mode = save_mode;
4824	scp->status &= ~UNKNOWN_MODE;
4825	set_mode(scp);
4826	load_palette(palette);
4827	toggle = 0;
4828    }
4829    else {
4830	save_mode = scp->mode;
4831	scp->mode = M_VGA_CG320;
4832	scp->status |= UNKNOWN_MODE;
4833	set_mode(scp);
4834	/* load image */
4835	toggle = 1;
4836    }
4837    splx(s);
4838}
4839#endif
4840#endif /* NSC */
4841