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