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