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