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