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