syscons.c revision 20073
1/*-
2 * Copyright (c) 1992-1996 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *  $Id: syscons.c,v 1.189 1996/11/19 17:08:10 nate Exp $
29 */
30
31#include "sc.h"
32#include "apm.h"
33#include "opt_ddb.h"
34#include "opt_syscons.h"
35
36#if NSC > 0
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/conf.h>
40#include <sys/ioctl.h>
41#include <sys/proc.h>
42#include <sys/signalvar.h>
43#include <sys/tty.h>
44#include <sys/uio.h>
45#include <sys/callout.h>
46#include <sys/kernel.h>
47#include <sys/syslog.h>
48#include <sys/errno.h>
49#include <sys/malloc.h>
50#ifdef	DEVFS
51#include <sys/devfsext.h>
52#endif
53
54#include <machine/clock.h>
55#include <machine/cons.h>
56#include <machine/console.h>
57#include <machine/md_var.h>
58#include <machine/psl.h>
59#include <machine/frame.h>
60#include <machine/pc/display.h>
61#include <machine/apm_bios.h>
62#include <machine/random.h>
63
64#include <vm/vm.h>
65#include <vm/vm_param.h>
66#include <vm/pmap.h>
67
68#include <i386/isa/isa.h>
69#include <i386/isa/isa_device.h>
70#include <i386/isa/timerreg.h>
71#include <i386/isa/kbdtables.h>
72#include <i386/isa/kbdio.h>
73#include <i386/isa/syscons.h>
74
75#if !defined(MAXCONS)
76#define MAXCONS 16
77#endif
78
79#define COLD 0
80#define WARM 1
81
82/* this may break on older VGA's but is usefull on real 32 bit systems */
83#define bcopyw  bcopy
84
85static default_attr user_default = {
86    (FG_LIGHTGREY | BG_BLACK) << 8,
87    (FG_BLACK | BG_LIGHTGREY) << 8
88};
89
90static default_attr kernel_default = {
91    (FG_WHITE | BG_BLACK) << 8,
92    (FG_BLACK | BG_LIGHTGREY) << 8
93};
94
95static  scr_stat    	main_console;
96static  scr_stat    	*console[MAXCONS];
97#ifdef DEVFS
98static	void		*sc_devfs_token[MAXCONS];
99#endif
100	scr_stat    	*cur_console;
101static  scr_stat    	*new_scp, *old_scp;
102static  term_stat   	kernel_console;
103static  default_attr    *current_default;
104static  int     	flags = 0;
105static  int		sc_port = IO_KBD;
106static  char        	init_done = COLD;
107static  u_short		sc_buffer[ROW*COL];
108static  char        	switch_in_progress = FALSE;
109static  char        	write_in_progress = FALSE;
110static  char        	blink_in_progress = FALSE;
111static  int        	blinkrate = 0;
112	u_int       	crtc_addr = MONO_BASE;
113	char        	crtc_vga = FALSE;
114static  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
115static  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
116	char        	*font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
117	int     	fonts_loaded = 0;
118	char        	*palette;
119static  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
120static  int     	delayed_next_scr = FALSE;
121static  long        	scrn_blank_time = 0;    /* screen saver timeout value */
122	int     	scrn_blanked = FALSE;   /* screen saver active flag */
123static  long       	scrn_time_stamp;
124	u_char      	scr_map[256];
125	u_char      	scr_rmap[256];
126	char        	*video_mode_ptr = NULL;
127static	char 		*cut_buffer;
128static  u_short 	mouse_and_mask[16] = {
129				0xc000, 0xe000, 0xf000, 0xf800,
130				0xfc00, 0xfe00, 0xff00, 0xff80,
131				0xfe00, 0x1e00, 0x1f00, 0x0f00,
132				0x0f00, 0x0000, 0x0000, 0x0000
133			};
134static  u_short 	mouse_or_mask[16] = {
135				0x0000, 0x4000, 0x6000, 0x7000,
136				0x7800, 0x7c00, 0x7e00, 0x6800,
137				0x0c00, 0x0c00, 0x0600, 0x0600,
138				0x0000, 0x0000, 0x0000, 0x0000
139			};
140
141static void    		none_saver(int blank) { }
142void    		(*current_saver)(int blank) = none_saver;
143int  			(*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data,
144					 int flag, struct proc *p) = NULL;
145
146/* OS specific stuff */
147#ifdef not_yet_done
148#define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
149struct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
150struct  MOUSE_TTY 	(sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
151struct  tty         	*sccons[MAXCONS+2];
152#else
153#define VIRTUAL_TTY(x)  &sccons[x]
154#define CONSOLE_TTY 	&sccons[MAXCONS]
155#define MOUSE_TTY 	&sccons[MAXCONS+1]
156static struct tty     	sccons[MAXCONS+2];
157#endif
158#define SC_MOUSE 	128
159#define SC_CONSOLE	255
160#define MONO_BUF    	pa_to_va(0xB0000)
161#define CGA_BUF     	pa_to_va(0xB8000)
162u_short         	*Crtat;
163static const int	nsccons = MAXCONS+2;
164
165#define WRAPHIST(scp, pointer, offset)\
166    ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
167    + (offset)) % (scp->history_size)))
168
169/* prototypes */
170static int scattach(struct isa_device *dev);
171static int scparam(struct tty *tp, struct termios *t);
172static int scprobe(struct isa_device *dev);
173static void scstart(struct tty *tp);
174static void scmousestart(struct tty *tp);
175static void scinit(void);
176static u_int scgetc(u_int flags);
177#define SCGETC_CN	1
178#define SCGETC_NONBLOCK	2
179static scr_stat *get_scr_stat(dev_t dev);
180static scr_stat *alloc_scp(void);
181static void init_scp(scr_stat *scp);
182static int get_scr_num(void);
183static void scrn_timer(void);
184static void clear_screen(scr_stat *scp);
185static int switch_scr(scr_stat *scp, u_int next_scr);
186static void exchange_scr(void);
187static inline void move_crsr(scr_stat *scp, int x, int y);
188static void scan_esc(scr_stat *scp, u_char c);
189static void draw_cursor_image(scr_stat *scp);
190static void remove_cursor_image(scr_stat *scp);
191static void ansi_put(scr_stat *scp, u_char *buf, int len);
192static u_char *get_fstr(u_int c, u_int *len);
193static void history_to_screen(scr_stat *scp);
194static int history_up_line(scr_stat *scp);
195static int history_down_line(scr_stat *scp);
196static int mask2attr(struct term_stat *term);
197static void update_leds(int which);
198static void set_vgaregs(char *modetable);
199static void set_font_mode(void);
200static void set_normal_mode(void);
201static void set_destructive_cursor(scr_stat *scp);
202static void set_mouse_pos(scr_stat *scp);
203static void mouse_cut_start(scr_stat *scp);
204static void mouse_cut_end(scr_stat *scp);
205static void mouse_paste(scr_stat *scp);
206static void draw_mouse_image(scr_stat *scp);
207static void remove_mouse_image(scr_stat *scp);
208static void draw_cutmarking(scr_stat *scp);
209static void remove_cutmarking(scr_stat *scp);
210static void save_palette(void);
211static void do_bell(scr_stat *scp, int pitch, int duration);
212static void blink_screen(scr_stat *scp);
213#ifdef SC_SPLASH_SCREEN
214static void toggle_splash_screen(scr_stat *scp);
215#endif
216
217struct  isa_driver scdriver = {
218    scprobe, scattach, "sc", 1
219};
220
221static	d_open_t	scopen;
222static	d_close_t	scclose;
223static	d_read_t	scread;
224static	d_write_t	scwrite;
225static	d_ioctl_t	scioctl;
226static	d_devtotty_t	scdevtotty;
227static	d_mmap_t	scmmap;
228
229#define CDEV_MAJOR 12
230static	struct cdevsw	scdevsw = {
231	scopen,		scclose,	scread,		scwrite,
232	scioctl,	nullstop,	noreset,	scdevtotty,
233	ttselect,	scmmap,		nostrategy,	"sc",	NULL,	-1 };
234
235/*
236 * These functions need to be before calls to them so they can be inlined.
237 */
238static inline void
239draw_cursor_image(scr_stat *scp)
240{
241    u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf);
242
243    /* do we have a destructive cursor ? */
244    if (flags & CHAR_CURSOR) {
245	cursor_image = *scp->cursor_pos;
246	scp->cursor_saveunder = cursor_image;
247	/* modify cursor_image */
248	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
249	    set_destructive_cursor(scp);
250	    cursor_image &= 0xff00;
251	    cursor_image |= DEAD_CHAR;
252	}
253    }
254    else {
255	cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
256	scp->cursor_saveunder = cursor_image;
257	if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
258	    if ((cursor_image & 0x7000) == 0x7000) {
259		cursor_image &= 0x8fff;
260		if(!(cursor_image & 0x0700))
261		    cursor_image |= 0x0700;
262	    } else {
263		cursor_image |= 0x7000;
264		if ((cursor_image & 0x0700) == 0x0700)
265		    cursor_image &= 0xf0ff;
266	    }
267	}
268    }
269    *ptr = cursor_image;
270}
271
272static inline void
273remove_cursor_image(scr_stat *scp)
274{
275    *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder;
276}
277
278static inline void
279move_crsr(scr_stat *scp, int x, int y)
280{
281    if (x < 0)
282	x = 0;
283    if (y < 0)
284	y = 0;
285    if (x >= scp->xsize)
286	x = scp->xsize-1;
287    if (y >= scp->ysize)
288	y = scp->ysize-1;
289    scp->xpos = x;
290    scp->ypos = y;
291    scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
292}
293
294static int
295scprobe(struct isa_device *dev)
296{
297    int c;
298
299    sc_port = dev->id_iobase;
300
301    /* discard anything left after UserConfig */
302    empty_both_buffers(sc_port, 10);
303
304    /* save the current keyboard controller command byte */
305    c = -1;
306    if (!write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE)) {
307	/* CONTROLLER ERROR */
308	printf("sc%d: unable to get the current command byte value.\n",
309	    dev->id_unit);
310	goto fail;
311    }
312    c = read_controller_data(sc_port);
313    if (c == -1) {
314	/* CONTROLLER ERROR */
315	printf("sc%d: unable to get the current command byte value.\n",
316	    dev->id_unit);
317	goto fail;
318    }
319#if 0
320    /* override the keyboard lock switch */
321    c |= KBD_OVERRIDE_KBD_LOCK;
322#endif
323
324    /*
325     * enable the keyboard port, but disable the keyboard intr.
326     * the aux port (mouse port) is disabled too.
327     */
328    if (!set_controller_command_byte(sc_port,
329            c & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS),
330            KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT
331            | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
332	/* CONTROLLER ERROR
333	 * there is very little we can do...
334	 */
335	printf("sc%d: unable to set the command byte.\n", dev->id_unit);
336	goto fail;
337     }
338
339     /* reset keyboard hardware */
340     if (!reset_kbd(sc_port)) {
341        /* KEYBOARD ERROR
342	 * Keyboard reset may fail either because the keyboard doen't exist,
343         * or because the keyboard doesn't pass the self-test, or the keyboard
344         * controller on the motherboard and the keyboard somehow fail to
345         * shake hands. It is just possible, particularly in the last case,
346         * that the keyoard controller may be left in a hung state.
347         * test_controller() and test_kbd_port() appear to bring the keyboard
348         * controller back (I don't know why and how, though.)
349	 */
350	empty_both_buffers(sc_port, 10);
351	test_controller(sc_port);
352	test_kbd_port(sc_port);
353	/* We could disable the keyboard port and interrupt... but,
354	 * the keyboard may still exist (see above).
355	 */
356	if (bootverbose)
357	    printf("sc%d: failed to reset the keyboard.\n", dev->id_unit);
358	goto fail;
359    }
360
361    /*
362     * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
363     * such as those on the IBM ThinkPad laptop computers can be used
364     * with the standard console driver.
365     */
366    if (dev->id_flags & XT_KEYBD) {
367	if (send_kbd_command_and_data(
368	        sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK) {
369	    /* XT kbd doesn't need scan code translation */
370	    c &= ~KBD_TRANSLATION;
371	} else {
372	    /* KEYBOARD ERROR
373	     * The XT kbd isn't usable unless the proper scan code set
374	     * is selected.
375	     */
376	    printf("sc%d: unable to set the XT keyboard mode.\n", dev->id_unit);
377	    goto fail;
378	}
379    }
380    /* enable the keyboard port and intr. */
381    if (!set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS,
382				KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
383	/* CONTROLLER ERROR
384	 * This is serious; we are left with the disabled keyboard intr.
385	 */
386	printf("sc%d: unable to enable the keyboard port and intr.\n",
387	    dev->id_unit);
388	goto fail;
389    }
390
391succeed:
392    return (IO_KBDSIZE);
393
394fail:
395    if (c != -1)
396	/* try to restore the command byte as before, if possible */
397	set_controller_command_byte(sc_port, c, 0);
398    return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
399}
400
401#if NAPM > 0
402static int
403scresume(void *dummy)
404{
405	shfts = ctls = alts = agrs = metas = 0;
406	return 0;
407}
408#endif
409
410static int
411scattach(struct isa_device *dev)
412{
413    scr_stat *scp;
414    dev_t cdev = makedev(CDEV_MAJOR, 0);
415#ifdef DEVFS
416    int vc;
417#endif
418
419    scinit();
420    flags = dev->id_flags;
421
422    scp = console[0];
423
424    if (crtc_vga) {
425    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
426	font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
427	font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
428	font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
429	copy_font(SAVE, FONT_16, font_16);
430	fonts_loaded = FONT_16;
431	scp->font_size = FONT_16;
432	palette = (char *)malloc(3*256, M_DEVBUF, M_NOWAIT);
433	save_palette();
434    }
435
436    scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
437				     M_DEVBUF, M_NOWAIT);
438
439    /* copy temporary buffer to final buffer */
440    bcopyw(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
441
442    scp->cursor_pos = scp->cursor_oldpos =
443	scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
444    scp->mouse_pos = scp->mouse_oldpos =
445	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
446	    		scp->mouse_xpos/8);
447
448    /* initialize history buffer & pointers */
449    scp->history_head = scp->history_pos = scp->history =
450	(u_short *)malloc(scp->history_size*sizeof(u_short),
451			  M_DEVBUF, M_NOWAIT);
452    bzero(scp->history_head, scp->history_size*sizeof(u_short));
453
454    /* initialize cursor stuff */
455    if (!(scp->status & UNKNOWN_MODE)) {
456    	draw_cursor_image(scp);
457    	if (crtc_vga && (flags & CHAR_CURSOR))
458	    set_destructive_cursor(scp);
459    }
460
461    /* get screen update going */
462    scrn_timer();
463
464    update_leds(scp->status);
465
466    printf("sc%d: ", dev->id_unit);
467    if (crtc_vga)
468	if (crtc_addr == MONO_BASE)
469	    printf("VGA mono");
470	else
471	    printf("VGA color");
472    else
473	if (crtc_addr == MONO_BASE)
474	    printf("MDA/hercules");
475	else
476	    printf("CGA/EGA");
477    printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags);
478
479#if NAPM > 0
480    scp->r_hook.ah_fun = scresume;
481    scp->r_hook.ah_arg = NULL;
482    scp->r_hook.ah_name = "system keyboard";
483    scp->r_hook.ah_order = APM_MID_ORDER;
484    apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
485#endif
486
487    cdevsw_add(&cdev, &scdevsw, NULL);
488
489#ifdef DEVFS
490    for (vc = 0; vc < MAXCONS; vc++)
491        sc_devfs_token[vc] = devfs_add_devswf(&scdevsw, vc, DV_CHR, UID_ROOT,
492					      GID_WHEEL, 0600, "ttyv%n", vc);
493#endif
494    return 0;
495}
496
497struct tty
498*scdevtotty(dev_t dev)
499{
500    int unit = minor(dev);
501
502    if (init_done == COLD)
503	return(NULL);
504    if (unit == SC_CONSOLE)
505	return CONSOLE_TTY;
506    if (unit == SC_MOUSE)
507	return MOUSE_TTY;
508    if (unit >= MAXCONS || unit < 0)
509	return(NULL);
510    return VIRTUAL_TTY(unit);
511}
512
513int
514scopen(dev_t dev, int flag, int mode, struct proc *p)
515{
516    struct tty *tp = scdevtotty(dev);
517
518    if (!tp)
519	return(ENXIO);
520
521    tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
522    tp->t_param = scparam;
523    tp->t_dev = dev;
524    if (!(tp->t_state & TS_ISOPEN)) {
525	ttychars(tp);
526	tp->t_iflag = TTYDEF_IFLAG;
527	tp->t_oflag = TTYDEF_OFLAG;
528	tp->t_cflag = TTYDEF_CFLAG;
529	tp->t_lflag = TTYDEF_LFLAG;
530	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
531	scparam(tp, &tp->t_termios);
532	ttsetwater(tp);
533	(*linesw[tp->t_line].l_modem)(tp, 1);
534    }
535    else
536	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
537	    return(EBUSY);
538    if (minor(dev) < MAXCONS && !console[minor(dev)]) {
539	console[minor(dev)] = alloc_scp();
540    }
541    if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
542	tp->t_winsize.ws_col = console[minor(dev)]->xsize;
543	tp->t_winsize.ws_row = console[minor(dev)]->ysize;
544    }
545    return ((*linesw[tp->t_line].l_open)(dev, tp));
546}
547
548int
549scclose(dev_t dev, int flag, int mode, struct proc *p)
550{
551    struct tty *tp = scdevtotty(dev);
552    struct scr_stat *scp;
553
554    if (!tp)
555	return(ENXIO);
556    if (minor(dev) < MAXCONS) {
557	scp = get_scr_stat(tp->t_dev);
558	if (scp->status & SWITCH_WAIT_ACQ)
559	    wakeup((caddr_t)&scp->smode);
560#if not_yet_done
561	if (scp == &main_console) {
562	    scp->pid = 0;
563	    scp->proc = NULL;
564	    scp->smode.mode = VT_AUTO;
565	}
566	else {
567	    free(scp->scr_buf, M_DEVBUF);
568	    free(scp->history, M_DEVBUF);
569	    free(scp, M_DEVBUF);
570	    console[minor(dev)] = NULL;
571	}
572#else
573	scp->pid = 0;
574	scp->proc = NULL;
575	scp->smode.mode = VT_AUTO;
576#endif
577    }
578    spltty();
579    (*linesw[tp->t_line].l_close)(tp, flag);
580    ttyclose(tp);
581    spl0();
582    return(0);
583}
584
585int
586scread(dev_t dev, struct uio *uio, int flag)
587{
588    struct tty *tp = scdevtotty(dev);
589
590    if (!tp)
591	return(ENXIO);
592    return((*linesw[tp->t_line].l_read)(tp, uio, flag));
593}
594
595int
596scwrite(dev_t dev, struct uio *uio, int flag)
597{
598    struct tty *tp = scdevtotty(dev);
599
600    if (!tp)
601	return(ENXIO);
602    return((*linesw[tp->t_line].l_write)(tp, uio, flag));
603}
604
605void
606scintr(int unit)
607{
608    static struct tty *cur_tty;
609    int c, len;
610    u_char *cp;
611
612    /* make screensaver happy */
613    scrn_time_stamp = time.tv_sec;
614    if (scrn_blanked) {
615	(*current_saver)(FALSE);
616	mark_all(cur_console);
617    }
618
619    /*
620     * Loop while there is still input to get from the keyboard.
621     * I don't think this is nessesary, and it doesn't fix
622     * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
623     */
624    while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
625
626	cur_tty = VIRTUAL_TTY(get_scr_num());
627	if (!(cur_tty->t_state & TS_ISOPEN))
628	    if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
629		continue;
630
631	switch (c & 0xff00) {
632	case 0x0000: /* normal key */
633	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
634	    break;
635	case FKEY:  /* function key, return string */
636	    if (cp = get_fstr((u_int)c, (u_int *)&len)) {
637	    	while (len-- >  0)
638		    (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
639	    }
640	    break;
641	case MKEY:  /* meta is active, prepend ESC */
642	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
643	    (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
644	    break;
645	case BKEY:  /* backtab fixed sequence (esc [ Z) */
646	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
647	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
648	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
649	    break;
650	}
651    }
652
653    if (cur_console->status & MOUSE_ENABLED) {
654	cur_console->status &= ~MOUSE_VISIBLE;
655	remove_mouse_image(cur_console);
656    }
657}
658
659static int
660scparam(struct tty *tp, struct termios *t)
661{
662    tp->t_ispeed = t->c_ispeed;
663    tp->t_ospeed = t->c_ospeed;
664    tp->t_cflag = t->c_cflag;
665    return 0;
666}
667
668int
669scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
670{
671    int error;
672    u_int i;
673    struct tty *tp;
674    struct trapframe *fp;
675    scr_stat *scp;
676
677    tp = scdevtotty(dev);
678    if (!tp)
679	return ENXIO;
680    scp = get_scr_stat(tp->t_dev);
681
682    /* If there is a user_ioctl function call that first */
683    if (sc_user_ioctl) {
684	if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p))
685	    return error;
686    }
687
688    switch (cmd) {  		/* process console hardware related ioctl's */
689
690    case GIO_ATTR:      	/* get current attributes */
691	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
692	return 0;
693
694    case GIO_COLOR:     	/* is this a color console ? */
695	if (crtc_addr == COLOR_BASE)
696	    *(int*)data = 1;
697	else
698	    *(int*)data = 0;
699	return 0;
700
701    case CONS_CURRENT:  	/* get current adapter type */
702	if (crtc_vga)
703	    *(int*)data = KD_VGA;
704	else
705	    if (crtc_addr == MONO_BASE)
706		*(int*)data = KD_MONO;
707	    else
708		*(int*)data = KD_CGA;
709	return 0;
710
711    case CONS_GET:      	/* get current video mode */
712	*(int*)data = scp->mode;
713	return 0;
714
715    case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
716	scrn_blank_time = *(int*)data;
717	return 0;
718
719    case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
720	if ((*(int*)data) & 0x01)
721	    flags |= BLINK_CURSOR;
722	else
723	    flags &= ~BLINK_CURSOR;
724	if ((*(int*)data) & 0x02) {
725	    if (!crtc_vga)
726		return ENXIO;
727	    flags |= CHAR_CURSOR;
728	    set_destructive_cursor(scp);
729	} else
730	    flags &= ~CHAR_CURSOR;
731	return 0;
732
733    case CONS_BELLTYPE: 	/* set bell type sound/visual */
734	if (*data)
735	    flags |= VISUAL_BELL;
736	else
737	    flags &= ~VISUAL_BELL;
738	return 0;
739
740    case CONS_HISTORY:  	/* set history size */
741	if (*data) {
742	    free(scp->history, M_DEVBUF);
743	    scp->history_size = *(int*)data;
744	    if (scp->history_size < scp->ysize)
745		scp->history = NULL;
746	    else {
747		scp->history_size *= scp->xsize;
748		scp->history_head = scp->history_pos = scp->history =
749		    (u_short *)malloc(scp->history_size*sizeof(u_short),
750				      M_DEVBUF, M_WAITOK);
751		bzero(scp->history_head, scp->history_size*sizeof(u_short));
752	    }
753	    return 0;
754	}
755	else
756	    return EINVAL;
757
758    case CONS_MOUSECTL:		/* control mouse arrow */
759    {
760	mouse_info_t *mouse = (mouse_info_t*)data;
761
762	if (!crtc_vga)
763	    return ENXIO;
764
765	switch (mouse->operation) {
766	case MOUSE_MODE:
767	    if (mouse->u.mode.signal > 0 && mouse->u.mode.signal < NSIG) {
768		scp->mouse_signal = mouse->u.mode.signal;
769		scp->mouse_proc = p;
770		scp->mouse_pid = p->p_pid;
771	    }
772	    else {
773		scp->mouse_signal = 0;
774		scp->mouse_proc = NULL;
775		scp->mouse_pid = 0;
776	    }
777	    break;
778
779	case MOUSE_SHOW:
780	    if (!(scp->status & MOUSE_ENABLED)) {
781		scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
782		scp->mouse_oldpos = scp->mouse_pos;
783		mark_all(scp);
784	    }
785	    else
786		return EINVAL;
787	    break;
788
789	case MOUSE_HIDE:
790	    if (scp->status & MOUSE_ENABLED) {
791		scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
792		mark_all(scp);
793	    }
794	    else
795		return EINVAL;
796	    break;
797
798	case MOUSE_MOVEABS:
799	    scp->mouse_xpos = mouse->u.data.x;
800	    scp->mouse_ypos = mouse->u.data.y;
801	    set_mouse_pos(scp);
802	    break;
803
804	case MOUSE_MOVEREL:
805	    scp->mouse_xpos += mouse->u.data.x;
806	    scp->mouse_ypos += mouse->u.data.y;
807	    set_mouse_pos(scp);
808	    break;
809
810	case MOUSE_GETINFO:
811	    mouse->u.data.x = scp->mouse_xpos;
812	    mouse->u.data.y = scp->mouse_ypos;
813	    mouse->u.data.buttons = scp->mouse_buttons;
814	    break;
815
816	case MOUSE_ACTION:
817	    /* this should maybe only be settable from /dev/consolectl SOS */
818	    /* send out mouse event on /dev/sysmouse */
819	    if (cur_console->status & MOUSE_ENABLED)
820	    	cur_console->status |= MOUSE_VISIBLE;
821	    if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
822		u_char buf[5];
823		int i;
824
825		buf[0] = 0x80 | ((~mouse->u.data.buttons) & 0x07);
826		buf[1] = (mouse->u.data.x & 0x1fe >> 1);
827		buf[3] = (mouse->u.data.x & 0x1ff) - buf[1];
828		buf[2] = -(mouse->u.data.y & 0x1fe >> 1);
829		buf[4] = -(mouse->u.data.y & 0x1ff) - buf[2];
830		for (i=0; i<5; i++)
831	    		(*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
832	    }
833	    cur_console->mouse_xpos += mouse->u.data.x;
834	    cur_console->mouse_ypos += mouse->u.data.y;
835	    if (cur_console->mouse_signal) {
836		cur_console->mouse_buttons = mouse->u.data.buttons;
837    		/* has controlling process died? */
838		if (cur_console->mouse_proc &&
839		    (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
840		    	cur_console->mouse_signal = 0;
841			cur_console->mouse_proc = NULL;
842			cur_console->mouse_pid = 0;
843		}
844		else
845		    psignal(cur_console->mouse_proc, cur_console->mouse_signal);
846	    }
847	    else {
848		/* process button presses */
849		if (cur_console->mouse_buttons != mouse->u.data.buttons) {
850		    cur_console->mouse_buttons = mouse->u.data.buttons;
851		    if (!(scp->status & UNKNOWN_MODE)) {
852			if (cur_console->mouse_buttons & LEFT_BUTTON)
853			    mouse_cut_start(cur_console);
854			else
855			    mouse_cut_end(cur_console);
856			if (cur_console->mouse_buttons & RIGHT_BUTTON ||
857			    cur_console->mouse_buttons & MIDDLE_BUTTON)
858			    mouse_paste(cur_console);
859		    }
860		}
861	    }
862	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0)
863		set_mouse_pos(cur_console);
864	    break;
865
866	default:
867	    return EINVAL;
868	}
869	/* make screensaver happy */
870	if (scp == cur_console) {
871	    scrn_time_stamp = time.tv_sec;
872	    if (scrn_blanked) {
873		(*current_saver)(FALSE);
874		mark_all(scp);
875	    }
876	}
877	return 0;
878    }
879
880    case CONS_GETINFO:  	/* get current (virtual) console info */
881    {
882	vid_info_t *ptr = (vid_info_t*)data;
883	if (ptr->size == sizeof(struct vid_info)) {
884	    ptr->m_num = get_scr_num();
885	    ptr->mv_col = scp->xpos;
886	    ptr->mv_row = scp->ypos;
887	    ptr->mv_csz = scp->xsize;
888	    ptr->mv_rsz = scp->ysize;
889	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
890	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
891	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
892	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
893	    ptr->mv_grfc.fore = 0;      /* not supported */
894	    ptr->mv_grfc.back = 0;      /* not supported */
895	    ptr->mv_ovscan = scp->border;
896	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
897	    return 0;
898	}
899	return EINVAL;
900    }
901
902    case CONS_GETVERS:  	/* get version number */
903	*(int*)data = 0x200;    /* version 2.0 */
904	return 0;
905
906    /* VGA TEXT MODES */
907    case SW_VGA_C40x25:
908    case SW_VGA_C80x25: case SW_VGA_M80x25:
909    case SW_VGA_C80x30: case SW_VGA_M80x30:
910    case SW_VGA_C80x50: case SW_VGA_M80x50:
911    case SW_VGA_C80x60: case SW_VGA_M80x60:
912    case SW_B40x25:     case SW_C40x25:
913    case SW_B80x25:     case SW_C80x25:
914    case SW_ENH_B40x25: case SW_ENH_C40x25:
915    case SW_ENH_B80x25: case SW_ENH_C80x25:
916    case SW_ENH_B80x43: case SW_ENH_C80x43:
917
918	if (!crtc_vga || video_mode_ptr == NULL)
919	    return ENXIO;
920	switch (cmd & 0xff) {
921	case M_VGA_C80x60: case M_VGA_M80x60:
922	    if (!(fonts_loaded & FONT_8))
923		return EINVAL;
924	    scp->xsize = 80;
925	    scp->ysize = 60;
926	    break;
927	case M_VGA_C80x50: case M_VGA_M80x50:
928	    if (!(fonts_loaded & FONT_8))
929		return EINVAL;
930	    scp->xsize = 80;
931	    scp->ysize = 50;
932	    break;
933	case M_ENH_B80x43: case M_ENH_C80x43:
934	    if (!(fonts_loaded & FONT_8))
935		return EINVAL;
936	    scp->xsize = 80;
937	    scp->ysize = 43;
938	    break;
939	case M_VGA_C80x30: case M_VGA_M80x30:
940	    scp->xsize = 80;
941	    scp->ysize = 30;
942	    break;
943	default:
944	    if ((cmd & 0xff) > M_VGA_CG320)
945		return EINVAL;
946	    else
947		scp->xsize = *(video_mode_ptr+((cmd&0xff)*64));
948		scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1;
949	    break;
950	}
951	scp->mode = cmd & 0xff;
952	free(scp->scr_buf, M_DEVBUF);
953	scp->scr_buf = (u_short *)
954	    malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK);
955    	scp->cursor_pos = scp->cursor_oldpos =
956	    scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
957    	scp->mouse_pos = scp->mouse_oldpos =
958	    scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
959	    scp->mouse_xpos/8);
960	free(cut_buffer, M_DEVBUF);
961    	cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT);
962	cut_buffer[0] = 0x00;
963	if (scp == cur_console)
964	    set_mode(scp);
965	scp->status &= ~UNKNOWN_MODE;
966	clear_screen(scp);
967	if (tp->t_winsize.ws_col != scp->xsize
968	    || tp->t_winsize.ws_row != scp->ysize) {
969	    tp->t_winsize.ws_col = scp->xsize;
970	    tp->t_winsize.ws_row = scp->ysize;
971	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
972	}
973	return 0;
974
975    /* GRAPHICS MODES */
976    case SW_BG320:     case SW_BG640:
977    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
978    case SW_CG640x350: case SW_ENH_CG640:
979    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
980
981	if (!crtc_vga || video_mode_ptr == NULL)
982	    return ENXIO;
983	scp->mode = cmd & 0xFF;
984	scp->xpixel = (*(video_mode_ptr + (scp->mode*64))) * 8;
985	scp->ypixel = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) *
986		     (*(video_mode_ptr + (scp->mode*64) + 2));
987	if (scp == cur_console)
988	    set_mode(scp);
989	scp->status |= UNKNOWN_MODE;    /* graphics mode */
990	/* clear_graphics();*/
991
992	if (tp->t_winsize.ws_xpixel != scp->xpixel
993	    || tp->t_winsize.ws_ypixel != scp->ypixel) {
994	    tp->t_winsize.ws_xpixel = scp->xpixel;
995	    tp->t_winsize.ws_ypixel = scp->ypixel;
996	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
997	}
998	return 0;
999
1000    case VT_SETMODE:    	/* set screen switcher mode */
1001	bcopy(data, &scp->smode, sizeof(struct vt_mode));
1002	if (scp->smode.mode == VT_PROCESS) {
1003	    scp->proc = p;
1004	    scp->pid = scp->proc->p_pid;
1005	}
1006	return 0;
1007
1008    case VT_GETMODE:    	/* get screen switcher mode */
1009	bcopy(&scp->smode, data, sizeof(struct vt_mode));
1010	return 0;
1011
1012    case VT_RELDISP:    	/* screen switcher ioctl */
1013	switch(*data) {
1014	case VT_FALSE:  	/* user refuses to release screen, abort */
1015	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1016		old_scp->status &= ~SWITCH_WAIT_REL;
1017		switch_in_progress = FALSE;
1018		return 0;
1019	    }
1020	    return EINVAL;
1021
1022	case VT_TRUE:   	/* user has released screen, go on */
1023	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1024		scp->status &= ~SWITCH_WAIT_REL;
1025		exchange_scr();
1026		if (new_scp->smode.mode == VT_PROCESS) {
1027		    new_scp->status |= SWITCH_WAIT_ACQ;
1028		    psignal(new_scp->proc, new_scp->smode.acqsig);
1029		}
1030		else
1031		    switch_in_progress = FALSE;
1032		return 0;
1033	    }
1034	    return EINVAL;
1035
1036	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
1037	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1038		scp->status &= ~SWITCH_WAIT_ACQ;
1039		switch_in_progress = FALSE;
1040		return 0;
1041	    }
1042	    return EINVAL;
1043
1044	default:
1045	    return EINVAL;
1046	}
1047	/* NOT REACHED */
1048
1049    case VT_OPENQRY:    	/* return free virtual console */
1050	for (i = 0; i < MAXCONS; i++) {
1051	    tp = VIRTUAL_TTY(i);
1052	    if (!(tp->t_state & TS_ISOPEN)) {
1053		*data = i + 1;
1054		return 0;
1055	    }
1056	}
1057	return EINVAL;
1058
1059    case VT_ACTIVATE:   	/* switch to screen *data */
1060	return switch_scr(scp, (*data) - 1);
1061
1062    case VT_WAITACTIVE: 	/* wait for switch to occur */
1063	if (*data > MAXCONS || *data < 0)
1064	    return EINVAL;
1065	if (minor(dev) == (*data) - 1)
1066	    return 0;
1067	if (*data == 0) {
1068	    if (scp == cur_console)
1069		return 0;
1070	}
1071	else
1072	    scp = console[(*data) - 1];
1073	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1074			     "waitvt", 0)) == ERESTART) ;
1075	return error;
1076
1077    case VT_GETACTIVE:
1078	*data = get_scr_num()+1;
1079	return 0;
1080
1081    case KDENABIO:      	/* allow io operations */
1082	error = suser(p->p_ucred, &p->p_acflag);
1083	if (error != 0)
1084	    return error;
1085	if (securelevel > 0)
1086	    return EPERM;
1087	fp = (struct trapframe *)p->p_md.md_regs;
1088	fp->tf_eflags |= PSL_IOPL;
1089	return 0;
1090
1091    case KDDISABIO:     	/* disallow io operations (default) */
1092	fp = (struct trapframe *)p->p_md.md_regs;
1093	fp->tf_eflags &= ~PSL_IOPL;
1094	return 0;
1095
1096    case KDSETMODE:     	/* set current mode of this (virtual) console */
1097	switch (*data) {
1098	case KD_TEXT:   	/* switch to TEXT (known) mode */
1099	    /* restore fonts & palette ! */
1100	    if (crtc_vga) {
1101		if (fonts_loaded & FONT_8)
1102		    copy_font(LOAD, FONT_8, font_8);
1103		if (fonts_loaded & FONT_14)
1104		    copy_font(LOAD, FONT_14, font_14);
1105		if (fonts_loaded & FONT_16)
1106		    copy_font(LOAD, FONT_16, font_16);
1107		if (flags & CHAR_CURSOR)
1108		    set_destructive_cursor(scp);
1109		load_palette();
1110	    }
1111	    /* FALL THROUGH */
1112
1113	case KD_TEXT1:  	/* switch to TEXT (known) mode */
1114	    /* no restore fonts & palette */
1115	    if (crtc_vga && video_mode_ptr)
1116		set_mode(scp);
1117	    scp->status &= ~UNKNOWN_MODE;
1118	    clear_screen(scp);
1119	    return 0;
1120
1121	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
1122	    scp->status |= UNKNOWN_MODE;
1123	    return 0;
1124	default:
1125	    return EINVAL;
1126	}
1127	/* NOT REACHED */
1128
1129    case KDGETMODE:     	/* get current mode of this (virtual) console */
1130	*data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
1131	return 0;
1132
1133    case KDSBORDER:     	/* set border color of this (virtual) console */
1134	if (!crtc_vga)
1135	    return ENXIO;
1136	scp->border = *data;
1137	if (scp == cur_console)
1138	    set_border(scp->border);
1139	return 0;
1140
1141    case KDSKBSTATE:    	/* set keyboard state (locks) */
1142	if (*data >= 0 && *data <= LOCK_KEY_MASK) {
1143	    scp->status &= ~LOCK_KEY_MASK;
1144	    scp->status |= *data;
1145	    if (scp == cur_console)
1146		update_leds(scp->status);
1147	    return 0;
1148	}
1149	return EINVAL;
1150
1151    case KDGKBSTATE:    	/* get keyboard state (locks) */
1152	*data = scp->status & LOCK_KEY_MASK;
1153	return 0;
1154
1155    case KDSETRAD:      	/* set keyboard repeat & delay rates */
1156	if (*data & 0x80)
1157	    return EINVAL;
1158	i = spltty();
1159	send_kbd_command_and_data(sc_port, KBDC_SET_TYPEMATIC, *data);
1160	splx(i);
1161	return 0;
1162
1163    case KDSKBMODE:     	/* set keyboard mode */
1164	switch (*data) {
1165	case K_RAW: 		/* switch to RAW scancode mode */
1166	    scp->status |= KBD_RAW_MODE;
1167	    return 0;
1168
1169	case K_XLATE:   	/* switch to XLT ascii mode */
1170	    if (scp == cur_console && scp->status == KBD_RAW_MODE)
1171		shfts = ctls = alts = agrs = metas = 0;
1172	    scp->status &= ~KBD_RAW_MODE;
1173	    return 0;
1174	default:
1175	    return EINVAL;
1176	}
1177	/* NOT REACHED */
1178
1179    case KDGKBMODE:     	/* get keyboard mode */
1180	*data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
1181	return 0;
1182
1183    case KDMKTONE:      	/* sound the bell */
1184	if (*(int*)data)
1185	    do_bell(scp, (*(int*)data)&0xffff,
1186		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1187	else
1188	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1189	return 0;
1190
1191    case KIOCSOUND:     	/* make tone (*data) hz */
1192	if (scp == cur_console) {
1193	    if (*(int*)data) {
1194		int pitch = timer_freq / *(int*)data;
1195
1196		/* set command for counter 2, 2 byte write */
1197		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1198		    return EBUSY;
1199
1200		/* set pitch */
1201		outb(TIMER_CNTR2, pitch);
1202		outb(TIMER_CNTR2, (pitch>>8));
1203
1204		/* enable counter 2 output to speaker */
1205		outb(IO_PPI, inb(IO_PPI) | 3);
1206	    }
1207	    else {
1208		/* disable counter 2 output to speaker */
1209		outb(IO_PPI, inb(IO_PPI) & 0xFC);
1210		release_timer2();
1211	    }
1212	}
1213	return 0;
1214
1215    case KDGKBTYPE:     	/* get keyboard type */
1216	*data = 0;  		/* type not known (yet) */
1217	return 0;
1218
1219    case KDSETLED:      	/* set keyboard LED status */
1220	if (*data >= 0 && *data <= LED_MASK) {
1221	    scp->status &= ~LED_MASK;
1222	    scp->status |= *data;
1223	    if (scp == cur_console)
1224		update_leds(scp->status);
1225	    return 0;
1226	}
1227	return EINVAL;
1228
1229    case KDGETLED:      	/* get keyboard LED status */
1230	*data = scp->status & LED_MASK;
1231	return 0;
1232
1233    case GETFKEY:       	/* get functionkey string */
1234	if (*(u_short*)data < n_fkey_tab) {
1235	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1236	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1237		  fkey_tab[ptr->keynum].len);
1238	    ptr->flen = fkey_tab[ptr->keynum].len;
1239	    return 0;
1240	}
1241	else
1242	    return EINVAL;
1243
1244    case SETFKEY:       	/* set functionkey string */
1245	if (*(u_short*)data < n_fkey_tab) {
1246	    fkeyarg_t *ptr = (fkeyarg_t*)data;
1247	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1248		  min(ptr->flen, MAXFK));
1249	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1250	    return 0;
1251	}
1252	else
1253	    return EINVAL;
1254
1255    case GIO_SCRNMAP:   	/* get output translation table */
1256	bcopy(&scr_map, data, sizeof(scr_map));
1257	return 0;
1258
1259    case PIO_SCRNMAP:   	/* set output translation table */
1260	bcopy(data, &scr_map, sizeof(scr_map));
1261	for (i=0; i<sizeof(scr_map); i++)
1262	    scr_rmap[scr_map[i]] = i;
1263	return 0;
1264
1265    case GIO_KEYMAP:    	/* get keyboard translation table */
1266	bcopy(&key_map, data, sizeof(key_map));
1267	return 0;
1268
1269    case PIO_KEYMAP:    	/* set keyboard translation table */
1270	bcopy(data, &key_map, sizeof(key_map));
1271	return 0;
1272
1273    case PIO_FONT8x8:   	/* set 8x8 dot font */
1274	if (!crtc_vga)
1275	    return ENXIO;
1276	bcopy(data, font_8, 8*256);
1277	fonts_loaded |= FONT_8;
1278	copy_font(LOAD, FONT_8, font_8);
1279	if (flags & CHAR_CURSOR)
1280	    set_destructive_cursor(scp);
1281	return 0;
1282
1283    case GIO_FONT8x8:   	/* get 8x8 dot font */
1284	if (!crtc_vga)
1285	    return ENXIO;
1286	if (fonts_loaded & FONT_8) {
1287	    bcopy(font_8, data, 8*256);
1288	    return 0;
1289	}
1290	else
1291	    return ENXIO;
1292
1293    case PIO_FONT8x14:  	/* set 8x14 dot font */
1294	if (!crtc_vga)
1295	    return ENXIO;
1296	bcopy(data, font_14, 14*256);
1297	fonts_loaded |= FONT_14;
1298	copy_font(LOAD, FONT_14, font_14);
1299	if (flags & CHAR_CURSOR)
1300	    set_destructive_cursor(scp);
1301	return 0;
1302
1303    case GIO_FONT8x14:  	/* get 8x14 dot font */
1304	if (!crtc_vga)
1305	    return ENXIO;
1306	if (fonts_loaded & FONT_14) {
1307	    bcopy(font_14, data, 14*256);
1308	    return 0;
1309	}
1310	else
1311	    return ENXIO;
1312
1313    case PIO_FONT8x16:  	/* set 8x16 dot font */
1314	if (!crtc_vga)
1315	    return ENXIO;
1316	bcopy(data, font_16, 16*256);
1317	fonts_loaded |= FONT_16;
1318	copy_font(LOAD, FONT_16, font_16);
1319	if (flags & CHAR_CURSOR)
1320	    set_destructive_cursor(scp);
1321	return 0;
1322
1323    case GIO_FONT8x16:  	/* get 8x16 dot font */
1324	if (!crtc_vga)
1325	    return ENXIO;
1326	if (fonts_loaded & FONT_16) {
1327	    bcopy(font_16, data, 16*256);
1328	    return 0;
1329	}
1330	else
1331	    return ENXIO;
1332    default:
1333	break;
1334    }
1335
1336    error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1337    if (error >= 0)
1338	return(error);
1339    error = ttioctl(tp, cmd, data, flag);
1340    if (error >= 0)
1341	return(error);
1342    return(ENOTTY);
1343}
1344
1345static void
1346scstart(struct tty *tp)
1347{
1348    struct clist *rbp;
1349    int s, len;
1350    u_char buf[PCBURST];
1351    scr_stat *scp = get_scr_stat(tp->t_dev);
1352
1353    if (scp->status & SLKED || blink_in_progress)
1354	return; /* XXX who repeats the call when the above flags are cleared? */
1355    s = spltty();
1356    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1357	tp->t_state |= TS_BUSY;
1358	rbp = &tp->t_outq;
1359	while (rbp->c_cc) {
1360	    len = q_to_b(rbp, buf, PCBURST);
1361	    splx(s);
1362	    ansi_put(scp, buf, len);
1363	    s = spltty();
1364	}
1365	tp->t_state &= ~TS_BUSY;
1366	ttwwakeup(tp);
1367    }
1368    splx(s);
1369}
1370
1371static void
1372scmousestart(struct tty *tp)
1373{
1374    struct clist *rbp;
1375    int s;
1376    u_char buf[PCBURST];
1377
1378    s = spltty();
1379    if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1380	tp->t_state |= TS_BUSY;
1381	rbp = &tp->t_outq;
1382	while (rbp->c_cc) {
1383	    q_to_b(rbp, buf, PCBURST);
1384	}
1385	tp->t_state &= ~TS_BUSY;
1386	ttwwakeup(tp);
1387    }
1388    splx(s);
1389}
1390
1391void
1392sccnprobe(struct consdev *cp)
1393{
1394    struct isa_device *dvp;
1395
1396    /*
1397     * Take control if we are the highest priority enabled display device.
1398     */
1399    dvp = find_display();
1400    if (dvp == NULL || dvp->id_driver != &scdriver) {
1401	cp->cn_pri = CN_DEAD;
1402	return;
1403    }
1404
1405    /* initialize required fields */
1406    cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
1407    cp->cn_pri = CN_INTERNAL;
1408}
1409
1410void
1411sccninit(struct consdev *cp)
1412{
1413    scinit();
1414}
1415
1416void
1417sccnputc(dev_t dev, int c)
1418{
1419    u_char buf[1];
1420    int s;
1421    scr_stat *scp = console[0];
1422    term_stat save = scp->term;
1423
1424    scp->term = kernel_console;
1425    current_default = &kernel_default;
1426    if (scp == cur_console && !(scp->status & UNKNOWN_MODE))
1427	remove_cursor_image(scp);
1428    buf[0] = c;
1429    ansi_put(scp, buf, 1);
1430    kernel_console = scp->term;
1431    current_default = &user_default;
1432    scp->term = save;
1433    s = splclock();
1434    if (scp == cur_console && !(scp->status & UNKNOWN_MODE)) {
1435	if (/* timer not running && */ (scp->start <= scp->end)) {
1436	    bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1437		   (1 + scp->end - scp->start) * sizeof(u_short));
1438	    scp->start = scp->xsize * scp->ysize;
1439	    scp->end = 0;
1440	}
1441    	scp->cursor_oldpos = scp->cursor_pos;
1442	draw_cursor_image(scp);
1443    }
1444    splx(s);
1445}
1446
1447int
1448sccngetc(dev_t dev)
1449{
1450    int s = spltty();       /* block scintr while we poll */
1451    int c = scgetc(SCGETC_CN);
1452    splx(s);
1453    return(c);
1454}
1455
1456int
1457sccncheckc(dev_t dev)
1458{
1459    int c, s;
1460
1461    s = spltty();
1462    c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
1463    splx(s);
1464    return(c == NOKEY ? -1 : c);	/* c == -1 can't happen */
1465}
1466
1467static scr_stat
1468*get_scr_stat(dev_t dev)
1469{
1470    int unit = minor(dev);
1471
1472    if (unit == SC_CONSOLE)
1473	return console[0];
1474    if (unit >= MAXCONS || unit < 0)
1475	return(NULL);
1476    return console[unit];
1477}
1478
1479static int
1480get_scr_num()
1481{
1482    int i = 0;
1483
1484    while ((i < MAXCONS) && (cur_console != console[i]))
1485	i++;
1486    return i < MAXCONS ? i : 0;
1487}
1488
1489static void
1490scrn_timer()
1491{
1492    scr_stat *scp = cur_console;
1493    int s = spltty();
1494
1495    /*
1496     * With release 2.1 of the Xaccel server, the keyboard is left
1497     * hanging pretty often. Apparently an interrupt from the
1498     * keyboard is lost, and I don't know why (yet).
1499     * This ugly hack calls scintr if input is ready for the keyboard
1500     * and conveniently hides the problem.			XXX
1501     */
1502    if ((inb(sc_port+KBD_STATUS_PORT)&KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL)
1503	scintr(0);
1504
1505    /* should we just return ? */
1506    if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
1507	timeout((timeout_func_t)scrn_timer, 0, hz/10);
1508	splx(s);
1509	return;
1510    }
1511
1512    if (!scrn_blanked) {
1513	/* update screen image */
1514	if (scp->start <= scp->end) {
1515	    bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1516		   (1 + scp->end - scp->start) * sizeof(u_short));
1517	}
1518
1519	/* update "pseudo" mouse pointer image */
1520	if ((scp->status & MOUSE_VISIBLE) && crtc_vga) {
1521	    /* did mouse move since last time ? */
1522	    if (scp->status & MOUSE_MOVED) {
1523		/* do we need to remove old mouse pointer image ? */
1524		if (scp->mouse_cut_start != NULL ||
1525		    (scp->mouse_pos-scp->scr_buf) <= scp->start ||
1526		    (scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->end) {
1527		    remove_mouse_image(scp);
1528		}
1529		scp->status &= ~MOUSE_MOVED;
1530		draw_mouse_image(scp);
1531	    }
1532	    else {
1533		/* mouse didn't move, has it been overwritten ? */
1534		if ((scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->start &&
1535		    (scp->mouse_pos - scp->scr_buf) <= scp->end) {
1536		    draw_mouse_image(scp);
1537		}
1538	    }
1539	}
1540
1541	/* update cursor image */
1542	if (scp->status & CURSOR_ENABLED) {
1543	    /* did cursor move since last time ? */
1544	    if (scp->cursor_pos != scp->cursor_oldpos) {
1545		/* do we need to remove old cursor image ? */
1546		if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
1547		    ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
1548		    remove_cursor_image(scp);
1549		}
1550    		scp->cursor_oldpos = scp->cursor_pos;
1551		draw_cursor_image(scp);
1552	    }
1553	    else {
1554		/* cursor didn't move, has it been overwritten ? */
1555		if (scp->cursor_pos - scp->scr_buf >= scp->start &&
1556		    scp->cursor_pos - scp->scr_buf <= scp->end) {
1557		    	draw_cursor_image(scp);
1558		} else {
1559		    /* if its a blinking cursor, we may have to update it */
1560		    if (flags & BLINK_CURSOR)
1561			draw_cursor_image(scp);
1562		}
1563	    }
1564	    blinkrate++;
1565	}
1566
1567	if (scp->mouse_cut_start != NULL)
1568	    draw_cutmarking(scp);
1569
1570	scp->end = 0;
1571	scp->start = scp->xsize*scp->ysize;
1572    }
1573    if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
1574	(*current_saver)(TRUE);
1575    timeout((timeout_func_t)scrn_timer, 0, hz/25);
1576    splx(s);
1577}
1578
1579static void
1580clear_screen(scr_stat *scp)
1581{
1582    move_crsr(scp, 0, 0);
1583    scp->cursor_oldpos = scp->cursor_pos;
1584    fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
1585	  scp->xsize * scp->ysize);
1586    mark_all(scp);
1587    remove_cutmarking(scp);
1588}
1589
1590static int
1591switch_scr(scr_stat *scp, u_int next_scr)
1592{
1593    if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
1594	switch_in_progress = FALSE;
1595
1596    if (next_scr >= MAXCONS || switch_in_progress ||
1597	(cur_console->smode.mode == VT_AUTO
1598	 && cur_console->status & UNKNOWN_MODE)) {
1599	do_bell(scp, BELL_PITCH, BELL_DURATION);
1600	return EINVAL;
1601    }
1602
1603    /* is the wanted virtual console open ? */
1604    if (next_scr) {
1605	struct tty *tp = VIRTUAL_TTY(next_scr);
1606	if (!(tp->t_state & TS_ISOPEN)) {
1607	    do_bell(scp, BELL_PITCH, BELL_DURATION);
1608	    return EINVAL;
1609	}
1610    }
1611    /* delay switch if actively updating screen */
1612    if (write_in_progress || blink_in_progress) {
1613	delayed_next_scr = next_scr+1;
1614	return 0;
1615    }
1616    switch_in_progress = TRUE;
1617    old_scp = cur_console;
1618    new_scp = console[next_scr];
1619    wakeup((caddr_t)&new_scp->smode);
1620    if (new_scp == old_scp) {
1621	switch_in_progress = FALSE;
1622	delayed_next_scr = FALSE;
1623	return 0;
1624    }
1625
1626    /* has controlling process died? */
1627    if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
1628	old_scp->smode.mode = VT_AUTO;
1629    if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
1630	new_scp->smode.mode = VT_AUTO;
1631
1632    /* check the modes and switch approbiatly */
1633    if (old_scp->smode.mode == VT_PROCESS) {
1634	old_scp->status |= SWITCH_WAIT_REL;
1635	psignal(old_scp->proc, old_scp->smode.relsig);
1636    }
1637    else {
1638	exchange_scr();
1639	if (new_scp->smode.mode == VT_PROCESS) {
1640	    new_scp->status |= SWITCH_WAIT_ACQ;
1641	    psignal(new_scp->proc, new_scp->smode.acqsig);
1642	}
1643	else
1644	    switch_in_progress = FALSE;
1645    }
1646    return 0;
1647}
1648
1649static void
1650exchange_scr(void)
1651{
1652    move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
1653    cur_console = new_scp;
1654    if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
1655	if (crtc_vga && video_mode_ptr)
1656	    set_mode(new_scp);
1657    }
1658    move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
1659    if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
1660	if (flags & CHAR_CURSOR)
1661	    set_destructive_cursor(new_scp);
1662	load_palette();
1663    }
1664    if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
1665	shfts = ctls = alts = agrs = metas = 0;
1666    update_leds(new_scp->status);
1667    delayed_next_scr = FALSE;
1668    mark_all(new_scp);
1669}
1670
1671static void
1672scan_esc(scr_stat *scp, u_char c)
1673{
1674    static u_char ansi_col[16] =
1675	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
1676    int i, n;
1677    u_short *src, *dst, count;
1678
1679    if (scp->term.esc == 1) {
1680	switch (c) {
1681
1682	case '[':   /* Start ESC [ sequence */
1683	    scp->term.esc = 2;
1684	    scp->term.last_param = -1;
1685	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1686		scp->term.param[i] = 1;
1687	    scp->term.num_param = 0;
1688	    return;
1689
1690	case 'M':   /* Move cursor up 1 line, scroll if at top */
1691	    if (scp->ypos > 0)
1692		move_crsr(scp, scp->xpos, scp->ypos - 1);
1693	    else {
1694		bcopyw(scp->scr_buf, scp->scr_buf + scp->xsize,
1695		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
1696		fillw(scp->term.cur_color | scr_map[0x20],
1697		      scp->scr_buf, scp->xsize);
1698    		mark_all(scp);
1699	    }
1700	    break;
1701#if notyet
1702	case 'Q':
1703	    scp->term.esc = 4;
1704	    break;
1705#endif
1706	case 'c':   /* Clear screen & home */
1707	    clear_screen(scp);
1708	    break;
1709	}
1710    }
1711    else if (scp->term.esc == 2) {
1712	if (c >= '0' && c <= '9') {
1713	    if (scp->term.num_param < MAX_ESC_PAR) {
1714	    if (scp->term.last_param != scp->term.num_param) {
1715		scp->term.last_param = scp->term.num_param;
1716		scp->term.param[scp->term.num_param] = 0;
1717	    }
1718	    else
1719		scp->term.param[scp->term.num_param] *= 10;
1720	    scp->term.param[scp->term.num_param] += c - '0';
1721	    return;
1722	    }
1723	}
1724	scp->term.num_param = scp->term.last_param + 1;
1725	switch (c) {
1726
1727	case ';':
1728	    if (scp->term.num_param < MAX_ESC_PAR)
1729		return;
1730	    break;
1731
1732	case '=':
1733	    scp->term.esc = 3;
1734	    scp->term.last_param = -1;
1735	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1736		scp->term.param[i] = 1;
1737	    scp->term.num_param = 0;
1738	    return;
1739
1740	case 'A':   /* up n rows */
1741	    n = scp->term.param[0]; if (n < 1) n = 1;
1742	    move_crsr(scp, scp->xpos, scp->ypos - n);
1743	    break;
1744
1745	case 'B':   /* down n rows */
1746	    n = scp->term.param[0]; if (n < 1) n = 1;
1747	    move_crsr(scp, scp->xpos, scp->ypos + n);
1748	    break;
1749
1750	case 'C':   /* right n columns */
1751	    n = scp->term.param[0]; if (n < 1) n = 1;
1752	    move_crsr(scp, scp->xpos + n, scp->ypos);
1753	    break;
1754
1755	case 'D':   /* left n columns */
1756	    n = scp->term.param[0]; if (n < 1) n = 1;
1757	    move_crsr(scp, scp->xpos - n, scp->ypos);
1758	    break;
1759
1760	case 'E':   /* cursor to start of line n lines down */
1761	    n = scp->term.param[0]; if (n < 1) n = 1;
1762	    move_crsr(scp, 0, scp->ypos + n);
1763	    break;
1764
1765	case 'F':   /* cursor to start of line n lines up */
1766	    n = scp->term.param[0]; if (n < 1) n = 1;
1767	    move_crsr(scp, 0, scp->ypos - n);
1768	    break;
1769
1770	case 'f':   /* Cursor move */
1771	case 'H':
1772	    if (scp->term.num_param == 0)
1773		move_crsr(scp, 0, 0);
1774	    else if (scp->term.num_param == 2)
1775		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
1776	    break;
1777
1778	case 'J':   /* Clear all or part of display */
1779	    if (scp->term.num_param == 0)
1780		n = 0;
1781	    else
1782		n = scp->term.param[0];
1783	    switch (n) {
1784	    case 0: /* clear form cursor to end of display */
1785		fillw(scp->term.cur_color | scr_map[0x20],
1786		      scp->cursor_pos,
1787		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
1788    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1789    		mark_for_update(scp, scp->xsize * scp->ysize);
1790		break;
1791	    case 1: /* clear from beginning of display to cursor */
1792		fillw(scp->term.cur_color | scr_map[0x20],
1793		      scp->scr_buf,
1794		      scp->cursor_pos - scp->scr_buf);
1795    		mark_for_update(scp, 0);
1796    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1797		break;
1798	    case 2: /* clear entire display */
1799		clear_screen(scp);
1800		break;
1801	    }
1802	    break;
1803
1804	case 'K':   /* Clear all or part of line */
1805	    if (scp->term.num_param == 0)
1806		n = 0;
1807	    else
1808		n = scp->term.param[0];
1809	    switch (n) {
1810	    case 0: /* clear form cursor to end of line */
1811		fillw(scp->term.cur_color | scr_map[0x20],
1812		      scp->cursor_pos,
1813		      scp->xsize - scp->xpos);
1814    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1815    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
1816				scp->xsize - scp->xpos);
1817		break;
1818	    case 1: /* clear from beginning of line to cursor */
1819		fillw(scp->term.cur_color | scr_map[0x20],
1820		      scp->cursor_pos - scp->xpos,
1821		      scp->xpos + 1);
1822    		mark_for_update(scp, scp->ypos * scp->xsize);
1823    		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1824		break;
1825	    case 2: /* clear entire line */
1826		fillw(scp->term.cur_color | scr_map[0x20],
1827		      scp->cursor_pos - scp->xpos,
1828		      scp->xsize);
1829    		mark_for_update(scp, scp->ypos * scp->xsize);
1830    		mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
1831		break;
1832	    }
1833	    break;
1834
1835	case 'L':   /* Insert n lines */
1836	    n = scp->term.param[0]; if (n < 1) n = 1;
1837	    if (n > scp->ysize - scp->ypos)
1838		n = scp->ysize - scp->ypos;
1839	    src = scp->scr_buf + scp->ypos * scp->xsize;
1840	    dst = src + n * scp->xsize;
1841	    count = scp->ysize - (scp->ypos + n);
1842	    bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1843	    fillw(scp->term.cur_color | scr_map[0x20], src,
1844		  n * scp->xsize);
1845	    mark_for_update(scp, scp->ypos * scp->xsize);
1846	    mark_for_update(scp, scp->xsize * scp->ysize);
1847	    break;
1848
1849	case 'M':   /* Delete n lines */
1850	    n = scp->term.param[0]; if (n < 1) n = 1;
1851	    if (n > scp->ysize - scp->ypos)
1852		n = scp->ysize - scp->ypos;
1853	    dst = scp->scr_buf + scp->ypos * scp->xsize;
1854	    src = dst + n * scp->xsize;
1855	    count = scp->ysize - (scp->ypos + n);
1856	    bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1857	    src = dst + count * scp->xsize;
1858	    fillw(scp->term.cur_color | scr_map[0x20], src,
1859		  n * scp->xsize);
1860	    mark_for_update(scp, scp->ypos * scp->xsize);
1861	    mark_for_update(scp, scp->xsize * scp->ysize);
1862	    break;
1863
1864	case 'P':   /* Delete n chars */
1865	    n = scp->term.param[0]; if (n < 1) n = 1;
1866	    if (n > scp->xsize - scp->xpos)
1867		n = scp->xsize - scp->xpos;
1868	    dst = scp->cursor_pos;
1869	    src = dst + n;
1870	    count = scp->xsize - (scp->xpos + n);
1871	    bcopyw(src, dst, count * sizeof(u_short));
1872	    src = dst + count;
1873	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
1874	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1875	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1876	    break;
1877
1878	case '@':   /* Insert n chars */
1879	    n = scp->term.param[0]; if (n < 1) n = 1;
1880	    if (n > scp->xsize - scp->xpos)
1881		n = scp->xsize - scp->xpos;
1882	    src = scp->cursor_pos;
1883	    dst = src + n;
1884	    count = scp->xsize - (scp->xpos + n);
1885	    bcopyw(src, dst, count * sizeof(u_short));
1886	    fillw(scp->term.cur_color | scr_map[0x20], src, n);
1887	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1888	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1889	    break;
1890
1891	case 'S':   /* scroll up n lines */
1892	    n = scp->term.param[0]; if (n < 1)  n = 1;
1893	    if (n > scp->ysize)
1894		n = scp->ysize;
1895	    bcopyw(scp->scr_buf + (scp->xsize * n),
1896		   scp->scr_buf,
1897		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
1898	    fillw(scp->term.cur_color | scr_map[0x20],
1899		  scp->scr_buf + scp->xsize * (scp->ysize - n),
1900		  scp->xsize * n);
1901    	    mark_all(scp);
1902	    break;
1903
1904	case 'T':   /* scroll down n lines */
1905	    n = scp->term.param[0]; if (n < 1)  n = 1;
1906	    if (n > scp->ysize)
1907		n = scp->ysize;
1908	    bcopyw(scp->scr_buf,
1909		  scp->scr_buf + (scp->xsize * n),
1910		  scp->xsize * (scp->ysize - n) *
1911		  sizeof(u_short));
1912	    fillw(scp->term.cur_color | scr_map[0x20],
1913		  scp->scr_buf, scp->xsize * n);
1914    	    mark_all(scp);
1915	    break;
1916
1917	case 'X':   /* erase n characters in line */
1918	    n = scp->term.param[0]; if (n < 1)  n = 1;
1919	    if (n > scp->xsize - scp->xpos)
1920		n = scp->xsize - scp->xpos;
1921	    fillw(scp->term.cur_color | scr_map[0x20],
1922		  scp->cursor_pos, n);
1923	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1924	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
1925	    break;
1926
1927	case 'Z':   /* move n tabs backwards */
1928	    n = scp->term.param[0]; if (n < 1)  n = 1;
1929	    if ((i = scp->xpos & 0xf8) == scp->xpos)
1930		i -= 8*n;
1931	    else
1932		i -= 8*(n-1);
1933	    if (i < 0)
1934		i = 0;
1935	    move_crsr(scp, i, scp->ypos);
1936	    break;
1937
1938	case '`':   /* move cursor to column n */
1939	    n = scp->term.param[0]; if (n < 1)  n = 1;
1940	    move_crsr(scp, n - 1, scp->ypos);
1941	    break;
1942
1943	case 'a':   /* move cursor n columns to the right */
1944	    n = scp->term.param[0]; if (n < 1)  n = 1;
1945	    move_crsr(scp, scp->xpos + n, scp->ypos);
1946	    break;
1947
1948	case 'd':   /* move cursor to row n */
1949	    n = scp->term.param[0]; if (n < 1)  n = 1;
1950	    move_crsr(scp, scp->xpos, n - 1);
1951	    break;
1952
1953	case 'e':   /* move cursor n rows down */
1954	    n = scp->term.param[0]; if (n < 1)  n = 1;
1955	    move_crsr(scp, scp->xpos, scp->ypos + n);
1956	    break;
1957
1958	case 'm':   /* change attribute */
1959	    if (scp->term.num_param == 0) {
1960		scp->term.attr_mask = NORMAL_ATTR;
1961		scp->term.cur_attr =
1962		    scp->term.cur_color = scp->term.std_color;
1963		break;
1964	    }
1965	    for (i = 0; i < scp->term.num_param; i++) {
1966		switch (n = scp->term.param[i]) {
1967		case 0: /* back to normal */
1968		    scp->term.attr_mask = NORMAL_ATTR;
1969		    scp->term.cur_attr =
1970			scp->term.cur_color = scp->term.std_color;
1971		    break;
1972		case 1: /* bold */
1973		    scp->term.attr_mask |= BOLD_ATTR;
1974		    scp->term.cur_attr = mask2attr(&scp->term);
1975		    break;
1976		case 4: /* underline */
1977		    scp->term.attr_mask |= UNDERLINE_ATTR;
1978		    scp->term.cur_attr = mask2attr(&scp->term);
1979		    break;
1980		case 5: /* blink */
1981		    scp->term.attr_mask |= BLINK_ATTR;
1982		    scp->term.cur_attr = mask2attr(&scp->term);
1983		    break;
1984		case 7: /* reverse video */
1985		    scp->term.attr_mask |= REVERSE_ATTR;
1986		    scp->term.cur_attr = mask2attr(&scp->term);
1987		    break;
1988		case 30: case 31: /* set fg color */
1989		case 32: case 33: case 34:
1990		case 35: case 36: case 37:
1991		    scp->term.attr_mask |= FOREGROUND_CHANGED;
1992		    scp->term.cur_color =
1993			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
1994		    scp->term.cur_attr = mask2attr(&scp->term);
1995		    break;
1996		case 40: case 41: /* set bg color */
1997		case 42: case 43: case 44:
1998		case 45: case 46: case 47:
1999		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2000		    scp->term.cur_color =
2001			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2002		    scp->term.cur_attr = mask2attr(&scp->term);
2003		    break;
2004		}
2005	    }
2006	    break;
2007
2008	case 'x':
2009	    if (scp->term.num_param == 0)
2010		n = 0;
2011	    else
2012		n = scp->term.param[0];
2013	    switch (n) {
2014	    case 0:     /* reset attributes */
2015		scp->term.attr_mask = NORMAL_ATTR;
2016		scp->term.cur_attr =
2017		    scp->term.cur_color = scp->term.std_color =
2018		    current_default->std_color;
2019		scp->term.rev_color = current_default->rev_color;
2020		break;
2021	    case 1:     /* set ansi background */
2022		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2023		scp->term.cur_color = scp->term.std_color =
2024		    (scp->term.std_color & 0x0F00) |
2025		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2026		scp->term.cur_attr = mask2attr(&scp->term);
2027		break;
2028	    case 2:     /* set ansi foreground */
2029		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2030		scp->term.cur_color = scp->term.std_color =
2031		    (scp->term.std_color & 0xF000) |
2032		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2033		scp->term.cur_attr = mask2attr(&scp->term);
2034		break;
2035	    case 3:     /* set ansi attribute directly */
2036		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2037		scp->term.cur_color = scp->term.std_color =
2038		    (scp->term.param[1]&0xFF)<<8;
2039		scp->term.cur_attr = mask2attr(&scp->term);
2040		break;
2041	    case 5:     /* set ansi reverse video background */
2042		scp->term.rev_color =
2043		    (scp->term.rev_color & 0x0F00) |
2044		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2045		scp->term.cur_attr = mask2attr(&scp->term);
2046		break;
2047	    case 6:     /* set ansi reverse video foreground */
2048		scp->term.rev_color =
2049		    (scp->term.rev_color & 0xF000) |
2050		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2051		scp->term.cur_attr = mask2attr(&scp->term);
2052		break;
2053	    case 7:     /* set ansi reverse video directly */
2054		scp->term.rev_color =
2055		    (scp->term.param[1]&0xFF)<<8;
2056		scp->term.cur_attr = mask2attr(&scp->term);
2057		break;
2058	    }
2059	    break;
2060
2061	case 'z':   /* switch to (virtual) console n */
2062	    if (scp->term.num_param == 1)
2063		switch_scr(scp, scp->term.param[0]);
2064	    break;
2065	}
2066    }
2067    else if (scp->term.esc == 3) {
2068	if (c >= '0' && c <= '9') {
2069	    if (scp->term.num_param < MAX_ESC_PAR) {
2070	    if (scp->term.last_param != scp->term.num_param) {
2071		scp->term.last_param = scp->term.num_param;
2072		scp->term.param[scp->term.num_param] = 0;
2073	    }
2074	    else
2075		scp->term.param[scp->term.num_param] *= 10;
2076	    scp->term.param[scp->term.num_param] += c - '0';
2077	    return;
2078	    }
2079	}
2080	scp->term.num_param = scp->term.last_param + 1;
2081	switch (c) {
2082
2083	case ';':
2084	    if (scp->term.num_param < MAX_ESC_PAR)
2085		return;
2086	    break;
2087
2088	case 'A':   /* set display border color */
2089	    if (scp->term.num_param == 1)
2090		scp->border=scp->term.param[0] & 0xff;
2091		if (scp == cur_console)
2092		    set_border(scp->border);
2093	    break;
2094
2095	case 'B':   /* set bell pitch and duration */
2096	    if (scp->term.num_param == 2) {
2097		scp->bell_pitch = scp->term.param[0];
2098		scp->bell_duration = scp->term.param[1]*10;
2099	    }
2100	    break;
2101
2102	case 'C':   /* set cursor type & shape */
2103	    if (scp->term.num_param == 1) {
2104		if (scp->term.param[0] & 0x01)
2105		    flags |= BLINK_CURSOR;
2106		else
2107		    flags &= ~BLINK_CURSOR;
2108		if (scp->term.param[0] & 0x02) {
2109		    flags |= CHAR_CURSOR;
2110		    set_destructive_cursor(scp);
2111		} else
2112		    flags &= ~CHAR_CURSOR;
2113	    }
2114	    else if (scp->term.num_param == 2) {
2115		scp->cursor_start = scp->term.param[0] & 0x1F;
2116		scp->cursor_end = scp->term.param[1] & 0x1F;
2117		if (flags & CHAR_CURSOR)
2118			set_destructive_cursor(scp);
2119	    }
2120	    break;
2121
2122	case 'F':   /* set ansi foreground */
2123	    if (scp->term.num_param == 1) {
2124		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2125		scp->term.cur_color = scp->term.std_color =
2126		    (scp->term.std_color & 0xF000)
2127		    | ((scp->term.param[0] & 0x0F) << 8);
2128		scp->term.cur_attr = mask2attr(&scp->term);
2129	    }
2130	    break;
2131
2132	case 'G':   /* set ansi background */
2133	    if (scp->term.num_param == 1) {
2134		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2135		scp->term.cur_color = scp->term.std_color =
2136		    (scp->term.std_color & 0x0F00)
2137		    | ((scp->term.param[0] & 0x0F) << 12);
2138		scp->term.cur_attr = mask2attr(&scp->term);
2139	    }
2140	    break;
2141
2142	case 'H':   /* set ansi reverse video foreground */
2143	    if (scp->term.num_param == 1) {
2144		scp->term.rev_color =
2145		    (scp->term.rev_color & 0xF000)
2146		    | ((scp->term.param[0] & 0x0F) << 8);
2147		scp->term.cur_attr = mask2attr(&scp->term);
2148	    }
2149	    break;
2150
2151	case 'I':   /* set ansi reverse video background */
2152	    if (scp->term.num_param == 1) {
2153		scp->term.rev_color =
2154		    (scp->term.rev_color & 0x0F00)
2155		    | ((scp->term.param[0] & 0x0F) << 12);
2156		scp->term.cur_attr = mask2attr(&scp->term);
2157	    }
2158	    break;
2159	}
2160    }
2161    scp->term.esc = 0;
2162}
2163
2164static void
2165ansi_put(scr_stat *scp, u_char *buf, int len)
2166{
2167    u_char *ptr = buf;
2168
2169    /* make screensaver happy */
2170    if (scp == cur_console) {
2171	scrn_time_stamp = time.tv_sec;
2172	if (scrn_blanked) {
2173	    (*current_saver)(FALSE);
2174	    mark_all(scp);
2175	}
2176    }
2177    write_in_progress++;
2178outloop:
2179    if (scp->term.esc) {
2180	scan_esc(scp, *ptr++);
2181	len--;
2182    }
2183    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2184 	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
2185 	u_short cur_attr = scp->term.cur_attr;
2186 	u_short *cursor_pos = scp->cursor_pos;
2187	do {
2188	    /*
2189	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2190	     * pointers in the following to volatile should have no effect,
2191	     * but in fact speeds up this inner loop from 26 to 18 cycles
2192	     * (+ cache misses) on i486's.
2193	     */
2194#define	UCVP(ucp)	((u_char volatile *)(ucp))
2195	    *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
2196	    ptr++;
2197	    cnt--;
2198	} while (cnt && PRINTABLE(*ptr));
2199	len -= (cursor_pos - scp->cursor_pos);
2200	scp->xpos += (cursor_pos - scp->cursor_pos);
2201	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2202	mark_for_update(scp, cursor_pos - scp->scr_buf);
2203	scp->cursor_pos = cursor_pos;
2204	if (scp->xpos >= scp->xsize) {
2205	    scp->xpos = 0;
2206	    scp->ypos++;
2207	}
2208    }
2209    else  {
2210	switch(*ptr) {
2211	case 0x07:
2212	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2213	    break;
2214
2215	case 0x08:      /* non-destructive backspace */
2216	    if (scp->cursor_pos > scp->scr_buf) {
2217	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2218		scp->cursor_pos--;
2219	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2220		if (scp->xpos > 0)
2221		    scp->xpos--;
2222		else {
2223		    scp->xpos += scp->xsize - 1;
2224		    scp->ypos--;
2225		}
2226	    }
2227	    break;
2228
2229	case 0x09:  /* non-destructive tab */
2230	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2231	    scp->cursor_pos += (8 - scp->xpos % 8u);
2232	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2233	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2234	        scp->xpos = 0;
2235	        scp->ypos++;
2236	    }
2237	    break;
2238
2239	case 0x0a:  /* newline, same pos */
2240	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2241	    scp->cursor_pos += scp->xsize;
2242	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2243	    scp->ypos++;
2244	    break;
2245
2246	case 0x0c:  /* form feed, clears screen */
2247	    clear_screen(scp);
2248	    break;
2249
2250	case 0x0d:  /* return, return to pos 0 */
2251	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2252	    scp->cursor_pos -= scp->xpos;
2253	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2254	    scp->xpos = 0;
2255	    break;
2256
2257	case 0x1b:  /* start escape sequence */
2258	    scp->term.esc = 1;
2259	    scp->term.num_param = 0;
2260	    break;
2261	}
2262	ptr++; len--;
2263    }
2264    /* do we have to scroll ?? */
2265    if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
2266	remove_cutmarking(scp);
2267	if (scp->history) {
2268	    bcopyw(scp->scr_buf, scp->history_head,
2269		   scp->xsize * sizeof(u_short));
2270	    scp->history_head += scp->xsize;
2271	    if (scp->history_head + scp->xsize >
2272		scp->history + scp->history_size)
2273		scp->history_head = scp->history;
2274	}
2275	bcopyw(scp->scr_buf + scp->xsize, scp->scr_buf,
2276	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
2277	fillw(scp->term.cur_color | scr_map[0x20],
2278	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
2279	      scp->xsize);
2280	scp->cursor_pos -= scp->xsize;
2281	scp->ypos--;
2282    	mark_all(scp);
2283    }
2284    if (len)
2285	goto outloop;
2286    write_in_progress--;
2287    if (delayed_next_scr)
2288	switch_scr(scp, delayed_next_scr - 1);
2289}
2290
2291static void
2292scinit(void)
2293{
2294    u_short volatile *cp;
2295    u_short was;
2296    u_int hw_cursor;
2297    u_int i;
2298
2299    if (init_done != COLD)
2300	return;
2301    init_done = WARM;
2302    /*
2303     * Finish defaulting crtc variables for a mono screen.  Crtat is a
2304     * bogus common variable so that it can be shared with pcvt, so it
2305     * can't be statically initialized.  XXX.
2306     */
2307     Crtat = (u_short *)MONO_BUF;
2308    /*
2309     * If CGA memory seems to work, switch to color.
2310     */
2311    cp = (u_short *)CGA_BUF;
2312    was = *cp;
2313    *cp = (u_short) 0xA55A;
2314    if (*cp == 0xA55A) {
2315	Crtat = (u_short *)CGA_BUF;
2316	crtc_addr = COLOR_BASE;
2317    }
2318    *cp = was;
2319
2320    /*
2321     * Ensure a zero start address.  This is mainly to recover after
2322     * switching from pcvt using userconfig().  The registers are w/o
2323     * for old hardware so it's too hard to relocate the active screen
2324     * memory.
2325     */
2326    outb(crtc_addr, 12);
2327    outb(crtc_addr + 1, 0);
2328    outb(crtc_addr, 13);
2329    outb(crtc_addr + 1, 0);
2330
2331    /* extract cursor location */
2332    outb(crtc_addr, 14);
2333    hw_cursor = inb(crtc_addr + 1) << 8;
2334    outb(crtc_addr, 15);
2335    hw_cursor |= inb(crtc_addr + 1);
2336
2337    /*
2338     * Validate cursor location.  It may be off the screen.  Then we must
2339     * not use it for the initial buffer offset.
2340     */
2341    if (hw_cursor >= ROW * COL)
2342	hw_cursor = (ROW - 1) * COL;
2343
2344    /* move hardware cursor out of the way */
2345    outb(crtc_addr, 14);
2346    outb(crtc_addr + 1, 0xff);
2347    outb(crtc_addr, 15);
2348    outb(crtc_addr + 1, 0xff);
2349
2350    /* is this a VGA or higher ? */
2351    outb(crtc_addr, 7);
2352    if (inb(crtc_addr) == 7) {
2353	u_long  pa;
2354	u_long  segoff;
2355
2356	crtc_vga = TRUE;
2357	/*
2358	 * Get the BIOS video mode pointer.
2359	 */
2360	segoff = *(u_long *)pa_to_va(0x4a8);
2361	pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2362	if (ISMAPPED(pa, sizeof(u_long))) {
2363	    segoff = *(u_long *)pa_to_va(pa);
2364	    pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2365	    if (ISMAPPED(pa, 64))
2366		video_mode_ptr = (char *)pa_to_va(pa);
2367	}
2368    }
2369    current_default = &user_default;
2370    console[0] = &main_console;
2371    init_scp(console[0]);
2372
2373    /* copy screen to temporary buffer */
2374    bcopyw(Crtat, sc_buffer,
2375	   console[0]->xsize * console[0]->ysize * sizeof(u_short));
2376
2377    console[0]->scr_buf = console[0]->mouse_pos = sc_buffer;
2378    console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor;
2379    console[0]->xpos = hw_cursor % COL;
2380    console[0]->ypos = hw_cursor / COL;
2381    cur_console = console[0];
2382    for (i=1; i<MAXCONS; i++)
2383	console[i] = NULL;
2384    kernel_console.esc = 0;
2385    kernel_console.attr_mask = NORMAL_ATTR;
2386    kernel_console.cur_attr =
2387	kernel_console.cur_color = kernel_console.std_color =
2388	kernel_default.std_color;
2389    kernel_console.rev_color = kernel_default.rev_color;
2390    /* initialize mapscrn arrays to a one to one map */
2391    for (i=0; i<sizeof(scr_map); i++) {
2392	scr_map[i] = scr_rmap[i] = i;
2393    }
2394
2395#ifdef SC_SPLASH_SCREEN
2396    /*
2397     * Now put up a graphics image, and maybe cycle a
2398     * couble of palette entries for simple animation.
2399     */
2400    toggle_splash_screen(cur_console);
2401#endif
2402}
2403
2404static scr_stat
2405*alloc_scp()
2406{
2407    scr_stat *scp;
2408
2409    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
2410    init_scp(scp);
2411    scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos =
2412	(u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
2413			  M_DEVBUF, M_WAITOK);
2414    scp->mouse_pos = scp->mouse_oldpos =
2415	scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
2416			scp->mouse_xpos/8);
2417    scp->history_head = scp->history_pos = scp->history =
2418	(u_short *)malloc(scp->history_size*sizeof(u_short),
2419			  M_DEVBUF, M_WAITOK);
2420    bzero(scp->history_head, scp->history_size*sizeof(u_short));
2421/* SOS
2422    if (crtc_vga && video_mode_ptr)
2423	set_mode(scp);
2424*/
2425    clear_screen(scp);
2426    return scp;
2427}
2428
2429static void
2430init_scp(scr_stat *scp)
2431{
2432    scp->mode = M_VGA_C80x25;
2433    scp->font_size = FONT_16;
2434    scp->xsize = COL;
2435    scp->ysize = ROW;
2436    scp->start = scp->xsize * scp->ysize;
2437    scp->end = 0;
2438    scp->term.esc = 0;
2439    scp->term.attr_mask = NORMAL_ATTR;
2440    scp->term.cur_attr =
2441	scp->term.cur_color = scp->term.std_color =
2442	current_default->std_color;
2443    scp->term.rev_color = current_default->rev_color;
2444    scp->border = BG_BLACK;
2445    scp->cursor_start = *(char *)pa_to_va(0x461);
2446    scp->cursor_end = *(char *)pa_to_va(0x460);
2447    scp->mouse_xpos = scp->xsize*8/2;
2448    scp->mouse_ypos = scp->ysize*scp->font_size/2;
2449    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
2450    scp->mouse_signal = 0;
2451    scp->mouse_pid = 0;
2452    scp->mouse_proc = NULL;
2453    scp->bell_pitch = BELL_PITCH;
2454    scp->bell_duration = BELL_DURATION;
2455    scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
2456    scp->status |= CURSOR_ENABLED;
2457    scp->pid = 0;
2458    scp->proc = NULL;
2459    scp->smode.mode = VT_AUTO;
2460    scp->history_head = scp->history_pos = scp->history = NULL;
2461    scp->history_size = HISTORY_SIZE;
2462}
2463
2464static u_char
2465*get_fstr(u_int c, u_int *len)
2466{
2467    u_int i;
2468
2469    if (!(c & FKEY))
2470	return(NULL);
2471    i = (c & 0xFF) - F_FN;
2472    if (i > n_fkey_tab)
2473	return(NULL);
2474    *len = fkey_tab[i].len;
2475    return(fkey_tab[i].str);
2476}
2477
2478static void
2479history_to_screen(scr_stat *scp)
2480{
2481    int i;
2482
2483    for (i=0; i<scp->ysize; i++)
2484	bcopyw(scp->history + (((scp->history_pos - scp->history) +
2485	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
2486	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
2487	       scp->xsize * sizeof(u_short));
2488    mark_all(scp);
2489}
2490
2491static int
2492history_up_line(scr_stat *scp)
2493{
2494    if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
2495	scp->history_head) {
2496	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
2497	history_to_screen(scp);
2498	return 0;
2499    }
2500    else
2501	return -1;
2502}
2503
2504static int
2505history_down_line(scr_stat *scp)
2506{
2507    if (scp->history_pos != scp->history_head) {
2508	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
2509	history_to_screen(scp);
2510	return 0;
2511    }
2512    else
2513	return -1;
2514}
2515
2516/*
2517 * scgetc(flags) - get character from keyboard.
2518 * If flags & SCGETC_CN, then avoid harmful side effects.
2519 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
2520 * return NOKEY if there is nothing there.
2521 */
2522static u_int
2523scgetc(u_int flags)
2524{
2525    struct key_t *key;
2526    u_char scancode, keycode;
2527    u_int state, action;
2528    int c;
2529    static u_char esc_flag = 0, compose = 0;
2530    static u_int chr = 0;
2531
2532next_code:
2533    /* first see if there is something in the keyboard port */
2534    if (flags & SCGETC_NONBLOCK) {
2535	c = read_kbd_data_no_wait(sc_port);
2536	if (c == -1)
2537	    return(NOKEY);
2538    } else {
2539	do {
2540	    c = read_kbd_data(sc_port);
2541	} while(c == -1);
2542    }
2543    scancode = (u_char)c;
2544
2545    /* do the /dev/random device a favour */
2546    if (!(flags & SCGETC_CN))
2547	add_keyboard_randomness(scancode);
2548
2549    if (cur_console->status & KBD_RAW_MODE)
2550	return scancode;
2551
2552    keycode = scancode & 0x7F;
2553    switch (esc_flag) {
2554    case 0x00:      /* normal scancode */
2555	switch(scancode) {
2556	case 0xB8:  /* left alt (compose key) */
2557	    if (compose) {
2558		compose = 0;
2559		if (chr > 255) {
2560		    do_bell(cur_console,
2561			BELL_PITCH, BELL_DURATION);
2562		    chr = 0;
2563		}
2564	    }
2565	    break;
2566	case 0x38:
2567	    if (!compose) {
2568		compose = 1;
2569		chr = 0;
2570	    }
2571	    break;
2572	case 0xE0:
2573	case 0xE1:
2574	    esc_flag = scancode;
2575	    goto next_code;
2576	}
2577	break;
2578    case 0xE0:      /* 0xE0 prefix */
2579	esc_flag = 0;
2580	switch (keycode) {
2581	case 0x1C:  /* right enter key */
2582	    keycode = 0x59;
2583	    break;
2584	case 0x1D:  /* right ctrl key */
2585	    keycode = 0x5A;
2586	    break;
2587	case 0x35:  /* keypad divide key */
2588	    keycode = 0x5B;
2589	    break;
2590	case 0x37:  /* print scrn key */
2591	    keycode = 0x5C;
2592	    break;
2593	case 0x38:  /* right alt key (alt gr) */
2594	    keycode = 0x5D;
2595	    break;
2596	case 0x47:  /* grey home key */
2597	    keycode = 0x5E;
2598	    break;
2599	case 0x48:  /* grey up arrow key */
2600	    keycode = 0x5F;
2601	    break;
2602	case 0x49:  /* grey page up key */
2603	    keycode = 0x60;
2604	    break;
2605	case 0x4B:  /* grey left arrow key */
2606	    keycode = 0x61;
2607	    break;
2608	case 0x4D:  /* grey right arrow key */
2609	    keycode = 0x62;
2610	    break;
2611	case 0x4F:  /* grey end key */
2612	    keycode = 0x63;
2613	    break;
2614	case 0x50:  /* grey down arrow key */
2615	    keycode = 0x64;
2616	    break;
2617	case 0x51:  /* grey page down key */
2618	    keycode = 0x65;
2619	    break;
2620	case 0x52:  /* grey insert key */
2621	    keycode = 0x66;
2622	    break;
2623	case 0x53:  /* grey delete key */
2624	    keycode = 0x67;
2625	    break;
2626
2627	/* the following 3 are only used on the MS "Natural" keyboard */
2628	case 0x5b:  /* left Window key */
2629	    keycode = 0x69;
2630	    break;
2631	case 0x5c:  /* right Window key */
2632	    keycode = 0x6a;
2633	    break;
2634	case 0x5d:  /* menu key */
2635	    keycode = 0x6b;
2636	    break;
2637	default:    /* ignore everything else */
2638	    goto next_code;
2639	}
2640	break;
2641    case 0xE1:      /* 0xE1 prefix */
2642	esc_flag = 0;
2643	if (keycode == 0x1D)
2644	    esc_flag = 0x1D;
2645	goto next_code;
2646	/* NOT REACHED */
2647    case 0x1D:      /* pause / break */
2648	esc_flag = 0;
2649	if (keycode != 0x45)
2650	    goto next_code;
2651	keycode = 0x68;
2652	break;
2653    }
2654
2655    /* if scroll-lock pressed allow history browsing */
2656    if (cur_console->history && cur_console->status & SLKED) {
2657	int i;
2658
2659	cur_console->status &= ~CURSOR_ENABLED;
2660	if (!(cur_console->status & BUFFER_SAVED)) {
2661	    cur_console->status |= BUFFER_SAVED;
2662	    cur_console->history_save = cur_console->history_head;
2663
2664	    /* copy screen into top of history buffer */
2665	    for (i=0; i<cur_console->ysize; i++) {
2666		bcopyw(cur_console->scr_buf + (cur_console->xsize * i),
2667		       cur_console->history_head,
2668		       cur_console->xsize * sizeof(u_short));
2669		cur_console->history_head += cur_console->xsize;
2670		if (cur_console->history_head + cur_console->xsize >
2671		    cur_console->history + cur_console->history_size)
2672		    cur_console->history_head=cur_console->history;
2673	    }
2674	    cur_console->history_pos = cur_console->history_head;
2675	    history_to_screen(cur_console);
2676	}
2677	switch (scancode) {
2678	case 0x47:  /* home key */
2679	    cur_console->history_pos = cur_console->history_head;
2680	    history_to_screen(cur_console);
2681	    goto next_code;
2682
2683	case 0x4F:  /* end key */
2684	    cur_console->history_pos =
2685		WRAPHIST(cur_console, cur_console->history_head,
2686			 cur_console->xsize*cur_console->ysize);
2687	    history_to_screen(cur_console);
2688	    goto next_code;
2689
2690	case 0x48:  /* up arrow key */
2691	    if (history_up_line(cur_console))
2692		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2693	    goto next_code;
2694
2695	case 0x50:  /* down arrow key */
2696	    if (history_down_line(cur_console))
2697		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2698	    goto next_code;
2699
2700	case 0x49:  /* page up key */
2701	    for (i=0; i<cur_console->ysize; i++)
2702	    if (history_up_line(cur_console)) {
2703		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2704		break;
2705	    }
2706	    goto next_code;
2707
2708	case 0x51:  /* page down key */
2709	    for (i=0; i<cur_console->ysize; i++)
2710	    if (history_down_line(cur_console)) {
2711		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2712		break;
2713	    }
2714	    goto next_code;
2715	}
2716    }
2717
2718    if (compose) {
2719	switch (scancode) {
2720	/* key pressed process it */
2721	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
2722	    chr = (scancode - 0x40) + chr*10;
2723	    goto next_code;
2724	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
2725	    chr = (scancode - 0x47) + chr*10;
2726	    goto next_code;
2727	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
2728	    chr = (scancode - 0x4E) + chr*10;
2729	    goto next_code;
2730	case 0x52:              /* keypad 0 */
2731	    chr *= 10;
2732	    goto next_code;
2733
2734	/* key release, no interest here */
2735	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
2736	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
2737	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
2738	case 0xD2:              /* keypad 0 */
2739	    goto next_code;
2740
2741	case 0x38:              /* left alt key */
2742	    break;
2743	default:
2744	    if (chr) {
2745		compose = chr = 0;
2746		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2747		goto next_code;
2748	    }
2749	    break;
2750	}
2751    }
2752
2753    state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
2754    if ((!agrs && (cur_console->status & ALKED))
2755	|| (agrs && !(cur_console->status & ALKED)))
2756	keycode += ALTGR_OFFSET;
2757    key = &key_map.key[keycode];
2758    if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
2759	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
2760	state ^= 1;
2761
2762    /* Check for make/break */
2763    action = key->map[state];
2764    if (scancode & 0x80) {      /* key released */
2765	if (key->spcl & 0x80) {
2766	    switch (action) {
2767	    case LSH:
2768		shfts &= ~1;
2769		break;
2770	    case RSH:
2771		shfts &= ~2;
2772		break;
2773	    case LCTR:
2774		ctls &= ~1;
2775		break;
2776	    case RCTR:
2777		ctls &= ~2;
2778		break;
2779	    case LALT:
2780		alts &= ~1;
2781		break;
2782	    case RALT:
2783		alts &= ~2;
2784		break;
2785	    case NLK:
2786		nlkcnt = 0;
2787		break;
2788	    case CLK:
2789		clkcnt = 0;
2790		break;
2791	    case SLK:
2792		slkcnt = 0;
2793		break;
2794	    case ASH:
2795		agrs = 0;
2796		break;
2797	    case ALK:
2798		alkcnt = 0;
2799		break;
2800	    case META:
2801		metas = 0;
2802		break;
2803	    }
2804	}
2805	if (chr && !compose) {
2806	    action = chr;
2807	    chr = 0;
2808	    return(action);
2809	}
2810    } else {
2811	/* key pressed */
2812	if (key->spcl & (0x80>>state)) {
2813	    switch (action) {
2814	    /* LOCKING KEYS */
2815	    case NLK:
2816#ifdef SC_SPLASH_SCREEN
2817		toggle_splash_screen(cur_console); /* SOS XXX */
2818#endif
2819		if (!nlkcnt) {
2820		    nlkcnt++;
2821		    if (cur_console->status & NLKED)
2822			cur_console->status &= ~NLKED;
2823		    else
2824			cur_console->status |= NLKED;
2825		    update_leds(cur_console->status);
2826		}
2827		break;
2828	    case CLK:
2829		if (!clkcnt) {
2830		    clkcnt++;
2831		    if (cur_console->status & CLKED)
2832			cur_console->status &= ~CLKED;
2833		    else
2834			cur_console->status |= CLKED;
2835		    update_leds(cur_console->status);
2836		}
2837		break;
2838	    case SLK:
2839		if (!slkcnt) {
2840		    slkcnt++;
2841		    if (cur_console->status & SLKED) {
2842			cur_console->status &= ~SLKED;
2843			if (cur_console->status & BUFFER_SAVED){
2844			    int i;
2845			    u_short *ptr = cur_console->history_save;
2846
2847			    for (i=0; i<cur_console->ysize; i++) {
2848				bcopyw(ptr,
2849				       cur_console->scr_buf +
2850				       (cur_console->xsize*i),
2851				       cur_console->xsize * sizeof(u_short));
2852				ptr += cur_console->xsize;
2853				if (ptr + cur_console->xsize >
2854				    cur_console->history +
2855				    cur_console->history_size)
2856				    ptr = cur_console->history;
2857			    }
2858			    cur_console->status &= ~BUFFER_SAVED;
2859			    cur_console->history_head=cur_console->history_save;
2860			    cur_console->status |= CURSOR_ENABLED;
2861			    mark_all(cur_console);
2862			}
2863			scstart(VIRTUAL_TTY(get_scr_num()));
2864		    }
2865		    else
2866			cur_console->status |= SLKED;
2867		    update_leds(cur_console->status);
2868		}
2869		break;
2870	    case ALK:
2871		if (!alkcnt) {
2872		    alkcnt++;
2873		    if (cur_console->status & ALKED)
2874			cur_console->status &= ~ALKED;
2875		    else
2876			cur_console->status |= ALKED;
2877		    update_leds(cur_console->status);
2878		}
2879		break;
2880
2881	    /* NON-LOCKING KEYS */
2882	    case NOP:
2883		break;
2884	    case SPSC:
2885#ifdef SC_SPLASH_SCREEN
2886		toggle_splash_screen(cur_console);
2887#endif
2888		break;
2889	    case RBT:
2890		shutdown_nice();
2891		break;
2892	    case SUSP:
2893#if NAPM > 0
2894		apm_suspend();
2895#endif
2896		break;
2897
2898	    case DBG:
2899#ifdef DDB          /* try to switch to console 0 */
2900		if (cur_console->smode.mode == VT_AUTO &&
2901		    console[0]->smode.mode == VT_AUTO)
2902		    switch_scr(cur_console, 0);
2903		Debugger("manual escape to debugger");
2904#else
2905		printf("No debugger in kernel\n");
2906#endif
2907		break;
2908	    case LSH:
2909		shfts |= 1;
2910		break;
2911	    case RSH:
2912		shfts |= 2;
2913		break;
2914	    case LCTR:
2915		ctls |= 1;
2916		break;
2917	    case RCTR:
2918		ctls |= 2;
2919		break;
2920	    case LALT:
2921		alts |= 1;
2922		break;
2923	    case RALT:
2924		alts |= 2;
2925		break;
2926	    case ASH:
2927		agrs = 1;
2928		break;
2929	    case META:
2930		metas = 1;
2931		break;
2932	    case NEXT:
2933		switch_scr(cur_console, (get_scr_num() + 1) % MAXCONS);
2934		break;
2935	    case BTAB:
2936		return(BKEY);
2937	    default:
2938		if (action >= F_SCR && action <= L_SCR) {
2939		    switch_scr(cur_console, action - F_SCR);
2940		    break;
2941		}
2942		if (action >= F_FN && action <= L_FN)
2943		    action |= FKEY;
2944		return(action);
2945	    }
2946	}
2947	else {
2948	    if (metas)
2949		action |= MKEY;
2950	    return(action);
2951	}
2952    }
2953    goto next_code;
2954}
2955
2956int
2957scmmap(dev_t dev, int offset, int nprot)
2958{
2959    if (offset > 0x20000 - PAGE_SIZE)
2960	return -1;
2961    return i386_btop((VIDEOMEM + offset));
2962}
2963
2964/*
2965 * Calculate hardware attributes word using logical attributes mask and
2966 * hardware colors
2967 */
2968
2969static int
2970mask2attr(struct term_stat *term)
2971{
2972    int attr, mask = term->attr_mask;
2973
2974    if (mask & REVERSE_ATTR) {
2975	attr = ((mask & FOREGROUND_CHANGED) ?
2976		((term->cur_color & 0xF000) >> 4) :
2977		(term->rev_color & 0x0F00)) |
2978	       ((mask & BACKGROUND_CHANGED) ?
2979		((term->cur_color & 0x0F00) << 4) :
2980		(term->rev_color & 0xF000));
2981    } else
2982	attr = term->cur_color;
2983
2984    /* XXX: underline mapping for Hercules adapter can be better */
2985    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
2986	attr ^= 0x0800;
2987    if (mask & BLINK_ATTR)
2988	attr ^= 0x8000;
2989
2990    return attr;
2991}
2992
2993static void
2994update_leds(int which)
2995{
2996    int s;
2997    static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2998
2999    /* replace CAPS led with ALTGR led for ALTGR keyboards */
3000    if (key_map.n_keys > ALTGR_OFFSET) {
3001	if (which & ALKED)
3002	    which |= CLKED;
3003	else
3004	    which &= ~CLKED;
3005    }
3006
3007    s = spltty();
3008    send_kbd_command_and_data(sc_port, KBDC_SET_LEDS,
3009			      xlate_leds[which & LED_MASK]);
3010    splx(s);
3011}
3012
3013void
3014set_mode(scr_stat *scp)
3015{
3016    char *modetable;
3017    char special_modetable[64];
3018
3019    if (scp != cur_console)
3020	return;
3021
3022    /* setup video hardware for the given mode */
3023    switch (scp->mode) {
3024    case M_VGA_M80x60:
3025	bcopyw(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64);
3026	goto special_80x60;
3027
3028    case M_VGA_C80x60:
3029	bcopyw(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64);
3030special_80x60:
3031	special_modetable[2]  = 0x08;
3032	special_modetable[19] = 0x47;
3033	goto special_480l;
3034
3035    case M_VGA_M80x30:
3036	bcopyw(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64);
3037	goto special_80x30;
3038
3039    case M_VGA_C80x30:
3040	bcopyw(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64);
3041special_80x30:
3042	special_modetable[19] = 0x4f;
3043special_480l:
3044	special_modetable[9] |= 0xc0;
3045	special_modetable[16] = 0x08;
3046	special_modetable[17] = 0x3e;
3047	special_modetable[26] = 0xea;
3048	special_modetable[28] = 0xdf;
3049	special_modetable[31] = 0xe7;
3050	special_modetable[32] = 0x04;
3051	modetable = special_modetable;
3052	goto setup_mode;
3053
3054    case M_ENH_B80x43:
3055	bcopyw(video_mode_ptr+(64*M_ENH_B80x25), &special_modetable, 64);
3056	goto special_80x43;
3057
3058    case M_ENH_C80x43:
3059	bcopyw(video_mode_ptr+(64*M_ENH_C80x25), &special_modetable, 64);
3060special_80x43:
3061	special_modetable[28] = 87;
3062	goto special_80x50;
3063
3064    case M_VGA_M80x50:
3065	bcopyw(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64);
3066	goto special_80x50;
3067
3068    case M_VGA_C80x50:
3069	bcopyw(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64);
3070special_80x50:
3071	special_modetable[2] = 8;
3072	special_modetable[19] = 7;
3073	modetable = special_modetable;
3074	goto setup_mode;
3075
3076    case M_VGA_C40x25: case M_VGA_C80x25:
3077    case M_VGA_M80x25:
3078    case M_B40x25:     case M_C40x25:
3079    case M_B80x25:     case M_C80x25:
3080    case M_ENH_B40x25: case M_ENH_C40x25:
3081    case M_ENH_B80x25: case M_ENH_C80x25:
3082
3083	modetable = video_mode_ptr + (scp->mode * 64);
3084setup_mode:
3085	set_vgaregs(modetable);
3086	scp->font_size = *(modetable + 2);
3087
3088	/* set font type (size) */
3089	if (scp->font_size < FONT_14) {
3090	    if (fonts_loaded & FONT_8)
3091		copy_font(LOAD, FONT_8, font_8);
3092	    outb(TSIDX, 0x03); outb(TSREG, 0x0A);   /* font 2 */
3093	} else if (scp->font_size >= FONT_16) {
3094	    if (fonts_loaded & FONT_16)
3095		copy_font(LOAD, FONT_16, font_16);
3096	    outb(TSIDX, 0x03); outb(TSREG, 0x00);   /* font 0 */
3097	} else {
3098	    if (fonts_loaded & FONT_14)
3099		copy_font(LOAD, FONT_14, font_14);
3100	    outb(TSIDX, 0x03); outb(TSREG, 0x05);   /* font 1 */
3101	}
3102	if (flags & CHAR_CURSOR)
3103	    set_destructive_cursor(scp);
3104	mark_all(scp);
3105	break;
3106
3107    case M_BG320:     case M_CG320:     case M_BG640:
3108    case M_CG320_D:   case M_CG640_E:
3109    case M_CG640x350: case M_ENH_CG640:
3110    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
3111
3112	set_vgaregs(video_mode_ptr + (scp->mode * 64));
3113	scp->font_size = FONT_NONE;
3114	break;
3115
3116    default:
3117	/* call user defined function XXX */
3118	break;
3119    }
3120
3121    /* set border color for this (virtual) console */
3122    set_border(scp->border);
3123    return;
3124}
3125
3126void
3127set_border(u_char color)
3128{
3129    inb(crtc_addr+6);               /* reset flip-flop */
3130    outb(ATC, 0x11); outb(ATC, color);
3131    inb(crtc_addr+6);               /* reset flip-flop */
3132    outb(ATC, 0x20);                /* enable Palette */
3133}
3134
3135static void
3136set_vgaregs(char *modetable)
3137{
3138    int i, s = splhigh();
3139
3140    outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
3141    outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
3142    for (i=0; i<4; i++) {           		/* program sequencer */
3143	outb(TSIDX, i+1);
3144	outb(TSREG, modetable[i+5]);
3145    }
3146    outb(MISC, modetable[9]);       		/* set dot-clock */
3147    outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
3148    outb(crtc_addr, 0x11);
3149    outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
3150    for (i=0; i<25; i++) {          		/* program crtc */
3151	outb(crtc_addr, i);
3152	if (i == 14 || i == 15)     		/* no hardware cursor */
3153	    outb(crtc_addr+1, 0xff);
3154	else
3155	    outb(crtc_addr+1, modetable[i+10]);
3156    }
3157    inb(crtc_addr+6);           		/* reset flip-flop */
3158    for (i=0; i<20; i++) {          		/* program attribute ctrl */
3159	outb(ATC, i);
3160	outb(ATC, modetable[i+35]);
3161    }
3162    for (i=0; i<9; i++) {           		/* program graph data ctrl */
3163	outb(GDCIDX, i);
3164	outb(GDCREG, modetable[i+55]);
3165    }
3166    inb(crtc_addr+6);           		/* reset flip-flop */
3167    outb(ATC, 0x20);            		/* enable palette */
3168    splx(s);
3169}
3170
3171static void
3172set_font_mode()
3173{
3174    /* setup vga for loading fonts (graphics plane mode) */
3175    inb(crtc_addr+6);           		/* reset flip-flop */
3176    outb(ATC, 0x10); outb(ATC, 0x01);
3177    inb(crtc_addr+6);               		/* reset flip-flop */
3178    outb(ATC, 0x20);            		/* enable palette */
3179#if SLOW_VGA
3180    outb(TSIDX, 0x02); outb(TSREG, 0x04);
3181    outb(TSIDX, 0x04); outb(TSREG, 0x06);
3182    outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
3183    outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
3184    outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
3185#else
3186    outw(TSIDX, 0x0402);
3187    outw(TSIDX, 0x0604);
3188    outw(GDCIDX, 0x0204);
3189    outw(GDCIDX, 0x0005);
3190    outw(GDCIDX, 0x0506);               /* addr = a0000, 64kb */
3191#endif
3192}
3193
3194static void
3195set_normal_mode()
3196{
3197    char *modetable;
3198    int s = splhigh();
3199
3200    switch (cur_console->mode) {
3201    case M_VGA_M80x60:
3202    case M_VGA_M80x50:
3203    case M_VGA_M80x30:
3204	modetable = video_mode_ptr + (64*M_VGA_M80x25);
3205	break;
3206
3207    case M_VGA_C80x60:
3208    case M_VGA_C80x50:
3209    case M_VGA_C80x30:
3210	modetable = video_mode_ptr + (64*M_VGA_C80x25);
3211	break;
3212
3213    case M_ENH_B80x43:
3214	modetable = video_mode_ptr + (64*M_ENH_B80x25);
3215	break;
3216
3217    case M_ENH_C80x43:
3218	modetable = video_mode_ptr + (64*M_ENH_C80x25);
3219	break;
3220
3221    case M_VGA_C40x25: case M_VGA_C80x25:
3222    case M_VGA_M80x25:
3223    case M_B40x25:     case M_C40x25:
3224    case M_B80x25:     case M_C80x25:
3225    case M_ENH_B40x25: case M_ENH_C40x25:
3226    case M_ENH_B80x25: case M_ENH_C80x25:
3227
3228    case M_BG320:     case M_CG320:     case M_BG640:
3229    case M_CG320_D:   case M_CG640_E:
3230    case M_CG640x350: case M_ENH_CG640:
3231    case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
3232	modetable = video_mode_ptr + (cur_console->mode * 64);
3233
3234    default:
3235	modetable = video_mode_ptr + (64*M_VGA_C80x25);
3236    }
3237
3238    /* setup vga for normal operation mode again */
3239    inb(crtc_addr+6);           		/* reset flip-flop */
3240    outb(ATC, 0x10); outb(ATC, modetable[0x10+35]);
3241    inb(crtc_addr+6);               		/* reset flip-flop */
3242    outb(ATC, 0x20);            		/* enable palette */
3243#if SLOW_VGA
3244    outb(TSIDX, 0x02); outb(TSREG, modetable[0x02+4]);
3245    outb(TSIDX, 0x04); outb(TSREG, modetable[0x04+4]);
3246    outb(GDCIDX, 0x04); outb(GDCREG, modetable[0x04+55]);
3247    outb(GDCIDX, 0x05); outb(GDCREG, modetable[0x05+55]);
3248    outb(GDCIDX, 0x06); outb(GDCREG, modetable[0x06+55]);
3249#else
3250    outw(TSIDX, 0x0002 | (modetable[0x02+4]<<8));
3251    outw(TSIDX, 0x0004 | (modetable[0x04+4]<<8));
3252    outw(GDCIDX, 0x0004 | (modetable[0x04+55]<<8));
3253    outw(GDCIDX, 0x0005 | (modetable[0x05+55]<<8));
3254    outw(GDCIDX, 0x0006 | (modetable[0x06+55]<<8));
3255#endif
3256    splx(s);
3257}
3258
3259void
3260copy_font(int operation, int font_type, char* font_image)
3261{
3262    int ch, line, segment, fontsize;
3263    u_char val;
3264
3265    /* dont mess with console we dont know video mode on */
3266    if (cur_console->status & UNKNOWN_MODE)
3267	return;
3268
3269    switch (font_type) {
3270    default:
3271    case FONT_8:
3272	segment = 0x8000;
3273	fontsize = 8;
3274	break;
3275    case FONT_14:
3276	segment = 0x4000;
3277	fontsize = 14;
3278	break;
3279    case FONT_16:
3280	segment = 0x0000;
3281	fontsize = 16;
3282	break;
3283    }
3284    outb(TSIDX, 0x01); val = inb(TSREG);        /* disable screen */
3285    outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
3286    set_font_mode();
3287    for (ch=0; ch < 256; ch++)
3288	for (line=0; line < fontsize; line++)
3289	if (operation)
3290	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
3291		    font_image[(ch*fontsize)+line];
3292	else
3293	    font_image[(ch*fontsize)+line] =
3294	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
3295    set_normal_mode();
3296    outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
3297}
3298
3299static void
3300set_destructive_cursor(scr_stat *scp)
3301{
3302    u_char cursor[32];
3303    caddr_t address;
3304    int i;
3305    char *font_buffer;
3306
3307
3308    if (scp->font_size < FONT_14) {
3309	font_buffer = font_8;
3310	address = (caddr_t)VIDEOMEM + 0x8000;
3311    }
3312    else if (scp->font_size >= FONT_16) {
3313	font_buffer = font_16;
3314	address = (caddr_t)VIDEOMEM;
3315    }
3316    else {
3317	font_buffer = font_14;
3318	address = (caddr_t)VIDEOMEM + 0x4000;
3319    }
3320
3321    if (scp->status & MOUSE_VISIBLE) {
3322	if ((scp->cursor_saveunder & 0xff) == 0xd0)
3323    	    bcopyw(&scp->mouse_cursor[0], cursor, scp->font_size);
3324	else if ((scp->cursor_saveunder & 0xff) == 0xd1)
3325    	    bcopyw(&scp->mouse_cursor[32], cursor, scp->font_size);
3326	else if ((scp->cursor_saveunder & 0xff) == 0xd2)
3327    	    bcopyw(&scp->mouse_cursor[64], cursor, scp->font_size);
3328	else if ((scp->cursor_saveunder & 0xff) == 0xd3)
3329    	    bcopyw(&scp->mouse_cursor[96], cursor, scp->font_size);
3330	else
3331	    bcopyw(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
3332 	       	   cursor, scp->font_size);
3333    }
3334    else
3335    	bcopyw(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
3336 	       cursor, scp->font_size);
3337    for (i=0; i<32; i++)
3338	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
3339	    (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
3340	    cursor[i] |= 0xff;
3341    while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3342    set_font_mode();
3343    bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
3344    set_normal_mode();
3345}
3346
3347static void
3348set_mouse_pos(scr_stat *scp)
3349{
3350    static int last_xpos = -1, last_ypos = -1;
3351    /*
3352     * the margins imposed here are not ideal, we loose
3353     * a couble of pixels on the borders..
3354     */
3355    if (scp->mouse_xpos < 0)
3356	scp->mouse_xpos = 0;
3357    if (scp->mouse_ypos < 0)
3358	scp->mouse_ypos = 0;
3359    if (scp->mouse_xpos > (scp->xsize*8)-2)
3360	scp->mouse_xpos = (scp->xsize*8)-2;
3361    if (scp->mouse_ypos > (scp->ysize*scp->font_size)-2)
3362	scp->mouse_ypos = (scp->ysize*scp->font_size)-2;
3363
3364    if (scp->status & UNKNOWN_MODE)
3365	return;
3366
3367    if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
3368	scp->status |= MOUSE_MOVED;
3369
3370    	scp->mouse_pos = scp->scr_buf +
3371	    ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
3372
3373	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) {
3374	    u_short *ptr;
3375	    int i = 0;
3376
3377	    mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
3378	    mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
3379	    scp->mouse_cut_end = scp->mouse_pos;
3380	    for (ptr = (scp->mouse_cut_start > scp->mouse_cut_end
3381			? scp->mouse_cut_end : scp->mouse_cut_start);
3382		 ptr <= (scp->mouse_cut_start > scp->mouse_cut_end
3383			 ? scp->mouse_cut_start : scp->mouse_cut_end);
3384	    	 ptr++) {
3385	        cut_buffer[i++] = *ptr & 0xff;
3386	        if (((ptr - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
3387		    cut_buffer[i++] = '\n';
3388	        }
3389	    }
3390	    cut_buffer[i] = 0x00;
3391        }
3392    }
3393}
3394
3395static void
3396mouse_cut_start(scr_stat *scp)
3397{
3398    int i;
3399
3400    if (scp->status & MOUSE_VISIBLE) {
3401	if (scp->mouse_pos == scp->mouse_cut_start &&
3402	    scp->mouse_cut_start == scp->mouse_cut_end) {
3403	    cut_buffer[0] = 0x00;
3404	    remove_cutmarking(scp);
3405	}
3406	else {
3407	    scp->mouse_cut_start = scp->mouse_cut_end = scp->mouse_pos;
3408	    cut_buffer[0] = *scp->mouse_cut_start & 0xff;
3409	    cut_buffer[1] = 0x00;
3410	    scp->status |= MOUSE_CUTTING;
3411	}
3412    	mark_all(scp);
3413	/* delete all other screens cut markings */
3414	for (i=0; i<MAXCONS; i++) {
3415	    if (console[i] == NULL || console[i] == scp)
3416		continue;
3417	    remove_cutmarking(console[i]);
3418	}
3419    }
3420}
3421
3422static void
3423mouse_cut_end(scr_stat *scp)
3424{
3425    if (scp->status & MOUSE_VISIBLE) {
3426	scp->status &= ~MOUSE_CUTTING;
3427    }
3428}
3429
3430static void
3431mouse_paste(scr_stat *scp)
3432{
3433    if (scp->status & MOUSE_VISIBLE) {
3434	struct tty *tp;
3435	u_char *ptr = cut_buffer;
3436
3437	tp = VIRTUAL_TTY(get_scr_num());
3438	while (*ptr)
3439	    (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
3440    }
3441}
3442
3443static void
3444draw_mouse_image(scr_stat *scp)
3445{
3446    caddr_t address;
3447    int i;
3448    char *font_buffer;
3449    u_short buffer[32];
3450    u_short xoffset, yoffset;
3451    u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
3452    int font_size = scp->font_size;
3453
3454    if (font_size < FONT_14) {
3455	font_buffer = font_8;
3456	address = (caddr_t)VIDEOMEM + 0x8000;
3457    }
3458    else if (font_size >= FONT_16) {
3459	font_buffer = font_16;
3460	address = (caddr_t)VIDEOMEM;
3461    }
3462    else {
3463	font_buffer = font_14;
3464	address = (caddr_t)VIDEOMEM + 0x4000;
3465    }
3466    xoffset = scp->mouse_xpos % 8;
3467    yoffset = scp->mouse_ypos % font_size;
3468
3469    /* prepare mousepointer char's bitmaps */
3470    bcopyw(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
3471	   &scp->mouse_cursor[0], font_size);
3472    bcopyw(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
3473	   &scp->mouse_cursor[32], font_size);
3474    bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
3475	   &scp->mouse_cursor[64], font_size);
3476    bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
3477	   &scp->mouse_cursor[96], font_size);
3478    for (i=0; i<font_size; i++) {
3479	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
3480	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
3481    }
3482
3483    /* now and-or in the mousepointer image */
3484    for (i=0; i<16; i++) {
3485	buffer[i+yoffset] =
3486	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
3487	    | (mouse_or_mask[i] >> xoffset);
3488    }
3489    for (i=0; i<font_size; i++) {
3490	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
3491	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
3492	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
3493	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
3494    }
3495
3496    scp->mouse_oldpos = scp->mouse_pos;
3497
3498    /* wait for vertical retrace to avoid jitter on some videocards */
3499    while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
3500    set_font_mode();
3501    bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
3502    set_normal_mode();
3503    *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0;
3504    *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2;
3505    if (scp->mouse_xpos < (scp->xsize-1)*8) {
3506    	*(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1;
3507    	*(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3;
3508    }
3509    mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
3510    mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
3511}
3512
3513static void
3514remove_mouse_image(scr_stat *scp)
3515{
3516    u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf);
3517
3518    *(crt_pos) = *(scp->mouse_oldpos);
3519    *(crt_pos+1) = *(scp->mouse_oldpos+1);
3520    *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
3521    *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
3522    mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
3523    mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
3524}
3525
3526static void
3527draw_cutmarking(scr_stat *scp)
3528{
3529    u_short *ptr;
3530    u_short och, nch;
3531
3532    for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
3533	nch = och = *(Crtat + (ptr - scp->scr_buf));
3534	/* are we outside the selected area ? */
3535	if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
3536	            scp->mouse_cut_end : scp->mouse_cut_start) ||
3537	     ptr > (scp->mouse_cut_start > scp->mouse_cut_end ?
3538	            scp->mouse_cut_start : scp->mouse_cut_end)) {
3539	    if (ptr != scp->cursor_pos)
3540		nch = (och & 0xff) | (*ptr & 0xff00);
3541	}
3542	else {
3543	    /* are we clear of the cursor image ? */
3544	    if (ptr != scp->cursor_pos)
3545		nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
3546	    else {
3547		if (flags & CHAR_CURSOR)
3548		    nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
3549		else
3550		    if (!(flags & BLINK_CURSOR))
3551		        nch = (och & 0xff) | (*ptr & 0xff00);
3552	    }
3553	}
3554	if (nch != och)
3555	    *(Crtat + (ptr - scp->scr_buf)) = nch;
3556    }
3557}
3558
3559static void
3560remove_cutmarking(scr_stat *scp)
3561{
3562    scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3563    scp->status &= ~MOUSE_CUTTING;
3564    mark_all(scp);
3565}
3566
3567static void
3568save_palette(void)
3569{
3570    int i;
3571
3572    outb(PALRADR, 0x00);
3573    for (i=0x00; i<0x300; i++)
3574	palette[i] = inb(PALDATA);
3575    inb(crtc_addr+6);           /* reset flip/flop */
3576}
3577
3578void
3579load_palette(void)
3580{
3581    int i;
3582
3583    outb(PIXMASK, 0xFF);            /* no pixelmask */
3584    outb(PALWADR, 0x00);
3585    for (i=0x00; i<0x300; i++)
3586	 outb(PALDATA, palette[i]);
3587    inb(crtc_addr+6);           /* reset flip/flop */
3588    outb(ATC, 0x20);            /* enable palette */
3589}
3590
3591static void
3592do_bell(scr_stat *scp, int pitch, int duration)
3593{
3594    if (flags & VISUAL_BELL) {
3595	if (blink_in_progress)
3596	    return;
3597	blink_in_progress = 4;
3598	if (scp != cur_console)
3599	    blink_in_progress += 2;
3600	blink_screen(cur_console);
3601	timeout((timeout_func_t)blink_screen, cur_console, hz/10);
3602    } else {
3603	if (scp != cur_console)
3604	    pitch *= 2;
3605	sysbeep(pitch, duration);
3606    }
3607}
3608
3609static void
3610blink_screen(scr_stat *scp)
3611{
3612    if (blink_in_progress > 1) {
3613	if (blink_in_progress & 1)
3614	    fillw(kernel_default.std_color | scr_map[0x20],
3615		  Crtat, scp->xsize * scp->ysize);
3616	else
3617	    fillw(kernel_default.rev_color | scr_map[0x20],
3618		  Crtat, scp->xsize * scp->ysize);
3619	blink_in_progress--;
3620	timeout((timeout_func_t)blink_screen, scp, hz/10);
3621    }
3622    else {
3623	blink_in_progress = FALSE;
3624    	mark_all(scp);
3625	if (delayed_next_scr)
3626	    switch_scr(scp, delayed_next_scr - 1);
3627    }
3628}
3629
3630#ifdef SC_SPLASH_SCREEN
3631static void
3632toggle_splash_screen(scr_stat *scp)
3633{
3634    static int toggle = 0;
3635    static u_char save_mode;
3636    int s = splhigh();
3637
3638    if (toggle) {
3639	scp->mode = save_mode;
3640	scp->status &= ~UNKNOWN_MODE;
3641	set_mode(scp);
3642	toggle = 0;
3643    }
3644    else {
3645	save_mode = scp->mode;
3646	scp->mode = M_VGA_CG320;
3647	scp->status |= UNKNOWN_MODE;
3648	set_mode(scp);
3649	/* load image */
3650	toggle = 1;
3651    }
3652    splx(s);
3653}
3654#endif
3655#endif /* NSC */
3656