syscons.c revision 39742
1333347Speter/*-
2362181Sdim * Copyright (c) 1992-1998 S�ren Schmidt
3333347Speter * All rights reserved.
4333347Speter *
5333347Speter * Redistribution and use in source and binary forms, with or without
6333347Speter * modification, are permitted provided that the following conditions
7333347Speter * are met:
8333347Speter * 1. Redistributions of source code must retain the above copyright
9333347Speter *    notice, this list of conditions and the following disclaimer,
10333347Speter *    without modification, immediately at the beginning of the file.
11333347Speter * 2. Redistributions in binary form must reproduce the above copyright
12333347Speter *    notice, this list of conditions and the following disclaimer in the
13333347Speter *    documentation and/or other materials provided with the distribution.
14333347Speter * 3. The name of the author may not be used to endorse or promote products
15333347Speter *    derived from this software without specific prior written permission.
16333347Speter *
17333347Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18333347Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19333347Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20333347Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21333347Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22333347Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23333347Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24333347Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25333347Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26333347Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27333347Speter *
28333347Speter *	$Id: syscons.c,v 1.281 1998/09/26 03:38:38 yokota Exp $
29333347Speter */
30333347Speter
31333347Speter#include "sc.h"
32333347Speter#include "apm.h"
33333347Speter#include "opt_ddb.h"
34333347Speter#include "opt_devfs.h"
35333347Speter#include "opt_vesa.h"
36333347Speter#include "opt_vm86.h"
37333347Speter#include "opt_syscons.h"
38333347Speter
39333347Speter#if NSC > 0
40333347Speter#include <sys/param.h>
41333347Speter#include <sys/systm.h>
42333347Speter#include <sys/reboot.h>
43333347Speter#include <sys/conf.h>
44333347Speter#include <sys/proc.h>
45333347Speter#include <sys/signalvar.h>
46333347Speter#include <sys/tty.h>
47333347Speter#include <sys/kernel.h>
48333347Speter#include <sys/malloc.h>
49333347Speter#ifdef	DEVFS
50333347Speter#include <sys/devfsext.h>
51333347Speter#endif
52333347Speter
53333347Speter#include <machine/bootinfo.h>
54333347Speter#include <machine/clock.h>
55333347Speter#include <machine/cons.h>
56333347Speter#include <machine/console.h>
57333347Speter#include <machine/mouse.h>
58333347Speter#include <machine/md_var.h>
59333347Speter#include <machine/psl.h>
60333347Speter#include <machine/frame.h>
61333347Speter#include <machine/pc/display.h>
62333347Speter#include <machine/pc/vesa.h>
63333347Speter#include <machine/apm_bios.h>
64333347Speter#include <machine/random.h>
65333347Speter
66333347Speter#include <vm/vm.h>
67333347Speter#include <vm/vm_param.h>
68333347Speter#include <vm/pmap.h>
69333347Speter
70333347Speter#include <i386/isa/isa.h>
71333347Speter#include <i386/isa/isa_device.h>
72333347Speter#include <i386/isa/timerreg.h>
73333347Speter#include <i386/isa/kbdtables.h>
74333347Speter#include <i386/isa/kbdio.h>
75333347Speter#include <i386/isa/videoio.h>
76333347Speter#include <i386/isa/syscons.h>
77333347Speter
78333347Speter#if !defined(MAXCONS)
79333347Speter#define MAXCONS 16
80333347Speter#endif
81333347Speter
82333347Speter#if !defined(SC_MAX_HISTORY_SIZE)
83333347Speter#define SC_MAX_HISTORY_SIZE	(1000 * MAXCONS)
84333347Speter#endif
85333347Speter
86333347Speter#if !defined(SC_HISTORY_SIZE)
87333347Speter#define SC_HISTORY_SIZE		(ROW * 4)
88333347Speter#endif
89333347Speter
90333347Speter#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
91333347Speter#undef SC_MAX_HISTORY_SIZE
92333347Speter#define SC_MAX_HISTORY_SIZE	(SC_HISTORY_SIZE * MAXCONS)
93333347Speter#endif
94333347Speter
95333347Speter#if !defined(SC_MOUSE_CHAR)
96333347Speter#define SC_MOUSE_CHAR		(0xd0)
97333347Speter#endif
98333347Speter
99333347Speter#define COLD 0
100333347Speter#define WARM 1
101333347Speter
102333347Speter#define DEFAULT_BLANKTIME	(5*60)		/* 5 minutes */
103333347Speter#define MAX_BLANKTIME		(7*24*60*60)	/* 7 days!? */
104333347Speter
105333347Speter/* for backward compatibility */
106333347Speter#define OLD_CONS_MOUSECTL	_IOWR('c', 10, old_mouse_info_t)
107333347Speter
108333347Spetertypedef struct old_mouse_data {
109333347Speter    int x;
110333347Speter    int y;
111333347Speter    int buttons;
112333347Speter} old_mouse_data_t;
113333347Speter
114333347Spetertypedef struct old_mouse_info {
115333347Speter    int operation;
116333347Speter    union {
117333347Speter	struct old_mouse_data data;
118333347Speter	struct mouse_mode mode;
119333347Speter    } u;
120333347Speter} old_mouse_info_t;
121333347Speter
122333347Speter/* XXX use sc_bcopy where video memory is concerned */
123333347Speterextern void generic_bcopy(const void *, void *, size_t);
124333347Speterextern void generic_bzero(void *, size_t);
125333347Speter
126333347Speterstatic default_attr user_default = {
127333347Speter    (FG_LIGHTGREY | BG_BLACK) << 8,
128333347Speter    (FG_BLACK | BG_LIGHTGREY) << 8
129333347Speter};
130333347Speter
131333347Speterstatic default_attr kernel_default = {
132333347Speter    (FG_WHITE | BG_BLACK) << 8,
133333347Speter    (FG_BLACK | BG_LIGHTGREY) << 8
134333347Speter};
135333347Speter
136333347Speterstatic  scr_stat    	main_console;
137333347Speterstatic  scr_stat    	*console[MAXCONS];
138333347Speter#ifdef DEVFS
139333347Speterstatic	void		*sc_devfs_token[MAXCONS];
140333347Speterstatic	void		*sc_mouse_devfs_token;
141333347Speterstatic	void		*sc_console_devfs_token;
142333347Speter#endif
143333347Speter	scr_stat    	*cur_console;
144333347Speterstatic  scr_stat    	*new_scp, *old_scp;
145333347Speterstatic  term_stat   	kernel_console;
146333347Speterstatic  default_attr    *current_default;
147333347Speter	int             sc_flags;
148333347Speterstatic  int		sc_port = IO_KBD;
149333347Speterstatic  KBDC		sc_kbdc = NULL;
150333347Speterstatic  char        	init_done = COLD;
151333347Speterstatic  u_short		sc_buffer[ROW*COL];
152333347Speterstatic  char		shutdown_in_progress = FALSE;
153333347Speterstatic  char        	font_loading_in_progress = FALSE;
154333347Speterstatic  char        	switch_in_progress = FALSE;
155333347Speterstatic  char        	write_in_progress = FALSE;
156333347Speterstatic  char        	blink_in_progress = FALSE;
157333347Speterstatic  int        	blinkrate = 0;
158333347Speter	u_int       	crtc_addr = MONO_BASE;
159333347Speter	char		crtc_type = KD_MONO;
160333347Speterstatic	char        	crtc_vga = FALSE;
161333347Speterstatic	int		adp_flags;
162333347Speterstatic  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
163333347Speterstatic  u_char		accents = 0;
164333347Speterstatic  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
165333347Speterstatic  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
166333347Speterstatic  int     	delayed_next_scr = FALSE;
167333347Speterstatic  long        	scrn_blank_time = 0;    /* screen saver timeout value */
168333347Speter	int     	scrn_blanked = 0;       /* screen saver active flag */
169333347Speterstatic  long		scrn_time_stamp;
170333347Speterstatic	int		saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
171333347Speterstatic	int		run_scrn_saver = FALSE;	/* should run the saver? */
172333347Speterstatic	int		scrn_idle = FALSE;	/* about to run the saver */
173333347Speter	u_char      	scr_map[256];
174333347Speter	u_char      	scr_rmap[256];
175333347Speterstatic	int		initial_video_mode;	/* initial video mode # */
176333347Speterstatic	int		bios_video_mode;	/* video mode # set by BIOS */
177333347Speter	int     	fonts_loaded = 0
178333347Speter#ifdef STD8X16FONT
179333347Speter	| FONT_16
180333347Speter#endif
181333347Speter	;
182333347Speter
183333347Speter	u_char		font_8[256*8];
184333347Speter	u_char		font_14[256*14];
185333347Speter#ifdef STD8X16FONT
186333347Speterextern
187333347Speter#endif
188333347Speter	u_char		font_16[256*16];
189333347Speter	u_char        	palette[256*3];
190333347Speterstatic	u_char 		*cut_buffer;
191333347Speterstatic	int		cut_buffer_size;
192333347Speterstatic	int		mouse_level;		/* sysmouse protocol level */
193333347Speterstatic	mousestatus_t	mouse_status = { 0, 0, 0, 0, 0, 0 };
194333347Speterstatic  u_short 	mouse_and_mask[16] = {
195333347Speter				0xc000, 0xe000, 0xf000, 0xf800,
196333347Speter				0xfc00, 0xfe00, 0xff00, 0xff80,
197333347Speter				0xfe00, 0x1e00, 0x1f00, 0x0f00,
198333347Speter				0x0f00, 0x0000, 0x0000, 0x0000
199333347Speter			};
200333347Speterstatic  u_short 	mouse_or_mask[16] = {
201333347Speter				0x0000, 0x4000, 0x6000, 0x7000,
202333347Speter				0x7800, 0x7c00, 0x7e00, 0x6800,
203333347Speter				0x0c00, 0x0c00, 0x0600, 0x0600,
204333347Speter				0x0000, 0x0000, 0x0000, 0x0000
205333347Speter			};
206333347Speter
207333347Speter	int		sc_history_size = SC_HISTORY_SIZE;
208333347Speterstatic	int		extra_history_size =
209333347Speter			    SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
210333347Speter
211333347Speterstatic void    		none_saver(int blank) { }
212333347Speterstatic void    		(*current_saver)(int blank) = none_saver;
213333347Speterstatic void    		(*default_saver)(int blank) = none_saver;
214333347Speter       d_ioctl_t  	*sc_user_ioctl;
215333347Speter
216333347Speterstatic int		sticky_splash = FALSE;
217333347Speter
218333347Speter/* OS specific stuff */
219333347Speter#ifdef not_yet_done
220333347Speter#define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
221333347Speterstruct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
222333347Speterstruct  MOUSE_TTY 	(sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
223333347Speterstruct  tty         	*sccons[MAXCONS+2];
224333347Speter#else
225333347Speter#define VIRTUAL_TTY(x)  &sccons[x]
226333347Speter#define CONSOLE_TTY 	&sccons[MAXCONS]
227333347Speter#define MOUSE_TTY 	&sccons[MAXCONS+1]
228333347Speterstatic struct tty     	sccons[MAXCONS+2];
229333347Speter#endif
230333347Speter#define SC_MOUSE 	128
231333347Speter#define SC_CONSOLE	255
232333347Speteru_short         	*Crtat;
233333347Speterstatic const int	nsccons = MAXCONS+2;
234333347Speter
235333347Speter#define WRAPHIST(scp, pointer, offset)\
236333347Speter    ((scp)->history + ((((pointer) - (scp)->history) + (scp)->history_size \
237333347Speter    + (offset)) % (scp)->history_size))
238333347Speter#define ISSIGVALID(sig)	((sig) > 0 && (sig) < NSIG)
239333347Speter
240333347Speter/* prototypes */
241333347Speterstatic int scattach(struct isa_device *dev);
242333347Speterstatic int scparam(struct tty *tp, struct termios *t);
243333347Speterstatic int scprobe(struct isa_device *dev);
244333347Speterstatic int scvidprobe(int unit, int flags);
245333347Speterstatic int sckbdprobe(int unit, int flags);
246333347Speterstatic void scstart(struct tty *tp);
247333347Speterstatic void scmousestart(struct tty *tp);
248333347Speterstatic void scinit(void);
249333347Speterstatic void scshutdown(int howto, void *arg);
250333347Speterstatic u_int scgetc(u_int flags);
251333347Speter#define SCGETC_CN	1
252333347Speter#define SCGETC_NONBLOCK	2
253333347Speterstatic void sccnupdate(scr_stat *scp);
254333347Speterstatic scr_stat *alloc_scp(void);
255333347Speterstatic void init_scp(scr_stat *scp);
256333347Speterstatic void sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark);
257333347Speterstatic int get_scr_num(void);
258333347Speterstatic timeout_t scrn_timer;
259333347Speterstatic void scrn_update(scr_stat *scp, int show_cursor);
260333347Speterstatic void scrn_saver(void (*saver)(int), int blank);
261333347Speterstatic void stop_scrn_saver(void (*saver)(int));
262333347Speterstatic int wait_scrn_saver_stop(void);
263333347Speterstatic int switch_scr(scr_stat *scp, u_int next_scr);
264333347Speterstatic void exchange_scr(void);
265333347Speterstatic void scan_esc(scr_stat *scp, u_char c);
266333347Speterstatic void ansi_put(scr_stat *scp, u_char *buf, int len);
267333347Speterstatic void draw_cursor_image(scr_stat *scp);
268333347Speterstatic void remove_cursor_image(scr_stat *scp);
269333347Speterstatic void move_crsr(scr_stat *scp, int x, int y);
270333347Speterstatic u_char *get_fstr(u_int c, u_int *len);
271333347Speterstatic void history_to_screen(scr_stat *scp);
272333347Speterstatic int history_up_line(scr_stat *scp);
273333347Speterstatic int history_down_line(scr_stat *scp);
274333347Speterstatic int mask2attr(struct term_stat *term);
275333347Speterstatic void set_keyboard(int command, int data);
276333347Speterstatic void update_leds(int which);
277333347Speterstatic void set_mouse_pos(scr_stat *scp);
278333347Speterstatic int skip_spc_right(scr_stat *scp, u_short *p);
279333347Speterstatic int skip_spc_left(scr_stat *scp, u_short *p);
280333347Speterstatic void mouse_cut(scr_stat *scp);
281333347Speterstatic void mouse_cut_start(scr_stat *scp);
282333347Speterstatic void mouse_cut_end(scr_stat *scp);
283333347Speterstatic void mouse_cut_word(scr_stat *scp);
284333347Speterstatic void mouse_cut_line(scr_stat *scp);
285333347Speterstatic void mouse_cut_extend(scr_stat *scp);
286333347Speterstatic void mouse_paste(scr_stat *scp);
287333347Speterstatic void draw_mouse_image(scr_stat *scp);
288333347Speterstatic void remove_mouse_image(scr_stat *scp);
289333347Speterstatic void draw_cutmarking(scr_stat *scp);
290333347Speterstatic void remove_cutmarking(scr_stat *scp);
291333347Speterstatic void do_bell(scr_stat *scp, int pitch, int duration);
292333347Speterstatic timeout_t blink_screen;
293333347Speter#ifdef SC_SPLASH_SCREEN
294333347Speterstatic void scsplash_init(scr_stat *scp);
295333347Speterstatic void scsplash_term(scr_stat *scp);
296333347Speterstatic void scsplash_saver(int show);
297333347Speter#define scsplash_stick(stick)		(sticky_splash = (stick))
298333347Speter#else
299333347Speter#define scsplash_stick(stick)
300333347Speter#endif
301333347Speter
302333347Speterstruct  isa_driver scdriver = {
303333347Speter    scprobe, scattach, "sc", 1
304333347Speter};
305333347Speter
306333347Speterstatic	d_open_t	scopen;
307333347Speterstatic	d_close_t	scclose;
308333347Speterstatic	d_read_t	scread;
309333347Speterstatic	d_write_t	scwrite;
310333347Speterstatic	d_ioctl_t	scioctl;
311333347Speterstatic	d_mmap_t	scmmap;
312333347Speter
313333347Speter#define	CDEV_MAJOR	12
314333347Speterstatic	struct cdevsw	sc_cdevsw = {
315333347Speter	scopen,		scclose,	scread,		scwrite,
316333347Speter	scioctl,	nullstop,	noreset,	scdevtotty,
317333347Speter	ttpoll,		scmmap,		nostrategy,	"sc",
318333347Speter	NULL,		-1,		nodump,		nopsize,
319333347Speter	D_TTY,
320333347Speter};
321333347Speter
322333347Speterstatic void
323333347Speterdraw_cursor_image(scr_stat *scp)
324333347Speter{
325333347Speter    u_short cursor_image;
326333347Speter    u_short *ptr;
327333347Speter    u_short prev_image;
328333347Speter
329333347Speter    if (ISPIXELSC(scp)) {
330333347Speter	sc_bcopy(scp, scp->scr_buf, scp->cursor_pos - scp->scr_buf,
331333347Speter	  scp->cursor_pos - scp->scr_buf, 1);
332333347Speter	return;
333333347Speter    }
334333347Speter
335333347Speter    ptr = (u_short *)(get_adapter(scp)->va_window)
336333347Speter			 + (scp->cursor_pos - scp->scr_buf);
337333347Speter
338333347Speter    /* do we have a destructive cursor ? */
339333347Speter    if (sc_flags & CHAR_CURSOR) {
340333347Speter	prev_image = scp->cursor_saveunder;
341333347Speter	cursor_image = *ptr & 0x00ff;
342333347Speter	if (cursor_image == DEAD_CHAR)
343333347Speter	    cursor_image = prev_image & 0x00ff;
344333347Speter	cursor_image |= *(scp->cursor_pos) & 0xff00;
345333347Speter	scp->cursor_saveunder = cursor_image;
346333347Speter	/* update the cursor bitmap if the char under the cursor has changed */
347333347Speter	if (prev_image != cursor_image)
348333347Speter	    set_destructive_cursor(scp);
349333347Speter	/* modify cursor_image */
350333347Speter	if (!(sc_flags & BLINK_CURSOR)||((sc_flags & BLINK_CURSOR)&&(blinkrate & 4))){
351333347Speter	    /*
352333347Speter	     * When the mouse pointer is at the same position as the cursor,
353333347Speter	     * the cursor bitmap needs to be updated even if the char under
354333347Speter	     * the cursor hasn't changed, because the mouse pionter may
355333347Speter	     * have moved by a few dots within the cursor cel.
356333347Speter	     */
357333347Speter	    if ((prev_image == cursor_image)
358333347Speter		    && (cursor_image != *(scp->cursor_pos)))
359333347Speter	        set_destructive_cursor(scp);
360333347Speter	    cursor_image &= 0xff00;
361333347Speter	    cursor_image |= DEAD_CHAR;
362333347Speter	}
363333347Speter    } else {
364333347Speter	cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
365333347Speter	scp->cursor_saveunder = cursor_image;
366333347Speter	if (!(sc_flags & BLINK_CURSOR)||((sc_flags & BLINK_CURSOR)&&(blinkrate & 4))){
367333347Speter	    if ((cursor_image & 0x7000) == 0x7000) {
368333347Speter		cursor_image &= 0x8fff;
369333347Speter		if(!(cursor_image & 0x0700))
370333347Speter		    cursor_image |= 0x0700;
371333347Speter	    } else {
372333347Speter		cursor_image |= 0x7000;
373333347Speter		if ((cursor_image & 0x0700) == 0x0700)
374333347Speter		    cursor_image &= 0xf0ff;
375333347Speter	    }
376333347Speter	}
377333347Speter    }
378333347Speter    *ptr = cursor_image;
379333347Speter}
380333347Speter
381333347Speterstatic void
382333347Speterremove_cursor_image(scr_stat *scp)
383333347Speter{
384333347Speter    if (ISPIXELSC(scp))
385333347Speter	sc_bcopy(scp, scp->scr_buf, scp->cursor_oldpos - scp->scr_buf,
386333347Speter		 scp->cursor_oldpos - scp->scr_buf, 0);
387333347Speter    else
388333347Speter	*((u_short *)(get_adapter(scp)->va_window)
389333347Speter			 + (scp->cursor_oldpos - scp->scr_buf))
390333347Speter	    = scp->cursor_saveunder;
391333347Speter}
392333347Speter
393333347Speterstatic void
394333347Spetermove_crsr(scr_stat *scp, int x, int y)
395333347Speter{
396333347Speter    if (x < 0)
397333347Speter	x = 0;
398333347Speter    if (y < 0)
399333347Speter	y = 0;
400333347Speter    if (x >= scp->xsize)
401333347Speter	x = scp->xsize-1;
402333347Speter    if (y >= scp->ysize)
403333347Speter	y = scp->ysize-1;
404333347Speter    scp->xpos = x;
405333347Speter    scp->ypos = y;
406333347Speter    scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
407333347Speter}
408333347Speter
409333347Speterstatic int
410333347Speterscprobe(struct isa_device *dev)
411333347Speter{
412333347Speter    if (!scvidprobe(dev->id_unit, dev->id_flags)) {
413333347Speter	if (bootverbose)
414333347Speter	    printf("sc%d: no video adapter is found.\n", dev->id_unit);
415333347Speter	return (0);
416333347Speter    }
417333347Speter
418333347Speter#if defined(VESA) && defined(VM86)
419333347Speter    if (vesa_load())
420333347Speter	return FALSE;
421333347Speter#endif
422333347Speter
423333347Speter    (*biosvidsw.diag)(bootverbose);
424333347Speter
425333347Speter    sc_port = dev->id_iobase;
426333347Speter    if (sckbdprobe(dev->id_unit, dev->id_flags))
427333347Speter	return (IO_KBDSIZE);
428333347Speter    else
429333347Speter        return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
430333347Speter}
431333347Speter
432333347Speter/* probe video adapters, return TRUE if found */
433333347Speterstatic int
434333347Speterscvidprobe(int unit, int flags)
435333347Speter{
436333347Speter    video_adapter_t *adp;
437333347Speter
438333347Speter    /* do this test only once */
439333347Speter    if (init_done != COLD)
440333347Speter	return (crtc_type != -1);
441333347Speter
442333347Speter    if ((*biosvidsw.init)() <= 0)
443333347Speter	return FALSE;
444333347Speter    if ((adp = (*biosvidsw.adapter)(V_ADP_PRIMARY)) == NULL)
445333347Speter	return FALSE;
446333347Speter
447333347Speter    crtc_type = adp->va_type;
448333347Speter    crtc_vga = (crtc_type == KD_VGA);
449333347Speter    crtc_addr = adp->va_crtc_addr;
450333347Speter    Crtat = (u_short *)adp->va_window;
451333347Speter    adp_flags = adp->va_flags;
452333347Speter    initial_video_mode = adp->va_initial_mode;
453333347Speter    bios_video_mode = adp->va_initial_bios_mode;
454333347Speter
455333347Speter    return TRUE;
456333347Speter}
457333347Speter
458333347Speter/* probe the keyboard, return TRUE if found */
459333347Speterstatic int
460333347Spetersckbdprobe(int unit, int flags)
461333347Speter{
462333347Speter    int codeset;
463333347Speter    int c = -1;
464333347Speter    int m;
465333347Speter    int res, id;
466333347Speter
467333347Speter    sc_kbdc = kbdc_open(sc_port);
468333347Speter
469333347Speter    if (!kbdc_lock(sc_kbdc, TRUE)) {
470333347Speter	/* driver error? */
471333347Speter	printf("sc%d: unable to lock the controller.\n", unit);
472333347Speter        return ((flags & DETECT_KBD) ? FALSE : TRUE);
473333347Speter    }
474333347Speter
475333347Speter    /* flush any noise in the buffer */
476333347Speter    empty_both_buffers(sc_kbdc, 10);
477333347Speter
478333347Speter    /* save the current keyboard controller command byte */
479333347Speter    m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
480333347Speter    c = get_controller_command_byte(sc_kbdc);
481333347Speter    if (c == -1) {
482333347Speter	/* CONTROLLER ERROR */
483333347Speter	printf("sc%d: unable to get the current command byte value.\n", unit);
484333347Speter	goto fail;
485333347Speter    }
486333347Speter    if (bootverbose)
487333347Speter	printf("sc%d: the current keyboard controller command byte %04x\n",
488333347Speter	    unit, c);
489333347Speter#if 0
490333347Speter    /* override the keyboard lock switch */
491333347Speter    c |= KBD_OVERRIDE_KBD_LOCK;
492333347Speter#endif
493333347Speter
494333347Speter    /*
495333347Speter     * The keyboard may have been screwed up by the boot block.
496333347Speter     * We may just be able to recover from error by testing the controller
497333347Speter     * and the keyboard port. The controller command byte needs to be saved
498333347Speter     * before this recovery operation, as some controllers seem to set
499333347Speter     * the command byte to particular values.
500333347Speter     */
501333347Speter    test_controller(sc_kbdc);
502333347Speter    test_kbd_port(sc_kbdc);
503333347Speter
504333347Speter    /* enable the keyboard port, but disable the keyboard intr. */
505333347Speter    if (!set_controller_command_byte(sc_kbdc,
506333347Speter            KBD_KBD_CONTROL_BITS,
507333347Speter            KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
508333347Speter	/* CONTROLLER ERROR
509333347Speter	 * there is very little we can do...
510333347Speter	 */
511333347Speter	printf("sc%d: unable to set the command byte.\n", unit);
512333347Speter	goto fail;
513333347Speter     }
514333347Speter
515333347Speter     /*
516333347Speter      * Check if we have an XT keyboard before we attempt to reset it.
517333347Speter      * The procedure assumes that the keyboard and the controller have
518333347Speter      * been set up properly by BIOS and have not been messed up
519333347Speter      * during the boot process.
520333347Speter      */
521333347Speter     codeset = -1;
522333347Speter     if (flags & XT_KEYBD)
523333347Speter	 /* the user says there is a XT keyboard */
524333347Speter	 codeset = 1;
525333347Speter#ifdef DETECT_XT_KEYBOARD
526333347Speter     else if ((c & KBD_TRANSLATION) == 0) {
527333347Speter	 /* SET_SCANCODE_SET is not always supported; ignore error */
528333347Speter	 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
529333347Speter		 == KBD_ACK)
530333347Speter	     codeset = read_kbd_data(sc_kbdc);
531333347Speter     }
532333347Speter     if (bootverbose)
533333347Speter         printf("sc%d: keyboard scancode set %d\n", unit, codeset);
534333347Speter#endif /* DETECT_XT_KEYBOARD */
535333347Speter
536333347Speter    if (flags & KBD_NORESET) {
537333347Speter        write_kbd_command(sc_kbdc, KBDC_ECHO);
538333347Speter        if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
539333347Speter            empty_both_buffers(sc_kbdc, 10);
540333347Speter            test_controller(sc_kbdc);
541333347Speter            test_kbd_port(sc_kbdc);
542333347Speter            if (bootverbose)
543333347Speter                printf("sc%d: failed to get response from the keyboard.\n",
544333347Speter		    unit);
545333347Speter	    goto fail;
546333347Speter	}
547333347Speter    } else {
548333347Speter        /* reset keyboard hardware */
549333347Speter        if (!reset_kbd(sc_kbdc)) {
550333347Speter            /* KEYBOARD ERROR
551333347Speter             * Keyboard reset may fail either because the keyboard doen't
552333347Speter             * exist, or because the keyboard doesn't pass the self-test,
553333347Speter             * or the keyboard controller on the motherboard and the keyboard
554333347Speter             * somehow fail to shake hands. It is just possible, particularly
555333347Speter             * in the last case, that the keyoard controller may be left
556333347Speter             * in a hung state. test_controller() and test_kbd_port() appear
557333347Speter             * to bring the keyboard controller back (I don't know why and
558333347Speter             * how, though.)
559333347Speter             */
560333347Speter            empty_both_buffers(sc_kbdc, 10);
561333347Speter            test_controller(sc_kbdc);
562333347Speter            test_kbd_port(sc_kbdc);
563333347Speter            /* We could disable the keyboard port and interrupt... but,
564333347Speter             * the keyboard may still exist (see above).
565333347Speter             */
566333347Speter            if (bootverbose)
567333347Speter                printf("sc%d: failed to reset the keyboard.\n", unit);
568333347Speter            goto fail;
569333347Speter        }
570333347Speter    }
571333347Speter
572333347Speter    /*
573333347Speter     * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
574333347Speter     * such as those on the IBM ThinkPad laptop computers can be used
575333347Speter     * with the standard console driver.
576333347Speter     */
577333347Speter    if (codeset == 1) {
578333347Speter	if (send_kbd_command_and_data(
579333347Speter	        sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
580333347Speter	    /* XT kbd doesn't need scan code translation */
581333347Speter	    c &= ~KBD_TRANSLATION;
582333347Speter	} else {
583333347Speter	    /* KEYBOARD ERROR
584333347Speter	     * The XT kbd isn't usable unless the proper scan code set
585333347Speter	     * is selected.
586333347Speter	     */
587333347Speter	    printf("sc%d: unable to set the XT keyboard mode.\n", unit);
588333347Speter	    goto fail;
589333347Speter	}
590333347Speter    }
591333347Speter    /* enable the keyboard port and intr. */
592333347Speter    if (!set_controller_command_byte(sc_kbdc,
593333347Speter            KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
594333347Speter	    (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
595333347Speter	        | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
596333347Speter	/* CONTROLLER ERROR
597333347Speter	 * This is serious; we are left with the disabled keyboard intr.
598333347Speter	 */
599333347Speter	printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
600333347Speter	goto fail;
601333347Speter    }
602333347Speter
603333347Speter    /* Get the ID of the keyboard, if any */
604333347Speter    empty_kbd_buffer(sc_kbdc, 5);
605333347Speter    res = send_kbd_command(sc_kbdc, KBDC_SEND_DEV_ID);
606333347Speter    if (res == KBD_ACK) {
607333347Speter	/* 10ms delay */
608333347Speter	DELAY(10000);
609333347Speter	id = (read_kbd_data(sc_kbdc) << 8) | read_kbd_data(sc_kbdc);
610333347Speter	if (bootverbose)
611333347Speter	    printf("sc%d: keyboard device ID: %04x\n", unit, id);
612333347Speter    }
613333347Speter
614333347Speter    kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
615333347Speter    kbdc_lock(sc_kbdc, FALSE);
616333347Speter    return TRUE;
617333347Speter
618333347Speterfail:
619333347Speter    if (c != -1)
620333347Speter        /* try to restore the command byte as before, if possible */
621333347Speter        set_controller_command_byte(sc_kbdc, 0xff, c);
622333347Speter    kbdc_set_device_mask(sc_kbdc,
623333347Speter        (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
624333347Speter    kbdc_lock(sc_kbdc, FALSE);
625333347Speter    return FALSE;
626333347Speter}
627333347Speter
628333347Speter#if NAPM > 0
629333347Speterstatic int
630333347Speterscresume(void *dummy)
631333347Speter{
632333347Speter	shfts = ctls = alts = agrs = metas = accents = 0;
633333347Speter	return 0;
634333347Speter}
635333347Speter#endif
636333347Speter
637333347Speterstatic int
638333347Speterscattach(struct isa_device *dev)
639333347Speter{
640333347Speter    scr_stat *scp;
641333347Speter    video_info_t info;
642333347Speter    dev_t cdev = makedev(CDEV_MAJOR, 0);
643333347Speter#ifdef DEVFS
644333347Speter    int vc;
645333347Speter#endif
646333347Speter
647333347Speter    scinit();
648333347Speter    sc_flags = dev->id_flags;
649333347Speter    if (!ISFONTAVAIL(adp_flags))
650333347Speter	sc_flags &= ~CHAR_CURSOR;
651333347Speter
652333347Speter    scp = console[0];
653333347Speter
654333347Speter    /* copy temporary buffer to final buffer */
655333347Speter    scp->scr_buf = NULL;
656333347Speter    sc_alloc_scr_buffer(scp, FALSE, FALSE);
657333347Speter    bcopy(sc_buffer, scp->scr_buf, scp->xsize*scp->ysize*sizeof(u_short));
658333347Speter
659333347Speter    /* cut buffer is available only when the mouse pointer is used */
660333347Speter    if (ISMOUSEAVAIL(adp_flags))
661333347Speter	sc_alloc_cut_buffer(scp, FALSE);
662333347Speter
663333347Speter    /* initialize history buffer & pointers */
664333347Speter    sc_alloc_history_buffer(scp, sc_history_size, 0, FALSE);
665333347Speter
666333347Speter#if defined(VESA) && defined(VM86)
667333347Speter    if ((sc_flags & VESA800X600)
668333347Speter	&& ((*biosvidsw.get_info)(scp->adp, M_VESA_800x600, &info) == 0)) {
669333347Speter#ifdef SC_SPLASH_SCREEN
670333347Speter	scsplash_term(scp);
671333347Speter#endif
672333347Speter	sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
673333347Speter	sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
674333347Speter	initial_video_mode = M_VESA_800x600;
675333347Speter#ifdef SC_SPLASH_SCREEN
676333347Speter	scsplash_init(scp);
677333347Speter#endif
678333347Speter    }
679333347Speter#endif /* VESA && VM86 */
680333347Speter
681333347Speter    /* initialize cursor stuff */
682333347Speter    if (!ISGRAPHSC(scp))
683333347Speter    	draw_cursor_image(scp);
684333347Speter
685333347Speter    /* get screen update going */
686333347Speter    scrn_timer((void *)TRUE);
687333347Speter
688333347Speter    update_leds(scp->status);
689333347Speter
690333347Speter    printf("sc%d: ", dev->id_unit);
691333347Speter    switch(crtc_type) {
692333347Speter    case KD_VGA:
693333347Speter	printf("VGA %s", (adp_flags & V_ADP_COLOR) ? "color" : "mono");
694333347Speter	break;
695333347Speter    case KD_EGA:
696333347Speter	printf("EGA %s", (adp_flags & V_ADP_COLOR) ? "color" : "mono");
697333347Speter	break;
698333347Speter    case KD_CGA:
699333347Speter	printf("CGA");
700333347Speter	break;
701333347Speter    case KD_MONO:
702333347Speter    case KD_HERCULES:
703333347Speter    default:
704333347Speter	printf("MDA/Hercules");
705333347Speter	break;
706333347Speter    }
707333347Speter    printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, sc_flags);
708333347Speter
709333347Speter#if NAPM > 0
710333347Speter    scp->r_hook.ah_fun = scresume;
711333347Speter    scp->r_hook.ah_arg = NULL;
712333347Speter    scp->r_hook.ah_name = "system keyboard";
713333347Speter    scp->r_hook.ah_order = APM_MID_ORDER;
714333347Speter    apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
715333347Speter#endif
716333347Speter
717333347Speter    at_shutdown(scshutdown, NULL, SHUTDOWN_PRE_SYNC);
718333347Speter
719333347Speter    cdevsw_add(&cdev, &sc_cdevsw, NULL);
720333347Speter
721333347Speter#ifdef DEVFS
722333347Speter    for (vc = 0; vc < MAXCONS; vc++)
723333347Speter        sc_devfs_token[vc] = devfs_add_devswf(&sc_cdevsw, vc, DV_CHR,
724333347Speter				UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc);
725333347Speter    sc_mouse_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_MOUSE, DV_CHR,
726333347Speter				UID_ROOT, GID_WHEEL, 0600, "sysmouse");
727333347Speter    sc_console_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_CONSOLE, DV_CHR,
728333347Speter				UID_ROOT, GID_WHEEL, 0600, "consolectl");
729333347Speter#endif
730333347Speter    return 0;
731333347Speter}
732333347Speter
733333347Speterstruct tty
734333347Speter*scdevtotty(dev_t dev)
735333347Speter{
736333347Speter    int unit = minor(dev);
737333347Speter
738333347Speter    if (init_done == COLD)
739333347Speter	return(NULL);
740333347Speter    if (unit == SC_CONSOLE)
741333347Speter	return CONSOLE_TTY;
742333347Speter    if (unit == SC_MOUSE)
743333347Speter	return MOUSE_TTY;
744333347Speter    if (unit >= MAXCONS || unit < 0)
745333347Speter	return(NULL);
746333347Speter    return VIRTUAL_TTY(unit);
747333347Speter}
748333347Speter
749333347Speterint
750333347Speterscopen(dev_t dev, int flag, int mode, struct proc *p)
751333347Speter{
752333347Speter    struct tty *tp = scdevtotty(dev);
753333347Speter
754333347Speter    if (!tp)
755333347Speter	return(ENXIO);
756333347Speter
757333347Speter    tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
758333347Speter    tp->t_param = scparam;
759333347Speter    tp->t_dev = dev;
760333347Speter    if (!(tp->t_state & TS_ISOPEN)) {
761333347Speter	ttychars(tp);
762333347Speter        /* Use the current setting of the <-- key as default VERASE. */
763333347Speter        /* If the Delete key is preferable, an stty is necessary     */
764333347Speter        tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
765333347Speter	tp->t_iflag = TTYDEF_IFLAG;
766333347Speter	tp->t_oflag = TTYDEF_OFLAG;
767333347Speter	tp->t_cflag = TTYDEF_CFLAG;
768333347Speter	tp->t_lflag = TTYDEF_LFLAG;
769333347Speter	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
770333347Speter	scparam(tp, &tp->t_termios);
771333347Speter	(*linesw[tp->t_line].l_modem)(tp, 1);
772333347Speter    	if (minor(dev) == SC_MOUSE)
773333347Speter	    mouse_level = 0;		/* XXX */
774333347Speter    }
775333347Speter    else
776333347Speter	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
777333347Speter	    return(EBUSY);
778333347Speter    if (minor(dev) < MAXCONS && !console[minor(dev)]) {
779333347Speter	console[minor(dev)] = alloc_scp();
780333347Speter	if (ISGRAPHSC(console[minor(dev)]))
781333347Speter	    sc_set_pixel_mode(console[minor(dev)], NULL, COL, ROW, 16);
782333347Speter    }
783333347Speter    if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
784333347Speter	tp->t_winsize.ws_col = console[minor(dev)]->xsize;
785333347Speter	tp->t_winsize.ws_row = console[minor(dev)]->ysize;
786333347Speter    }
787333347Speter    return ((*linesw[tp->t_line].l_open)(dev, tp));
788333347Speter}
789333347Speter
790333347Speterint
791333347Speterscclose(dev_t dev, int flag, int mode, struct proc *p)
792333347Speter{
793333347Speter    struct tty *tp = scdevtotty(dev);
794333347Speter    struct scr_stat *scp;
795333347Speter
796333347Speter    if (!tp)
797333347Speter	return(ENXIO);
798333347Speter    if (minor(dev) < MAXCONS) {
799333347Speter	scp = sc_get_scr_stat(tp->t_dev);
800333347Speter	if (scp->status & SWITCH_WAIT_ACQ)
801333347Speter	    wakeup((caddr_t)&scp->smode);
802333347Speter#if not_yet_done
803333347Speter	if (scp == &main_console) {
804333347Speter	    scp->pid = 0;
805333347Speter	    scp->proc = NULL;
806333347Speter	    scp->smode.mode = VT_AUTO;
807333347Speter	}
808333347Speter	else {
809333347Speter	    free(scp->scr_buf, M_DEVBUF);
810333347Speter	    if (scp->history != NULL) {
811333347Speter		free(scp->history, M_DEVBUF);
812333347Speter		if (scp->history_size / scp->xsize
813333347Speter			> imax(sc_history_size, scp->ysize))
814333347Speter		    extra_history_size += scp->history_size / scp->xsize
815333347Speter			- imax(sc_history_size, scp->ysize);
816333347Speter	    }
817333347Speter	    free(scp, M_DEVBUF);
818333347Speter	    console[minor(dev)] = NULL;
819333347Speter	}
820333347Speter#else
821333347Speter	scp->pid = 0;
822333347Speter	scp->proc = NULL;
823333347Speter	scp->smode.mode = VT_AUTO;
824333347Speter#endif
825333347Speter    }
826333347Speter    spltty();
827333347Speter    (*linesw[tp->t_line].l_close)(tp, flag);
828333347Speter    ttyclose(tp);
829333347Speter    spl0();
830333347Speter    return(0);
831333347Speter}
832333347Speter
833333347Speterint
834333347Speterscread(dev_t dev, struct uio *uio, int flag)
835333347Speter{
836333347Speter    struct tty *tp = scdevtotty(dev);
837333347Speter
838333347Speter    if (!tp)
839333347Speter	return(ENXIO);
840333347Speter    return((*linesw[tp->t_line].l_read)(tp, uio, flag));
841333347Speter}
842333347Speter
843333347Speterint
844333347Speterscwrite(dev_t dev, struct uio *uio, int flag)
845333347Speter{
846333347Speter    struct tty *tp = scdevtotty(dev);
847333347Speter
848333347Speter    if (!tp)
849333347Speter	return(ENXIO);
850333347Speter    return((*linesw[tp->t_line].l_write)(tp, uio, flag));
851333347Speter}
852333347Speter
853333347Spetervoid
854333347Speterscintr(int unit)
855333347Speter{
856333347Speter    static struct tty *cur_tty;
857333347Speter    int c, len;
858333347Speter    u_char *cp;
859333347Speter
860333347Speter    /*
861333347Speter     * Loop while there is still input to get from the keyboard.
862333347Speter     * I don't think this is nessesary, and it doesn't fix
863333347Speter     * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
864333347Speter     */
865333347Speter    while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
866333347Speter
867333347Speter	cur_tty = VIRTUAL_TTY(get_scr_num());
868333347Speter	if (!(cur_tty->t_state & TS_ISOPEN))
869333347Speter	    if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
870333347Speter		continue;
871333347Speter
872333347Speter	switch (c & 0xff00) {
873333347Speter	case 0x0000: /* normal key */
874333347Speter	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
875333347Speter	    break;
876333347Speter	case FKEY:  /* function key, return string */
877333347Speter	    if (cp = get_fstr((u_int)c, (u_int *)&len)) {
878333347Speter	    	while (len-- >  0)
879333347Speter		    (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
880333347Speter	    }
881333347Speter	    break;
882333347Speter	case MKEY:  /* meta is active, prepend ESC */
883333347Speter	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
884333347Speter	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
885333347Speter	    break;
886333347Speter	case BKEY:  /* backtab fixed sequence (esc [ Z) */
887333347Speter	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
888333347Speter	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
889333347Speter	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
890333347Speter	    break;
891333347Speter	}
892333347Speter    }
893333347Speter
894333347Speter#if 0
895333347Speter    if (cur_console->status & MOUSE_ENABLED) {
896333347Speter	cur_console->status &= ~MOUSE_VISIBLE;
897333347Speter	remove_mouse_image(cur_console);
898333347Speter    }
899333347Speter#else
900333347Speter    if (cur_console->status & MOUSE_VISIBLE) {
901333347Speter	remove_mouse_image(cur_console);
902333347Speter	cur_console->status &= ~MOUSE_VISIBLE;
903333347Speter    }
904333347Speter#endif
905333347Speter}
906333347Speter
907333347Speterstatic int
908333347Speterscparam(struct tty *tp, struct termios *t)
909333347Speter{
910333347Speter    tp->t_ispeed = t->c_ispeed;
911333347Speter    tp->t_ospeed = t->c_ospeed;
912333347Speter    tp->t_cflag = t->c_cflag;
913333347Speter    return 0;
914333347Speter}
915333347Speter
916333347Speterint
917333347Speterscioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
918333347Speter{
919333347Speter    u_int delta_ehs;
920333347Speter    int error;
921333347Speter    int i;
922333347Speter    struct tty *tp;
923333347Speter    scr_stat *scp;
924333347Speter    video_adapter_t *adp;
925333347Speter    int s;
926333347Speter
927333347Speter    tp = scdevtotty(dev);
928333347Speter    if (!tp)
929333347Speter	return ENXIO;
930333347Speter    scp = sc_get_scr_stat(tp->t_dev);
931333347Speter
932333347Speter    /* If there is a user_ioctl function call that first */
933333347Speter    if (sc_user_ioctl) {
934333347Speter	error = (*sc_user_ioctl)(dev, cmd, data, flag, p);
935333347Speter	if (error != ENOIOCTL)
936333347Speter	    return error;
937333347Speter    }
938333347Speter
939333347Speter    error = sc_vid_ioctl(tp, cmd, data, flag, p);
940333347Speter    if (error != ENOIOCTL)
941333347Speter	return error;
942333347Speter
943333347Speter    switch (cmd) {  		/* process console hardware related ioctl's */
944333347Speter
945333347Speter    case GIO_ATTR:      	/* get current attributes */
946333347Speter	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
947333347Speter	return 0;
948333347Speter
949333347Speter    case GIO_COLOR:     	/* is this a color console ? */
950333347Speter	*(int *)data = (adp_flags & V_ADP_COLOR) ? 1 : 0;
951333347Speter	return 0;
952333347Speter
953333347Speter    case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
954333347Speter	if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
955333347Speter            return EINVAL;
956333347Speter	s = spltty();
957333347Speter	scrn_blank_time = *(int *)data;
958333347Speter	run_scrn_saver = (scrn_blank_time != 0);
959333347Speter	splx(s);
960333347Speter	return 0;
961333347Speter
962333347Speter    case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
963333347Speter	if ((*(int*)data) & 0x01)
964333347Speter	    sc_flags |= BLINK_CURSOR;
965333347Speter	else
966333347Speter	    sc_flags &= ~BLINK_CURSOR;
967333347Speter	if ((*(int*)data) & 0x02) {
968333347Speter	    if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
969333347Speter		return ENXIO;
970333347Speter	    sc_flags |= CHAR_CURSOR;
971333347Speter	} else
972333347Speter	    sc_flags &= ~CHAR_CURSOR;
973333347Speter	/*
974333347Speter	 * The cursor shape is global property; all virtual consoles
975333347Speter	 * are affected. Update the cursor in the current console...
976333347Speter	 */
977333347Speter	if (!ISGRAPHSC(cur_console)) {
978333347Speter            remove_cursor_image(cur_console);
979333347Speter	    if (sc_flags & CHAR_CURSOR)
980333347Speter	        set_destructive_cursor(cur_console);
981333347Speter	    draw_cursor_image(cur_console);
982333347Speter	}
983333347Speter	return 0;
984333347Speter
985333347Speter    case CONS_BELLTYPE: 	/* set bell type sound/visual */
986333347Speter	if ((*(int *)data) & 0x01)
987333347Speter	    sc_flags |= VISUAL_BELL;
988333347Speter	else
989333347Speter	    sc_flags &= ~VISUAL_BELL;
990333347Speter	if ((*(int *)data) & 0x02)
991333347Speter	    sc_flags |= QUIET_BELL;
992333347Speter	else
993333347Speter	    sc_flags &= ~QUIET_BELL;
994333347Speter	return 0;
995333347Speter
996333347Speter    case CONS_HISTORY:  	/* set history size */
997333347Speter	if (*(int *)data > 0) {
998333347Speter	    int lines;	/* buffer size to allocate */
999333347Speter	    int lines0;	/* current buffer size */
1000333347Speter
1001333347Speter	    lines = imax(*(int *)data, scp->ysize);
1002333347Speter	    lines0 = (scp->history != NULL) ?
1003333347Speter		      scp->history_size / scp->xsize : scp->ysize;
1004333347Speter	    if (lines0 > imax(sc_history_size, scp->ysize))
1005333347Speter		delta_ehs = lines0 - imax(sc_history_size, scp->ysize);
1006333347Speter	    else
1007333347Speter		delta_ehs = 0;
1008333347Speter	    /*
1009333347Speter	     * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
1010333347Speter	     * lines or scp->ysize lines, whichever is larger. A value
1011333347Speter	     * greater than that is allowed, subject to extra_history_size.
1012333347Speter	     */
1013333347Speter	    if (lines > imax(sc_history_size, scp->ysize))
1014333347Speter		if (lines - imax(sc_history_size, scp->ysize) >
1015333347Speter		    extra_history_size + delta_ehs)
1016333347Speter		    return EINVAL;
1017333347Speter            if (cur_console->status & BUFFER_SAVED)
1018333347Speter                return EBUSY;
1019333347Speter	    sc_alloc_history_buffer(scp, lines, delta_ehs, TRUE);
1020333347Speter	    return 0;
1021333347Speter	}
1022333347Speter	else
1023333347Speter	    return EINVAL;
1024333347Speter
1025333347Speter    case CONS_MOUSECTL:		/* control mouse arrow */
1026333347Speter    case OLD_CONS_MOUSECTL:
1027333347Speter    {
1028333347Speter	/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
1029333347Speter	static int butmap[8] = {
1030333347Speter            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1031333347Speter            MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1032333347Speter            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1033333347Speter            MOUSE_MSC_BUTTON3UP,
1034333347Speter            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1035333347Speter            MOUSE_MSC_BUTTON2UP,
1036333347Speter            MOUSE_MSC_BUTTON1UP,
1037333347Speter            0,
1038333347Speter	};
1039333347Speter	mouse_info_t *mouse = (mouse_info_t*)data;
1040333347Speter	mouse_info_t buf;
1041333347Speter
1042333347Speter	/* FIXME: */
1043333347Speter	if (!ISMOUSEAVAIL(get_adapter(scp)->va_flags))
1044333347Speter	    return ENODEV;
1045333347Speter
1046333347Speter	if (cmd == OLD_CONS_MOUSECTL) {
1047333347Speter	    static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
1048333347Speter	    old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
1049333347Speter
1050333347Speter	    mouse = &buf;
1051333347Speter	    mouse->operation = old_mouse->operation;
1052333347Speter	    switch (mouse->operation) {
1053333347Speter	    case MOUSE_MODE:
1054333347Speter		mouse->u.mode = old_mouse->u.mode;
1055333347Speter		break;
1056333347Speter	    case MOUSE_SHOW:
1057333347Speter	    case MOUSE_HIDE:
1058333347Speter		break;
1059333347Speter	    case MOUSE_MOVEABS:
1060333347Speter	    case MOUSE_MOVEREL:
1061333347Speter	    case MOUSE_ACTION:
1062333347Speter		mouse->u.data.x = old_mouse->u.data.x;
1063333347Speter		mouse->u.data.y = old_mouse->u.data.y;
1064333347Speter		mouse->u.data.z = 0;
1065333347Speter		mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
1066333347Speter		break;
1067333347Speter	    case MOUSE_GETINFO:
1068333347Speter		old_mouse->u.data.x = scp->mouse_xpos;
1069333347Speter		old_mouse->u.data.y = scp->mouse_ypos;
1070333347Speter		old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
1071333347Speter		break;
1072333347Speter	    default:
1073333347Speter		return EINVAL;
1074333347Speter	    }
1075333347Speter	}
1076333347Speter
1077333347Speter	switch (mouse->operation) {
1078333347Speter	case MOUSE_MODE:
1079333347Speter	    if (ISSIGVALID(mouse->u.mode.signal)) {
1080333347Speter		scp->mouse_signal = mouse->u.mode.signal;
1081333347Speter		scp->mouse_proc = p;
1082333347Speter		scp->mouse_pid = p->p_pid;
1083333347Speter	    }
1084333347Speter	    else {
1085333347Speter		scp->mouse_signal = 0;
1086333347Speter		scp->mouse_proc = NULL;
1087333347Speter		scp->mouse_pid = 0;
1088333347Speter	    }
1089333347Speter	    return 0;
1090333347Speter
1091333347Speter	case MOUSE_SHOW:
1092333347Speter	    if (ISTEXTSC(scp) && !(scp->status & MOUSE_ENABLED)) {
1093333347Speter		scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
1094333347Speter		scp->mouse_oldpos = scp->mouse_pos;
1095333347Speter		mark_all(scp);
1096333347Speter		return 0;
1097333347Speter	    }
1098333347Speter	    else
1099333347Speter		return EINVAL;
1100333347Speter	    break;
1101333347Speter
1102333347Speter	case MOUSE_HIDE:
1103333347Speter	    if (ISTEXTSC(scp) && (scp->status & MOUSE_ENABLED)) {
1104333347Speter		scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
1105333347Speter		mark_all(scp);
1106333347Speter		return 0;
1107333347Speter	    }
1108333347Speter	    else
1109333347Speter		return EINVAL;
1110333347Speter	    break;
1111333347Speter
1112333347Speter	case MOUSE_MOVEABS:
1113333347Speter	    scp->mouse_xpos = mouse->u.data.x;
1114333347Speter	    scp->mouse_ypos = mouse->u.data.y;
1115333347Speter	    set_mouse_pos(scp);
1116333347Speter	    break;
1117333347Speter
1118333347Speter	case MOUSE_MOVEREL:
1119333347Speter	    scp->mouse_xpos += mouse->u.data.x;
1120333347Speter	    scp->mouse_ypos += mouse->u.data.y;
1121333347Speter	    set_mouse_pos(scp);
1122333347Speter	    break;
1123333347Speter
1124333347Speter	case MOUSE_GETINFO:
1125333347Speter	    mouse->u.data.x = scp->mouse_xpos;
1126333347Speter	    mouse->u.data.y = scp->mouse_ypos;
1127333347Speter	    mouse->u.data.z = 0;
1128333347Speter	    mouse->u.data.buttons = scp->mouse_buttons;
1129333347Speter	    return 0;
1130333347Speter
1131333347Speter	case MOUSE_ACTION:
1132333347Speter	case MOUSE_MOTION_EVENT:
1133333347Speter	    /* this should maybe only be settable from /dev/consolectl SOS */
1134333347Speter	    /* send out mouse event on /dev/sysmouse */
1135333347Speter
1136333347Speter	    mouse_status.dx += mouse->u.data.x;
1137333347Speter	    mouse_status.dy += mouse->u.data.y;
1138333347Speter	    mouse_status.dz += mouse->u.data.z;
1139333347Speter	    if (mouse->operation == MOUSE_ACTION)
1140333347Speter	        mouse_status.button = mouse->u.data.buttons;
1141333347Speter	    mouse_status.flags |=
1142333347Speter		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1143333347Speter		    MOUSE_POSCHANGED : 0)
1144333347Speter		| (mouse_status.obutton ^ mouse_status.button);
1145333347Speter	    if (mouse_status.flags == 0)
1146333347Speter		return 0;
1147333347Speter
1148333347Speter	    if (ISTEXTSC(cur_console) && (cur_console->status & MOUSE_ENABLED))
1149333347Speter	    	cur_console->status |= MOUSE_VISIBLE;
1150333347Speter
1151333347Speter	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1152333347Speter		u_char buf[MOUSE_SYS_PACKETSIZE];
1153333347Speter		int j;
1154333347Speter
1155333347Speter		/* the first five bytes are compatible with MouseSystems' */
1156333347Speter		buf[0] = MOUSE_MSC_SYNC
1157333347Speter		    | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1158333347Speter		j = imax(imin(mouse->u.data.x, 255), -256);
1159333347Speter		buf[1] = j >> 1;
1160333347Speter		buf[3] = j - buf[1];
1161333347Speter		j = -imax(imin(mouse->u.data.y, 255), -256);
1162333347Speter		buf[2] = j >> 1;
1163333347Speter		buf[4] = j - buf[2];
1164333347Speter		for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
1165333347Speter	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1166333347Speter		if (mouse_level >= 1) { 	/* extended part */
1167333347Speter		    j = imax(imin(mouse->u.data.z, 127), -128);
1168333347Speter		    buf[5] = (j >> 1) & 0x7f;
1169333347Speter		    buf[6] = (j - (j >> 1)) & 0x7f;
1170333347Speter		    /* buttons 4-10 */
1171333347Speter		    buf[7] = (~mouse_status.button >> 3) & 0x7f;
1172333347Speter		    for (j = MOUSE_MSC_PACKETSIZE;
1173333347Speter			 j < MOUSE_SYS_PACKETSIZE; j++)
1174333347Speter	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1175333347Speter		}
1176333347Speter	    }
1177333347Speter
1178333347Speter	    if (cur_console->mouse_signal) {
1179333347Speter		cur_console->mouse_buttons = mouse->u.data.buttons;
1180333347Speter    		/* has controlling process died? */
1181333347Speter		if (cur_console->mouse_proc &&
1182333347Speter		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1183333347Speter		    	cur_console->mouse_signal = 0;
1184333347Speter			cur_console->mouse_proc = NULL;
1185333347Speter			cur_console->mouse_pid = 0;
1186333347Speter		}
1187333347Speter		else
1188333347Speter		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1189333347Speter	    }
1190333347Speter	    else if (mouse->operation == MOUSE_ACTION && cut_buffer != NULL) {
1191333347Speter		/* process button presses */
1192333347Speter		if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
1193333347Speter		    ISTEXTSC(cur_console)) {
1194333347Speter		    cur_console->mouse_buttons = mouse->u.data.buttons;
1195333347Speter		    if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
1196333347Speter			mouse_cut_start(cur_console);
1197333347Speter		    else
1198333347Speter			mouse_cut_end(cur_console);
1199333347Speter		    if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
1200333347Speter			cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
1201333347Speter			mouse_paste(cur_console);
1202333347Speter		}
1203333347Speter	    }
1204333347Speter
1205333347Speter	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
1206333347Speter		cur_console->mouse_xpos += mouse->u.data.x;
1207333347Speter		cur_console->mouse_ypos += mouse->u.data.y;
1208333347Speter		set_mouse_pos(cur_console);
1209333347Speter	    }
1210333347Speter
1211333347Speter	    break;
1212333347Speter
1213333347Speter	case MOUSE_BUTTON_EVENT:
1214333347Speter	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
1215333347Speter		return EINVAL;
1216333347Speter	    if (mouse->u.event.value < 0)
1217333347Speter		return EINVAL;
1218333347Speter
1219333347Speter	    if (mouse->u.event.value > 0) {
1220333347Speter	        cur_console->mouse_buttons |= mouse->u.event.id;
1221333347Speter	        mouse_status.button |= mouse->u.event.id;
1222333347Speter	    } else {
1223333347Speter	        cur_console->mouse_buttons &= ~mouse->u.event.id;
1224333347Speter	        mouse_status.button &= ~mouse->u.event.id;
1225333347Speter	    }
1226333347Speter	    mouse_status.flags |= mouse_status.obutton ^ mouse_status.button;
1227333347Speter	    if (mouse_status.flags == 0)
1228333347Speter		return 0;
1229333347Speter
1230333347Speter	    if (ISTEXTSC(cur_console) && (cur_console->status & MOUSE_ENABLED))
1231333347Speter	    	cur_console->status |= MOUSE_VISIBLE;
1232333347Speter
1233333347Speter	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1234333347Speter		u_char buf[8];
1235333347Speter		int i;
1236333347Speter
1237333347Speter		buf[0] = MOUSE_MSC_SYNC
1238333347Speter			 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1239333347Speter		buf[7] = (~mouse_status.button >> 3) & 0x7f;
1240333347Speter		buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
1241333347Speter		for (i = 0;
1242333347Speter		     i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
1243333347Speter					     : MOUSE_MSC_PACKETSIZE); i++)
1244333347Speter	    	    (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
1245333347Speter	    }
1246333347Speter
1247333347Speter	    if (cur_console->mouse_signal) {
1248333347Speter		if (cur_console->mouse_proc &&
1249333347Speter		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1250333347Speter		    	cur_console->mouse_signal = 0;
1251333347Speter			cur_console->mouse_proc = NULL;
1252333347Speter			cur_console->mouse_pid = 0;
1253333347Speter		}
1254333347Speter		else
1255333347Speter		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1256333347Speter		break;
1257333347Speter	    }
1258333347Speter
1259333347Speter	    if (!ISTEXTSC(cur_console) || (cut_buffer == NULL))
1260333347Speter		break;
1261333347Speter
1262333347Speter	    switch (mouse->u.event.id) {
1263333347Speter	    case MOUSE_BUTTON1DOWN:
1264333347Speter	        switch (mouse->u.event.value % 4) {
1265333347Speter		case 0:	/* up */
1266333347Speter		    mouse_cut_end(cur_console);
1267333347Speter		    break;
1268333347Speter		case 1:
1269333347Speter		    mouse_cut_start(cur_console);
1270333347Speter		    break;
1271333347Speter		case 2:
1272333347Speter		    mouse_cut_word(cur_console);
1273333347Speter		    break;
1274333347Speter		case 3:
1275333347Speter		    mouse_cut_line(cur_console);
1276333347Speter		    break;
1277333347Speter		}
1278333347Speter		break;
1279333347Speter	    case MOUSE_BUTTON2DOWN:
1280333347Speter	        switch (mouse->u.event.value) {
1281333347Speter		case 0:	/* up */
1282333347Speter		    break;
1283333347Speter		default:
1284333347Speter		    mouse_paste(cur_console);
1285333347Speter		    break;
1286333347Speter		}
1287333347Speter		break;
1288333347Speter	    case MOUSE_BUTTON3DOWN:
1289333347Speter	        switch (mouse->u.event.value) {
1290333347Speter		case 0:	/* up */
1291333347Speter		    if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
1292333347Speter		        mouse_cut_end(cur_console);
1293333347Speter		    break;
1294333347Speter		default:
1295333347Speter		    mouse_cut_extend(cur_console);
1296333347Speter		    break;
1297333347Speter		}
1298333347Speter		break;
1299333347Speter	    }
1300333347Speter	    break;
1301333347Speter
1302333347Speter	default:
1303333347Speter	    return EINVAL;
1304333347Speter	}
1305333347Speter	/* make screensaver happy */
1306333347Speter	scsplash_stick(FALSE);
1307333347Speter	run_scrn_saver = FALSE;
1308333347Speter	return 0;
1309333347Speter    }
1310333347Speter
1311333347Speter    /* MOUSE_XXX: /dev/sysmouse ioctls */
1312333347Speter    case MOUSE_GETHWINFO:	/* get device information */
1313333347Speter    {
1314333347Speter	mousehw_t *hw = (mousehw_t *)data;
1315333347Speter
1316333347Speter	if (tp != MOUSE_TTY)
1317333347Speter	    return ENOTTY;
1318333347Speter	hw->buttons = 10;		/* XXX unknown */
1319333347Speter	hw->iftype = MOUSE_IF_SYSMOUSE;
1320333347Speter	hw->type = MOUSE_MOUSE;
1321333347Speter	hw->model = MOUSE_MODEL_GENERIC;
1322333347Speter	hw->hwid = 0;
1323333347Speter	return 0;
1324333347Speter    }
1325333347Speter
1326333347Speter    case MOUSE_GETMODE:		/* get protocol/mode */
1327333347Speter    {
1328333347Speter	mousemode_t *mode = (mousemode_t *)data;
1329333347Speter
1330333347Speter	if (tp != MOUSE_TTY)
1331333347Speter	    return ENOTTY;
1332333347Speter	mode->level = mouse_level;
1333333347Speter	switch (mode->level) {
1334333347Speter	case 0:
1335333347Speter	    /* at this level, sysmouse emulates MouseSystems protocol */
1336333347Speter	    mode->protocol = MOUSE_PROTO_MSC;
1337333347Speter	    mode->rate = -1;		/* unknown */
1338333347Speter	    mode->resolution = -1;	/* unknown */
1339333347Speter	    mode->accelfactor = 0;	/* disabled */
1340333347Speter	    mode->packetsize = MOUSE_MSC_PACKETSIZE;
1341333347Speter	    mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
1342333347Speter	    mode->syncmask[1] = MOUSE_MSC_SYNC;
1343333347Speter	    break;
1344333347Speter
1345333347Speter	case 1:
1346333347Speter	    /* at this level, sysmouse uses its own protocol */
1347333347Speter	    mode->protocol = MOUSE_PROTO_SYSMOUSE;
1348333347Speter	    mode->rate = -1;
1349333347Speter	    mode->resolution = -1;
1350333347Speter	    mode->accelfactor = 0;
1351333347Speter	    mode->packetsize = MOUSE_SYS_PACKETSIZE;
1352333347Speter	    mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
1353333347Speter	    mode->syncmask[1] = MOUSE_SYS_SYNC;
1354333347Speter	    break;
1355333347Speter	}
1356333347Speter	return 0;
1357333347Speter    }
1358333347Speter
1359333347Speter    case MOUSE_SETMODE:		/* set protocol/mode */
1360333347Speter    {
1361333347Speter	mousemode_t *mode = (mousemode_t *)data;
1362333347Speter
1363333347Speter	if (tp != MOUSE_TTY)
1364333347Speter	    return ENOTTY;
1365333347Speter	if ((mode->level < 0) || (mode->level > 1))
1366333347Speter	    return EINVAL;
1367333347Speter	mouse_level = mode->level;
1368333347Speter	return 0;
1369333347Speter    }
1370333347Speter
1371333347Speter    case MOUSE_GETLEVEL:	/* get operation level */
1372333347Speter	if (tp != MOUSE_TTY)
1373333347Speter	    return ENOTTY;
1374333347Speter	*(int *)data = mouse_level;
1375333347Speter	return 0;
1376333347Speter
1377333347Speter    case MOUSE_SETLEVEL:	/* set operation level */
1378333347Speter	if (tp != MOUSE_TTY)
1379333347Speter	    return ENOTTY;
1380333347Speter	if ((*(int *)data  < 0) || (*(int *)data > 1))
1381333347Speter	    return EINVAL;
1382333347Speter	mouse_level = *(int *)data;
1383333347Speter	return 0;
1384333347Speter
1385333347Speter    case MOUSE_GETSTATUS:	/* get accumulated mouse events */
1386333347Speter	if (tp != MOUSE_TTY)
1387333347Speter	    return ENOTTY;
1388333347Speter	s = spltty();
1389333347Speter	*(mousestatus_t *)data = mouse_status;
1390333347Speter	mouse_status.flags = 0;
1391333347Speter	mouse_status.obutton = mouse_status.button;
1392333347Speter	mouse_status.dx = 0;
1393333347Speter	mouse_status.dy = 0;
1394333347Speter	mouse_status.dz = 0;
1395333347Speter	splx(s);
1396333347Speter	return 0;
1397333347Speter
1398333347Speter#if notyet
1399333347Speter    case MOUSE_GETVARS:		/* get internal mouse variables */
1400333347Speter    case MOUSE_SETVARS:		/* set internal mouse variables */
1401333347Speter	if (tp != MOUSE_TTY)
1402333347Speter	    return ENOTTY;
1403333347Speter	return ENODEV;
1404333347Speter#endif
1405333347Speter
1406333347Speter    case MOUSE_READSTATE:	/* read status from the device */
1407333347Speter    case MOUSE_READDATA:	/* read data from the device */
1408333347Speter	if (tp != MOUSE_TTY)
1409333347Speter	    return ENOTTY;
1410333347Speter	return ENODEV;
1411333347Speter
1412333347Speter    case CONS_GETINFO:  	/* get current (virtual) console info */
1413333347Speter    {
1414333347Speter	vid_info_t *ptr = (vid_info_t*)data;
1415333347Speter	if (ptr->size == sizeof(struct vid_info)) {
1416333347Speter	    ptr->m_num = get_scr_num();
1417333347Speter	    ptr->mv_col = scp->xpos;
1418333347Speter	    ptr->mv_row = scp->ypos;
1419333347Speter	    ptr->mv_csz = scp->xsize;
1420333347Speter	    ptr->mv_rsz = scp->ysize;
1421333347Speter	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
1422333347Speter	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
1423333347Speter	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
1424333347Speter	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
1425333347Speter	    ptr->mv_grfc.fore = 0;      /* not supported */
1426333347Speter	    ptr->mv_grfc.back = 0;      /* not supported */
1427333347Speter	    ptr->mv_ovscan = scp->border;
1428333347Speter	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
1429333347Speter	    return 0;
1430333347Speter	}
1431333347Speter	return EINVAL;
1432333347Speter    }
1433333347Speter
1434333347Speter    case CONS_GETVERS:  	/* get version number */
1435333347Speter	*(int*)data = 0x200;    /* version 2.0 */
1436333347Speter	return 0;
1437333347Speter
1438333347Speter    case CONS_IDLE:		/* see if the screen has been idle */
1439333347Speter	/*
1440333347Speter	 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
1441333347Speter	 * the user process may have been writing something on the
1442333347Speter	 * screen and syscons is not aware of it. Declare the screen
1443333347Speter	 * is NOT idle if it is in one of these modes. But there is
1444333347Speter	 * an exception to it; if a screen saver is running in the
1445333347Speter	 * graphics mode in the current screen, we should say that the
1446333347Speter	 * screen has been idle.
1447333347Speter	 */
1448333347Speter	*(int *)data = scrn_idle
1449333347Speter		       && (!ISGRAPHSC(cur_console)
1450333347Speter			   || (cur_console->status & SAVER_RUNNING));
1451333347Speter	return 0;
1452333347Speter
1453333347Speter    case CONS_SAVERMODE:	/* set saver mode */
1454333347Speter	switch(*(int *)data) {
1455333347Speter	case CONS_USR_SAVER:
1456333347Speter	    /* if a LKM screen saver is running, stop it first. */
1457333347Speter	    scsplash_stick(FALSE);
1458333347Speter	    saver_mode = *(int *)data;
1459333347Speter	    s = spltty();
1460333347Speter	    if ((error = wait_scrn_saver_stop())) {
1461333347Speter		splx(s);
1462333347Speter		return error;
1463333347Speter	    }
1464333347Speter	    scp->status |= SAVER_RUNNING;
1465333347Speter	    scsplash_stick(TRUE);
1466333347Speter	    splx(s);
1467333347Speter	    break;
1468333347Speter	case CONS_LKM_SAVER:
1469333347Speter	    s = spltty();
1470333347Speter	    if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
1471333347Speter		scp->status &= ~SAVER_RUNNING;
1472333347Speter	    saver_mode = *(int *)data;
1473333347Speter	    splx(s);
1474333347Speter	    break;
1475333347Speter	default:
1476333347Speter	    return EINVAL;
1477333347Speter	}
1478333347Speter	return 0;
1479333347Speter
1480333347Speter    case CONS_SAVERSTART:	/* immediately start/stop the screen saver */
1481333347Speter	/*
1482	 * Note that this ioctl does not guarantee the screen saver
1483	 * actually starts or stops. It merely attempts to do so...
1484	 */
1485	s = spltty();
1486	run_scrn_saver = (*(int *)data != 0);
1487	if (run_scrn_saver)
1488	    scrn_time_stamp -= scrn_blank_time;
1489	splx(s);
1490	return 0;
1491
1492    case VT_SETMODE:    	/* set screen switcher mode */
1493    {
1494	struct vt_mode *mode;
1495
1496	mode = (struct vt_mode *)data;
1497	if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
1498	    ISSIGVALID(mode->frsig)) {
1499	    bcopy(data, &scp->smode, sizeof(struct vt_mode));
1500	    if (scp->smode.mode == VT_PROCESS) {
1501		scp->proc = p;
1502		scp->pid = scp->proc->p_pid;
1503	    }
1504	    return 0;
1505	} else
1506	    return EINVAL;
1507    }
1508
1509    case VT_GETMODE:    	/* get screen switcher mode */
1510	bcopy(&scp->smode, data, sizeof(struct vt_mode));
1511	return 0;
1512
1513    case VT_RELDISP:    	/* screen switcher ioctl */
1514	switch(*(int *)data) {
1515	case VT_FALSE:  	/* user refuses to release screen, abort */
1516	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1517		old_scp->status &= ~SWITCH_WAIT_REL;
1518		switch_in_progress = FALSE;
1519		return 0;
1520	    }
1521	    return EINVAL;
1522
1523	case VT_TRUE:   	/* user has released screen, go on */
1524	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1525		scp->status &= ~SWITCH_WAIT_REL;
1526		exchange_scr();
1527		if (new_scp->smode.mode == VT_PROCESS) {
1528		    new_scp->status |= SWITCH_WAIT_ACQ;
1529		    psignal(new_scp->proc, new_scp->smode.acqsig);
1530		}
1531		else
1532		    switch_in_progress = FALSE;
1533		return 0;
1534	    }
1535	    return EINVAL;
1536
1537	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
1538	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1539		scp->status &= ~SWITCH_WAIT_ACQ;
1540		switch_in_progress = FALSE;
1541		return 0;
1542	    }
1543	    return EINVAL;
1544
1545	default:
1546	    return EINVAL;
1547	}
1548	/* NOT REACHED */
1549
1550    case VT_OPENQRY:    	/* return free virtual console */
1551	for (i = 0; i < MAXCONS; i++) {
1552	    tp = VIRTUAL_TTY(i);
1553	    if (!(tp->t_state & TS_ISOPEN)) {
1554		*(int *)data = i + 1;
1555		return 0;
1556	    }
1557	}
1558	return EINVAL;
1559
1560    case VT_ACTIVATE:   	/* switch to screen *data */
1561	return switch_scr(scp, *(int *)data - 1);
1562
1563    case VT_WAITACTIVE: 	/* wait for switch to occur */
1564	if (*(int *)data > MAXCONS || *(int *)data < 0)
1565	    return EINVAL;
1566	if (minor(dev) == *(int *)data - 1)
1567	    return 0;
1568	if (*(int *)data == 0) {
1569	    if (scp == cur_console)
1570		return 0;
1571	}
1572	else
1573	    scp = console[*(int *)data - 1];
1574	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1575			     "waitvt", 0)) == ERESTART) ;
1576	return error;
1577
1578    case VT_GETACTIVE:
1579	*(int *)data = get_scr_num()+1;
1580	return 0;
1581
1582    case KDENABIO:      	/* allow io operations */
1583	error = suser(p->p_ucred, &p->p_acflag);
1584	if (error != 0)
1585	    return error;
1586	if (securelevel > 0)
1587	    return EPERM;
1588	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1589	return 0;
1590
1591    case KDDISABIO:     	/* disallow io operations (default) */
1592	p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1593	return 0;
1594
1595    case KDSKBSTATE:    	/* set keyboard state (locks) */
1596	if (*(int *)data & ~LOCK_KEY_MASK)
1597	    return EINVAL;
1598	scp->status &= ~LOCK_KEY_MASK;
1599	scp->status |= *(int *)data;
1600	if (scp == cur_console)
1601	    update_leds(scp->status);
1602	return 0;
1603
1604    case KDGKBSTATE:    	/* get keyboard state (locks) */
1605	*(int *)data = scp->status & LOCK_KEY_MASK;
1606	return 0;
1607
1608    case KDSETRAD:      	/* set keyboard repeat & delay rates */
1609	if (*(int *)data & ~0x7f)
1610	    return EINVAL;
1611	if (sc_kbdc != NULL)
1612	    set_keyboard(KBDC_SET_TYPEMATIC, *(int *)data);
1613	return 0;
1614
1615    case KDSKBMODE:     	/* set keyboard mode */
1616	switch (*(int *)data) {
1617	case K_RAW: 		/* switch to RAW scancode mode */
1618	    scp->status &= ~KBD_CODE_MODE;
1619	    scp->status |= KBD_RAW_MODE;
1620	    return 0;
1621
1622	case K_CODE: 		/* switch to CODE mode */
1623	    scp->status &= ~KBD_RAW_MODE;
1624	    scp->status |= KBD_CODE_MODE;
1625	    return 0;
1626
1627	case K_XLATE:   	/* switch to XLT ascii mode */
1628	    if (scp == cur_console && scp->status & KBD_RAW_MODE)
1629		shfts = ctls = alts = agrs = metas = accents = 0;
1630	    scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
1631	    return 0;
1632	default:
1633	    return EINVAL;
1634	}
1635	/* NOT REACHED */
1636
1637    case KDGKBMODE:     	/* get keyboard mode */
1638	*(int *)data = (scp->status & KBD_RAW_MODE) ? K_RAW :
1639		((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
1640	return 0;
1641
1642    case KDMKTONE:      	/* sound the bell */
1643	if (*(int*)data)
1644	    do_bell(scp, (*(int*)data)&0xffff,
1645		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1646	else
1647	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1648	return 0;
1649
1650    case KIOCSOUND:     	/* make tone (*data) hz */
1651	if (scp == cur_console) {
1652	    if (*(int*)data) {
1653		int pitch = timer_freq / *(int*)data;
1654
1655		/* set command for counter 2, 2 byte write */
1656		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1657		    return EBUSY;
1658
1659		/* set pitch */
1660		outb(TIMER_CNTR2, pitch);
1661		outb(TIMER_CNTR2, (pitch>>8));
1662
1663		/* enable counter 2 output to speaker */
1664		outb(IO_PPI, inb(IO_PPI) | 3);
1665	    }
1666	    else {
1667		/* disable counter 2 output to speaker */
1668		outb(IO_PPI, inb(IO_PPI) & 0xFC);
1669		release_timer2();
1670	    }
1671	}
1672	return 0;
1673
1674    case KDGKBTYPE:     	/* get keyboard type */
1675	*(int *)data = 0;  	/* type not known (yet) */
1676	return 0;
1677
1678    case KDSETLED:      	/* set keyboard LED status */
1679	if (*(int *)data & ~LED_MASK)
1680	    return EINVAL;
1681	scp->status &= ~LED_MASK;
1682	scp->status |= *(int *)data;
1683	if (scp == cur_console)
1684	    update_leds(scp->status);
1685	return 0;
1686
1687    case KDGETLED:      	/* get keyboard LED status */
1688	*(int *)data = scp->status & LED_MASK;
1689	return 0;
1690
1691    case GETFKEY:       	/* get functionkey string */
1692	if (*(u_short*)data < n_fkey_tab) {
1693	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1694	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1695		  fkey_tab[ptr->keynum].len);
1696	    ptr->flen = fkey_tab[ptr->keynum].len;
1697	    return 0;
1698	}
1699	else
1700	    return EINVAL;
1701
1702    case SETFKEY:       	/* set functionkey string */
1703	if (*(u_short*)data < n_fkey_tab) {
1704	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1705	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1706		  min(ptr->flen, MAXFK));
1707	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1708	    return 0;
1709	}
1710	else
1711	    return EINVAL;
1712
1713    case GIO_SCRNMAP:   	/* get output translation table */
1714	bcopy(&scr_map, data, sizeof(scr_map));
1715	return 0;
1716
1717    case PIO_SCRNMAP:   	/* set output translation table */
1718	bcopy(data, &scr_map, sizeof(scr_map));
1719	for (i=0; i<sizeof(scr_map); i++)
1720	    scr_rmap[scr_map[i]] = i;
1721	return 0;
1722
1723    case GIO_KEYMAP:    	/* get keyboard translation table */
1724	bcopy(&key_map, data, sizeof(key_map));
1725	return 0;
1726
1727    case PIO_KEYMAP:    	/* set keyboard translation table */
1728	accents = 0;
1729	bzero(&accent_map, sizeof(accent_map));
1730	bcopy(data, &key_map, sizeof(key_map));
1731	return 0;
1732
1733    case GIO_DEADKEYMAP:    	/* get accent key translation table */
1734	bcopy(&accent_map, data, sizeof(accent_map));
1735	return 0;
1736
1737    case PIO_DEADKEYMAP:    	/* set accent key translation table */
1738	accents = 0;
1739	bcopy(data, &accent_map, sizeof(accent_map));
1740	return 0;
1741
1742    case PIO_FONT8x8:   	/* set 8x8 dot font */
1743	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1744	    return ENXIO;
1745	bcopy(data, font_8, 8*256);
1746	fonts_loaded |= FONT_8;
1747	/*
1748	 * FONT KLUDGE
1749	 * Always use the font page #0. XXX
1750	 * Don't load if the current font size is not 8x8.
1751	 */
1752	if (ISTEXTSC(cur_console) && (cur_console->font_size < 14))
1753	    copy_font(cur_console, LOAD, 8, font_8);
1754	return 0;
1755
1756    case GIO_FONT8x8:   	/* get 8x8 dot font */
1757	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1758	    return ENXIO;
1759	if (fonts_loaded & FONT_8) {
1760	    bcopy(font_8, data, 8*256);
1761	    return 0;
1762	}
1763	else
1764	    return ENXIO;
1765
1766    case PIO_FONT8x14:  	/* set 8x14 dot font */
1767	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1768	    return ENXIO;
1769	bcopy(data, font_14, 14*256);
1770	fonts_loaded |= FONT_14;
1771	/*
1772	 * FONT KLUDGE
1773	 * Always use the font page #0. XXX
1774	 * Don't load if the current font size is not 8x14.
1775	 */
1776	if (ISTEXTSC(cur_console)
1777	    && (cur_console->font_size >= 14) && (cur_console->font_size < 16))
1778	    copy_font(cur_console, LOAD, 14, font_14);
1779	return 0;
1780
1781    case GIO_FONT8x14:  	/* get 8x14 dot font */
1782	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1783	    return ENXIO;
1784	if (fonts_loaded & FONT_14) {
1785	    bcopy(font_14, data, 14*256);
1786	    return 0;
1787	}
1788	else
1789	    return ENXIO;
1790
1791    case PIO_FONT8x16:  	/* set 8x16 dot font */
1792	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1793	    return ENXIO;
1794	bcopy(data, font_16, 16*256);
1795	fonts_loaded |= FONT_16;
1796	/*
1797	 * FONT KLUDGE
1798	 * Always use the font page #0. XXX
1799	 * Don't load if the current font size is not 8x16.
1800	 */
1801	if (ISTEXTSC(cur_console) && (cur_console->font_size >= 16))
1802	    copy_font(cur_console, LOAD, 16, font_16);
1803	return 0;
1804
1805    case GIO_FONT8x16:  	/* get 8x16 dot font */
1806	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1807	    return ENXIO;
1808	if (fonts_loaded & FONT_16) {
1809	    bcopy(font_16, data, 16*256);
1810	    return 0;
1811	}
1812	else
1813	    return ENXIO;
1814    default:
1815	break;
1816    }
1817
1818    error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1819    if (error != ENOIOCTL)
1820	return(error);
1821    error = ttioctl(tp, cmd, data, flag);
1822    if (error != ENOIOCTL)
1823	return(error);
1824    return(ENOTTY);
1825}
1826
1827static void
1828scstart(struct tty *tp)
1829{
1830    struct clist *rbp;
1831    int s, len;
1832    u_char buf[PCBURST];
1833    scr_stat *scp = sc_get_scr_stat(tp->t_dev);
1834
1835    if (scp->status & SLKED || blink_in_progress)
1836	return; /* XXX who repeats the call when the above flags are cleared? */
1837    s = spltty();
1838    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1839	tp->t_state |= TS_BUSY;
1840	rbp = &tp->t_outq;
1841	while (rbp->c_cc) {
1842	    len = q_to_b(rbp, buf, PCBURST);
1843	    splx(s);
1844	    ansi_put(scp, buf, len);
1845	    s = spltty();
1846	}
1847	tp->t_state &= ~TS_BUSY;
1848	ttwwakeup(tp);
1849    }
1850    splx(s);
1851}
1852
1853static void
1854scmousestart(struct tty *tp)
1855{
1856    struct clist *rbp;
1857    int s;
1858    u_char buf[PCBURST];
1859
1860    s = spltty();
1861    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1862	tp->t_state |= TS_BUSY;
1863	rbp = &tp->t_outq;
1864	while (rbp->c_cc) {
1865	    q_to_b(rbp, buf, PCBURST);
1866	}
1867	tp->t_state &= ~TS_BUSY;
1868	ttwwakeup(tp);
1869    }
1870    splx(s);
1871}
1872
1873void
1874sccnprobe(struct consdev *cp)
1875{
1876    struct isa_device *dvp;
1877
1878    /*
1879     * Take control if we are the highest priority enabled display device.
1880     */
1881    dvp = find_display();
1882    if (dvp == NULL || dvp->id_driver != &scdriver) {
1883	cp->cn_pri = CN_DEAD;
1884	return;
1885    }
1886
1887    if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
1888	cp->cn_pri = CN_DEAD;
1889	return;
1890    }
1891
1892    /* initialize required fields */
1893    cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
1894    cp->cn_pri = CN_INTERNAL;
1895
1896    sc_kbdc = kbdc_open(sc_port);
1897}
1898
1899void
1900sccninit(struct consdev *cp)
1901{
1902    scinit();
1903}
1904
1905void
1906sccnputc(dev_t dev, int c)
1907{
1908    u_char buf[1];
1909    int s;
1910    scr_stat *scp = console[0];
1911    term_stat save = scp->term;
1912
1913    scp->term = kernel_console;
1914    current_default = &kernel_default;
1915    if (scp == cur_console && !ISGRAPHSC(scp))
1916	remove_cursor_image(scp);
1917    buf[0] = c;
1918    ansi_put(scp, buf, 1);
1919    kernel_console = scp->term;
1920    current_default = &user_default;
1921    scp->term = save;
1922
1923    s = spltty();	/* block scintr and scrn_timer */
1924    sccnupdate(scp);
1925    splx(s);
1926}
1927
1928int
1929sccngetc(dev_t dev)
1930{
1931    int s = spltty();	/* block scintr and scrn_timer while we poll */
1932    int c;
1933
1934    /*
1935     * Stop the screen saver and update the screen if necessary.
1936     * What if we have been running in the screen saver code... XXX
1937     */
1938    scsplash_stick(FALSE);
1939    run_scrn_saver = FALSE;
1940    sccnupdate(cur_console);
1941
1942    c = scgetc(SCGETC_CN);
1943    splx(s);
1944    return(c);
1945}
1946
1947int
1948sccncheckc(dev_t dev)
1949{
1950    int s = spltty();	/* block scintr and scrn_timer while we poll */
1951    int c;
1952
1953    scsplash_stick(FALSE);
1954    run_scrn_saver = FALSE;
1955    sccnupdate(cur_console);
1956
1957    c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
1958    splx(s);
1959    return(c == NOKEY ? -1 : c);	/* c == -1 can't happen */
1960}
1961
1962static void
1963sccnupdate(scr_stat *scp)
1964{
1965    /* this is a cut-down version of scrn_timer()... */
1966
1967    if (font_loading_in_progress)
1968	return;
1969
1970    if (panicstr || shutdown_in_progress) {
1971	scsplash_stick(FALSE);
1972	run_scrn_saver = FALSE;
1973    } else if (scp != cur_console) {
1974	return;
1975    }
1976
1977    if (!run_scrn_saver)
1978	scrn_idle = FALSE;
1979    if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
1980	if (scp->status & SAVER_RUNNING)
1981            stop_scrn_saver(current_saver);
1982
1983    if (scp != cur_console || blink_in_progress || switch_in_progress)
1984	return;
1985
1986    if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1987	scrn_update(scp, TRUE);
1988}
1989
1990scr_stat
1991*sc_get_scr_stat(dev_t dev)
1992{
1993    int unit = minor(dev);
1994
1995    if (unit == SC_CONSOLE)
1996	return console[0];
1997    if (unit >= MAXCONS || unit < 0)
1998	return(NULL);
1999    return console[unit];
2000}
2001
2002static int
2003get_scr_num()
2004{
2005    int i = 0;
2006
2007    while ((i < MAXCONS) && (cur_console != console[i]))
2008	i++;
2009    return i < MAXCONS ? i : 0;
2010}
2011
2012static void
2013scrn_timer(void *arg)
2014{
2015    struct timeval tv;
2016    scr_stat *scp;
2017    int s;
2018
2019    /* don't do anything when we are touching font */
2020    if (font_loading_in_progress) {
2021	if (arg)
2022	    timeout(scrn_timer, (void *)TRUE, hz / 10);
2023	return;
2024    }
2025    s = spltty();
2026
2027    /*
2028     * With release 2.1 of the Xaccel server, the keyboard is left
2029     * hanging pretty often. Apparently an interrupt from the
2030     * keyboard is lost, and I don't know why (yet).
2031     * This ugly hack calls scintr if input is ready for the keyboard
2032     * and conveniently hides the problem.			XXX
2033     */
2034    /* Try removing anything stuck in the keyboard controller; whether
2035     * it's a keyboard scan code or mouse data. `scintr()' doesn't
2036     * read the mouse data directly, but `kbdio' routines will, as a
2037     * side effect.
2038     */
2039    if (kbdc_lock(sc_kbdc, TRUE)) {
2040	/*
2041	 * We have seen the lock flag is not set. Let's reset the flag early;
2042	 * otherwise `update_led()' failes which may want the lock
2043	 * during `scintr()'.
2044	 */
2045	kbdc_lock(sc_kbdc, FALSE);
2046	if (kbdc_data_ready(sc_kbdc))
2047	    scintr(0);
2048    }
2049
2050    scp = cur_console;
2051
2052    /* should we stop the screen saver? */
2053    getmicrouptime(&tv);
2054    if (panicstr || shutdown_in_progress) {
2055	scsplash_stick(FALSE);
2056	run_scrn_saver = FALSE;
2057    }
2058    if (run_scrn_saver) {
2059	scrn_idle = (tv.tv_sec > scrn_time_stamp + scrn_blank_time);
2060    } else {
2061	scrn_time_stamp = tv.tv_sec;
2062	scrn_idle = FALSE;
2063	if (scrn_blank_time > 0)
2064	    run_scrn_saver = TRUE;
2065    }
2066    if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2067	if (scp->status & SAVER_RUNNING)
2068            stop_scrn_saver(current_saver);
2069
2070    /* should we just return ? */
2071    if (blink_in_progress || switch_in_progress) {
2072	if (arg)
2073	    timeout(scrn_timer, (void *)TRUE, hz / 10);
2074	splx(s);
2075	return;
2076    }
2077
2078    /* Update the screen */
2079    if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
2080	scrn_update(scp, TRUE);
2081
2082    /* should we activate the screen saver? */
2083    if ((saver_mode == CONS_LKM_SAVER) && scrn_idle)
2084	if (!ISGRAPHSC(scp) || (scp->status & SAVER_RUNNING))
2085	    scrn_saver(current_saver, TRUE);
2086
2087    if (arg)
2088	timeout(scrn_timer, (void *)TRUE, hz / 25);
2089    splx(s);
2090}
2091
2092static void
2093scrn_update(scr_stat *scp, int show_cursor)
2094{
2095    /* update screen image */
2096    if (scp->start <= scp->end)
2097        sc_bcopy(scp, scp->scr_buf, scp->start, scp->end, 0);
2098
2099    /* we are not to show the cursor and the mouse pointer... */
2100    if (!show_cursor) {
2101        scp->end = 0;
2102        scp->start = scp->xsize*scp->ysize - 1;
2103	return;
2104    }
2105
2106    /* update "pseudo" mouse pointer image */
2107    if (scp->status & MOUSE_VISIBLE) {
2108        /* did mouse move since last time ? */
2109        if (scp->status & MOUSE_MOVED) {
2110            /* do we need to remove old mouse pointer image ? */
2111            if (scp->mouse_cut_start != NULL ||
2112                (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2113                (scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->end) {
2114                remove_mouse_image(scp);
2115            }
2116            scp->status &= ~MOUSE_MOVED;
2117            draw_mouse_image(scp);
2118        }
2119        else {
2120            /* mouse didn't move, has it been overwritten ? */
2121            if ((scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->start &&
2122                (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2123                draw_mouse_image(scp);
2124            }
2125        }
2126    }
2127
2128    /* update cursor image */
2129    if (scp->status & CURSOR_ENABLED) {
2130        /* did cursor move since last time ? */
2131        if (scp->cursor_pos != scp->cursor_oldpos) {
2132            /* do we need to remove old cursor image ? */
2133            if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2134                ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2135                remove_cursor_image(scp);
2136            }
2137            scp->cursor_oldpos = scp->cursor_pos;
2138            draw_cursor_image(scp);
2139        }
2140        else {
2141            /* cursor didn't move, has it been overwritten ? */
2142            if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2143                scp->cursor_pos - scp->scr_buf <= scp->end) {
2144                draw_cursor_image(scp);
2145            } else {
2146                /* if its a blinking cursor, we may have to update it */
2147		if (sc_flags & BLINK_CURSOR)
2148                    draw_cursor_image(scp);
2149            }
2150        }
2151        blinkrate++;
2152    }
2153
2154    if (scp->mouse_cut_start != NULL)
2155        draw_cutmarking(scp);
2156
2157    scp->end = 0;
2158    scp->start = scp->xsize*scp->ysize - 1;
2159}
2160
2161int
2162add_scrn_saver(void (*this_saver)(int))
2163{
2164#ifdef SC_SPLASH_SCREEN
2165    if (current_saver == scsplash) {
2166	scsplash_stick(FALSE);
2167        stop_scrn_saver(scsplash);
2168    }
2169#endif
2170
2171    if (current_saver != default_saver)
2172	return EBUSY;
2173    run_scrn_saver = FALSE;
2174    saver_mode = CONS_LKM_SAVER;
2175    current_saver = this_saver;
2176    return 0;
2177}
2178
2179int
2180remove_scrn_saver(void (*this_saver)(int))
2181{
2182    if (current_saver != this_saver)
2183	return EINVAL;
2184
2185    /*
2186     * In order to prevent `current_saver' from being called by
2187     * the timeout routine `scrn_timer()' while we manipulate
2188     * the saver list, we shall set `current_saver' to `none_saver'
2189     * before stopping the current saver, rather than blocking by `splXX()'.
2190     */
2191    current_saver = none_saver;
2192    if (scrn_blanked > 0)
2193        stop_scrn_saver(this_saver);
2194
2195    if (scrn_blanked > 0)
2196	return EBUSY;	/* XXX */
2197
2198    current_saver = default_saver;
2199    return 0;
2200}
2201
2202static void
2203scrn_saver(void (*saver)(int), int blank)
2204{
2205    static int busy = FALSE;
2206
2207    if (busy)
2208	return;
2209    busy = TRUE;
2210    (*saver)(blank);
2211    busy = FALSE;
2212}
2213
2214static void
2215stop_scrn_saver(void (*saver)(int))
2216{
2217    scrn_saver(saver, FALSE);
2218    run_scrn_saver = FALSE;
2219    /* the screen saver may have chosen not to stop after all... */
2220    if (scrn_blanked > 0)
2221	return;
2222
2223    mark_all(cur_console);
2224    if (delayed_next_scr)
2225	switch_scr(cur_console, delayed_next_scr - 1);
2226    wakeup((caddr_t)&scrn_blanked);
2227}
2228
2229static int
2230wait_scrn_saver_stop(void)
2231{
2232    int error = 0;
2233
2234    while (scrn_blanked > 0) {
2235	run_scrn_saver = FALSE;
2236	error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2237	run_scrn_saver = FALSE;
2238	if (error != ERESTART)
2239	    break;
2240    }
2241    return error;
2242}
2243
2244void
2245sc_clear_screen(scr_stat *scp)
2246{
2247    move_crsr(scp, 0, 0);
2248    scp->cursor_oldpos = scp->cursor_pos;
2249    fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2250	  scp->xsize * scp->ysize);
2251    mark_all(scp);
2252    remove_cutmarking(scp);
2253}
2254
2255static int
2256switch_scr(scr_stat *scp, u_int next_scr)
2257{
2258    /* delay switch if actively updating screen */
2259    if (scrn_blanked > 0 || write_in_progress || blink_in_progress) {
2260	scsplash_stick(FALSE);
2261	run_scrn_saver = FALSE;
2262	delayed_next_scr = next_scr+1;
2263	return 0;
2264    }
2265
2266    if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2267	switch_in_progress = FALSE;
2268
2269    if (next_scr >= MAXCONS || switch_in_progress ||
2270	(cur_console->smode.mode == VT_AUTO && ISGRAPHSC(cur_console))) {
2271	do_bell(scp, BELL_PITCH, BELL_DURATION);
2272	return EINVAL;
2273    }
2274
2275    /* is the wanted virtual console open ? */
2276    if (next_scr) {
2277	struct tty *tp = VIRTUAL_TTY(next_scr);
2278	if (!(tp->t_state & TS_ISOPEN)) {
2279	    do_bell(scp, BELL_PITCH, BELL_DURATION);
2280	    return EINVAL;
2281	}
2282    }
2283
2284    switch_in_progress = TRUE;
2285    old_scp = cur_console;
2286    new_scp = console[next_scr];
2287    wakeup((caddr_t)&new_scp->smode);
2288    if (new_scp == old_scp) {
2289	switch_in_progress = FALSE;
2290	delayed_next_scr = FALSE;
2291	return 0;
2292    }
2293
2294    /* has controlling process died? */
2295    if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2296	old_scp->smode.mode = VT_AUTO;
2297    if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2298	new_scp->smode.mode = VT_AUTO;
2299
2300    /* check the modes and switch appropriately */
2301    if (old_scp->smode.mode == VT_PROCESS) {
2302	old_scp->status |= SWITCH_WAIT_REL;
2303	psignal(old_scp->proc, old_scp->smode.relsig);
2304    }
2305    else {
2306	exchange_scr();
2307	if (new_scp->smode.mode == VT_PROCESS) {
2308	    new_scp->status |= SWITCH_WAIT_ACQ;
2309	    psignal(new_scp->proc, new_scp->smode.acqsig);
2310	}
2311	else
2312	    switch_in_progress = FALSE;
2313    }
2314    return 0;
2315}
2316
2317static void
2318exchange_scr(void)
2319{
2320    move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2321    cur_console = new_scp;
2322    if (old_scp->mode != new_scp->mode || ISUNKNOWNSC(old_scp))
2323	set_mode(new_scp);
2324    move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2325    if (ISTEXTSC(new_scp) && (sc_flags & CHAR_CURSOR))
2326	set_destructive_cursor(new_scp);
2327    if (ISGRAPHSC(old_scp))
2328	load_palette(new_scp, palette);
2329    if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2330        old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2331	shfts = ctls = alts = agrs = metas = accents = 0;
2332    set_border(new_scp, new_scp->border);
2333    update_leds(new_scp->status);
2334    delayed_next_scr = FALSE;
2335    mark_all(new_scp);
2336}
2337
2338static void
2339scan_esc(scr_stat *scp, u_char c)
2340{
2341    static u_char ansi_col[16] =
2342	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2343    int i, n;
2344    u_short *src, *dst, count;
2345
2346    if (scp->term.esc == 1) {	/* seen ESC */
2347	switch (c) {
2348
2349	case '7':   /* Save cursor position */
2350	    scp->saved_xpos = scp->xpos;
2351	    scp->saved_ypos = scp->ypos;
2352	    break;
2353
2354	case '8':   /* Restore saved cursor position */
2355	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2356		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2357	    break;
2358
2359	case '[':   /* Start ESC [ sequence */
2360	    scp->term.esc = 2;
2361	    scp->term.last_param = -1;
2362	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2363		scp->term.param[i] = 1;
2364	    scp->term.num_param = 0;
2365	    return;
2366
2367	case 'M':   /* Move cursor up 1 line, scroll if at top */
2368	    if (scp->ypos > 0)
2369		move_crsr(scp, scp->xpos, scp->ypos - 1);
2370	    else {
2371		bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2372		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2373		fillw(scp->term.cur_color | scr_map[0x20],
2374		      scp->scr_buf, scp->xsize);
2375    		mark_all(scp);
2376	    }
2377	    break;
2378#if notyet
2379	case 'Q':
2380	    scp->term.esc = 4;
2381	    return;
2382#endif
2383	case 'c':   /* Clear screen & home */
2384	    sc_clear_screen(scp);
2385	    break;
2386
2387	case '(':   /* iso-2022: designate 94 character set to G0 */
2388	    scp->term.esc = 5;
2389	    return;
2390	}
2391    }
2392    else if (scp->term.esc == 2) {	/* seen ESC [ */
2393	if (c >= '0' && c <= '9') {
2394	    if (scp->term.num_param < MAX_ESC_PAR) {
2395	    if (scp->term.last_param != scp->term.num_param) {
2396		scp->term.last_param = scp->term.num_param;
2397		scp->term.param[scp->term.num_param] = 0;
2398	    }
2399	    else
2400		scp->term.param[scp->term.num_param] *= 10;
2401	    scp->term.param[scp->term.num_param] += c - '0';
2402	    return;
2403	    }
2404	}
2405	scp->term.num_param = scp->term.last_param + 1;
2406	switch (c) {
2407
2408	case ';':
2409	    if (scp->term.num_param < MAX_ESC_PAR)
2410		return;
2411	    break;
2412
2413	case '=':
2414	    scp->term.esc = 3;
2415	    scp->term.last_param = -1;
2416	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2417		scp->term.param[i] = 1;
2418	    scp->term.num_param = 0;
2419	    return;
2420
2421	case 'A':   /* up n rows */
2422	    n = scp->term.param[0]; if (n < 1) n = 1;
2423	    move_crsr(scp, scp->xpos, scp->ypos - n);
2424	    break;
2425
2426	case 'B':   /* down n rows */
2427	    n = scp->term.param[0]; if (n < 1) n = 1;
2428	    move_crsr(scp, scp->xpos, scp->ypos + n);
2429	    break;
2430
2431	case 'C':   /* right n columns */
2432	    n = scp->term.param[0]; if (n < 1) n = 1;
2433	    move_crsr(scp, scp->xpos + n, scp->ypos);
2434	    break;
2435
2436	case 'D':   /* left n columns */
2437	    n = scp->term.param[0]; if (n < 1) n = 1;
2438	    move_crsr(scp, scp->xpos - n, scp->ypos);
2439	    break;
2440
2441	case 'E':   /* cursor to start of line n lines down */
2442	    n = scp->term.param[0]; if (n < 1) n = 1;
2443	    move_crsr(scp, 0, scp->ypos + n);
2444	    break;
2445
2446	case 'F':   /* cursor to start of line n lines up */
2447	    n = scp->term.param[0]; if (n < 1) n = 1;
2448	    move_crsr(scp, 0, scp->ypos - n);
2449	    break;
2450
2451	case 'f':   /* Cursor move */
2452	case 'H':
2453	    if (scp->term.num_param == 0)
2454		move_crsr(scp, 0, 0);
2455	    else if (scp->term.num_param == 2)
2456		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2457	    break;
2458
2459	case 'J':   /* Clear all or part of display */
2460	    if (scp->term.num_param == 0)
2461		n = 0;
2462	    else
2463		n = scp->term.param[0];
2464	    switch (n) {
2465	    case 0: /* clear form cursor to end of display */
2466		fillw(scp->term.cur_color | scr_map[0x20],
2467		      scp->cursor_pos,
2468		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2469    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2470    		mark_for_update(scp, scp->xsize * scp->ysize - 1);
2471		remove_cutmarking(scp);
2472		break;
2473	    case 1: /* clear from beginning of display to cursor */
2474		fillw(scp->term.cur_color | scr_map[0x20],
2475		      scp->scr_buf,
2476		      scp->cursor_pos - scp->scr_buf);
2477    		mark_for_update(scp, 0);
2478    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2479		remove_cutmarking(scp);
2480		break;
2481	    case 2: /* clear entire display */
2482		fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2483		      scp->xsize * scp->ysize);
2484		mark_all(scp);
2485		remove_cutmarking(scp);
2486		break;
2487	    }
2488	    break;
2489
2490	case 'K':   /* Clear all or part of line */
2491	    if (scp->term.num_param == 0)
2492		n = 0;
2493	    else
2494		n = scp->term.param[0];
2495	    switch (n) {
2496	    case 0: /* clear form cursor to end of line */
2497		fillw(scp->term.cur_color | scr_map[0x20],
2498		      scp->cursor_pos,
2499		      scp->xsize - scp->xpos);
2500    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2501    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2502				scp->xsize - 1 - scp->xpos);
2503		break;
2504	    case 1: /* clear from beginning of line to cursor */
2505		fillw(scp->term.cur_color | scr_map[0x20],
2506		      scp->cursor_pos - scp->xpos,
2507		      scp->xpos + 1);
2508    		mark_for_update(scp, scp->ypos * scp->xsize);
2509    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2510		break;
2511	    case 2: /* clear entire line */
2512		fillw(scp->term.cur_color | scr_map[0x20],
2513		      scp->cursor_pos - scp->xpos,
2514		      scp->xsize);
2515    		mark_for_update(scp, scp->ypos * scp->xsize);
2516    		mark_for_update(scp, (scp->ypos + 1) * scp->xsize - 1);
2517		break;
2518	    }
2519	    break;
2520
2521	case 'L':   /* Insert n lines */
2522	    n = scp->term.param[0]; if (n < 1) n = 1;
2523	    if (n > scp->ysize - scp->ypos)
2524		n = scp->ysize - scp->ypos;
2525	    src = scp->scr_buf + scp->ypos * scp->xsize;
2526	    dst = src + n * scp->xsize;
2527	    count = scp->ysize - (scp->ypos + n);
2528	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2529	    fillw(scp->term.cur_color | scr_map[0x20], src,
2530		  n * scp->xsize);
2531	    mark_for_update(scp, scp->ypos * scp->xsize);
2532	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2533	    break;
2534
2535	case 'M':   /* Delete n lines */
2536	    n = scp->term.param[0]; if (n < 1) n = 1;
2537	    if (n > scp->ysize - scp->ypos)
2538		n = scp->ysize - scp->ypos;
2539	    dst = scp->scr_buf + scp->ypos * scp->xsize;
2540	    src = dst + n * scp->xsize;
2541	    count = scp->ysize - (scp->ypos + n);
2542	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2543	    src = dst + count * scp->xsize;
2544	    fillw(scp->term.cur_color | scr_map[0x20], src,
2545		  n * scp->xsize);
2546	    mark_for_update(scp, scp->ypos * scp->xsize);
2547	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2548	    break;
2549
2550	case 'P':   /* Delete n chars */
2551	    n = scp->term.param[0]; if (n < 1) n = 1;
2552	    if (n > scp->xsize - scp->xpos)
2553		n = scp->xsize - scp->xpos;
2554	    dst = scp->cursor_pos;
2555	    src = dst + n;
2556	    count = scp->xsize - (scp->xpos + n);
2557	    bcopy(src, dst, count * sizeof(u_short));
2558	    src = dst + count;
2559	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2560	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2561	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count - 1);
2562	    break;
2563
2564	case '@':   /* Insert n chars */
2565	    n = scp->term.param[0]; if (n < 1) n = 1;
2566	    if (n > scp->xsize - scp->xpos)
2567		n = scp->xsize - scp->xpos;
2568	    src = scp->cursor_pos;
2569	    dst = src + n;
2570	    count = scp->xsize - (scp->xpos + n);
2571	    bcopy(src, dst, count * sizeof(u_short));
2572	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2573	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2574	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count - 1);
2575	    break;
2576
2577	case 'S':   /* scroll up n lines */
2578	    n = scp->term.param[0]; if (n < 1)  n = 1;
2579	    if (n > scp->ysize)
2580		n = scp->ysize;
2581	    bcopy(scp->scr_buf + (scp->xsize * n),
2582		   scp->scr_buf,
2583		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
2584	    fillw(scp->term.cur_color | scr_map[0x20],
2585		  scp->scr_buf + scp->xsize * (scp->ysize - n),
2586		  scp->xsize * n);
2587    	    mark_all(scp);
2588	    break;
2589
2590	case 'T':   /* scroll down n lines */
2591	    n = scp->term.param[0]; if (n < 1)  n = 1;
2592	    if (n > scp->ysize)
2593		n = scp->ysize;
2594	    bcopy(scp->scr_buf,
2595		  scp->scr_buf + (scp->xsize * n),
2596		  scp->xsize * (scp->ysize - n) *
2597		  sizeof(u_short));
2598	    fillw(scp->term.cur_color | scr_map[0x20],
2599		  scp->scr_buf, scp->xsize * n);
2600    	    mark_all(scp);
2601	    break;
2602
2603	case 'X':   /* erase n characters in line */
2604	    n = scp->term.param[0]; if (n < 1)  n = 1;
2605	    if (n > scp->xsize - scp->xpos)
2606		n = scp->xsize - scp->xpos;
2607	    fillw(scp->term.cur_color | scr_map[0x20],
2608		  scp->cursor_pos, n);
2609	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2610	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n - 1);
2611	    break;
2612
2613	case 'Z':   /* move n tabs backwards */
2614	    n = scp->term.param[0]; if (n < 1)  n = 1;
2615	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2616		i -= 8*n;
2617	    else
2618		i -= 8*(n-1);
2619	    if (i < 0)
2620		i = 0;
2621	    move_crsr(scp, i, scp->ypos);
2622	    break;
2623
2624	case '`':   /* move cursor to column n */
2625	    n = scp->term.param[0]; if (n < 1)  n = 1;
2626	    move_crsr(scp, n - 1, scp->ypos);
2627	    break;
2628
2629	case 'a':   /* move cursor n columns to the right */
2630	    n = scp->term.param[0]; if (n < 1)  n = 1;
2631	    move_crsr(scp, scp->xpos + n, scp->ypos);
2632	    break;
2633
2634	case 'd':   /* move cursor to row n */
2635	    n = scp->term.param[0]; if (n < 1)  n = 1;
2636	    move_crsr(scp, scp->xpos, n - 1);
2637	    break;
2638
2639	case 'e':   /* move cursor n rows down */
2640	    n = scp->term.param[0]; if (n < 1)  n = 1;
2641	    move_crsr(scp, scp->xpos, scp->ypos + n);
2642	    break;
2643
2644	case 'm':   /* change attribute */
2645	    if (scp->term.num_param == 0) {
2646		scp->term.attr_mask = NORMAL_ATTR;
2647		scp->term.cur_attr =
2648		    scp->term.cur_color = scp->term.std_color;
2649		break;
2650	    }
2651	    for (i = 0; i < scp->term.num_param; i++) {
2652		switch (n = scp->term.param[i]) {
2653		case 0: /* back to normal */
2654		    scp->term.attr_mask = NORMAL_ATTR;
2655		    scp->term.cur_attr =
2656			scp->term.cur_color = scp->term.std_color;
2657		    break;
2658		case 1: /* bold */
2659		    scp->term.attr_mask |= BOLD_ATTR;
2660		    scp->term.cur_attr = mask2attr(&scp->term);
2661		    break;
2662		case 4: /* underline */
2663		    scp->term.attr_mask |= UNDERLINE_ATTR;
2664		    scp->term.cur_attr = mask2attr(&scp->term);
2665		    break;
2666		case 5: /* blink */
2667		    scp->term.attr_mask |= BLINK_ATTR;
2668		    scp->term.cur_attr = mask2attr(&scp->term);
2669		    break;
2670		case 7: /* reverse video */
2671		    scp->term.attr_mask |= REVERSE_ATTR;
2672		    scp->term.cur_attr = mask2attr(&scp->term);
2673		    break;
2674		case 30: case 31: /* set fg color */
2675		case 32: case 33: case 34:
2676		case 35: case 36: case 37:
2677		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2678		    scp->term.cur_color =
2679			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2680		    scp->term.cur_attr = mask2attr(&scp->term);
2681		    break;
2682		case 40: case 41: /* set bg color */
2683		case 42: case 43: case 44:
2684		case 45: case 46: case 47:
2685		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2686		    scp->term.cur_color =
2687			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2688		    scp->term.cur_attr = mask2attr(&scp->term);
2689		    break;
2690		}
2691	    }
2692	    break;
2693
2694	case 's':   /* Save cursor position */
2695	    scp->saved_xpos = scp->xpos;
2696	    scp->saved_ypos = scp->ypos;
2697	    break;
2698
2699	case 'u':   /* Restore saved cursor position */
2700	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2701		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2702	    break;
2703
2704	case 'x':
2705	    if (scp->term.num_param == 0)
2706		n = 0;
2707	    else
2708		n = scp->term.param[0];
2709	    switch (n) {
2710	    case 0:     /* reset attributes */
2711		scp->term.attr_mask = NORMAL_ATTR;
2712		scp->term.cur_attr =
2713		    scp->term.cur_color = scp->term.std_color =
2714		    current_default->std_color;
2715		scp->term.rev_color = current_default->rev_color;
2716		break;
2717	    case 1:     /* set ansi background */
2718		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2719		scp->term.cur_color = scp->term.std_color =
2720		    (scp->term.std_color & 0x0F00) |
2721		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2722		scp->term.cur_attr = mask2attr(&scp->term);
2723		break;
2724	    case 2:     /* set ansi foreground */
2725		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2726		scp->term.cur_color = scp->term.std_color =
2727		    (scp->term.std_color & 0xF000) |
2728		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2729		scp->term.cur_attr = mask2attr(&scp->term);
2730		break;
2731	    case 3:     /* set ansi attribute directly */
2732		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2733		scp->term.cur_color = scp->term.std_color =
2734		    (scp->term.param[1]&0xFF)<<8;
2735		scp->term.cur_attr = mask2attr(&scp->term);
2736		break;
2737	    case 5:     /* set ansi reverse video background */
2738		scp->term.rev_color =
2739		    (scp->term.rev_color & 0x0F00) |
2740		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2741		scp->term.cur_attr = mask2attr(&scp->term);
2742		break;
2743	    case 6:     /* set ansi reverse video foreground */
2744		scp->term.rev_color =
2745		    (scp->term.rev_color & 0xF000) |
2746		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2747		scp->term.cur_attr = mask2attr(&scp->term);
2748		break;
2749	    case 7:     /* set ansi reverse video directly */
2750		scp->term.rev_color =
2751		    (scp->term.param[1]&0xFF)<<8;
2752		scp->term.cur_attr = mask2attr(&scp->term);
2753		break;
2754	    }
2755	    break;
2756
2757	case 'z':   /* switch to (virtual) console n */
2758	    if (scp->term.num_param == 1)
2759		switch_scr(scp, scp->term.param[0]);
2760	    break;
2761	}
2762    }
2763    else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2764	if (c >= '0' && c <= '9') {
2765	    if (scp->term.num_param < MAX_ESC_PAR) {
2766	    if (scp->term.last_param != scp->term.num_param) {
2767		scp->term.last_param = scp->term.num_param;
2768		scp->term.param[scp->term.num_param] = 0;
2769	    }
2770	    else
2771		scp->term.param[scp->term.num_param] *= 10;
2772	    scp->term.param[scp->term.num_param] += c - '0';
2773	    return;
2774	    }
2775	}
2776	scp->term.num_param = scp->term.last_param + 1;
2777	switch (c) {
2778
2779	case ';':
2780	    if (scp->term.num_param < MAX_ESC_PAR)
2781		return;
2782	    break;
2783
2784	case 'A':   /* set display border color */
2785	    if (scp->term.num_param == 1) {
2786		scp->border=scp->term.param[0] & 0xff;
2787		if (scp == cur_console)
2788		    set_border(cur_console, scp->border);
2789            }
2790	    break;
2791
2792	case 'B':   /* set bell pitch and duration */
2793	    if (scp->term.num_param == 2) {
2794		scp->bell_pitch = scp->term.param[0];
2795		scp->bell_duration = scp->term.param[1];
2796	    }
2797	    break;
2798
2799	case 'C':   /* set cursor type & shape */
2800	    if (scp->term.num_param == 1) {
2801		if (scp->term.param[0] & 0x01)
2802		    sc_flags |= BLINK_CURSOR;
2803		else
2804		    sc_flags &= ~BLINK_CURSOR;
2805		if ((scp->term.param[0] & 0x02)
2806		    && ISFONTAVAIL(get_adapter(scp)->va_flags))
2807		    sc_flags |= CHAR_CURSOR;
2808		else
2809		    sc_flags &= ~CHAR_CURSOR;
2810	    }
2811	    else if (scp->term.num_param == 2) {
2812		scp->cursor_start = scp->term.param[0] & 0x1F;
2813		scp->cursor_end = scp->term.param[1] & 0x1F;
2814	    }
2815	    /*
2816	     * The cursor shape is global property; all virtual consoles
2817	     * are affected. Update the cursor in the current console...
2818	     */
2819	    if (!ISGRAPHSC(cur_console)) {
2820		remove_cursor_image(cur_console);
2821		if (sc_flags & CHAR_CURSOR)
2822	            set_destructive_cursor(cur_console);
2823		draw_cursor_image(cur_console);
2824	    }
2825	    break;
2826
2827	case 'F':   /* set ansi foreground */
2828	    if (scp->term.num_param == 1) {
2829		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2830		scp->term.cur_color = scp->term.std_color =
2831		    (scp->term.std_color & 0xF000)
2832		    | ((scp->term.param[0] & 0x0F) << 8);
2833		scp->term.cur_attr = mask2attr(&scp->term);
2834	    }
2835	    break;
2836
2837	case 'G':   /* set ansi background */
2838	    if (scp->term.num_param == 1) {
2839		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2840		scp->term.cur_color = scp->term.std_color =
2841		    (scp->term.std_color & 0x0F00)
2842		    | ((scp->term.param[0] & 0x0F) << 12);
2843		scp->term.cur_attr = mask2attr(&scp->term);
2844	    }
2845	    break;
2846
2847	case 'H':   /* set ansi reverse video foreground */
2848	    if (scp->term.num_param == 1) {
2849		scp->term.rev_color =
2850		    (scp->term.rev_color & 0xF000)
2851		    | ((scp->term.param[0] & 0x0F) << 8);
2852		scp->term.cur_attr = mask2attr(&scp->term);
2853	    }
2854	    break;
2855
2856	case 'I':   /* set ansi reverse video background */
2857	    if (scp->term.num_param == 1) {
2858		scp->term.rev_color =
2859		    (scp->term.rev_color & 0x0F00)
2860		    | ((scp->term.param[0] & 0x0F) << 12);
2861		scp->term.cur_attr = mask2attr(&scp->term);
2862	    }
2863	    break;
2864	}
2865    }
2866#if notyet
2867    else if (scp->term.esc == 4) {	/* seen ESC Q */
2868	/* to be filled */
2869    }
2870#endif
2871    else if (scp->term.esc == 5) {	/* seen ESC ( */
2872	switch (c) {
2873	case 'B':   /* iso-2022: desginate ASCII into G0 */
2874	    break;
2875	/* other items to be filled */
2876	default:
2877	    break;
2878	}
2879    }
2880    scp->term.esc = 0;
2881}
2882
2883static void
2884ansi_put(scr_stat *scp, u_char *buf, int len)
2885{
2886    u_char *ptr = buf;
2887
2888    /* make screensaver happy */
2889    if (!sticky_splash && scp == cur_console)
2890	run_scrn_saver = FALSE;
2891
2892    write_in_progress++;
2893outloop:
2894    if (scp->term.esc) {
2895	scan_esc(scp, *ptr++);
2896	len--;
2897    }
2898    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2899 	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
2900 	u_short cur_attr = scp->term.cur_attr;
2901 	u_short *cursor_pos = scp->cursor_pos;
2902	do {
2903	    /*
2904	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2905	     * pointers in the following to volatile should have no effect,
2906	     * but in fact speeds up this inner loop from 26 to 18 cycles
2907	     * (+ cache misses) on i486's.
2908	     */
2909#define	UCVP(ucp)	((u_char volatile *)(ucp))
2910	    *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
2911	    ptr++;
2912	    cnt--;
2913	} while (cnt && PRINTABLE(*ptr));
2914	len -= (cursor_pos - scp->cursor_pos);
2915	scp->xpos += (cursor_pos - scp->cursor_pos);
2916	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2917	mark_for_update(scp, cursor_pos - scp->scr_buf);
2918	scp->cursor_pos = cursor_pos;
2919	if (scp->xpos >= scp->xsize) {
2920	    scp->xpos = 0;
2921	    scp->ypos++;
2922	}
2923    }
2924    else  {
2925	switch(*ptr) {
2926	case 0x07:
2927	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2928	    break;
2929
2930	case 0x08:      /* non-destructive backspace */
2931	    if (scp->cursor_pos > scp->scr_buf) {
2932	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2933		scp->cursor_pos--;
2934	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2935		if (scp->xpos > 0)
2936		    scp->xpos--;
2937		else {
2938		    scp->xpos += scp->xsize - 1;
2939		    scp->ypos--;
2940		}
2941	    }
2942	    break;
2943
2944	case 0x09:  /* non-destructive tab */
2945	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2946	    scp->cursor_pos += (8 - scp->xpos % 8u);
2947	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2948	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2949	        scp->xpos = 0;
2950	        scp->ypos++;
2951	    }
2952	    break;
2953
2954	case 0x0a:  /* newline, same pos */
2955	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2956	    scp->cursor_pos += scp->xsize;
2957	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2958	    scp->ypos++;
2959	    break;
2960
2961	case 0x0c:  /* form feed, clears screen */
2962	    sc_clear_screen(scp);
2963	    break;
2964
2965	case 0x0d:  /* return, return to pos 0 */
2966	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2967	    scp->cursor_pos -= scp->xpos;
2968	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2969	    scp->xpos = 0;
2970	    break;
2971
2972	case 0x1b:  /* start escape sequence */
2973	    scp->term.esc = 1;
2974	    scp->term.num_param = 0;
2975	    break;
2976	}
2977	ptr++; len--;
2978    }
2979    /* do we have to scroll ?? */
2980    if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
2981	remove_cutmarking(scp);
2982	if (scp->history != NULL) {
2983	    bcopy(scp->scr_buf, scp->history_head,
2984		   scp->xsize * sizeof(u_short));
2985	    scp->history_head += scp->xsize;
2986	    if (scp->history_head + scp->xsize >
2987		scp->history + scp->history_size)
2988		scp->history_head = scp->history;
2989	}
2990	bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
2991	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
2992	fillw(scp->term.cur_color | scr_map[0x20],
2993	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
2994	      scp->xsize);
2995	scp->cursor_pos -= scp->xsize;
2996	scp->ypos--;
2997    	mark_all(scp);
2998    }
2999    if (len)
3000	goto outloop;
3001    write_in_progress--;
3002    if (delayed_next_scr)
3003	switch_scr(scp, delayed_next_scr - 1);
3004}
3005
3006static void
3007scinit(void)
3008{
3009    int col;
3010    int row;
3011    u_int i;
3012
3013    if (init_done != COLD)
3014	return;
3015    init_done = WARM;
3016
3017    /* extract the hardware cursor location and move it out of the way */
3018    (*biosvidsw.read_hw_cursor)(V_ADP_PRIMARY, &col, &row);
3019    (*biosvidsw.set_hw_cursor)(V_ADP_PRIMARY, -1, -1);
3020
3021    /* set up the first console */
3022    current_default = &user_default;
3023    console[0] = &main_console;
3024    init_scp(console[0]);
3025    cur_console = console[0];
3026
3027    /* copy screen to temporary buffer */
3028    if (ISTEXTSC(console[0]))
3029	generic_bcopy((ushort *)(get_adapter(console[0])->va_window), sc_buffer,
3030		      console[0]->xsize * console[0]->ysize * sizeof(u_short));
3031
3032    console[0]->scr_buf = console[0]->mouse_pos = console[0]->mouse_oldpos
3033	= sc_buffer;
3034    if (col >= console[0]->xsize)
3035	col = 0;
3036    if (row >= console[0]->ysize)
3037	row = console[0]->ysize - 1;
3038    console[0]->xpos = col;
3039    console[0]->ypos = row;
3040    console[0]->cursor_pos = console[0]->cursor_oldpos =
3041	sc_buffer + row*console[0]->xsize + col;
3042    console[0]->cursor_saveunder = *console[0]->cursor_pos;
3043    for (i=1; i<MAXCONS; i++)
3044	console[i] = NULL;
3045    kernel_console.esc = 0;
3046    kernel_console.attr_mask = NORMAL_ATTR;
3047    kernel_console.cur_attr =
3048	kernel_console.cur_color = kernel_console.std_color =
3049	kernel_default.std_color;
3050    kernel_console.rev_color = kernel_default.rev_color;
3051
3052    /* initialize mapscrn arrays to a one to one map */
3053    for (i=0; i<sizeof(scr_map); i++) {
3054	scr_map[i] = scr_rmap[i] = i;
3055    }
3056
3057    /* Save font and palette */
3058    if (ISFONTAVAIL(get_adapter(cur_console)->va_flags)) {
3059	if (fonts_loaded & FONT_16) {
3060	    copy_font(cur_console, LOAD, 16, font_16);
3061	} else {
3062	    copy_font(cur_console, SAVE, 16, font_16);
3063	    fonts_loaded = FONT_16;
3064	    set_destructive_cursor(cur_console);
3065	}
3066	/*
3067	 * FONT KLUDGE
3068	 * Always use the font page #0. XXX
3069	 */
3070	(*biosvidsw.show_font)(cur_console->adp, 0);
3071    }
3072    save_palette(cur_console, palette);
3073
3074#ifdef SC_SPLASH_SCREEN
3075    /* put up the splash. */
3076    scsplash_init(cur_console);
3077#endif
3078}
3079
3080static void
3081scshutdown(int howto, void *arg)
3082{
3083    scsplash_stick(FALSE);
3084    run_scrn_saver = FALSE;
3085    if (!cold && cur_console->smode.mode == VT_AUTO
3086	&& console[0]->smode.mode == VT_AUTO)
3087	switch_scr(cur_console, 0);
3088    shutdown_in_progress = TRUE;
3089}
3090
3091int
3092sc_clean_up(scr_stat *scp)
3093{
3094    int error;
3095
3096    if ((error = wait_scrn_saver_stop()))
3097	return error;
3098    scp->status &= ~MOUSE_VISIBLE;
3099    remove_cutmarking(scp);
3100    return 0;
3101}
3102
3103void
3104sc_alloc_scr_buffer(scr_stat *scp, int wait, int clear)
3105{
3106    if (scp->scr_buf)
3107	free(scp->scr_buf, M_DEVBUF);
3108    scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3109				     M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3110
3111    if (clear) {
3112        /* clear the screen and move the text cursor to the top-left position */
3113	sc_clear_screen(scp);
3114    } else {
3115	/* retain the current cursor position, but adjust pointers */
3116	move_crsr(scp, scp->xpos, scp->ypos);
3117	scp->cursor_oldpos = scp->cursor_pos;
3118    }
3119
3120    /* move the mouse cursor at the center of the screen */
3121    sc_move_mouse(scp, scp->xpixel / 2, scp->ypixel / 2);
3122}
3123
3124void
3125sc_alloc_cut_buffer(scr_stat *scp, int wait)
3126{
3127    if ((cut_buffer == NULL)
3128	|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
3129	if (cut_buffer != NULL)
3130	    free(cut_buffer, M_DEVBUF);
3131	cut_buffer_size = scp->xsize * scp->ysize + 1;
3132	cut_buffer = (u_char *)malloc(cut_buffer_size,
3133				    M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3134	if (cut_buffer != NULL)
3135	    cut_buffer[0] = '\0';
3136    }
3137}
3138
3139void
3140sc_alloc_history_buffer(scr_stat *scp, int lines, int extra, int wait)
3141{
3142    u_short *usp;
3143
3144    if (lines < scp->ysize)
3145	lines = scp->ysize;
3146
3147    usp = scp->history;
3148    scp->history = NULL;
3149    if (usp != NULL) {
3150	free(usp, M_DEVBUF);
3151	if (extra > 0)
3152	    extra_history_size += extra;
3153    }
3154
3155    scp->history_size = lines * scp->xsize;
3156    if (lines > imax(sc_history_size, scp->ysize))
3157	extra_history_size -= lines - imax(sc_history_size, scp->ysize);
3158    usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
3159			    M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3160    if (usp != NULL)
3161	bzero(usp, scp->history_size * sizeof(u_short));
3162    scp->history_head = scp->history_pos = usp;
3163    scp->history = usp;
3164}
3165
3166static scr_stat
3167*alloc_scp()
3168{
3169    scr_stat *scp;
3170
3171    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3172    init_scp(scp);
3173    sc_alloc_scr_buffer(scp, TRUE, TRUE);
3174    if (ISMOUSEAVAIL(get_adapter(scp)->va_flags))
3175	sc_alloc_cut_buffer(scp, TRUE);
3176    sc_alloc_history_buffer(scp, sc_history_size, 0, TRUE);
3177/* SOS
3178    if (get_adapter(scp)->va_flags & V_ADP_MODECHANGE)
3179	set_mode(scp);
3180*/
3181    sc_clear_screen(scp);
3182    scp->cursor_saveunder = *scp->cursor_pos;
3183    return scp;
3184}
3185
3186static void
3187init_scp(scr_stat *scp)
3188{
3189    video_info_t info;
3190
3191    scp->adp = V_ADP_PRIMARY;
3192    (*biosvidsw.get_info)(scp->adp, initial_video_mode, &info);
3193
3194    scp->status = 0;
3195    scp->mode = scp->initial_mode = initial_video_mode;
3196    scp->scr_buf = NULL;
3197    if (info.vi_flags & V_INFO_GRAPHICS) {
3198	scp->status |= GRAPHICS_MODE;
3199	scp->xpixel = info.vi_width;
3200	scp->ypixel = info.vi_height;
3201	scp->xsize = info.vi_width/8;
3202	scp->ysize = info.vi_height/info.vi_cheight;
3203	scp->font_size = FONT_NONE;
3204    } else {
3205	scp->xsize = info.vi_width;
3206	scp->ysize = info.vi_height;
3207	scp->xpixel = scp->xsize*8;
3208	scp->ypixel = scp->ysize*info.vi_cheight;
3209	scp->font_size = info.vi_cheight;
3210    }
3211    scp->xoff = scp->yoff = 0;
3212    scp->xpos = scp->ypos = 0;
3213    scp->saved_xpos = scp->saved_ypos = -1;
3214    scp->start = scp->xsize * scp->ysize;
3215    scp->end = 0;
3216    scp->term.esc = 0;
3217    scp->term.attr_mask = NORMAL_ATTR;
3218    scp->term.cur_attr =
3219	scp->term.cur_color = scp->term.std_color =
3220	current_default->std_color;
3221    scp->term.rev_color = current_default->rev_color;
3222    scp->border = BG_BLACK;
3223    scp->cursor_start = *(u_int8_t *)pa_to_va(0x461);
3224    scp->cursor_end = *(u_int8_t *)pa_to_va(0x460);
3225    scp->mouse_xpos = scp->xsize*8/2;
3226    scp->mouse_ypos = scp->ysize*scp->font_size/2;
3227    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3228    scp->mouse_signal = 0;
3229    scp->mouse_pid = 0;
3230    scp->mouse_proc = NULL;
3231    scp->bell_pitch = BELL_PITCH;
3232    scp->bell_duration = BELL_DURATION;
3233    scp->status |= (*(u_int8_t *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3234    scp->status |= CURSOR_ENABLED;
3235    scp->pid = 0;
3236    scp->proc = NULL;
3237    scp->smode.mode = VT_AUTO;
3238    scp->history_head = scp->history_pos = scp->history = NULL;
3239    scp->history_size = imax(sc_history_size, scp->ysize) * scp->xsize;
3240}
3241
3242static u_char
3243*get_fstr(u_int c, u_int *len)
3244{
3245    u_int i;
3246
3247    if (!(c & FKEY))
3248	return(NULL);
3249    i = (c & 0xFF) - F_FN;
3250    if (i > n_fkey_tab)
3251	return(NULL);
3252    *len = fkey_tab[i].len;
3253    return(fkey_tab[i].str);
3254}
3255
3256static void
3257history_to_screen(scr_stat *scp)
3258{
3259    int i;
3260
3261    for (i=0; i<scp->ysize; i++)
3262	bcopy(scp->history + (((scp->history_pos - scp->history) +
3263	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3264	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3265	       scp->xsize * sizeof(u_short));
3266    mark_all(scp);
3267}
3268
3269static int
3270history_up_line(scr_stat *scp)
3271{
3272    if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3273	scp->history_head) {
3274	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3275	history_to_screen(scp);
3276	return 0;
3277    }
3278    else
3279	return -1;
3280}
3281
3282static int
3283history_down_line(scr_stat *scp)
3284{
3285    if (scp->history_pos != scp->history_head) {
3286	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3287	history_to_screen(scp);
3288	return 0;
3289    }
3290    else
3291	return -1;
3292}
3293
3294/*
3295 * scgetc(flags) - get character from keyboard.
3296 * If flags & SCGETC_CN, then avoid harmful side effects.
3297 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3298 * return NOKEY if there is nothing there.
3299 */
3300static u_int
3301scgetc(u_int flags)
3302{
3303    struct key_t *key;
3304    u_char scancode, keycode;
3305    u_int state, action;
3306    int c;
3307    static u_char esc_flag = 0, compose = 0;
3308    static u_int chr = 0;
3309
3310next_code:
3311    /* first see if there is something in the keyboard port */
3312    if (flags & SCGETC_NONBLOCK) {
3313	c = read_kbd_data_no_wait(sc_kbdc);
3314	if (c == -1)
3315	    return(NOKEY);
3316    } else {
3317	do {
3318	    c = read_kbd_data(sc_kbdc);
3319	} while(c == -1);
3320    }
3321    scancode = (u_char)c;
3322
3323    /* make screensaver happy */
3324    if (!(scancode & 0x80)) {
3325	scsplash_stick(FALSE);
3326	run_scrn_saver = FALSE;
3327    }
3328
3329    if (!(flags & SCGETC_CN)) {
3330	/* do the /dev/random device a favour */
3331	add_keyboard_randomness(scancode);
3332
3333	if (cur_console->status & KBD_RAW_MODE)
3334	    return scancode;
3335    }
3336
3337    keycode = scancode & 0x7F;
3338    switch (esc_flag) {
3339    case 0x00:      /* normal scancode */
3340	switch(scancode) {
3341	case 0xB8:  /* left alt (compose key) */
3342	    if (compose) {
3343		compose = 0;
3344		if (chr > 255) {
3345		    do_bell(cur_console,
3346			BELL_PITCH, BELL_DURATION);
3347		    chr = 0;
3348		}
3349	    }
3350	    break;
3351	case 0x38:
3352	    if (!compose) {
3353		compose = 1;
3354		chr = 0;
3355	    }
3356	    break;
3357	case 0xE0:
3358	case 0xE1:
3359	    esc_flag = scancode;
3360	    goto next_code;
3361	}
3362	break;
3363    case 0xE0:      /* 0xE0 prefix */
3364	esc_flag = 0;
3365	switch (keycode) {
3366	case 0x1C:  /* right enter key */
3367	    keycode = 0x59;
3368	    break;
3369	case 0x1D:  /* right ctrl key */
3370	    keycode = 0x5A;
3371	    break;
3372	case 0x35:  /* keypad divide key */
3373	    keycode = 0x5B;
3374	    break;
3375	case 0x37:  /* print scrn key */
3376	    keycode = 0x5C;
3377	    break;
3378	case 0x38:  /* right alt key (alt gr) */
3379	    keycode = 0x5D;
3380	    break;
3381	case 0x47:  /* grey home key */
3382	    keycode = 0x5E;
3383	    break;
3384	case 0x48:  /* grey up arrow key */
3385	    keycode = 0x5F;
3386	    break;
3387	case 0x49:  /* grey page up key */
3388	    keycode = 0x60;
3389	    break;
3390	case 0x4B:  /* grey left arrow key */
3391	    keycode = 0x61;
3392	    break;
3393	case 0x4D:  /* grey right arrow key */
3394	    keycode = 0x62;
3395	    break;
3396	case 0x4F:  /* grey end key */
3397	    keycode = 0x63;
3398	    break;
3399	case 0x50:  /* grey down arrow key */
3400	    keycode = 0x64;
3401	    break;
3402	case 0x51:  /* grey page down key */
3403	    keycode = 0x65;
3404	    break;
3405	case 0x52:  /* grey insert key */
3406	    keycode = 0x66;
3407	    break;
3408	case 0x53:  /* grey delete key */
3409	    keycode = 0x67;
3410	    break;
3411
3412	/* the following 3 are only used on the MS "Natural" keyboard */
3413	case 0x5b:  /* left Window key */
3414	    keycode = 0x69;
3415	    break;
3416	case 0x5c:  /* right Window key */
3417	    keycode = 0x6a;
3418	    break;
3419	case 0x5d:  /* menu key */
3420	    keycode = 0x6b;
3421	    break;
3422	default:    /* ignore everything else */
3423	    goto next_code;
3424	}
3425	break;
3426    case 0xE1:      /* 0xE1 prefix */
3427	esc_flag = 0;
3428	if (keycode == 0x1D)
3429	    esc_flag = 0x1D;
3430	goto next_code;
3431	/* NOT REACHED */
3432    case 0x1D:      /* pause / break */
3433	esc_flag = 0;
3434	if (keycode != 0x45)
3435	    goto next_code;
3436	keycode = 0x68;
3437	break;
3438    }
3439
3440    if (!(flags & SCGETC_CN) && (cur_console->status & KBD_CODE_MODE))
3441	return (keycode | (scancode & 0x80));
3442
3443    /* if scroll-lock pressed allow history browsing */
3444    if (cur_console->history && cur_console->status & SLKED) {
3445	int i;
3446
3447	cur_console->status &= ~CURSOR_ENABLED;
3448	if (!(cur_console->status & BUFFER_SAVED)) {
3449	    cur_console->status |= BUFFER_SAVED;
3450	    cur_console->history_save = cur_console->history_head;
3451
3452	    /* copy screen into top of history buffer */
3453	    for (i=0; i<cur_console->ysize; i++) {
3454		bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3455		       cur_console->history_head,
3456		       cur_console->xsize * sizeof(u_short));
3457		cur_console->history_head += cur_console->xsize;
3458		if (cur_console->history_head + cur_console->xsize >
3459		    cur_console->history + cur_console->history_size)
3460		    cur_console->history_head=cur_console->history;
3461	    }
3462	    cur_console->history_pos = cur_console->history_head;
3463	    history_to_screen(cur_console);
3464	}
3465	switch (scancode) {
3466	case 0x47:  /* home key */
3467	    cur_console->history_pos = cur_console->history_head;
3468	    history_to_screen(cur_console);
3469	    goto next_code;
3470
3471	case 0x4F:  /* end key */
3472	    cur_console->history_pos =
3473		WRAPHIST(cur_console, cur_console->history_head,
3474			 cur_console->xsize*cur_console->ysize);
3475	    history_to_screen(cur_console);
3476	    goto next_code;
3477
3478	case 0x48:  /* up arrow key */
3479	    if (history_up_line(cur_console))
3480		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3481	    goto next_code;
3482
3483	case 0x50:  /* down arrow key */
3484	    if (history_down_line(cur_console))
3485		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3486	    goto next_code;
3487
3488	case 0x49:  /* page up key */
3489	    for (i=0; i<cur_console->ysize; i++)
3490	    if (history_up_line(cur_console)) {
3491		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3492		break;
3493	    }
3494	    goto next_code;
3495
3496	case 0x51:  /* page down key */
3497	    for (i=0; i<cur_console->ysize; i++)
3498	    if (history_down_line(cur_console)) {
3499		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3500		break;
3501	    }
3502	    goto next_code;
3503	}
3504    }
3505
3506    if (compose) {
3507	switch (scancode) {
3508	/* key pressed process it */
3509	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
3510	    chr = (scancode - 0x40) + chr*10;
3511	    goto next_code;
3512	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
3513	    chr = (scancode - 0x47) + chr*10;
3514	    goto next_code;
3515	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
3516	    chr = (scancode - 0x4E) + chr*10;
3517	    goto next_code;
3518	case 0x52:              /* keypad 0 */
3519	    chr *= 10;
3520	    goto next_code;
3521
3522	/* key release, no interest here */
3523	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
3524	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
3525	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
3526	case 0xD2:              /* keypad 0 */
3527	    goto next_code;
3528
3529	case 0x38:              /* left alt key */
3530	    break;
3531	default:
3532	    if (chr) {
3533		compose = chr = 0;
3534		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3535		goto next_code;
3536	    }
3537	    break;
3538	}
3539    }
3540
3541    state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
3542    if ((!agrs && (cur_console->status & ALKED))
3543	|| (agrs && !(cur_console->status & ALKED)))
3544	keycode += ALTGR_OFFSET;
3545    key = &key_map.key[keycode];
3546    if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
3547	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
3548	state ^= 1;
3549
3550    /* Check for make/break */
3551    action = key->map[state];
3552    if (scancode & 0x80) {      /* key released */
3553	if (key->spcl & (0x80>>state)) {
3554	    switch (action) {
3555	    case LSH:
3556		shfts &= ~1;
3557		break;
3558	    case RSH:
3559		shfts &= ~2;
3560		break;
3561	    case LCTR:
3562		ctls &= ~1;
3563		break;
3564	    case RCTR:
3565		ctls &= ~2;
3566		break;
3567	    case LALT:
3568		alts &= ~1;
3569		break;
3570	    case RALT:
3571		alts &= ~2;
3572		break;
3573	    case NLK:
3574		nlkcnt = 0;
3575		break;
3576	    case CLK:
3577		clkcnt = 0;
3578		break;
3579	    case SLK:
3580		slkcnt = 0;
3581		break;
3582	    case ASH:
3583		agrs = 0;
3584		break;
3585	    case ALK:
3586		alkcnt = 0;
3587		break;
3588	    case META:
3589		metas = 0;
3590		break;
3591	    }
3592	}
3593	if (chr && !compose) {
3594	    action = chr;
3595	    chr = 0;
3596	    return(action);
3597	}
3598    } else {
3599	/* key pressed */
3600	if (key->spcl & (0x80>>state)) {
3601	    switch (action) {
3602	    /* LOCKING KEYS */
3603	    case NLK:
3604		if (!nlkcnt) {
3605		    nlkcnt++;
3606		    if (cur_console->status & NLKED)
3607			cur_console->status &= ~NLKED;
3608		    else
3609			cur_console->status |= NLKED;
3610		    update_leds(cur_console->status);
3611		}
3612		break;
3613	    case CLK:
3614		if (!clkcnt) {
3615		    clkcnt++;
3616		    if (cur_console->status & CLKED)
3617			cur_console->status &= ~CLKED;
3618		    else
3619			cur_console->status |= CLKED;
3620		    update_leds(cur_console->status);
3621		}
3622		break;
3623	    case SLK:
3624		if (!slkcnt) {
3625		    slkcnt++;
3626		    if (cur_console->status & SLKED) {
3627			cur_console->status &= ~SLKED;
3628			if (cur_console->status & BUFFER_SAVED){
3629			    int i;
3630			    u_short *ptr = cur_console->history_save;
3631
3632			    for (i=0; i<cur_console->ysize; i++) {
3633				bcopy(ptr,
3634				       cur_console->scr_buf +
3635				       (cur_console->xsize*i),
3636				       cur_console->xsize * sizeof(u_short));
3637				ptr += cur_console->xsize;
3638				if (ptr + cur_console->xsize >
3639				    cur_console->history +
3640				    cur_console->history_size)
3641				    ptr = cur_console->history;
3642			    }
3643			    cur_console->status &= ~BUFFER_SAVED;
3644			    cur_console->history_head=cur_console->history_save;
3645			    cur_console->status |= CURSOR_ENABLED;
3646			    mark_all(cur_console);
3647			}
3648			scstart(VIRTUAL_TTY(get_scr_num()));
3649		    }
3650		    else
3651			cur_console->status |= SLKED;
3652		    update_leds(cur_console->status);
3653		}
3654		break;
3655	    case ALK:
3656		if (!alkcnt) {
3657		    alkcnt++;
3658		    if (cur_console->status & ALKED)
3659			cur_console->status &= ~ALKED;
3660		    else
3661			cur_console->status |= ALKED;
3662		    update_leds(cur_console->status);
3663		}
3664		break;
3665
3666	    /* NON-LOCKING KEYS */
3667	    case NOP:
3668		break;
3669	    case SPSC:
3670		/* force activatation/deactivation of the screen saver */
3671		accents = 0;
3672		if (scrn_blanked <= 0) {
3673		    run_scrn_saver = TRUE;
3674		    scrn_time_stamp -= scrn_blank_time;
3675		}
3676#ifdef SC_SPLASH_SCREEN
3677		if (cold) {
3678		    /*
3679		     * While devices are being probed, the screen saver need
3680		     * to be invoked explictly. XXX
3681		     */
3682		    if (scrn_blanked > 0) {
3683			scsplash_stick(FALSE);
3684			stop_scrn_saver(current_saver);
3685		    } else {
3686			if (!ISGRAPHSC(cur_console)) {
3687			    scsplash_stick(TRUE);
3688			    scrn_saver(current_saver, TRUE);
3689			}
3690		    }
3691		}
3692#endif
3693		break;
3694	    case RBT:
3695#ifndef SC_DISABLE_REBOOT
3696		accents = 0;
3697		shutdown_nice();
3698#endif
3699		break;
3700	    case SUSP:
3701#if NAPM > 0
3702		accents = 0;
3703		apm_suspend(PMST_SUSPEND);
3704#endif
3705		break;
3706
3707	    case STBY:
3708#if NAPM > 0
3709		accents = 0;
3710		apm_suspend(PMST_STANDBY);
3711#endif
3712		break;
3713
3714	    case DBG:
3715#ifdef DDB          /* try to switch to console 0 */
3716		accents = 0;
3717		/*
3718		 * TRY to make sure the screen saver is stopped,
3719		 * and the screen is updated before switching to
3720		 * the vty0.
3721		 */
3722		scrn_timer((void *)FALSE);
3723		if (cur_console->smode.mode == VT_AUTO &&
3724		    console[0]->smode.mode == VT_AUTO)
3725		    switch_scr(cur_console, 0);
3726		Debugger("manual escape to debugger");
3727#else
3728		printf("No debugger in kernel\n");
3729#endif
3730		break;
3731	    case LSH:
3732		shfts |= 1;
3733		break;
3734	    case RSH:
3735		shfts |= 2;
3736		break;
3737	    case LCTR:
3738		ctls |= 1;
3739		break;
3740	    case RCTR:
3741		ctls |= 2;
3742		break;
3743	    case LALT:
3744		alts |= 1;
3745		break;
3746	    case RALT:
3747		alts |= 2;
3748		break;
3749	    case ASH:
3750		agrs = 1;
3751		break;
3752	    case META:
3753		metas = 1;
3754		break;
3755	    case NEXT:
3756		{
3757		int next, this = get_scr_num();
3758		accents = 0;
3759		for (next = this+1; next != this; next = (next+1)%MAXCONS) {
3760		    struct tty *tp = VIRTUAL_TTY(next);
3761		    if (tp->t_state & TS_ISOPEN) {
3762			switch_scr(cur_console, next);
3763			break;
3764		    }
3765		}
3766		}
3767		break;
3768	    case BTAB:
3769		accents = 0;
3770		return(BKEY);
3771	    default:
3772		if (action >= F_ACC && action <= L_ACC) {
3773		    /* turn it into an index */
3774		    action -= F_ACC - 1;
3775		    if ((action > accent_map.n_accs)
3776			|| (accent_map.acc[action - 1].accchar == 0)) {
3777			/*
3778			 * The index is out of range or pointing to an
3779			 * empty entry.
3780			 */
3781			accents = 0;
3782			do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3783		    }
3784		    /*
3785		     * If the same accent key has been hit twice,
3786		     * produce the accent char itself.
3787		     */
3788		    if (action == accents) {
3789			action = accent_map.acc[accents - 1].accchar;
3790			accents = 0;
3791			if (metas)
3792			    action |= MKEY;
3793			return (action);
3794		    }
3795		    /* remember the index and wait for the next key stroke */
3796		    accents = action;
3797		    break;
3798		}
3799		if (accents > 0) {
3800		    accents = 0;
3801		    do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3802		}
3803		if (action >= F_SCR && action <= L_SCR) {
3804		    switch_scr(cur_console, action - F_SCR);
3805		    break;
3806		}
3807		if (action >= F_FN && action <= L_FN)
3808		    action |= FKEY;
3809		return(action);
3810	    }
3811	}
3812	else {
3813	    if (accents) {
3814		struct acc_t *acc;
3815		int i;
3816
3817		acc = &accent_map.acc[accents - 1];
3818		accents = 0;
3819		/*
3820		 * If the accent key is followed by the space key,
3821		 * produce the accent char itself.
3822		 */
3823		if (action == ' ') {
3824		    action = acc->accchar;
3825		    if (metas)
3826			action |= MKEY;
3827		    return (action);
3828		}
3829		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
3830		    if (acc->map[i][0] == 0)	/* end of the map entry */
3831			break;
3832		    if (acc->map[i][0] == action) {
3833			action = acc->map[i][1];
3834			if (metas)
3835			    action |= MKEY;
3836			return (action);
3837		    }
3838		}
3839		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3840		goto next_code;
3841	    }
3842	    if (metas)
3843		action |= MKEY;
3844	    return(action);
3845	}
3846    }
3847    goto next_code;
3848}
3849
3850int
3851scmmap(dev_t dev, int offset, int nprot)
3852{
3853    if (offset > 0x20000 - PAGE_SIZE)
3854	return -1;
3855    return i386_btop((VIDEOMEM + offset));
3856}
3857
3858/*
3859 * Calculate hardware attributes word using logical attributes mask and
3860 * hardware colors
3861 */
3862
3863static int
3864mask2attr(struct term_stat *term)
3865{
3866    int attr, mask = term->attr_mask;
3867
3868    if (mask & REVERSE_ATTR) {
3869	attr = ((mask & FOREGROUND_CHANGED) ?
3870		((term->cur_color & 0xF000) >> 4) :
3871		(term->rev_color & 0x0F00)) |
3872	       ((mask & BACKGROUND_CHANGED) ?
3873		((term->cur_color & 0x0F00) << 4) :
3874		(term->rev_color & 0xF000));
3875    } else
3876	attr = term->cur_color;
3877
3878    /* XXX: underline mapping for Hercules adapter can be better */
3879    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3880	attr ^= 0x0800;
3881    if (mask & BLINK_ATTR)
3882	attr ^= 0x8000;
3883
3884    return attr;
3885}
3886
3887static void
3888set_keyboard(int command, int data)
3889{
3890    int s;
3891
3892    if (sc_kbdc == NULL)
3893	return;
3894
3895    /* prevent the timeout routine from polling the keyboard */
3896    if (!kbdc_lock(sc_kbdc, TRUE))
3897	return;
3898
3899    /* disable the keyboard and mouse interrupt */
3900    s = spltty();
3901#if 0
3902    c = get_controller_command_byte(sc_kbdc);
3903    if ((c == -1)
3904	|| !set_controller_command_byte(sc_kbdc,
3905            kbdc_get_device_mask(sc_kbdc),
3906            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
3907                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
3908	/* CONTROLLER ERROR */
3909        kbdc_lock(sc_kbdc, FALSE);
3910	splx(s);
3911	return;
3912    }
3913    /*
3914     * Now that the keyboard controller is told not to generate
3915     * the keyboard and mouse interrupts, call `splx()' to allow
3916     * the other tty interrupts. The clock interrupt may also occur,
3917     * but the timeout routine (`scrn_timer()') will be blocked
3918     * by the lock flag set via `kbdc_lock()'
3919     */
3920    splx(s);
3921#endif
3922
3923    if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
3924        send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
3925
3926#if 0
3927    /* restore the interrupts */
3928    if (!set_controller_command_byte(sc_kbdc,
3929            kbdc_get_device_mask(sc_kbdc),
3930	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
3931	/* CONTROLLER ERROR */
3932    }
3933#else
3934    splx(s);
3935#endif
3936    kbdc_lock(sc_kbdc, FALSE);
3937}
3938
3939static void
3940update_leds(int which)
3941{
3942    static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
3943
3944    /* replace CAPS led with ALTGR led for ALTGR keyboards */
3945    if (key_map.n_keys > ALTGR_OFFSET) {
3946	if (which & ALKED)
3947	    which |= CLKED;
3948	else
3949	    which &= ~CLKED;
3950    }
3951
3952    set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
3953}
3954
3955int
3956set_mode(scr_stat *scp)
3957{
3958    video_info_t info;
3959    video_adapter_t *adp;
3960
3961    /* reject unsupported mode */
3962    if ((*biosvidsw.get_info)(scp->adp, scp->mode, &info))
3963	return 1;
3964
3965    /* if this vty is not currently showing, do nothing */
3966    if (scp != cur_console)
3967	return 0;
3968
3969    /* setup video hardware for the given mode */
3970    adp = get_adapter(scp);
3971    (*biosvidsw.set_mode)(scp->adp, scp->mode);
3972    Crtat = (u_short *)adp->va_window;
3973
3974    if (!(scp->status & GRAPHICS_MODE)) {
3975	/* load appropriate font */
3976	if (!(scp->status & PIXEL_MODE)
3977	    && ISFONTAVAIL(get_adapter(scp)->va_flags)) {
3978	    if (scp->font_size < 14) {
3979		if (fonts_loaded & FONT_8)
3980		    copy_font(scp, LOAD, 8, font_8);
3981	    } else if (scp->font_size >= 16) {
3982		if (fonts_loaded & FONT_16)
3983		    copy_font(scp, LOAD, 16, font_16);
3984	    } else {
3985		if (fonts_loaded & FONT_14)
3986		    copy_font(scp, LOAD, 14, font_14);
3987	    }
3988	    /*
3989	    * FONT KLUDGE:
3990	    * This is an interim kludge to display correct font.
3991	    * Always use the font page #0 on the video plane 2.
3992	    * Somehow we cannot show the font in other font pages on
3993	    * some video cards... XXX
3994	    */
3995	    (*biosvidsw.show_font)(scp->adp, 0);
3996	}
3997	mark_all(scp);
3998    }
3999
4000    if (scp->status & PIXEL_MODE)
4001	generic_bzero((u_char *)(adp->va_window), scp->xpixel*scp->ypixel/8);
4002    set_border(scp, scp->border);
4003
4004    /* move hardware cursor out of the way */
4005    (*biosvidsw.set_hw_cursor)(scp->adp, -1, -1);
4006
4007    return 0;
4008}
4009
4010void
4011set_border(scr_stat *scp, int color)
4012{
4013    u_char *p;
4014    int xoff;
4015    int yoff;
4016    int xlen;
4017    int ylen;
4018    int i;
4019
4020    (*biosvidsw.set_border)(scp->adp, color);
4021
4022    if (scp->status & PIXEL_MODE) {
4023	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4024	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4025	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4026	outw(GDCIDX, 0xff08);		/* bit mask */
4027	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
4028	p = (u_char *)(get_adapter(scp)->va_window);
4029	xoff = scp->xoff;
4030	yoff = scp->yoff*scp->font_size;
4031	xlen = scp->xpixel/8;
4032	ylen = scp->ysize*scp->font_size;
4033	if (yoff > 0) {
4034	    generic_bzero(p, xlen*yoff);
4035	    generic_bzero(p + xlen*(yoff + ylen),
4036			  xlen*scp->ypixel - xlen*(yoff + ylen));
4037	}
4038	if (xoff > 0) {
4039	    for (i = 0; i < ylen; ++i) {
4040		generic_bzero(p + xlen*(yoff + i), xoff);
4041		generic_bzero(p + xlen*(yoff + i) + xoff + scp->xsize,
4042			      xlen - xoff - scp->xsize);
4043	    }
4044	}
4045	outw(GDCIDX, 0x0000);		/* set/reset */
4046	outw(GDCIDX, 0x0001);		/* set/reset enable */
4047    }
4048}
4049
4050void
4051copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
4052{
4053    /*
4054     * FONT KLUDGE:
4055     * This is an interim kludge to display correct font.
4056     * Always use the font page #0 on the video plane 2.
4057     * Somehow we cannot show the font in other font pages on
4058     * some video cards... XXX
4059     */
4060    font_loading_in_progress = TRUE;
4061    if (operation == LOAD) {
4062	(*biosvidsw.load_font)(scp->adp, 0, font_size, buf, 0, 256);
4063	if (sc_flags & CHAR_CURSOR)
4064	    set_destructive_cursor(scp);
4065    } else if (operation == SAVE) {
4066	(*biosvidsw.save_font)(scp->adp, 0, font_size, buf, 0, 256);
4067    }
4068    font_loading_in_progress = FALSE;
4069}
4070
4071void
4072set_destructive_cursor(scr_stat *scp)
4073{
4074    u_char cursor[32];
4075    u_char *font_buffer;
4076    int font_size;
4077    int i;
4078
4079    if (!ISFONTAVAIL(get_adapter(scp)->va_flags) || !ISTEXTSC(scp))
4080	return;
4081
4082    if (scp->font_size < 14) {
4083	font_buffer = font_8;
4084	font_size = 8;
4085    } else if (scp->font_size >= 16) {
4086	font_buffer = font_16;
4087	font_size = 16;
4088    } else {
4089	font_buffer = font_14;
4090	font_size = 14;
4091    }
4092
4093    if (scp->status & MOUSE_VISIBLE) {
4094	if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR)
4095    	    bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4096	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 1)
4097    	    bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4098	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 2)
4099    	    bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4100	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 3)
4101    	    bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4102	else
4103	    bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4104 	       	   cursor, scp->font_size);
4105    }
4106    else
4107    	bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4108 	       cursor, scp->font_size);
4109    for (i=0; i<32; i++)
4110	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4111	    (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4112	    cursor[i] |= 0xff;
4113#if 1
4114    while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4115#endif
4116    font_loading_in_progress = TRUE;
4117    (*biosvidsw.load_font)(scp->adp, 0, font_size, cursor, DEAD_CHAR, 1);
4118    font_loading_in_progress = FALSE;
4119}
4120
4121void
4122sc_move_mouse(scr_stat *scp, int x, int y)
4123{
4124    scp->mouse_xpos = x;
4125    scp->mouse_ypos = y;
4126    scp->mouse_pos = scp->mouse_oldpos =
4127	scp->scr_buf + (y / scp->font_size) * scp->xsize + x / 8;
4128}
4129
4130static void
4131set_mouse_pos(scr_stat *scp)
4132{
4133    static int last_xpos = -1, last_ypos = -1;
4134
4135    if (scp->mouse_xpos < 0)
4136	scp->mouse_xpos = 0;
4137    if (scp->mouse_ypos < 0)
4138	scp->mouse_ypos = 0;
4139    if (!ISTEXTSC(scp)) {
4140        if (scp->mouse_xpos > scp->xpixel-1)
4141	    scp->mouse_xpos = scp->xpixel-1;
4142        if (scp->mouse_ypos > scp->ypixel-1)
4143	    scp->mouse_ypos = scp->ypixel-1;
4144	return;
4145    }
4146    if (scp->mouse_xpos > (scp->xsize*8)-1)
4147	scp->mouse_xpos = (scp->xsize*8)-1;
4148    if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4149	scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4150
4151    if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4152	scp->status |= MOUSE_MOVED;
4153
4154    	scp->mouse_pos = scp->scr_buf +
4155	    ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4156
4157	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4158	    mouse_cut(scp);
4159    }
4160}
4161
4162#define isspace(c)	(((c) & 0xff) == ' ')
4163
4164static int
4165skip_spc_right(scr_stat *scp, u_short *p)
4166{
4167    int i;
4168
4169    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4170	if (!isspace(*p))
4171	    break;
4172	++p;
4173    }
4174    return i;
4175}
4176
4177static int
4178skip_spc_left(scr_stat *scp, u_short *p)
4179{
4180    int i;
4181
4182    for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4183	if (!isspace(*p))
4184	    break;
4185	--p;
4186    }
4187    return i;
4188}
4189
4190static void
4191mouse_cut(scr_stat *scp)
4192{
4193    u_short *end;
4194    u_short *p;
4195    int i = 0;
4196    int j = 0;
4197
4198    scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4199	scp->mouse_pos + 1 : scp->mouse_pos;
4200    end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4201	scp->mouse_cut_start : scp->mouse_cut_end;
4202    for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4203	    scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4204	cut_buffer[i] = *p & 0xff;
4205	/* remember the position of the last non-space char */
4206	if (!isspace(cut_buffer[i++]))
4207	    j = i;
4208	/* trim trailing blank when crossing lines */
4209	if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4210	    cut_buffer[j++] = '\r';
4211	    i = j;
4212	}
4213    }
4214    cut_buffer[i] = '\0';
4215
4216    /* scan towards the end of the last line */
4217    --p;
4218    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4219	if (!isspace(*p))
4220	    break;
4221	++p;
4222    }
4223    /* if there is nothing but blank chars, trim them, but mark towards eol */
4224    if (i >= scp->xsize) {
4225	if (scp->mouse_cut_start > scp->mouse_cut_end)
4226	    scp->mouse_cut_start = p;
4227	else
4228	    scp->mouse_cut_end = p;
4229	cut_buffer[j++] = '\r';
4230	cut_buffer[j] = '\0';
4231    }
4232
4233    mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
4234    mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
4235}
4236
4237static void
4238mouse_cut_start(scr_stat *scp)
4239{
4240    int i;
4241
4242    if (scp->status & MOUSE_VISIBLE) {
4243	if (scp->mouse_pos == scp->mouse_cut_start &&
4244	    scp->mouse_cut_start == scp->mouse_cut_end - 1) {
4245	    cut_buffer[0] = '\0';
4246	    remove_cutmarking(scp);
4247	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
4248	    /* if the pointer is on trailing blank chars, mark towards eol */
4249	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
4250	    scp->mouse_cut_start = scp->scr_buf +
4251	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
4252	    scp->mouse_cut_end = scp->scr_buf +
4253	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
4254	    cut_buffer[0] = '\r';
4255	    cut_buffer[1] = '\0';
4256	    scp->status |= MOUSE_CUTTING;
4257	} else {
4258	    scp->mouse_cut_start = scp->mouse_pos;
4259	    scp->mouse_cut_end = scp->mouse_cut_start + 1;
4260	    cut_buffer[0] = *scp->mouse_cut_start & 0xff;
4261	    cut_buffer[1] = '\0';
4262	    scp->status |= MOUSE_CUTTING;
4263	}
4264    	mark_all(scp);
4265	/* delete all other screens cut markings */
4266	for (i=0; i<MAXCONS; i++) {
4267	    if (console[i] == NULL || console[i] == scp)
4268		continue;
4269	    remove_cutmarking(console[i]);
4270	}
4271    }
4272}
4273
4274static void
4275mouse_cut_end(scr_stat *scp)
4276{
4277    if (scp->status & MOUSE_VISIBLE) {
4278	scp->status &= ~MOUSE_CUTTING;
4279    }
4280}
4281
4282static void
4283mouse_cut_word(scr_stat *scp)
4284{
4285    u_short *p;
4286    u_short *sol;
4287    u_short *eol;
4288    int i;
4289
4290    /*
4291     * Because we don't have locale information in the kernel,
4292     * we only distinguish space char and non-space chars.  Punctuation
4293     * chars, symbols and other regular chars are all treated alike.
4294     */
4295    if (scp->status & MOUSE_VISIBLE) {
4296	sol = scp->scr_buf
4297	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4298	eol = sol + scp->xsize;
4299	if (isspace(*scp->mouse_pos)) {
4300	    for (p = scp->mouse_pos; p >= sol; --p)
4301	        if (!isspace(*p))
4302		    break;
4303	    scp->mouse_cut_start = ++p;
4304	    for (p = scp->mouse_pos; p < eol; ++p)
4305	        if (!isspace(*p))
4306		    break;
4307	    scp->mouse_cut_end = p;
4308	} else {
4309	    for (p = scp->mouse_pos; p >= sol; --p)
4310	        if (isspace(*p))
4311		    break;
4312	    scp->mouse_cut_start = ++p;
4313	    for (p = scp->mouse_pos; p < eol; ++p)
4314	        if (isspace(*p))
4315		    break;
4316	    scp->mouse_cut_end = p;
4317	}
4318	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4319	    cut_buffer[i++] = *p & 0xff;
4320	cut_buffer[i] = '\0';
4321	scp->status |= MOUSE_CUTTING;
4322    }
4323}
4324
4325static void
4326mouse_cut_line(scr_stat *scp)
4327{
4328    u_short *p;
4329    int i;
4330
4331    if (scp->status & MOUSE_VISIBLE) {
4332	scp->mouse_cut_start = scp->scr_buf
4333	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4334	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
4335	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4336	    cut_buffer[i++] = *p & 0xff;
4337	cut_buffer[i++] = '\r';
4338	cut_buffer[i] = '\0';
4339	scp->status |= MOUSE_CUTTING;
4340    }
4341}
4342
4343static void
4344mouse_cut_extend(scr_stat *scp)
4345{
4346    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
4347	&& (scp->mouse_cut_start != NULL)) {
4348	mouse_cut(scp);
4349	scp->status |= MOUSE_CUTTING;
4350    }
4351}
4352
4353static void
4354mouse_paste(scr_stat *scp)
4355{
4356    if (scp->status & MOUSE_VISIBLE) {
4357	struct tty *tp;
4358	u_char *ptr = cut_buffer;
4359
4360	tp = VIRTUAL_TTY(get_scr_num());
4361	while (*ptr)
4362	    (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
4363    }
4364}
4365
4366static void
4367draw_mouse_image(scr_stat *scp)
4368{
4369    u_short buffer[32];
4370    u_short xoffset, yoffset;
4371    u_short *crt_pos = (u_short *)(get_adapter(scp)->va_window)
4372				      + (scp->mouse_pos - scp->scr_buf);
4373    u_char *font_buffer;
4374    int font_size;
4375    int i;
4376
4377    if (scp->font_size < 14) {
4378	font_buffer = font_8;
4379	font_size = 8;
4380    } else if (scp->font_size >= 16) {
4381	font_buffer = font_16;
4382	font_size = 16;
4383    } else {
4384	font_buffer = font_14;
4385	font_size = 14;
4386    }
4387
4388    xoffset = scp->mouse_xpos % 8;
4389    yoffset = scp->mouse_ypos % scp->font_size;
4390
4391    /* prepare mousepointer char's bitmaps */
4392    bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
4393	   &scp->mouse_cursor[0], font_size);
4394    bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
4395	   &scp->mouse_cursor[32], font_size);
4396    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
4397	   &scp->mouse_cursor[64], font_size);
4398    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
4399	   &scp->mouse_cursor[96], font_size);
4400    for (i=0; i<font_size; i++) {
4401	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
4402	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
4403    }
4404
4405    /* now and-or in the mousepointer image */
4406    for (i=0; i<16; i++) {
4407	buffer[i+yoffset] =
4408	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
4409	    | (mouse_or_mask[i] >> xoffset);
4410    }
4411    for (i=0; i<font_size; i++) {
4412	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
4413	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
4414	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
4415	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
4416    }
4417
4418    scp->mouse_oldpos = scp->mouse_pos;
4419
4420#if 1
4421    /* wait for vertical retrace to avoid jitter on some videocards */
4422    while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
4423#endif
4424    font_loading_in_progress = TRUE;
4425    (*biosvidsw.load_font)(scp->adp, 0, 32, scp->mouse_cursor,
4426			   SC_MOUSE_CHAR, 4);
4427    font_loading_in_progress = FALSE;
4428
4429    *(crt_pos) = (*(scp->mouse_pos) & 0xff00) | SC_MOUSE_CHAR;
4430    *(crt_pos+scp->xsize) =
4431	(*(scp->mouse_pos + scp->xsize) & 0xff00) | (SC_MOUSE_CHAR + 2);
4432    if (scp->mouse_xpos < (scp->xsize-1)*8) {
4433    	*(crt_pos + 1) = (*(scp->mouse_pos + 1) & 0xff00) | (SC_MOUSE_CHAR + 1);
4434    	*(crt_pos+scp->xsize + 1) =
4435	    (*(scp->mouse_pos + scp->xsize + 1) & 0xff00) | (SC_MOUSE_CHAR + 3);
4436    }
4437    mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
4438    mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
4439}
4440
4441static void
4442remove_mouse_image(scr_stat *scp)
4443{
4444    u_short *crt_pos;
4445
4446    if (!ISTEXTSC(scp))
4447	return;
4448
4449    crt_pos = (u_short *)(get_adapter(scp)->va_window)
4450			     + (scp->mouse_oldpos - scp->scr_buf);
4451    *(crt_pos) = *(scp->mouse_oldpos);
4452    *(crt_pos+1) = *(scp->mouse_oldpos+1);
4453    *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
4454    *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
4455    mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
4456    mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
4457}
4458
4459static void
4460draw_cutmarking(scr_stat *scp)
4461{
4462    u_short *crt_pos;
4463    u_short *ptr;
4464    u_short och, nch;
4465
4466    crt_pos = (u_short *)(get_adapter(scp)->va_window);
4467    for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
4468	nch = och = *(crt_pos + (ptr - scp->scr_buf));
4469	/* are we outside the selected area ? */
4470	if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
4471	            scp->mouse_cut_end : scp->mouse_cut_start) ||
4472	     ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
4473	            scp->mouse_cut_start : scp->mouse_cut_end)) {
4474	    if (ptr != scp->cursor_pos)
4475		nch = (och & 0xff) | (*ptr & 0xff00);
4476	}
4477	else {
4478	    /* are we clear of the cursor image ? */
4479	    if (ptr != scp->cursor_pos)
4480		nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
4481	    else {
4482		if (sc_flags & CHAR_CURSOR)
4483		    nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
4484		else
4485		    if (!(sc_flags & BLINK_CURSOR))
4486		        nch = (och & 0xff) | (*ptr & 0xff00);
4487	    }
4488	}
4489	if (nch != och)
4490	    *(crt_pos + (ptr - scp->scr_buf)) = nch;
4491    }
4492}
4493
4494static void
4495remove_cutmarking(scr_stat *scp)
4496{
4497    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
4498    scp->status &= ~MOUSE_CUTTING;
4499    mark_all(scp);
4500}
4501
4502static void
4503do_bell(scr_stat *scp, int pitch, int duration)
4504{
4505    if (cold || shutdown_in_progress)
4506	return;
4507
4508    if (scp != cur_console && (sc_flags & QUIET_BELL))
4509	return;
4510
4511    if (sc_flags & VISUAL_BELL) {
4512	if (blink_in_progress)
4513	    return;
4514	blink_in_progress = 4;
4515	if (scp != cur_console)
4516	    blink_in_progress += 2;
4517	blink_screen(cur_console);
4518    } else {
4519	if (scp != cur_console)
4520	    pitch *= 2;
4521	sysbeep(pitch, duration);
4522    }
4523}
4524
4525static void
4526blink_screen(void *arg)
4527{
4528    scr_stat *scp = arg;
4529
4530    if (!ISTEXTSC(scp) || (blink_in_progress <= 1)) {
4531	blink_in_progress = FALSE;
4532    	mark_all(scp);
4533	if (delayed_next_scr)
4534	    switch_scr(scp, delayed_next_scr - 1);
4535    }
4536    else {
4537	if (blink_in_progress & 1)
4538	    fillw(kernel_default.std_color | scr_map[0x20],
4539		  (u_short *)(get_adapter(scp)->va_window),
4540		  scp->xsize * scp->ysize);
4541	else
4542	    fillw(kernel_default.rev_color | scr_map[0x20],
4543		  (u_short *)(get_adapter(scp)->va_window),
4544		  scp->xsize * scp->ysize);
4545	blink_in_progress--;
4546	timeout(blink_screen, scp, hz / 10);
4547    }
4548}
4549
4550void
4551sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark)
4552{
4553    u_char *font;
4554    u_char volatile *d;
4555    u_char *e;
4556    u_char *f;
4557    int font_size;
4558    int line_length;
4559    int xsize;
4560    u_short bg;
4561    int i, j;
4562    u_char c;
4563
4564    if (ISTEXTSC(scp)) {
4565	generic_bcopy(p + from, (u_short *)(get_adapter(scp)->va_window) + from,
4566		      (to - from + 1)*sizeof(u_short));
4567    } else /* if ISPIXELSC(scp) */ {
4568	if (mark)
4569	    mark = 255;
4570	font_size = scp->font_size;
4571	if (font_size < 14)
4572	    font = font_8;
4573	else if (font_size >= 16)
4574	    font = font_16;
4575	else
4576	    font = font_14;
4577	line_length = scp->xpixel/8;
4578	xsize = scp->xsize;
4579	d = (u_char *)(get_adapter(scp)->va_window)
4580	    + scp->xoff + scp->yoff*font_size*line_length
4581	    + (from%xsize) + font_size*line_length*(from/xsize);
4582
4583	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4584	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4585	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4586	bg = -1;
4587	for (i = from ; i <= to ; i++) {
4588	    /* set background color in EGA/VGA latch */
4589	    if (bg != (p[i] & 0xf000)) {
4590		bg = (p[i] & 0xf000);
4591		outw(GDCIDX, (bg >> 4) | 0x00); /* set/reset */
4592		outw(GDCIDX, 0xff08);		/* bit mask */
4593		*d = 0;
4594		c = *d;		/* set the background color in the latch */
4595	    }
4596	    /* foreground color */
4597	    outw(GDCIDX, (p[i] & 0x0f00) | 0x00); /* set/reset */
4598	    e = (u_char *)d;
4599	    f = &font[(p[i] & 0x00ff)*font_size];
4600	    for (j = 0 ; j < font_size; j++, f++) {
4601		outw(GDCIDX, ((*f^mark) << 8) | 0x08);	/* bit mask */
4602	        *e = 0;
4603		e += line_length;
4604	    }
4605	    d++;
4606	    if ((i % xsize) == xsize - 1)
4607		d += scp->xoff*2 + (font_size - 1)*line_length;
4608	}
4609	outw(GDCIDX, 0x0000);		/* set/reset */
4610	outw(GDCIDX, 0x0001);		/* set/reset enable */
4611	outw(GDCIDX, 0xff08);		/* bit mask */
4612
4613#if 0	/* VGA only */
4614	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
4615	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4616	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4617	outw(GDCIDX, 0xff08);		/* bit mask */
4618	bg = -1;
4619	for (i = from ; i <= to ; i++) {
4620	    /* set background color in EGA/VGA latch */
4621	    if (bg != (p[i] & 0xf000)) {
4622		bg = (p[i] & 0xf000);
4623		outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
4624		outw(GDCIDX, (bg >> 4) | 0x00); /* set/reset */
4625		*d = 0;
4626		c = *d;		/* set the background color in the latch */
4627		outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
4628	    }
4629	    /* foreground color */
4630	    outw(GDCIDX, (p[i] & 0x0f00) | 0x00); /* set/reset */
4631	    e = (u_char *)d;
4632	    f = &font[(p[i] & 0x00ff)*font_size];
4633	    for (j = 0 ; j < font_size; j++, f++) {
4634	        *e = *f^mark;
4635		e += line_length;
4636	    }
4637	    d++;
4638	    if ((i % xsize) == xsize - 1)
4639		d += scp->xoff*2 + (font_size - 1)*line_length;
4640	}
4641	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4642	outw(GDCIDX, 0x0000);		/* set/reset */
4643	outw(GDCIDX, 0x0001);		/* set/reset enable */
4644#endif /* 0 */
4645    }
4646}
4647
4648#ifdef SC_SPLASH_SCREEN
4649
4650static void
4651scsplash_init(scr_stat *scp)
4652{
4653    video_info_t info;
4654
4655    if (scsplash_load(scp) == 0 && add_scrn_saver(scsplash_saver) == 0) {
4656	default_saver = scsplash_saver;
4657	scrn_blank_time = DEFAULT_BLANKTIME;
4658	run_scrn_saver = TRUE;
4659	if (!(boothowto & (RB_VERBOSE | RB_CONFIG))) {
4660	    scsplash_stick(TRUE);
4661	    scsplash_saver(TRUE);
4662	}
4663    }
4664}
4665
4666static void
4667scsplash_term(scr_stat *scp)
4668{
4669    default_saver = none_saver;
4670    scsplash_stick(FALSE);
4671    remove_scrn_saver(scsplash_saver);
4672    scsplash_unload(scp);
4673}
4674
4675static void
4676scsplash_saver(int show)
4677{
4678    if (show)
4679	scsplash(TRUE);
4680    else if (!sticky_splash)
4681	scsplash(FALSE);
4682}
4683
4684#endif /* SC_SPLASH_SCREEN */
4685
4686#endif /* NSC */
4687