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