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