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