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