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