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