syscons.c revision 42373
1262182Semaste/*-
2262182Semaste * Copyright (c) 1992-1998 S�ren Schmidt
3353358Sdim * All rights reserved.
4353358Sdim *
5353358Sdim * Redistribution and use in source and binary forms, with or without
6262182Semaste * modification, are permitted provided that the following conditions
7262182Semaste * are met:
8262182Semaste * 1. Redistributions of source code must retain the above copyright
9280031Sdim *    notice, this list of conditions and the following disclaimer,
10280031Sdim *    without modification, immediately at the beginning of the file.
11280031Sdim * 2. Redistributions in binary form must reproduce the above copyright
12262182Semaste *    notice, this list of conditions and the following disclaimer in the
13314564Sdim *    documentation and/or other materials provided with the distribution.
14314564Sdim * 3. The name of the author may not be used to endorse or promote products
15344779Sdim *    derived from this software without specific prior written permission.
16262182Semaste *
17360784Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18321369Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19288943Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20314564Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21321369Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22321369Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23321369Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24321369Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25262182Semaste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26321369Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27321369Sdim *
28321369Sdim *	$Id: syscons.c,v 1.288 1998/12/07 21:58:23 archie Exp $
29262182Semaste */
30280031Sdim
31262182Semaste#include "sc.h"
32288943Sdim#include "apm.h"
33288943Sdim#include "opt_ddb.h"
34288943Sdim#include "opt_devfs.h"
35288943Sdim#include "opt_vesa.h"
36288943Sdim#include "opt_vm86.h"
37341825Sdim#include "opt_syscons.h"
38341825Sdim
39288943Sdim#if NSC > 0
40288943Sdim#include <sys/param.h>
41314564Sdim#include <sys/systm.h>
42288943Sdim#include <sys/reboot.h>
43288943Sdim#include <sys/conf.h>
44288943Sdim#include <sys/proc.h>
45288943Sdim#include <sys/signalvar.h>
46314564Sdim#include <sys/tty.h>
47341825Sdim#include <sys/kernel.h>
48341825Sdim#include <sys/malloc.h>
49341825Sdim#ifdef	DEVFS
50341825Sdim#include <sys/devfsext.h>
51280031Sdim#endif
52280031Sdim
53280031Sdim#include <machine/bootinfo.h>
54280031Sdim#include <machine/clock.h>
55280031Sdim#include <machine/cons.h>
56280031Sdim#include <machine/console.h>
57280031Sdim#include <machine/mouse.h>
58280031Sdim#include <machine/md_var.h>
59280031Sdim#include <machine/psl.h>
60280031Sdim#include <machine/frame.h>
61280031Sdim#include <machine/pc/display.h>
62280031Sdim#include <machine/pc/vesa.h>
63280031Sdim#include <machine/apm_bios.h>
64280031Sdim#include <machine/random.h>
65280031Sdim
66280031Sdim#include <vm/vm.h>
67280031Sdim#include <vm/vm_param.h>
68280031Sdim#include <vm/pmap.h>
69280031Sdim
70280031Sdim#include <i386/isa/isa.h>
71314564Sdim#include <i386/isa/isa_device.h>
72341825Sdim#include <i386/isa/timerreg.h>
73280031Sdim#include <i386/isa/kbdtables.h>
74280031Sdim#include <i386/isa/kbdio.h>
75280031Sdim#include <i386/isa/videoio.h>
76280031Sdim#include <i386/isa/syscons.h>
77280031Sdim
78280031Sdim#if !defined(MAXCONS)
79280031Sdim#define MAXCONS 16
80280031Sdim#endif
81280031Sdim
82280031Sdim#if !defined(SC_MAX_HISTORY_SIZE)
83280031Sdim#define SC_MAX_HISTORY_SIZE	(1000 * MAXCONS)
84314564Sdim#endif
85314564Sdim
86280031Sdim#if !defined(SC_HISTORY_SIZE)
87280031Sdim#define SC_HISTORY_SIZE		(ROW * 4)
88314564Sdim#endif
89280031Sdim
90280031Sdim#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
91280031Sdim#undef SC_MAX_HISTORY_SIZE
92314564Sdim#define SC_MAX_HISTORY_SIZE	(SC_HISTORY_SIZE * MAXCONS)
93314564Sdim#endif
94314564Sdim
95314564Sdim#if !defined(SC_MOUSE_CHAR)
96314564Sdim#define SC_MOUSE_CHAR		(0xd0)
97314564Sdim#endif
98280031Sdim
99280031Sdim#define COLD 0
100360784Sdim#define WARM 1
101360784Sdim
102360784Sdim#define DEFAULT_BLANKTIME	(5*60)		/* 5 minutes */
103360784Sdim#define MAX_BLANKTIME		(7*24*60*60)	/* 7 days!? */
104360784Sdim
105360784Sdim/* for backward compatibility */
106360784Sdim#define OLD_CONS_MOUSECTL	_IOWR('c', 10, old_mouse_info_t)
107360784Sdim
108360784Sdimtypedef struct old_mouse_data {
109360784Sdim    int x;
110360784Sdim    int y;
111360784Sdim    int buttons;
112360784Sdim} old_mouse_data_t;
113360784Sdim
114360784Sdimtypedef struct old_mouse_info {
115360784Sdim    int operation;
116360784Sdim    union {
117360784Sdim	struct old_mouse_data data;
118360784Sdim	struct mouse_mode mode;
119360784Sdim    } u;
120360784Sdim} old_mouse_info_t;
121360784Sdim
122360784Sdim/* XXX use sc_bcopy where video memory is concerned */
123360784Sdimextern void generic_bcopy(const void *, void *, size_t);
124360784Sdimextern void generic_bzero(void *, size_t);
125360784Sdim
126360784Sdimstatic default_attr user_default = {
127314564Sdim    (FG_LIGHTGREY | BG_BLACK) << 8,
128314564Sdim    (FG_BLACK | BG_LIGHTGREY) << 8
129314564Sdim};
130314564Sdim
131314564Sdimstatic default_attr kernel_default = {
132314564Sdim    (FG_WHITE | BG_BLACK) << 8,
133280031Sdim    (FG_BLACK | BG_LIGHTGREY) << 8
134280031Sdim};
135314564Sdim
136314564Sdimstatic  scr_stat    	main_console;
137314564Sdimstatic  scr_stat    	*console[MAXCONS];
138314564Sdim#ifdef DEVFS
139314564Sdimstatic	void		*sc_devfs_token[MAXCONS];
140314564Sdimstatic	void		*sc_mouse_devfs_token;
141314564Sdimstatic	void		*sc_console_devfs_token;
142314564Sdim#endif
143280031Sdim	scr_stat    	*cur_console;
144314564Sdimstatic  scr_stat    	*new_scp, *old_scp;
145314564Sdimstatic  term_stat   	kernel_console;
146314564Sdimstatic  default_attr    *current_default;
147314564Sdimstatic  int		sc_flags;
148280031Sdimstatic  int		sc_port = IO_KBD;
149280031Sdimstatic  KBDC		sc_kbdc = NULL;
150314564Sdimstatic  char        	init_done = COLD;
151314564Sdimstatic  u_short		sc_buffer[ROW*COL];
152314564Sdimstatic  char		shutdown_in_progress = FALSE;
153314564Sdimstatic  char        	font_loading_in_progress = FALSE;
154314564Sdimstatic  char        	switch_in_progress = FALSE;
155314564Sdimstatic  char        	write_in_progress = FALSE;
156314564Sdimstatic  char        	blink_in_progress = FALSE;
157280031Sdimstatic  int        	blinkrate = 0;
158280031Sdim	u_int       	crtc_addr = MONO_BASE;
159314564Sdim	char		crtc_type = KD_MONO;
160314564Sdimstatic	char        	crtc_vga = FALSE;
161314564Sdimstatic	int		adp_flags;
162314564Sdimstatic  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
163314564Sdimstatic  u_char		accents = 0;
164314564Sdimstatic  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
165314564Sdimstatic  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
166314564Sdimstatic  int     	delayed_next_scr = FALSE;
167280031Sdimstatic  long        	scrn_blank_time = 0;    /* screen saver timeout value */
168280031Sdim	int     	scrn_blanked = 0;       /* screen saver active flag */
169314564Sdimstatic  long		scrn_time_stamp;
170314564Sdimstatic	int		saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
171314564Sdimstatic	int		run_scrn_saver = FALSE;	/* should run the saver? */
172314564Sdimstatic	int		scrn_idle = FALSE;	/* about to run the saver */
173341825Sdim	u_char      	scr_map[256];
174341825Sdim	u_char      	scr_rmap[256];
175314564Sdimstatic	int		initial_video_mode;	/* initial video mode # */
176314564Sdimstatic	int		bios_video_mode;	/* video mode # set by BIOS */
177314564Sdim	int     	fonts_loaded = 0
178314564Sdim#ifdef STD8X16FONT
179314564Sdim	| FONT_16
180280031Sdim#endif
181280031Sdim	;
182314564Sdim
183314564Sdim	u_char		font_8[256*8];
184314564Sdim	u_char		font_14[256*14];
185280031Sdim#ifdef STD8X16FONT
186341825Sdimextern
187341825Sdim#endif
188280031Sdim	u_char		font_16[256*16];
189314564Sdim	u_char        	palette[256*3];
190314564Sdimstatic	u_char 		*cut_buffer;
191341825Sdimstatic	int		cut_buffer_size;
192341825Sdimstatic	int		mouse_level;		/* sysmouse protocol level */
193314564Sdimstatic	mousestatus_t	mouse_status = { 0, 0, 0, 0, 0, 0 };
194353358Sdimstatic  u_short 	mouse_and_mask[16] = {
195314564Sdim				0xc000, 0xe000, 0xf000, 0xf800,
196314564Sdim				0xfc00, 0xfe00, 0xff00, 0xff80,
197314564Sdim				0xfe00, 0x1e00, 0x1f00, 0x0f00,
198314564Sdim				0x0f00, 0x0000, 0x0000, 0x0000
199314564Sdim			};
200314564Sdimstatic  u_short 	mouse_or_mask[16] = {
201314564Sdim				0x0000, 0x4000, 0x6000, 0x7000,
202353358Sdim				0x7800, 0x7c00, 0x7e00, 0x6800,
203314564Sdim				0x0c00, 0x0c00, 0x0600, 0x0600,
204353358Sdim				0x0000, 0x0000, 0x0000, 0x0000
205353358Sdim			};
206353358Sdim
207353358Sdim	int		sc_history_size = SC_HISTORY_SIZE;
208353358Sdimstatic	int		extra_history_size =
209353358Sdim			    SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
210353358Sdim
211353358Sdimstatic void    		none_saver(int blank) { }
212353358Sdimstatic void    		(*current_saver)(int blank) = none_saver;
213353358Sdimstatic void    		(*default_saver)(int blank) = none_saver;
214353358Sdim       d_ioctl_t  	*sc_user_ioctl;
215353358Sdim
216353358Sdimstatic int		sticky_splash = FALSE;
217353358Sdim
218314564Sdim/* OS specific stuff */
219280031Sdim#ifdef not_yet_done
220353358Sdim#define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
221314564Sdimstruct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
222353358Sdimstruct  MOUSE_TTY 	(sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
223353358Sdimstruct  tty         	*sccons[MAXCONS+2];
224314564Sdim#else
225314564Sdim#define VIRTUAL_TTY(x)  &sccons[x]
226314564Sdim#define CONSOLE_TTY 	&sccons[MAXCONS]
227314564Sdim#define MOUSE_TTY 	&sccons[MAXCONS+1]
228314564Sdimstatic struct tty     	sccons[MAXCONS+2];
229314564Sdim#endif
230314564Sdim#define SC_MOUSE 	128
231314564Sdim#define SC_CONSOLE	255
232314564Sdimu_short         	*Crtat;
233353358Sdimstatic const int	nsccons = MAXCONS+2;
234314564Sdim
235314564Sdim#define WRAPHIST(scp, pointer, offset)\
236314564Sdim    ((scp)->history + ((((pointer) - (scp)->history) + (scp)->history_size \
237314564Sdim    + (offset)) % (scp)->history_size))
238314564Sdim#define ISSIGVALID(sig)	((sig) > 0 && (sig) < NSIG)
239314564Sdim
240314564Sdim/* prototypes */
241314564Sdimstatic int scattach(struct isa_device *dev);
242314564Sdimstatic ointhand2_t scintr;
243314564Sdimstatic int scparam(struct tty *tp, struct termios *t);
244314564Sdimstatic int scprobe(struct isa_device *dev);
245314564Sdimstatic int scvidprobe(int unit, int flags);
246314564Sdimstatic int sckbdprobe(int unit, int flags);
247314564Sdimstatic void scstart(struct tty *tp);
248314564Sdimstatic void scmousestart(struct tty *tp);
249314564Sdimstatic void scinit(void);
250314564Sdimstatic void scshutdown(int howto, void *arg);
251314564Sdimstatic u_int scgetc(u_int flags);
252314564Sdim#define SCGETC_CN	1
253314564Sdim#define SCGETC_NONBLOCK	2
254314564Sdimstatic void sccnupdate(scr_stat *scp);
255353358Sdimstatic scr_stat *alloc_scp(void);
256314564Sdimstatic void init_scp(scr_stat *scp);
257314564Sdimstatic void sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark);
258314564Sdimstatic int get_scr_num(void);
259314564Sdimstatic timeout_t scrn_timer;
260314564Sdimstatic void scrn_update(scr_stat *scp, int show_cursor);
261314564Sdimstatic void scrn_saver(void (*saver)(int), int blank);
262314564Sdimstatic void stop_scrn_saver(void (*saver)(int));
263314564Sdimstatic int wait_scrn_saver_stop(void);
264314564Sdimstatic int switch_scr(scr_stat *scp, u_int next_scr);
265314564Sdimstatic void exchange_scr(void);
266314564Sdimstatic void scan_esc(scr_stat *scp, u_char c);
267314564Sdimstatic void ansi_put(scr_stat *scp, u_char *buf, int len);
268314564Sdimstatic void draw_cursor_image(scr_stat *scp);
269314564Sdimstatic void remove_cursor_image(scr_stat *scp);
270314564Sdimstatic void move_crsr(scr_stat *scp, int x, int y);
271314564Sdimstatic u_char *get_fstr(u_int c, u_int *len);
272314564Sdimstatic void history_to_screen(scr_stat *scp);
273314564Sdimstatic int history_up_line(scr_stat *scp);
274314564Sdimstatic int history_down_line(scr_stat *scp);
275314564Sdimstatic int mask2attr(struct term_stat *term);
276314564Sdimstatic void set_keyboard(int command, int data);
277314564Sdimstatic void update_leds(int which);
278314564Sdimstatic void set_destructive_cursor(scr_stat *scp);
279314564Sdimstatic void set_mouse_pos(scr_stat *scp);
280314564Sdimstatic int skip_spc_right(scr_stat *scp, u_short *p);
281314564Sdimstatic int skip_spc_left(scr_stat *scp, u_short *p);
282314564Sdimstatic void mouse_cut(scr_stat *scp);
283314564Sdimstatic void mouse_cut_start(scr_stat *scp);
284314564Sdimstatic void mouse_cut_end(scr_stat *scp);
285314564Sdimstatic void mouse_cut_word(scr_stat *scp);
286314564Sdimstatic void mouse_cut_line(scr_stat *scp);
287314564Sdimstatic void mouse_cut_extend(scr_stat *scp);
288314564Sdimstatic void mouse_paste(scr_stat *scp);
289314564Sdimstatic void draw_mouse_image(scr_stat *scp);
290314564Sdimstatic void remove_mouse_image(scr_stat *scp);
291314564Sdimstatic void draw_cutmarking(scr_stat *scp);
292314564Sdimstatic void remove_cutmarking(scr_stat *scp);
293276479Sdimstatic void do_bell(scr_stat *scp, int pitch, int duration);
294314564Sdimstatic timeout_t blink_screen;
295276479Sdim#ifdef SC_SPLASH_SCREEN
296280031Sdimstatic void scsplash_init(scr_stat *scp);
297276479Sdimstatic void scsplash_term(scr_stat *scp);
298314564Sdimstatic void scsplash_saver(int show);
299314564Sdim#define scsplash_stick(stick)		(sticky_splash = (stick))
300314564Sdim#else
301314564Sdim#define scsplash_stick(stick)
302314564Sdim#endif
303314564Sdim
304280031Sdimstatic cn_probe_t	sccnprobe;
305262182Semastestatic cn_init_t	sccninit;
306314564Sdimstatic cn_getc_t	sccngetc;
307314564Sdimstatic cn_checkc_t	sccncheckc;
308314564Sdimstatic cn_putc_t	sccnputc;
309314564Sdim
310314564SdimCONS_DRIVER(sc, sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc);
311314564Sdim
312314564Sdimstruct  isa_driver scdriver = {
313314564Sdim    scprobe, scattach, "sc", 1
314314564Sdim};
315314564Sdim
316314564Sdimstatic	d_open_t	scopen;
317314564Sdimstatic	d_close_t	scclose;
318314564Sdimstatic	d_read_t	scread;
319280031Sdimstatic	d_write_t	scwrite;
320314564Sdimstatic	d_ioctl_t	scioctl;
321314564Sdimstatic	d_mmap_t	scmmap;
322262182Semaste
323314564Sdim#define	CDEV_MAJOR	12
324262182Semastestatic	struct cdevsw	sc_cdevsw = {
325314564Sdim	scopen,		scclose,	scread,		scwrite,
326314564Sdim	scioctl,	nullstop,	noreset,	scdevtotty,
327314564Sdim	ttpoll,		scmmap,		nostrategy,	"sc",
328314564Sdim	NULL,		-1,		nodump,		nopsize,
329314564Sdim	D_TTY,
330314564Sdim};
331314564Sdim
332314564Sdimstatic void
333280031Sdimdraw_cursor_image(scr_stat *scp)
334262182Semaste{
335314564Sdim    u_short cursor_image;
336314564Sdim    u_short *ptr;
337314564Sdim    u_short prev_image;
338280031Sdim
339262182Semaste    if (ISPIXELSC(scp)) {
340314564Sdim	sc_bcopy(scp, scp->scr_buf, scp->cursor_pos - scp->scr_buf,
341280031Sdim	  scp->cursor_pos - scp->scr_buf, 1);
342314564Sdim	return;
343314564Sdim    }
344314564Sdim
345314564Sdim    ptr = (u_short *)(get_adapter(scp)->va_window)
346280031Sdim			 + (scp->cursor_pos - scp->scr_buf);
347262182Semaste
348314564Sdim    /* do we have a destructive cursor ? */
349314564Sdim    if (sc_flags & CHAR_CURSOR) {
350314564Sdim	prev_image = scp->cursor_saveunder;
351314564Sdim	cursor_image = *ptr & 0x00ff;
352314564Sdim	if (cursor_image == DEAD_CHAR)
353314564Sdim	    cursor_image = prev_image & 0x00ff;
354314564Sdim	cursor_image |= *(scp->cursor_pos) & 0xff00;
355314564Sdim	scp->cursor_saveunder = cursor_image;
356280031Sdim	/* update the cursor bitmap if the char under the cursor has changed */
357280031Sdim	if (prev_image != cursor_image)
358314564Sdim	    set_destructive_cursor(scp);
359314564Sdim	/* modify cursor_image */
360314564Sdim	if (!(sc_flags & BLINK_CURSOR)||((sc_flags & BLINK_CURSOR)&&(blinkrate & 4))){
361314564Sdim	    /*
362314564Sdim	     * When the mouse pointer is at the same position as the cursor,
363314564Sdim	     * the cursor bitmap needs to be updated even if the char under
364314564Sdim	     * the cursor hasn't changed, because the mouse pionter may
365276479Sdim	     * have moved by a few dots within the cursor cel.
366314564Sdim	     */
367314564Sdim	    if ((prev_image == cursor_image)
368314564Sdim		    && (cursor_image != *(scp->cursor_pos)))
369314564Sdim	        set_destructive_cursor(scp);
370314564Sdim	    cursor_image &= 0xff00;
371314564Sdim	    cursor_image |= DEAD_CHAR;
372314564Sdim	}
373314564Sdim    } else {
374276479Sdim	cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
375314564Sdim	scp->cursor_saveunder = cursor_image;
376314564Sdim	if (!(sc_flags & BLINK_CURSOR)||((sc_flags & BLINK_CURSOR)&&(blinkrate & 4))){
377262182Semaste	    if ((cursor_image & 0x7000) == 0x7000) {
378262182Semaste		cursor_image &= 0x8fff;
379314564Sdim		if(!(cursor_image & 0x0700))
380314564Sdim		    cursor_image |= 0x0700;
381314564Sdim	    } else {
382314564Sdim		cursor_image |= 0x7000;
383314564Sdim		if ((cursor_image & 0x0700) == 0x0700)
384314564Sdim		    cursor_image &= 0xf0ff;
385314564Sdim	    }
386314564Sdim	}
387314564Sdim    }
388314564Sdim    *ptr = cursor_image;
389314564Sdim}
390314564Sdim
391314564Sdimstatic void
392314564Sdimremove_cursor_image(scr_stat *scp)
393314564Sdim{
394314564Sdim    if (ISPIXELSC(scp))
395314564Sdim	sc_bcopy(scp, scp->scr_buf, scp->cursor_oldpos - scp->scr_buf,
396314564Sdim		 scp->cursor_oldpos - scp->scr_buf, 0);
397314564Sdim    else
398314564Sdim	*((u_short *)(get_adapter(scp)->va_window)
399321369Sdim			 + (scp->cursor_oldpos - scp->scr_buf))
400314564Sdim	    = scp->cursor_saveunder;
401314564Sdim}
402314564Sdim
403314564Sdimstatic void
404314564Sdimmove_crsr(scr_stat *scp, int x, int y)
405314564Sdim{
406280031Sdim    if (x < 0)
407262182Semaste	x = 0;
408314564Sdim    if (y < 0)
409314564Sdim	y = 0;
410314564Sdim    if (x >= scp->xsize)
411314564Sdim	x = scp->xsize-1;
412314564Sdim    if (y >= scp->ysize)
413280031Sdim	y = scp->ysize-1;
414314564Sdim    scp->xpos = x;
415314564Sdim    scp->ypos = y;
416314564Sdim    scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
417314564Sdim}
418314564Sdim
419314564Sdimstatic int
420314564Sdimscprobe(struct isa_device *dev)
421314564Sdim{
422314564Sdim    if (!scvidprobe(dev->id_unit, dev->id_flags)) {
423262182Semaste	if (bootverbose)
424262182Semaste	    printf("sc%d: no video adapter is found.\n", dev->id_unit);
425314564Sdim	return (0);
426314564Sdim    }
427314564Sdim
428314564Sdim#if defined(VESA) && defined(VM86)
429314564Sdim    if (vesa_load())
430262182Semaste	return FALSE;
431262182Semaste#endif
432314564Sdim
433314564Sdim    (*biosvidsw.diag)(bootverbose);
434314564Sdim
435314564Sdim    sc_port = dev->id_iobase;
436314564Sdim    if (sckbdprobe(dev->id_unit, dev->id_flags))
437314564Sdim	return (IO_KBDSIZE);
438314564Sdim    else
439314564Sdim        return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
440314564Sdim}
441314564Sdim
442314564Sdim/* probe video adapters, return TRUE if found */
443280031Sdimstatic int
444314564Sdimscvidprobe(int unit, int flags)
445280031Sdim{
446314564Sdim    video_adapter_t *adp;
447280031Sdim
448314564Sdim    /* do this test only once */
449314564Sdim    if (init_done != COLD)
450314564Sdim	return (crtc_type != -1);
451262182Semaste
452262182Semaste    if ((*biosvidsw.init)() <= 0)
453360784Sdim	return FALSE;
454360784Sdim    if ((adp = (*biosvidsw.adapter)(V_ADP_PRIMARY)) == NULL)
455314564Sdim	return FALSE;
456314564Sdim
457314564Sdim    crtc_type = adp->va_type;
458314564Sdim    crtc_vga = (crtc_type == KD_VGA);
459314564Sdim    crtc_addr = adp->va_crtc_addr;
460314564Sdim    Crtat = (u_short *)adp->va_window;
461314564Sdim    adp_flags = adp->va_flags;
462314564Sdim    initial_video_mode = adp->va_initial_mode;
463314564Sdim    bios_video_mode = adp->va_initial_bios_mode;
464360784Sdim
465360784Sdim    return TRUE;
466314564Sdim}
467360784Sdim
468360784Sdim/* probe the keyboard, return TRUE if found */
469360784Sdimstatic int
470360784Sdimsckbdprobe(int unit, int flags)
471360784Sdim{
472360784Sdim    int codeset;
473360784Sdim    int c = -1;
474360784Sdim    int m;
475360784Sdim    int res, id;
476360784Sdim
477360784Sdim    sc_kbdc = kbdc_open(sc_port);
478360784Sdim
479360784Sdim    if (!kbdc_lock(sc_kbdc, TRUE)) {
480360784Sdim	/* driver error? */
481360784Sdim	printf("sc%d: unable to lock the controller.\n", unit);
482314564Sdim        return ((flags & DETECT_KBD) ? FALSE : TRUE);
483360784Sdim    }
484360784Sdim
485360784Sdim    /* flush any noise in the buffer */
486360784Sdim    empty_both_buffers(sc_kbdc, 10);
487280031Sdim
488360784Sdim    /* save the current keyboard controller command byte */
489360784Sdim    m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
490360784Sdim    c = get_controller_command_byte(sc_kbdc);
491360784Sdim    if (c == -1) {
492360784Sdim	/* CONTROLLER ERROR */
493360784Sdim	printf("sc%d: unable to get the current command byte value.\n", unit);
494360784Sdim	goto fail;
495360784Sdim    }
496280031Sdim    if (bootverbose)
497314564Sdim	printf("sc%d: the current keyboard controller command byte %04x\n",
498280031Sdim	    unit, c);
499314564Sdim#if 0
500314564Sdim    /* override the keyboard lock switch */
501314564Sdim    c |= KBD_OVERRIDE_KBD_LOCK;
502280031Sdim#endif
503314564Sdim
504314564Sdim    /*
505314564Sdim     * The keyboard may have been screwed up by the boot block.
506314564Sdim     * We may just be able to recover from error by testing the controller
507314564Sdim     * and the keyboard port. The controller command byte needs to be saved
508314564Sdim     * before this recovery operation, as some controllers seem to set
509341825Sdim     * the command byte to particular values.
510360784Sdim     */
511360784Sdim    test_controller(sc_kbdc);
512360784Sdim    test_kbd_port(sc_kbdc);
513360784Sdim
514360784Sdim    /* enable the keyboard port, but disable the keyboard intr. */
515360784Sdim    if (!set_controller_command_byte(sc_kbdc,
516360784Sdim            KBD_KBD_CONTROL_BITS,
517360784Sdim            KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
518360784Sdim	/* CONTROLLER ERROR
519360784Sdim	 * there is very little we can do...
520360784Sdim	 */
521314564Sdim	printf("sc%d: unable to set the command byte.\n", unit);
522314564Sdim	goto fail;
523262182Semaste     }
524262182Semaste
525321369Sdim     /*
526314564Sdim      * Check if we have an XT keyboard before we attempt to reset it.
527314564Sdim      * The procedure assumes that the keyboard and the controller have
528314564Sdim      * been set up properly by BIOS and have not been messed up
529314564Sdim      * during the boot process.
530314564Sdim      */
531314564Sdim     codeset = -1;
532314564Sdim     if (flags & XT_KEYBD)
533314564Sdim	 /* the user says there is a XT keyboard */
534314564Sdim	 codeset = 1;
535314564Sdim#ifdef DETECT_XT_KEYBOARD
536314564Sdim     else if ((c & KBD_TRANSLATION) == 0) {
537314564Sdim	 /* SET_SCANCODE_SET is not always supported; ignore error */
538314564Sdim	 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
539314564Sdim		 == KBD_ACK)
540314564Sdim	     codeset = read_kbd_data(sc_kbdc);
541341825Sdim     }
542341825Sdim     if (bootverbose)
543314564Sdim         printf("sc%d: keyboard scancode set %d\n", unit, codeset);
544314564Sdim#endif /* DETECT_XT_KEYBOARD */
545314564Sdim
546314564Sdim    if (flags & KBD_NORESET) {
547314564Sdim        write_kbd_command(sc_kbdc, KBDC_ECHO);
548314564Sdim        if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
549314564Sdim            empty_both_buffers(sc_kbdc, 10);
550314564Sdim            test_controller(sc_kbdc);
551262182Semaste            test_kbd_port(sc_kbdc);
552314564Sdim            if (bootverbose)
553314564Sdim                printf("sc%d: failed to get response from the keyboard.\n",
554314564Sdim		    unit);
555314564Sdim	    goto fail;
556314564Sdim	}
557314564Sdim    } else {
558314564Sdim        /* reset keyboard hardware */
559314564Sdim        if (!reset_kbd(sc_kbdc)) {
560314564Sdim            /* KEYBOARD ERROR
561341825Sdim             * Keyboard reset may fail either because the keyboard doen't
562341825Sdim             * exist, or because the keyboard doesn't pass the self-test,
563341825Sdim             * or the keyboard controller on the motherboard and the keyboard
564341825Sdim             * somehow fail to shake hands. It is just possible, particularly
565314564Sdim             * in the last case, that the keyoard controller may be left
566353358Sdim             * in a hung state. test_controller() and test_kbd_port() appear
567353358Sdim             * to bring the keyboard controller back (I don't know why and
568314564Sdim             * how, though.)
569314564Sdim             */
570314564Sdim            empty_both_buffers(sc_kbdc, 10);
571353358Sdim            test_controller(sc_kbdc);
572353358Sdim            test_kbd_port(sc_kbdc);
573314564Sdim            /* We could disable the keyboard port and interrupt... but,
574314564Sdim             * the keyboard may still exist (see above).
575280031Sdim             */
576288943Sdim            if (bootverbose)
577314564Sdim                printf("sc%d: failed to reset the keyboard.\n", unit);
578314564Sdim            goto fail;
579314564Sdim        }
580314564Sdim    }
581314564Sdim
582314564Sdim    /*
583314564Sdim     * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
584288943Sdim     * such as those on the IBM ThinkPad laptop computers can be used
585314564Sdim     * with the standard console driver.
586344779Sdim     */
587288943Sdim    if (codeset == 1) {
588314564Sdim	if (send_kbd_command_and_data(
589314564Sdim	        sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
590314564Sdim	    /* XT kbd doesn't need scan code translation */
591314564Sdim	    c &= ~KBD_TRANSLATION;
592314564Sdim	} else {
593314564Sdim	    /* KEYBOARD ERROR
594314564Sdim	     * The XT kbd isn't usable unless the proper scan code set
595314564Sdim	     * is selected.
596314564Sdim	     */
597314564Sdim	    printf("sc%d: unable to set the XT keyboard mode.\n", unit);
598262182Semaste	    goto fail;
599314564Sdim	}
600262182Semaste    }
601262182Semaste    /* enable the keyboard port and intr. */
602314564Sdim    if (!set_controller_command_byte(sc_kbdc,
603314564Sdim            KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
604314564Sdim	    (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
605314564Sdim	        | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
606280031Sdim	/* CONTROLLER ERROR
607262182Semaste	 * This is serious; we are left with the disabled keyboard intr.
608314564Sdim	 */
609314564Sdim	printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
610314564Sdim	goto fail;
611314564Sdim    }
612314564Sdim
613314564Sdim    /* Get the ID of the keyboard, if any */
614314564Sdim    empty_kbd_buffer(sc_kbdc, 5);
615314564Sdim    res = send_kbd_command(sc_kbdc, KBDC_SEND_DEV_ID);
616262182Semaste    if (res == KBD_ACK) {
617314564Sdim	/* 10ms delay */
618314564Sdim	DELAY(10000);
619314564Sdim	id = (read_kbd_data(sc_kbdc) << 8) | read_kbd_data(sc_kbdc);
620262182Semaste	if (bootverbose)
621314564Sdim	    printf("sc%d: keyboard device ID: %04x\n", unit, id);
622314564Sdim    }
623314564Sdim
624314564Sdim    kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
625314564Sdim    kbdc_lock(sc_kbdc, FALSE);
626314564Sdim    return TRUE;
627314564Sdim
628314564Sdimfail:
629314564Sdim    if (c != -1)
630280031Sdim        /* try to restore the command byte as before, if possible */
631314564Sdim        set_controller_command_byte(sc_kbdc, 0xff, c);
632280031Sdim    kbdc_set_device_mask(sc_kbdc,
633314564Sdim        (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
634280031Sdim    kbdc_lock(sc_kbdc, FALSE);
635314564Sdim    return FALSE;
636314564Sdim}
637314564Sdim
638314564Sdim#if NAPM > 0
639314564Sdimstatic int
640262182Semastescresume(void *dummy)
641314564Sdim{
642314564Sdim	shfts = ctls = alts = agrs = metas = accents = 0;
643314564Sdim	return 0;
644314564Sdim}
645314564Sdim#endif
646314564Sdim
647314564Sdimstatic int
648314564Sdimscattach(struct isa_device *dev)
649314564Sdim{
650314564Sdim    scr_stat *scp;
651314564Sdim#if defined(VESA) && defined(VM86)
652314564Sdim    video_info_t info;
653280031Sdim#endif
654262182Semaste    dev_t cdev = makedev(CDEV_MAJOR, 0);
655314564Sdim#ifdef DEVFS
656314564Sdim    int vc;
657314564Sdim#endif
658314564Sdim
659314564Sdim    dev->id_ointr = scintr;
660314564Sdim    scinit();
661309124Sdim    sc_flags = dev->id_flags;
662314564Sdim    if (!ISFONTAVAIL(adp_flags))
663314564Sdim	sc_flags &= ~CHAR_CURSOR;
664309124Sdim
665341825Sdim    scp = console[0];
666341825Sdim
667314564Sdim    /* copy temporary buffer to final buffer */
668314564Sdim    scp->scr_buf = NULL;
669314564Sdim    sc_alloc_scr_buffer(scp, FALSE, FALSE);
670314564Sdim    bcopy(sc_buffer, scp->scr_buf, scp->xsize*scp->ysize*sizeof(u_short));
671314564Sdim
672314564Sdim    /* cut buffer is available only when the mouse pointer is used */
673314564Sdim    if (ISMOUSEAVAIL(adp_flags))
674314564Sdim	sc_alloc_cut_buffer(scp, FALSE);
675314564Sdim
676309124Sdim    /* initialize history buffer & pointers */
677314564Sdim    sc_alloc_history_buffer(scp, sc_history_size, 0, FALSE);
678314564Sdim
679314564Sdim#if defined(VESA) && defined(VM86)
680309124Sdim    if ((sc_flags & VESA800X600)
681314564Sdim	&& ((*biosvidsw.get_info)(scp->adp, M_VESA_800x600, &info) == 0)) {
682314564Sdim#ifdef SC_SPLASH_SCREEN
683309124Sdim	scsplash_term(scp);
684314564Sdim#endif
685309124Sdim	sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
686314564Sdim	sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
687309124Sdim	initial_video_mode = M_VESA_800x600;
688314564Sdim#ifdef SC_SPLASH_SCREEN
689314564Sdim	scsplash_init(scp);
690314564Sdim#endif
691314564Sdim    }
692314564Sdim#endif /* VESA && VM86 */
693309124Sdim
694309124Sdim    /* initialize cursor stuff */
695314564Sdim    if (!ISGRAPHSC(scp))
696314564Sdim    	draw_cursor_image(scp);
697276479Sdim
698314564Sdim    /* get screen update going */
699314564Sdim    scrn_timer((void *)TRUE);
700314564Sdim
701314564Sdim    update_leds(scp->status);
702280031Sdim
703314564Sdim    printf("sc%d: ", dev->id_unit);
704262182Semaste    switch(crtc_type) {
705341825Sdim    case KD_VGA:
706341825Sdim	printf("VGA %s", (adp_flags & V_ADP_COLOR) ? "color" : "mono");
707314564Sdim	break;
708314564Sdim    case KD_EGA:
709314564Sdim	printf("EGA %s", (adp_flags & V_ADP_COLOR) ? "color" : "mono");
710314564Sdim	break;
711314564Sdim    case KD_CGA:
712262182Semaste	printf("CGA");
713314564Sdim	break;
714314564Sdim    case KD_MONO:
715314564Sdim    case KD_HERCULES:
716314564Sdim    default:
717314564Sdim	printf("MDA/Hercules");
718314564Sdim	break;
719314564Sdim    }
720314564Sdim    printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, sc_flags);
721314564Sdim
722314564Sdim#if NAPM > 0
723314564Sdim    scp->r_hook.ah_fun = scresume;
724314564Sdim    scp->r_hook.ah_arg = NULL;
725314564Sdim    scp->r_hook.ah_name = "system keyboard";
726314564Sdim    scp->r_hook.ah_order = APM_MID_ORDER;
727314564Sdim    apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
728314564Sdim#endif
729314564Sdim
730314564Sdim    at_shutdown(scshutdown, NULL, SHUTDOWN_PRE_SYNC);
731314564Sdim
732262182Semaste    cdevsw_add(&cdev, &sc_cdevsw, NULL);
733262182Semaste
734314564Sdim#ifdef DEVFS
735314564Sdim    for (vc = 0; vc < MAXCONS; vc++)
736262182Semaste        sc_devfs_token[vc] = devfs_add_devswf(&sc_cdevsw, vc, DV_CHR,
737341825Sdim				UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc);
738341825Sdim    sc_mouse_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_MOUSE, DV_CHR,
739314564Sdim				UID_ROOT, GID_WHEEL, 0600, "sysmouse");
740314564Sdim    sc_console_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_CONSOLE, DV_CHR,
741314564Sdim				UID_ROOT, GID_WHEEL, 0600, "consolectl");
742314564Sdim#endif
743314564Sdim    return 0;
744314564Sdim}
745314564Sdim
746314564Sdimstruct tty
747314564Sdim*scdevtotty(dev_t dev)
748314564Sdim{
749314564Sdim    int unit = minor(dev);
750314564Sdim
751314564Sdim    if (init_done == COLD)
752314564Sdim	return(NULL);
753314564Sdim    if (unit == SC_CONSOLE)
754314564Sdim	return CONSOLE_TTY;
755314564Sdim    if (unit == SC_MOUSE)
756314564Sdim	return MOUSE_TTY;
757314564Sdim    if (unit >= MAXCONS || unit < 0)
758314564Sdim	return(NULL);
759314564Sdim    return VIRTUAL_TTY(unit);
760314564Sdim}
761314564Sdim
762341825Sdimint
763314564Sdimscopen(dev_t dev, int flag, int mode, struct proc *p)
764314564Sdim{
765314564Sdim    struct tty *tp = scdevtotty(dev);
766280031Sdim
767262182Semaste    if (!tp)
768314564Sdim	return(ENXIO);
769314564Sdim
770262182Semaste    tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
771314564Sdim    tp->t_param = scparam;
772360784Sdim    tp->t_dev = dev;
773314564Sdim    if (!(tp->t_state & TS_ISOPEN)) {
774314564Sdim	ttychars(tp);
775314564Sdim        /* Use the current setting of the <-- key as default VERASE. */
776314564Sdim        /* If the Delete key is preferable, an stty is necessary     */
777314564Sdim        tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
778314564Sdim	tp->t_iflag = TTYDEF_IFLAG;
779314564Sdim	tp->t_oflag = TTYDEF_OFLAG;
780314564Sdim	tp->t_cflag = TTYDEF_CFLAG;
781314564Sdim	tp->t_lflag = TTYDEF_LFLAG;
782314564Sdim	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
783314564Sdim	scparam(tp, &tp->t_termios);
784314564Sdim	(*linesw[tp->t_line].l_modem)(tp, 1);
785314564Sdim    	if (minor(dev) == SC_MOUSE)
786314564Sdim	    mouse_level = 0;		/* XXX */
787314564Sdim    }
788314564Sdim    else
789314564Sdim	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
790314564Sdim	    return(EBUSY);
791314564Sdim    if (minor(dev) < MAXCONS && !console[minor(dev)]) {
792314564Sdim	console[minor(dev)] = alloc_scp();
793314564Sdim	if (ISGRAPHSC(console[minor(dev)]))
794314564Sdim	    sc_set_pixel_mode(console[minor(dev)], NULL, COL, ROW, 16);
795314564Sdim    }
796314564Sdim    if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
797314564Sdim	tp->t_winsize.ws_col = console[minor(dev)]->xsize;
798360784Sdim	tp->t_winsize.ws_row = console[minor(dev)]->ysize;
799280031Sdim    }
800314564Sdim    return ((*linesw[tp->t_line].l_open)(dev, tp));
801314564Sdim}
802314564Sdim
803314564Sdimint
804314564Sdimscclose(dev_t dev, int flag, int mode, struct proc *p)
805314564Sdim{
806314564Sdim    struct tty *tp = scdevtotty(dev);
807314564Sdim    struct scr_stat *scp;
808280031Sdim
809314564Sdim    if (!tp)
810314564Sdim	return(ENXIO);
811314564Sdim    if (minor(dev) < MAXCONS) {
812314564Sdim	scp = sc_get_scr_stat(tp->t_dev);
813314564Sdim	if (scp->status & SWITCH_WAIT_ACQ)
814341825Sdim	    wakeup((caddr_t)&scp->smode);
815341825Sdim#if not_yet_done
816314564Sdim	if (scp == &main_console) {
817314564Sdim	    scp->pid = 0;
818314564Sdim	    scp->proc = NULL;
819314564Sdim	    scp->smode.mode = VT_AUTO;
820314564Sdim	}
821314564Sdim	else {
822314564Sdim	    free(scp->scr_buf, M_DEVBUF);
823314564Sdim	    if (scp->history != NULL) {
824314564Sdim		free(scp->history, M_DEVBUF);
825280031Sdim		if (scp->history_size / scp->xsize
826280031Sdim			> imax(sc_history_size, scp->ysize))
827314564Sdim		    extra_history_size += scp->history_size / scp->xsize
828314564Sdim			- imax(sc_history_size, scp->ysize);
829309124Sdim	    }
830360784Sdim	    free(scp, M_DEVBUF);
831309124Sdim	    console[minor(dev)] = NULL;
832309124Sdim	}
833314564Sdim#else
834314564Sdim	scp->pid = 0;
835309124Sdim	scp->proc = NULL;
836360784Sdim	scp->smode.mode = VT_AUTO;
837309124Sdim#endif
838309124Sdim    }
839314564Sdim    spltty();
840314564Sdim    (*linesw[tp->t_line].l_close)(tp, flag);
841314564Sdim    ttyclose(tp);
842296417Sdim    spl0();
843314564Sdim    return(0);
844314564Sdim}
845314564Sdim
846314564Sdimint
847314564Sdimscread(dev_t dev, struct uio *uio, int flag)
848296417Sdim{
849314564Sdim    struct tty *tp = scdevtotty(dev);
850314564Sdim
851314564Sdim    if (!tp)
852314564Sdim	return(ENXIO);
853314564Sdim    return((*linesw[tp->t_line].l_read)(tp, uio, flag));
854280031Sdim}
855314564Sdim
856314564Sdimint
857314564Sdimscwrite(dev_t dev, struct uio *uio, int flag)
858296417Sdim{
859314564Sdim    struct tty *tp = scdevtotty(dev);
860314564Sdim
861314564Sdim    if (!tp)
862314564Sdim	return(ENXIO);
863314564Sdim    return((*linesw[tp->t_line].l_write)(tp, uio, flag));
864314564Sdim}
865314564Sdim
866296417Sdimstatic void
867314564Sdimscintr(int unit)
868296417Sdim{
869314564Sdim    static struct tty *cur_tty;
870296417Sdim    int c, len;
871296417Sdim    u_char *cp;
872314564Sdim
873314564Sdim    /*
874314564Sdim     * Loop while there is still input to get from the keyboard.
875314564Sdim     * I don't think this is nessesary, and it doesn't fix
876314564Sdim     * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
877341825Sdim     */
878314564Sdim    while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
879314564Sdim
880314564Sdim	cur_tty = VIRTUAL_TTY(get_scr_num());
881314564Sdim	if (!(cur_tty->t_state & TS_ISOPEN))
882280031Sdim	    if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
883280031Sdim		continue;
884314564Sdim
885314564Sdim	switch (c & 0xff00) {
886314564Sdim	case 0x0000: /* normal key */
887314564Sdim	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
888314564Sdim	    break;
889314564Sdim	case FKEY:  /* function key, return string */
890314564Sdim	    if (cp = get_fstr((u_int)c, (u_int *)&len)) {
891262182Semaste	    	while (len-- >  0)
892314564Sdim		    (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
893314564Sdim	    }
894314564Sdim	    break;
895280031Sdim	case MKEY:  /* meta is active, prepend ESC */
896262182Semaste	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
897314564Sdim	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
898314564Sdim	    break;
899314564Sdim	case BKEY:  /* backtab fixed sequence (esc [ Z) */
900314564Sdim	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
901314564Sdim	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
902314564Sdim	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
903280031Sdim	    break;
904262182Semaste	}
905314564Sdim    }
906314564Sdim
907314564Sdim#if 0
908314564Sdim    if (cur_console->status & MOUSE_ENABLED) {
909314564Sdim	cur_console->status &= ~MOUSE_VISIBLE;
910314564Sdim	remove_mouse_image(cur_console);
911262182Semaste    }
912262182Semaste#else
913344779Sdim    if (cur_console->status & MOUSE_VISIBLE) {
914344779Sdim	remove_mouse_image(cur_console);
915360784Sdim	cur_console->status &= ~MOUSE_VISIBLE;
916360784Sdim    }
917360784Sdim#endif
918360784Sdim}
919360784Sdim
920360784Sdimstatic int
921360784Sdimscparam(struct tty *tp, struct termios *t)
922360784Sdim{
923360784Sdim    tp->t_ispeed = t->c_ispeed;
924360784Sdim    tp->t_ospeed = t->c_ospeed;
925360784Sdim    tp->t_cflag = t->c_cflag;
926344779Sdim    return 0;
927360784Sdim}
928360784Sdim
929360784Sdimint
930360784Sdimscioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
931360784Sdim{
932360784Sdim    u_int delta_ehs;
933360784Sdim    int error;
934360784Sdim    int i;
935360784Sdim    struct tty *tp;
936360784Sdim    scr_stat *scp;
937360784Sdim    int s;
938360784Sdim
939360784Sdim    tp = scdevtotty(dev);
940360784Sdim    if (!tp)
941360784Sdim	return ENXIO;
942360784Sdim    scp = sc_get_scr_stat(tp->t_dev);
943360784Sdim
944360784Sdim    /* If there is a user_ioctl function call that first */
945360784Sdim    if (sc_user_ioctl) {
946344779Sdim	error = (*sc_user_ioctl)(dev, cmd, data, flag, p);
947344779Sdim	if (error != ENOIOCTL)
948360784Sdim	    return error;
949360784Sdim    }
950360784Sdim
951360784Sdim    error = sc_vid_ioctl(tp, cmd, data, flag, p);
952344779Sdim    if (error != ENOIOCTL)
953360784Sdim	return error;
954344779Sdim
955360784Sdim    switch (cmd) {  		/* process console hardware related ioctl's */
956360784Sdim
957360784Sdim    case GIO_ATTR:      	/* get current attributes */
958360784Sdim	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
959360784Sdim	return 0;
960360784Sdim
961360784Sdim    case GIO_COLOR:     	/* is this a color console ? */
962360784Sdim	*(int *)data = (adp_flags & V_ADP_COLOR) ? 1 : 0;
963360784Sdim	return 0;
964360784Sdim
965360784Sdim    case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
966360784Sdim	if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
967360784Sdim            return EINVAL;
968344779Sdim	s = spltty();
969344779Sdim	scrn_blank_time = *(int *)data;
970344779Sdim	run_scrn_saver = (scrn_blank_time != 0);
971314564Sdim	splx(s);
972314564Sdim	return 0;
973314564Sdim
974314564Sdim    case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
975314564Sdim	if ((*(int*)data) & 0x01)
976314564Sdim	    sc_flags |= BLINK_CURSOR;
977360784Sdim	else
978360784Sdim	    sc_flags &= ~BLINK_CURSOR;
979360784Sdim	if ((*(int*)data) & 0x02) {
980360784Sdim	    if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
981360784Sdim		return ENXIO;
982314564Sdim	    sc_flags |= CHAR_CURSOR;
983360784Sdim	} else
984360784Sdim	    sc_flags &= ~CHAR_CURSOR;
985360784Sdim	/*
986360784Sdim	 * The cursor shape is global property; all virtual consoles
987360784Sdim	 * are affected. Update the cursor in the current console...
988360784Sdim	 */
989360784Sdim	if (!ISGRAPHSC(cur_console)) {
990360784Sdim	    s = spltty();
991314564Sdim            remove_cursor_image(cur_console);
992360784Sdim	    if (sc_flags & CHAR_CURSOR)
993360784Sdim	        set_destructive_cursor(cur_console);
994360784Sdim	    draw_cursor_image(cur_console);
995360784Sdim	    splx(s);
996360784Sdim	}
997360784Sdim	return 0;
998360784Sdim
999360784Sdim    case CONS_BELLTYPE: 	/* set bell type sound/visual */
1000360784Sdim	if ((*(int *)data) & 0x01)
1001360784Sdim	    sc_flags |= VISUAL_BELL;
1002360784Sdim	else
1003360784Sdim	    sc_flags &= ~VISUAL_BELL;
1004360784Sdim	if ((*(int *)data) & 0x02)
1005360784Sdim	    sc_flags |= QUIET_BELL;
1006360784Sdim	else
1007360784Sdim	    sc_flags &= ~QUIET_BELL;
1008360784Sdim	return 0;
1009360784Sdim
1010360784Sdim    case CONS_HISTORY:  	/* set history size */
1011360784Sdim	if (*(int *)data > 0) {
1012360784Sdim	    int lines;	/* buffer size to allocate */
1013360784Sdim	    int lines0;	/* current buffer size */
1014360784Sdim
1015360784Sdim	    lines = imax(*(int *)data, scp->ysize);
1016360784Sdim	    lines0 = (scp->history != NULL) ?
1017314564Sdim		      scp->history_size / scp->xsize : scp->ysize;
1018314564Sdim	    if (lines0 > imax(sc_history_size, scp->ysize))
1019314564Sdim		delta_ehs = lines0 - imax(sc_history_size, scp->ysize);
1020314564Sdim	    else
1021360784Sdim		delta_ehs = 0;
1022360784Sdim	    /*
1023360784Sdim	     * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
1024360784Sdim	     * lines or scp->ysize lines, whichever is larger. A value
1025360784Sdim	     * greater than that is allowed, subject to extra_history_size.
1026360784Sdim	     */
1027314564Sdim	    if (lines > imax(sc_history_size, scp->ysize))
1028314564Sdim		if (lines - imax(sc_history_size, scp->ysize) >
1029314564Sdim		    extra_history_size + delta_ehs)
1030360784Sdim		    return EINVAL;
1031314564Sdim            if (cur_console->status & BUFFER_SAVED)
1032360784Sdim                return EBUSY;
1033360784Sdim	    sc_alloc_history_buffer(scp, lines, delta_ehs, TRUE);
1034314564Sdim	    return 0;
1035280031Sdim	}
1036280031Sdim	else
1037314564Sdim	    return EINVAL;
1038314564Sdim
1039314564Sdim    case CONS_MOUSECTL:		/* control mouse arrow */
1040314564Sdim    case OLD_CONS_MOUSECTL:
1041280031Sdim    {
1042314564Sdim	/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
1043341825Sdim	static int butmap[8] = {
1044341825Sdim            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1045341825Sdim            MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1046314564Sdim            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1047314564Sdim            MOUSE_MSC_BUTTON3UP,
1048314564Sdim            MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1049280031Sdim            MOUSE_MSC_BUTTON2UP,
1050314564Sdim            MOUSE_MSC_BUTTON1UP,
1051314564Sdim            0,
1052314564Sdim	};
1053309124Sdim	mouse_info_t *mouse = (mouse_info_t*)data;
1054314564Sdim	mouse_info_t buf;
1055353358Sdim
1056353358Sdim	/* FIXME: */
1057353358Sdim	if (!ISMOUSEAVAIL(get_adapter(scp)->va_flags))
1058314564Sdim	    return ENODEV;
1059314564Sdim
1060314564Sdim	if (cmd == OLD_CONS_MOUSECTL) {
1061314564Sdim	    static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
1062314564Sdim	    old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
1063314564Sdim
1064314564Sdim	    mouse = &buf;
1065314564Sdim	    mouse->operation = old_mouse->operation;
1066314564Sdim	    switch (mouse->operation) {
1067280031Sdim	    case MOUSE_MODE:
1068314564Sdim		mouse->u.mode = old_mouse->u.mode;
1069321369Sdim		break;
1070314564Sdim	    case MOUSE_SHOW:
1071314564Sdim	    case MOUSE_HIDE:
1072280031Sdim		break;
1073341825Sdim	    case MOUSE_MOVEABS:
1074341825Sdim	    case MOUSE_MOVEREL:
1075314564Sdim	    case MOUSE_ACTION:
1076314564Sdim		mouse->u.data.x = old_mouse->u.data.x;
1077314564Sdim		mouse->u.data.y = old_mouse->u.data.y;
1078314564Sdim		mouse->u.data.z = 0;
1079314564Sdim		mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
1080314564Sdim		break;
1081314564Sdim	    case MOUSE_GETINFO:
1082314564Sdim		old_mouse->u.data.x = scp->mouse_xpos;
1083314564Sdim		old_mouse->u.data.y = scp->mouse_ypos;
1084314564Sdim		old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
1085314564Sdim		break;
1086314564Sdim	    default:
1087314564Sdim		return EINVAL;
1088314564Sdim	    }
1089314564Sdim	}
1090314564Sdim
1091314564Sdim	switch (mouse->operation) {
1092314564Sdim	case MOUSE_MODE:
1093314564Sdim	    if (ISSIGVALID(mouse->u.mode.signal)) {
1094314564Sdim		scp->mouse_signal = mouse->u.mode.signal;
1095314564Sdim		scp->mouse_proc = p;
1096314564Sdim		scp->mouse_pid = p->p_pid;
1097314564Sdim	    }
1098314564Sdim	    else {
1099314564Sdim		scp->mouse_signal = 0;
1100314564Sdim		scp->mouse_proc = NULL;
1101314564Sdim		scp->mouse_pid = 0;
1102314564Sdim	    }
1103314564Sdim	    return 0;
1104314564Sdim
1105314564Sdim	case MOUSE_SHOW:
1106314564Sdim	    if (ISTEXTSC(scp) && !(scp->status & MOUSE_ENABLED)) {
1107314564Sdim		scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
1108314564Sdim		scp->mouse_oldpos = scp->mouse_pos;
1109314564Sdim		mark_all(scp);
1110314564Sdim		return 0;
1111314564Sdim	    }
1112314564Sdim	    else
1113314564Sdim		return EINVAL;
1114314564Sdim	    break;
1115314564Sdim
1116314564Sdim	case MOUSE_HIDE:
1117314564Sdim	    if (ISTEXTSC(scp) && (scp->status & MOUSE_ENABLED)) {
1118314564Sdim		scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
1119314564Sdim		mark_all(scp);
1120314564Sdim		return 0;
1121314564Sdim	    }
1122314564Sdim	    else
1123314564Sdim		return EINVAL;
1124314564Sdim	    break;
1125314564Sdim
1126314564Sdim	case MOUSE_MOVEABS:
1127314564Sdim	    scp->mouse_xpos = mouse->u.data.x;
1128314564Sdim	    scp->mouse_ypos = mouse->u.data.y;
1129314564Sdim	    set_mouse_pos(scp);
1130314564Sdim	    break;
1131314564Sdim
1132341825Sdim	case MOUSE_MOVEREL:
1133341825Sdim	    scp->mouse_xpos += mouse->u.data.x;
1134341825Sdim	    scp->mouse_ypos += mouse->u.data.y;
1135341825Sdim	    set_mouse_pos(scp);
1136341825Sdim	    break;
1137314564Sdim
1138314564Sdim	case MOUSE_GETINFO:
1139314564Sdim	    mouse->u.data.x = scp->mouse_xpos;
1140314564Sdim	    mouse->u.data.y = scp->mouse_ypos;
1141314564Sdim	    mouse->u.data.z = 0;
1142314564Sdim	    mouse->u.data.buttons = scp->mouse_buttons;
1143314564Sdim	    return 0;
1144314564Sdim
1145314564Sdim	case MOUSE_ACTION:
1146314564Sdim	case MOUSE_MOTION_EVENT:
1147314564Sdim	    /* this should maybe only be settable from /dev/consolectl SOS */
1148314564Sdim	    /* send out mouse event on /dev/sysmouse */
1149314564Sdim
1150314564Sdim	    mouse_status.dx += mouse->u.data.x;
1151314564Sdim	    mouse_status.dy += mouse->u.data.y;
1152314564Sdim	    mouse_status.dz += mouse->u.data.z;
1153314564Sdim	    if (mouse->operation == MOUSE_ACTION)
1154314564Sdim	        mouse_status.button = mouse->u.data.buttons;
1155314564Sdim	    mouse_status.flags |=
1156360784Sdim		((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1157360784Sdim		    MOUSE_POSCHANGED : 0)
1158360784Sdim		| (mouse_status.obutton ^ mouse_status.button);
1159360784Sdim	    if (mouse_status.flags == 0)
1160360784Sdim		return 0;
1161360784Sdim
1162360784Sdim	    if (ISTEXTSC(cur_console) && (cur_console->status & MOUSE_ENABLED))
1163360784Sdim	    	cur_console->status |= MOUSE_VISIBLE;
1164360784Sdim
1165314564Sdim	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1166314564Sdim		u_char buf[MOUSE_SYS_PACKETSIZE];
1167353358Sdim		int j;
1168314564Sdim
1169314564Sdim		/* the first five bytes are compatible with MouseSystems' */
1170314564Sdim		buf[0] = MOUSE_MSC_SYNC
1171314564Sdim		    | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1172314564Sdim		j = imax(imin(mouse->u.data.x, 255), -256);
1173314564Sdim		buf[1] = j >> 1;
1174314564Sdim		buf[3] = j - buf[1];
1175314564Sdim		j = -imax(imin(mouse->u.data.y, 255), -256);
1176314564Sdim		buf[2] = j >> 1;
1177314564Sdim		buf[4] = j - buf[2];
1178314564Sdim		for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
1179314564Sdim	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1180314564Sdim		if (mouse_level >= 1) { 	/* extended part */
1181314564Sdim		    j = imax(imin(mouse->u.data.z, 127), -128);
1182314564Sdim		    buf[5] = (j >> 1) & 0x7f;
1183314564Sdim		    buf[6] = (j - (j >> 1)) & 0x7f;
1184280031Sdim		    /* buttons 4-10 */
1185314564Sdim		    buf[7] = (~mouse_status.button >> 3) & 0x7f;
1186280031Sdim		    for (j = MOUSE_MSC_PACKETSIZE;
1187314564Sdim			 j < MOUSE_SYS_PACKETSIZE; j++)
1188314564Sdim	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1189314564Sdim		}
1190314564Sdim	    }
1191314564Sdim
1192314564Sdim	    if (cur_console->mouse_signal) {
1193314564Sdim		cur_console->mouse_buttons = mouse->u.data.buttons;
1194314564Sdim    		/* has controlling process died? */
1195314564Sdim		if (cur_console->mouse_proc &&
1196314564Sdim		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1197314564Sdim		    	cur_console->mouse_signal = 0;
1198314564Sdim			cur_console->mouse_proc = NULL;
1199280031Sdim			cur_console->mouse_pid = 0;
1200314564Sdim		}
1201314564Sdim		else
1202314564Sdim		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1203314564Sdim	    }
1204314564Sdim	    else if (mouse->operation == MOUSE_ACTION && cut_buffer != NULL) {
1205314564Sdim		/* process button presses */
1206314564Sdim		if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
1207314564Sdim		    ISTEXTSC(cur_console)) {
1208314564Sdim		    cur_console->mouse_buttons = mouse->u.data.buttons;
1209314564Sdim		    if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
1210314564Sdim			mouse_cut_start(cur_console);
1211314564Sdim		    else
1212314564Sdim			mouse_cut_end(cur_console);
1213314564Sdim		    if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
1214314564Sdim			cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
1215314564Sdim			mouse_paste(cur_console);
1216314564Sdim		}
1217314564Sdim	    }
1218314564Sdim
1219314564Sdim	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
1220314564Sdim		cur_console->mouse_xpos += mouse->u.data.x;
1221314564Sdim		cur_console->mouse_ypos += mouse->u.data.y;
1222314564Sdim		set_mouse_pos(cur_console);
1223314564Sdim	    }
1224314564Sdim
1225314564Sdim	    break;
1226341825Sdim
1227314564Sdim	case MOUSE_BUTTON_EVENT:
1228314564Sdim	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
1229314564Sdim		return EINVAL;
1230280031Sdim	    if (mouse->u.event.value < 0)
1231314564Sdim		return EINVAL;
1232262182Semaste
1233262182Semaste	    if (mouse->u.event.value > 0) {
1234280031Sdim	        cur_console->mouse_buttons |= mouse->u.event.id;
1235280031Sdim	        mouse_status.button |= mouse->u.event.id;
1236314564Sdim	    } else {
1237314564Sdim	        cur_console->mouse_buttons &= ~mouse->u.event.id;
1238314564Sdim	        mouse_status.button &= ~mouse->u.event.id;
1239314564Sdim	    }
1240262182Semaste	    mouse_status.flags |= mouse_status.obutton ^ mouse_status.button;
1241262182Semaste	    if (mouse_status.flags == 0)
1242314564Sdim		return 0;
1243314564Sdim
1244314564Sdim	    if (ISTEXTSC(cur_console) && (cur_console->status & MOUSE_ENABLED))
1245314564Sdim	    	cur_console->status |= MOUSE_VISIBLE;
1246314564Sdim
1247314564Sdim	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1248314564Sdim		u_char buf[8];
1249314564Sdim		int i;
1250309124Sdim
1251309124Sdim		buf[0] = MOUSE_MSC_SYNC
1252314564Sdim			 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1253314564Sdim		buf[7] = (~mouse_status.button >> 3) & 0x7f;
1254314564Sdim		buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
1255314564Sdim		for (i = 0;
1256314564Sdim		     i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
1257321369Sdim					     : MOUSE_MSC_PACKETSIZE); i++)
1258321369Sdim	    	    (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
1259314564Sdim	    }
1260314564Sdim
1261314564Sdim	    if (cur_console->mouse_signal) {
1262314564Sdim		if (cur_console->mouse_proc &&
1263314564Sdim		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1264314564Sdim		    	cur_console->mouse_signal = 0;
1265309124Sdim			cur_console->mouse_proc = NULL;
1266314564Sdim			cur_console->mouse_pid = 0;
1267314564Sdim		}
1268314564Sdim		else
1269314564Sdim		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1270314564Sdim		break;
1271314564Sdim	    }
1272314564Sdim
1273314564Sdim	    if (!ISTEXTSC(cur_console) || (cut_buffer == NULL))
1274309124Sdim		break;
1275314564Sdim
1276309124Sdim	    switch (mouse->u.event.id) {
1277262182Semaste	    case MOUSE_BUTTON1DOWN:
1278262182Semaste	        switch (mouse->u.event.value % 4) {
1279314564Sdim		case 0:	/* up */
1280314564Sdim		    mouse_cut_end(cur_console);
1281341825Sdim		    break;
1282341825Sdim		case 1:
1283341825Sdim		    mouse_cut_start(cur_console);
1284314564Sdim		    break;
1285314564Sdim		case 2:
1286314564Sdim		    mouse_cut_word(cur_console);
1287314564Sdim		    break;
1288280031Sdim		case 3:
1289341825Sdim		    mouse_cut_line(cur_console);
1290341825Sdim		    break;
1291341825Sdim		}
1292341825Sdim		break;
1293314564Sdim	    case MOUSE_BUTTON2DOWN:
1294262182Semaste	        switch (mouse->u.event.value) {
1295262182Semaste		case 0:	/* up */
1296314564Sdim		    break;
1297314564Sdim		default:
1298262182Semaste		    mouse_paste(cur_console);
1299262182Semaste		    break;
1300314564Sdim		}
1301314564Sdim		break;
1302314564Sdim	    case MOUSE_BUTTON3DOWN:
1303280031Sdim	        switch (mouse->u.event.value) {
1304280031Sdim		case 0:	/* up */
1305314564Sdim		    if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
1306314564Sdim		        mouse_cut_end(cur_console);
1307314564Sdim		    break;
1308314564Sdim		default:
1309353358Sdim		    mouse_cut_extend(cur_console);
1310353358Sdim		    break;
1311353358Sdim		}
1312353358Sdim		break;
1313353358Sdim	    }
1314353358Sdim	    break;
1315353358Sdim
1316314564Sdim	default:
1317314564Sdim	    return EINVAL;
1318314564Sdim	}
1319314564Sdim	/* make screensaver happy */
1320314564Sdim	scsplash_stick(FALSE);
1321314564Sdim	run_scrn_saver = FALSE;
1322314564Sdim	return 0;
1323314564Sdim    }
1324314564Sdim
1325314564Sdim    /* MOUSE_XXX: /dev/sysmouse ioctls */
1326280031Sdim    case MOUSE_GETHWINFO:	/* get device information */
1327314564Sdim    {
1328280031Sdim	mousehw_t *hw = (mousehw_t *)data;
1329280031Sdim
1330314564Sdim	if (tp != MOUSE_TTY)
1331280031Sdim	    return ENOTTY;
1332314564Sdim	hw->buttons = 10;		/* XXX unknown */
1333280031Sdim	hw->iftype = MOUSE_IF_SYSMOUSE;
1334314564Sdim	hw->type = MOUSE_MOUSE;
1335314564Sdim	hw->model = MOUSE_MODEL_GENERIC;
1336314564Sdim	hw->hwid = 0;
1337314564Sdim	return 0;
1338314564Sdim    }
1339314564Sdim
1340314564Sdim    case MOUSE_GETMODE:		/* get protocol/mode */
1341314564Sdim    {
1342314564Sdim	mousemode_t *mode = (mousemode_t *)data;
1343262182Semaste
1344262182Semaste	if (tp != MOUSE_TTY)
1345314564Sdim	    return ENOTTY;
1346314564Sdim	mode->level = mouse_level;
1347314564Sdim	switch (mode->level) {
1348314564Sdim	case 0:
1349314564Sdim	    /* at this level, sysmouse emulates MouseSystems protocol */
1350314564Sdim	    mode->protocol = MOUSE_PROTO_MSC;
1351314564Sdim	    mode->rate = -1;		/* unknown */
1352314564Sdim	    mode->resolution = -1;	/* unknown */
1353314564Sdim	    mode->accelfactor = 0;	/* disabled */
1354314564Sdim	    mode->packetsize = MOUSE_MSC_PACKETSIZE;
1355262182Semaste	    mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
1356280031Sdim	    mode->syncmask[1] = MOUSE_MSC_SYNC;
1357314564Sdim	    break;
1358314564Sdim
1359314564Sdim	case 1:
1360314564Sdim	    /* at this level, sysmouse uses its own protocol */
1361262182Semaste	    mode->protocol = MOUSE_PROTO_SYSMOUSE;
1362262182Semaste	    mode->rate = -1;
1363314564Sdim	    mode->resolution = -1;
1364314564Sdim	    mode->accelfactor = 0;
1365314564Sdim	    mode->packetsize = MOUSE_SYS_PACKETSIZE;
1366314564Sdim	    mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
1367262182Semaste	    mode->syncmask[1] = MOUSE_SYS_SYNC;
1368262182Semaste	    break;
1369314564Sdim	}
1370314564Sdim	return 0;
1371314564Sdim    }
1372314564Sdim
1373314564Sdim    case MOUSE_SETMODE:		/* set protocol/mode */
1374314564Sdim    {
1375314564Sdim	mousemode_t *mode = (mousemode_t *)data;
1376262182Semaste
1377262182Semaste	if (tp != MOUSE_TTY)
1378314564Sdim	    return ENOTTY;
1379314564Sdim	if ((mode->level < 0) || (mode->level > 1))
1380314564Sdim	    return EINVAL;
1381314564Sdim	mouse_level = mode->level;
1382288943Sdim	return 0;
1383314564Sdim    }
1384309124Sdim
1385314564Sdim    case MOUSE_GETLEVEL:	/* get operation level */
1386314564Sdim	if (tp != MOUSE_TTY)
1387314564Sdim	    return ENOTTY;
1388314564Sdim	*(int *)data = mouse_level;
1389314564Sdim	return 0;
1390314564Sdim
1391288943Sdim    case MOUSE_SETLEVEL:	/* set operation level */
1392314564Sdim	if (tp != MOUSE_TTY)
1393314564Sdim	    return ENOTTY;
1394314564Sdim	if ((*(int *)data  < 0) || (*(int *)data > 1))
1395314564Sdim	    return EINVAL;
1396280031Sdim	mouse_level = *(int *)data;
1397314564Sdim	return 0;
1398314564Sdim
1399280031Sdim    case MOUSE_GETSTATUS:	/* get accumulated mouse events */
1400314564Sdim	if (tp != MOUSE_TTY)
1401314564Sdim	    return ENOTTY;
1402314564Sdim	s = spltty();
1403314564Sdim	*(mousestatus_t *)data = mouse_status;
1404314564Sdim	mouse_status.flags = 0;
1405314564Sdim	mouse_status.obutton = mouse_status.button;
1406314564Sdim	mouse_status.dx = 0;
1407280031Sdim	mouse_status.dy = 0;
1408314564Sdim	mouse_status.dz = 0;
1409280031Sdim	splx(s);
1410314564Sdim	return 0;
1411280031Sdim
1412314564Sdim#if notyet
1413262182Semaste    case MOUSE_GETVARS:		/* get internal mouse variables */
1414314564Sdim    case MOUSE_SETVARS:		/* set internal mouse variables */
1415314564Sdim	if (tp != MOUSE_TTY)
1416262182Semaste	    return ENOTTY;
1417262182Semaste	return ENODEV;
1418314564Sdim#endif
1419314564Sdim
1420314564Sdim    case MOUSE_READSTATE:	/* read status from the device */
1421309124Sdim    case MOUSE_READDATA:	/* read data from the device */
1422341825Sdim	if (tp != MOUSE_TTY)
1423341825Sdim	    return ENOTTY;
1424314564Sdim	return ENODEV;
1425314564Sdim
1426314564Sdim    case CONS_GETINFO:  	/* get current (virtual) console info */
1427280031Sdim    {
1428314564Sdim	vid_info_t *ptr = (vid_info_t*)data;
1429314564Sdim	if (ptr->size == sizeof(struct vid_info)) {
1430314564Sdim	    ptr->m_num = get_scr_num();
1431314564Sdim	    ptr->mv_col = scp->xpos;
1432314564Sdim	    ptr->mv_row = scp->ypos;
1433314564Sdim	    ptr->mv_csz = scp->xsize;
1434314564Sdim	    ptr->mv_rsz = scp->ysize;
1435262182Semaste	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
1436314564Sdim	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
1437314564Sdim	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
1438314564Sdim	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
1439314564Sdim	    ptr->mv_grfc.fore = 0;      /* not supported */
1440314564Sdim	    ptr->mv_grfc.back = 0;      /* not supported */
1441314564Sdim	    ptr->mv_ovscan = scp->border;
1442314564Sdim	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
1443314564Sdim	    return 0;
1444314564Sdim	}
1445314564Sdim	return EINVAL;
1446314564Sdim    }
1447314564Sdim
1448314564Sdim    case CONS_GETVERS:  	/* get version number */
1449314564Sdim	*(int*)data = 0x200;    /* version 2.0 */
1450314564Sdim	return 0;
1451314564Sdim
1452314564Sdim    case CONS_IDLE:		/* see if the screen has been idle */
1453262182Semaste	/*
1454288943Sdim	 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
1455314564Sdim	 * the user process may have been writing something on the
1456314564Sdim	 * screen and syscons is not aware of it. Declare the screen
1457314564Sdim	 * is NOT idle if it is in one of these modes. But there is
1458314564Sdim	 * an exception to it; if a screen saver is running in the
1459314564Sdim	 * graphics mode in the current screen, we should say that the
1460314564Sdim	 * screen has been idle.
1461314564Sdim	 */
1462314564Sdim	*(int *)data = scrn_idle
1463314564Sdim		       && (!ISGRAPHSC(cur_console)
1464314564Sdim			   || (cur_console->status & SAVER_RUNNING));
1465314564Sdim	return 0;
1466314564Sdim
1467314564Sdim    case CONS_SAVERMODE:	/* set saver mode */
1468314564Sdim	switch(*(int *)data) {
1469321369Sdim	case CONS_USR_SAVER:
1470314564Sdim	    /* if a LKM screen saver is running, stop it first. */
1471314564Sdim	    scsplash_stick(FALSE);
1472314564Sdim	    saver_mode = *(int *)data;
1473314564Sdim	    s = spltty();
1474321369Sdim	    if ((error = wait_scrn_saver_stop())) {
1475314564Sdim		splx(s);
1476314564Sdim		return error;
1477314564Sdim	    }
1478314564Sdim	    scp->status |= SAVER_RUNNING;
1479314564Sdim	    scsplash_stick(TRUE);
1480314564Sdim	    splx(s);
1481314564Sdim	    break;
1482314564Sdim	case CONS_LKM_SAVER:
1483314564Sdim	    s = spltty();
1484314564Sdim	    if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
1485314564Sdim		scp->status &= ~SAVER_RUNNING;
1486314564Sdim	    saver_mode = *(int *)data;
1487360784Sdim	    splx(s);
1488314564Sdim	    break;
1489314564Sdim	default:
1490314564Sdim	    return EINVAL;
1491314564Sdim	}
1492314564Sdim	return 0;
1493314564Sdim
1494314564Sdim    case CONS_SAVERSTART:	/* immediately start/stop the screen saver */
1495314564Sdim	/*
1496314564Sdim	 * Note that this ioctl does not guarantee the screen saver
1497314564Sdim	 * actually starts or stops. It merely attempts to do so...
1498314564Sdim	 */
1499314564Sdim	s = spltty();
1500288943Sdim	run_scrn_saver = (*(int *)data != 0);
1501314564Sdim	if (run_scrn_saver)
1502314564Sdim	    scrn_time_stamp -= scrn_blank_time;
1503288943Sdim	splx(s);
1504	return 0;
1505
1506    case VT_SETMODE:    	/* set screen switcher mode */
1507    {
1508	struct vt_mode *mode;
1509
1510	mode = (struct vt_mode *)data;
1511	if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
1512	    ISSIGVALID(mode->frsig)) {
1513	    bcopy(data, &scp->smode, sizeof(struct vt_mode));
1514	    if (scp->smode.mode == VT_PROCESS) {
1515		scp->proc = p;
1516		scp->pid = scp->proc->p_pid;
1517	    }
1518	    return 0;
1519	} else
1520	    return EINVAL;
1521    }
1522
1523    case VT_GETMODE:    	/* get screen switcher mode */
1524	bcopy(&scp->smode, data, sizeof(struct vt_mode));
1525	return 0;
1526
1527    case VT_RELDISP:    	/* screen switcher ioctl */
1528	switch(*(int *)data) {
1529	case VT_FALSE:  	/* user refuses to release screen, abort */
1530	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1531		old_scp->status &= ~SWITCH_WAIT_REL;
1532		switch_in_progress = FALSE;
1533		return 0;
1534	    }
1535	    return EINVAL;
1536
1537	case VT_TRUE:   	/* user has released screen, go on */
1538	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1539		scp->status &= ~SWITCH_WAIT_REL;
1540		exchange_scr();
1541		if (new_scp->smode.mode == VT_PROCESS) {
1542		    new_scp->status |= SWITCH_WAIT_ACQ;
1543		    psignal(new_scp->proc, new_scp->smode.acqsig);
1544		}
1545		else
1546		    switch_in_progress = FALSE;
1547		return 0;
1548	    }
1549	    return EINVAL;
1550
1551	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
1552	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1553		scp->status &= ~SWITCH_WAIT_ACQ;
1554		switch_in_progress = FALSE;
1555		return 0;
1556	    }
1557	    return EINVAL;
1558
1559	default:
1560	    return EINVAL;
1561	}
1562	/* NOT REACHED */
1563
1564    case VT_OPENQRY:    	/* return free virtual console */
1565	for (i = 0; i < MAXCONS; i++) {
1566	    tp = VIRTUAL_TTY(i);
1567	    if (!(tp->t_state & TS_ISOPEN)) {
1568		*(int *)data = i + 1;
1569		return 0;
1570	    }
1571	}
1572	return EINVAL;
1573
1574    case VT_ACTIVATE:   	/* switch to screen *data */
1575	return switch_scr(scp, *(int *)data - 1);
1576
1577    case VT_WAITACTIVE: 	/* wait for switch to occur */
1578	if (*(int *)data > MAXCONS || *(int *)data < 0)
1579	    return EINVAL;
1580	if (minor(dev) == *(int *)data - 1)
1581	    return 0;
1582	if (*(int *)data == 0) {
1583	    if (scp == cur_console)
1584		return 0;
1585	}
1586	else
1587	    scp = console[*(int *)data - 1];
1588	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1589			     "waitvt", 0)) == ERESTART) ;
1590	return error;
1591
1592    case VT_GETACTIVE:
1593	*(int *)data = get_scr_num()+1;
1594	return 0;
1595
1596    case KDENABIO:      	/* allow io operations */
1597	error = suser(p->p_ucred, &p->p_acflag);
1598	if (error != 0)
1599	    return error;
1600	if (securelevel > 0)
1601	    return EPERM;
1602	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1603	return 0;
1604
1605    case KDDISABIO:     	/* disallow io operations (default) */
1606	p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1607	return 0;
1608
1609    case KDSKBSTATE:    	/* set keyboard state (locks) */
1610	if (*(int *)data & ~LOCK_KEY_MASK)
1611	    return EINVAL;
1612	scp->status &= ~LOCK_KEY_MASK;
1613	scp->status |= *(int *)data;
1614	if (scp == cur_console)
1615	    update_leds(scp->status);
1616	return 0;
1617
1618    case KDGKBSTATE:    	/* get keyboard state (locks) */
1619	*(int *)data = scp->status & LOCK_KEY_MASK;
1620	return 0;
1621
1622    case KDSETRAD:      	/* set keyboard repeat & delay rates */
1623	if (*(int *)data & ~0x7f)
1624	    return EINVAL;
1625	if (sc_kbdc != NULL)
1626	    set_keyboard(KBDC_SET_TYPEMATIC, *(int *)data);
1627	return 0;
1628
1629    case KDSKBMODE:     	/* set keyboard mode */
1630	switch (*(int *)data) {
1631	case K_RAW: 		/* switch to RAW scancode mode */
1632	    scp->status &= ~KBD_CODE_MODE;
1633	    scp->status |= KBD_RAW_MODE;
1634	    return 0;
1635
1636	case K_CODE: 		/* switch to CODE mode */
1637	    scp->status &= ~KBD_RAW_MODE;
1638	    scp->status |= KBD_CODE_MODE;
1639	    return 0;
1640
1641	case K_XLATE:   	/* switch to XLT ascii mode */
1642	    if (scp == cur_console && scp->status & KBD_RAW_MODE)
1643		shfts = ctls = alts = agrs = metas = accents = 0;
1644	    scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
1645	    return 0;
1646	default:
1647	    return EINVAL;
1648	}
1649	/* NOT REACHED */
1650
1651    case KDGKBMODE:     	/* get keyboard mode */
1652	*(int *)data = (scp->status & KBD_RAW_MODE) ? K_RAW :
1653		((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
1654	return 0;
1655
1656    case KDMKTONE:      	/* sound the bell */
1657	if (*(int*)data)
1658	    do_bell(scp, (*(int*)data)&0xffff,
1659		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1660	else
1661	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1662	return 0;
1663
1664    case KIOCSOUND:     	/* make tone (*data) hz */
1665	if (scp == cur_console) {
1666	    if (*(int*)data) {
1667		int pitch = timer_freq / *(int*)data;
1668
1669		/* set command for counter 2, 2 byte write */
1670		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1671		    return EBUSY;
1672
1673		/* set pitch */
1674		outb(TIMER_CNTR2, pitch);
1675		outb(TIMER_CNTR2, (pitch>>8));
1676
1677		/* enable counter 2 output to speaker */
1678		outb(IO_PPI, inb(IO_PPI) | 3);
1679	    }
1680	    else {
1681		/* disable counter 2 output to speaker */
1682		outb(IO_PPI, inb(IO_PPI) & 0xFC);
1683		release_timer2();
1684	    }
1685	}
1686	return 0;
1687
1688    case KDGKBTYPE:     	/* get keyboard type */
1689	*(int *)data = 0;  	/* type not known (yet) */
1690	return 0;
1691
1692    case KDSETLED:      	/* set keyboard LED status */
1693	if (*(int *)data & ~LED_MASK)
1694	    return EINVAL;
1695	scp->status &= ~LED_MASK;
1696	scp->status |= *(int *)data;
1697	if (scp == cur_console)
1698	    update_leds(scp->status);
1699	return 0;
1700
1701    case KDGETLED:      	/* get keyboard LED status */
1702	*(int *)data = scp->status & LED_MASK;
1703	return 0;
1704
1705    case GETFKEY:       	/* get functionkey string */
1706	if (*(u_short*)data < n_fkey_tab) {
1707	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1708	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1709		  fkey_tab[ptr->keynum].len);
1710	    ptr->flen = fkey_tab[ptr->keynum].len;
1711	    return 0;
1712	}
1713	else
1714	    return EINVAL;
1715
1716    case SETFKEY:       	/* set functionkey string */
1717	if (*(u_short*)data < n_fkey_tab) {
1718	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1719	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1720		  min(ptr->flen, MAXFK));
1721	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1722	    return 0;
1723	}
1724	else
1725	    return EINVAL;
1726
1727    case GIO_SCRNMAP:   	/* get output translation table */
1728	bcopy(&scr_map, data, sizeof(scr_map));
1729	return 0;
1730
1731    case PIO_SCRNMAP:   	/* set output translation table */
1732	bcopy(data, &scr_map, sizeof(scr_map));
1733	for (i=0; i<sizeof(scr_map); i++)
1734	    scr_rmap[scr_map[i]] = i;
1735	return 0;
1736
1737    case GIO_KEYMAP:    	/* get keyboard translation table */
1738	bcopy(&key_map, data, sizeof(key_map));
1739	return 0;
1740
1741    case PIO_KEYMAP:    	/* set keyboard translation table */
1742	accents = 0;
1743	bzero(&accent_map, sizeof(accent_map));
1744	bcopy(data, &key_map, sizeof(key_map));
1745	return 0;
1746
1747    case GIO_DEADKEYMAP:    	/* get accent key translation table */
1748	bcopy(&accent_map, data, sizeof(accent_map));
1749	return 0;
1750
1751    case PIO_DEADKEYMAP:    	/* set accent key translation table */
1752	accents = 0;
1753	bcopy(data, &accent_map, sizeof(accent_map));
1754	return 0;
1755
1756    case PIO_FONT8x8:   	/* set 8x8 dot font */
1757	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1758	    return ENXIO;
1759	bcopy(data, font_8, 8*256);
1760	fonts_loaded |= FONT_8;
1761	/*
1762	 * FONT KLUDGE
1763	 * Always use the font page #0. XXX
1764	 * Don't load if the current font size is not 8x8.
1765	 */
1766	if (ISTEXTSC(cur_console) && (cur_console->font_size < 14))
1767	    copy_font(cur_console, LOAD, 8, font_8);
1768	return 0;
1769
1770    case GIO_FONT8x8:   	/* get 8x8 dot font */
1771	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1772	    return ENXIO;
1773	if (fonts_loaded & FONT_8) {
1774	    bcopy(font_8, data, 8*256);
1775	    return 0;
1776	}
1777	else
1778	    return ENXIO;
1779
1780    case PIO_FONT8x14:  	/* set 8x14 dot font */
1781	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1782	    return ENXIO;
1783	bcopy(data, font_14, 14*256);
1784	fonts_loaded |= FONT_14;
1785	/*
1786	 * FONT KLUDGE
1787	 * Always use the font page #0. XXX
1788	 * Don't load if the current font size is not 8x14.
1789	 */
1790	if (ISTEXTSC(cur_console)
1791	    && (cur_console->font_size >= 14) && (cur_console->font_size < 16))
1792	    copy_font(cur_console, LOAD, 14, font_14);
1793	return 0;
1794
1795    case GIO_FONT8x14:  	/* get 8x14 dot font */
1796	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1797	    return ENXIO;
1798	if (fonts_loaded & FONT_14) {
1799	    bcopy(font_14, data, 14*256);
1800	    return 0;
1801	}
1802	else
1803	    return ENXIO;
1804
1805    case PIO_FONT8x16:  	/* set 8x16 dot font */
1806	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1807	    return ENXIO;
1808	bcopy(data, font_16, 16*256);
1809	fonts_loaded |= FONT_16;
1810	/*
1811	 * FONT KLUDGE
1812	 * Always use the font page #0. XXX
1813	 * Don't load if the current font size is not 8x16.
1814	 */
1815	if (ISTEXTSC(cur_console) && (cur_console->font_size >= 16))
1816	    copy_font(cur_console, LOAD, 16, font_16);
1817	return 0;
1818
1819    case GIO_FONT8x16:  	/* get 8x16 dot font */
1820	if (!ISFONTAVAIL(get_adapter(scp)->va_flags))
1821	    return ENXIO;
1822	if (fonts_loaded & FONT_16) {
1823	    bcopy(font_16, data, 16*256);
1824	    return 0;
1825	}
1826	else
1827	    return ENXIO;
1828    default:
1829	break;
1830    }
1831
1832    error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1833    if (error != ENOIOCTL)
1834	return(error);
1835    error = ttioctl(tp, cmd, data, flag);
1836    if (error != ENOIOCTL)
1837	return(error);
1838    return(ENOTTY);
1839}
1840
1841static void
1842scstart(struct tty *tp)
1843{
1844    struct clist *rbp;
1845    int s, len;
1846    u_char buf[PCBURST];
1847    scr_stat *scp = sc_get_scr_stat(tp->t_dev);
1848
1849    if (scp->status & SLKED || blink_in_progress)
1850	return; /* XXX who repeats the call when the above flags are cleared? */
1851    s = spltty();
1852    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1853	tp->t_state |= TS_BUSY;
1854	rbp = &tp->t_outq;
1855	while (rbp->c_cc) {
1856	    len = q_to_b(rbp, buf, PCBURST);
1857	    splx(s);
1858	    ansi_put(scp, buf, len);
1859	    s = spltty();
1860	}
1861	tp->t_state &= ~TS_BUSY;
1862	ttwwakeup(tp);
1863    }
1864    splx(s);
1865}
1866
1867static void
1868scmousestart(struct tty *tp)
1869{
1870    struct clist *rbp;
1871    int s;
1872    u_char buf[PCBURST];
1873
1874    s = spltty();
1875    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1876	tp->t_state |= TS_BUSY;
1877	rbp = &tp->t_outq;
1878	while (rbp->c_cc) {
1879	    q_to_b(rbp, buf, PCBURST);
1880	}
1881	tp->t_state &= ~TS_BUSY;
1882	ttwwakeup(tp);
1883    }
1884    splx(s);
1885}
1886
1887static void
1888sccnprobe(struct consdev *cp)
1889{
1890    struct isa_device *dvp;
1891
1892    /*
1893     * Take control if we are the highest priority enabled display device.
1894     */
1895    dvp = find_display();
1896    if (dvp == NULL || dvp->id_driver != &scdriver) {
1897	cp->cn_pri = CN_DEAD;
1898	return;
1899    }
1900
1901    if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
1902	cp->cn_pri = CN_DEAD;
1903	return;
1904    }
1905
1906    /* initialize required fields */
1907    cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
1908    cp->cn_pri = CN_INTERNAL;
1909
1910    sc_kbdc = kbdc_open(sc_port);
1911}
1912
1913static void
1914sccninit(struct consdev *cp)
1915{
1916    scinit();
1917}
1918
1919static void
1920sccnputc(dev_t dev, int c)
1921{
1922    u_char buf[1];
1923    int s;
1924    scr_stat *scp = console[0];
1925    term_stat save = scp->term;
1926
1927    scp->term = kernel_console;
1928    current_default = &kernel_default;
1929    if (scp == cur_console && !ISGRAPHSC(scp))
1930	remove_cursor_image(scp);
1931    buf[0] = c;
1932    ansi_put(scp, buf, 1);
1933    kernel_console = scp->term;
1934    current_default = &user_default;
1935    scp->term = save;
1936
1937    s = spltty();	/* block scintr and scrn_timer */
1938    sccnupdate(scp);
1939    splx(s);
1940}
1941
1942static int
1943sccngetc(dev_t dev)
1944{
1945    int s = spltty();	/* block scintr and scrn_timer while we poll */
1946    int c;
1947
1948    /*
1949     * Stop the screen saver and update the screen if necessary.
1950     * What if we have been running in the screen saver code... XXX
1951     */
1952    scsplash_stick(FALSE);
1953    run_scrn_saver = FALSE;
1954    sccnupdate(cur_console);
1955
1956    c = scgetc(SCGETC_CN);
1957    splx(s);
1958    return(c);
1959}
1960
1961static int
1962sccncheckc(dev_t dev)
1963{
1964    int s = spltty();	/* block scintr and scrn_timer while we poll */
1965    int c;
1966
1967    scsplash_stick(FALSE);
1968    run_scrn_saver = FALSE;
1969    sccnupdate(cur_console);
1970
1971    c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
1972    splx(s);
1973    return(c == NOKEY ? -1 : c);	/* c == -1 can't happen */
1974}
1975
1976static void
1977sccnupdate(scr_stat *scp)
1978{
1979    /* this is a cut-down version of scrn_timer()... */
1980
1981    if (font_loading_in_progress)
1982	return;
1983
1984    if (panicstr || shutdown_in_progress) {
1985	scsplash_stick(FALSE);
1986	run_scrn_saver = FALSE;
1987    } else if (scp != cur_console) {
1988	return;
1989    }
1990
1991    if (!run_scrn_saver)
1992	scrn_idle = FALSE;
1993    if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
1994	if (scp->status & SAVER_RUNNING)
1995            stop_scrn_saver(current_saver);
1996
1997    if (scp != cur_console || blink_in_progress || switch_in_progress)
1998	return;
1999
2000    if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
2001	scrn_update(scp, TRUE);
2002}
2003
2004scr_stat
2005*sc_get_scr_stat(dev_t dev)
2006{
2007    int unit = minor(dev);
2008
2009    if (unit == SC_CONSOLE)
2010	return console[0];
2011    if (unit >= MAXCONS || unit < 0)
2012	return(NULL);
2013    return console[unit];
2014}
2015
2016static int
2017get_scr_num()
2018{
2019    int i = 0;
2020
2021    while ((i < MAXCONS) && (cur_console != console[i]))
2022	i++;
2023    return i < MAXCONS ? i : 0;
2024}
2025
2026static void
2027scrn_timer(void *arg)
2028{
2029    struct timeval tv;
2030    scr_stat *scp;
2031    int s;
2032
2033    /* don't do anything when we are touching font */
2034    if (font_loading_in_progress) {
2035	if (arg)
2036	    timeout(scrn_timer, (void *)TRUE, hz / 10);
2037	return;
2038    }
2039    s = spltty();
2040
2041    /*
2042     * With release 2.1 of the Xaccel server, the keyboard is left
2043     * hanging pretty often. Apparently an interrupt from the
2044     * keyboard is lost, and I don't know why (yet).
2045     * This ugly hack calls scintr if input is ready for the keyboard
2046     * and conveniently hides the problem.			XXX
2047     */
2048    /* Try removing anything stuck in the keyboard controller; whether
2049     * it's a keyboard scan code or mouse data. `scintr()' doesn't
2050     * read the mouse data directly, but `kbdio' routines will, as a
2051     * side effect.
2052     */
2053    if (kbdc_lock(sc_kbdc, TRUE)) {
2054	/*
2055	 * We have seen the lock flag is not set. Let's reset the flag early;
2056	 * otherwise `update_led()' failes which may want the lock
2057	 * during `scintr()'.
2058	 */
2059	kbdc_lock(sc_kbdc, FALSE);
2060	if (kbdc_data_ready(sc_kbdc))
2061	    scintr(0);
2062    }
2063
2064    scp = cur_console;
2065
2066    /* should we stop the screen saver? */
2067    getmicrouptime(&tv);
2068    if (panicstr || shutdown_in_progress) {
2069	scsplash_stick(FALSE);
2070	run_scrn_saver = FALSE;
2071    }
2072    if (run_scrn_saver) {
2073	scrn_idle = (tv.tv_sec > scrn_time_stamp + scrn_blank_time);
2074    } else {
2075	scrn_time_stamp = tv.tv_sec;
2076	scrn_idle = FALSE;
2077	if (scrn_blank_time > 0)
2078	    run_scrn_saver = TRUE;
2079    }
2080    if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2081	if (scp->status & SAVER_RUNNING)
2082            stop_scrn_saver(current_saver);
2083
2084    /* should we just return ? */
2085    if (blink_in_progress || switch_in_progress) {
2086	if (arg)
2087	    timeout(scrn_timer, (void *)TRUE, hz / 10);
2088	splx(s);
2089	return;
2090    }
2091
2092    /* Update the screen */
2093    if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
2094	scrn_update(scp, TRUE);
2095
2096    /* should we activate the screen saver? */
2097    if ((saver_mode == CONS_LKM_SAVER) && scrn_idle)
2098	if (!ISGRAPHSC(scp) || (scp->status & SAVER_RUNNING))
2099	    scrn_saver(current_saver, TRUE);
2100
2101    if (arg)
2102	timeout(scrn_timer, (void *)TRUE, hz / 25);
2103    splx(s);
2104}
2105
2106static void
2107scrn_update(scr_stat *scp, int show_cursor)
2108{
2109    /* update screen image */
2110    if (scp->start <= scp->end)
2111        sc_bcopy(scp, scp->scr_buf, scp->start, scp->end, 0);
2112
2113    /* we are not to show the cursor and the mouse pointer... */
2114    if (!show_cursor) {
2115        scp->end = 0;
2116        scp->start = scp->xsize*scp->ysize - 1;
2117	return;
2118    }
2119
2120    /* update "pseudo" mouse pointer image */
2121    if (scp->status & MOUSE_VISIBLE) {
2122        /* did mouse move since last time ? */
2123        if (scp->status & MOUSE_MOVED) {
2124            /* do we need to remove old mouse pointer image ? */
2125            if (scp->mouse_cut_start != NULL ||
2126                (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2127                (scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->end) {
2128                remove_mouse_image(scp);
2129            }
2130            scp->status &= ~MOUSE_MOVED;
2131            draw_mouse_image(scp);
2132        }
2133        else {
2134            /* mouse didn't move, has it been overwritten ? */
2135            if ((scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->start &&
2136                (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2137                draw_mouse_image(scp);
2138            }
2139        }
2140    }
2141
2142    /* update cursor image */
2143    if (scp->status & CURSOR_ENABLED) {
2144        /* did cursor move since last time ? */
2145        if (scp->cursor_pos != scp->cursor_oldpos) {
2146            /* do we need to remove old cursor image ? */
2147            if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2148                ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2149                remove_cursor_image(scp);
2150            }
2151            scp->cursor_oldpos = scp->cursor_pos;
2152            draw_cursor_image(scp);
2153        }
2154        else {
2155            /* cursor didn't move, has it been overwritten ? */
2156            if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2157                scp->cursor_pos - scp->scr_buf <= scp->end) {
2158                draw_cursor_image(scp);
2159            } else {
2160                /* if its a blinking cursor, we may have to update it */
2161		if (sc_flags & BLINK_CURSOR)
2162                    draw_cursor_image(scp);
2163            }
2164        }
2165        blinkrate++;
2166    }
2167
2168    if (scp->mouse_cut_start != NULL)
2169        draw_cutmarking(scp);
2170
2171    scp->end = 0;
2172    scp->start = scp->xsize*scp->ysize - 1;
2173}
2174
2175int
2176add_scrn_saver(void (*this_saver)(int))
2177{
2178#ifdef SC_SPLASH_SCREEN
2179    if (current_saver == scsplash) {
2180	scsplash_stick(FALSE);
2181        stop_scrn_saver(scsplash);
2182    }
2183#endif
2184
2185    if (current_saver != default_saver)
2186	return EBUSY;
2187    run_scrn_saver = FALSE;
2188    saver_mode = CONS_LKM_SAVER;
2189    current_saver = this_saver;
2190    return 0;
2191}
2192
2193int
2194remove_scrn_saver(void (*this_saver)(int))
2195{
2196    if (current_saver != this_saver)
2197	return EINVAL;
2198
2199    /*
2200     * In order to prevent `current_saver' from being called by
2201     * the timeout routine `scrn_timer()' while we manipulate
2202     * the saver list, we shall set `current_saver' to `none_saver'
2203     * before stopping the current saver, rather than blocking by `splXX()'.
2204     */
2205    current_saver = none_saver;
2206    if (scrn_blanked > 0)
2207        stop_scrn_saver(this_saver);
2208
2209    if (scrn_blanked > 0)
2210	return EBUSY;	/* XXX */
2211
2212    current_saver = default_saver;
2213    return 0;
2214}
2215
2216static void
2217scrn_saver(void (*saver)(int), int blank)
2218{
2219    static int busy = FALSE;
2220
2221    if (busy)
2222	return;
2223    busy = TRUE;
2224    (*saver)(blank);
2225    busy = FALSE;
2226}
2227
2228static void
2229stop_scrn_saver(void (*saver)(int))
2230{
2231    scrn_saver(saver, FALSE);
2232    run_scrn_saver = FALSE;
2233    /* the screen saver may have chosen not to stop after all... */
2234    if (scrn_blanked > 0)
2235	return;
2236
2237    mark_all(cur_console);
2238    if (delayed_next_scr)
2239	switch_scr(cur_console, delayed_next_scr - 1);
2240    wakeup((caddr_t)&scrn_blanked);
2241}
2242
2243static int
2244wait_scrn_saver_stop(void)
2245{
2246    int error = 0;
2247
2248    while (scrn_blanked > 0) {
2249	run_scrn_saver = FALSE;
2250	error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2251	run_scrn_saver = FALSE;
2252	if (error != ERESTART)
2253	    break;
2254    }
2255    return error;
2256}
2257
2258void
2259sc_clear_screen(scr_stat *scp)
2260{
2261    move_crsr(scp, 0, 0);
2262    scp->cursor_oldpos = scp->cursor_pos;
2263    fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2264	  scp->xsize * scp->ysize);
2265    mark_all(scp);
2266    remove_cutmarking(scp);
2267}
2268
2269static int
2270switch_scr(scr_stat *scp, u_int next_scr)
2271{
2272    /* delay switch if actively updating screen */
2273    if (scrn_blanked > 0 || write_in_progress || blink_in_progress) {
2274	scsplash_stick(FALSE);
2275	run_scrn_saver = FALSE;
2276	delayed_next_scr = next_scr+1;
2277	return 0;
2278    }
2279
2280    if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2281	switch_in_progress = FALSE;
2282
2283    if (next_scr >= MAXCONS || switch_in_progress ||
2284	(cur_console->smode.mode == VT_AUTO && ISGRAPHSC(cur_console))) {
2285	do_bell(scp, BELL_PITCH, BELL_DURATION);
2286	return EINVAL;
2287    }
2288
2289    /* is the wanted virtual console open ? */
2290    if (next_scr) {
2291	struct tty *tp = VIRTUAL_TTY(next_scr);
2292	if (!(tp->t_state & TS_ISOPEN)) {
2293	    do_bell(scp, BELL_PITCH, BELL_DURATION);
2294	    return EINVAL;
2295	}
2296    }
2297
2298    switch_in_progress = TRUE;
2299    old_scp = cur_console;
2300    new_scp = console[next_scr];
2301    wakeup((caddr_t)&new_scp->smode);
2302    if (new_scp == old_scp) {
2303	switch_in_progress = FALSE;
2304	delayed_next_scr = FALSE;
2305	return 0;
2306    }
2307
2308    /* has controlling process died? */
2309    if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2310	old_scp->smode.mode = VT_AUTO;
2311    if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2312	new_scp->smode.mode = VT_AUTO;
2313
2314    /* check the modes and switch appropriately */
2315    if (old_scp->smode.mode == VT_PROCESS) {
2316	old_scp->status |= SWITCH_WAIT_REL;
2317	psignal(old_scp->proc, old_scp->smode.relsig);
2318    }
2319    else {
2320	exchange_scr();
2321	if (new_scp->smode.mode == VT_PROCESS) {
2322	    new_scp->status |= SWITCH_WAIT_ACQ;
2323	    psignal(new_scp->proc, new_scp->smode.acqsig);
2324	}
2325	else
2326	    switch_in_progress = FALSE;
2327    }
2328    return 0;
2329}
2330
2331static void
2332exchange_scr(void)
2333{
2334    move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2335    cur_console = new_scp;
2336    if (old_scp->mode != new_scp->mode || ISUNKNOWNSC(old_scp))
2337	set_mode(new_scp);
2338    move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2339    if (ISTEXTSC(new_scp) && (sc_flags & CHAR_CURSOR))
2340	set_destructive_cursor(new_scp);
2341    if (ISGRAPHSC(old_scp))
2342	load_palette(new_scp, palette);
2343    if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2344        old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2345	shfts = ctls = alts = agrs = metas = accents = 0;
2346    set_border(new_scp, new_scp->border);
2347    update_leds(new_scp->status);
2348    delayed_next_scr = FALSE;
2349    mark_all(new_scp);
2350}
2351
2352static void
2353scan_esc(scr_stat *scp, u_char c)
2354{
2355    static u_char ansi_col[16] =
2356	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2357    int i, n;
2358    u_short *src, *dst, count;
2359
2360    if (scp->term.esc == 1) {	/* seen ESC */
2361	switch (c) {
2362
2363	case '7':   /* Save cursor position */
2364	    scp->saved_xpos = scp->xpos;
2365	    scp->saved_ypos = scp->ypos;
2366	    break;
2367
2368	case '8':   /* Restore saved cursor position */
2369	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2370		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2371	    break;
2372
2373	case '[':   /* Start ESC [ sequence */
2374	    scp->term.esc = 2;
2375	    scp->term.last_param = -1;
2376	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2377		scp->term.param[i] = 1;
2378	    scp->term.num_param = 0;
2379	    return;
2380
2381	case 'M':   /* Move cursor up 1 line, scroll if at top */
2382	    if (scp->ypos > 0)
2383		move_crsr(scp, scp->xpos, scp->ypos - 1);
2384	    else {
2385		bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2386		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2387		fillw(scp->term.cur_color | scr_map[0x20],
2388		      scp->scr_buf, scp->xsize);
2389    		mark_all(scp);
2390	    }
2391	    break;
2392#if notyet
2393	case 'Q':
2394	    scp->term.esc = 4;
2395	    return;
2396#endif
2397	case 'c':   /* Clear screen & home */
2398	    sc_clear_screen(scp);
2399	    break;
2400
2401	case '(':   /* iso-2022: designate 94 character set to G0 */
2402	    scp->term.esc = 5;
2403	    return;
2404	}
2405    }
2406    else if (scp->term.esc == 2) {	/* seen ESC [ */
2407	if (c >= '0' && c <= '9') {
2408	    if (scp->term.num_param < MAX_ESC_PAR) {
2409	    if (scp->term.last_param != scp->term.num_param) {
2410		scp->term.last_param = scp->term.num_param;
2411		scp->term.param[scp->term.num_param] = 0;
2412	    }
2413	    else
2414		scp->term.param[scp->term.num_param] *= 10;
2415	    scp->term.param[scp->term.num_param] += c - '0';
2416	    return;
2417	    }
2418	}
2419	scp->term.num_param = scp->term.last_param + 1;
2420	switch (c) {
2421
2422	case ';':
2423	    if (scp->term.num_param < MAX_ESC_PAR)
2424		return;
2425	    break;
2426
2427	case '=':
2428	    scp->term.esc = 3;
2429	    scp->term.last_param = -1;
2430	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2431		scp->term.param[i] = 1;
2432	    scp->term.num_param = 0;
2433	    return;
2434
2435	case 'A':   /* up n rows */
2436	    n = scp->term.param[0]; if (n < 1) n = 1;
2437	    move_crsr(scp, scp->xpos, scp->ypos - n);
2438	    break;
2439
2440	case 'B':   /* down n rows */
2441	    n = scp->term.param[0]; if (n < 1) n = 1;
2442	    move_crsr(scp, scp->xpos, scp->ypos + n);
2443	    break;
2444
2445	case 'C':   /* right n columns */
2446	    n = scp->term.param[0]; if (n < 1) n = 1;
2447	    move_crsr(scp, scp->xpos + n, scp->ypos);
2448	    break;
2449
2450	case 'D':   /* left n columns */
2451	    n = scp->term.param[0]; if (n < 1) n = 1;
2452	    move_crsr(scp, scp->xpos - n, scp->ypos);
2453	    break;
2454
2455	case 'E':   /* cursor to start of line n lines down */
2456	    n = scp->term.param[0]; if (n < 1) n = 1;
2457	    move_crsr(scp, 0, scp->ypos + n);
2458	    break;
2459
2460	case 'F':   /* cursor to start of line n lines up */
2461	    n = scp->term.param[0]; if (n < 1) n = 1;
2462	    move_crsr(scp, 0, scp->ypos - n);
2463	    break;
2464
2465	case 'f':   /* Cursor move */
2466	case 'H':
2467	    if (scp->term.num_param == 0)
2468		move_crsr(scp, 0, 0);
2469	    else if (scp->term.num_param == 2)
2470		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2471	    break;
2472
2473	case 'J':   /* Clear all or part of display */
2474	    if (scp->term.num_param == 0)
2475		n = 0;
2476	    else
2477		n = scp->term.param[0];
2478	    switch (n) {
2479	    case 0: /* clear form cursor to end of display */
2480		fillw(scp->term.cur_color | scr_map[0x20],
2481		      scp->cursor_pos,
2482		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2483    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2484    		mark_for_update(scp, scp->xsize * scp->ysize - 1);
2485		remove_cutmarking(scp);
2486		break;
2487	    case 1: /* clear from beginning of display to cursor */
2488		fillw(scp->term.cur_color | scr_map[0x20],
2489		      scp->scr_buf,
2490		      scp->cursor_pos - scp->scr_buf);
2491    		mark_for_update(scp, 0);
2492    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2493		remove_cutmarking(scp);
2494		break;
2495	    case 2: /* clear entire display */
2496		fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2497		      scp->xsize * scp->ysize);
2498		mark_all(scp);
2499		remove_cutmarking(scp);
2500		break;
2501	    }
2502	    break;
2503
2504	case 'K':   /* Clear all or part of line */
2505	    if (scp->term.num_param == 0)
2506		n = 0;
2507	    else
2508		n = scp->term.param[0];
2509	    switch (n) {
2510	    case 0: /* clear form cursor to end of line */
2511		fillw(scp->term.cur_color | scr_map[0x20],
2512		      scp->cursor_pos,
2513		      scp->xsize - scp->xpos);
2514    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2515    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2516				scp->xsize - 1 - scp->xpos);
2517		break;
2518	    case 1: /* clear from beginning of line to cursor */
2519		fillw(scp->term.cur_color | scr_map[0x20],
2520		      scp->cursor_pos - scp->xpos,
2521		      scp->xpos + 1);
2522    		mark_for_update(scp, scp->ypos * scp->xsize);
2523    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2524		break;
2525	    case 2: /* clear entire line */
2526		fillw(scp->term.cur_color | scr_map[0x20],
2527		      scp->cursor_pos - scp->xpos,
2528		      scp->xsize);
2529    		mark_for_update(scp, scp->ypos * scp->xsize);
2530    		mark_for_update(scp, (scp->ypos + 1) * scp->xsize - 1);
2531		break;
2532	    }
2533	    break;
2534
2535	case 'L':   /* Insert 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	    src = scp->scr_buf + scp->ypos * scp->xsize;
2540	    dst = src + n * scp->xsize;
2541	    count = scp->ysize - (scp->ypos + n);
2542	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2543	    fillw(scp->term.cur_color | scr_map[0x20], src,
2544		  n * scp->xsize);
2545	    mark_for_update(scp, scp->ypos * scp->xsize);
2546	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2547	    break;
2548
2549	case 'M':   /* Delete n lines */
2550	    n = scp->term.param[0]; if (n < 1) n = 1;
2551	    if (n > scp->ysize - scp->ypos)
2552		n = scp->ysize - scp->ypos;
2553	    dst = scp->scr_buf + scp->ypos * scp->xsize;
2554	    src = dst + n * scp->xsize;
2555	    count = scp->ysize - (scp->ypos + n);
2556	    bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2557	    src = dst + count * scp->xsize;
2558	    fillw(scp->term.cur_color | scr_map[0x20], src,
2559		  n * scp->xsize);
2560	    mark_for_update(scp, scp->ypos * scp->xsize);
2561	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2562	    break;
2563
2564	case 'P':   /* Delete 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	    dst = scp->cursor_pos;
2569	    src = dst + n;
2570	    count = scp->xsize - (scp->xpos + n);
2571	    bcopy(src, dst, count * sizeof(u_short));
2572	    src = dst + count;
2573	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2574	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2575	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count - 1);
2576	    break;
2577
2578	case '@':   /* Insert n chars */
2579	    n = scp->term.param[0]; if (n < 1) n = 1;
2580	    if (n > scp->xsize - scp->xpos)
2581		n = scp->xsize - scp->xpos;
2582	    src = scp->cursor_pos;
2583	    dst = src + n;
2584	    count = scp->xsize - (scp->xpos + n);
2585	    bcopy(src, dst, count * sizeof(u_short));
2586	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
2587	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2588	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count - 1);
2589	    break;
2590
2591	case 'S':   /* scroll up n lines */
2592	    n = scp->term.param[0]; if (n < 1)  n = 1;
2593	    if (n > scp->ysize)
2594		n = scp->ysize;
2595	    bcopy(scp->scr_buf + (scp->xsize * n),
2596		   scp->scr_buf,
2597		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
2598	    fillw(scp->term.cur_color | scr_map[0x20],
2599		  scp->scr_buf + scp->xsize * (scp->ysize - n),
2600		  scp->xsize * n);
2601    	    mark_all(scp);
2602	    break;
2603
2604	case 'T':   /* scroll down n lines */
2605	    n = scp->term.param[0]; if (n < 1)  n = 1;
2606	    if (n > scp->ysize)
2607		n = scp->ysize;
2608	    bcopy(scp->scr_buf,
2609		  scp->scr_buf + (scp->xsize * n),
2610		  scp->xsize * (scp->ysize - n) *
2611		  sizeof(u_short));
2612	    fillw(scp->term.cur_color | scr_map[0x20],
2613		  scp->scr_buf, scp->xsize * n);
2614    	    mark_all(scp);
2615	    break;
2616
2617	case 'X':   /* erase n characters in line */
2618	    n = scp->term.param[0]; if (n < 1)  n = 1;
2619	    if (n > scp->xsize - scp->xpos)
2620		n = scp->xsize - scp->xpos;
2621	    fillw(scp->term.cur_color | scr_map[0x20],
2622		  scp->cursor_pos, n);
2623	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2624	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n - 1);
2625	    break;
2626
2627	case 'Z':   /* move n tabs backwards */
2628	    n = scp->term.param[0]; if (n < 1)  n = 1;
2629	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2630		i -= 8*n;
2631	    else
2632		i -= 8*(n-1);
2633	    if (i < 0)
2634		i = 0;
2635	    move_crsr(scp, i, scp->ypos);
2636	    break;
2637
2638	case '`':   /* move cursor to column n */
2639	    n = scp->term.param[0]; if (n < 1)  n = 1;
2640	    move_crsr(scp, n - 1, scp->ypos);
2641	    break;
2642
2643	case 'a':   /* move cursor n columns to the right */
2644	    n = scp->term.param[0]; if (n < 1)  n = 1;
2645	    move_crsr(scp, scp->xpos + n, scp->ypos);
2646	    break;
2647
2648	case 'd':   /* move cursor to row n */
2649	    n = scp->term.param[0]; if (n < 1)  n = 1;
2650	    move_crsr(scp, scp->xpos, n - 1);
2651	    break;
2652
2653	case 'e':   /* move cursor n rows down */
2654	    n = scp->term.param[0]; if (n < 1)  n = 1;
2655	    move_crsr(scp, scp->xpos, scp->ypos + n);
2656	    break;
2657
2658	case 'm':   /* change attribute */
2659	    if (scp->term.num_param == 0) {
2660		scp->term.attr_mask = NORMAL_ATTR;
2661		scp->term.cur_attr =
2662		    scp->term.cur_color = scp->term.std_color;
2663		break;
2664	    }
2665	    for (i = 0; i < scp->term.num_param; i++) {
2666		switch (n = scp->term.param[i]) {
2667		case 0: /* back to normal */
2668		    scp->term.attr_mask = NORMAL_ATTR;
2669		    scp->term.cur_attr =
2670			scp->term.cur_color = scp->term.std_color;
2671		    break;
2672		case 1: /* bold */
2673		    scp->term.attr_mask |= BOLD_ATTR;
2674		    scp->term.cur_attr = mask2attr(&scp->term);
2675		    break;
2676		case 4: /* underline */
2677		    scp->term.attr_mask |= UNDERLINE_ATTR;
2678		    scp->term.cur_attr = mask2attr(&scp->term);
2679		    break;
2680		case 5: /* blink */
2681		    scp->term.attr_mask |= BLINK_ATTR;
2682		    scp->term.cur_attr = mask2attr(&scp->term);
2683		    break;
2684		case 7: /* reverse video */
2685		    scp->term.attr_mask |= REVERSE_ATTR;
2686		    scp->term.cur_attr = mask2attr(&scp->term);
2687		    break;
2688		case 30: case 31: /* set fg color */
2689		case 32: case 33: case 34:
2690		case 35: case 36: case 37:
2691		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2692		    scp->term.cur_color =
2693			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2694		    scp->term.cur_attr = mask2attr(&scp->term);
2695		    break;
2696		case 40: case 41: /* set bg color */
2697		case 42: case 43: case 44:
2698		case 45: case 46: case 47:
2699		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2700		    scp->term.cur_color =
2701			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2702		    scp->term.cur_attr = mask2attr(&scp->term);
2703		    break;
2704		}
2705	    }
2706	    break;
2707
2708	case 's':   /* Save cursor position */
2709	    scp->saved_xpos = scp->xpos;
2710	    scp->saved_ypos = scp->ypos;
2711	    break;
2712
2713	case 'u':   /* Restore saved cursor position */
2714	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2715		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2716	    break;
2717
2718	case 'x':
2719	    if (scp->term.num_param == 0)
2720		n = 0;
2721	    else
2722		n = scp->term.param[0];
2723	    switch (n) {
2724	    case 0:     /* reset attributes */
2725		scp->term.attr_mask = NORMAL_ATTR;
2726		scp->term.cur_attr =
2727		    scp->term.cur_color = scp->term.std_color =
2728		    current_default->std_color;
2729		scp->term.rev_color = current_default->rev_color;
2730		break;
2731	    case 1:     /* set ansi background */
2732		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2733		scp->term.cur_color = scp->term.std_color =
2734		    (scp->term.std_color & 0x0F00) |
2735		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2736		scp->term.cur_attr = mask2attr(&scp->term);
2737		break;
2738	    case 2:     /* set ansi foreground */
2739		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2740		scp->term.cur_color = scp->term.std_color =
2741		    (scp->term.std_color & 0xF000) |
2742		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2743		scp->term.cur_attr = mask2attr(&scp->term);
2744		break;
2745	    case 3:     /* set ansi attribute directly */
2746		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2747		scp->term.cur_color = scp->term.std_color =
2748		    (scp->term.param[1]&0xFF)<<8;
2749		scp->term.cur_attr = mask2attr(&scp->term);
2750		break;
2751	    case 5:     /* set ansi reverse video background */
2752		scp->term.rev_color =
2753		    (scp->term.rev_color & 0x0F00) |
2754		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2755		scp->term.cur_attr = mask2attr(&scp->term);
2756		break;
2757	    case 6:     /* set ansi reverse video foreground */
2758		scp->term.rev_color =
2759		    (scp->term.rev_color & 0xF000) |
2760		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2761		scp->term.cur_attr = mask2attr(&scp->term);
2762		break;
2763	    case 7:     /* set ansi reverse video directly */
2764		scp->term.rev_color =
2765		    (scp->term.param[1]&0xFF)<<8;
2766		scp->term.cur_attr = mask2attr(&scp->term);
2767		break;
2768	    }
2769	    break;
2770
2771	case 'z':   /* switch to (virtual) console n */
2772	    if (scp->term.num_param == 1)
2773		switch_scr(scp, scp->term.param[0]);
2774	    break;
2775	}
2776    }
2777    else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2778	if (c >= '0' && c <= '9') {
2779	    if (scp->term.num_param < MAX_ESC_PAR) {
2780	    if (scp->term.last_param != scp->term.num_param) {
2781		scp->term.last_param = scp->term.num_param;
2782		scp->term.param[scp->term.num_param] = 0;
2783	    }
2784	    else
2785		scp->term.param[scp->term.num_param] *= 10;
2786	    scp->term.param[scp->term.num_param] += c - '0';
2787	    return;
2788	    }
2789	}
2790	scp->term.num_param = scp->term.last_param + 1;
2791	switch (c) {
2792
2793	case ';':
2794	    if (scp->term.num_param < MAX_ESC_PAR)
2795		return;
2796	    break;
2797
2798	case 'A':   /* set display border color */
2799	    if (scp->term.num_param == 1) {
2800		scp->border=scp->term.param[0] & 0xff;
2801		if (scp == cur_console)
2802		    set_border(cur_console, scp->border);
2803            }
2804	    break;
2805
2806	case 'B':   /* set bell pitch and duration */
2807	    if (scp->term.num_param == 2) {
2808		scp->bell_pitch = scp->term.param[0];
2809		scp->bell_duration = scp->term.param[1];
2810	    }
2811	    break;
2812
2813	case 'C':   /* set cursor type & shape */
2814	    if (scp->term.num_param == 1) {
2815		if (scp->term.param[0] & 0x01)
2816		    sc_flags |= BLINK_CURSOR;
2817		else
2818		    sc_flags &= ~BLINK_CURSOR;
2819		if ((scp->term.param[0] & 0x02)
2820		    && ISFONTAVAIL(get_adapter(scp)->va_flags))
2821		    sc_flags |= CHAR_CURSOR;
2822		else
2823		    sc_flags &= ~CHAR_CURSOR;
2824	    }
2825	    else if (scp->term.num_param == 2) {
2826		scp->cursor_start = scp->term.param[0] & 0x1F;
2827		scp->cursor_end = scp->term.param[1] & 0x1F;
2828	    }
2829	    /*
2830	     * The cursor shape is global property; all virtual consoles
2831	     * are affected. Update the cursor in the current console...
2832	     */
2833	    if (!ISGRAPHSC(cur_console)) {
2834		i = spltty();
2835		remove_cursor_image(cur_console);
2836		if (sc_flags & CHAR_CURSOR)
2837	            set_destructive_cursor(cur_console);
2838		draw_cursor_image(cur_console);
2839		splx(i);
2840	    }
2841	    break;
2842
2843	case 'F':   /* set ansi foreground */
2844	    if (scp->term.num_param == 1) {
2845		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2846		scp->term.cur_color = scp->term.std_color =
2847		    (scp->term.std_color & 0xF000)
2848		    | ((scp->term.param[0] & 0x0F) << 8);
2849		scp->term.cur_attr = mask2attr(&scp->term);
2850	    }
2851	    break;
2852
2853	case 'G':   /* set ansi background */
2854	    if (scp->term.num_param == 1) {
2855		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2856		scp->term.cur_color = scp->term.std_color =
2857		    (scp->term.std_color & 0x0F00)
2858		    | ((scp->term.param[0] & 0x0F) << 12);
2859		scp->term.cur_attr = mask2attr(&scp->term);
2860	    }
2861	    break;
2862
2863	case 'H':   /* set ansi reverse video foreground */
2864	    if (scp->term.num_param == 1) {
2865		scp->term.rev_color =
2866		    (scp->term.rev_color & 0xF000)
2867		    | ((scp->term.param[0] & 0x0F) << 8);
2868		scp->term.cur_attr = mask2attr(&scp->term);
2869	    }
2870	    break;
2871
2872	case 'I':   /* set ansi reverse video background */
2873	    if (scp->term.num_param == 1) {
2874		scp->term.rev_color =
2875		    (scp->term.rev_color & 0x0F00)
2876		    | ((scp->term.param[0] & 0x0F) << 12);
2877		scp->term.cur_attr = mask2attr(&scp->term);
2878	    }
2879	    break;
2880	}
2881    }
2882#if notyet
2883    else if (scp->term.esc == 4) {	/* seen ESC Q */
2884	/* to be filled */
2885    }
2886#endif
2887    else if (scp->term.esc == 5) {	/* seen ESC ( */
2888	switch (c) {
2889	case 'B':   /* iso-2022: desginate ASCII into G0 */
2890	    break;
2891	/* other items to be filled */
2892	default:
2893	    break;
2894	}
2895    }
2896    scp->term.esc = 0;
2897}
2898
2899static void
2900ansi_put(scr_stat *scp, u_char *buf, int len)
2901{
2902    u_char *ptr = buf;
2903
2904    /* make screensaver happy */
2905    if (!sticky_splash && scp == cur_console)
2906	run_scrn_saver = FALSE;
2907
2908    write_in_progress++;
2909outloop:
2910    if (scp->term.esc) {
2911	scan_esc(scp, *ptr++);
2912	len--;
2913    }
2914    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2915 	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
2916 	u_short cur_attr = scp->term.cur_attr;
2917 	u_short *cursor_pos = scp->cursor_pos;
2918	do {
2919	    /*
2920	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2921	     * pointers in the following to volatile should have no effect,
2922	     * but in fact speeds up this inner loop from 26 to 18 cycles
2923	     * (+ cache misses) on i486's.
2924	     */
2925#define	UCVP(ucp)	((u_char volatile *)(ucp))
2926	    *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
2927	    ptr++;
2928	    cnt--;
2929	} while (cnt && PRINTABLE(*ptr));
2930	len -= (cursor_pos - scp->cursor_pos);
2931	scp->xpos += (cursor_pos - scp->cursor_pos);
2932	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2933	mark_for_update(scp, cursor_pos - scp->scr_buf);
2934	scp->cursor_pos = cursor_pos;
2935	if (scp->xpos >= scp->xsize) {
2936	    scp->xpos = 0;
2937	    scp->ypos++;
2938	}
2939    }
2940    else  {
2941	switch(*ptr) {
2942	case 0x07:
2943	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2944	    break;
2945
2946	case 0x08:      /* non-destructive backspace */
2947	    if (scp->cursor_pos > scp->scr_buf) {
2948	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2949		scp->cursor_pos--;
2950	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2951		if (scp->xpos > 0)
2952		    scp->xpos--;
2953		else {
2954		    scp->xpos += scp->xsize - 1;
2955		    scp->ypos--;
2956		}
2957	    }
2958	    break;
2959
2960	case 0x09:  /* non-destructive tab */
2961	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2962	    scp->cursor_pos += (8 - scp->xpos % 8u);
2963	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2964	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2965	        scp->xpos = 0;
2966	        scp->ypos++;
2967	    }
2968	    break;
2969
2970	case 0x0a:  /* newline, same pos */
2971	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2972	    scp->cursor_pos += scp->xsize;
2973	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2974	    scp->ypos++;
2975	    break;
2976
2977	case 0x0c:  /* form feed, clears screen */
2978	    sc_clear_screen(scp);
2979	    break;
2980
2981	case 0x0d:  /* return, return to pos 0 */
2982	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2983	    scp->cursor_pos -= scp->xpos;
2984	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2985	    scp->xpos = 0;
2986	    break;
2987
2988	case 0x1b:  /* start escape sequence */
2989	    scp->term.esc = 1;
2990	    scp->term.num_param = 0;
2991	    break;
2992	}
2993	ptr++; len--;
2994    }
2995    /* do we have to scroll ?? */
2996    if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
2997	remove_cutmarking(scp);
2998	if (scp->history != NULL) {
2999	    bcopy(scp->scr_buf, scp->history_head,
3000		   scp->xsize * sizeof(u_short));
3001	    scp->history_head += scp->xsize;
3002	    if (scp->history_head + scp->xsize >
3003		scp->history + scp->history_size)
3004		scp->history_head = scp->history;
3005	}
3006	bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
3007	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
3008	fillw(scp->term.cur_color | scr_map[0x20],
3009	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
3010	      scp->xsize);
3011	scp->cursor_pos -= scp->xsize;
3012	scp->ypos--;
3013    	mark_all(scp);
3014    }
3015    if (len)
3016	goto outloop;
3017    write_in_progress--;
3018    if (delayed_next_scr)
3019	switch_scr(scp, delayed_next_scr - 1);
3020}
3021
3022static void
3023scinit(void)
3024{
3025    int col;
3026    int row;
3027    u_int i;
3028
3029    if (init_done != COLD)
3030	return;
3031    init_done = WARM;
3032
3033    /* extract the hardware cursor location and move it out of the way */
3034    (*biosvidsw.read_hw_cursor)(V_ADP_PRIMARY, &col, &row);
3035    (*biosvidsw.set_hw_cursor)(V_ADP_PRIMARY, -1, -1);
3036
3037    /* set up the first console */
3038    current_default = &user_default;
3039    console[0] = &main_console;
3040    init_scp(console[0]);
3041    cur_console = console[0];
3042
3043    /* copy screen to temporary buffer */
3044    if (ISTEXTSC(console[0]))
3045	generic_bcopy((ushort *)(get_adapter(console[0])->va_window), sc_buffer,
3046		      console[0]->xsize * console[0]->ysize * sizeof(u_short));
3047
3048    console[0]->scr_buf = console[0]->mouse_pos = console[0]->mouse_oldpos
3049	= sc_buffer;
3050    if (col >= console[0]->xsize)
3051	col = 0;
3052    if (row >= console[0]->ysize)
3053	row = console[0]->ysize - 1;
3054    console[0]->xpos = col;
3055    console[0]->ypos = row;
3056    console[0]->cursor_pos = console[0]->cursor_oldpos =
3057	sc_buffer + row*console[0]->xsize + col;
3058    console[0]->cursor_saveunder = *console[0]->cursor_pos;
3059    for (i=1; i<MAXCONS; i++)
3060	console[i] = NULL;
3061    kernel_console.esc = 0;
3062    kernel_console.attr_mask = NORMAL_ATTR;
3063    kernel_console.cur_attr =
3064	kernel_console.cur_color = kernel_console.std_color =
3065	kernel_default.std_color;
3066    kernel_console.rev_color = kernel_default.rev_color;
3067
3068    /* initialize mapscrn arrays to a one to one map */
3069    for (i=0; i<sizeof(scr_map); i++) {
3070	scr_map[i] = scr_rmap[i] = i;
3071    }
3072
3073    /* Save font and palette */
3074    if (ISFONTAVAIL(get_adapter(cur_console)->va_flags)) {
3075	if (fonts_loaded & FONT_16) {
3076	    copy_font(cur_console, LOAD, 16, font_16);
3077	} else {
3078	    copy_font(cur_console, SAVE, 16, font_16);
3079	    fonts_loaded = FONT_16;
3080	    set_destructive_cursor(cur_console);
3081	}
3082	/*
3083	 * FONT KLUDGE
3084	 * Always use the font page #0. XXX
3085	 */
3086	(*biosvidsw.show_font)(cur_console->adp, 0);
3087    }
3088    save_palette(cur_console, palette);
3089
3090#ifdef SC_SPLASH_SCREEN
3091    /* put up the splash. */
3092    scsplash_init(cur_console);
3093#endif
3094}
3095
3096static void
3097scshutdown(int howto, void *arg)
3098{
3099    scsplash_stick(FALSE);
3100    run_scrn_saver = FALSE;
3101    if (!cold && cur_console->smode.mode == VT_AUTO
3102	&& console[0]->smode.mode == VT_AUTO)
3103	switch_scr(cur_console, 0);
3104    shutdown_in_progress = TRUE;
3105}
3106
3107int
3108sc_clean_up(scr_stat *scp)
3109{
3110    int error;
3111
3112    if ((error = wait_scrn_saver_stop()))
3113	return error;
3114    scp->status &= ~MOUSE_VISIBLE;
3115    remove_cutmarking(scp);
3116    return 0;
3117}
3118
3119void
3120sc_alloc_scr_buffer(scr_stat *scp, int wait, int clear)
3121{
3122    if (scp->scr_buf)
3123	free(scp->scr_buf, M_DEVBUF);
3124    scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3125				     M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3126
3127    if (clear) {
3128        /* clear the screen and move the text cursor to the top-left position */
3129	sc_clear_screen(scp);
3130    } else {
3131	/* retain the current cursor position, but adjust pointers */
3132	move_crsr(scp, scp->xpos, scp->ypos);
3133	scp->cursor_oldpos = scp->cursor_pos;
3134    }
3135
3136    /* move the mouse cursor at the center of the screen */
3137    sc_move_mouse(scp, scp->xpixel / 2, scp->ypixel / 2);
3138}
3139
3140void
3141sc_alloc_cut_buffer(scr_stat *scp, int wait)
3142{
3143    if ((cut_buffer == NULL)
3144	|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
3145	if (cut_buffer != NULL)
3146	    free(cut_buffer, M_DEVBUF);
3147	cut_buffer_size = scp->xsize * scp->ysize + 1;
3148	cut_buffer = (u_char *)malloc(cut_buffer_size,
3149				    M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3150	if (cut_buffer != NULL)
3151	    cut_buffer[0] = '\0';
3152    }
3153}
3154
3155void
3156sc_alloc_history_buffer(scr_stat *scp, int lines, int extra, int wait)
3157{
3158    u_short *usp;
3159
3160    if (lines < scp->ysize)
3161	lines = scp->ysize;
3162
3163    usp = scp->history;
3164    scp->history = NULL;
3165    if (usp != NULL) {
3166	free(usp, M_DEVBUF);
3167	if (extra > 0)
3168	    extra_history_size += extra;
3169    }
3170
3171    scp->history_size = lines * scp->xsize;
3172    if (lines > imax(sc_history_size, scp->ysize))
3173	extra_history_size -= lines - imax(sc_history_size, scp->ysize);
3174    usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
3175			    M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
3176    if (usp != NULL)
3177	bzero(usp, scp->history_size * sizeof(u_short));
3178    scp->history_head = scp->history_pos = usp;
3179    scp->history = usp;
3180}
3181
3182static scr_stat
3183*alloc_scp()
3184{
3185    scr_stat *scp;
3186
3187    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3188    init_scp(scp);
3189    sc_alloc_scr_buffer(scp, TRUE, TRUE);
3190    if (ISMOUSEAVAIL(get_adapter(scp)->va_flags))
3191	sc_alloc_cut_buffer(scp, TRUE);
3192    sc_alloc_history_buffer(scp, sc_history_size, 0, TRUE);
3193/* SOS
3194    if (get_adapter(scp)->va_flags & V_ADP_MODECHANGE)
3195	set_mode(scp);
3196*/
3197    sc_clear_screen(scp);
3198    scp->cursor_saveunder = *scp->cursor_pos;
3199    return scp;
3200}
3201
3202static void
3203init_scp(scr_stat *scp)
3204{
3205    video_info_t info;
3206
3207    scp->adp = V_ADP_PRIMARY;
3208    (*biosvidsw.get_info)(scp->adp, initial_video_mode, &info);
3209
3210    scp->status = 0;
3211    scp->mode = scp->initial_mode = initial_video_mode;
3212    scp->scr_buf = NULL;
3213    if (info.vi_flags & V_INFO_GRAPHICS) {
3214	scp->status |= GRAPHICS_MODE;
3215	scp->xpixel = info.vi_width;
3216	scp->ypixel = info.vi_height;
3217	scp->xsize = info.vi_width/8;
3218	scp->ysize = info.vi_height/info.vi_cheight;
3219	scp->font_size = FONT_NONE;
3220    } else {
3221	scp->xsize = info.vi_width;
3222	scp->ysize = info.vi_height;
3223	scp->xpixel = scp->xsize*8;
3224	scp->ypixel = scp->ysize*info.vi_cheight;
3225	scp->font_size = info.vi_cheight;
3226    }
3227    scp->xoff = scp->yoff = 0;
3228    scp->xpos = scp->ypos = 0;
3229    scp->saved_xpos = scp->saved_ypos = -1;
3230    scp->start = scp->xsize * scp->ysize;
3231    scp->end = 0;
3232    scp->term.esc = 0;
3233    scp->term.attr_mask = NORMAL_ATTR;
3234    scp->term.cur_attr =
3235	scp->term.cur_color = scp->term.std_color =
3236	current_default->std_color;
3237    scp->term.rev_color = current_default->rev_color;
3238    scp->border = BG_BLACK;
3239    scp->cursor_start = *(u_int8_t *)pa_to_va(0x461);
3240    scp->cursor_end = *(u_int8_t *)pa_to_va(0x460);
3241    scp->mouse_xpos = scp->xsize*8/2;
3242    scp->mouse_ypos = scp->ysize*scp->font_size/2;
3243    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3244    scp->mouse_signal = 0;
3245    scp->mouse_pid = 0;
3246    scp->mouse_proc = NULL;
3247    scp->bell_pitch = BELL_PITCH;
3248    scp->bell_duration = BELL_DURATION;
3249    scp->status |= (*(u_int8_t *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3250    scp->status |= CURSOR_ENABLED;
3251    scp->pid = 0;
3252    scp->proc = NULL;
3253    scp->smode.mode = VT_AUTO;
3254    scp->history_head = scp->history_pos = scp->history = NULL;
3255    scp->history_size = imax(sc_history_size, scp->ysize) * scp->xsize;
3256}
3257
3258static u_char
3259*get_fstr(u_int c, u_int *len)
3260{
3261    u_int i;
3262
3263    if (!(c & FKEY))
3264	return(NULL);
3265    i = (c & 0xFF) - F_FN;
3266    if (i > n_fkey_tab)
3267	return(NULL);
3268    *len = fkey_tab[i].len;
3269    return(fkey_tab[i].str);
3270}
3271
3272static void
3273history_to_screen(scr_stat *scp)
3274{
3275    int i;
3276
3277    for (i=0; i<scp->ysize; i++)
3278	bcopy(scp->history + (((scp->history_pos - scp->history) +
3279	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3280	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3281	       scp->xsize * sizeof(u_short));
3282    mark_all(scp);
3283}
3284
3285static int
3286history_up_line(scr_stat *scp)
3287{
3288    if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3289	scp->history_head) {
3290	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3291	history_to_screen(scp);
3292	return 0;
3293    }
3294    else
3295	return -1;
3296}
3297
3298static int
3299history_down_line(scr_stat *scp)
3300{
3301    if (scp->history_pos != scp->history_head) {
3302	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3303	history_to_screen(scp);
3304	return 0;
3305    }
3306    else
3307	return -1;
3308}
3309
3310/*
3311 * scgetc(flags) - get character from keyboard.
3312 * If flags & SCGETC_CN, then avoid harmful side effects.
3313 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3314 * return NOKEY if there is nothing there.
3315 */
3316static u_int
3317scgetc(u_int flags)
3318{
3319    struct key_t *key;
3320    u_char scancode, keycode;
3321    u_int state, action;
3322    int c;
3323    static u_char esc_flag = 0, compose = 0;
3324    static u_int chr = 0;
3325
3326next_code:
3327    /* first see if there is something in the keyboard port */
3328    if (flags & SCGETC_NONBLOCK) {
3329	c = read_kbd_data_no_wait(sc_kbdc);
3330	if (c == -1)
3331	    return(NOKEY);
3332    } else {
3333	do {
3334	    c = read_kbd_data(sc_kbdc);
3335	} while(c == -1);
3336    }
3337    scancode = (u_char)c;
3338
3339    /* make screensaver happy */
3340    if (!(scancode & 0x80)) {
3341	scsplash_stick(FALSE);
3342	run_scrn_saver = FALSE;
3343    }
3344
3345    if (!(flags & SCGETC_CN)) {
3346	/* do the /dev/random device a favour */
3347	add_keyboard_randomness(scancode);
3348
3349	if (cur_console->status & KBD_RAW_MODE)
3350	    return scancode;
3351    }
3352
3353    keycode = scancode & 0x7F;
3354    switch (esc_flag) {
3355    case 0x00:      /* normal scancode */
3356	switch(scancode) {
3357	case 0xB8:  /* left alt (compose key) */
3358	    if (compose) {
3359		compose = 0;
3360		if (chr > 255) {
3361		    do_bell(cur_console,
3362			BELL_PITCH, BELL_DURATION);
3363		    chr = 0;
3364		}
3365	    }
3366	    break;
3367	case 0x38:
3368	    if (!compose) {
3369		compose = 1;
3370		chr = 0;
3371	    }
3372	    break;
3373	case 0xE0:
3374	case 0xE1:
3375	    esc_flag = scancode;
3376	    goto next_code;
3377	}
3378	break;
3379    case 0xE0:      /* 0xE0 prefix */
3380	esc_flag = 0;
3381	switch (keycode) {
3382	case 0x1C:  /* right enter key */
3383	    keycode = 0x59;
3384	    break;
3385	case 0x1D:  /* right ctrl key */
3386	    keycode = 0x5A;
3387	    break;
3388	case 0x35:  /* keypad divide key */
3389	    keycode = 0x5B;
3390	    break;
3391	case 0x37:  /* print scrn key */
3392	    keycode = 0x5C;
3393	    break;
3394	case 0x38:  /* right alt key (alt gr) */
3395	    keycode = 0x5D;
3396	    break;
3397	case 0x47:  /* grey home key */
3398	    keycode = 0x5E;
3399	    break;
3400	case 0x48:  /* grey up arrow key */
3401	    keycode = 0x5F;
3402	    break;
3403	case 0x49:  /* grey page up key */
3404	    keycode = 0x60;
3405	    break;
3406	case 0x4B:  /* grey left arrow key */
3407	    keycode = 0x61;
3408	    break;
3409	case 0x4D:  /* grey right arrow key */
3410	    keycode = 0x62;
3411	    break;
3412	case 0x4F:  /* grey end key */
3413	    keycode = 0x63;
3414	    break;
3415	case 0x50:  /* grey down arrow key */
3416	    keycode = 0x64;
3417	    break;
3418	case 0x51:  /* grey page down key */
3419	    keycode = 0x65;
3420	    break;
3421	case 0x52:  /* grey insert key */
3422	    keycode = 0x66;
3423	    break;
3424	case 0x53:  /* grey delete key */
3425	    keycode = 0x67;
3426	    break;
3427
3428	/* the following 3 are only used on the MS "Natural" keyboard */
3429	case 0x5b:  /* left Window key */
3430	    keycode = 0x69;
3431	    break;
3432	case 0x5c:  /* right Window key */
3433	    keycode = 0x6a;
3434	    break;
3435	case 0x5d:  /* menu key */
3436	    keycode = 0x6b;
3437	    break;
3438	default:    /* ignore everything else */
3439	    goto next_code;
3440	}
3441	break;
3442    case 0xE1:      /* 0xE1 prefix */
3443	esc_flag = 0;
3444	if (keycode == 0x1D)
3445	    esc_flag = 0x1D;
3446	goto next_code;
3447	/* NOT REACHED */
3448    case 0x1D:      /* pause / break */
3449	esc_flag = 0;
3450	if (keycode != 0x45)
3451	    goto next_code;
3452	keycode = 0x68;
3453	break;
3454    }
3455
3456    if (!(flags & SCGETC_CN) && (cur_console->status & KBD_CODE_MODE))
3457	return (keycode | (scancode & 0x80));
3458
3459    /* if scroll-lock pressed allow history browsing */
3460    if (cur_console->history && cur_console->status & SLKED) {
3461	int i;
3462
3463	cur_console->status &= ~CURSOR_ENABLED;
3464	if (!(cur_console->status & BUFFER_SAVED)) {
3465	    cur_console->status |= BUFFER_SAVED;
3466	    cur_console->history_save = cur_console->history_head;
3467
3468	    /* copy screen into top of history buffer */
3469	    for (i=0; i<cur_console->ysize; i++) {
3470		bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3471		       cur_console->history_head,
3472		       cur_console->xsize * sizeof(u_short));
3473		cur_console->history_head += cur_console->xsize;
3474		if (cur_console->history_head + cur_console->xsize >
3475		    cur_console->history + cur_console->history_size)
3476		    cur_console->history_head=cur_console->history;
3477	    }
3478	    cur_console->history_pos = cur_console->history_head;
3479	    history_to_screen(cur_console);
3480	}
3481	switch (scancode) {
3482	case 0x47:  /* home key */
3483	    cur_console->history_pos = cur_console->history_head;
3484	    history_to_screen(cur_console);
3485	    goto next_code;
3486
3487	case 0x4F:  /* end key */
3488	    cur_console->history_pos =
3489		WRAPHIST(cur_console, cur_console->history_head,
3490			 cur_console->xsize*cur_console->ysize);
3491	    history_to_screen(cur_console);
3492	    goto next_code;
3493
3494	case 0x48:  /* up arrow key */
3495	    if (history_up_line(cur_console))
3496		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3497	    goto next_code;
3498
3499	case 0x50:  /* down arrow key */
3500	    if (history_down_line(cur_console))
3501		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3502	    goto next_code;
3503
3504	case 0x49:  /* page up key */
3505	    for (i=0; i<cur_console->ysize; i++)
3506	    if (history_up_line(cur_console)) {
3507		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3508		break;
3509	    }
3510	    goto next_code;
3511
3512	case 0x51:  /* page down key */
3513	    for (i=0; i<cur_console->ysize; i++)
3514	    if (history_down_line(cur_console)) {
3515		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3516		break;
3517	    }
3518	    goto next_code;
3519	}
3520    }
3521
3522    if (compose) {
3523	switch (scancode) {
3524	/* key pressed process it */
3525	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
3526	    chr = (scancode - 0x40) + chr*10;
3527	    goto next_code;
3528	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
3529	    chr = (scancode - 0x47) + chr*10;
3530	    goto next_code;
3531	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
3532	    chr = (scancode - 0x4E) + chr*10;
3533	    goto next_code;
3534	case 0x52:              /* keypad 0 */
3535	    chr *= 10;
3536	    goto next_code;
3537
3538	/* key release, no interest here */
3539	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
3540	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
3541	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
3542	case 0xD2:              /* keypad 0 */
3543	    goto next_code;
3544
3545	case 0x38:              /* left alt key */
3546	    break;
3547	default:
3548	    if (chr) {
3549		compose = chr = 0;
3550		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3551		goto next_code;
3552	    }
3553	    break;
3554	}
3555    }
3556
3557    state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
3558    if ((!agrs && (cur_console->status & ALKED))
3559	|| (agrs && !(cur_console->status & ALKED)))
3560	keycode += ALTGR_OFFSET;
3561    key = &key_map.key[keycode];
3562    if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
3563	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
3564	state ^= 1;
3565
3566    /* Check for make/break */
3567    action = key->map[state];
3568    if (scancode & 0x80) {      /* key released */
3569	if (key->spcl & (0x80>>state)) {
3570	    switch (action) {
3571	    case LSH:
3572		shfts &= ~1;
3573		break;
3574	    case RSH:
3575		shfts &= ~2;
3576		break;
3577	    case LCTR:
3578		ctls &= ~1;
3579		break;
3580	    case RCTR:
3581		ctls &= ~2;
3582		break;
3583	    case LALT:
3584		alts &= ~1;
3585		break;
3586	    case RALT:
3587		alts &= ~2;
3588		break;
3589	    case NLK:
3590		nlkcnt = 0;
3591		break;
3592	    case CLK:
3593		clkcnt = 0;
3594		break;
3595	    case SLK:
3596		slkcnt = 0;
3597		break;
3598	    case ASH:
3599		agrs = 0;
3600		break;
3601	    case ALK:
3602		alkcnt = 0;
3603		break;
3604	    case META:
3605		metas = 0;
3606		break;
3607	    }
3608	}
3609	if (chr && !compose) {
3610	    action = chr;
3611	    chr = 0;
3612	    return(action);
3613	}
3614    } else {
3615	/* key pressed */
3616	if (key->spcl & (0x80>>state)) {
3617	    switch (action) {
3618	    /* LOCKING KEYS */
3619	    case NLK:
3620		if (!nlkcnt) {
3621		    nlkcnt++;
3622		    if (cur_console->status & NLKED)
3623			cur_console->status &= ~NLKED;
3624		    else
3625			cur_console->status |= NLKED;
3626		    update_leds(cur_console->status);
3627		}
3628		break;
3629	    case CLK:
3630		if (!clkcnt) {
3631		    clkcnt++;
3632		    if (cur_console->status & CLKED)
3633			cur_console->status &= ~CLKED;
3634		    else
3635			cur_console->status |= CLKED;
3636		    update_leds(cur_console->status);
3637		}
3638		break;
3639	    case SLK:
3640		if (!slkcnt) {
3641		    slkcnt++;
3642		    if (cur_console->status & SLKED) {
3643			cur_console->status &= ~SLKED;
3644			if (cur_console->status & BUFFER_SAVED){
3645			    int i;
3646			    u_short *ptr = cur_console->history_save;
3647
3648			    for (i=0; i<cur_console->ysize; i++) {
3649				bcopy(ptr,
3650				       cur_console->scr_buf +
3651				       (cur_console->xsize*i),
3652				       cur_console->xsize * sizeof(u_short));
3653				ptr += cur_console->xsize;
3654				if (ptr + cur_console->xsize >
3655				    cur_console->history +
3656				    cur_console->history_size)
3657				    ptr = cur_console->history;
3658			    }
3659			    cur_console->status &= ~BUFFER_SAVED;
3660			    cur_console->history_head=cur_console->history_save;
3661			    cur_console->status |= CURSOR_ENABLED;
3662			    mark_all(cur_console);
3663			}
3664			scstart(VIRTUAL_TTY(get_scr_num()));
3665		    }
3666		    else
3667			cur_console->status |= SLKED;
3668		    update_leds(cur_console->status);
3669		}
3670		break;
3671	    case ALK:
3672		if (!alkcnt) {
3673		    alkcnt++;
3674		    if (cur_console->status & ALKED)
3675			cur_console->status &= ~ALKED;
3676		    else
3677			cur_console->status |= ALKED;
3678		    update_leds(cur_console->status);
3679		}
3680		break;
3681
3682	    /* NON-LOCKING KEYS */
3683	    case NOP:
3684		break;
3685	    case SPSC:
3686		/* force activatation/deactivation of the screen saver */
3687		accents = 0;
3688		if (scrn_blanked <= 0) {
3689		    run_scrn_saver = TRUE;
3690		    scrn_time_stamp -= scrn_blank_time;
3691		}
3692#ifdef SC_SPLASH_SCREEN
3693		if (cold) {
3694		    /*
3695		     * While devices are being probed, the screen saver need
3696		     * to be invoked explictly. XXX
3697		     */
3698		    if (scrn_blanked > 0) {
3699			scsplash_stick(FALSE);
3700			stop_scrn_saver(current_saver);
3701		    } else {
3702			if (!ISGRAPHSC(cur_console)) {
3703			    scsplash_stick(TRUE);
3704			    scrn_saver(current_saver, TRUE);
3705			}
3706		    }
3707		}
3708#endif
3709		break;
3710	    case RBT:
3711#ifndef SC_DISABLE_REBOOT
3712		accents = 0;
3713		shutdown_nice();
3714#endif
3715		break;
3716	    case SUSP:
3717#if NAPM > 0
3718		accents = 0;
3719		apm_suspend(PMST_SUSPEND);
3720#endif
3721		break;
3722
3723	    case STBY:
3724#if NAPM > 0
3725		accents = 0;
3726		apm_suspend(PMST_STANDBY);
3727#endif
3728		break;
3729
3730	    case DBG:
3731#ifdef DDB          /* try to switch to console 0 */
3732		accents = 0;
3733		/*
3734		 * TRY to make sure the screen saver is stopped,
3735		 * and the screen is updated before switching to
3736		 * the vty0.
3737		 */
3738		scrn_timer((void *)FALSE);
3739		if (cur_console->smode.mode == VT_AUTO &&
3740		    console[0]->smode.mode == VT_AUTO)
3741		    switch_scr(cur_console, 0);
3742		Debugger("manual escape to debugger");
3743#else
3744		printf("No debugger in kernel\n");
3745#endif
3746		break;
3747	    case LSH:
3748		shfts |= 1;
3749		break;
3750	    case RSH:
3751		shfts |= 2;
3752		break;
3753	    case LCTR:
3754		ctls |= 1;
3755		break;
3756	    case RCTR:
3757		ctls |= 2;
3758		break;
3759	    case LALT:
3760		alts |= 1;
3761		break;
3762	    case RALT:
3763		alts |= 2;
3764		break;
3765	    case ASH:
3766		agrs = 1;
3767		break;
3768	    case META:
3769		metas = 1;
3770		break;
3771	    case NEXT:
3772		{
3773		int next, this = get_scr_num();
3774		accents = 0;
3775		for (next = this+1; next != this; next = (next+1)%MAXCONS) {
3776		    struct tty *tp = VIRTUAL_TTY(next);
3777		    if (tp->t_state & TS_ISOPEN) {
3778			switch_scr(cur_console, next);
3779			break;
3780		    }
3781		}
3782		}
3783		break;
3784	    case BTAB:
3785		accents = 0;
3786		return(BKEY);
3787	    default:
3788		if (action >= F_ACC && action <= L_ACC) {
3789		    /* turn it into an index */
3790		    action -= F_ACC - 1;
3791		    if ((action > accent_map.n_accs)
3792			|| (accent_map.acc[action - 1].accchar == 0)) {
3793			/*
3794			 * The index is out of range or pointing to an
3795			 * empty entry.
3796			 */
3797			accents = 0;
3798			do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3799		    }
3800		    /*
3801		     * If the same accent key has been hit twice,
3802		     * produce the accent char itself.
3803		     */
3804		    if (action == accents) {
3805			action = accent_map.acc[accents - 1].accchar;
3806			accents = 0;
3807			if (metas)
3808			    action |= MKEY;
3809			return (action);
3810		    }
3811		    /* remember the index and wait for the next key stroke */
3812		    accents = action;
3813		    break;
3814		}
3815		if (accents > 0) {
3816		    accents = 0;
3817		    do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3818		}
3819		if (action >= F_SCR && action <= L_SCR) {
3820		    switch_scr(cur_console, action - F_SCR);
3821		    break;
3822		}
3823		if (action >= F_FN && action <= L_FN)
3824		    action |= FKEY;
3825		return(action);
3826	    }
3827	}
3828	else {
3829	    if (accents) {
3830		struct acc_t *acc;
3831		int i;
3832
3833		acc = &accent_map.acc[accents - 1];
3834		accents = 0;
3835		/*
3836		 * If the accent key is followed by the space key,
3837		 * produce the accent char itself.
3838		 */
3839		if (action == ' ') {
3840		    action = acc->accchar;
3841		    if (metas)
3842			action |= MKEY;
3843		    return (action);
3844		}
3845		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
3846		    if (acc->map[i][0] == 0)	/* end of the map entry */
3847			break;
3848		    if (acc->map[i][0] == action) {
3849			action = acc->map[i][1];
3850			if (metas)
3851			    action |= MKEY;
3852			return (action);
3853		    }
3854		}
3855		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3856		goto next_code;
3857	    }
3858	    if (metas)
3859		action |= MKEY;
3860	    return(action);
3861	}
3862    }
3863    goto next_code;
3864}
3865
3866int
3867scmmap(dev_t dev, vm_offset_t offset, int nprot)
3868{
3869    if (offset > 0x20000 - PAGE_SIZE)
3870	return -1;
3871    return i386_btop((VIDEOMEM + offset));
3872}
3873
3874/*
3875 * Calculate hardware attributes word using logical attributes mask and
3876 * hardware colors
3877 */
3878
3879static int
3880mask2attr(struct term_stat *term)
3881{
3882    int attr, mask = term->attr_mask;
3883
3884    if (mask & REVERSE_ATTR) {
3885	attr = ((mask & FOREGROUND_CHANGED) ?
3886		((term->cur_color & 0xF000) >> 4) :
3887		(term->rev_color & 0x0F00)) |
3888	       ((mask & BACKGROUND_CHANGED) ?
3889		((term->cur_color & 0x0F00) << 4) :
3890		(term->rev_color & 0xF000));
3891    } else
3892	attr = term->cur_color;
3893
3894    /* XXX: underline mapping for Hercules adapter can be better */
3895    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3896	attr ^= 0x0800;
3897    if (mask & BLINK_ATTR)
3898	attr ^= 0x8000;
3899
3900    return attr;
3901}
3902
3903static void
3904set_keyboard(int command, int data)
3905{
3906    int s;
3907
3908    if (sc_kbdc == NULL)
3909	return;
3910
3911    /* prevent the timeout routine from polling the keyboard */
3912    if (!kbdc_lock(sc_kbdc, TRUE))
3913	return;
3914
3915    /* disable the keyboard and mouse interrupt */
3916    s = spltty();
3917#if 0
3918    c = get_controller_command_byte(sc_kbdc);
3919    if ((c == -1)
3920	|| !set_controller_command_byte(sc_kbdc,
3921            kbdc_get_device_mask(sc_kbdc),
3922            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
3923                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
3924	/* CONTROLLER ERROR */
3925        kbdc_lock(sc_kbdc, FALSE);
3926	splx(s);
3927	return;
3928    }
3929    /*
3930     * Now that the keyboard controller is told not to generate
3931     * the keyboard and mouse interrupts, call `splx()' to allow
3932     * the other tty interrupts. The clock interrupt may also occur,
3933     * but the timeout routine (`scrn_timer()') will be blocked
3934     * by the lock flag set via `kbdc_lock()'
3935     */
3936    splx(s);
3937#endif
3938
3939    if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
3940        send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
3941
3942#if 0
3943    /* restore the interrupts */
3944    if (!set_controller_command_byte(sc_kbdc,
3945            kbdc_get_device_mask(sc_kbdc),
3946	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
3947	/* CONTROLLER ERROR */
3948    }
3949#else
3950    splx(s);
3951#endif
3952    kbdc_lock(sc_kbdc, FALSE);
3953}
3954
3955static void
3956update_leds(int which)
3957{
3958    static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
3959
3960    /* replace CAPS led with ALTGR led for ALTGR keyboards */
3961    if (key_map.n_keys > ALTGR_OFFSET) {
3962	if (which & ALKED)
3963	    which |= CLKED;
3964	else
3965	    which &= ~CLKED;
3966    }
3967
3968    set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
3969}
3970
3971int
3972set_mode(scr_stat *scp)
3973{
3974    video_info_t info;
3975    video_adapter_t *adp;
3976
3977    /* reject unsupported mode */
3978    if ((*biosvidsw.get_info)(scp->adp, scp->mode, &info))
3979	return 1;
3980
3981    /* if this vty is not currently showing, do nothing */
3982    if (scp != cur_console)
3983	return 0;
3984
3985    /* setup video hardware for the given mode */
3986    adp = get_adapter(scp);
3987    (*biosvidsw.set_mode)(scp->adp, scp->mode);
3988    Crtat = (u_short *)adp->va_window;
3989
3990    if (!(scp->status & GRAPHICS_MODE)) {
3991	/* load appropriate font */
3992	if (!(scp->status & PIXEL_MODE)
3993	    && ISFONTAVAIL(get_adapter(scp)->va_flags)) {
3994	    if (scp->font_size < 14) {
3995		if (fonts_loaded & FONT_8)
3996		    copy_font(scp, LOAD, 8, font_8);
3997	    } else if (scp->font_size >= 16) {
3998		if (fonts_loaded & FONT_16)
3999		    copy_font(scp, LOAD, 16, font_16);
4000	    } else {
4001		if (fonts_loaded & FONT_14)
4002		    copy_font(scp, LOAD, 14, font_14);
4003	    }
4004	    /*
4005	    * FONT KLUDGE:
4006	    * This is an interim kludge to display correct font.
4007	    * Always use the font page #0 on the video plane 2.
4008	    * Somehow we cannot show the font in other font pages on
4009	    * some video cards... XXX
4010	    */
4011	    (*biosvidsw.show_font)(scp->adp, 0);
4012	}
4013	mark_all(scp);
4014    }
4015
4016    if (scp->status & PIXEL_MODE)
4017	generic_bzero((u_char *)(adp->va_window), scp->xpixel*scp->ypixel/8);
4018    set_border(scp, scp->border);
4019
4020    /* move hardware cursor out of the way */
4021    (*biosvidsw.set_hw_cursor)(scp->adp, -1, -1);
4022
4023    return 0;
4024}
4025
4026void
4027set_border(scr_stat *scp, int color)
4028{
4029    u_char *p;
4030    int xoff;
4031    int yoff;
4032    int xlen;
4033    int ylen;
4034    int i;
4035
4036    (*biosvidsw.set_border)(scp->adp, color);
4037
4038    if (scp->status & PIXEL_MODE) {
4039	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4040	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4041	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4042	outw(GDCIDX, 0xff08);		/* bit mask */
4043	outw(GDCIDX, (color << 8) | 0x00);	/* set/reset */
4044	p = (u_char *)(get_adapter(scp)->va_window);
4045	xoff = scp->xoff;
4046	yoff = scp->yoff*scp->font_size;
4047	xlen = scp->xpixel/8;
4048	ylen = scp->ysize*scp->font_size;
4049	if (yoff > 0) {
4050	    generic_bzero(p, xlen*yoff);
4051	    generic_bzero(p + xlen*(yoff + ylen),
4052			  xlen*scp->ypixel - xlen*(yoff + ylen));
4053	}
4054	if (xoff > 0) {
4055	    for (i = 0; i < ylen; ++i) {
4056		generic_bzero(p + xlen*(yoff + i), xoff);
4057		generic_bzero(p + xlen*(yoff + i) + xoff + scp->xsize,
4058			      xlen - xoff - scp->xsize);
4059	    }
4060	}
4061	outw(GDCIDX, 0x0000);		/* set/reset */
4062	outw(GDCIDX, 0x0001);		/* set/reset enable */
4063    }
4064}
4065
4066void
4067copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
4068{
4069    /*
4070     * FONT KLUDGE:
4071     * This is an interim kludge to display correct font.
4072     * Always use the font page #0 on the video plane 2.
4073     * Somehow we cannot show the font in other font pages on
4074     * some video cards... XXX
4075     */
4076    font_loading_in_progress = TRUE;
4077    if (operation == LOAD) {
4078	(*biosvidsw.load_font)(scp->adp, 0, font_size, buf, 0, 256);
4079	if (sc_flags & CHAR_CURSOR)
4080	    set_destructive_cursor(scp);
4081    } else if (operation == SAVE) {
4082	(*biosvidsw.save_font)(scp->adp, 0, font_size, buf, 0, 256);
4083    }
4084    font_loading_in_progress = FALSE;
4085}
4086
4087static void
4088set_destructive_cursor(scr_stat *scp)
4089{
4090    u_char cursor[32];
4091    u_char *font_buffer;
4092    int font_size;
4093    int i;
4094
4095    if (!ISFONTAVAIL(get_adapter(scp)->va_flags)
4096	|| (scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
4097	return;
4098
4099    if (scp->font_size < 14) {
4100	font_buffer = font_8;
4101	font_size = 8;
4102    } else if (scp->font_size >= 16) {
4103	font_buffer = font_16;
4104	font_size = 16;
4105    } else {
4106	font_buffer = font_14;
4107	font_size = 14;
4108    }
4109
4110    if (scp->status & MOUSE_VISIBLE) {
4111	if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR)
4112    	    bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4113	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 1)
4114    	    bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4115	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 2)
4116    	    bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4117	else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 3)
4118    	    bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4119	else
4120	    bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4121 	       	   cursor, scp->font_size);
4122    }
4123    else
4124    	bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4125 	       cursor, scp->font_size);
4126    for (i=0; i<32; i++)
4127	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4128	    (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4129	    cursor[i] |= 0xff;
4130#if 1
4131    while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4132#endif
4133    font_loading_in_progress = TRUE;
4134    (*biosvidsw.load_font)(scp->adp, 0, font_size, cursor, DEAD_CHAR, 1);
4135    font_loading_in_progress = FALSE;
4136}
4137
4138void
4139sc_move_mouse(scr_stat *scp, int x, int y)
4140{
4141    scp->mouse_xpos = x;
4142    scp->mouse_ypos = y;
4143    scp->mouse_pos = scp->mouse_oldpos =
4144	scp->scr_buf + (y / scp->font_size) * scp->xsize + x / 8;
4145}
4146
4147static void
4148set_mouse_pos(scr_stat *scp)
4149{
4150    static int last_xpos = -1, last_ypos = -1;
4151
4152    if (scp->mouse_xpos < 0)
4153	scp->mouse_xpos = 0;
4154    if (scp->mouse_ypos < 0)
4155	scp->mouse_ypos = 0;
4156    if (!ISTEXTSC(scp)) {
4157        if (scp->mouse_xpos > scp->xpixel-1)
4158	    scp->mouse_xpos = scp->xpixel-1;
4159        if (scp->mouse_ypos > scp->ypixel-1)
4160	    scp->mouse_ypos = scp->ypixel-1;
4161	return;
4162    }
4163    if (scp->mouse_xpos > (scp->xsize*8)-1)
4164	scp->mouse_xpos = (scp->xsize*8)-1;
4165    if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4166	scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4167
4168    if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4169	scp->status |= MOUSE_MOVED;
4170
4171    	scp->mouse_pos = scp->scr_buf +
4172	    ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4173
4174	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4175	    mouse_cut(scp);
4176    }
4177}
4178
4179#define isspace(c)	(((c) & 0xff) == ' ')
4180
4181static int
4182skip_spc_right(scr_stat *scp, u_short *p)
4183{
4184    int i;
4185
4186    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4187	if (!isspace(*p))
4188	    break;
4189	++p;
4190    }
4191    return i;
4192}
4193
4194static int
4195skip_spc_left(scr_stat *scp, u_short *p)
4196{
4197    int i;
4198
4199    for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4200	if (!isspace(*p))
4201	    break;
4202	--p;
4203    }
4204    return i;
4205}
4206
4207static void
4208mouse_cut(scr_stat *scp)
4209{
4210    u_short *end;
4211    u_short *p;
4212    int i = 0;
4213    int j = 0;
4214
4215    scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4216	scp->mouse_pos + 1 : scp->mouse_pos;
4217    end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4218	scp->mouse_cut_start : scp->mouse_cut_end;
4219    for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4220	    scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4221	cut_buffer[i] = *p & 0xff;
4222	/* remember the position of the last non-space char */
4223	if (!isspace(cut_buffer[i++]))
4224	    j = i;
4225	/* trim trailing blank when crossing lines */
4226	if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4227	    cut_buffer[j++] = '\r';
4228	    i = j;
4229	}
4230    }
4231    cut_buffer[i] = '\0';
4232
4233    /* scan towards the end of the last line */
4234    --p;
4235    for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4236	if (!isspace(*p))
4237	    break;
4238	++p;
4239    }
4240    /* if there is nothing but blank chars, trim them, but mark towards eol */
4241    if (i >= scp->xsize) {
4242	if (scp->mouse_cut_start > scp->mouse_cut_end)
4243	    scp->mouse_cut_start = p;
4244	else
4245	    scp->mouse_cut_end = p;
4246	cut_buffer[j++] = '\r';
4247	cut_buffer[j] = '\0';
4248    }
4249
4250    mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
4251    mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
4252}
4253
4254static void
4255mouse_cut_start(scr_stat *scp)
4256{
4257    int i;
4258
4259    if (scp->status & MOUSE_VISIBLE) {
4260	if (scp->mouse_pos == scp->mouse_cut_start &&
4261	    scp->mouse_cut_start == scp->mouse_cut_end - 1) {
4262	    cut_buffer[0] = '\0';
4263	    remove_cutmarking(scp);
4264	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
4265	    /* if the pointer is on trailing blank chars, mark towards eol */
4266	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
4267	    scp->mouse_cut_start = scp->scr_buf +
4268	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
4269	    scp->mouse_cut_end = scp->scr_buf +
4270	        ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
4271	    cut_buffer[0] = '\r';
4272	    cut_buffer[1] = '\0';
4273	    scp->status |= MOUSE_CUTTING;
4274	} else {
4275	    scp->mouse_cut_start = scp->mouse_pos;
4276	    scp->mouse_cut_end = scp->mouse_cut_start + 1;
4277	    cut_buffer[0] = *scp->mouse_cut_start & 0xff;
4278	    cut_buffer[1] = '\0';
4279	    scp->status |= MOUSE_CUTTING;
4280	}
4281    	mark_all(scp);
4282	/* delete all other screens cut markings */
4283	for (i=0; i<MAXCONS; i++) {
4284	    if (console[i] == NULL || console[i] == scp)
4285		continue;
4286	    remove_cutmarking(console[i]);
4287	}
4288    }
4289}
4290
4291static void
4292mouse_cut_end(scr_stat *scp)
4293{
4294    if (scp->status & MOUSE_VISIBLE) {
4295	scp->status &= ~MOUSE_CUTTING;
4296    }
4297}
4298
4299static void
4300mouse_cut_word(scr_stat *scp)
4301{
4302    u_short *p;
4303    u_short *sol;
4304    u_short *eol;
4305    int i;
4306
4307    /*
4308     * Because we don't have locale information in the kernel,
4309     * we only distinguish space char and non-space chars.  Punctuation
4310     * chars, symbols and other regular chars are all treated alike.
4311     */
4312    if (scp->status & MOUSE_VISIBLE) {
4313	sol = scp->scr_buf
4314	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4315	eol = sol + scp->xsize;
4316	if (isspace(*scp->mouse_pos)) {
4317	    for (p = scp->mouse_pos; p >= sol; --p)
4318	        if (!isspace(*p))
4319		    break;
4320	    scp->mouse_cut_start = ++p;
4321	    for (p = scp->mouse_pos; p < eol; ++p)
4322	        if (!isspace(*p))
4323		    break;
4324	    scp->mouse_cut_end = p;
4325	} else {
4326	    for (p = scp->mouse_pos; p >= sol; --p)
4327	        if (isspace(*p))
4328		    break;
4329	    scp->mouse_cut_start = ++p;
4330	    for (p = scp->mouse_pos; p < eol; ++p)
4331	        if (isspace(*p))
4332		    break;
4333	    scp->mouse_cut_end = p;
4334	}
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] = '\0';
4338	scp->status |= MOUSE_CUTTING;
4339    }
4340}
4341
4342static void
4343mouse_cut_line(scr_stat *scp)
4344{
4345    u_short *p;
4346    int i;
4347
4348    if (scp->status & MOUSE_VISIBLE) {
4349	scp->mouse_cut_start = scp->scr_buf
4350	    + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
4351	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
4352	for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
4353	    cut_buffer[i++] = *p & 0xff;
4354	cut_buffer[i++] = '\r';
4355	cut_buffer[i] = '\0';
4356	scp->status |= MOUSE_CUTTING;
4357    }
4358}
4359
4360static void
4361mouse_cut_extend(scr_stat *scp)
4362{
4363    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
4364	&& (scp->mouse_cut_start != NULL)) {
4365	mouse_cut(scp);
4366	scp->status |= MOUSE_CUTTING;
4367    }
4368}
4369
4370static void
4371mouse_paste(scr_stat *scp)
4372{
4373    if (scp->status & MOUSE_VISIBLE) {
4374	struct tty *tp;
4375	u_char *ptr = cut_buffer;
4376
4377	tp = VIRTUAL_TTY(get_scr_num());
4378	while (*ptr)
4379	    (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
4380    }
4381}
4382
4383static void
4384draw_mouse_image(scr_stat *scp)
4385{
4386    u_short buffer[32];
4387    u_short xoffset, yoffset;
4388    u_short *crt_pos = (u_short *)(get_adapter(scp)->va_window)
4389				      + (scp->mouse_pos - scp->scr_buf);
4390    u_char *font_buffer;
4391    int font_size;
4392    int i;
4393
4394    if (scp->font_size < 14) {
4395	font_buffer = font_8;
4396	font_size = 8;
4397    } else if (scp->font_size >= 16) {
4398	font_buffer = font_16;
4399	font_size = 16;
4400    } else {
4401	font_buffer = font_14;
4402	font_size = 14;
4403    }
4404
4405    xoffset = scp->mouse_xpos % 8;
4406    yoffset = scp->mouse_ypos % scp->font_size;
4407
4408    /* prepare mousepointer char's bitmaps */
4409    bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
4410	   &scp->mouse_cursor[0], font_size);
4411    bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
4412	   &scp->mouse_cursor[32], font_size);
4413    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
4414	   &scp->mouse_cursor[64], font_size);
4415    bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
4416	   &scp->mouse_cursor[96], font_size);
4417    for (i=0; i<font_size; i++) {
4418	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
4419	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
4420    }
4421
4422    /* now and-or in the mousepointer image */
4423    for (i=0; i<16; i++) {
4424	buffer[i+yoffset] =
4425	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
4426	    | (mouse_or_mask[i] >> xoffset);
4427    }
4428    for (i=0; i<font_size; i++) {
4429	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
4430	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
4431	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
4432	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
4433    }
4434
4435    scp->mouse_oldpos = scp->mouse_pos;
4436
4437#if 1
4438    /* wait for vertical retrace to avoid jitter on some videocards */
4439    while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
4440#endif
4441    font_loading_in_progress = TRUE;
4442    (*biosvidsw.load_font)(scp->adp, 0, 32, scp->mouse_cursor,
4443			   SC_MOUSE_CHAR, 4);
4444    font_loading_in_progress = FALSE;
4445
4446    *(crt_pos) = (*(scp->mouse_pos) & 0xff00) | SC_MOUSE_CHAR;
4447    *(crt_pos+scp->xsize) =
4448	(*(scp->mouse_pos + scp->xsize) & 0xff00) | (SC_MOUSE_CHAR + 2);
4449    if (scp->mouse_xpos < (scp->xsize-1)*8) {
4450    	*(crt_pos + 1) = (*(scp->mouse_pos + 1) & 0xff00) | (SC_MOUSE_CHAR + 1);
4451    	*(crt_pos+scp->xsize + 1) =
4452	    (*(scp->mouse_pos + scp->xsize + 1) & 0xff00) | (SC_MOUSE_CHAR + 3);
4453    }
4454    mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
4455    mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
4456}
4457
4458static void
4459remove_mouse_image(scr_stat *scp)
4460{
4461    u_short *crt_pos;
4462
4463    if (!ISTEXTSC(scp))
4464	return;
4465
4466    crt_pos = (u_short *)(get_adapter(scp)->va_window)
4467			     + (scp->mouse_oldpos - scp->scr_buf);
4468    *(crt_pos) = *(scp->mouse_oldpos);
4469    *(crt_pos+1) = *(scp->mouse_oldpos+1);
4470    *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
4471    *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
4472    mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
4473    mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
4474}
4475
4476static void
4477draw_cutmarking(scr_stat *scp)
4478{
4479    u_short *crt_pos;
4480    u_short *ptr;
4481    u_short och, nch;
4482
4483    crt_pos = (u_short *)(get_adapter(scp)->va_window);
4484    for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
4485	nch = och = *(crt_pos + (ptr - scp->scr_buf));
4486	/* are we outside the selected area ? */
4487	if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
4488	            scp->mouse_cut_end : scp->mouse_cut_start) ||
4489	     ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
4490	            scp->mouse_cut_start : scp->mouse_cut_end)) {
4491	    if (ptr != scp->cursor_pos)
4492		nch = (och & 0xff) | (*ptr & 0xff00);
4493	}
4494	else {
4495	    /* are we clear of the cursor image ? */
4496	    if (ptr != scp->cursor_pos)
4497		nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
4498	    else {
4499		if (sc_flags & CHAR_CURSOR)
4500		    nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
4501		else
4502		    if (!(sc_flags & BLINK_CURSOR))
4503		        nch = (och & 0xff) | (*ptr & 0xff00);
4504	    }
4505	}
4506	if (nch != och)
4507	    *(crt_pos + (ptr - scp->scr_buf)) = nch;
4508    }
4509}
4510
4511static void
4512remove_cutmarking(scr_stat *scp)
4513{
4514    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
4515    scp->status &= ~MOUSE_CUTTING;
4516    mark_all(scp);
4517}
4518
4519static void
4520do_bell(scr_stat *scp, int pitch, int duration)
4521{
4522    if (cold || shutdown_in_progress)
4523	return;
4524
4525    if (scp != cur_console && (sc_flags & QUIET_BELL))
4526	return;
4527
4528    if (sc_flags & VISUAL_BELL) {
4529	if (blink_in_progress)
4530	    return;
4531	blink_in_progress = 4;
4532	if (scp != cur_console)
4533	    blink_in_progress += 2;
4534	blink_screen(cur_console);
4535    } else {
4536	if (scp != cur_console)
4537	    pitch *= 2;
4538	sysbeep(pitch, duration);
4539    }
4540}
4541
4542static void
4543blink_screen(void *arg)
4544{
4545    scr_stat *scp = arg;
4546
4547    if (!ISTEXTSC(scp) || (blink_in_progress <= 1)) {
4548	blink_in_progress = FALSE;
4549    	mark_all(scp);
4550	if (delayed_next_scr)
4551	    switch_scr(scp, delayed_next_scr - 1);
4552    }
4553    else {
4554	if (blink_in_progress & 1)
4555	    fillw(kernel_default.std_color | scr_map[0x20],
4556		  (u_short *)(get_adapter(scp)->va_window),
4557		  scp->xsize * scp->ysize);
4558	else
4559	    fillw(kernel_default.rev_color | scr_map[0x20],
4560		  (u_short *)(get_adapter(scp)->va_window),
4561		  scp->xsize * scp->ysize);
4562	blink_in_progress--;
4563	timeout(blink_screen, scp, hz / 10);
4564    }
4565}
4566
4567void
4568sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark)
4569{
4570    u_char *font;
4571    u_char volatile *d;
4572    u_char *e;
4573    u_char *f;
4574    int font_size;
4575    int line_length;
4576    int xsize;
4577    u_short bg;
4578    int i, j;
4579    u_char c;
4580
4581    if (ISTEXTSC(scp)) {
4582	generic_bcopy(p + from, (u_short *)(get_adapter(scp)->va_window) + from,
4583		      (to - from + 1)*sizeof(u_short));
4584    } else /* if ISPIXELSC(scp) */ {
4585	if (mark)
4586	    mark = 255;
4587	font_size = scp->font_size;
4588	if (font_size < 14)
4589	    font = font_8;
4590	else if (font_size >= 16)
4591	    font = font_16;
4592	else
4593	    font = font_14;
4594	line_length = scp->xpixel/8;
4595	xsize = scp->xsize;
4596	d = (u_char *)(get_adapter(scp)->va_window)
4597	    + scp->xoff + scp->yoff*font_size*line_length
4598	    + (from%xsize) + font_size*line_length*(from/xsize);
4599
4600	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4601	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4602	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4603	bg = -1;
4604	for (i = from ; i <= to ; i++) {
4605	    /* set background color in EGA/VGA latch */
4606	    if (bg != (p[i] & 0xf000)) {
4607		bg = (p[i] & 0xf000);
4608		outw(GDCIDX, (bg >> 4) | 0x00); /* set/reset */
4609		outw(GDCIDX, 0xff08);		/* bit mask */
4610		*d = 0;
4611		c = *d;		/* set the background color in the latch */
4612	    }
4613	    /* foreground color */
4614	    outw(GDCIDX, (p[i] & 0x0f00) | 0x00); /* set/reset */
4615	    e = (u_char *)d;
4616	    f = &font[(p[i] & 0x00ff)*font_size];
4617	    for (j = 0 ; j < font_size; j++, f++) {
4618		outw(GDCIDX, ((*f^mark) << 8) | 0x08);	/* bit mask */
4619	        *e = 0;
4620		e += line_length;
4621	    }
4622	    d++;
4623	    if ((i % xsize) == xsize - 1)
4624		d += scp->xoff*2 + (font_size - 1)*line_length;
4625	}
4626	outw(GDCIDX, 0x0000);		/* set/reset */
4627	outw(GDCIDX, 0x0001);		/* set/reset enable */
4628	outw(GDCIDX, 0xff08);		/* bit mask */
4629
4630#if 0	/* VGA only */
4631	outw(GDCIDX, 0x0305);		/* read mode 0, write mode 3 */
4632	outw(GDCIDX, 0x0003);		/* data rotate/function select */
4633	outw(GDCIDX, 0x0f01);		/* set/reset enable */
4634	outw(GDCIDX, 0xff08);		/* bit mask */
4635	bg = -1;
4636	for (i = from ; i <= to ; i++) {
4637	    /* set background color in EGA/VGA latch */
4638	    if (bg != (p[i] & 0xf000)) {
4639		bg = (p[i] & 0xf000);
4640		outw(GDCIDX, 0x0005);	/* read mode 0, write mode 0 */
4641		outw(GDCIDX, (bg >> 4) | 0x00); /* set/reset */
4642		*d = 0;
4643		c = *d;		/* set the background color in the latch */
4644		outw(GDCIDX, 0x0305);	/* read mode 0, write mode 3 */
4645	    }
4646	    /* foreground color */
4647	    outw(GDCIDX, (p[i] & 0x0f00) | 0x00); /* set/reset */
4648	    e = (u_char *)d;
4649	    f = &font[(p[i] & 0x00ff)*font_size];
4650	    for (j = 0 ; j < font_size; j++, f++) {
4651	        *e = *f^mark;
4652		e += line_length;
4653	    }
4654	    d++;
4655	    if ((i % xsize) == xsize - 1)
4656		d += scp->xoff*2 + (font_size - 1)*line_length;
4657	}
4658	outw(GDCIDX, 0x0005);		/* read mode 0, write mode 0 */
4659	outw(GDCIDX, 0x0000);		/* set/reset */
4660	outw(GDCIDX, 0x0001);		/* set/reset enable */
4661#endif /* 0 */
4662    }
4663}
4664
4665#ifdef SC_SPLASH_SCREEN
4666
4667static void
4668scsplash_init(scr_stat *scp)
4669{
4670    video_info_t info;
4671
4672    if (scsplash_load(scp) == 0 && add_scrn_saver(scsplash_saver) == 0) {
4673	default_saver = scsplash_saver;
4674	scrn_blank_time = DEFAULT_BLANKTIME;
4675	run_scrn_saver = TRUE;
4676	if (!(boothowto & (RB_VERBOSE | RB_CONFIG))) {
4677	    scsplash_stick(TRUE);
4678	    scsplash_saver(TRUE);
4679	}
4680    }
4681}
4682
4683static void
4684scsplash_term(scr_stat *scp)
4685{
4686    default_saver = none_saver;
4687    scsplash_stick(FALSE);
4688    remove_scrn_saver(scsplash_saver);
4689    scsplash_unload(scp);
4690}
4691
4692static void
4693scsplash_saver(int show)
4694{
4695    if (show)
4696	scsplash(TRUE);
4697    else if (!sticky_splash)
4698	scsplash(FALSE);
4699}
4700
4701#endif /* SC_SPLASH_SCREEN */
4702
4703#endif /* NSC */
4704