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