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