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