Revamp SYSINIT ordering. Relabel sysinit IDs (SI_* in sys/kernel.h) to
[dragonfly.git] / sys / dev / misc / syscons / syscons.c
1 /*-
2  * Copyright (c) 1992-1998 Søren Schmidt
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The DragonFly Project
6  * by Sascha Wildner <saw@online.de>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/dev/syscons/syscons.c,v 1.336.2.17 2004/03/25 08:41:09 ru Exp $
32  * $DragonFly: src/sys/dev/misc/syscons/syscons.c,v 1.31 2007/04/30 07:18:49 dillon Exp $
33  */
34
35 #include "use_splash.h"
36 #include "opt_syscons.h"
37 #include "opt_ddb.h"
38 #include "use_apm.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/eventhandler.h>
43 #include <sys/reboot.h>
44 #include <sys/conf.h>
45 #include <sys/proc.h>
46 #include <sys/signalvar.h>
47 #include <sys/sysctl.h>
48 #include <sys/tty.h>
49 #include <sys/kernel.h>
50 #include <sys/cons.h>
51 #include <sys/random.h>
52 #include <sys/thread2.h>
53
54 #include <machine/clock.h>
55 #include <machine/console.h>
56 #include <machine/psl.h>
57 #include <machine/pc/display.h>
58 #include <machine/apm_bios.h>
59 #include <machine/frame.h>
60
61 #include <dev/misc/kbd/kbdreg.h>
62 #include <dev/video/fb/fbreg.h>
63 #include <dev/video/fb/splashreg.h>
64 #include "syscons.h"
65
66 #define COLD 0
67 #define WARM 1
68
69 #define DEFAULT_BLANKTIME       (5*60)          /* 5 minutes */
70 #define MAX_BLANKTIME           (7*24*60*60)    /* 7 days!? */
71
72 #define KEYCODE_BS              0x0e            /* "<-- Backspace" key, XXX */
73
74 MALLOC_DEFINE(M_SYSCONS, "syscons", "Syscons");
75
76 typedef struct default_attr {
77         int             std_color;              /* normal hardware color */
78         int             rev_color;              /* reverse hardware color */
79 } default_attr;
80
81 static default_attr user_default = {
82     SC_NORM_ATTR,
83     SC_NORM_REV_ATTR,
84 };
85
86 static default_attr kernel_default = {
87     SC_KERNEL_CONS_ATTR,
88     SC_KERNEL_CONS_REV_ATTR,
89 };
90
91 static  int             sc_console_unit = -1;
92 static  scr_stat        *sc_console;
93 static  struct tty      *sc_console_tty;
94 static  void            *kernel_console_ts;
95
96 static  char            init_done = COLD;
97 static  char            shutdown_in_progress = FALSE;
98 static  char            sc_malloc = FALSE;
99
100 static  int             saver_mode = CONS_NO_SAVER; /* LKM/user saver */
101 static  int             run_scrn_saver = FALSE; /* should run the saver? */
102 static  long            scrn_blank_time = 0;    /* screen saver timeout value */
103 #if NSPLASH > 0
104 static  int             scrn_blanked;           /* # of blanked screen */
105 static  int             sticky_splash = FALSE;
106
107 static  void            none_saver(sc_softc_t *sc, int blank) { }
108 static  void            (*current_saver)(sc_softc_t *, int) = none_saver;
109 #endif
110
111 #if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
112 #include "font.h"
113 #endif
114
115         d_ioctl_t       *sc_user_ioctl;
116
117 static  bios_values_t   bios_value;
118
119 static  int             enable_panic_key;
120 SYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key,
121            0, "");
122
123 #define SC_CONSOLECTL   255
124
125 #define VIRTUAL_TTY(sc, x) (SC_DEV((sc), (x)) != NULL ? \
126         SC_DEV((sc), (x))->si_tty : NULL)
127 #define ISTTYOPEN(tp)   ((tp) && ((tp)->t_state & TS_ISOPEN))
128
129 static  int             debugger;
130
131 /* prototypes */
132 static int scvidprobe(int unit, int flags, int cons);
133 static int sckbdprobe(int unit, int flags, int cons);
134 static void scmeminit(void *arg);
135 static int scdevtounit(cdev_t dev);
136 static kbd_callback_func_t sckbdevent;
137 static int scparam(struct tty *tp, struct termios *t);
138 static void scstart(struct tty *tp);
139 static void scinit(int unit, int flags);
140 static void scterm(int unit, int flags);
141 static void scshutdown(void *arg, int howto);
142 static u_int scgetc(sc_softc_t *sc, u_int flags);
143 #define SCGETC_CN       1
144 #define SCGETC_NONBLOCK 2
145 static int sccngetch(int flags);
146 static void sccnupdate(scr_stat *scp);
147 static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
148 static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
149 static timeout_t scrn_timer;
150 static int and_region(int *s1, int *e1, int s2, int e2);
151 static void scrn_update(scr_stat *scp, int show_cursor);
152
153 #if NSPLASH > 0
154 static int scsplash_callback(int event, void *arg);
155 static void scsplash_saver(sc_softc_t *sc, int show);
156 static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
157 static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
158 static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
159 static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
160 static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
161 static int wait_scrn_saver_stop(sc_softc_t *sc);
162 #define scsplash_stick(stick)           (sticky_splash = (stick))
163 #else /* !NSPLASH */
164 #define scsplash_stick(stick)
165 #endif /* NSPLASH */
166
167 static void do_switch_scr(sc_softc_t *sc);
168 static int vt_proc_alive(scr_stat *scp);
169 static int signal_vt_rel(scr_stat *scp);
170 static int signal_vt_acq(scr_stat *scp);
171 static int finish_vt_rel(scr_stat *scp, int release);
172 static int finish_vt_acq(scr_stat *scp);
173 static void exchange_scr(sc_softc_t *sc);
174 static void update_cursor_image(scr_stat *scp);
175 static int save_kbd_state(scr_stat *scp);
176 static int update_kbd_state(scr_stat *scp, int state, int mask);
177 static int update_kbd_leds(scr_stat *scp, int which);
178 static timeout_t blink_screen;
179
180 #define CDEV_MAJOR      12
181
182 static cn_probe_t       sccnprobe;
183 static cn_init_t        sccninit;
184 static cn_getc_t        sccngetc;
185 static cn_checkc_t      sccncheckc;
186 static cn_putc_t        sccnputc;
187 static cn_dbctl_t       sccndbctl;
188 static cn_term_t        sccnterm;
189
190 CONS_DRIVER(sc, sccnprobe, sccninit, sccnterm, sccngetc, sccncheckc, sccnputc,
191             sccndbctl);
192
193 static  d_open_t        scopen;
194 static  d_close_t       scclose;
195 static  d_read_t        scread;
196 static  d_ioctl_t       scioctl;
197 static  d_mmap_t        scmmap;
198
199 static struct dev_ops sc_ops = {
200         { "sc", CDEV_MAJOR, D_TTY | D_KQFILTER },
201         .d_open =       scopen,
202         .d_close =      scclose,
203         .d_read =       scread,
204         .d_write =      ttywrite,
205         .d_ioctl =      scioctl,
206         .d_poll =       ttypoll,
207         .d_mmap =       scmmap,
208         .d_kqfilter =   ttykqfilter
209 };
210
211 int
212 sc_probe_unit(int unit, int flags)
213 {
214     if (!scvidprobe(unit, flags, FALSE)) {
215         if (bootverbose)
216             kprintf("sc%d: no video adapter found.\n", unit);
217         return ENXIO;
218     }
219
220     /* syscons will be attached even when there is no keyboard */
221     sckbdprobe(unit, flags, FALSE);
222
223     return 0;
224 }
225
226 /* probe video adapters, return TRUE if found */ 
227 static int
228 scvidprobe(int unit, int flags, int cons)
229 {
230     /*
231      * Access the video adapter driver through the back door!
232      * Video adapter drivers need to be configured before syscons.
233      * However, when syscons is being probed as the low-level console,
234      * they have not been initialized yet.  We force them to initialize
235      * themselves here. XXX
236      */
237     vid_configure(cons ? VIO_PROBE_ONLY : 0);
238
239     return (vid_find_adapter("*", unit) >= 0);
240 }
241
242 /* probe the keyboard, return TRUE if found */
243 static int
244 sckbdprobe(int unit, int flags, int cons)
245 {
246     /* access the keyboard driver through the backdoor! */
247     kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
248
249     return (kbd_find_keyboard("*", unit) >= 0);
250 }
251
252 static char *
253 adapter_name(video_adapter_t *adp)
254 {
255     static struct {
256         int type;
257         char *name[2];
258     } names[] = {
259         { KD_MONO,      { "MDA",        "MDA" } },
260         { KD_HERCULES,  { "Hercules",   "Hercules" } },
261         { KD_CGA,       { "CGA",        "CGA" } },
262         { KD_EGA,       { "EGA",        "EGA (mono)" } },
263         { KD_VGA,       { "VGA",        "VGA (mono)" } },
264         { KD_TGA,       { "TGA",        "TGA" } },
265         { -1,           { "Unknown",    "Unknown" } },
266     };
267     int i;
268
269     for (i = 0; names[i].type != -1; ++i)
270         if (names[i].type == adp->va_type)
271             break;
272     return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
273 }
274
275 int
276 sc_attach_unit(int unit, int flags)
277 {
278     sc_softc_t *sc;
279     scr_stat *scp;
280 #ifdef SC_PIXEL_MODE
281     video_info_t info;
282 #endif
283     int vc;
284     cdev_t dev;
285
286     flags &= ~SC_KERNEL_CONSOLE;
287
288     if (sc_console_unit == unit) {
289         /*
290          * If this unit is being used as the system console, we need to
291          * adjust some variables and buffers before and after scinit().
292          */
293         /* assert(sc_console != NULL) */
294         flags |= SC_KERNEL_CONSOLE;
295         scmeminit(NULL);
296
297         scinit(unit, flags);
298
299         if (sc_console->tsw->te_size > 0) {
300             /* assert(sc_console->ts != NULL); */
301             kernel_console_ts = sc_console->ts;
302             sc_console->ts = kmalloc(sc_console->tsw->te_size,
303                                     M_SYSCONS, M_WAITOK);
304             bcopy(kernel_console_ts, sc_console->ts, sc_console->tsw->te_size);
305             (*sc_console->tsw->te_default_attr)(sc_console,
306                                                 user_default.std_color,
307                                                 user_default.rev_color);
308         }
309     } else {
310         scinit(unit, flags);
311     }
312
313     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
314     sc->config = flags;
315     callout_init(&sc->scrn_timer_ch);
316     scp = SC_STAT(sc->dev[0]);
317     if (sc_console == NULL)     /* sc_console_unit < 0 */
318         sc_console = scp;
319
320 #ifdef SC_PIXEL_MODE
321     if ((sc->config & SC_VESA800X600)
322         && ((*vidsw[sc->adapter]->get_info)(sc->adp, M_VESA_800x600, &info) == 0)) {
323 #if NSPLASH > 0
324         if (sc->flags & SC_SPLASH_SCRN)
325             splash_term(sc->adp);
326 #endif
327         sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
328         sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
329         sc->initial_mode = M_VESA_800x600;
330 #if NSPLASH > 0
331         /* put up the splash again! */
332         if (sc->flags & SC_SPLASH_SCRN)
333             splash_init(sc->adp, scsplash_callback, sc);
334 #endif
335     }
336 #endif /* SC_PIXEL_MODE */
337
338     /* initialize cursor */
339     if (!ISGRAPHSC(scp))
340         update_cursor_image(scp);
341
342     /* get screen update going */
343     scrn_timer(sc);
344
345     /* set up the keyboard */
346     kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
347     update_kbd_state(scp, scp->status, LOCK_MASK);
348
349     kprintf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
350            unit, adapter_name(sc->adp), sc->vtys, sc->config);
351     if (bootverbose) {
352         kprintf("sc%d:", unit);
353         if (sc->adapter >= 0)
354             kprintf(" fb%d", sc->adapter);
355         if (sc->keyboard >= 0)
356             kprintf(", kbd%d", sc->keyboard);
357         if (scp->tsw)
358             kprintf(", terminal emulator: %s (%s)",
359                    scp->tsw->te_name, scp->tsw->te_desc);
360         kprintf("\n");
361     }
362
363     /* register a shutdown callback for the kernel console */
364     if (sc_console_unit == unit)
365         EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown, 
366                               (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
367
368     /* 
369      * create devices.  dev_ops_add() must be called to make devices under
370      * this major number available to userland.
371      */
372     dev_ops_add(&sc_ops, ~(MAXCONS - 1), unit * MAXCONS);
373
374     for (vc = 0; vc < sc->vtys; vc++) {
375         dev = make_dev(&sc_ops, vc + unit * MAXCONS,
376             UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc + unit * MAXCONS);
377         sc->dev[vc] = dev;
378         /*
379          * The first vty already has struct tty and scr_stat initialized
380          * in scinit().  The other vtys will have these structs when
381          * first opened.
382          */
383     }
384
385     dev_ops_add(&sc_ops, -1, SC_CONSOLECTL);    /* XXX */
386     dev = make_dev(&sc_ops, SC_CONSOLECTL,
387                    UID_ROOT, GID_WHEEL, 0600, "consolectl");
388     dev->si_tty = sc_console_tty = ttymalloc(sc_console_tty);
389     dev->si_drv1 = sc_console;
390
391     return 0;
392 }
393
394 static void
395 scmeminit(void *arg)
396 {
397     if (sc_malloc)
398         return;
399     sc_malloc = TRUE;
400
401     /*
402      * As soon as malloc() becomes functional, we had better allocate
403      * various buffers for the kernel console.
404      */
405
406     if (sc_console_unit < 0)    /* sc_console == NULL */
407         return;
408
409     /* copy the temporary buffer to the final buffer */
410     sc_alloc_scr_buffer(sc_console, TRUE, FALSE);
411
412 #ifndef SC_NO_CUTPASTE
413     sc_alloc_cut_buffer(sc_console, TRUE);
414 #endif
415
416 #ifndef SC_NO_HISTORY
417     /* initialize history buffer & pointers */
418     sc_alloc_history_buffer(sc_console, 0, 0, TRUE);
419 #endif
420 }
421
422 SYSINIT(sc_mem, SI_BOOT1_POST, SI_ORDER_ANY, scmeminit, NULL);
423
424 static int
425 scdevtounit(cdev_t dev)
426 {
427     int vty = SC_VTY(dev);
428
429     if (vty == SC_CONSOLECTL)
430         return ((sc_console != NULL) ? sc_console->sc->unit : -1);
431     else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
432         return -1;
433     else
434         return vty/MAXCONS;
435 }
436
437 int
438 scopen(struct dev_open_args *ap)
439 {
440     cdev_t dev = ap->a_head.a_dev;
441     int unit = scdevtounit(dev);
442     sc_softc_t *sc;
443     struct tty *tp;
444     scr_stat *scp;
445     keyarg_t key;
446     int error;
447
448     DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
449                 major(dev), minor(dev), unit, SC_VTY(dev)));
450
451     sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
452     if (sc == NULL)
453         return ENXIO;
454
455     tp = dev->si_tty = ttymalloc(dev->si_tty);
456     tp->t_oproc = scstart;
457     tp->t_param = scparam;
458     tp->t_stop = nottystop;
459     tp->t_dev = dev;
460     if (!ISTTYOPEN(tp)) {
461         ttychars(tp);
462         /* Use the current setting of the <-- key as default VERASE. */  
463         /* If the Delete key is preferable, an stty is necessary     */
464         if (sc->kbd != NULL) {
465             key.keynum = KEYCODE_BS;
466             kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
467             tp->t_cc[VERASE] = key.key.map[0];
468         }
469         tp->t_iflag = TTYDEF_IFLAG;
470         tp->t_oflag = TTYDEF_OFLAG;
471         tp->t_cflag = TTYDEF_CFLAG;
472         tp->t_lflag = TTYDEF_LFLAG;
473         tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
474         scparam(tp, &tp->t_termios);
475         (*linesw[tp->t_line].l_modem)(tp, 1);
476     }
477     else
478         if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0))
479             return(EBUSY);
480
481     error = (*linesw[tp->t_line].l_open)(dev, tp);
482
483     scp = SC_STAT(dev);
484     if (scp == NULL) {
485         scp = dev->si_drv1 = alloc_scp(sc, SC_VTY(dev));
486         if (ISGRAPHSC(scp))
487             sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
488     }
489     if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
490         tp->t_winsize.ws_col = scp->xsize;
491         tp->t_winsize.ws_row = scp->ysize;
492     }
493
494     return error;
495 }
496
497 int
498 scclose(struct dev_close_args *ap)
499 {
500     cdev_t dev = ap->a_head.a_dev;
501     struct tty *tp = dev->si_tty;
502     scr_stat *scp;
503
504     crit_enter();
505     if (SC_VTY(dev) != SC_CONSOLECTL) {
506         scp = SC_STAT(tp->t_dev);
507         /* were we in the middle of the VT switching process? */
508         DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
509         if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit))
510             cons_unavail = FALSE;
511         /* 
512          * note: must be called from a critical section because finish_vt_rel
513          * will call do_switch_scr which releases it temporarily 
514          */
515         if (finish_vt_rel(scp, TRUE) == 0)      /* force release */
516             DPRINTF(5, ("reset WAIT_REL, "));
517         if (finish_vt_acq(scp) == 0)            /* force acknowledge */
518             DPRINTF(5, ("reset WAIT_ACQ, "));
519 #if not_yet_done
520         if (scp == &main_console) {
521             scp->pid = 0;
522             scp->proc = NULL;
523             scp->smode.mode = VT_AUTO;
524         }
525         else {
526             sc_vtb_destroy(&scp->vtb);
527             sc_vtb_destroy(&scp->scr);
528             sc_free_history_buffer(scp, scp->ysize);
529             SC_STAT(dev) = NULL;
530             kfree(scp, M_SYSCONS);
531         }
532 #else
533         scp->pid = 0;
534         scp->proc = NULL;
535         scp->smode.mode = VT_AUTO;
536 #endif
537         scp->kbd_mode = K_XLATE;
538         if (scp == scp->sc->cur_scp)
539             kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
540         DPRINTF(5, ("done.\n"));
541     }
542     (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
543     ttyclose(tp);
544     crit_exit();
545     return(0);
546 }
547
548 int
549 scread(struct dev_read_args *ap)
550 {
551     sc_touch_scrn_saver();
552     return (ttyread(ap));
553 }
554
555 static int
556 sckbdevent(keyboard_t *thiskbd, int event, void *arg)
557 {
558     sc_softc_t *sc;
559     struct tty *cur_tty;
560     int c; 
561     size_t len;
562     u_char *cp;
563
564     sc = (sc_softc_t *)arg;
565     /* assert(thiskbd == sc->kbd) */
566
567     switch (event) {
568     case KBDIO_KEYINPUT:
569         break;
570     case KBDIO_UNLOADING:
571         sc->kbd = NULL;
572         sc->keyboard = -1;
573         kbd_release(thiskbd, (void *)&sc->keyboard);
574         return 0;
575     default:
576         return EINVAL;
577     }
578
579     /* 
580      * Loop while there is still input to get from the keyboard.
581      * I don't think this is nessesary, and it doesn't fix
582      * the Xaccel-2.1 keyboard hang, but it can't hurt.         XXX
583      */
584     while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
585
586         cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
587         if (!ISTTYOPEN(cur_tty)) {
588             cur_tty = sc_console_tty;
589             if (!ISTTYOPEN(cur_tty))
590                 continue;
591         }
592
593         if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty))
594             continue;
595
596         switch (KEYFLAGS(c)) {
597         case 0x0000: /* normal key */
598             (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
599             break;
600         case FKEY:  /* function key, return string */
601             cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
602             if (cp != NULL) {
603                 while (len-- >  0)
604                     (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
605             }
606             break;
607         case MKEY:  /* meta is active, prepend ESC */
608             (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
609             (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
610             break;
611         case BKEY:  /* backtab fixed sequence (esc [ Z) */
612             (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
613             (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
614             (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
615             break;
616         }
617     }
618
619     sc->cur_scp->status |= MOUSE_HIDDEN;
620
621     return 0;
622 }
623
624 static int
625 scparam(struct tty *tp, struct termios *t)
626 {
627     tp->t_ispeed = t->c_ispeed;
628     tp->t_ospeed = t->c_ospeed;
629     tp->t_cflag = t->c_cflag;
630     return 0;
631 }
632
633 int
634 scioctl(struct dev_ioctl_args *ap)
635 {
636     cdev_t dev = ap->a_head.a_dev;
637     u_long cmd = ap->a_cmd;
638     caddr_t data = ap->a_data;
639     int flag = ap->a_fflag;
640     int error;
641     int i;
642     struct tty *tp;
643     sc_softc_t *sc;
644     scr_stat *scp;
645
646     tp = dev->si_tty;
647
648     /* If there is a user_ioctl function call that first */
649     if (sc_user_ioctl) {
650         error = (*sc_user_ioctl)(ap);
651         if (error != ENOIOCTL)
652             return error;
653     }
654
655     error = sc_vid_ioctl(tp, cmd, data, flag);
656     if (error != ENOIOCTL)
657         return error;
658
659 #ifndef SC_NO_HISTORY
660     error = sc_hist_ioctl(tp, cmd, data, flag);
661     if (error != ENOIOCTL)
662         return error;
663 #endif
664
665 #ifndef SC_NO_SYSMOUSE
666     error = sc_mouse_ioctl(tp, cmd, data, flag);
667     if (error != ENOIOCTL)
668         return error;
669 #endif
670
671     scp = SC_STAT(tp->t_dev);
672     /* assert(scp != NULL) */
673     /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
674     sc = scp->sc;
675
676     if (scp->tsw) {
677         error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, flag);
678         if (error != ENOIOCTL)
679             return error;
680     }
681
682     switch (cmd) {              /* process console hardware related ioctl's */
683
684     case GIO_ATTR:              /* get current attributes */
685         /* this ioctl is not processed here, but in the terminal emulator */
686         return ENOTTY;
687
688     case GIO_COLOR:             /* is this a color console ? */
689         *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
690         return 0;
691
692     case CONS_BLANKTIME:        /* set screen saver timeout (0 = no saver) */
693         if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
694             return EINVAL;
695         crit_enter();
696         scrn_blank_time = *(int *)data;
697         run_scrn_saver = (scrn_blank_time != 0);
698         crit_exit();
699         return 0;
700
701     case CONS_CURSORTYPE:       /* set cursor type blink/noblink */
702         crit_enter();
703         if (!ISGRAPHSC(sc->cur_scp))
704             sc_remove_cursor_image(sc->cur_scp);
705         if ((*(int*)data) & 0x01)
706             sc->flags |= SC_BLINK_CURSOR;
707         else
708             sc->flags &= ~SC_BLINK_CURSOR;
709         if ((*(int*)data) & 0x02) {
710             sc->flags |= SC_CHAR_CURSOR;
711         } else
712             sc->flags &= ~SC_CHAR_CURSOR;
713         /* 
714          * The cursor shape is global property; all virtual consoles
715          * are affected. Update the cursor in the current console...
716          */
717         if (!ISGRAPHSC(sc->cur_scp)) {
718             sc_set_cursor_image(sc->cur_scp);
719             sc_draw_cursor_image(sc->cur_scp);
720         }
721         crit_exit();
722         return 0;
723
724     case CONS_BELLTYPE:         /* set bell type sound/visual */
725         if ((*(int *)data) & 0x01)
726             sc->flags |= SC_VISUAL_BELL;
727         else
728             sc->flags &= ~SC_VISUAL_BELL;
729         if ((*(int *)data) & 0x02)
730             sc->flags |= SC_QUIET_BELL;
731         else
732             sc->flags &= ~SC_QUIET_BELL;
733         return 0;
734
735     case CONS_GETINFO:          /* get current (virtual) console info */
736     {
737         vid_info_t *ptr = (vid_info_t*)data;
738         if (ptr->size == sizeof(struct vid_info)) {
739             ptr->m_num = sc->cur_scp->index;
740             ptr->font_size = scp->font_size;
741             ptr->mv_col = scp->xpos;
742             ptr->mv_row = scp->ypos;
743             ptr->mv_csz = scp->xsize;
744             ptr->mv_rsz = scp->ysize;
745             /*
746              * The following fields are filled by the terminal emulator. XXX
747              *
748              * ptr->mv_norm.fore
749              * ptr->mv_norm.back
750              * ptr->mv_rev.fore
751              * ptr->mv_rev.back
752              */
753             ptr->mv_grfc.fore = 0;      /* not supported */
754             ptr->mv_grfc.back = 0;      /* not supported */
755             ptr->mv_ovscan = scp->border;
756             if (scp == sc->cur_scp)
757                 save_kbd_state(scp);
758             ptr->mk_keylock = scp->status & LOCK_MASK;
759             return 0;
760         }
761         return EINVAL;
762     }
763
764     case CONS_GETVERS:          /* get version number */
765         *(int*)data = 0x200;    /* version 2.0 */
766         return 0;
767
768     case CONS_IDLE:             /* see if the screen has been idle */
769         /*
770          * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
771          * the user process may have been writing something on the
772          * screen and syscons is not aware of it. Declare the screen
773          * is NOT idle if it is in one of these modes. But there is
774          * an exception to it; if a screen saver is running in the 
775          * graphics mode in the current screen, we should say that the
776          * screen has been idle.
777          */
778         *(int *)data = (sc->flags & SC_SCRN_IDLE)
779                        && (!ISGRAPHSC(sc->cur_scp)
780                            || (sc->cur_scp->status & SAVER_RUNNING));
781         return 0;
782
783     case CONS_SAVERMODE:        /* set saver mode */
784         switch(*(int *)data) {
785         case CONS_NO_SAVER:
786         case CONS_USR_SAVER:
787             /* if a LKM screen saver is running, stop it first. */
788             scsplash_stick(FALSE);
789             saver_mode = *(int *)data;
790             crit_enter();
791 #if NSPLASH > 0
792             if ((error = wait_scrn_saver_stop(NULL))) {
793                 crit_exit();
794                 return error;
795             }
796 #endif /* NSPLASH */
797             run_scrn_saver = TRUE;
798             if (saver_mode == CONS_USR_SAVER)
799                 scp->status |= SAVER_RUNNING;
800             else
801                 scp->status &= ~SAVER_RUNNING;
802             scsplash_stick(TRUE);
803             crit_exit();
804             break;
805         case CONS_LKM_SAVER:
806             crit_enter();
807             if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
808                 scp->status &= ~SAVER_RUNNING;
809             saver_mode = *(int *)data;
810             crit_exit();
811             break;
812         default:
813             return EINVAL;
814         }
815         return 0;
816
817     case CONS_SAVERSTART:       /* immediately start/stop the screen saver */
818         /*
819          * Note that this ioctl does not guarantee the screen saver 
820          * actually starts or stops. It merely attempts to do so...
821          */
822         crit_enter();
823         run_scrn_saver = (*(int *)data != 0);
824         if (run_scrn_saver)
825             sc->scrn_time_stamp -= scrn_blank_time;
826         crit_exit();
827         return 0;
828
829     case CONS_SCRSHOT:          /* get a screen shot */
830     {
831         scrshot_t *ptr = (scrshot_t*)data;
832         crit_enter();
833         if (ISGRAPHSC(scp)) {
834             crit_exit();
835             return EOPNOTSUPP;
836         }
837         if (scp->xsize != ptr->xsize || scp->ysize != ptr->ysize) {
838             crit_exit();
839             return EINVAL;
840         }
841         copyout ((void*)scp->vtb.vtb_buffer, ptr->buf,
842                  ptr->xsize * ptr->ysize * sizeof(uint16_t));
843         crit_exit();
844         return 0;
845     }
846
847     case VT_SETMODE:            /* set screen switcher mode */
848     {
849         struct vt_mode *mode;
850
851         mode = (struct vt_mode *)data;
852         DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
853         if (scp->smode.mode == VT_PROCESS) {
854             if (scp->proc == pfind(scp->pid) && scp->proc != curproc) {
855                 DPRINTF(5, ("error EPERM\n"));
856                 return EPERM;
857             }
858         }
859         crit_enter();
860         if (mode->mode == VT_AUTO) {
861             scp->smode.mode = VT_AUTO;
862             scp->proc = NULL;
863             scp->pid = 0;
864             DPRINTF(5, ("VT_AUTO, "));
865             if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
866                 cons_unavail = FALSE;
867             /* 
868              * note: must be called from a critical section because 
869              * finish_vt_rel will call do_switch_scr which releases it
870              * temporarily.
871              */
872             if (finish_vt_rel(scp, TRUE) == 0)
873                 DPRINTF(5, ("reset WAIT_REL, "));
874             if (finish_vt_acq(scp) == 0)
875                 DPRINTF(5, ("reset WAIT_ACQ, "));
876         } else {
877             if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
878                 || !ISSIGVALID(mode->frsig)) {
879                 crit_exit();
880                 DPRINTF(5, ("error EINVAL\n"));
881                 return EINVAL;
882             }
883             DPRINTF(5, ("VT_PROCESS %d, ", curproc->p_pid));
884             bcopy(data, &scp->smode, sizeof(struct vt_mode));
885             scp->proc = curproc;
886             scp->pid = scp->proc->p_pid;
887             if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
888                 cons_unavail = TRUE;
889         }
890         crit_exit();
891         DPRINTF(5, ("\n"));
892         return 0;
893     }
894
895     case VT_GETMODE:            /* get screen switcher mode */
896         bcopy(&scp->smode, data, sizeof(struct vt_mode));
897         return 0;
898
899     case VT_RELDISP:            /* screen switcher ioctl */
900         crit_enter();
901         /*
902          * This must be the current vty which is in the VT_PROCESS
903          * switching mode...
904          */
905         if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
906             crit_exit();
907             return EINVAL;
908         }
909         /* ...and this process is controlling it. */
910         if (scp->proc != curproc) {
911             crit_exit();
912             return EPERM;
913         }
914         error = EINVAL;
915         switch(*(int *)data) {
916         case VT_FALSE:          /* user refuses to release screen, abort */
917             /* 
918              * note: must be called from a critical section because 
919              * finish_vt_rel will call do_switch_scr which releases it
920              * temporarily.
921              */
922             if ((error = finish_vt_rel(scp, FALSE)) == 0)
923                 DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
924             break;
925         case VT_TRUE:           /* user has released screen, go on */
926             /* 
927              * note: must be called from a critical section because 
928              * finish_vt_rel will call do_switch_scr which releases it
929              * temporarily.
930              */
931             if ((error = finish_vt_rel(scp, TRUE)) == 0)
932                 DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
933             break;
934         case VT_ACKACQ:         /* acquire acknowledged, switch completed */
935             if ((error = finish_vt_acq(scp)) == 0)
936                 DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
937             break;
938         default:
939             break;
940         }
941         crit_exit();
942         return error;
943
944     case VT_OPENQRY:            /* return free virtual console */
945         for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
946             tp = VIRTUAL_TTY(sc, i);
947             if (!ISTTYOPEN(tp)) {
948                 *(int *)data = i + 1;
949                 return 0;
950             }
951         }
952         return EINVAL;
953
954     case VT_ACTIVATE:           /* switch to screen *data */
955         i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
956         crit_enter();
957         sc_clean_up(sc->cur_scp);
958         crit_exit();
959         return sc_switch_scr(sc, i);
960
961     case VT_WAITACTIVE:         /* wait for switch to occur */
962         i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
963         if ((i < sc->first_vty) || (i >= sc->first_vty + sc->vtys))
964             return EINVAL;
965         crit_enter();
966         error = sc_clean_up(sc->cur_scp);
967         crit_exit();
968         if (error)
969             return error;
970         scp = SC_STAT(SC_DEV(sc, i));
971         if (scp == scp->sc->cur_scp)
972             return 0;
973         while ((error=tsleep((caddr_t)&scp->smode, PCATCH,
974                              "waitvt", 0)) == ERESTART) ;
975         return error;
976
977     case VT_GETACTIVE:          /* get active vty # */
978         *(int *)data = sc->cur_scp->index + 1;
979         return 0;
980
981     case VT_GETINDEX:           /* get this vty # */
982         *(int *)data = scp->index + 1;
983         return 0;
984
985     case VT_LOCKSWITCH:         /* prevent vty switching */
986         if ((*(int *)data) & 0x01)
987             sc->flags |= SC_SCRN_VTYLOCK;
988         else
989             sc->flags &= ~SC_SCRN_VTYLOCK;
990         return 0;
991
992     case KDENABIO:              /* allow io operations */
993         error = suser_cred(ap->a_cred, 0);
994         if (error != 0)
995             return error;
996         if (securelevel > 0)
997             return EPERM;
998         curthread->td_lwp->lwp_md.md_regs->tf_eflags |= PSL_IOPL;
999         return 0;
1000
1001     case KDDISABIO:             /* disallow io operations (default) */
1002         curthread->td_lwp->lwp_md.md_regs->tf_eflags &= ~PSL_IOPL;
1003         return 0;
1004
1005     case KDSKBSTATE:            /* set keyboard state (locks) */
1006         if (*(int *)data & ~LOCK_MASK)
1007             return EINVAL;
1008         scp->status &= ~LOCK_MASK;
1009         scp->status |= *(int *)data;
1010         if (scp == sc->cur_scp)
1011             update_kbd_state(scp, scp->status, LOCK_MASK);
1012         return 0;
1013
1014     case KDGKBSTATE:            /* get keyboard state (locks) */
1015         if (scp == sc->cur_scp)
1016             save_kbd_state(scp);
1017         *(int *)data = scp->status & LOCK_MASK;
1018         return 0;
1019
1020     case KDGETREPEAT:           /* get keyboard repeat & delay rates */
1021     case KDSETREPEAT:           /* set keyboard repeat & delay rates (new) */
1022         error = kbd_ioctl(sc->kbd, cmd, data);
1023         if (error == ENOIOCTL)
1024             error = ENODEV;
1025         return error;
1026
1027     case KDSETRAD:              /* set keyboard repeat & delay rates (old) */
1028         if (*(int *)data & ~0x7f)
1029             return EINVAL;
1030         error = kbd_ioctl(sc->kbd, cmd, data);
1031         if (error == ENOIOCTL)
1032             error = ENODEV;
1033         return error;
1034
1035     case KDSKBMODE:             /* set keyboard mode */
1036         switch (*(int *)data) {
1037         case K_XLATE:           /* switch to XLT ascii mode */
1038         case K_RAW:             /* switch to RAW scancode mode */
1039         case K_CODE:            /* switch to CODE mode */
1040             scp->kbd_mode = *(int *)data;
1041             if (scp == sc->cur_scp)
1042                 kbd_ioctl(sc->kbd, cmd, data);
1043             return 0;
1044         default:
1045             return EINVAL;
1046         }
1047         /* NOT REACHED */
1048
1049     case KDGKBMODE:             /* get keyboard mode */
1050         *(int *)data = scp->kbd_mode;
1051         return 0;
1052
1053     case KDGKBINFO:
1054         error = kbd_ioctl(sc->kbd, cmd, data);
1055         if (error == ENOIOCTL)
1056             error = ENODEV;
1057         return error;
1058
1059     case KDMKTONE:              /* sound the bell */
1060         if (*(int*)data)
1061             sc_bell(scp, (*(int*)data)&0xffff,
1062                     (((*(int*)data)>>16)&0xffff)*hz/1000);
1063         else
1064             sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1065         return 0;
1066
1067     case KIOCSOUND:             /* make tone (*data) hz */
1068         if (scp == sc->cur_scp) {
1069             if (*(int *)data)
1070                 return sc_tone(*(int *)data);
1071             else
1072                 return sc_tone(0);
1073         }
1074         return 0;
1075
1076     case KDGKBTYPE:             /* get keyboard type */
1077         error = kbd_ioctl(sc->kbd, cmd, data);
1078         if (error == ENOIOCTL) {
1079             /* always return something? XXX */
1080             *(int *)data = 0;
1081         }
1082         return 0;
1083
1084     case KDSETLED:              /* set keyboard LED status */
1085         if (*(int *)data & ~LED_MASK)   /* FIXME: LOCK_MASK? */
1086             return EINVAL;
1087         scp->status &= ~LED_MASK;
1088         scp->status |= *(int *)data;
1089         if (scp == sc->cur_scp)
1090             update_kbd_leds(scp, scp->status);
1091         return 0;
1092
1093     case KDGETLED:              /* get keyboard LED status */
1094         if (scp == sc->cur_scp)
1095             save_kbd_state(scp);
1096         *(int *)data = scp->status & LED_MASK;
1097         return 0;
1098
1099     case CONS_SETKBD:           /* set the new keyboard */
1100         {
1101             keyboard_t *newkbd;
1102
1103             crit_enter();
1104             newkbd = kbd_get_keyboard(*(int *)data);
1105             if (newkbd == NULL) {
1106                 crit_exit();
1107                 return EINVAL;
1108             }
1109             error = 0;
1110             if (sc->kbd != newkbd) {
1111                 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1112                                  (void *)&sc->keyboard, sckbdevent, sc);
1113                 /* i == newkbd->kb_index */
1114                 if (i >= 0) {
1115                     if (sc->kbd != NULL) {
1116                         save_kbd_state(sc->cur_scp);
1117                         kbd_release(sc->kbd, (void *)&sc->keyboard);
1118                     }
1119                     sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1120                     sc->keyboard = i;
1121                     kbd_ioctl(sc->kbd, KDSKBMODE,
1122                               (caddr_t)&sc->cur_scp->kbd_mode);
1123                     update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1124                                      LOCK_MASK);
1125                 } else {
1126                     error = EPERM;      /* XXX */
1127                 }
1128             }
1129             crit_exit();
1130             return error;
1131         }
1132
1133     case CONS_RELKBD:           /* release the current keyboard */
1134         crit_enter();
1135         error = 0;
1136         if (sc->kbd != NULL) {
1137             save_kbd_state(sc->cur_scp);
1138             error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1139             if (error == 0) {
1140                 sc->kbd = NULL;
1141                 sc->keyboard = -1;
1142             }
1143         }
1144         crit_exit();
1145         return error;
1146
1147     case CONS_GETTERM:          /* get the current terminal emulator info */
1148         {
1149             sc_term_sw_t *sw;
1150
1151             if (((term_info_t *)data)->ti_index == 0) {
1152                 sw = scp->tsw;
1153             } else {
1154                 sw = sc_term_match_by_number(((term_info_t *)data)->ti_index);
1155             }
1156             if (sw != NULL) {
1157                 strncpy(((term_info_t *)data)->ti_name, sw->te_name, 
1158                         sizeof(((term_info_t *)data)->ti_name));
1159                 strncpy(((term_info_t *)data)->ti_desc, sw->te_desc, 
1160                         sizeof(((term_info_t *)data)->ti_desc));
1161                 ((term_info_t *)data)->ti_flags = 0;
1162                 return 0;
1163             } else {
1164                 ((term_info_t *)data)->ti_name[0] = '\0';
1165                 ((term_info_t *)data)->ti_desc[0] = '\0';
1166                 ((term_info_t *)data)->ti_flags = 0;
1167                 return EINVAL;
1168             }
1169         }
1170
1171     case CONS_SETTERM:          /* set the current terminal emulator */
1172         crit_enter();
1173         error = sc_init_emulator(scp, ((term_info_t *)data)->ti_name);
1174         /* FIXME: what if scp == sc_console! XXX */
1175         crit_exit();
1176         return error;
1177
1178     case GIO_SCRNMAP:           /* get output translation table */
1179         bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
1180         return 0;
1181
1182     case PIO_SCRNMAP:           /* set output translation table */
1183         bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1184         for (i=0; i<sizeof(sc->scr_map); i++) {
1185             sc->scr_rmap[sc->scr_map[i]] = i;
1186         }
1187         return 0;
1188
1189     case GIO_KEYMAP:            /* get keyboard translation table */
1190     case PIO_KEYMAP:            /* set keyboard translation table */
1191     case GIO_DEADKEYMAP:        /* get accent key translation table */
1192     case PIO_DEADKEYMAP:        /* set accent key translation table */
1193     case GETFKEY:               /* get function key string */
1194     case SETFKEY:               /* set function key string */
1195         error = kbd_ioctl(sc->kbd, cmd, data);
1196         if (error == ENOIOCTL)
1197             error = ENODEV;
1198         return error;
1199
1200 #ifndef SC_NO_FONT_LOADING
1201
1202     case PIO_FONT8x8:           /* set 8x8 dot font */
1203         if (!ISFONTAVAIL(sc->adp->va_flags))
1204             return ENXIO;
1205         bcopy(data, sc->font_8, 8*256);
1206         sc->fonts_loaded |= FONT_8;
1207         /*
1208          * FONT KLUDGE
1209          * Always use the font page #0. XXX
1210          * Don't load if the current font size is not 8x8.
1211          */
1212         if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14))
1213             sc_load_font(sc->cur_scp, 0, 8, sc->font_8, 0, 256);
1214         return 0;
1215
1216     case GIO_FONT8x8:           /* get 8x8 dot font */
1217         if (!ISFONTAVAIL(sc->adp->va_flags))
1218             return ENXIO;
1219         if (sc->fonts_loaded & FONT_8) {
1220             bcopy(sc->font_8, data, 8*256);
1221             return 0;
1222         }
1223         else
1224             return ENXIO;
1225
1226     case PIO_FONT8x14:          /* set 8x14 dot font */
1227         if (!ISFONTAVAIL(sc->adp->va_flags))
1228             return ENXIO;
1229         bcopy(data, sc->font_14, 14*256);
1230         sc->fonts_loaded |= FONT_14;
1231         /*
1232          * FONT KLUDGE
1233          * Always use the font page #0. XXX
1234          * Don't load if the current font size is not 8x14.
1235          */
1236         if (ISTEXTSC(sc->cur_scp)
1237             && (sc->cur_scp->font_size >= 14)
1238             && (sc->cur_scp->font_size < 16))
1239             sc_load_font(sc->cur_scp, 0, 14, sc->font_14, 0, 256);
1240         return 0;
1241
1242     case GIO_FONT8x14:          /* get 8x14 dot font */
1243         if (!ISFONTAVAIL(sc->adp->va_flags))
1244             return ENXIO;
1245         if (sc->fonts_loaded & FONT_14) {
1246             bcopy(sc->font_14, data, 14*256);
1247             return 0;
1248         }
1249         else
1250             return ENXIO;
1251
1252     case PIO_FONT8x16:          /* set 8x16 dot font */
1253         if (!ISFONTAVAIL(sc->adp->va_flags))
1254             return ENXIO;
1255         bcopy(data, sc->font_16, 16*256);
1256         sc->fonts_loaded |= FONT_16;
1257         /*
1258          * FONT KLUDGE
1259          * Always use the font page #0. XXX
1260          * Don't load if the current font size is not 8x16.
1261          */
1262         if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16))
1263             sc_load_font(sc->cur_scp, 0, 16, sc->font_16, 0, 256);
1264         return 0;
1265
1266     case GIO_FONT8x16:          /* get 8x16 dot font */
1267         if (!ISFONTAVAIL(sc->adp->va_flags))
1268             return ENXIO;
1269         if (sc->fonts_loaded & FONT_16) {
1270             bcopy(sc->font_16, data, 16*256);
1271             return 0;
1272         }
1273         else
1274             return ENXIO;
1275
1276 #endif /* SC_NO_FONT_LOADING */
1277
1278     default:
1279         break;
1280     }
1281
1282     error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, ap->a_cred);
1283     if (error != ENOIOCTL)
1284         return(error);
1285     error = ttioctl(tp, cmd, data, flag);
1286     if (error != ENOIOCTL)
1287         return(error);
1288     return(ENOTTY);
1289 }
1290
1291 static void
1292 scstart(struct tty *tp)
1293 {
1294     struct clist *rbp;
1295     int len;
1296     u_char buf[PCBURST];
1297     scr_stat *scp = SC_STAT(tp->t_dev);
1298
1299     if (scp->status & SLKED ||
1300         (scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
1301         return;
1302     crit_enter();
1303     if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1304         tp->t_state |= TS_BUSY;
1305         rbp = &tp->t_outq;
1306         while (rbp->c_cc) {
1307             len = q_to_b(rbp, buf, PCBURST);
1308             crit_exit();
1309             sc_puts(scp, buf, len);
1310             crit_enter();
1311         }
1312         tp->t_state &= ~TS_BUSY;
1313         ttwwakeup(tp);
1314     }
1315     crit_exit();
1316 }
1317
1318 static void
1319 sccnprobe(struct consdev *cp)
1320 {
1321     int unit;
1322     int flags;
1323
1324     cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1325
1326     /* a video card is always required */
1327     if (!scvidprobe(unit, flags, TRUE))
1328         cp->cn_pri = CN_DEAD;
1329
1330     /* syscons will become console even when there is no keyboard */
1331     sckbdprobe(unit, flags, TRUE);
1332
1333     if (cp->cn_pri == CN_DEAD)
1334         return;
1335
1336     /* initialize required fields */
1337     cp->cn_dev = make_dev(&sc_ops, SC_CONSOLECTL,
1338                    UID_ROOT, GID_WHEEL, 0600, "consolectl");
1339 }
1340
1341 static void
1342 sccninit(struct consdev *cp)
1343 {
1344     int unit;
1345     int flags;
1346
1347     sc_get_cons_priority(&unit, &flags);
1348     scinit(unit, flags | SC_KERNEL_CONSOLE);
1349     sc_console_unit = unit;
1350     sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1351 }
1352
1353 static void
1354 sccnterm(struct consdev *cp)
1355 {
1356     /* we are not the kernel console any more, release everything */
1357
1358     if (sc_console_unit < 0)
1359         return;                 /* shouldn't happen */
1360
1361 #if 0 /* XXX */
1362     sc_clear_screen(sc_console);
1363     sccnupdate(sc_console);
1364 #endif
1365     scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1366     sc_console_unit = -1;
1367     sc_console = NULL;
1368 }
1369
1370 static void
1371 sccnputc(cdev_t dev, int c)
1372 {
1373     u_char buf[1];
1374     scr_stat *scp = sc_console;
1375     void *save;
1376 #ifndef SC_NO_HISTORY
1377     struct tty *tp;
1378 #endif /* !SC_NO_HISTORY */
1379
1380     /* assert(sc_console != NULL) */
1381
1382 #ifndef SC_NO_HISTORY
1383     if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1384         scp->status &= ~SLKED;
1385         update_kbd_state(scp, scp->status, SLKED);
1386         if (scp->status & BUFFER_SAVED) {
1387             if (!sc_hist_restore(scp))
1388                 sc_remove_cutmarking(scp);
1389             scp->status &= ~BUFFER_SAVED;
1390             scp->status |= CURSOR_ENABLED;
1391             sc_draw_cursor_image(scp);
1392         }
1393         tp = VIRTUAL_TTY(scp->sc, scp->index);
1394         if (ISTTYOPEN(tp))
1395             scstart(tp);
1396     }
1397 #endif /* !SC_NO_HISTORY */
1398
1399     save = scp->ts;
1400     if (kernel_console_ts != NULL)
1401         scp->ts = kernel_console_ts;
1402     buf[0] = c;
1403     sc_puts(scp, buf, 1);
1404     scp->ts = save;
1405
1406     crit_enter();
1407     sccnupdate(scp);
1408     crit_exit();
1409 }
1410
1411 static int
1412 sccngetc(cdev_t dev)
1413 {
1414     return sccngetch(0);
1415 }
1416
1417 static int
1418 sccncheckc(cdev_t dev)
1419 {
1420     return sccngetch(SCGETC_NONBLOCK);
1421 }
1422
1423 static void
1424 sccndbctl(cdev_t dev, int on)
1425 {
1426     /* assert(sc_console_unit >= 0) */
1427     /* try to switch to the kernel console screen */
1428     if (on && debugger == 0) {
1429         /*
1430          * TRY to make sure the screen saver is stopped, 
1431          * and the screen is updated before switching to 
1432          * the vty0.
1433          */
1434         scrn_timer(NULL);
1435         if (!cold
1436             && sc_console->sc->cur_scp->smode.mode == VT_AUTO
1437             && sc_console->smode.mode == VT_AUTO) {
1438             sc_console->sc->cur_scp->status |= MOUSE_HIDDEN;
1439             sc_switch_scr(sc_console->sc, sc_console->index);
1440         }
1441     }
1442     if (on)
1443         ++debugger;
1444     else
1445         --debugger;
1446 }
1447
1448 static int
1449 sccngetch(int flags)
1450 {
1451     static struct fkeytab fkey;
1452     static int fkeycp;
1453     scr_stat *scp;
1454     u_char *p;
1455     int cur_mode;
1456     int c;
1457
1458     crit_enter();
1459     /* assert(sc_console != NULL) */
1460
1461     /* 
1462      * Stop the screen saver and update the screen if necessary.
1463      * What if we have been running in the screen saver code... XXX
1464      */
1465     sc_touch_scrn_saver();
1466     scp = sc_console->sc->cur_scp;      /* XXX */
1467     sccnupdate(scp);
1468
1469     if (fkeycp < fkey.len) {
1470         crit_exit();
1471         return fkey.str[fkeycp++];
1472     }
1473
1474     if (scp->sc->kbd == NULL) {
1475         crit_exit();
1476         return -1;
1477     }
1478
1479     /* 
1480      * Make sure the keyboard is accessible even when the kbd device
1481      * driver is disabled.
1482      */
1483     kbd_enable(scp->sc->kbd);
1484
1485     /* we shall always use the keyboard in the XLATE mode here */
1486     cur_mode = scp->kbd_mode;
1487     scp->kbd_mode = K_XLATE;
1488     kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1489
1490     kbd_poll(scp->sc->kbd, TRUE);
1491     c = scgetc(scp->sc, SCGETC_CN | flags);
1492     kbd_poll(scp->sc->kbd, FALSE);
1493
1494     scp->kbd_mode = cur_mode;
1495     kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1496     kbd_disable(scp->sc->kbd);
1497     crit_exit();
1498
1499     switch (KEYFLAGS(c)) {
1500     case 0:     /* normal char */
1501         return KEYCHAR(c);
1502     case FKEY:  /* function key */
1503         p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
1504         fkey.len = fkeycp;
1505         if ((p != NULL) && (fkey.len > 0)) {
1506             bcopy(p, fkey.str, fkey.len);
1507             fkeycp = 1;
1508             return fkey.str[0];
1509         }
1510         return c;       /* XXX */
1511     case NOKEY:
1512     case ERRKEY:
1513     default:
1514         return -1;
1515     }
1516     /* NOT REACHED */
1517 }
1518
1519 static void
1520 sccnupdate(scr_stat *scp)
1521 {
1522     /* this is a cut-down version of scrn_timer()... */
1523
1524     if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress)
1525         return;
1526
1527     if (debugger > 0 || panicstr || shutdown_in_progress) {
1528         sc_touch_scrn_saver();
1529     } else if (scp != scp->sc->cur_scp) {
1530         return;
1531     }
1532
1533     if (!run_scrn_saver)
1534         scp->sc->flags &= ~SC_SCRN_IDLE;
1535 #if NSPLASH > 0
1536     if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1537         if (scp->sc->flags & SC_SCRN_BLANKED)
1538             stop_scrn_saver(scp->sc, current_saver);
1539 #endif /* NSPLASH */
1540
1541     if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
1542         || scp->sc->switch_in_progress)
1543         return;
1544     /*
1545      * FIXME: unlike scrn_timer(), we call scrn_update() from here even
1546      * when write_in_progress is non-zero.  XXX
1547      */
1548
1549     if (!ISGRAPHSC(scp) && !(scp->sc->flags & SC_SCRN_BLANKED))
1550         scrn_update(scp, TRUE);
1551 }
1552
1553 static void
1554 scrn_timer(void *arg)
1555 {
1556     static int kbd_interval = 0;
1557     struct timeval tv;
1558     sc_softc_t *sc;
1559     scr_stat *scp;
1560     int again;
1561
1562     again = (arg != NULL);
1563     if (arg != NULL)
1564         sc = (sc_softc_t *)arg;
1565     else if (sc_console != NULL)
1566         sc = sc_console->sc;
1567     else
1568         return;
1569
1570     /* don't do anything when we are performing some I/O operations */
1571     if (sc->font_loading_in_progress || sc->videoio_in_progress) {
1572         if (again)
1573             callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
1574         return;
1575     }
1576     crit_enter();
1577
1578     if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
1579         /* try to allocate a keyboard automatically */
1580         if (++kbd_interval >= 25) {
1581             sc->keyboard = kbd_allocate("*", -1, (void *)&sc->keyboard,
1582                                         sckbdevent, sc);
1583             if (sc->keyboard >= 0) {
1584                 sc->kbd = kbd_get_keyboard(sc->keyboard);
1585                 kbd_ioctl(sc->kbd, KDSKBMODE,
1586                           (caddr_t)&sc->cur_scp->kbd_mode);
1587                 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1588                                  LOCK_MASK);
1589             }
1590             kbd_interval = 0;
1591         }
1592     }
1593
1594     /* find the vty to update */
1595     scp = sc->cur_scp;
1596
1597     /* should we stop the screen saver? */
1598     getmicrouptime(&tv);
1599     if (debugger > 0 || panicstr || shutdown_in_progress)
1600         sc_touch_scrn_saver();
1601     if (run_scrn_saver) {
1602         if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
1603             sc->flags |= SC_SCRN_IDLE;
1604         else
1605             sc->flags &= ~SC_SCRN_IDLE;
1606     } else {
1607         sc->scrn_time_stamp = tv.tv_sec;
1608         sc->flags &= ~SC_SCRN_IDLE;
1609         if (scrn_blank_time > 0)
1610             run_scrn_saver = TRUE;
1611     }
1612 #if NSPLASH > 0
1613     if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE))
1614         if (sc->flags & SC_SCRN_BLANKED)
1615             stop_scrn_saver(sc, current_saver);
1616 #endif /* NSPLASH */
1617
1618     /* should we just return ? */
1619     if (sc->blink_in_progress || sc->switch_in_progress
1620         || sc->write_in_progress) {
1621         if (again)
1622             callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
1623         crit_exit();
1624         return;
1625     }
1626
1627     /* Update the screen */
1628     scp = sc->cur_scp;          /* cur_scp may have changed... */
1629     if (!ISGRAPHSC(scp) && !(sc->flags & SC_SCRN_BLANKED))
1630         scrn_update(scp, TRUE);
1631
1632 #if NSPLASH > 0
1633     /* should we activate the screen saver? */
1634     if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
1635         if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
1636             (*current_saver)(sc, TRUE);
1637 #endif /* NSPLASH */
1638
1639     if (again)
1640         callout_reset(&sc->scrn_timer_ch, hz / 25, scrn_timer, sc);
1641     crit_exit();
1642 }
1643
1644 static int
1645 and_region(int *s1, int *e1, int s2, int e2)
1646 {
1647     if (*e1 < s2 || e2 < *s1)
1648         return FALSE;
1649     *s1 = imax(*s1, s2);
1650     *e1 = imin(*e1, e2);
1651     return TRUE;
1652 }
1653
1654 static void 
1655 scrn_update(scr_stat *scp, int show_cursor)
1656 {
1657     int start;
1658     int end;
1659     int s;
1660     int e;
1661
1662     /* assert(scp == scp->sc->cur_scp) */
1663
1664     ++scp->sc->videoio_in_progress;
1665
1666 #ifndef SC_NO_CUTPASTE
1667     /* remove the previous mouse pointer image if necessary */
1668     if (scp->status & MOUSE_VISIBLE) {
1669         s = scp->mouse_pos;
1670         e = scp->mouse_pos + scp->xsize + 1;
1671         if ((scp->status & (MOUSE_MOVED | MOUSE_HIDDEN))
1672             || and_region(&s, &e, scp->start, scp->end)
1673             || ((scp->status & CURSOR_ENABLED) && 
1674                 (scp->cursor_pos != scp->cursor_oldpos) &&
1675                 (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos)
1676                  || and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)))) {
1677             sc_remove_mouse_image(scp);
1678             if (scp->end >= scp->xsize*scp->ysize)
1679                 scp->end = scp->xsize*scp->ysize - 1;
1680         }
1681     }
1682 #endif /* !SC_NO_CUTPASTE */
1683
1684 #if 1
1685     /* debug: XXX */
1686     if (scp->end >= scp->xsize*scp->ysize) {
1687         kprintf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end);
1688         scp->end = scp->xsize*scp->ysize - 1;
1689     }
1690     if (scp->start < 0) {
1691         kprintf("scrn_update(): scp->start %d < 0\n", scp->start);
1692         scp->start = 0;
1693     }
1694 #endif
1695
1696     /* update screen image */
1697     if (scp->start <= scp->end)  {
1698         if (scp->mouse_cut_end >= 0) {
1699             /* there is a marked region for cut & paste */
1700             if (scp->mouse_cut_start <= scp->mouse_cut_end) {
1701                 start = scp->mouse_cut_start;
1702                 end = scp->mouse_cut_end;
1703             } else {
1704                 start = scp->mouse_cut_end;
1705                 end = scp->mouse_cut_start - 1;
1706             }
1707             s = start;
1708             e = end;
1709             /* does the cut-mark region overlap with the update region? */
1710             if (and_region(&s, &e, scp->start, scp->end)) {
1711                 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
1712                 s = 0;
1713                 e = start - 1;
1714                 if (and_region(&s, &e, scp->start, scp->end))
1715                     (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1716                 s = end + 1;
1717                 e = scp->xsize*scp->ysize - 1;
1718                 if (and_region(&s, &e, scp->start, scp->end))
1719                     (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1720             } else {
1721                 (*scp->rndr->draw)(scp, scp->start,
1722                                    scp->end - scp->start + 1, FALSE);
1723             }
1724         } else {
1725             (*scp->rndr->draw)(scp, scp->start,
1726                                scp->end - scp->start + 1, FALSE);
1727         }
1728     }
1729
1730     /* we are not to show the cursor and the mouse pointer... */
1731     if (!show_cursor) {
1732         scp->end = 0;
1733         scp->start = scp->xsize*scp->ysize - 1;
1734         --scp->sc->videoio_in_progress;
1735         return;
1736     }
1737
1738     /* update cursor image */
1739     if (scp->status & CURSOR_ENABLED) {
1740         s = scp->start;
1741         e = scp->end;
1742         /* did cursor move since last time ? */
1743         if (scp->cursor_pos != scp->cursor_oldpos) {
1744             /* do we need to remove old cursor image ? */
1745             if (!and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos))
1746                 sc_remove_cursor_image(scp);
1747             sc_draw_cursor_image(scp);
1748         } else {
1749             if (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos))
1750                 /* cursor didn't move, but has been overwritten */
1751                 sc_draw_cursor_image(scp);
1752             else if (scp->sc->flags & SC_BLINK_CURSOR)
1753                 /* if it's a blinking cursor, update it */
1754                 (*scp->rndr->blink_cursor)(scp, scp->cursor_pos,
1755                                            sc_inside_cutmark(scp,
1756                                                scp->cursor_pos));
1757         }
1758     }
1759
1760 #ifndef SC_NO_CUTPASTE
1761     /* update "pseudo" mouse pointer image */
1762     if (scp->sc->flags & SC_MOUSE_ENABLED) {
1763         if (!(scp->status & (MOUSE_VISIBLE | MOUSE_HIDDEN))) {
1764             scp->status &= ~MOUSE_MOVED;
1765             sc_draw_mouse_image(scp);
1766         }
1767     }
1768 #endif /* SC_NO_CUTPASTE */
1769
1770     scp->end = 0;
1771     scp->start = scp->xsize*scp->ysize - 1;
1772
1773     --scp->sc->videoio_in_progress;
1774 }
1775
1776 #if NSPLASH > 0
1777 static int
1778 scsplash_callback(int event, void *arg)
1779 {
1780     sc_softc_t *sc;
1781     int error;
1782
1783     sc = (sc_softc_t *)arg;
1784
1785     switch (event) {
1786     case SPLASH_INIT:
1787         if (add_scrn_saver(scsplash_saver) == 0) {
1788             sc->flags &= ~SC_SAVER_FAILED;
1789             run_scrn_saver = TRUE;
1790             if (cold && !(boothowto & (RB_VERBOSE | RB_CONFIG))) {
1791                 scsplash_stick(TRUE);
1792                 (*current_saver)(sc, TRUE);
1793             }
1794         }
1795         return 0;
1796
1797     case SPLASH_TERM:
1798         if (current_saver == scsplash_saver) {
1799             scsplash_stick(FALSE);
1800             error = remove_scrn_saver(scsplash_saver);
1801             if (error)
1802                 return error;
1803         }
1804         return 0;
1805
1806     default:
1807         return EINVAL;
1808     }
1809 }
1810
1811 static void
1812 scsplash_saver(sc_softc_t *sc, int show)
1813 {
1814     static int busy = FALSE;
1815     scr_stat *scp;
1816
1817     if (busy)
1818         return;
1819     busy = TRUE;
1820
1821     scp = sc->cur_scp;
1822     if (show) {
1823         if (!(sc->flags & SC_SAVER_FAILED)) {
1824             if (!(sc->flags & SC_SCRN_BLANKED))
1825                 set_scrn_saver_mode(scp, -1, NULL, 0);
1826             switch (splash(sc->adp, TRUE)) {
1827             case 0:             /* succeeded */
1828                 break;
1829             case EAGAIN:        /* try later */
1830                 restore_scrn_saver_mode(scp, FALSE);
1831                 sc_touch_scrn_saver();          /* XXX */
1832                 break;
1833             default:
1834                 sc->flags |= SC_SAVER_FAILED;
1835                 scsplash_stick(FALSE);
1836                 restore_scrn_saver_mode(scp, TRUE);
1837                 kprintf("scsplash_saver(): failed to put up the image\n");
1838                 break;
1839             }
1840         }
1841     } else if (!sticky_splash) {
1842         if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
1843             restore_scrn_saver_mode(scp, TRUE);
1844     }
1845     busy = FALSE;
1846 }
1847
1848 static int
1849 add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1850 {
1851 #if 0
1852     int error;
1853
1854     if (current_saver != none_saver) {
1855         error = remove_scrn_saver(current_saver);
1856         if (error)
1857             return error;
1858     }
1859 #endif
1860     if (current_saver != none_saver)
1861         return EBUSY;
1862
1863     run_scrn_saver = FALSE;
1864     saver_mode = CONS_LKM_SAVER;
1865     current_saver = this_saver;
1866     return 0;
1867 }
1868
1869 static int
1870 remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1871 {
1872     if (current_saver != this_saver)
1873         return EINVAL;
1874
1875 #if 0
1876     /*
1877      * In order to prevent `current_saver' from being called by
1878      * the timeout routine `scrn_timer()' while we manipulate 
1879      * the saver list, we shall set `current_saver' to `none_saver' 
1880      * before stopping the current saver, rather than blocking by `splXX()'.
1881      */
1882     current_saver = none_saver;
1883     if (scrn_blanked)
1884         stop_scrn_saver(this_saver);
1885 #endif
1886
1887     /* unblank all blanked screens */
1888     wait_scrn_saver_stop(NULL);
1889     if (scrn_blanked)
1890         return EBUSY;
1891
1892     current_saver = none_saver;
1893     return 0;
1894 }
1895
1896 static int
1897 set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
1898 {
1899
1900     /* assert(scp == scp->sc->cur_scp) */
1901     crit_enter();
1902     if (!ISGRAPHSC(scp))
1903         sc_remove_cursor_image(scp);
1904     scp->splash_save_mode = scp->mode;
1905     scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
1906     scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
1907     scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
1908     scp->sc->flags |= SC_SCRN_BLANKED;
1909     ++scrn_blanked;
1910     crit_exit();
1911     if (mode < 0)
1912         return 0;
1913     scp->mode = mode;
1914     if (set_mode(scp) == 0) {
1915         if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS)
1916             scp->status |= GRAPHICS_MODE;
1917 #ifndef SC_NO_PALETTE_LOADING
1918         if (pal != NULL)
1919             load_palette(scp->sc->adp, pal);
1920 #endif
1921         sc_set_border(scp, border);
1922         return 0;
1923     } else {
1924         crit_enter();
1925         scp->mode = scp->splash_save_mode;
1926         scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1927         scp->status |= scp->splash_save_status;
1928         crit_exit();
1929         return 1;
1930     }
1931 }
1932
1933 static int
1934 restore_scrn_saver_mode(scr_stat *scp, int changemode)
1935 {
1936     int mode;
1937     int status;
1938
1939     /* assert(scp == scp->sc->cur_scp) */
1940     crit_enter();
1941     mode = scp->mode;
1942     status = scp->status;
1943     scp->mode = scp->splash_save_mode;
1944     scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1945     scp->status |= scp->splash_save_status;
1946     scp->sc->flags &= ~SC_SCRN_BLANKED;
1947     if (!changemode) {
1948         if (!ISGRAPHSC(scp))
1949             sc_draw_cursor_image(scp);
1950         --scrn_blanked;
1951         crit_exit();
1952         return 0;
1953     }
1954     if (set_mode(scp) == 0) {
1955 #ifndef SC_NO_PALETTE_LOADING
1956         load_palette(scp->sc->adp, scp->sc->palette);
1957 #endif
1958         --scrn_blanked;
1959         crit_exit();
1960         return 0;
1961     } else {
1962         scp->mode = mode;
1963         scp->status = status;
1964         crit_exit();
1965         return 1;
1966     }
1967 }
1968
1969 static void
1970 stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
1971 {
1972     (*saver)(sc, FALSE);
1973     run_scrn_saver = FALSE;
1974     /* the screen saver may have chosen not to stop after all... */
1975     if (sc->flags & SC_SCRN_BLANKED)
1976         return;
1977
1978     mark_all(sc->cur_scp);
1979     if (sc->delayed_next_scr)
1980         sc_switch_scr(sc, sc->delayed_next_scr - 1);
1981     wakeup((caddr_t)&scrn_blanked);
1982 }
1983
1984 static int
1985 wait_scrn_saver_stop(sc_softc_t *sc)
1986 {
1987     int error = 0;
1988
1989     while (scrn_blanked > 0) {
1990         run_scrn_saver = FALSE;
1991         if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
1992             error = 0;
1993             break;
1994         }
1995         error = tsleep((caddr_t)&scrn_blanked, PCATCH, "scrsav", 0);
1996         if ((error != 0) && (error != ERESTART))
1997             break;
1998     }
1999     run_scrn_saver = FALSE;
2000     return error;
2001 }
2002 #endif /* NSPLASH */
2003
2004 void
2005 sc_touch_scrn_saver(void)
2006 {
2007     scsplash_stick(FALSE);
2008     run_scrn_saver = FALSE;
2009 }
2010
2011 int
2012 sc_switch_scr(sc_softc_t *sc, u_int next_scr)
2013 {
2014     scr_stat *cur_scp;
2015     struct tty *tp;
2016
2017     DPRINTF(5, ("sc0: sc_switch_scr() %d ", next_scr + 1));
2018
2019     /* prevent switch if previously requested */
2020     if (sc->flags & SC_SCRN_VTYLOCK) {
2021             sc_bell(sc->cur_scp, sc->cur_scp->bell_pitch,
2022                 sc->cur_scp->bell_duration);
2023             return EPERM;
2024     }
2025
2026     /* delay switch if the screen is blanked or being updated */
2027     if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2028         || sc->blink_in_progress || sc->videoio_in_progress) {
2029         sc->delayed_next_scr = next_scr + 1;
2030         sc_touch_scrn_saver();
2031         DPRINTF(5, ("switch delayed\n"));
2032         return 0;
2033     }
2034
2035     crit_enter();
2036     cur_scp = sc->cur_scp;
2037
2038     /* we are in the middle of the vty switching process... */
2039     if (sc->switch_in_progress
2040         && (cur_scp->smode.mode == VT_PROCESS)
2041         && cur_scp->proc) {
2042         if (cur_scp->proc != pfind(cur_scp->pid)) {
2043             /* 
2044              * The controlling process has died!!.  Do some clean up.
2045              * NOTE:`cur_scp->proc' and `cur_scp->smode.mode' 
2046              * are not reset here yet; they will be cleared later.
2047              */
2048             DPRINTF(5, ("cur_scp controlling process %d died, ",
2049                cur_scp->pid));
2050             if (cur_scp->status & SWITCH_WAIT_REL) {
2051                 /*
2052                  * Force the previous switch to finish, but return now 
2053                  * with error.
2054                  *
2055                  * note: must be called from a critical section because 
2056                  * finish_vt_rel will call do_switch_scr which releases it
2057                  * temporarily.
2058                  */
2059                 DPRINTF(5, ("reset WAIT_REL, "));
2060                 finish_vt_rel(cur_scp, TRUE);
2061                 crit_exit();
2062                 DPRINTF(5, ("finishing previous switch\n"));
2063                 return EINVAL;
2064             } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2065                 /* let's assume screen switch has been completed. */
2066                 DPRINTF(5, ("reset WAIT_ACQ, "));
2067                 finish_vt_acq(cur_scp);
2068             } else {
2069                 /* 
2070                  * We are in between screen release and acquisition, and
2071                  * reached here via scgetc() or scrn_timer() which has 
2072                  * interrupted exchange_scr(). Don't do anything stupid.
2073                  */
2074                 DPRINTF(5, ("waiting nothing, "));
2075             }
2076         } else {
2077             /*
2078              * The controlling process is alive, but not responding... 
2079              * It is either buggy or it may be just taking time.
2080              * The following code is a gross kludge to cope with this
2081              * problem for which there is no clean solution. XXX
2082              */
2083             if (cur_scp->status & SWITCH_WAIT_REL) {
2084                 switch (sc->switch_in_progress++) {
2085                 case 1:
2086                     break;
2087                 case 2:
2088                     DPRINTF(5, ("sending relsig again, "));
2089                     signal_vt_rel(cur_scp);
2090                     break;
2091                 case 3:
2092                     break;
2093                 case 4:
2094                 default:
2095                     /*
2096                      * Act as if the controlling program returned
2097                      * VT_FALSE.
2098                      *
2099                      * note: must be called from a critical section because 
2100                      * finish_vt_rel will call do_switch_scr which releases it
2101                      * temporarily.
2102                      */
2103                     DPRINTF(5, ("force reset WAIT_REL, "));
2104                     finish_vt_rel(cur_scp, FALSE);
2105                     crit_exit();
2106                     DPRINTF(5, ("act as if VT_FALSE was seen\n"));
2107                     return EINVAL;
2108                 }
2109             } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2110                 switch (sc->switch_in_progress++) {
2111                 case 1:
2112                     break;
2113                 case 2:
2114                     DPRINTF(5, ("sending acqsig again, "));
2115                     signal_vt_acq(cur_scp);
2116                     break;
2117                 case 3:
2118                     break;
2119                 case 4:
2120                 default:
2121                      /* clear the flag and finish the previous switch */
2122                     DPRINTF(5, ("force reset WAIT_ACQ, "));
2123                     finish_vt_acq(cur_scp);
2124                     break;
2125                 }
2126             }
2127         }
2128     }
2129
2130     /*
2131      * Return error if an invalid argument is given, or vty switch
2132      * is still in progress.
2133      */
2134     if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2135         || sc->switch_in_progress) {
2136         crit_exit();
2137         sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2138         DPRINTF(5, ("error 1\n"));
2139         return EINVAL;
2140     }
2141
2142     /*
2143      * Don't allow switching away from the graphics mode vty
2144      * if the switch mode is VT_AUTO, unless the next vty is the same 
2145      * as the current or the current vty has been closed (but showing).
2146      */
2147     tp = VIRTUAL_TTY(sc, cur_scp->index);
2148     if ((cur_scp->index != next_scr)
2149         && ISTTYOPEN(tp)
2150         && (cur_scp->smode.mode == VT_AUTO)
2151         && ISGRAPHSC(cur_scp)) {
2152         crit_exit();
2153         sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2154         DPRINTF(5, ("error, graphics mode\n"));
2155         return EINVAL;
2156     }
2157
2158     /*
2159      * Is the wanted vty open? Don't allow switching to a closed vty.
2160      * If we are in DDB, don't switch to a vty in the VT_PROCESS mode.
2161      * Note that we always allow the user to switch to the kernel 
2162      * console even if it is closed.
2163      */
2164     if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2165         tp = VIRTUAL_TTY(sc, next_scr);
2166         if (!ISTTYOPEN(tp)) {
2167             crit_exit();
2168             sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2169             DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2170             return EINVAL;
2171         }
2172         if ((debugger > 0) && (SC_STAT(tp->t_dev)->smode.mode == VT_PROCESS)) {
2173             crit_exit();
2174             DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n"));
2175             return EINVAL;
2176         }
2177     }
2178
2179     /* this is the start of vty switching process... */
2180     ++sc->switch_in_progress;
2181     sc->delayed_next_scr = 0;
2182     sc->old_scp = cur_scp;
2183     sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2184     if (sc->new_scp == sc->old_scp) {
2185         sc->switch_in_progress = 0;
2186         wakeup((caddr_t)&sc->new_scp->smode);
2187         crit_exit();
2188         DPRINTF(5, ("switch done (new == old)\n"));
2189         return 0;
2190     }
2191
2192     /* has controlling process died? */
2193     vt_proc_alive(sc->old_scp);
2194     vt_proc_alive(sc->new_scp);
2195
2196     /* wait for the controlling process to release the screen, if necessary */
2197     if (signal_vt_rel(sc->old_scp)) {
2198         crit_exit();
2199         return 0;
2200     }
2201
2202     /* go set up the new vty screen */
2203     crit_exit();
2204     exchange_scr(sc);
2205     crit_enter();
2206
2207     /* wake up processes waiting for this vty */
2208     wakeup((caddr_t)&sc->cur_scp->smode);
2209
2210     /* wait for the controlling process to acknowledge, if necessary */
2211     if (signal_vt_acq(sc->cur_scp)) {
2212         crit_exit();
2213         return 0;
2214     }
2215
2216     sc->switch_in_progress = 0;
2217     if (sc->unit == sc_console_unit)
2218         cons_unavail = FALSE;
2219     crit_exit();
2220     DPRINTF(5, ("switch done\n"));
2221
2222     return 0;
2223 }
2224
2225 /*
2226  * NOTE: must be called from a critical section because do_switch_scr
2227  * will release it temporarily.
2228  */
2229 static void
2230 do_switch_scr(sc_softc_t *sc)
2231 {
2232     vt_proc_alive(sc->new_scp);
2233
2234     crit_exit();
2235     exchange_scr(sc);
2236     crit_enter();
2237     /* sc->cur_scp == sc->new_scp */
2238     wakeup((caddr_t)&sc->cur_scp->smode);
2239
2240     /* wait for the controlling process to acknowledge, if necessary */
2241     if (!signal_vt_acq(sc->cur_scp)) {
2242         sc->switch_in_progress = 0;
2243         if (sc->unit == sc_console_unit)
2244             cons_unavail = FALSE;
2245     }
2246 }
2247
2248 static int
2249 vt_proc_alive(scr_stat *scp)
2250 {
2251     if (scp->proc) {
2252         if (scp->proc == pfind(scp->pid))
2253             return TRUE;
2254         scp->proc = NULL;
2255         scp->smode.mode = VT_AUTO;
2256         DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2257     }
2258     return FALSE;
2259 }
2260
2261 static int
2262 signal_vt_rel(scr_stat *scp)
2263 {
2264     if (scp->smode.mode != VT_PROCESS)
2265         return FALSE;
2266     scp->status |= SWITCH_WAIT_REL;
2267     ksignal(scp->proc, scp->smode.relsig);
2268     DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2269     return TRUE;
2270 }
2271
2272 static int
2273 signal_vt_acq(scr_stat *scp)
2274 {
2275     if (scp->smode.mode != VT_PROCESS)
2276         return FALSE;
2277     if (scp->sc->unit == sc_console_unit)
2278         cons_unavail = TRUE;
2279     scp->status |= SWITCH_WAIT_ACQ;
2280     ksignal(scp->proc, scp->smode.acqsig);
2281     DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2282     return TRUE;
2283 }
2284
2285 /*
2286  * NOTE: must be called from a critical section because do_switch_scr
2287  * will release it temporarily.
2288  */
2289 static int
2290 finish_vt_rel(scr_stat *scp, int release)
2291 {
2292     if (scp == scp->sc->old_scp && scp->status & SWITCH_WAIT_REL) {
2293         scp->status &= ~SWITCH_WAIT_REL;
2294         if (release)
2295             do_switch_scr(scp->sc);
2296         else
2297             scp->sc->switch_in_progress = 0;
2298         return 0;
2299     }
2300     return EINVAL;
2301 }
2302
2303 static int
2304 finish_vt_acq(scr_stat *scp)
2305 {
2306     if (scp == scp->sc->new_scp && scp->status & SWITCH_WAIT_ACQ) {
2307         scp->status &= ~SWITCH_WAIT_ACQ;
2308         scp->sc->switch_in_progress = 0;
2309         return 0;
2310     }
2311     return EINVAL;
2312 }
2313
2314 static void
2315 exchange_scr(sc_softc_t *sc)
2316 {
2317     scr_stat *scp;
2318
2319     /* save the current state of video and keyboard */
2320     sc_move_cursor(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
2321     if (!ISGRAPHSC(sc->old_scp))
2322         sc_remove_cursor_image(sc->old_scp);
2323     if (sc->old_scp->kbd_mode == K_XLATE)
2324         save_kbd_state(sc->old_scp);
2325
2326     /* set up the video for the new screen */
2327     scp = sc->cur_scp = sc->new_scp;
2328     if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
2329         set_mode(scp);
2330     else
2331         sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2332                     (void *)sc->adp->va_window, FALSE);
2333     scp->status |= MOUSE_HIDDEN;
2334     sc_move_cursor(scp, scp->xpos, scp->ypos);
2335     if (!ISGRAPHSC(scp))
2336         sc_set_cursor_image(scp);
2337 #ifndef SC_NO_PALETTE_LOADING
2338     if (ISGRAPHSC(sc->old_scp))
2339         load_palette(sc->adp, sc->palette);
2340 #endif
2341     sc_set_border(scp, scp->border);
2342
2343     /* set up the keyboard for the new screen */
2344     if (sc->old_scp->kbd_mode != scp->kbd_mode)
2345         kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2346     update_kbd_state(scp, scp->status, LOCK_MASK);
2347
2348     mark_all(scp);
2349 }
2350
2351 void
2352 sc_puts(scr_stat *scp, u_char *buf, int len)
2353 {
2354 #if NSPLASH > 0
2355     /* make screensaver happy */
2356     if (!sticky_splash && scp == scp->sc->cur_scp)
2357         run_scrn_saver = FALSE;
2358 #endif
2359
2360     if (scp->tsw)
2361         (*scp->tsw->te_puts)(scp, buf, len);
2362
2363     if (scp->sc->delayed_next_scr)
2364         sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
2365 }
2366
2367 void
2368 sc_draw_cursor_image(scr_stat *scp)
2369 {
2370     /* assert(scp == scp->sc->cur_scp); */
2371     ++scp->sc->videoio_in_progress;
2372     (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
2373                               scp->sc->flags & SC_BLINK_CURSOR, TRUE,
2374                               sc_inside_cutmark(scp, scp->cursor_pos));
2375     scp->cursor_oldpos = scp->cursor_pos;
2376     --scp->sc->videoio_in_progress;
2377 }
2378
2379 void
2380 sc_remove_cursor_image(scr_stat *scp)
2381 {
2382     /* assert(scp == scp->sc->cur_scp); */
2383     ++scp->sc->videoio_in_progress;
2384     (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
2385                               scp->sc->flags & SC_BLINK_CURSOR, FALSE,
2386                               sc_inside_cutmark(scp, scp->cursor_oldpos));
2387     --scp->sc->videoio_in_progress;
2388 }
2389
2390 static void
2391 update_cursor_image(scr_stat *scp)
2392 {
2393     int blink;
2394
2395     if (scp->sc->flags & SC_CHAR_CURSOR) {
2396         scp->cursor_base = imax(0, scp->sc->cursor_base);
2397         scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
2398     } else {
2399         scp->cursor_base = 0;
2400         scp->cursor_height = scp->font_size;
2401     }
2402     blink = scp->sc->flags & SC_BLINK_CURSOR;
2403
2404     /* assert(scp == scp->sc->cur_scp); */
2405     ++scp->sc->videoio_in_progress;
2406     (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE, 
2407                               sc_inside_cutmark(scp, scp->cursor_pos));
2408     (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
2409     (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE, 
2410                               sc_inside_cutmark(scp, scp->cursor_pos));
2411     --scp->sc->videoio_in_progress;
2412 }
2413
2414 void
2415 sc_set_cursor_image(scr_stat *scp)
2416 {
2417     if (scp->sc->flags & SC_CHAR_CURSOR) {
2418         scp->cursor_base = imax(0, scp->sc->cursor_base);
2419         scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
2420     } else {
2421         scp->cursor_base = 0;
2422         scp->cursor_height = scp->font_size;
2423     }
2424
2425     /* assert(scp == scp->sc->cur_scp); */
2426     ++scp->sc->videoio_in_progress;
2427     (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
2428                              scp->sc->flags & SC_BLINK_CURSOR);
2429     --scp->sc->videoio_in_progress;
2430 }
2431
2432 static void
2433 scinit(int unit, int flags)
2434 {
2435     /*
2436      * When syscons is being initialized as the kernel console, malloc()
2437      * is not yet functional, because various kernel structures has not been
2438      * fully initialized yet.  Therefore, we need to declare the following
2439      * static buffers for the console.  This is less than ideal, 
2440      * but is necessry evil for the time being.  XXX
2441      */
2442     static scr_stat main_console;
2443     static cdev_t main_devs[MAXCONS];
2444     static struct tty main_tty;
2445     static u_short sc_buffer[ROW*COL];  /* XXX */
2446 #ifndef SC_NO_FONT_LOADING
2447     static u_char font_8[256*8];
2448     static u_char font_14[256*14];
2449     static u_char font_16[256*16];
2450 #endif
2451
2452     sc_softc_t *sc;
2453     scr_stat *scp;
2454     video_adapter_t *adp;
2455     int col;
2456     int row;
2457     int i;
2458
2459     /* one time initialization */
2460     if (init_done == COLD)
2461         sc_get_bios_values(&bios_value);
2462     init_done = WARM;
2463
2464     /*
2465      * Allocate resources.  Even if we are being called for the second
2466      * time, we must allocate them again, because they might have 
2467      * disappeared...
2468      */
2469     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
2470     adp = NULL;
2471     if (sc->adapter >= 0) {
2472         vid_release(sc->adp, (void *)&sc->adapter);
2473         adp = sc->adp;
2474         sc->adp = NULL;
2475     }
2476     if (sc->keyboard >= 0) {
2477         DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
2478         i = kbd_release(sc->kbd, (void *)&sc->keyboard);
2479         DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
2480         if (sc->kbd != NULL) {
2481             DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, unit:%d, flags:0x%x\n",
2482                 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags));
2483         }
2484         sc->kbd = NULL;
2485     }
2486     sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
2487     sc->adp = vid_get_adapter(sc->adapter);
2488     /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
2489     sc->keyboard = kbd_allocate("*", unit, (void *)&sc->keyboard,
2490                                 sckbdevent, sc);
2491     DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
2492     sc->kbd = kbd_get_keyboard(sc->keyboard);
2493     if (sc->kbd != NULL) {
2494         DPRINTF(1, ("sc%d: kbd index:%d, unit:%d, flags:0x%x\n",
2495                 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags));
2496     }
2497
2498     if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
2499
2500         sc->initial_mode = sc->adp->va_initial_mode;
2501
2502 #ifndef SC_NO_FONT_LOADING
2503         if (flags & SC_KERNEL_CONSOLE) {
2504             sc->font_8 = font_8;
2505             sc->font_14 = font_14;
2506             sc->font_16 = font_16;
2507         } else if (sc->font_8 == NULL) {
2508             /* assert(sc_malloc) */
2509             sc->font_8 = kmalloc(sizeof(font_8), M_SYSCONS, M_WAITOK);
2510             sc->font_14 = kmalloc(sizeof(font_14), M_SYSCONS, M_WAITOK);
2511             sc->font_16 = kmalloc(sizeof(font_16), M_SYSCONS, M_WAITOK);
2512         }
2513 #endif
2514
2515         /* extract the hardware cursor location and hide the cursor for now */
2516         (*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
2517         (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
2518
2519         /* set up the first console */
2520         sc->first_vty = unit*MAXCONS;
2521         sc->vtys = MAXCONS;             /* XXX: should be configurable */
2522         if (flags & SC_KERNEL_CONSOLE) {
2523             sc->dev = main_devs;
2524             sc->dev[0] = make_dev(&sc_ops, unit*MAXCONS, UID_ROOT, 
2525                                 GID_WHEEL, 0600, "ttyv%r", unit*MAXCONS);
2526             sc->dev[0]->si_tty = &main_tty;
2527             ttyregister(&main_tty);
2528             scp = &main_console;
2529             init_scp(sc, sc->first_vty, scp);
2530             sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
2531                         (void *)sc_buffer, FALSE);
2532             if (sc_init_emulator(scp, SC_DFLT_TERM))
2533                 sc_init_emulator(scp, "*");
2534             (*scp->tsw->te_default_attr)(scp,
2535                                          kernel_default.std_color,
2536                                          kernel_default.rev_color);
2537         } else {
2538             /* assert(sc_malloc) */
2539             sc->dev = kmalloc(sizeof(cdev_t)*sc->vtys, M_SYSCONS, M_WAITOK | M_ZERO);
2540             sc->dev[0] = make_dev(&sc_ops, unit*MAXCONS, UID_ROOT, 
2541                                 GID_WHEEL, 0600, "ttyv%r", unit*MAXCONS);
2542             sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
2543             scp = alloc_scp(sc, sc->first_vty);
2544         }
2545         sc->dev[0]->si_drv1 = scp;
2546         sc->cur_scp = scp;
2547
2548         /* copy screen to temporary buffer */
2549         sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2550                     (void *)scp->sc->adp->va_window, FALSE);
2551         if (ISTEXTSC(scp))
2552             sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
2553
2554         /* move cursors to the initial positions */
2555         if (col >= scp->xsize)
2556             col = 0;
2557         if (row >= scp->ysize)
2558             row = scp->ysize - 1;
2559         scp->xpos = col;
2560         scp->ypos = row;
2561         scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
2562         if (bios_value.cursor_end < scp->font_size)
2563             sc->cursor_base = scp->font_size - bios_value.cursor_end - 1;
2564         else
2565             sc->cursor_base = 0;
2566         i = bios_value.cursor_end - bios_value.cursor_start + 1;
2567         sc->cursor_height = imin(i, scp->font_size);
2568 #ifndef SC_NO_SYSMOUSE
2569         sc_mouse_move(scp, scp->xpixel/2, scp->ypixel/2);
2570 #endif
2571         if (!ISGRAPHSC(scp)) {
2572             sc_set_cursor_image(scp);
2573             sc_draw_cursor_image(scp);
2574         }
2575
2576         /* save font and palette */
2577 #ifndef SC_NO_FONT_LOADING
2578         sc->fonts_loaded = 0;
2579         if (ISFONTAVAIL(sc->adp->va_flags)) {
2580 #ifdef SC_DFLT_FONT
2581             bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
2582             bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
2583             bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
2584             sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
2585             if (scp->font_size < 14) {
2586                 sc_load_font(scp, 0, 8, sc->font_8, 0, 256);
2587             } else if (scp->font_size >= 16) {
2588                 sc_load_font(scp, 0, 16, sc->font_16, 0, 256);
2589             } else {
2590                 sc_load_font(scp, 0, 14, sc->font_14, 0, 256);
2591             }
2592 #else /* !SC_DFLT_FONT */
2593             if (scp->font_size < 14) {
2594                 sc_save_font(scp, 0, 8, sc->font_8, 0, 256);
2595                 sc->fonts_loaded = FONT_8;
2596             } else if (scp->font_size >= 16) {
2597                 sc_save_font(scp, 0, 16, sc->font_16, 0, 256);
2598                 sc->fonts_loaded = FONT_16;
2599             } else {
2600                 sc_save_font(scp, 0, 14, sc->font_14, 0, 256);
2601                 sc->fonts_loaded = FONT_14;
2602             }
2603 #endif /* SC_DFLT_FONT */
2604             /* FONT KLUDGE: always use the font page #0. XXX */
2605             sc_show_font(scp, 0);
2606         }
2607 #endif /* !SC_NO_FONT_LOADING */
2608
2609 #ifndef SC_NO_PALETTE_LOADING
2610         save_palette(sc->adp, sc->palette);
2611 #endif
2612
2613 #if NSPLASH > 0
2614         if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
2615             /* we are ready to put up the splash image! */
2616             splash_init(sc->adp, scsplash_callback, sc);
2617             sc->flags |= SC_SPLASH_SCRN;
2618         }
2619 #endif /* NSPLASH */
2620     }
2621
2622     /* the rest is not necessary, if we have done it once */
2623     if (sc->flags & SC_INIT_DONE)
2624         return;
2625
2626     /* initialize mapscrn arrays to a one to one map */
2627     for (i = 0; i < sizeof(sc->scr_map); i++)
2628         sc->scr_map[i] = sc->scr_rmap[i] = i;
2629
2630     sc->flags |= SC_INIT_DONE;
2631 }
2632
2633 static void
2634 scterm(int unit, int flags)
2635 {
2636     sc_softc_t *sc;
2637     scr_stat *scp;
2638
2639     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
2640     if (sc == NULL)
2641         return;                 /* shouldn't happen */
2642
2643 #if NSPLASH > 0
2644     /* this console is no longer available for the splash screen */
2645     if (sc->flags & SC_SPLASH_SCRN) {
2646         splash_term(sc->adp);
2647         sc->flags &= ~SC_SPLASH_SCRN;
2648     }
2649 #endif /* NSPLASH */
2650
2651 #if 0 /* XXX */
2652     /* move the hardware cursor to the upper-left corner */
2653     (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
2654 #endif
2655
2656     /* release the keyboard and the video card */
2657     if (sc->keyboard >= 0)
2658         kbd_release(sc->kbd, &sc->keyboard);
2659     if (sc->adapter >= 0)
2660         vid_release(sc->adp, &sc->adapter);
2661
2662     /* stop the terminal emulator, if any */
2663     scp = SC_STAT(sc->dev[0]);
2664     if (scp->tsw)
2665         (*scp->tsw->te_term)(scp, &scp->ts);
2666     if (scp->ts != NULL)
2667         kfree(scp->ts, M_SYSCONS);
2668
2669     /* clear the structure */
2670     if (!(flags & SC_KERNEL_CONSOLE)) {
2671         /* XXX: We need delete_dev() for this */
2672         kfree(sc->dev, M_SYSCONS);
2673 #if 0
2674         /* XXX: We need a ttyunregister for this */
2675         kfree(sc->tty, M_SYSCONS);
2676 #endif
2677 #ifndef SC_NO_FONT_LOADING
2678         kfree(sc->font_8, M_SYSCONS);
2679         kfree(sc->font_14, M_SYSCONS);
2680         kfree(sc->font_16, M_SYSCONS);
2681 #endif
2682         /* XXX vtb, history */
2683     }
2684     bzero(sc, sizeof(*sc));
2685     sc->keyboard = -1;
2686     sc->adapter = -1;
2687 }
2688
2689 static void
2690 scshutdown(void *arg, int howto)
2691 {
2692     /* assert(sc_console != NULL) */
2693
2694     sc_touch_scrn_saver();
2695     if (!cold && sc_console
2696         && sc_console->sc->cur_scp->smode.mode == VT_AUTO 
2697         && sc_console->smode.mode == VT_AUTO)
2698         sc_switch_scr(sc_console->sc, sc_console->index);
2699     shutdown_in_progress = TRUE;
2700 }
2701
2702 int
2703 sc_clean_up(scr_stat *scp)
2704 {
2705 #if NSPLASH > 0
2706     int error;
2707 #endif /* NSPLASH */
2708
2709     if (scp->sc->flags & SC_SCRN_BLANKED) {
2710         sc_touch_scrn_saver();
2711 #if NSPLASH > 0
2712         if ((error = wait_scrn_saver_stop(scp->sc)))
2713             return error;
2714 #endif /* NSPLASH */
2715     }
2716     scp->status |= MOUSE_HIDDEN;
2717     sc_remove_mouse_image(scp);
2718     sc_remove_cutmarking(scp);
2719     return 0;
2720 }
2721
2722 void
2723 sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
2724 {
2725     sc_vtb_t new;
2726     sc_vtb_t old;
2727
2728     old = scp->vtb;
2729     sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
2730     if (!discard && (old.vtb_flags & VTB_VALID)) {
2731         /* retain the current cursor position and buffer contants */
2732         scp->cursor_oldpos = scp->cursor_pos;
2733         /* 
2734          * This works only if the old buffer has the same size as or larger 
2735          * than the new one. XXX
2736          */
2737         sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
2738         scp->vtb = new;
2739     } else {
2740         scp->vtb = new;
2741         sc_vtb_destroy(&old);
2742     }
2743
2744 #ifndef SC_NO_SYSMOUSE
2745     /* move the mouse cursor at the center of the screen */
2746     sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
2747 #endif
2748 }
2749
2750 static scr_stat *
2751 alloc_scp(sc_softc_t *sc, int vty)
2752 {
2753     scr_stat *scp;
2754
2755     /* assert(sc_malloc) */
2756
2757     scp = kmalloc(sizeof(scr_stat), M_SYSCONS, M_WAITOK);
2758     init_scp(sc, vty, scp);
2759
2760     sc_alloc_scr_buffer(scp, TRUE, TRUE);
2761     if (sc_init_emulator(scp, SC_DFLT_TERM))
2762         sc_init_emulator(scp, "*");
2763
2764 #ifndef SC_NO_CUTPASTE
2765     sc_alloc_cut_buffer(scp, TRUE);
2766 #endif
2767
2768 #ifndef SC_NO_HISTORY
2769     sc_alloc_history_buffer(scp, 0, 0, TRUE);
2770 #endif
2771
2772     return scp;
2773 }
2774
2775 static void
2776 init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
2777 {
2778     video_info_t info;
2779
2780     bzero(scp, sizeof(*scp));
2781
2782     scp->index = vty;
2783     scp->sc = sc;
2784     scp->status = 0;
2785     scp->mode = sc->initial_mode;
2786     callout_init(&scp->blink_screen_ch);
2787     (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
2788     if (info.vi_flags & V_INFO_GRAPHICS) {
2789         scp->status |= GRAPHICS_MODE;
2790         scp->xpixel = info.vi_width;
2791         scp->ypixel = info.vi_height;
2792         scp->xsize = info.vi_width/8;
2793         scp->ysize = info.vi_height/info.vi_cheight;
2794         scp->font_size = 0;
2795         scp->font = NULL;
2796     } else {
2797         scp->xsize = info.vi_width;
2798         scp->ysize = info.vi_height;
2799         scp->xpixel = scp->xsize*8;
2800         scp->ypixel = scp->ysize*info.vi_cheight;
2801         if (info.vi_cheight < 14) {
2802             scp->font_size = 8;
2803 #ifndef SC_NO_FONT_LOADING
2804             scp->font = sc->font_8;
2805 #else
2806             scp->font = NULL;
2807 #endif
2808         } else if (info.vi_cheight >= 16) {
2809             scp->font_size = 16;
2810 #ifndef SC_NO_FONT_LOADING
2811             scp->font = sc->font_16;
2812 #else
2813             scp->font = NULL;
2814 #endif
2815         } else {
2816             scp->font_size = 14;
2817 #ifndef SC_NO_FONT_LOADING
2818             scp->font = sc->font_14;
2819 #else
2820             scp->font = NULL;
2821 #endif
2822         }
2823     }
2824     sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
2825     sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
2826     scp->xoff = scp->yoff = 0;
2827     scp->xpos = scp->ypos = 0;
2828     scp->start = scp->xsize * scp->ysize - 1;
2829     scp->end = 0;
2830     scp->tsw = NULL;
2831     scp->ts = NULL;
2832     scp->rndr = NULL;
2833     scp->border = BG_BLACK;
2834     scp->cursor_base = sc->cursor_base;
2835     scp->cursor_height = imin(sc->cursor_height, scp->font_size);
2836     scp->mouse_cut_start = scp->xsize*scp->ysize;
2837     scp->mouse_cut_end = -1;
2838     scp->mouse_signal = 0;
2839     scp->mouse_pid = 0;
2840     scp->mouse_proc = NULL;
2841     scp->kbd_mode = K_XLATE;
2842     scp->bell_pitch = bios_value.bell_pitch;
2843     scp->bell_duration = BELL_DURATION;
2844     scp->status |= (bios_value.shift_state & NLKED);
2845     scp->status |= CURSOR_ENABLED | MOUSE_HIDDEN;
2846     scp->pid = 0;
2847     scp->proc = NULL;
2848     scp->smode.mode = VT_AUTO;
2849     scp->history = NULL;
2850     scp->history_pos = 0;
2851     scp->history_size = 0;
2852 }
2853
2854 int
2855 sc_init_emulator(scr_stat *scp, char *name)
2856 {
2857     sc_term_sw_t *sw;
2858     sc_rndr_sw_t *rndr;
2859     void *p;
2860     int error;
2861
2862     if (name == NULL)   /* if no name is given, use the current emulator */
2863         sw = scp->tsw;
2864     else                /* ...otherwise find the named emulator */
2865         sw = sc_term_match(name);
2866     if (sw == NULL)
2867         return EINVAL;
2868
2869     rndr = NULL;
2870     if (strcmp(sw->te_renderer, "*") != 0) {
2871         rndr = sc_render_match(scp, sw->te_renderer,
2872                                scp->status & (GRAPHICS_MODE | PIXEL_MODE));
2873     }
2874     if (rndr == NULL) {
2875         rndr = sc_render_match(scp, scp->sc->adp->va_name,
2876                                scp->status & (GRAPHICS_MODE | PIXEL_MODE));
2877         if (rndr == NULL)
2878             return ENODEV;
2879     }
2880
2881     if (sw == scp->tsw) {
2882         error = (*sw->te_init)(scp, &scp->ts, SC_TE_WARM_INIT);
2883         scp->rndr = rndr;
2884         scp->rndr->init(scp);
2885         sc_clear_screen(scp);
2886         /* assert(error == 0); */
2887         return error;
2888     }
2889
2890     if (sc_malloc && (sw->te_size > 0))
2891         p = kmalloc(sw->te_size, M_SYSCONS, M_NOWAIT);
2892     else
2893         p = NULL;
2894     error = (*sw->te_init)(scp, &p, SC_TE_COLD_INIT);
2895     if (error)
2896         return error;
2897
2898     if (scp->tsw)
2899         (*scp->tsw->te_term)(scp, &scp->ts);
2900     if (scp->ts != NULL)
2901         kfree(scp->ts, M_SYSCONS);
2902     scp->tsw = sw;
2903     scp->ts = p;
2904     scp->rndr = rndr;
2905     scp->rndr->init(scp);
2906
2907     /* XXX */
2908     (*sw->te_default_attr)(scp, user_default.std_color, user_default.rev_color);
2909     sc_clear_screen(scp);
2910
2911     return 0;
2912 }
2913
2914 /*
2915  * scgetc(flags) - get character from keyboard.
2916  * If flags & SCGETC_CN, then avoid harmful side effects.
2917  * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
2918  * return NOKEY if there is nothing there.
2919  */
2920 static u_int
2921 scgetc(sc_softc_t *sc, u_int flags)
2922 {
2923     scr_stat *scp;
2924 #ifndef SC_NO_HISTORY
2925     struct tty *tp;
2926 #endif
2927     u_int c;
2928     int this_scr;
2929     int f;
2930     int i;
2931
2932     if (sc->kbd == NULL)
2933         return NOKEY;
2934
2935 next_code:
2936 #if 1
2937     /* I don't like this, but... XXX */
2938     if (flags & SCGETC_CN)
2939         sccnupdate(sc->cur_scp);
2940 #endif
2941     scp = sc->cur_scp;
2942     /* first see if there is something in the keyboard port */
2943     for (;;) {
2944         c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
2945         if (c == ERRKEY) {
2946             if (!(flags & SCGETC_CN))
2947                 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
2948         } else if (c == NOKEY)
2949             return c;
2950         else
2951             break;
2952     }
2953
2954     /* make screensaver happy */
2955     if (!(c & RELKEY))
2956         sc_touch_scrn_saver();
2957
2958     if (!(flags & SCGETC_CN))
2959         /* do the /dev/random device a favour */
2960         add_keyboard_randomness(c);
2961
2962     if (scp->kbd_mode != K_XLATE)
2963         return KEYCHAR(c);
2964
2965     /* if scroll-lock pressed allow history browsing */
2966     if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
2967
2968         scp->status &= ~CURSOR_ENABLED;
2969         sc_remove_cursor_image(scp);
2970
2971 #ifndef SC_NO_HISTORY
2972         if (!(scp->status & BUFFER_SAVED)) {
2973             scp->status |= BUFFER_SAVED;
2974             sc_hist_save(scp);
2975         }
2976         switch (c) {
2977         /* FIXME: key codes */
2978         case SPCLKEY | FKEY | F(49):  /* home key */
2979             sc_remove_cutmarking(scp);
2980             sc_hist_home(scp);
2981             goto next_code;
2982
2983         case SPCLKEY | FKEY | F(57):  /* end key */
2984             sc_remove_cutmarking(scp);
2985             sc_hist_end(scp);
2986             goto next_code;
2987
2988         case SPCLKEY | FKEY | F(50):  /* up arrow key */
2989             sc_remove_cutmarking(scp);
2990             if (sc_hist_up_line(scp))
2991                 if (!(flags & SCGETC_CN))
2992                     sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
2993             goto next_code;
2994
2995         case SPCLKEY | FKEY | F(58):  /* down arrow key */
2996             sc_remove_cutmarking(scp);
2997             if (sc_hist_down_line(scp))
2998                 if (!(flags & SCGETC_CN))
2999                     sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3000             goto next_code;
3001
3002         case SPCLKEY | FKEY | F(51):  /* page up key */
3003             sc_remove_cutmarking(scp);
3004             for (i=0; i<scp->ysize; i++)
3005             if (sc_hist_up_line(scp)) {
3006                 if (!(flags & SCGETC_CN))
3007                     sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3008                 break;
3009             }
3010             goto next_code;
3011
3012         case SPCLKEY | FKEY | F(59):  /* page down key */
3013             sc_remove_cutmarking(scp);
3014             for (i=0; i<scp->ysize; i++)
3015             if (sc_hist_down_line(scp)) {
3016                 if (!(flags & SCGETC_CN))
3017                     sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3018                 break;
3019             }
3020             goto next_code;
3021         }
3022 #endif /* SC_NO_HISTORY */
3023     }
3024
3025     /* 
3026      * Process and consume special keys here.  Return a plain char code
3027      * or a char code with the META flag or a function key code.
3028      */
3029     if (c & RELKEY) {
3030         /* key released */
3031         /* goto next_code */
3032     } else {
3033         /* key pressed */
3034         if (c & SPCLKEY) {
3035             c &= ~SPCLKEY;
3036             switch (KEYCHAR(c)) {
3037             /* LOCKING KEYS */
3038             case NLK: case CLK: case ALK:
3039                 break;
3040             case SLK:
3041                 kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3042                 if (f & SLKED) {
3043                     scp->status |= SLKED;
3044                 } else {
3045                     if (scp->status & SLKED) {
3046                         scp->status &= ~SLKED;
3047 #ifndef SC_NO_HISTORY
3048                         if (scp->status & BUFFER_SAVED) {
3049                             if (!sc_hist_restore(scp))
3050                                 sc_remove_cutmarking(scp);
3051                             scp->status &= ~BUFFER_SAVED;
3052                             scp->status |= CURSOR_ENABLED;
3053                             sc_draw_cursor_image(scp);
3054                         }
3055                         tp = VIRTUAL_TTY(sc, scp->index);
3056                         if (ISTTYOPEN(tp))
3057                             scstart(tp);
3058 #endif
3059                     }
3060                 }
3061                 break;
3062
3063             /* NON-LOCKING KEYS */
3064             case NOP:
3065             case LSH:  case RSH:  case LCTR: case RCTR:
3066             case LALT: case RALT: case ASH:  case META:
3067                 break;
3068
3069             case BTAB:
3070                 if (!(sc->flags & SC_SCRN_BLANKED))
3071                     return c;
3072                 break;
3073
3074             case SPSC:
3075 #if NSPLASH > 0
3076                 /* force activatation/deactivation of the screen saver */
3077                 if (!(sc->flags & SC_SCRN_BLANKED)) {
3078                     run_scrn_saver = TRUE;
3079                     sc->scrn_time_stamp -= scrn_blank_time;
3080                 }
3081                 if (cold) {
3082                     /*
3083                      * While devices are being probed, the screen saver need
3084                      * to be invoked explictly. XXX
3085                      */
3086                     if (sc->flags & SC_SCRN_BLANKED) {
3087                         scsplash_stick(FALSE);
3088                         stop_scrn_saver(sc, current_saver);
3089                     } else {
3090                         if (!ISGRAPHSC(scp)) {
3091                             scsplash_stick(TRUE);
3092                             (*current_saver)(sc, TRUE);
3093                         }
3094                     }
3095                 }
3096 #endif /* NSPLASH */
3097                 break;
3098
3099             case RBT:
3100 #ifndef SC_DISABLE_REBOOT
3101                 shutdown_nice(0);
3102 #endif
3103                 break;
3104
3105             case HALT:
3106 #ifndef SC_DISABLE_REBOOT
3107                 shutdown_nice(RB_HALT);
3108 #endif
3109                 break;
3110
3111             case PDWN:
3112 #ifndef SC_DISABLE_REBOOT
3113                 shutdown_nice(RB_HALT|RB_POWEROFF);
3114 #endif
3115                 break;
3116
3117 #if NAPM > 0
3118             case SUSP:
3119                 apm_suspend(PMST_SUSPEND);
3120                 break;
3121             case STBY:
3122                 apm_suspend(PMST_STANDBY);
3123                 break;
3124 #else
3125             case SUSP:
3126             case STBY:
3127                 break;
3128 #endif
3129
3130             case DBG:
3131 #ifndef SC_DISABLE_DDBKEY
3132 #ifdef DDB
3133                 Debugger("manual escape to debugger");
3134 #else
3135                 kprintf("No debugger in kernel\n");
3136 #endif
3137 #else /* SC_DISABLE_DDBKEY */
3138                 /* do nothing */
3139 #endif /* SC_DISABLE_DDBKEY */
3140                 break;
3141
3142             case PNC:
3143                 if (enable_panic_key)
3144                         panic("Forced by the panic key");
3145                 break;
3146
3147             case NEXT:
3148                 this_scr = scp->index;
3149                 for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3150                         sc->first_vty + i != this_scr; 
3151                         i = (i + 1)%sc->vtys) {
3152                     struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3153                     if (ISTTYOPEN(tp)) {
3154                         sc_switch_scr(scp->sc, sc->first_vty + i);
3155                         break;
3156                     }
3157                 }
3158                 break;
3159
3160             case PREV:
3161                 this_scr = scp->index;
3162                 for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3163                         sc->first_vty + i != this_scr;
3164                         i = (i + sc->vtys - 1)%sc->vtys) {
3165                     struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3166                     if (ISTTYOPEN(tp)) {
3167                         sc_switch_scr(scp->sc, sc->first_vty + i);
3168                         break;
3169                     }
3170                 }
3171                 break;
3172
3173             default:
3174                 if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3175                     sc_switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3176                     break;
3177                 }
3178                 /* assert(c & FKEY) */
3179                 if (!(sc->flags & SC_SCRN_BLANKED))
3180                     return c;
3181                 break;
3182             }
3183             /* goto next_code */
3184         } else {
3185             /* regular keys (maybe MKEY is set) */
3186             if (!(sc->flags & SC_SCRN_BLANKED))
3187                 return c;
3188         }
3189     }
3190
3191     goto next_code;
3192 }
3193
3194 int
3195 scmmap(struct dev_mmap_args *ap)
3196 {
3197     scr_stat *scp;
3198
3199     scp = SC_STAT(ap->a_head.a_dev);
3200     if (scp != scp->sc->cur_scp)
3201         return EINVAL;
3202     ap->a_result = (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, ap->a_offset,
3203                                                     ap->a_nprot);
3204     return(0);
3205 }
3206
3207 static int
3208 save_kbd_state(scr_stat *scp)
3209 {
3210     int state;
3211     int error;
3212
3213     error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3214     if (error == ENOIOCTL)
3215         error = ENODEV;
3216     if (error == 0) {
3217         scp->status &= ~LOCK_MASK;
3218         scp->status |= state;
3219     }
3220     return error;
3221 }
3222
3223 static int
3224 update_kbd_state(scr_stat *scp, int new_bits, int mask)
3225 {
3226     int state;
3227     int error;
3228
3229     if (mask != LOCK_MASK) {
3230         error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3231         if (error == ENOIOCTL)
3232             error = ENODEV;
3233         if (error)
3234             return error;
3235         state &= ~mask;
3236         state |= new_bits & mask;
3237     } else {
3238         state = new_bits & LOCK_MASK;
3239     }
3240     error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3241     if (error == ENOIOCTL)
3242         error = ENODEV;
3243     return error;
3244 }
3245
3246 static int
3247 update_kbd_leds(scr_stat *scp, int which)
3248 {
3249     int error;
3250
3251     which &= LOCK_MASK;
3252     error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3253     if (error == ENOIOCTL)
3254         error = ENODEV;
3255     return error;
3256 }
3257
3258 int
3259 set_mode(scr_stat *scp)
3260 {
3261     video_info_t info;
3262
3263     /* reject unsupported mode */
3264     if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
3265         return 1;
3266
3267     /* if this vty is not currently showing, do nothing */
3268     if (scp != scp->sc->cur_scp)
3269         return 0;
3270
3271     /* setup video hardware for the given mode */
3272     (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3273     scp->rndr->init(scp);
3274     sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3275                 (void *)scp->sc->adp->va_window, FALSE);
3276
3277 #ifndef SC_NO_FONT_LOADING
3278     /* load appropriate font */
3279     if (!(scp->status & GRAPHICS_MODE)) {
3280         if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3281             if (scp->font_size < 14) {
3282                 if (scp->sc->fonts_loaded & FONT_8)
3283                     sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256);
3284             } else if (scp->font_size >= 16) {
3285                 if (scp->sc->fonts_loaded & FONT_16)
3286                     sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256);
3287             } else {
3288                 if (scp->sc->fonts_loaded & FONT_14)
3289                     sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256);
3290             }
3291             /*
3292              * FONT KLUDGE:
3293              * This is an interim kludge to display correct font.
3294              * Always use the font page #0 on the video plane 2.
3295              * Somehow we cannot show the font in other font pages on
3296              * some video cards... XXX
3297              */ 
3298             sc_show_font(scp, 0);
3299         }
3300         mark_all(scp);
3301     }
3302 #endif /* !SC_NO_FONT_LOADING */
3303
3304     sc_set_border(scp, scp->border);
3305     sc_set_cursor_image(scp);
3306
3307     return 0;
3308 }
3309
3310 void
3311 refresh_ega_palette(scr_stat *scp)
3312 {
3313     uint32_t r, g, b;
3314     int reg;
3315     int rsize, gsize, bsize;
3316     int rfld, gfld, bfld;
3317     int i;
3318
3319     rsize = scp->sc->adp->va_info.vi_pixel_fsizes[0];
3320     gsize = scp->sc->adp->va_info.vi_pixel_fsizes[1];
3321     bsize = scp->sc->adp->va_info.vi_pixel_fsizes[2];
3322     rfld = scp->sc->adp->va_info.vi_pixel_fields[0];
3323     gfld = scp->sc->adp->va_info.vi_pixel_fields[1];
3324     bfld = scp->sc->adp->va_info.vi_pixel_fields[2];
3325
3326     for (i = 0; i < 16; i++) {
3327         reg = scp->sc->adp->va_palette_regs[i];
3328
3329         r = scp->sc->palette[reg * 3] >> (8 - rsize);
3330         g = scp->sc->palette[reg * 3 + 1] >> (8 - gsize);
3331         b = scp->sc->palette[reg * 3 + 2] >> (8 - bsize);
3332
3333         scp->ega_palette[i] = (r << rfld) + (g << gfld) + (b << bfld);
3334     }
3335 }
3336
3337 void
3338 sc_set_border(scr_stat *scp, int color)
3339 {
3340     ++scp->sc->videoio_in_progress;
3341     (*scp->rndr->draw_border)(scp, color);
3342     --scp->sc->videoio_in_progress;
3343 }
3344
3345 #ifndef SC_NO_FONT_LOADING
3346 void
3347 sc_load_font(scr_stat *scp, int page, int size, u_char *buf,
3348              int base, int count)
3349 {
3350     sc_softc_t *sc;
3351
3352     sc = scp->sc;
3353     sc->font_loading_in_progress = TRUE;
3354     (*vidsw[sc->adapter]->load_font)(sc->adp, page, size, buf, base, count);
3355     sc->font_loading_in_progress = FALSE;
3356 }
3357
3358 void
3359 sc_save_font(scr_stat *scp, int page, int size, u_char *buf,
3360              int base, int count)
3361 {
3362     sc_softc_t *sc;
3363
3364     sc = scp->sc;
3365     sc->font_loading_in_progress = TRUE;
3366     (*vidsw[sc->adapter]->save_font)(sc->adp, page, size, buf, base, count);
3367     sc->font_loading_in_progress = FALSE;
3368 }
3369
3370 void
3371 sc_show_font(scr_stat *scp, int page)
3372 {
3373     (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, page);
3374 }
3375 #endif /* !SC_NO_FONT_LOADING */
3376
3377 void
3378 sc_paste(scr_stat *scp, u_char *p, int count) 
3379 {
3380     struct tty *tp;
3381     u_char *rmap;
3382
3383     if (scp->status & MOUSE_VISIBLE) {
3384         tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
3385         if (!ISTTYOPEN(tp))
3386             return;
3387         rmap = scp->sc->scr_rmap;
3388         for (; count > 0; --count)
3389             (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
3390     }
3391 }
3392
3393 void
3394 sc_bell(scr_stat *scp, int pitch, int duration)
3395 {
3396     if (cold || shutdown_in_progress)
3397         return;
3398
3399     if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL))
3400         return;
3401
3402     if (scp->sc->flags & SC_VISUAL_BELL) {
3403         if (scp->sc->blink_in_progress)
3404             return;
3405         scp->sc->blink_in_progress = 3;
3406         if (scp != scp->sc->cur_scp)
3407             scp->sc->blink_in_progress += 2;
3408         blink_screen(scp->sc->cur_scp);
3409     } else if (duration != 0 && pitch != 0) {
3410         if (scp != scp->sc->cur_scp)
3411             pitch *= 2;
3412         sysbeep(pitch, duration);
3413     }
3414 }
3415
3416 static void
3417 blink_screen(void *arg)
3418 {
3419     scr_stat *scp = arg;
3420     struct tty *tp;
3421
3422     if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
3423         scp->sc->blink_in_progress = 0;
3424         mark_all(scp);
3425         tp = VIRTUAL_TTY(scp->sc, scp->index);
3426         if (ISTTYOPEN(tp))
3427             scstart(tp);
3428         if (scp->sc->delayed_next_scr)
3429             sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3430     }
3431     else {
3432         (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize, 
3433                            scp->sc->blink_in_progress & 1);
3434         scp->sc->blink_in_progress--;
3435         callout_reset(&scp->blink_screen_ch, hz / 10, blink_screen, scp);
3436     }
3437 }