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