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