syscons.c revision 197109
1215166Slstewart/*- 2215166Slstewart * Copyright (c) 1992-1998 S�ren Schmidt 3215166Slstewart * All rights reserved. 4215166Slstewart * 5215166Slstewart * This code is derived from software contributed to The DragonFly Project 6215166Slstewart * by Sascha Wildner <saw@online.de> 7215166Slstewart * 8215166Slstewart * Redistribution and use in source and binary forms, with or without 9220560Slstewart * modification, are permitted provided that the following conditions 10220560Slstewart * are met: 11220560Slstewart * 1. Redistributions of source code must retain the above copyright 12215166Slstewart * notice, this list of conditions and the following disclaimer, 13215166Slstewart * without modification, immediately at the beginning of the file. 14215166Slstewart * 2. Redistributions in binary form must reproduce the above copyright 15215166Slstewart * notice, this list of conditions and the following disclaimer in the 16215166Slstewart * documentation and/or other materials provided with the distribution. 17215166Slstewart * 3. The name of the author may not be used to endorse or promote products 18215166Slstewart * derived from this software without specific prior written permission. 19215166Slstewart * 20215166Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21215166Slstewart * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22215166Slstewart * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23215166Slstewart * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24215166Slstewart * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25215166Slstewart * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26215166Slstewart * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27215166Slstewart * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28215166Slstewart * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29215166Slstewart * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30215166Slstewart */ 31215166Slstewart 32215166Slstewart#include <sys/cdefs.h> 33215166Slstewart__FBSDID("$FreeBSD: head/sys/dev/syscons/syscons.c 197109 2009-09-12 00:12:47Z delphij $"); 34215166Slstewart 35215166Slstewart#include "opt_compat.h" 36215166Slstewart#include "opt_syscons.h" 37215166Slstewart#include "opt_splash.h" 38215166Slstewart#include "opt_ddb.h" 39215166Slstewart 40215166Slstewart#include <sys/param.h> 41220560Slstewart#include <sys/systm.h> 42220560Slstewart#include <sys/bus.h> 43220560Slstewart#include <sys/conf.h> 44220560Slstewart#include <sys/cons.h> 45220560Slstewart#include <sys/consio.h> 46215166Slstewart#include <sys/kdb.h> 47215166Slstewart#include <sys/eventhandler.h> 48215166Slstewart#include <sys/fbio.h> 49215166Slstewart#include <sys/kbio.h> 50215166Slstewart#include <sys/kernel.h> 51215166Slstewart#include <sys/lock.h> 52215166Slstewart#include <sys/malloc.h> 53215166Slstewart#include <sys/mutex.h> 54215166Slstewart#include <sys/priv.h> 55215166Slstewart#include <sys/proc.h> 56215166Slstewart#include <sys/random.h> 57215166Slstewart#include <sys/reboot.h> 58215166Slstewart#include <sys/serial.h> 59215166Slstewart#include <sys/signalvar.h> 60215166Slstewart#include <sys/sysctl.h> 61215166Slstewart#include <sys/tty.h> 62215166Slstewart#include <sys/power.h> 63215166Slstewart 64215166Slstewart#include <machine/clock.h> 65215166Slstewart#if defined(__sparc64__) || defined(__powerpc__) 66215166Slstewart#include <machine/sc_machdep.h> 67215166Slstewart#else 68215166Slstewart#include <machine/pc/display.h> 69215166Slstewart#endif 70215166Slstewart#if defined( __i386__) || defined(__amd64__) 71215166Slstewart#include <machine/psl.h> 72215166Slstewart#include <machine/frame.h> 73215166Slstewart#endif 74215166Slstewart#include <machine/stdarg.h> 75215166Slstewart 76215166Slstewart#include <dev/kbd/kbdreg.h> 77215166Slstewart#include <dev/fb/fbreg.h> 78215166Slstewart#include <dev/fb/splashreg.h> 79215166Slstewart#include <dev/syscons/syscons.h> 80215166Slstewart 81215166Slstewart#define COLD 0 82215166Slstewart#define WARM 1 83215166Slstewart 84215166Slstewart#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */ 85215395Slstewart#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */ 86215166Slstewart 87215166Slstewart#define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */ 88215166Slstewart 89215166Slstewarttypedef struct default_attr { 90215166Slstewart int std_color; /* normal hardware color */ 91215166Slstewart int rev_color; /* reverse hardware color */ 92215166Slstewart} default_attr; 93215393Slstewart 94215166Slstewartstatic default_attr user_default = { 95215166Slstewart SC_NORM_ATTR, 96215166Slstewart SC_NORM_REV_ATTR, 97215166Slstewart}; 98215166Slstewart 99215166Slstewartstatic int sc_console_unit = -1; 100215166Slstewartstatic int sc_saver_keyb_only = 1; 101215166Slstewartstatic scr_stat *sc_console; 102215166Slstewartstatic struct consdev *sc_consptr; 103215166Slstewartstatic scr_stat main_console; 104215166Slstewartstatic struct tty *main_devs[MAXCONS]; 105215166Slstewart 106215166Slstewartstatic char init_done = COLD; 107215395Slstewartstatic char shutdown_in_progress = FALSE; 108215166Slstewartstatic char sc_malloc = FALSE; 109215166Slstewart 110215166Slstewartstatic int saver_mode = CONS_NO_SAVER; /* LKM/user saver */ 111215166Slstewartstatic int run_scrn_saver = FALSE; /* should run the saver? */ 112215395Slstewartstatic int enable_bell = TRUE; /* enable beeper */ 113215166Slstewart 114215166Slstewart#ifndef SC_DISABLE_REBOOT 115215395Slstewartstatic int enable_reboot = TRUE; /* enable keyboard reboot */ 116215166Slstewart#endif 117215166Slstewart 118215166Slstewart#ifndef SC_DISABLE_KDBKEY 119215166Slstewartstatic int enable_kdbkey = TRUE; /* enable keyboard debug */ 120215166Slstewart#endif 121215166Slstewart 122215166Slstewartstatic long scrn_blank_time = 0; /* screen saver timeout value */ 123215166Slstewart#ifdef DEV_SPLASH 124215166Slstewartstatic int scrn_blanked; /* # of blanked screen */ 125215166Slstewartstatic int sticky_splash = FALSE; 126215166Slstewart 127215166Slstewartstatic void none_saver(sc_softc_t *sc, int blank) { } 128215166Slstewartstatic void (*current_saver)(sc_softc_t *, int) = none_saver; 129215166Slstewart#endif 130215166Slstewart 131215166SlstewartSYSCTL_NODE(_hw, OID_AUTO, syscons, CTLFLAG_RD, 0, "syscons"); 132217748SlstewartSYSCTL_NODE(_hw_syscons, OID_AUTO, saver, CTLFLAG_RD, 0, "saver"); 133215166SlstewartSYSCTL_INT(_hw_syscons_saver, OID_AUTO, keybonly, CTLFLAG_RW, 134217748Slstewart &sc_saver_keyb_only, 0, "screen saver interrupted by input only"); 135215166SlstewartSYSCTL_INT(_hw_syscons, OID_AUTO, bell, CTLFLAG_RW, &enable_bell, 136215166Slstewart 0, "enable bell"); 137217748Slstewart#ifndef SC_DISABLE_REBOOT 138217748SlstewartSYSCTL_INT(_hw_syscons, OID_AUTO, kbd_reboot, CTLFLAG_RW|CTLFLAG_SECURE, &enable_reboot, 139217748Slstewart 0, "enable keyboard reboot"); 140217748Slstewart#endif 141217748Slstewart#ifndef SC_DISABLE_KDBKEY 142217748SlstewartSYSCTL_INT(_hw_syscons, OID_AUTO, kbd_debug, CTLFLAG_RW|CTLFLAG_SECURE, &enable_kdbkey, 143217748Slstewart 0, "enable keyboard debug"); 144217748Slstewart#endif 145215166Slstewart#if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT) 146215166Slstewart#include "font.h" 147215166Slstewart#endif 148217748Slstewart 149217748Slstewart tsw_ioctl_t *sc_user_ioctl; 150217748Slstewart 151217748Slstewartstatic bios_values_t bios_value; 152217748Slstewart 153217748Slstewartstatic int enable_panic_key; 154217748SlstewartSYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key, 155215166Slstewart 0, "Enable panic via keypress specified in kbdmap(5)"); 156215166Slstewart 157215166Slstewart#define SC_CONSOLECTL 255 158217748Slstewart 159217748Slstewart#define VTY_WCHAN(sc, vty) (&SC_DEV(sc, vty)) 160217748Slstewart 161215166Slstewartstatic int debugger; 162217748Slstewart 163215166Slstewart/* prototypes */ 164215166Slstewartstatic int sc_allocate_keyboard(sc_softc_t *sc, int unit); 165215166Slstewartstatic int scvidprobe(int unit, int flags, int cons); 166215166Slstewartstatic int sckbdprobe(int unit, int flags, int cons); 167215166Slstewartstatic void scmeminit(void *arg); 168215166Slstewartstatic int scdevtounit(struct tty *tp); 169215166Slstewartstatic kbd_callback_func_t sckbdevent; 170215166Slstewartstatic void scinit(int unit, int flags); 171215166Slstewartstatic scr_stat *sc_get_stat(struct tty *tp); 172215166Slstewartstatic void scterm(int unit, int flags); 173215166Slstewartstatic void scshutdown(void *arg, int howto); 174215166Slstewartstatic u_int scgetc(sc_softc_t *sc, u_int flags); 175215166Slstewart#define SCGETC_CN 1 176215166Slstewart#define SCGETC_NONBLOCK 2 177215395Slstewartstatic void sccnupdate(scr_stat *scp); 178215395Slstewartstatic scr_stat *alloc_scp(sc_softc_t *sc, int vty); 179215395Slstewartstatic void init_scp(sc_softc_t *sc, int vty, scr_stat *scp); 180215395Slstewartstatic timeout_t scrn_timer; 181215395Slstewartstatic int and_region(int *s1, int *e1, int s2, int e2); 182215395Slstewartstatic void scrn_update(scr_stat *scp, int show_cursor); 183215395Slstewart 184215395Slstewart#ifdef DEV_SPLASH 185215395Slstewartstatic int scsplash_callback(int event, void *arg); 186215395Slstewartstatic void scsplash_saver(sc_softc_t *sc, int show); 187215395Slstewartstatic int add_scrn_saver(void (*this_saver)(sc_softc_t *, int)); 188215395Slstewartstatic int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int)); 189215395Slstewartstatic int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border); 190215395Slstewartstatic int restore_scrn_saver_mode(scr_stat *scp, int changemode); 191215395Slstewartstatic void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int)); 192215395Slstewartstatic int wait_scrn_saver_stop(sc_softc_t *sc); 193215395Slstewart#define scsplash_stick(stick) (sticky_splash = (stick)) 194215395Slstewart#else /* !DEV_SPLASH */ 195215395Slstewart#define scsplash_stick(stick) 196215395Slstewart#endif /* DEV_SPLASH */ 197215395Slstewart 198215395Slstewartstatic int do_switch_scr(sc_softc_t *sc, int s); 199215166Slstewartstatic int vt_proc_alive(scr_stat *scp); 200215166Slstewartstatic int signal_vt_rel(scr_stat *scp); 201215377Slstewartstatic int signal_vt_acq(scr_stat *scp); 202215377Slstewartstatic int finish_vt_rel(scr_stat *scp, int release, int *s); 203215166Slstewartstatic int finish_vt_acq(scr_stat *scp); 204215166Slstewartstatic void exchange_scr(sc_softc_t *sc); 205215166Slstewartstatic void update_cursor_image(scr_stat *scp); 206215166Slstewartstatic void change_cursor_shape(scr_stat *scp, int flags, int base, int height); 207215166Slstewartstatic int save_kbd_state(scr_stat *scp); 208215166Slstewartstatic int update_kbd_state(scr_stat *scp, int state, int mask); 209215166Slstewartstatic int update_kbd_leds(scr_stat *scp, int which); 210215166Slstewartstatic timeout_t blink_screen; 211215166Slstewartstatic struct tty *sc_alloc_tty(int, int); 212215166Slstewart 213215166Slstewartstatic cn_probe_t sc_cnprobe; 214215166Slstewartstatic cn_init_t sc_cninit; 215215166Slstewartstatic cn_term_t sc_cnterm; 216215166Slstewartstatic cn_getc_t sc_cngetc; 217215166Slstewartstatic cn_putc_t sc_cnputc; 218215166Slstewart 219215166SlstewartCONSOLE_DRIVER(sc); 220215166Slstewart 221215166Slstewartstatic tsw_open_t sctty_open; 222215166Slstewartstatic tsw_close_t sctty_close; 223215166Slstewartstatic tsw_outwakeup_t sctty_outwakeup; 224215166Slstewartstatic tsw_ioctl_t sctty_ioctl; 225215166Slstewartstatic tsw_mmap_t sctty_mmap; 226215166Slstewart 227215395Slstewartstatic struct ttydevsw sc_ttydevsw = { 228215166Slstewart .tsw_open = sctty_open, 229215166Slstewart .tsw_close = sctty_close, 230215166Slstewart .tsw_outwakeup = sctty_outwakeup, 231215166Slstewart .tsw_ioctl = sctty_ioctl, 232215166Slstewart .tsw_mmap = sctty_mmap, 233215166Slstewart}; 234215393Slstewart 235215392Slstewartstatic d_ioctl_t consolectl_ioctl; 236215166Slstewart 237215392Slstewartstatic struct cdevsw consolectl_devsw = { 238215392Slstewart .d_version = D_VERSION, 239215392Slstewart .d_flags = D_NEEDGIANT, 240215392Slstewart .d_ioctl = consolectl_ioctl, 241215166Slstewart .d_name = "consolectl", 242215392Slstewart}; 243215166Slstewart 244215166Slstewartint 245215166Slstewartsc_probe_unit(int unit, int flags) 246215166Slstewart{ 247215166Slstewart if (!scvidprobe(unit, flags, FALSE)) { 248215166Slstewart if (bootverbose) 249215166Slstewart printf("%s%d: no video adapter found.\n", SC_DRIVER_NAME, unit); 250215166Slstewart return ENXIO; 251215166Slstewart } 252215166Slstewart 253215166Slstewart /* syscons will be attached even when there is no keyboard */ 254215166Slstewart sckbdprobe(unit, flags, FALSE); 255215166Slstewart 256215166Slstewart return 0; 257215166Slstewart} 258215166Slstewart 259215166Slstewart/* probe video adapters, return TRUE if found */ 260215166Slstewartstatic int 261215166Slstewartscvidprobe(int unit, int flags, int cons) 262215166Slstewart{ 263215166Slstewart /* 264215166Slstewart * Access the video adapter driver through the back door! 265215166Slstewart * Video adapter drivers need to be configured before syscons. 266215166Slstewart * However, when syscons is being probed as the low-level console, 267215166Slstewart * they have not been initialized yet. We force them to initialize 268215166Slstewart * themselves here. XXX 269215166Slstewart */ 270215166Slstewart vid_configure(cons ? VIO_PROBE_ONLY : 0); 271215166Slstewart 272215166Slstewart return (vid_find_adapter("*", unit) >= 0); 273215166Slstewart} 274215166Slstewart 275215166Slstewart/* probe the keyboard, return TRUE if found */ 276215166Slstewartstatic int 277215166Slstewartsckbdprobe(int unit, int flags, int cons) 278215166Slstewart{ 279215166Slstewart /* access the keyboard driver through the backdoor! */ 280215166Slstewart kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0); 281215166Slstewart 282215166Slstewart return (kbd_find_keyboard("*", unit) >= 0); 283215166Slstewart} 284215166Slstewart 285215166Slstewartstatic char 286215166Slstewart*adapter_name(video_adapter_t *adp) 287215166Slstewart{ 288215166Slstewart static struct { 289215166Slstewart int type; 290215166Slstewart char *name[2]; 291215166Slstewart } names[] = { 292215166Slstewart { KD_MONO, { "MDA", "MDA" } }, 293215166Slstewart { KD_HERCULES, { "Hercules", "Hercules" } }, 294215166Slstewart { KD_CGA, { "CGA", "CGA" } }, 295215166Slstewart { KD_EGA, { "EGA", "EGA (mono)" } }, 296215166Slstewart { KD_VGA, { "VGA", "VGA (mono)" } }, 297215166Slstewart { KD_PC98, { "PC-98x1", "PC-98x1" } }, 298215166Slstewart { KD_TGA, { "TGA", "TGA" } }, 299215166Slstewart { -1, { "Unknown", "Unknown" } }, 300215166Slstewart }; 301215166Slstewart int i; 302215166Slstewart 303215166Slstewart for (i = 0; names[i].type != -1; ++i) 304215166Slstewart if (names[i].type == adp->va_type) 305215166Slstewart break; 306215166Slstewart return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1]; 307215166Slstewart} 308215166Slstewart 309215166Slstewartstatic void 310215166Slstewartsctty_outwakeup(struct tty *tp) 311215166Slstewart{ 312215166Slstewart size_t len; 313215166Slstewart u_char buf[PCBURST]; 314215166Slstewart scr_stat *scp = sc_get_stat(tp); 315215377Slstewart 316215377Slstewart if (scp->status & SLKED || 317215166Slstewart (scp == scp->sc->cur_scp && scp->sc->blink_in_progress)) 318215166Slstewart return; 319215166Slstewart 320215166Slstewart for (;;) { 321215395Slstewart len = ttydisc_getc(tp, buf, sizeof buf); 322215166Slstewart if (len == 0) 323215166Slstewart break; 324215166Slstewart sc_puts(scp, buf, len, 0); 325215166Slstewart } 326215166Slstewart} 327 328static struct tty * 329sc_alloc_tty(int index, int devnum) 330{ 331 struct sc_ttysoftc *stc; 332 struct tty *tp; 333 334 /* Allocate TTY object and softc to store unit number. */ 335 stc = malloc(sizeof(struct sc_ttysoftc), M_DEVBUF, M_WAITOK); 336 stc->st_index = index; 337 stc->st_stat = NULL; 338 tp = tty_alloc_mutex(&sc_ttydevsw, stc, &Giant); 339 340 /* Create device node. */ 341 tty_makedev(tp, NULL, "v%r", devnum); 342 343 return (tp); 344} 345 346int 347sc_attach_unit(int unit, int flags) 348{ 349 sc_softc_t *sc; 350 scr_stat *scp; 351#ifdef SC_PIXEL_MODE 352 video_info_t info; 353#endif 354 int vc; 355 struct cdev *dev; 356 unsigned int vmode = 0; 357 358 flags &= ~SC_KERNEL_CONSOLE; 359 360 if (sc_console_unit == unit) { 361 /* 362 * If this unit is being used as the system console, we need to 363 * adjust some variables and buffers before and after scinit(). 364 */ 365 /* assert(sc_console != NULL) */ 366 flags |= SC_KERNEL_CONSOLE; 367 scmeminit(NULL); 368 } 369 scinit(unit, flags); 370 371 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); 372 sc->config = flags; 373 scp = sc_get_stat(sc->dev[0]); 374 if (sc_console == NULL) /* sc_console_unit < 0 */ 375 sc_console = scp; 376 377 (void)resource_int_value("sc", unit, "vesa_mode", &vmode); 378 if (vmode < M_VESA_BASE || vmode > M_VESA_MODE_MAX) 379 vmode = M_VESA_FULL_800; 380 381#ifdef SC_PIXEL_MODE 382 if ((sc->config & SC_VESAMODE) 383 && (vidd_get_info(sc->adp, vmode, &info) == 0)) { 384#ifdef DEV_SPLASH 385 if (sc->flags & SC_SPLASH_SCRN) 386 splash_term(sc->adp); 387#endif 388 sc_set_graphics_mode(scp, NULL, vmode); 389 sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8); 390 sc->initial_mode = vmode; 391#ifdef DEV_SPLASH 392 /* put up the splash again! */ 393 if (sc->flags & SC_SPLASH_SCRN) 394 splash_init(sc->adp, scsplash_callback, sc); 395#endif 396 } 397#endif /* SC_PIXEL_MODE */ 398 399 /* initialize cursor */ 400 if (!ISGRAPHSC(scp)) 401 update_cursor_image(scp); 402 403 /* get screen update going */ 404 scrn_timer(sc); 405 406 /* set up the keyboard */ 407 kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); 408 update_kbd_state(scp, scp->status, LOCK_MASK); 409 410 printf("%s%d: %s <%d virtual consoles, flags=0x%x>\n", 411 SC_DRIVER_NAME, unit, adapter_name(sc->adp), sc->vtys, sc->config); 412 if (bootverbose) { 413 printf("%s%d:", SC_DRIVER_NAME, unit); 414 if (sc->adapter >= 0) 415 printf(" fb%d", sc->adapter); 416 if (sc->keyboard >= 0) 417 printf(", kbd%d", sc->keyboard); 418 if (scp->tsw) 419 printf(", terminal emulator: %s (%s)", 420 scp->tsw->te_name, scp->tsw->te_desc); 421 printf("\n"); 422 } 423 424 /* register a shutdown callback for the kernel console */ 425 if (sc_console_unit == unit) 426 EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown, 427 (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT); 428 429 for (vc = 0; vc < sc->vtys; vc++) { 430 if (sc->dev[vc] == NULL) { 431 sc->dev[vc] = sc_alloc_tty(vc, vc + unit * MAXCONS); 432 if (vc == 0 && sc->dev == main_devs) 433 SC_STAT(sc->dev[0]) = &main_console; 434 } 435 /* 436 * The first vty already has struct tty and scr_stat initialized 437 * in scinit(). The other vtys will have these structs when 438 * first opened. 439 */ 440 } 441 442 dev = make_dev(&consolectl_devsw, 0, UID_ROOT, GID_WHEEL, 0600, 443 "consolectl"); 444 dev->si_drv1 = sc->dev[0]; 445 446 return 0; 447} 448 449static void 450scmeminit(void *arg) 451{ 452 if (sc_malloc) 453 return; 454 sc_malloc = TRUE; 455 456 /* 457 * As soon as malloc() becomes functional, we had better allocate 458 * various buffers for the kernel console. 459 */ 460 461 if (sc_console_unit < 0) /* sc_console == NULL */ 462 return; 463 464 /* copy the temporary buffer to the final buffer */ 465 sc_alloc_scr_buffer(sc_console, FALSE, FALSE); 466 467#ifndef SC_NO_CUTPASTE 468 sc_alloc_cut_buffer(sc_console, FALSE); 469#endif 470 471#ifndef SC_NO_HISTORY 472 /* initialize history buffer & pointers */ 473 sc_alloc_history_buffer(sc_console, 0, 0, FALSE); 474#endif 475} 476 477/* XXX */ 478SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL); 479 480static int 481scdevtounit(struct tty *tp) 482{ 483 int vty = SC_VTY(tp); 484 485 if (vty == SC_CONSOLECTL) 486 return ((sc_console != NULL) ? sc_console->sc->unit : -1); 487 else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit())) 488 return -1; 489 else 490 return vty/MAXCONS; 491} 492 493static int 494sctty_open(struct tty *tp) 495{ 496 int unit = scdevtounit(tp); 497 sc_softc_t *sc; 498 scr_stat *scp; 499#ifndef __sparc64__ 500 keyarg_t key; 501#endif 502 503 DPRINTF(5, ("scopen: dev:%s, unit:%d, vty:%d\n", 504 devtoname(tp->t_dev), unit, SC_VTY(tp))); 505 506 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0); 507 if (sc == NULL) 508 return ENXIO; 509 510 if (!tty_opened(tp)) { 511 /* Use the current setting of the <-- key as default VERASE. */ 512 /* If the Delete key is preferable, an stty is necessary */ 513#ifndef __sparc64__ 514 if (sc->kbd != NULL) { 515 key.keynum = KEYCODE_BS; 516 kbdd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key); 517 tp->t_termios.c_cc[VERASE] = key.key.map[0]; 518 } 519#endif 520 } 521 522 scp = sc_get_stat(tp); 523 if (scp == NULL) { 524 scp = SC_STAT(tp) = alloc_scp(sc, SC_VTY(tp)); 525 if (ISGRAPHSC(scp)) 526 sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8); 527 } 528 if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) { 529 tp->t_winsize.ws_col = scp->xsize; 530 tp->t_winsize.ws_row = scp->ysize; 531 } 532 533 return (0); 534} 535 536static void 537sctty_close(struct tty *tp) 538{ 539 scr_stat *scp; 540 int s; 541 542 if (SC_VTY(tp) != SC_CONSOLECTL) { 543 scp = sc_get_stat(tp); 544 /* were we in the middle of the VT switching process? */ 545 DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit)); 546 s = spltty(); 547 if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit)) 548 cnavailable(sc_consptr, TRUE); 549 if (finish_vt_rel(scp, TRUE, &s) == 0) /* force release */ 550 DPRINTF(5, ("reset WAIT_REL, ")); 551 if (finish_vt_acq(scp) == 0) /* force acknowledge */ 552 DPRINTF(5, ("reset WAIT_ACQ, ")); 553#ifdef not_yet_done 554 if (scp == &main_console) { 555 scp->pid = 0; 556 scp->proc = NULL; 557 scp->smode.mode = VT_AUTO; 558 } 559 else { 560 sc_vtb_destroy(&scp->vtb); 561#ifndef __sparc64__ 562 sc_vtb_destroy(&scp->scr); 563#endif 564 sc_free_history_buffer(scp, scp->ysize); 565 SC_STAT(tp) = NULL; 566 free(scp, M_DEVBUF); 567 } 568#else 569 scp->pid = 0; 570 scp->proc = NULL; 571 scp->smode.mode = VT_AUTO; 572#endif 573 scp->kbd_mode = K_XLATE; 574 if (scp == scp->sc->cur_scp) 575 kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); 576 DPRINTF(5, ("done.\n")); 577 } 578} 579 580#if 0 /* XXX mpsafetty: fix screensaver. What about outwakeup? */ 581static int 582scread(struct cdev *dev, struct uio *uio, int flag) 583{ 584 if (!sc_saver_keyb_only) 585 sc_touch_scrn_saver(); 586 return ttyread(dev, uio, flag); 587} 588#endif 589 590static int 591sckbdevent(keyboard_t *thiskbd, int event, void *arg) 592{ 593 sc_softc_t *sc; 594 struct tty *cur_tty; 595 int c, error = 0; 596 size_t len; 597 u_char *cp; 598 599 sc = (sc_softc_t *)arg; 600 /* assert(thiskbd == sc->kbd) */ 601 602 mtx_lock(&Giant); 603 604 switch (event) { 605 case KBDIO_KEYINPUT: 606 break; 607 case KBDIO_UNLOADING: 608 sc->kbd = NULL; 609 sc->keyboard = -1; 610 kbd_release(thiskbd, (void *)&sc->keyboard); 611 goto done; 612 default: 613 error = EINVAL; 614 goto done; 615 } 616 617 /* 618 * Loop while there is still input to get from the keyboard. 619 * I don't think this is nessesary, and it doesn't fix 620 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX 621 */ 622 while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) { 623 624 cur_tty = SC_DEV(sc, sc->cur_scp->index); 625 if (!tty_opened(cur_tty)) 626 continue; 627 628 if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty)) 629 continue; 630 631 switch (KEYFLAGS(c)) { 632 case 0x0000: /* normal key */ 633 ttydisc_rint(cur_tty, KEYCHAR(c), 0); 634 break; 635 case FKEY: /* function key, return string */ 636 cp = kbdd_get_fkeystr(thiskbd, KEYCHAR(c), &len); 637 if (cp != NULL) { 638 if (ttydisc_can_bypass(cur_tty)) { 639 ttydisc_rint_bypass(cur_tty, cp, len); 640 } else { 641 while (len-- > 0) 642 ttydisc_rint(cur_tty, *cp++, 0); 643 } 644 } 645 break; 646 case MKEY: /* meta is active, prepend ESC */ 647 ttydisc_rint(cur_tty, 0x1b, 0); 648 ttydisc_rint(cur_tty, KEYCHAR(c), 0); 649 break; 650 case BKEY: /* backtab fixed sequence (esc [ Z) */ 651 ttydisc_rint(cur_tty, 0x1b, 0); 652 ttydisc_rint(cur_tty, '[', 0); 653 ttydisc_rint(cur_tty, 'Z', 0); 654 break; 655 } 656 657 ttydisc_rint_done(cur_tty); 658 } 659 660 sc->cur_scp->status |= MOUSE_HIDDEN; 661 662done: 663 mtx_unlock(&Giant); 664 return (error); 665} 666 667static int 668sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 669{ 670 int error; 671 int i; 672 sc_softc_t *sc; 673 scr_stat *scp; 674 int s; 675#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 676 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 677 int ival; 678#endif 679 680 /* If there is a user_ioctl function call that first */ 681 if (sc_user_ioctl) { 682 error = (*sc_user_ioctl)(tp, cmd, data, td); 683 if (error != ENOIOCTL) 684 return error; 685 } 686 687 error = sc_vid_ioctl(tp, cmd, data, td); 688 if (error != ENOIOCTL) 689 return error; 690 691#ifndef SC_NO_HISTORY 692 error = sc_hist_ioctl(tp, cmd, data, td); 693 if (error != ENOIOCTL) 694 return error; 695#endif 696 697#ifndef SC_NO_SYSMOUSE 698 error = sc_mouse_ioctl(tp, cmd, data, td); 699 if (error != ENOIOCTL) 700 return error; 701#endif 702 703 scp = sc_get_stat(tp); 704 /* assert(scp != NULL) */ 705 /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */ 706 sc = scp->sc; 707 708 if (scp->tsw) { 709 error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, td); 710 if (error != ENOIOCTL) 711 return error; 712 } 713 714 switch (cmd) { /* process console hardware related ioctl's */ 715 716 case GIO_ATTR: /* get current attributes */ 717 /* this ioctl is not processed here, but in the terminal emulator */ 718 return ENOTTY; 719 720 case GIO_COLOR: /* is this a color console ? */ 721 *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0; 722 return 0; 723 724 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ 725 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME) 726 return EINVAL; 727 s = spltty(); 728 scrn_blank_time = *(int *)data; 729 run_scrn_saver = (scrn_blank_time != 0); 730 splx(s); 731 return 0; 732 733 case CONS_CURSORTYPE: /* set cursor type (obsolete) */ 734 s = spltty(); 735 *(int *)data &= CONS_CURSOR_ATTRS; 736 sc_change_cursor_shape(scp, *(int *)data, -1, -1); 737 splx(s); 738 return 0; 739 740 case CONS_GETCURSORSHAPE: /* get cursor shape (new interface) */ 741 if (((int *)data)[0] & CONS_LOCAL_CURSOR) { 742 ((int *)data)[0] = scp->curr_curs_attr.flags; 743 ((int *)data)[1] = scp->curr_curs_attr.base; 744 ((int *)data)[2] = scp->curr_curs_attr.height; 745 } else { 746 ((int *)data)[0] = sc->curs_attr.flags; 747 ((int *)data)[1] = sc->curs_attr.base; 748 ((int *)data)[2] = sc->curs_attr.height; 749 } 750 return 0; 751 752 case CONS_SETCURSORSHAPE: /* set cursor shape (new interface) */ 753 s = spltty(); 754 sc_change_cursor_shape(scp, ((int *)data)[0], 755 ((int *)data)[1], ((int *)data)[2]); 756 splx(s); 757 return 0; 758 759 case CONS_BELLTYPE: /* set bell type sound/visual */ 760 if ((*(int *)data) & CONS_VISUAL_BELL) 761 sc->flags |= SC_VISUAL_BELL; 762 else 763 sc->flags &= ~SC_VISUAL_BELL; 764 if ((*(int *)data) & CONS_QUIET_BELL) 765 sc->flags |= SC_QUIET_BELL; 766 else 767 sc->flags &= ~SC_QUIET_BELL; 768 return 0; 769 770 case CONS_GETINFO: /* get current (virtual) console info */ 771 { 772 vid_info_t *ptr = (vid_info_t*)data; 773 if (ptr->size == sizeof(struct vid_info)) { 774 ptr->m_num = sc->cur_scp->index; 775 ptr->font_size = scp->font_size; 776 ptr->mv_col = scp->xpos; 777 ptr->mv_row = scp->ypos; 778 ptr->mv_csz = scp->xsize; 779 ptr->mv_rsz = scp->ysize; 780 ptr->mv_hsz = (scp->history != NULL) ? scp->history->vtb_rows : 0; 781 /* 782 * The following fields are filled by the terminal emulator. XXX 783 * 784 * ptr->mv_norm.fore 785 * ptr->mv_norm.back 786 * ptr->mv_rev.fore 787 * ptr->mv_rev.back 788 */ 789 ptr->mv_grfc.fore = 0; /* not supported */ 790 ptr->mv_grfc.back = 0; /* not supported */ 791 ptr->mv_ovscan = scp->border; 792 if (scp == sc->cur_scp) 793 save_kbd_state(scp); 794 ptr->mk_keylock = scp->status & LOCK_MASK; 795 return 0; 796 } 797 return EINVAL; 798 } 799 800 case CONS_GETVERS: /* get version number */ 801 *(int*)data = 0x200; /* version 2.0 */ 802 return 0; 803 804 case CONS_IDLE: /* see if the screen has been idle */ 805 /* 806 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE, 807 * the user process may have been writing something on the 808 * screen and syscons is not aware of it. Declare the screen 809 * is NOT idle if it is in one of these modes. But there is 810 * an exception to it; if a screen saver is running in the 811 * graphics mode in the current screen, we should say that the 812 * screen has been idle. 813 */ 814 *(int *)data = (sc->flags & SC_SCRN_IDLE) 815 && (!ISGRAPHSC(sc->cur_scp) 816 || (sc->cur_scp->status & SAVER_RUNNING)); 817 return 0; 818 819 case CONS_SAVERMODE: /* set saver mode */ 820 switch(*(int *)data) { 821 case CONS_NO_SAVER: 822 case CONS_USR_SAVER: 823 /* if a LKM screen saver is running, stop it first. */ 824 scsplash_stick(FALSE); 825 saver_mode = *(int *)data; 826 s = spltty(); 827#ifdef DEV_SPLASH 828 if ((error = wait_scrn_saver_stop(NULL))) { 829 splx(s); 830 return error; 831 } 832#endif 833 run_scrn_saver = TRUE; 834 if (saver_mode == CONS_USR_SAVER) 835 scp->status |= SAVER_RUNNING; 836 else 837 scp->status &= ~SAVER_RUNNING; 838 scsplash_stick(TRUE); 839 splx(s); 840 break; 841 case CONS_LKM_SAVER: 842 s = spltty(); 843 if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING)) 844 scp->status &= ~SAVER_RUNNING; 845 saver_mode = *(int *)data; 846 splx(s); 847 break; 848 default: 849 return EINVAL; 850 } 851 return 0; 852 853 case CONS_SAVERSTART: /* immediately start/stop the screen saver */ 854 /* 855 * Note that this ioctl does not guarantee the screen saver 856 * actually starts or stops. It merely attempts to do so... 857 */ 858 s = spltty(); 859 run_scrn_saver = (*(int *)data != 0); 860 if (run_scrn_saver) 861 sc->scrn_time_stamp -= scrn_blank_time; 862 splx(s); 863 return 0; 864 865 case CONS_SCRSHOT: /* get a screen shot */ 866 { 867 int retval, hist_rsz; 868 size_t lsize, csize; 869 vm_offset_t frbp, hstp; 870 unsigned lnum; 871 scrshot_t *ptr = (scrshot_t *)data; 872 void *outp = ptr->buf; 873 874 if (ptr->x < 0 || ptr->y < 0 || ptr->xsize < 0 || ptr->ysize < 0) 875 return EINVAL; 876 s = spltty(); 877 if (ISGRAPHSC(scp)) { 878 splx(s); 879 return EOPNOTSUPP; 880 } 881 hist_rsz = (scp->history != NULL) ? scp->history->vtb_rows : 0; 882 if (((u_int)ptr->x + ptr->xsize) > scp->xsize || 883 ((u_int)ptr->y + ptr->ysize) > (scp->ysize + hist_rsz)) { 884 splx(s); 885 return EINVAL; 886 } 887 888 lsize = scp->xsize * sizeof(u_int16_t); 889 csize = ptr->xsize * sizeof(u_int16_t); 890 /* Pointer to the last line of framebuffer */ 891 frbp = scp->vtb.vtb_buffer + scp->ysize * lsize + ptr->x * 892 sizeof(u_int16_t); 893 /* Pointer to the last line of target buffer */ 894 outp = (char *)outp + ptr->ysize * csize; 895 /* Pointer to the last line of history buffer */ 896 if (scp->history != NULL) 897 hstp = scp->history->vtb_buffer + sc_vtb_tail(scp->history) * 898 sizeof(u_int16_t) + ptr->x * sizeof(u_int16_t); 899 else 900 hstp = 0; 901 902 retval = 0; 903 for (lnum = 0; lnum < (ptr->y + ptr->ysize); lnum++) { 904 if (lnum < scp->ysize) { 905 frbp -= lsize; 906 } else { 907 hstp -= lsize; 908 if (hstp < scp->history->vtb_buffer) 909 hstp += scp->history->vtb_rows * lsize; 910 frbp = hstp; 911 } 912 if (lnum < ptr->y) 913 continue; 914 outp = (char *)outp - csize; 915 retval = copyout((void *)frbp, outp, csize); 916 if (retval != 0) 917 break; 918 } 919 splx(s); 920 return retval; 921 } 922 923 case VT_SETMODE: /* set screen switcher mode */ 924 { 925 struct vt_mode *mode; 926 struct proc *p1; 927 928 mode = (struct vt_mode *)data; 929 DPRINTF(5, ("%s%d: VT_SETMODE ", SC_DRIVER_NAME, sc->unit)); 930 if (scp->smode.mode == VT_PROCESS) { 931 p1 = pfind(scp->pid); 932 if (scp->proc == p1 && scp->proc != td->td_proc) { 933 if (p1) 934 PROC_UNLOCK(p1); 935 DPRINTF(5, ("error EPERM\n")); 936 return EPERM; 937 } 938 if (p1) 939 PROC_UNLOCK(p1); 940 } 941 s = spltty(); 942 if (mode->mode == VT_AUTO) { 943 scp->smode.mode = VT_AUTO; 944 scp->proc = NULL; 945 scp->pid = 0; 946 DPRINTF(5, ("VT_AUTO, ")); 947 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit)) 948 cnavailable(sc_consptr, TRUE); 949 /* were we in the middle of the vty switching process? */ 950 if (finish_vt_rel(scp, TRUE, &s) == 0) 951 DPRINTF(5, ("reset WAIT_REL, ")); 952 if (finish_vt_acq(scp) == 0) 953 DPRINTF(5, ("reset WAIT_ACQ, ")); 954 } else { 955 if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig) 956 || !ISSIGVALID(mode->frsig)) { 957 splx(s); 958 DPRINTF(5, ("error EINVAL\n")); 959 return EINVAL; 960 } 961 DPRINTF(5, ("VT_PROCESS %d, ", td->td_proc->p_pid)); 962 bcopy(data, &scp->smode, sizeof(struct vt_mode)); 963 scp->proc = td->td_proc; 964 scp->pid = scp->proc->p_pid; 965 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit)) 966 cnavailable(sc_consptr, FALSE); 967 } 968 splx(s); 969 DPRINTF(5, ("\n")); 970 return 0; 971 } 972 973 case VT_GETMODE: /* get screen switcher mode */ 974 bcopy(&scp->smode, data, sizeof(struct vt_mode)); 975 return 0; 976 977#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 978 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 979 case _IO('v', 4): 980 ival = IOCPARM_IVAL(data); 981 data = (caddr_t)&ival; 982 /* FALLTHROUGH */ 983#endif 984 case VT_RELDISP: /* screen switcher ioctl */ 985 s = spltty(); 986 /* 987 * This must be the current vty which is in the VT_PROCESS 988 * switching mode... 989 */ 990 if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) { 991 splx(s); 992 return EINVAL; 993 } 994 /* ...and this process is controlling it. */ 995 if (scp->proc != td->td_proc) { 996 splx(s); 997 return EPERM; 998 } 999 error = EINVAL; 1000 switch(*(int *)data) { 1001 case VT_FALSE: /* user refuses to release screen, abort */ 1002 if ((error = finish_vt_rel(scp, FALSE, &s)) == 0) 1003 DPRINTF(5, ("%s%d: VT_FALSE\n", SC_DRIVER_NAME, sc->unit)); 1004 break; 1005 case VT_TRUE: /* user has released screen, go on */ 1006 if ((error = finish_vt_rel(scp, TRUE, &s)) == 0) 1007 DPRINTF(5, ("%s%d: VT_TRUE\n", SC_DRIVER_NAME, sc->unit)); 1008 break; 1009 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1010 if ((error = finish_vt_acq(scp)) == 0) 1011 DPRINTF(5, ("%s%d: VT_ACKACQ\n", SC_DRIVER_NAME, sc->unit)); 1012 break; 1013 default: 1014 break; 1015 } 1016 splx(s); 1017 return error; 1018 1019 case VT_OPENQRY: /* return free virtual console */ 1020 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) { 1021 tp = SC_DEV(sc, i); 1022 if (!tty_opened(tp)) { 1023 *(int *)data = i + 1; 1024 return 0; 1025 } 1026 } 1027 return EINVAL; 1028 1029#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1030 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1031 case _IO('v', 5): 1032 ival = IOCPARM_IVAL(data); 1033 data = (caddr_t)&ival; 1034 /* FALLTHROUGH */ 1035#endif 1036 case VT_ACTIVATE: /* switch to screen *data */ 1037 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1); 1038 s = spltty(); 1039 error = sc_clean_up(sc->cur_scp); 1040 splx(s); 1041 if (error) 1042 return error; 1043 error = sc_switch_scr(sc, i); 1044 return (error); 1045 1046#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1047 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1048 case _IO('v', 6): 1049 ival = IOCPARM_IVAL(data); 1050 data = (caddr_t)&ival; 1051 /* FALLTHROUGH */ 1052#endif 1053 case VT_WAITACTIVE: /* wait for switch to occur */ 1054 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1); 1055 if ((i < sc->first_vty) || (i >= sc->first_vty + sc->vtys)) 1056 return EINVAL; 1057 if (i == sc->cur_scp->index) 1058 return 0; 1059 error = tsleep(VTY_WCHAN(sc, i), (PZERO + 1) | PCATCH, "waitvt", 0); 1060 return error; 1061 1062 case VT_GETACTIVE: /* get active vty # */ 1063 *(int *)data = sc->cur_scp->index + 1; 1064 return 0; 1065 1066 case VT_GETINDEX: /* get this vty # */ 1067 *(int *)data = scp->index + 1; 1068 return 0; 1069 1070 case VT_LOCKSWITCH: /* prevent vty switching */ 1071 if ((*(int *)data) & 0x01) 1072 sc->flags |= SC_SCRN_VTYLOCK; 1073 else 1074 sc->flags &= ~SC_SCRN_VTYLOCK; 1075 return 0; 1076 1077 case KDENABIO: /* allow io operations */ 1078 error = priv_check(td, PRIV_IO); 1079 if (error != 0) 1080 return error; 1081 error = securelevel_gt(td->td_ucred, 0); 1082 if (error != 0) 1083 return error; 1084#ifdef __i386__ 1085 td->td_frame->tf_eflags |= PSL_IOPL; 1086#elif defined(__amd64__) 1087 td->td_frame->tf_rflags |= PSL_IOPL; 1088#endif 1089 return 0; 1090 1091 case KDDISABIO: /* disallow io operations (default) */ 1092#ifdef __i386__ 1093 td->td_frame->tf_eflags &= ~PSL_IOPL; 1094#elif defined(__amd64__) 1095 td->td_frame->tf_rflags &= ~PSL_IOPL; 1096#endif 1097 return 0; 1098 1099#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1100 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1101 case _IO('K', 20): 1102 ival = IOCPARM_IVAL(data); 1103 data = (caddr_t)&ival; 1104 /* FALLTHROUGH */ 1105#endif 1106 case KDSKBSTATE: /* set keyboard state (locks) */ 1107 if (*(int *)data & ~LOCK_MASK) 1108 return EINVAL; 1109 scp->status &= ~LOCK_MASK; 1110 scp->status |= *(int *)data; 1111 if (scp == sc->cur_scp) 1112 update_kbd_state(scp, scp->status, LOCK_MASK); 1113 return 0; 1114 1115 case KDGKBSTATE: /* get keyboard state (locks) */ 1116 if (scp == sc->cur_scp) 1117 save_kbd_state(scp); 1118 *(int *)data = scp->status & LOCK_MASK; 1119 return 0; 1120 1121 case KDGETREPEAT: /* get keyboard repeat & delay rates */ 1122 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ 1123 error = kbdd_ioctl(sc->kbd, cmd, data); 1124 if (error == ENOIOCTL) 1125 error = ENODEV; 1126 return error; 1127 1128#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1129 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1130 case _IO('K', 67): 1131 ival = IOCPARM_IVAL(data); 1132 data = (caddr_t)&ival; 1133 /* FALLTHROUGH */ 1134#endif 1135 case KDSETRAD: /* set keyboard repeat & delay rates (old) */ 1136 if (*(int *)data & ~0x7f) 1137 return EINVAL; 1138 error = kbdd_ioctl(sc->kbd, KDSETRAD, data); 1139 if (error == ENOIOCTL) 1140 error = ENODEV; 1141 return error; 1142 1143#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1144 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1145 case _IO('K', 7): 1146 ival = IOCPARM_IVAL(data); 1147 data = (caddr_t)&ival; 1148 /* FALLTHROUGH */ 1149#endif 1150 case KDSKBMODE: /* set keyboard mode */ 1151 switch (*(int *)data) { 1152 case K_XLATE: /* switch to XLT ascii mode */ 1153 case K_RAW: /* switch to RAW scancode mode */ 1154 case K_CODE: /* switch to CODE mode */ 1155 scp->kbd_mode = *(int *)data; 1156 if (scp == sc->cur_scp) 1157 kbdd_ioctl(sc->kbd, KDSKBMODE, data); 1158 return 0; 1159 default: 1160 return EINVAL; 1161 } 1162 /* NOT REACHED */ 1163 1164 case KDGKBMODE: /* get keyboard mode */ 1165 *(int *)data = scp->kbd_mode; 1166 return 0; 1167 1168 case KDGKBINFO: 1169 error = kbdd_ioctl(sc->kbd, cmd, data); 1170 if (error == ENOIOCTL) 1171 error = ENODEV; 1172 return error; 1173 1174#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1175 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1176 case _IO('K', 8): 1177 ival = IOCPARM_IVAL(data); 1178 data = (caddr_t)&ival; 1179 /* FALLTHROUGH */ 1180#endif 1181 case KDMKTONE: /* sound the bell */ 1182 if (*(int*)data) 1183 sc_bell(scp, (*(int*)data)&0xffff, 1184 (((*(int*)data)>>16)&0xffff)*hz/1000); 1185 else 1186 sc_bell(scp, scp->bell_pitch, scp->bell_duration); 1187 return 0; 1188 1189#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1190 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1191 case _IO('K', 63): 1192 ival = IOCPARM_IVAL(data); 1193 data = (caddr_t)&ival; 1194 /* FALLTHROUGH */ 1195#endif 1196 case KIOCSOUND: /* make tone (*data) hz */ 1197 if (scp == sc->cur_scp) { 1198 if (*(int *)data) 1199 return sc_tone(*(int *)data); 1200 else 1201 return sc_tone(0); 1202 } 1203 return 0; 1204 1205 case KDGKBTYPE: /* get keyboard type */ 1206 error = kbdd_ioctl(sc->kbd, cmd, data); 1207 if (error == ENOIOCTL) { 1208 /* always return something? XXX */ 1209 *(int *)data = 0; 1210 } 1211 return 0; 1212 1213#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1214 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1215 case _IO('K', 66): 1216 ival = IOCPARM_IVAL(data); 1217 data = (caddr_t)&ival; 1218 /* FALLTHROUGH */ 1219#endif 1220 case KDSETLED: /* set keyboard LED status */ 1221 if (*(int *)data & ~LED_MASK) /* FIXME: LOCK_MASK? */ 1222 return EINVAL; 1223 scp->status &= ~LED_MASK; 1224 scp->status |= *(int *)data; 1225 if (scp == sc->cur_scp) 1226 update_kbd_leds(scp, scp->status); 1227 return 0; 1228 1229 case KDGETLED: /* get keyboard LED status */ 1230 if (scp == sc->cur_scp) 1231 save_kbd_state(scp); 1232 *(int *)data = scp->status & LED_MASK; 1233 return 0; 1234 1235 case KBADDKBD: /* add/remove keyboard to/from mux */ 1236 case KBRELKBD: 1237 error = kbdd_ioctl(sc->kbd, cmd, data); 1238 if (error == ENOIOCTL) 1239 error = ENODEV; 1240 return error; 1241 1242#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1243 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1244 case _IO('c', 110): 1245 ival = IOCPARM_IVAL(data); 1246 data = (caddr_t)&ival; 1247 /* FALLTHROUGH */ 1248#endif 1249 case CONS_SETKBD: /* set the new keyboard */ 1250 { 1251 keyboard_t *newkbd; 1252 1253 s = spltty(); 1254 newkbd = kbd_get_keyboard(*(int *)data); 1255 if (newkbd == NULL) { 1256 splx(s); 1257 return EINVAL; 1258 } 1259 error = 0; 1260 if (sc->kbd != newkbd) { 1261 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit, 1262 (void *)&sc->keyboard, sckbdevent, sc); 1263 /* i == newkbd->kb_index */ 1264 if (i >= 0) { 1265 if (sc->kbd != NULL) { 1266 save_kbd_state(sc->cur_scp); 1267 kbd_release(sc->kbd, (void *)&sc->keyboard); 1268 } 1269 sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */ 1270 sc->keyboard = i; 1271 kbdd_ioctl(sc->kbd, KDSKBMODE, 1272 (caddr_t)&sc->cur_scp->kbd_mode); 1273 update_kbd_state(sc->cur_scp, sc->cur_scp->status, 1274 LOCK_MASK); 1275 } else { 1276 error = EPERM; /* XXX */ 1277 } 1278 } 1279 splx(s); 1280 return error; 1281 } 1282 1283 case CONS_RELKBD: /* release the current keyboard */ 1284 s = spltty(); 1285 error = 0; 1286 if (sc->kbd != NULL) { 1287 save_kbd_state(sc->cur_scp); 1288 error = kbd_release(sc->kbd, (void *)&sc->keyboard); 1289 if (error == 0) { 1290 sc->kbd = NULL; 1291 sc->keyboard = -1; 1292 } 1293 } 1294 splx(s); 1295 return error; 1296 1297 case CONS_GETTERM: /* get the current terminal emulator info */ 1298 { 1299 sc_term_sw_t *sw; 1300 1301 if (((term_info_t *)data)->ti_index == 0) { 1302 sw = scp->tsw; 1303 } else { 1304 sw = sc_term_match_by_number(((term_info_t *)data)->ti_index); 1305 } 1306 if (sw != NULL) { 1307 strncpy(((term_info_t *)data)->ti_name, sw->te_name, 1308 sizeof(((term_info_t *)data)->ti_name)); 1309 strncpy(((term_info_t *)data)->ti_desc, sw->te_desc, 1310 sizeof(((term_info_t *)data)->ti_desc)); 1311 ((term_info_t *)data)->ti_flags = 0; 1312 return 0; 1313 } else { 1314 ((term_info_t *)data)->ti_name[0] = '\0'; 1315 ((term_info_t *)data)->ti_desc[0] = '\0'; 1316 ((term_info_t *)data)->ti_flags = 0; 1317 return EINVAL; 1318 } 1319 } 1320 1321 case CONS_SETTERM: /* set the current terminal emulator */ 1322 s = spltty(); 1323 error = sc_init_emulator(scp, ((term_info_t *)data)->ti_name); 1324 /* FIXME: what if scp == sc_console! XXX */ 1325 splx(s); 1326 return error; 1327 1328 case GIO_SCRNMAP: /* get output translation table */ 1329 bcopy(&sc->scr_map, data, sizeof(sc->scr_map)); 1330 return 0; 1331 1332 case PIO_SCRNMAP: /* set output translation table */ 1333 bcopy(data, &sc->scr_map, sizeof(sc->scr_map)); 1334 for (i=0; i<sizeof(sc->scr_map); i++) { 1335 sc->scr_rmap[sc->scr_map[i]] = i; 1336 } 1337 return 0; 1338 1339 case GIO_KEYMAP: /* get keyboard translation table */ 1340 case PIO_KEYMAP: /* set keyboard translation table */ 1341 case GIO_DEADKEYMAP: /* get accent key translation table */ 1342 case PIO_DEADKEYMAP: /* set accent key translation table */ 1343 case GETFKEY: /* get function key string */ 1344 case SETFKEY: /* set function key string */ 1345 error = kbdd_ioctl(sc->kbd, cmd, data); 1346 if (error == ENOIOCTL) 1347 error = ENODEV; 1348 return error; 1349 1350#ifndef SC_NO_FONT_LOADING 1351 1352 case PIO_FONT8x8: /* set 8x8 dot font */ 1353 if (!ISFONTAVAIL(sc->adp->va_flags)) 1354 return ENXIO; 1355 bcopy(data, sc->font_8, 8*256); 1356 sc->fonts_loaded |= FONT_8; 1357 /* 1358 * FONT KLUDGE 1359 * Always use the font page #0. XXX 1360 * Don't load if the current font size is not 8x8. 1361 */ 1362 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14)) 1363 sc_load_font(sc->cur_scp, 0, 8, 8, sc->font_8, 0, 256); 1364 return 0; 1365 1366 case GIO_FONT8x8: /* get 8x8 dot font */ 1367 if (!ISFONTAVAIL(sc->adp->va_flags)) 1368 return ENXIO; 1369 if (sc->fonts_loaded & FONT_8) { 1370 bcopy(sc->font_8, data, 8*256); 1371 return 0; 1372 } 1373 else 1374 return ENXIO; 1375 1376 case PIO_FONT8x14: /* set 8x14 dot font */ 1377 if (!ISFONTAVAIL(sc->adp->va_flags)) 1378 return ENXIO; 1379 bcopy(data, sc->font_14, 14*256); 1380 sc->fonts_loaded |= FONT_14; 1381 /* 1382 * FONT KLUDGE 1383 * Always use the font page #0. XXX 1384 * Don't load if the current font size is not 8x14. 1385 */ 1386 if (ISTEXTSC(sc->cur_scp) 1387 && (sc->cur_scp->font_size >= 14) 1388 && (sc->cur_scp->font_size < 16)) 1389 sc_load_font(sc->cur_scp, 0, 14, 8, sc->font_14, 0, 256); 1390 return 0; 1391 1392 case GIO_FONT8x14: /* get 8x14 dot font */ 1393 if (!ISFONTAVAIL(sc->adp->va_flags)) 1394 return ENXIO; 1395 if (sc->fonts_loaded & FONT_14) { 1396 bcopy(sc->font_14, data, 14*256); 1397 return 0; 1398 } 1399 else 1400 return ENXIO; 1401 1402 case PIO_FONT8x16: /* set 8x16 dot font */ 1403 if (!ISFONTAVAIL(sc->adp->va_flags)) 1404 return ENXIO; 1405 bcopy(data, sc->font_16, 16*256); 1406 sc->fonts_loaded |= FONT_16; 1407 /* 1408 * FONT KLUDGE 1409 * Always use the font page #0. XXX 1410 * Don't load if the current font size is not 8x16. 1411 */ 1412 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16)) 1413 sc_load_font(sc->cur_scp, 0, 16, 8, sc->font_16, 0, 256); 1414 return 0; 1415 1416 case GIO_FONT8x16: /* get 8x16 dot font */ 1417 if (!ISFONTAVAIL(sc->adp->va_flags)) 1418 return ENXIO; 1419 if (sc->fonts_loaded & FONT_16) { 1420 bcopy(sc->font_16, data, 16*256); 1421 return 0; 1422 } 1423 else 1424 return ENXIO; 1425 1426#endif /* SC_NO_FONT_LOADING */ 1427 1428 default: 1429 break; 1430 } 1431 1432 return (ENOIOCTL); 1433} 1434 1435static int 1436consolectl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 1437 struct thread *td) 1438{ 1439 1440 return sctty_ioctl(dev->si_drv1, cmd, data, td); 1441} 1442 1443static void 1444sc_cnprobe(struct consdev *cp) 1445{ 1446 int unit; 1447 int flags; 1448 1449 cp->cn_pri = sc_get_cons_priority(&unit, &flags); 1450 1451 /* a video card is always required */ 1452 if (!scvidprobe(unit, flags, TRUE)) 1453 cp->cn_pri = CN_DEAD; 1454 1455 /* syscons will become console even when there is no keyboard */ 1456 sckbdprobe(unit, flags, TRUE); 1457 1458 if (cp->cn_pri == CN_DEAD) 1459 return; 1460 1461 /* initialize required fields */ 1462 strcpy(cp->cn_name, "ttyv0"); 1463} 1464 1465static void 1466sc_cninit(struct consdev *cp) 1467{ 1468 int unit; 1469 int flags; 1470 1471 sc_get_cons_priority(&unit, &flags); 1472 scinit(unit, flags | SC_KERNEL_CONSOLE); 1473 sc_console_unit = unit; 1474 sc_console = sc_get_stat(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]); 1475 sc_consptr = cp; 1476} 1477 1478static void 1479sc_cnterm(struct consdev *cp) 1480{ 1481 /* we are not the kernel console any more, release everything */ 1482 1483 if (sc_console_unit < 0) 1484 return; /* shouldn't happen */ 1485 1486#if 0 /* XXX */ 1487 sc_clear_screen(sc_console); 1488 sccnupdate(sc_console); 1489#endif 1490 1491 scterm(sc_console_unit, SC_KERNEL_CONSOLE); 1492 sc_console_unit = -1; 1493 sc_console = NULL; 1494} 1495 1496static void 1497sc_cnputc(struct consdev *cd, int c) 1498{ 1499 u_char buf[1]; 1500 scr_stat *scp = sc_console; 1501#ifndef SC_NO_HISTORY 1502#if 0 1503 struct tty *tp; 1504#endif 1505#endif /* !SC_NO_HISTORY */ 1506 int s; 1507 1508 /* assert(sc_console != NULL) */ 1509 1510#ifndef SC_NO_HISTORY 1511 if (scp == scp->sc->cur_scp && scp->status & SLKED) { 1512 scp->status &= ~SLKED; 1513 update_kbd_state(scp, scp->status, SLKED); 1514 if (scp->status & BUFFER_SAVED) { 1515 if (!sc_hist_restore(scp)) 1516 sc_remove_cutmarking(scp); 1517 scp->status &= ~BUFFER_SAVED; 1518 scp->status |= CURSOR_ENABLED; 1519 sc_draw_cursor_image(scp); 1520 } 1521#if 0 1522 /* 1523 * XXX: Now that TTY's have their own locks, we cannot process 1524 * any data after disabling scroll lock. cnputs already holds a 1525 * spinlock. 1526 */ 1527 tp = SC_DEV(scp->sc, scp->index); 1528 tty_lock(tp); 1529 if (tty_opened(tp)) 1530 sctty_outwakeup(tp); 1531 tty_unlock(tp); 1532#endif 1533 } 1534#endif /* !SC_NO_HISTORY */ 1535 1536 buf[0] = c; 1537 sc_puts(scp, buf, 1, 1); 1538 1539 s = spltty(); /* block sckbdevent and scrn_timer */ 1540 sccnupdate(scp); 1541 splx(s); 1542} 1543 1544static int 1545sc_cngetc(struct consdev *cd) 1546{ 1547 static struct fkeytab fkey; 1548 static int fkeycp; 1549 scr_stat *scp; 1550 u_char *p; 1551 int cur_mode; 1552 int s = spltty(); /* block sckbdevent and scrn_timer while we poll */ 1553 int c; 1554 1555 /* assert(sc_console != NULL) */ 1556 1557 /* 1558 * Stop the screen saver and update the screen if necessary. 1559 * What if we have been running in the screen saver code... XXX 1560 */ 1561 sc_touch_scrn_saver(); 1562 scp = sc_console->sc->cur_scp; /* XXX */ 1563 sccnupdate(scp); 1564 1565 if (fkeycp < fkey.len) { 1566 splx(s); 1567 return fkey.str[fkeycp++]; 1568 } 1569 1570 if (scp->sc->kbd == NULL) { 1571 splx(s); 1572 return -1; 1573 } 1574 1575 /* 1576 * Make sure the keyboard is accessible even when the kbd device 1577 * driver is disabled. 1578 */ 1579 kbdd_enable(scp->sc->kbd); 1580 1581 /* we shall always use the keyboard in the XLATE mode here */ 1582 cur_mode = scp->kbd_mode; 1583 scp->kbd_mode = K_XLATE; 1584 kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); 1585 1586 kbdd_poll(scp->sc->kbd, TRUE); 1587 c = scgetc(scp->sc, SCGETC_CN | SCGETC_NONBLOCK); 1588 kbdd_poll(scp->sc->kbd, FALSE); 1589 1590 scp->kbd_mode = cur_mode; 1591 kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); 1592 kbdd_disable(scp->sc->kbd); 1593 splx(s); 1594 1595 switch (KEYFLAGS(c)) { 1596 case 0: /* normal char */ 1597 return KEYCHAR(c); 1598 case FKEY: /* function key */ 1599 p = kbdd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp); 1600 fkey.len = fkeycp; 1601 if ((p != NULL) && (fkey.len > 0)) { 1602 bcopy(p, fkey.str, fkey.len); 1603 fkeycp = 1; 1604 return fkey.str[0]; 1605 } 1606 return c; /* XXX */ 1607 case NOKEY: 1608 case ERRKEY: 1609 default: 1610 return -1; 1611 } 1612 /* NOT REACHED */ 1613} 1614 1615static void 1616sccnupdate(scr_stat *scp) 1617{ 1618 /* this is a cut-down version of scrn_timer()... */ 1619 1620 if (scp->sc->font_loading_in_progress) 1621 return; 1622 1623 if (debugger > 0 || panicstr || shutdown_in_progress) { 1624 sc_touch_scrn_saver(); 1625 } else if (scp != scp->sc->cur_scp) { 1626 return; 1627 } 1628 1629 if (!run_scrn_saver) 1630 scp->sc->flags &= ~SC_SCRN_IDLE; 1631#ifdef DEV_SPLASH 1632 if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE)) 1633 if (scp->sc->flags & SC_SCRN_BLANKED) 1634 stop_scrn_saver(scp->sc, current_saver); 1635#endif 1636 1637 if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress 1638 || scp->sc->switch_in_progress) 1639 return; 1640 /* 1641 * FIXME: unlike scrn_timer(), we call scrn_update() from here even 1642 * when write_in_progress is non-zero. XXX 1643 */ 1644 1645 if (!ISGRAPHSC(scp) && !(scp->sc->flags & SC_SCRN_BLANKED)) 1646 scrn_update(scp, TRUE); 1647} 1648 1649static void 1650scrn_timer(void *arg) 1651{ 1652#ifndef PC98 1653 static int kbd_interval = 0; 1654#endif 1655 struct timeval tv; 1656 sc_softc_t *sc; 1657 scr_stat *scp; 1658 int again; 1659 int s; 1660 1661 again = (arg != NULL); 1662 if (arg != NULL) 1663 sc = (sc_softc_t *)arg; 1664 else if (sc_console != NULL) 1665 sc = sc_console->sc; 1666 else 1667 return; 1668 1669 /* don't do anything when we are performing some I/O operations */ 1670 if (sc->font_loading_in_progress) { 1671 if (again) 1672 timeout(scrn_timer, sc, hz / 10); 1673 return; 1674 } 1675 s = spltty(); 1676 1677#ifndef PC98 1678 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) { 1679 /* try to allocate a keyboard automatically */ 1680 if (++kbd_interval >= 25) { 1681 sc->keyboard = sc_allocate_keyboard(sc, -1); 1682 if (sc->keyboard >= 0) { 1683 sc->kbd = kbd_get_keyboard(sc->keyboard); 1684 kbdd_ioctl(sc->kbd, KDSKBMODE, 1685 (caddr_t)&sc->cur_scp->kbd_mode); 1686 update_kbd_state(sc->cur_scp, sc->cur_scp->status, 1687 LOCK_MASK); 1688 } 1689 kbd_interval = 0; 1690 } 1691 } 1692#endif /* PC98 */ 1693 1694 /* find the vty to update */ 1695 scp = sc->cur_scp; 1696 1697 /* should we stop the screen saver? */ 1698 getmicrouptime(&tv); 1699 if (debugger > 0 || panicstr || shutdown_in_progress) 1700 sc_touch_scrn_saver(); 1701 if (run_scrn_saver) { 1702 if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time) 1703 sc->flags |= SC_SCRN_IDLE; 1704 else 1705 sc->flags &= ~SC_SCRN_IDLE; 1706 } else { 1707 sc->scrn_time_stamp = tv.tv_sec; 1708 sc->flags &= ~SC_SCRN_IDLE; 1709 if (scrn_blank_time > 0) 1710 run_scrn_saver = TRUE; 1711 } 1712#ifdef DEV_SPLASH 1713 if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE)) 1714 if (sc->flags & SC_SCRN_BLANKED) 1715 stop_scrn_saver(sc, current_saver); 1716#endif 1717 1718 /* should we just return ? */ 1719 if (sc->blink_in_progress || sc->switch_in_progress 1720 || sc->write_in_progress) { 1721 if (again) 1722 timeout(scrn_timer, sc, hz / 10); 1723 splx(s); 1724 return; 1725 } 1726 1727 /* Update the screen */ 1728 scp = sc->cur_scp; /* cur_scp may have changed... */ 1729 if (!ISGRAPHSC(scp) && !(sc->flags & SC_SCRN_BLANKED)) 1730 scrn_update(scp, TRUE); 1731 1732#ifdef DEV_SPLASH 1733 /* should we activate the screen saver? */ 1734 if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE)) 1735 if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED)) 1736 (*current_saver)(sc, TRUE); 1737#endif 1738 1739 if (again) 1740 timeout(scrn_timer, sc, hz / 25); 1741 splx(s); 1742} 1743 1744static int 1745and_region(int *s1, int *e1, int s2, int e2) 1746{ 1747 if (*e1 < s2 || e2 < *s1) 1748 return FALSE; 1749 *s1 = imax(*s1, s2); 1750 *e1 = imin(*e1, e2); 1751 return TRUE; 1752} 1753 1754static void 1755scrn_update(scr_stat *scp, int show_cursor) 1756{ 1757 int start; 1758 int end; 1759 int s; 1760 int e; 1761 1762 /* assert(scp == scp->sc->cur_scp) */ 1763 1764 SC_VIDEO_LOCK(scp->sc); 1765 1766#ifndef SC_NO_CUTPASTE 1767 /* remove the previous mouse pointer image if necessary */ 1768 if (scp->status & MOUSE_VISIBLE) { 1769 s = scp->mouse_pos; 1770 e = scp->mouse_pos + scp->xsize + 1; 1771 if ((scp->status & (MOUSE_MOVED | MOUSE_HIDDEN)) 1772 || and_region(&s, &e, scp->start, scp->end) 1773 || ((scp->status & CURSOR_ENABLED) && 1774 (scp->cursor_pos != scp->cursor_oldpos) && 1775 (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos) 1776 || and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)))) { 1777 sc_remove_mouse_image(scp); 1778 if (scp->end >= scp->xsize*scp->ysize) 1779 scp->end = scp->xsize*scp->ysize - 1; 1780 } 1781 } 1782#endif /* !SC_NO_CUTPASTE */ 1783 1784#if 1 1785 /* debug: XXX */ 1786 if (scp->end >= scp->xsize*scp->ysize) { 1787 printf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end); 1788 scp->end = scp->xsize*scp->ysize - 1; 1789 } 1790 if (scp->start < 0) { 1791 printf("scrn_update(): scp->start %d < 0\n", scp->start); 1792 scp->start = 0; 1793 } 1794#endif 1795 1796 /* update screen image */ 1797 if (scp->start <= scp->end) { 1798 if (scp->mouse_cut_end >= 0) { 1799 /* there is a marked region for cut & paste */ 1800 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 1801 start = scp->mouse_cut_start; 1802 end = scp->mouse_cut_end; 1803 } else { 1804 start = scp->mouse_cut_end; 1805 end = scp->mouse_cut_start - 1; 1806 } 1807 s = start; 1808 e = end; 1809 /* does the cut-mark region overlap with the update region? */ 1810 if (and_region(&s, &e, scp->start, scp->end)) { 1811 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE); 1812 s = 0; 1813 e = start - 1; 1814 if (and_region(&s, &e, scp->start, scp->end)) 1815 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE); 1816 s = end + 1; 1817 e = scp->xsize*scp->ysize - 1; 1818 if (and_region(&s, &e, scp->start, scp->end)) 1819 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE); 1820 } else { 1821 (*scp->rndr->draw)(scp, scp->start, 1822 scp->end - scp->start + 1, FALSE); 1823 } 1824 } else { 1825 (*scp->rndr->draw)(scp, scp->start, 1826 scp->end - scp->start + 1, FALSE); 1827 } 1828 } 1829 1830 /* we are not to show the cursor and the mouse pointer... */ 1831 if (!show_cursor) { 1832 scp->end = 0; 1833 scp->start = scp->xsize*scp->ysize - 1; 1834 SC_VIDEO_UNLOCK(scp->sc); 1835 return; 1836 } 1837 1838 /* update cursor image */ 1839 if (scp->status & CURSOR_ENABLED) { 1840 s = scp->start; 1841 e = scp->end; 1842 /* did cursor move since last time ? */ 1843 if (scp->cursor_pos != scp->cursor_oldpos) { 1844 /* do we need to remove old cursor image ? */ 1845 if (!and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)) 1846 sc_remove_cursor_image(scp); 1847 sc_draw_cursor_image(scp); 1848 } else { 1849 if (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos)) 1850 /* cursor didn't move, but has been overwritten */ 1851 sc_draw_cursor_image(scp); 1852 else if (scp->curs_attr.flags & CONS_BLINK_CURSOR) 1853 /* if it's a blinking cursor, update it */ 1854 (*scp->rndr->blink_cursor)(scp, scp->cursor_pos, 1855 sc_inside_cutmark(scp, 1856 scp->cursor_pos)); 1857 } 1858 } 1859 1860#ifndef SC_NO_CUTPASTE 1861 /* update "pseudo" mouse pointer image */ 1862 if (scp->sc->flags & SC_MOUSE_ENABLED) { 1863 if (!(scp->status & (MOUSE_VISIBLE | MOUSE_HIDDEN))) { 1864 scp->status &= ~MOUSE_MOVED; 1865 sc_draw_mouse_image(scp); 1866 } 1867 } 1868#endif /* SC_NO_CUTPASTE */ 1869 1870 scp->end = 0; 1871 scp->start = scp->xsize*scp->ysize - 1; 1872 1873 SC_VIDEO_UNLOCK(scp->sc); 1874} 1875 1876#ifdef DEV_SPLASH 1877static int 1878scsplash_callback(int event, void *arg) 1879{ 1880 sc_softc_t *sc; 1881 int error; 1882 1883 sc = (sc_softc_t *)arg; 1884 1885 switch (event) { 1886 case SPLASH_INIT: 1887 if (add_scrn_saver(scsplash_saver) == 0) { 1888 sc->flags &= ~SC_SAVER_FAILED; 1889 run_scrn_saver = TRUE; 1890 if (cold && !(boothowto & RB_VERBOSE)) { 1891 scsplash_stick(TRUE); 1892 (*current_saver)(sc, TRUE); 1893 } 1894 } 1895 return 0; 1896 1897 case SPLASH_TERM: 1898 if (current_saver == scsplash_saver) { 1899 scsplash_stick(FALSE); 1900 error = remove_scrn_saver(scsplash_saver); 1901 if (error) 1902 return error; 1903 } 1904 return 0; 1905 1906 default: 1907 return EINVAL; 1908 } 1909} 1910 1911static void 1912scsplash_saver(sc_softc_t *sc, int show) 1913{ 1914 static int busy = FALSE; 1915 scr_stat *scp; 1916 1917 if (busy) 1918 return; 1919 busy = TRUE; 1920 1921 scp = sc->cur_scp; 1922 if (show) { 1923 if (!(sc->flags & SC_SAVER_FAILED)) { 1924 if (!(sc->flags & SC_SCRN_BLANKED)) 1925 set_scrn_saver_mode(scp, -1, NULL, 0); 1926 switch (splash(sc->adp, TRUE)) { 1927 case 0: /* succeeded */ 1928 break; 1929 case EAGAIN: /* try later */ 1930 restore_scrn_saver_mode(scp, FALSE); 1931 sc_touch_scrn_saver(); /* XXX */ 1932 break; 1933 default: 1934 sc->flags |= SC_SAVER_FAILED; 1935 scsplash_stick(FALSE); 1936 restore_scrn_saver_mode(scp, TRUE); 1937 printf("scsplash_saver(): failed to put up the image\n"); 1938 break; 1939 } 1940 } 1941 } else if (!sticky_splash) { 1942 if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0)) 1943 restore_scrn_saver_mode(scp, TRUE); 1944 } 1945 busy = FALSE; 1946} 1947 1948static int 1949add_scrn_saver(void (*this_saver)(sc_softc_t *, int)) 1950{ 1951#if 0 1952 int error; 1953 1954 if (current_saver != none_saver) { 1955 error = remove_scrn_saver(current_saver); 1956 if (error) 1957 return error; 1958 } 1959#endif 1960 if (current_saver != none_saver) 1961 return EBUSY; 1962 1963 run_scrn_saver = FALSE; 1964 saver_mode = CONS_LKM_SAVER; 1965 current_saver = this_saver; 1966 return 0; 1967} 1968 1969static int 1970remove_scrn_saver(void (*this_saver)(sc_softc_t *, int)) 1971{ 1972 if (current_saver != this_saver) 1973 return EINVAL; 1974 1975#if 0 1976 /* 1977 * In order to prevent `current_saver' from being called by 1978 * the timeout routine `scrn_timer()' while we manipulate 1979 * the saver list, we shall set `current_saver' to `none_saver' 1980 * before stopping the current saver, rather than blocking by `splXX()'. 1981 */ 1982 current_saver = none_saver; 1983 if (scrn_blanked) 1984 stop_scrn_saver(this_saver); 1985#endif 1986 1987 /* unblank all blanked screens */ 1988 wait_scrn_saver_stop(NULL); 1989 if (scrn_blanked) 1990 return EBUSY; 1991 1992 current_saver = none_saver; 1993 return 0; 1994} 1995 1996static int 1997set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border) 1998{ 1999 int s; 2000 2001 /* assert(scp == scp->sc->cur_scp) */ 2002 s = spltty(); 2003 if (!ISGRAPHSC(scp)) 2004 sc_remove_cursor_image(scp); 2005 scp->splash_save_mode = scp->mode; 2006 scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE); 2007 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE); 2008 scp->status |= (UNKNOWN_MODE | SAVER_RUNNING); 2009 scp->sc->flags |= SC_SCRN_BLANKED; 2010 ++scrn_blanked; 2011 splx(s); 2012 if (mode < 0) 2013 return 0; 2014 scp->mode = mode; 2015 if (set_mode(scp) == 0) { 2016 if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS) 2017 scp->status |= GRAPHICS_MODE; 2018#ifndef SC_NO_PALETTE_LOADING 2019 if (pal != NULL) 2020 vidd_load_palette(scp->sc->adp, pal); 2021#endif 2022 sc_set_border(scp, border); 2023 return 0; 2024 } else { 2025 s = spltty(); 2026 scp->mode = scp->splash_save_mode; 2027 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING); 2028 scp->status |= scp->splash_save_status; 2029 splx(s); 2030 return 1; 2031 } 2032} 2033 2034static int 2035restore_scrn_saver_mode(scr_stat *scp, int changemode) 2036{ 2037 int mode; 2038 int status; 2039 int s; 2040 2041 /* assert(scp == scp->sc->cur_scp) */ 2042 s = spltty(); 2043 mode = scp->mode; 2044 status = scp->status; 2045 scp->mode = scp->splash_save_mode; 2046 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING); 2047 scp->status |= scp->splash_save_status; 2048 scp->sc->flags &= ~SC_SCRN_BLANKED; 2049 if (!changemode) { 2050 if (!ISGRAPHSC(scp)) 2051 sc_draw_cursor_image(scp); 2052 --scrn_blanked; 2053 splx(s); 2054 return 0; 2055 } 2056 if (set_mode(scp) == 0) { 2057#ifndef SC_NO_PALETTE_LOADING 2058 vidd_load_palette(scp->sc->adp, scp->sc->palette); 2059#endif 2060 --scrn_blanked; 2061 splx(s); 2062 return 0; 2063 } else { 2064 scp->mode = mode; 2065 scp->status = status; 2066 splx(s); 2067 return 1; 2068 } 2069} 2070 2071static void 2072stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int)) 2073{ 2074 (*saver)(sc, FALSE); 2075 run_scrn_saver = FALSE; 2076 /* the screen saver may have chosen not to stop after all... */ 2077 if (sc->flags & SC_SCRN_BLANKED) 2078 return; 2079 2080 mark_all(sc->cur_scp); 2081 if (sc->delayed_next_scr) 2082 sc_switch_scr(sc, sc->delayed_next_scr - 1); 2083 if (debugger == 0) 2084 wakeup(&scrn_blanked); 2085} 2086 2087static int 2088wait_scrn_saver_stop(sc_softc_t *sc) 2089{ 2090 int error = 0; 2091 2092 while (scrn_blanked > 0) { 2093 run_scrn_saver = FALSE; 2094 if (sc && !(sc->flags & SC_SCRN_BLANKED)) { 2095 error = 0; 2096 break; 2097 } 2098 error = tsleep(&scrn_blanked, PZERO | PCATCH, "scrsav", 0); 2099 if ((error != 0) && (error != ERESTART)) 2100 break; 2101 } 2102 run_scrn_saver = FALSE; 2103 return error; 2104} 2105#endif /* DEV_SPLASH */ 2106 2107void 2108sc_touch_scrn_saver(void) 2109{ 2110 scsplash_stick(FALSE); 2111 run_scrn_saver = FALSE; 2112} 2113 2114int 2115sc_switch_scr(sc_softc_t *sc, u_int next_scr) 2116{ 2117 scr_stat *cur_scp; 2118 struct tty *tp; 2119 struct proc *p; 2120 int s; 2121 2122 DPRINTF(5, ("sc0: sc_switch_scr() %d ", next_scr + 1)); 2123 2124 if (sc->cur_scp == NULL) 2125 return (0); 2126 2127 /* prevent switch if previously requested */ 2128 if (sc->flags & SC_SCRN_VTYLOCK) { 2129 sc_bell(sc->cur_scp, sc->cur_scp->bell_pitch, 2130 sc->cur_scp->bell_duration); 2131 return EPERM; 2132 } 2133 2134 /* delay switch if the screen is blanked or being updated */ 2135 if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress 2136 || sc->blink_in_progress) { 2137 sc->delayed_next_scr = next_scr + 1; 2138 sc_touch_scrn_saver(); 2139 DPRINTF(5, ("switch delayed\n")); 2140 return 0; 2141 } 2142 sc->delayed_next_scr = 0; 2143 2144 s = spltty(); 2145 cur_scp = sc->cur_scp; 2146 2147 /* we are in the middle of the vty switching process... */ 2148 if (sc->switch_in_progress 2149 && (cur_scp->smode.mode == VT_PROCESS) 2150 && cur_scp->proc) { 2151 p = pfind(cur_scp->pid); 2152 if (cur_scp->proc != p) { 2153 if (p) 2154 PROC_UNLOCK(p); 2155 /* 2156 * The controlling process has died!!. Do some clean up. 2157 * NOTE:`cur_scp->proc' and `cur_scp->smode.mode' 2158 * are not reset here yet; they will be cleared later. 2159 */ 2160 DPRINTF(5, ("cur_scp controlling process %d died, ", 2161 cur_scp->pid)); 2162 if (cur_scp->status & SWITCH_WAIT_REL) { 2163 /* 2164 * Force the previous switch to finish, but return now 2165 * with error. 2166 */ 2167 DPRINTF(5, ("reset WAIT_REL, ")); 2168 finish_vt_rel(cur_scp, TRUE, &s); 2169 splx(s); 2170 DPRINTF(5, ("finishing previous switch\n")); 2171 return EINVAL; 2172 } else if (cur_scp->status & SWITCH_WAIT_ACQ) { 2173 /* let's assume screen switch has been completed. */ 2174 DPRINTF(5, ("reset WAIT_ACQ, ")); 2175 finish_vt_acq(cur_scp); 2176 } else { 2177 /* 2178 * We are in between screen release and acquisition, and 2179 * reached here via scgetc() or scrn_timer() which has 2180 * interrupted exchange_scr(). Don't do anything stupid. 2181 */ 2182 DPRINTF(5, ("waiting nothing, ")); 2183 } 2184 } else { 2185 if (p) 2186 PROC_UNLOCK(p); 2187 /* 2188 * The controlling process is alive, but not responding... 2189 * It is either buggy or it may be just taking time. 2190 * The following code is a gross kludge to cope with this 2191 * problem for which there is no clean solution. XXX 2192 */ 2193 if (cur_scp->status & SWITCH_WAIT_REL) { 2194 switch (sc->switch_in_progress++) { 2195 case 1: 2196 break; 2197 case 2: 2198 DPRINTF(5, ("sending relsig again, ")); 2199 signal_vt_rel(cur_scp); 2200 break; 2201 case 3: 2202 break; 2203 case 4: 2204 default: 2205 /* 2206 * Act as if the controlling program returned 2207 * VT_FALSE. 2208 */ 2209 DPRINTF(5, ("force reset WAIT_REL, ")); 2210 finish_vt_rel(cur_scp, FALSE, &s); 2211 splx(s); 2212 DPRINTF(5, ("act as if VT_FALSE was seen\n")); 2213 return EINVAL; 2214 } 2215 } else if (cur_scp->status & SWITCH_WAIT_ACQ) { 2216 switch (sc->switch_in_progress++) { 2217 case 1: 2218 break; 2219 case 2: 2220 DPRINTF(5, ("sending acqsig again, ")); 2221 signal_vt_acq(cur_scp); 2222 break; 2223 case 3: 2224 break; 2225 case 4: 2226 default: 2227 /* clear the flag and finish the previous switch */ 2228 DPRINTF(5, ("force reset WAIT_ACQ, ")); 2229 finish_vt_acq(cur_scp); 2230 break; 2231 } 2232 } 2233 } 2234 } 2235 2236 /* 2237 * Return error if an invalid argument is given, or vty switch 2238 * is still in progress. 2239 */ 2240 if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys) 2241 || sc->switch_in_progress) { 2242 splx(s); 2243 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); 2244 DPRINTF(5, ("error 1\n")); 2245 return EINVAL; 2246 } 2247 2248 /* 2249 * Don't allow switching away from the graphics mode vty 2250 * if the switch mode is VT_AUTO, unless the next vty is the same 2251 * as the current or the current vty has been closed (but showing). 2252 */ 2253 tp = SC_DEV(sc, cur_scp->index); 2254 if ((cur_scp->index != next_scr) 2255 && tty_opened(tp) 2256 && (cur_scp->smode.mode == VT_AUTO) 2257 && ISGRAPHSC(cur_scp)) { 2258 splx(s); 2259 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); 2260 DPRINTF(5, ("error, graphics mode\n")); 2261 return EINVAL; 2262 } 2263 2264 /* 2265 * Is the wanted vty open? Don't allow switching to a closed vty. 2266 * If we are in DDB, don't switch to a vty in the VT_PROCESS mode. 2267 * Note that we always allow the user to switch to the kernel 2268 * console even if it is closed. 2269 */ 2270 if ((sc_console == NULL) || (next_scr != sc_console->index)) { 2271 tp = SC_DEV(sc, next_scr); 2272 if (!tty_opened(tp)) { 2273 splx(s); 2274 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); 2275 DPRINTF(5, ("error 2, requested vty isn't open!\n")); 2276 return EINVAL; 2277 } 2278 if ((debugger > 0) && (SC_STAT(tp)->smode.mode == VT_PROCESS)) { 2279 splx(s); 2280 DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n")); 2281 return EINVAL; 2282 } 2283 } 2284 2285 /* this is the start of vty switching process... */ 2286 ++sc->switch_in_progress; 2287 sc->old_scp = cur_scp; 2288 sc->new_scp = sc_get_stat(SC_DEV(sc, next_scr)); 2289 if (sc->new_scp == sc->old_scp) { 2290 sc->switch_in_progress = 0; 2291 /* 2292 * XXX wakeup() locks the scheduler lock which will hang if 2293 * the lock is in an in-between state, e.g., when we stop at 2294 * a breakpoint at fork_exit. It has always been wrong to call 2295 * wakeup() when the debugger is active. In RELENG_4, wakeup() 2296 * is supposed to be locked by splhigh(), but the debugger may 2297 * be invoked at splhigh(). 2298 */ 2299 if (debugger == 0) 2300 wakeup(VTY_WCHAN(sc,next_scr)); 2301 splx(s); 2302 DPRINTF(5, ("switch done (new == old)\n")); 2303 return 0; 2304 } 2305 2306 /* has controlling process died? */ 2307 vt_proc_alive(sc->old_scp); 2308 vt_proc_alive(sc->new_scp); 2309 2310 /* wait for the controlling process to release the screen, if necessary */ 2311 if (signal_vt_rel(sc->old_scp)) { 2312 splx(s); 2313 return 0; 2314 } 2315 2316 /* go set up the new vty screen */ 2317 splx(s); 2318 exchange_scr(sc); 2319 s = spltty(); 2320 2321 /* wake up processes waiting for this vty */ 2322 if (debugger == 0) 2323 wakeup(VTY_WCHAN(sc,next_scr)); 2324 2325 /* wait for the controlling process to acknowledge, if necessary */ 2326 if (signal_vt_acq(sc->cur_scp)) { 2327 splx(s); 2328 return 0; 2329 } 2330 2331 sc->switch_in_progress = 0; 2332 if (sc->unit == sc_console_unit) 2333 cnavailable(sc_consptr, TRUE); 2334 splx(s); 2335 DPRINTF(5, ("switch done\n")); 2336 2337 return 0; 2338} 2339 2340static int 2341do_switch_scr(sc_softc_t *sc, int s) 2342{ 2343 vt_proc_alive(sc->new_scp); 2344 2345 splx(s); 2346 exchange_scr(sc); 2347 s = spltty(); 2348 /* sc->cur_scp == sc->new_scp */ 2349 wakeup(VTY_WCHAN(sc,sc->cur_scp->index)); 2350 2351 /* wait for the controlling process to acknowledge, if necessary */ 2352 if (!signal_vt_acq(sc->cur_scp)) { 2353 sc->switch_in_progress = 0; 2354 if (sc->unit == sc_console_unit) 2355 cnavailable(sc_consptr, TRUE); 2356 } 2357 2358 return s; 2359} 2360 2361static int 2362vt_proc_alive(scr_stat *scp) 2363{ 2364 struct proc *p; 2365 2366 if (scp->proc) { 2367 if ((p = pfind(scp->pid)) != NULL) 2368 PROC_UNLOCK(p); 2369 if (scp->proc == p) 2370 return TRUE; 2371 scp->proc = NULL; 2372 scp->smode.mode = VT_AUTO; 2373 DPRINTF(5, ("vt controlling process %d died\n", scp->pid)); 2374 } 2375 return FALSE; 2376} 2377 2378static int 2379signal_vt_rel(scr_stat *scp) 2380{ 2381 if (scp->smode.mode != VT_PROCESS) 2382 return FALSE; 2383 scp->status |= SWITCH_WAIT_REL; 2384 PROC_LOCK(scp->proc); 2385 psignal(scp->proc, scp->smode.relsig); 2386 PROC_UNLOCK(scp->proc); 2387 DPRINTF(5, ("sending relsig to %d\n", scp->pid)); 2388 return TRUE; 2389} 2390 2391static int 2392signal_vt_acq(scr_stat *scp) 2393{ 2394 if (scp->smode.mode != VT_PROCESS) 2395 return FALSE; 2396 if (scp->sc->unit == sc_console_unit) 2397 cnavailable(sc_consptr, FALSE); 2398 scp->status |= SWITCH_WAIT_ACQ; 2399 PROC_LOCK(scp->proc); 2400 psignal(scp->proc, scp->smode.acqsig); 2401 PROC_UNLOCK(scp->proc); 2402 DPRINTF(5, ("sending acqsig to %d\n", scp->pid)); 2403 return TRUE; 2404} 2405 2406static int 2407finish_vt_rel(scr_stat *scp, int release, int *s) 2408{ 2409 if (scp == scp->sc->old_scp && scp->status & SWITCH_WAIT_REL) { 2410 scp->status &= ~SWITCH_WAIT_REL; 2411 if (release) 2412 *s = do_switch_scr(scp->sc, *s); 2413 else 2414 scp->sc->switch_in_progress = 0; 2415 return 0; 2416 } 2417 return EINVAL; 2418} 2419 2420static int 2421finish_vt_acq(scr_stat *scp) 2422{ 2423 if (scp == scp->sc->new_scp && scp->status & SWITCH_WAIT_ACQ) { 2424 scp->status &= ~SWITCH_WAIT_ACQ; 2425 scp->sc->switch_in_progress = 0; 2426 return 0; 2427 } 2428 return EINVAL; 2429} 2430 2431static void 2432exchange_scr(sc_softc_t *sc) 2433{ 2434 scr_stat *scp; 2435 2436 /* save the current state of video and keyboard */ 2437 sc_move_cursor(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos); 2438 if (!ISGRAPHSC(sc->old_scp)) 2439 sc_remove_cursor_image(sc->old_scp); 2440 if (sc->old_scp->kbd_mode == K_XLATE) 2441 save_kbd_state(sc->old_scp); 2442 2443 /* set up the video for the new screen */ 2444 scp = sc->cur_scp = sc->new_scp; 2445#ifdef PC98 2446 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp) || ISUNKNOWNSC(sc->new_scp)) 2447#else 2448 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp)) 2449#endif 2450 set_mode(scp); 2451#ifndef __sparc64__ 2452 else 2453 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, 2454 (void *)sc->adp->va_window, FALSE); 2455#endif 2456 scp->status |= MOUSE_HIDDEN; 2457 sc_move_cursor(scp, scp->xpos, scp->ypos); 2458 if (!ISGRAPHSC(scp)) 2459 sc_set_cursor_image(scp); 2460#ifndef SC_NO_PALETTE_LOADING 2461 if (ISGRAPHSC(sc->old_scp)) 2462 vidd_load_palette(sc->adp, sc->palette); 2463#endif 2464 sc_set_border(scp, scp->border); 2465 2466 /* set up the keyboard for the new screen */ 2467 if (sc->old_scp->kbd_mode != scp->kbd_mode) 2468 kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); 2469 update_kbd_state(scp, scp->status, LOCK_MASK); 2470 2471 mark_all(scp); 2472} 2473 2474void 2475sc_puts(scr_stat *scp, u_char *buf, int len, int kernel) 2476{ 2477 int need_unlock = 0; 2478 2479#ifdef DEV_SPLASH 2480 /* make screensaver happy */ 2481 if (!sticky_splash && scp == scp->sc->cur_scp && !sc_saver_keyb_only) 2482 run_scrn_saver = FALSE; 2483#endif 2484 2485 if (scp->tsw) { 2486 if (!kdb_active && !mtx_owned(&scp->scr_lock)) { 2487 need_unlock = 1; 2488 mtx_lock_spin(&scp->scr_lock); 2489 } 2490 (*scp->tsw->te_puts)(scp, buf, len, kernel); 2491 if (need_unlock) 2492 mtx_unlock_spin(&scp->scr_lock); 2493 } 2494 2495 if (scp->sc->delayed_next_scr) 2496 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1); 2497} 2498 2499void 2500sc_draw_cursor_image(scr_stat *scp) 2501{ 2502 /* assert(scp == scp->sc->cur_scp); */ 2503 SC_VIDEO_LOCK(scp->sc); 2504 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, 2505 scp->curs_attr.flags & CONS_BLINK_CURSOR, TRUE, 2506 sc_inside_cutmark(scp, scp->cursor_pos)); 2507 scp->cursor_oldpos = scp->cursor_pos; 2508 SC_VIDEO_UNLOCK(scp->sc); 2509} 2510 2511void 2512sc_remove_cursor_image(scr_stat *scp) 2513{ 2514 /* assert(scp == scp->sc->cur_scp); */ 2515 SC_VIDEO_LOCK(scp->sc); 2516 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, 2517 scp->curs_attr.flags & CONS_BLINK_CURSOR, FALSE, 2518 sc_inside_cutmark(scp, scp->cursor_oldpos)); 2519 SC_VIDEO_UNLOCK(scp->sc); 2520} 2521 2522static void 2523update_cursor_image(scr_stat *scp) 2524{ 2525 /* assert(scp == scp->sc->cur_scp); */ 2526 sc_remove_cursor_image(scp); 2527 sc_set_cursor_image(scp); 2528 sc_draw_cursor_image(scp); 2529} 2530 2531void 2532sc_set_cursor_image(scr_stat *scp) 2533{ 2534 scp->curs_attr.flags = scp->curr_curs_attr.flags; 2535 if (scp->curs_attr.flags & CONS_HIDDEN_CURSOR) { 2536 /* hidden cursor is internally represented as zero-height underline */ 2537 scp->curs_attr.flags = CONS_CHAR_CURSOR; 2538 scp->curs_attr.base = scp->curs_attr.height = 0; 2539 } else if (scp->curs_attr.flags & CONS_CHAR_CURSOR) { 2540 scp->curs_attr.base = imin(scp->curr_curs_attr.base, 2541 scp->font_size - 1); 2542 scp->curs_attr.height = imin(scp->curr_curs_attr.height, 2543 scp->font_size - scp->curs_attr.base); 2544 } else { /* block cursor */ 2545 scp->curs_attr.base = 0; 2546 scp->curs_attr.height = scp->font_size; 2547 } 2548 2549 /* assert(scp == scp->sc->cur_scp); */ 2550 SC_VIDEO_LOCK(scp->sc); 2551 (*scp->rndr->set_cursor)(scp, scp->curs_attr.base, scp->curs_attr.height, 2552 scp->curs_attr.flags & CONS_BLINK_CURSOR); 2553 SC_VIDEO_UNLOCK(scp->sc); 2554} 2555 2556static void 2557change_cursor_shape(scr_stat *scp, int flags, int base, int height) 2558{ 2559 if ((scp == scp->sc->cur_scp) && !ISGRAPHSC(scp)) 2560 sc_remove_cursor_image(scp); 2561 2562 if (base >= 0) 2563 scp->curr_curs_attr.base = base; 2564 if (height >= 0) 2565 scp->curr_curs_attr.height = height; 2566 if (flags & CONS_RESET_CURSOR) 2567 scp->curr_curs_attr = scp->dflt_curs_attr; 2568 else 2569 scp->curr_curs_attr.flags = flags & CONS_CURSOR_ATTRS; 2570 2571 if ((scp == scp->sc->cur_scp) && !ISGRAPHSC(scp)) { 2572 sc_set_cursor_image(scp); 2573 sc_draw_cursor_image(scp); 2574 } 2575} 2576 2577void 2578sc_change_cursor_shape(scr_stat *scp, int flags, int base, int height) 2579{ 2580 sc_softc_t *sc; 2581 struct tty *tp; 2582 int s; 2583 int i; 2584 2585 s = spltty(); 2586 if ((flags != -1) && (flags & CONS_LOCAL_CURSOR)) { 2587 /* local (per vty) change */ 2588 change_cursor_shape(scp, flags, base, height); 2589 splx(s); 2590 return; 2591 } 2592 2593 /* global change */ 2594 sc = scp->sc; 2595 if (base >= 0) 2596 sc->curs_attr.base = base; 2597 if (height >= 0) 2598 sc->curs_attr.height = height; 2599 if (flags != -1) { 2600 if (flags & CONS_RESET_CURSOR) 2601 sc->curs_attr = sc->dflt_curs_attr; 2602 else 2603 sc->curs_attr.flags = flags & CONS_CURSOR_ATTRS; 2604 } 2605 2606 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; ++i) { 2607 if ((tp = SC_DEV(sc, i)) == NULL) 2608 continue; 2609 if ((scp = sc_get_stat(tp)) == NULL) 2610 continue; 2611 scp->dflt_curs_attr = sc->curs_attr; 2612 change_cursor_shape(scp, CONS_RESET_CURSOR, -1, -1); 2613 } 2614 splx(s); 2615} 2616 2617static void 2618scinit(int unit, int flags) 2619{ 2620 2621 /* 2622 * When syscons is being initialized as the kernel console, malloc() 2623 * is not yet functional, because various kernel structures has not been 2624 * fully initialized yet. Therefore, we need to declare the following 2625 * static buffers for the console. This is less than ideal, 2626 * but is necessry evil for the time being. XXX 2627 */ 2628#ifdef PC98 2629 static u_short sc_buffer[ROW*COL*2];/* XXX */ 2630#else 2631 static u_short sc_buffer[ROW*COL]; /* XXX */ 2632#endif 2633#ifndef SC_NO_FONT_LOADING 2634 static u_char font_8[256*8]; 2635 static u_char font_14[256*14]; 2636 static u_char font_16[256*16]; 2637#endif 2638 2639 sc_softc_t *sc; 2640 scr_stat *scp; 2641 video_adapter_t *adp; 2642 int col; 2643 int row; 2644 int i; 2645 2646 /* one time initialization */ 2647 if (init_done == COLD) 2648 sc_get_bios_values(&bios_value); 2649 init_done = WARM; 2650 2651 /* 2652 * Allocate resources. Even if we are being called for the second 2653 * time, we must allocate them again, because they might have 2654 * disappeared... 2655 */ 2656 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); 2657 if ((sc->flags & SC_INIT_DONE) == 0) 2658 SC_VIDEO_LOCKINIT(sc); 2659 2660 adp = NULL; 2661 if (sc->adapter >= 0) { 2662 vid_release(sc->adp, (void *)&sc->adapter); 2663 adp = sc->adp; 2664 sc->adp = NULL; 2665 } 2666 if (sc->keyboard >= 0) { 2667 DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard)); 2668 i = kbd_release(sc->kbd, (void *)&sc->keyboard); 2669 DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i)); 2670 if (sc->kbd != NULL) { 2671 DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, unit:%d, flags:0x%x\n", 2672 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags)); 2673 } 2674 sc->kbd = NULL; 2675 } 2676 sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter); 2677 sc->adp = vid_get_adapter(sc->adapter); 2678 /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */ 2679 2680 sc->keyboard = sc_allocate_keyboard(sc, unit); 2681 DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard)); 2682 2683 sc->kbd = kbd_get_keyboard(sc->keyboard); 2684 if (sc->kbd != NULL) { 2685 DPRINTF(1, ("sc%d: kbd index:%d, unit:%d, flags:0x%x\n", 2686 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags)); 2687 } 2688 2689 if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) { 2690 2691 sc->initial_mode = sc->adp->va_initial_mode; 2692 2693#ifndef SC_NO_FONT_LOADING 2694 if (flags & SC_KERNEL_CONSOLE) { 2695 sc->font_8 = font_8; 2696 sc->font_14 = font_14; 2697 sc->font_16 = font_16; 2698 } else if (sc->font_8 == NULL) { 2699 /* assert(sc_malloc) */ 2700 sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK); 2701 sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK); 2702 sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK); 2703 } 2704#endif 2705 2706 /* extract the hardware cursor location and hide the cursor for now */ 2707 vidd_read_hw_cursor(sc->adp, &col, &row); 2708 vidd_set_hw_cursor(sc->adp, -1, -1); 2709 2710 /* set up the first console */ 2711 sc->first_vty = unit*MAXCONS; 2712 sc->vtys = MAXCONS; /* XXX: should be configurable */ 2713 if (flags & SC_KERNEL_CONSOLE) { 2714 /* 2715 * Set up devs structure but don't use it yet, calling make_dev() 2716 * might panic kernel. Wait for sc_attach_unit() to actually 2717 * create the devices. 2718 */ 2719 sc->dev = main_devs; 2720 scp = &main_console; 2721 init_scp(sc, sc->first_vty, scp); 2722 sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize, 2723 (void *)sc_buffer, FALSE); 2724 2725 /* move cursors to the initial positions */ 2726 if (col >= scp->xsize) 2727 col = 0; 2728 if (row >= scp->ysize) 2729 row = scp->ysize - 1; 2730 scp->xpos = col; 2731 scp->ypos = row; 2732 scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col; 2733 2734 if (sc_init_emulator(scp, SC_DFLT_TERM)) 2735 sc_init_emulator(scp, "*"); 2736 (*scp->tsw->te_default_attr)(scp, 2737 user_default.std_color, 2738 user_default.rev_color); 2739 } else { 2740 /* assert(sc_malloc) */ 2741 sc->dev = malloc(sizeof(struct tty *)*sc->vtys, M_DEVBUF, 2742 M_WAITOK|M_ZERO); 2743 sc->dev[0] = sc_alloc_tty(0, unit * MAXCONS); 2744 scp = alloc_scp(sc, sc->first_vty); 2745 SC_STAT(sc->dev[0]) = scp; 2746 } 2747 sc->cur_scp = scp; 2748 2749#ifndef __sparc64__ 2750 /* copy screen to temporary buffer */ 2751 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, 2752 (void *)scp->sc->adp->va_window, FALSE); 2753 if (ISTEXTSC(scp)) 2754 sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize); 2755#endif 2756 2757 if (bios_value.cursor_end < scp->font_size) 2758 sc->dflt_curs_attr.base = scp->font_size - 2759 bios_value.cursor_end - 1; 2760 else 2761 sc->dflt_curs_attr.base = 0; 2762 i = bios_value.cursor_end - bios_value.cursor_start + 1; 2763 sc->dflt_curs_attr.height = imin(i, scp->font_size); 2764 sc->dflt_curs_attr.flags = 0; 2765 sc->curs_attr = sc->dflt_curs_attr; 2766 scp->curr_curs_attr = scp->dflt_curs_attr = sc->curs_attr; 2767 2768#ifndef SC_NO_SYSMOUSE 2769 sc_mouse_move(scp, scp->xpixel/2, scp->ypixel/2); 2770#endif 2771 if (!ISGRAPHSC(scp)) { 2772 sc_set_cursor_image(scp); 2773 sc_draw_cursor_image(scp); 2774 } 2775 2776 /* save font and palette */ 2777#ifndef SC_NO_FONT_LOADING 2778 sc->fonts_loaded = 0; 2779 if (ISFONTAVAIL(sc->adp->va_flags)) { 2780#ifdef SC_DFLT_FONT 2781 bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8)); 2782 bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14)); 2783 bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16)); 2784 sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8; 2785 if (scp->font_size < 14) { 2786 sc_load_font(scp, 0, 8, 8, sc->font_8, 0, 256); 2787 } else if (scp->font_size >= 16) { 2788 sc_load_font(scp, 0, 16, 8, sc->font_16, 0, 256); 2789 } else { 2790 sc_load_font(scp, 0, 14, 8, sc->font_14, 0, 256); 2791 } 2792#else /* !SC_DFLT_FONT */ 2793 if (scp->font_size < 14) { 2794 sc_save_font(scp, 0, 8, 8, sc->font_8, 0, 256); 2795 sc->fonts_loaded = FONT_8; 2796 } else if (scp->font_size >= 16) { 2797 sc_save_font(scp, 0, 16, 8, sc->font_16, 0, 256); 2798 sc->fonts_loaded = FONT_16; 2799 } else { 2800 sc_save_font(scp, 0, 14, 8, sc->font_14, 0, 256); 2801 sc->fonts_loaded = FONT_14; 2802 } 2803#endif /* SC_DFLT_FONT */ 2804 /* FONT KLUDGE: always use the font page #0. XXX */ 2805 sc_show_font(scp, 0); 2806 } 2807#endif /* !SC_NO_FONT_LOADING */ 2808 2809#ifndef SC_NO_PALETTE_LOADING 2810 vidd_save_palette(sc->adp, sc->palette); 2811#endif 2812 2813#ifdef DEV_SPLASH 2814 if (!(sc->flags & SC_SPLASH_SCRN)) { 2815 /* we are ready to put up the splash image! */ 2816 splash_init(sc->adp, scsplash_callback, sc); 2817 sc->flags |= SC_SPLASH_SCRN; 2818 } 2819#endif 2820 } 2821 2822 /* the rest is not necessary, if we have done it once */ 2823 if (sc->flags & SC_INIT_DONE) 2824 return; 2825 2826 /* initialize mapscrn arrays to a one to one map */ 2827 for (i = 0; i < sizeof(sc->scr_map); i++) 2828 sc->scr_map[i] = sc->scr_rmap[i] = i; 2829#ifdef PC98 2830 sc->scr_map[0x5c] = (u_char)0xfc; /* for backslash */ 2831#endif 2832 2833 sc->flags |= SC_INIT_DONE; 2834} 2835 2836static void 2837scterm(int unit, int flags) 2838{ 2839 sc_softc_t *sc; 2840 scr_stat *scp; 2841 2842 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); 2843 if (sc == NULL) 2844 return; /* shouldn't happen */ 2845 2846#ifdef DEV_SPLASH 2847 /* this console is no longer available for the splash screen */ 2848 if (sc->flags & SC_SPLASH_SCRN) { 2849 splash_term(sc->adp); 2850 sc->flags &= ~SC_SPLASH_SCRN; 2851 } 2852#endif 2853 2854#if 0 /* XXX */ 2855 /* move the hardware cursor to the upper-left corner */ 2856 vidd_set_hw_cursor(sc->adp, 0, 0); 2857#endif 2858 2859 /* release the keyboard and the video card */ 2860 if (sc->keyboard >= 0) 2861 kbd_release(sc->kbd, &sc->keyboard); 2862 if (sc->adapter >= 0) 2863 vid_release(sc->adp, &sc->adapter); 2864 2865 /* stop the terminal emulator, if any */ 2866 scp = sc_get_stat(sc->dev[0]); 2867 if (scp->tsw) 2868 (*scp->tsw->te_term)(scp, &scp->ts); 2869 if (scp->ts != NULL) 2870 free(scp->ts, M_DEVBUF); 2871 mtx_destroy(&scp->scr_lock); 2872 2873 /* clear the structure */ 2874 if (!(flags & SC_KERNEL_CONSOLE)) { 2875 /* XXX: We need delete_dev() for this */ 2876 free(sc->dev, M_DEVBUF); 2877#if 0 2878 /* XXX: We need a ttyunregister for this */ 2879 free(sc->tty, M_DEVBUF); 2880#endif 2881#ifndef SC_NO_FONT_LOADING 2882 free(sc->font_8, M_DEVBUF); 2883 free(sc->font_14, M_DEVBUF); 2884 free(sc->font_16, M_DEVBUF); 2885#endif 2886 /* XXX vtb, history */ 2887 } 2888 bzero(sc, sizeof(*sc)); 2889 sc->keyboard = -1; 2890 sc->adapter = -1; 2891} 2892 2893static void 2894scshutdown(void *arg, int howto) 2895{ 2896 /* assert(sc_console != NULL) */ 2897 2898 sc_touch_scrn_saver(); 2899 if (!cold && sc_console 2900 && sc_console->sc->cur_scp->smode.mode == VT_AUTO 2901 && sc_console->smode.mode == VT_AUTO) 2902 sc_switch_scr(sc_console->sc, sc_console->index); 2903 shutdown_in_progress = TRUE; 2904} 2905 2906int 2907sc_clean_up(scr_stat *scp) 2908{ 2909#ifdef DEV_SPLASH 2910 int error; 2911#endif 2912 2913 if (scp->sc->flags & SC_SCRN_BLANKED) { 2914 sc_touch_scrn_saver(); 2915#ifdef DEV_SPLASH 2916 if ((error = wait_scrn_saver_stop(scp->sc))) 2917 return error; 2918#endif 2919 } 2920 scp->status |= MOUSE_HIDDEN; 2921 sc_remove_mouse_image(scp); 2922 sc_remove_cutmarking(scp); 2923 return 0; 2924} 2925 2926void 2927sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard) 2928{ 2929 sc_vtb_t new; 2930 sc_vtb_t old; 2931 2932 old = scp->vtb; 2933 sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait); 2934 if (!discard && (old.vtb_flags & VTB_VALID)) { 2935 /* retain the current cursor position and buffer contants */ 2936 scp->cursor_oldpos = scp->cursor_pos; 2937 /* 2938 * This works only if the old buffer has the same size as or larger 2939 * than the new one. XXX 2940 */ 2941 sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize); 2942 scp->vtb = new; 2943 } else { 2944 scp->vtb = new; 2945 sc_vtb_destroy(&old); 2946 } 2947 2948#ifndef SC_NO_SYSMOUSE 2949 /* move the mouse cursor at the center of the screen */ 2950 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); 2951#endif 2952} 2953 2954static scr_stat 2955*alloc_scp(sc_softc_t *sc, int vty) 2956{ 2957 scr_stat *scp; 2958 2959 /* assert(sc_malloc) */ 2960 2961 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK); 2962 init_scp(sc, vty, scp); 2963 2964 sc_alloc_scr_buffer(scp, TRUE, TRUE); 2965 if (sc_init_emulator(scp, SC_DFLT_TERM)) 2966 sc_init_emulator(scp, "*"); 2967 2968#ifndef SC_NO_CUTPASTE 2969 sc_alloc_cut_buffer(scp, TRUE); 2970#endif 2971 2972#ifndef SC_NO_HISTORY 2973 sc_alloc_history_buffer(scp, 0, 0, TRUE); 2974#endif 2975 2976 return scp; 2977} 2978 2979static void 2980init_scp(sc_softc_t *sc, int vty, scr_stat *scp) 2981{ 2982 video_info_t info; 2983 2984 bzero(scp, sizeof(*scp)); 2985 2986 scp->index = vty; 2987 scp->sc = sc; 2988 scp->status = 0; 2989 scp->mode = sc->initial_mode; 2990 vidd_get_info(sc->adp, scp->mode, &info); 2991 if (info.vi_flags & V_INFO_GRAPHICS) { 2992 scp->status |= GRAPHICS_MODE; 2993 scp->xpixel = info.vi_width; 2994 scp->ypixel = info.vi_height; 2995 scp->xsize = info.vi_width/info.vi_cwidth; 2996 scp->ysize = info.vi_height/info.vi_cheight; 2997 scp->font_size = 0; 2998 scp->font = NULL; 2999 } else { 3000 scp->xsize = info.vi_width; 3001 scp->ysize = info.vi_height; 3002 scp->xpixel = scp->xsize*info.vi_cwidth; 3003 scp->ypixel = scp->ysize*info.vi_cheight; 3004 } 3005 3006 scp->font_size = info.vi_cheight; 3007 scp->font_width = info.vi_cwidth; 3008 if (info.vi_cheight < 14) { 3009#ifndef SC_NO_FONT_LOADING 3010 scp->font = sc->font_8; 3011#else 3012 scp->font = NULL; 3013#endif 3014 } else if (info.vi_cheight >= 16) { 3015#ifndef SC_NO_FONT_LOADING 3016 scp->font = sc->font_16; 3017#else 3018 scp->font = NULL; 3019#endif 3020 } else { 3021#ifndef SC_NO_FONT_LOADING 3022 scp->font = sc->font_14; 3023#else 3024 scp->font = NULL; 3025#endif 3026 } 3027 3028 sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE); 3029#ifndef __sparc64__ 3030 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE); 3031#endif 3032 scp->xoff = scp->yoff = 0; 3033 scp->xpos = scp->ypos = 0; 3034 scp->start = scp->xsize * scp->ysize - 1; 3035 scp->end = 0; 3036 scp->tsw = NULL; 3037 scp->ts = NULL; 3038 scp->rndr = NULL; 3039 scp->border = (SC_NORM_ATTR >> 4) & 0x0f; 3040 scp->curr_curs_attr = scp->dflt_curs_attr = sc->curs_attr; 3041 scp->mouse_cut_start = scp->xsize*scp->ysize; 3042 scp->mouse_cut_end = -1; 3043 scp->mouse_signal = 0; 3044 scp->mouse_pid = 0; 3045 scp->mouse_proc = NULL; 3046 scp->kbd_mode = K_XLATE; 3047 scp->bell_pitch = bios_value.bell_pitch; 3048 scp->bell_duration = BELL_DURATION; 3049 scp->status |= (bios_value.shift_state & NLKED); 3050 scp->status |= CURSOR_ENABLED | MOUSE_HIDDEN; 3051 scp->pid = 0; 3052 scp->proc = NULL; 3053 scp->smode.mode = VT_AUTO; 3054 scp->history = NULL; 3055 scp->history_pos = 0; 3056 scp->history_size = 0; 3057 3058 mtx_init(&scp->scr_lock, "scrlock", NULL, MTX_SPIN); 3059} 3060 3061int 3062sc_init_emulator(scr_stat *scp, char *name) 3063{ 3064 sc_term_sw_t *sw; 3065 sc_rndr_sw_t *rndr; 3066 void *p; 3067 int error; 3068 3069 if (name == NULL) /* if no name is given, use the current emulator */ 3070 sw = scp->tsw; 3071 else /* ...otherwise find the named emulator */ 3072 sw = sc_term_match(name); 3073 if (sw == NULL) 3074 return EINVAL; 3075 3076 rndr = NULL; 3077 if (strcmp(sw->te_renderer, "*") != 0) { 3078 rndr = sc_render_match(scp, sw->te_renderer, 3079 scp->status & (GRAPHICS_MODE | PIXEL_MODE)); 3080 } 3081 if (rndr == NULL) { 3082 rndr = sc_render_match(scp, scp->sc->adp->va_name, 3083 scp->status & (GRAPHICS_MODE | PIXEL_MODE)); 3084 if (rndr == NULL) 3085 return ENODEV; 3086 } 3087 3088 if (sw == scp->tsw) { 3089 error = (*sw->te_init)(scp, &scp->ts, SC_TE_WARM_INIT); 3090 scp->rndr = rndr; 3091 scp->rndr->init(scp); 3092 sc_clear_screen(scp); 3093 /* assert(error == 0); */ 3094 return error; 3095 } 3096 3097 if (sc_malloc && (sw->te_size > 0)) 3098 p = malloc(sw->te_size, M_DEVBUF, M_NOWAIT); 3099 else 3100 p = NULL; 3101 error = (*sw->te_init)(scp, &p, SC_TE_COLD_INIT); 3102 if (error) 3103 return error; 3104 3105 if (scp->tsw) 3106 (*scp->tsw->te_term)(scp, &scp->ts); 3107 if (scp->ts != NULL) 3108 free(scp->ts, M_DEVBUF); 3109 scp->tsw = sw; 3110 scp->ts = p; 3111 scp->rndr = rndr; 3112 scp->rndr->init(scp); 3113 3114 /* XXX */ 3115 (*sw->te_default_attr)(scp, user_default.std_color, user_default.rev_color); 3116 sc_clear_screen(scp); 3117 3118 return 0; 3119} 3120 3121/* 3122 * scgetc(flags) - get character from keyboard. 3123 * If flags & SCGETC_CN, then avoid harmful side effects. 3124 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else 3125 * return NOKEY if there is nothing there. 3126 */ 3127static u_int 3128scgetc(sc_softc_t *sc, u_int flags) 3129{ 3130 scr_stat *scp; 3131#ifndef SC_NO_HISTORY 3132 struct tty *tp; 3133#endif 3134 u_int c; 3135 int this_scr; 3136 int f; 3137 int i; 3138 3139 if (sc->kbd == NULL) 3140 return NOKEY; 3141 3142next_code: 3143#if 1 3144 /* I don't like this, but... XXX */ 3145 if (flags & SCGETC_CN) 3146 sccnupdate(sc->cur_scp); 3147#endif 3148 scp = sc->cur_scp; 3149 /* first see if there is something in the keyboard port */ 3150 for (;;) { 3151 c = kbdd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK)); 3152 if (c == ERRKEY) { 3153 if (!(flags & SCGETC_CN)) 3154 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); 3155 } else if (c == NOKEY) 3156 return c; 3157 else 3158 break; 3159 } 3160 3161 /* make screensaver happy */ 3162 if (!(c & RELKEY)) 3163 sc_touch_scrn_saver(); 3164 3165 if (!(flags & SCGETC_CN)) 3166 random_harvest(&c, sizeof(c), 1, 0, RANDOM_KEYBOARD); 3167 3168 if (scp->kbd_mode != K_XLATE) 3169 return KEYCHAR(c); 3170 3171 /* if scroll-lock pressed allow history browsing */ 3172 if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) { 3173 3174 scp->status &= ~CURSOR_ENABLED; 3175 sc_remove_cursor_image(scp); 3176 3177#ifndef SC_NO_HISTORY 3178 if (!(scp->status & BUFFER_SAVED)) { 3179 scp->status |= BUFFER_SAVED; 3180 sc_hist_save(scp); 3181 } 3182 switch (c) { 3183 /* FIXME: key codes */ 3184 case SPCLKEY | FKEY | F(49): /* home key */ 3185 sc_remove_cutmarking(scp); 3186 sc_hist_home(scp); 3187 goto next_code; 3188 3189 case SPCLKEY | FKEY | F(57): /* end key */ 3190 sc_remove_cutmarking(scp); 3191 sc_hist_end(scp); 3192 goto next_code; 3193 3194 case SPCLKEY | FKEY | F(50): /* up arrow key */ 3195 sc_remove_cutmarking(scp); 3196 if (sc_hist_up_line(scp)) 3197 if (!(flags & SCGETC_CN)) 3198 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); 3199 goto next_code; 3200 3201 case SPCLKEY | FKEY | F(58): /* down arrow key */ 3202 sc_remove_cutmarking(scp); 3203 if (sc_hist_down_line(scp)) 3204 if (!(flags & SCGETC_CN)) 3205 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); 3206 goto next_code; 3207 3208 case SPCLKEY | FKEY | F(51): /* page up key */ 3209 sc_remove_cutmarking(scp); 3210 for (i=0; i<scp->ysize; i++) 3211 if (sc_hist_up_line(scp)) { 3212 if (!(flags & SCGETC_CN)) 3213 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); 3214 break; 3215 } 3216 goto next_code; 3217 3218 case SPCLKEY | FKEY | F(59): /* page down key */ 3219 sc_remove_cutmarking(scp); 3220 for (i=0; i<scp->ysize; i++) 3221 if (sc_hist_down_line(scp)) { 3222 if (!(flags & SCGETC_CN)) 3223 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); 3224 break; 3225 } 3226 goto next_code; 3227 } 3228#endif /* SC_NO_HISTORY */ 3229 } 3230 3231 /* 3232 * Process and consume special keys here. Return a plain char code 3233 * or a char code with the META flag or a function key code. 3234 */ 3235 if (c & RELKEY) { 3236 /* key released */ 3237 /* goto next_code */ 3238 } else { 3239 /* key pressed */ 3240 if (c & SPCLKEY) { 3241 c &= ~SPCLKEY; 3242 switch (KEYCHAR(c)) { 3243 /* LOCKING KEYS */ 3244 case NLK: case CLK: case ALK: 3245 break; 3246 case SLK: 3247 kbdd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f); 3248 if (f & SLKED) { 3249 scp->status |= SLKED; 3250 } else { 3251 if (scp->status & SLKED) { 3252 scp->status &= ~SLKED; 3253#ifndef SC_NO_HISTORY 3254 if (scp->status & BUFFER_SAVED) { 3255 if (!sc_hist_restore(scp)) 3256 sc_remove_cutmarking(scp); 3257 scp->status &= ~BUFFER_SAVED; 3258 scp->status |= CURSOR_ENABLED; 3259 sc_draw_cursor_image(scp); 3260 } 3261 tp = SC_DEV(sc, scp->index); 3262 if (!kdb_active && tty_opened(tp)) 3263 sctty_outwakeup(tp); 3264#endif 3265 } 3266 } 3267 break; 3268 3269 case PASTE: 3270#ifndef SC_NO_CUTPASTE 3271 sc_mouse_paste(scp); 3272#endif 3273 break; 3274 3275 /* NON-LOCKING KEYS */ 3276 case NOP: 3277 case LSH: case RSH: case LCTR: case RCTR: 3278 case LALT: case RALT: case ASH: case META: 3279 break; 3280 3281 case BTAB: 3282 if (!(sc->flags & SC_SCRN_BLANKED)) 3283 return c; 3284 break; 3285 3286 case SPSC: 3287#ifdef DEV_SPLASH 3288 /* force activatation/deactivation of the screen saver */ 3289 if (!(sc->flags & SC_SCRN_BLANKED)) { 3290 run_scrn_saver = TRUE; 3291 sc->scrn_time_stamp -= scrn_blank_time; 3292 } 3293 if (cold) { 3294 /* 3295 * While devices are being probed, the screen saver need 3296 * to be invoked explictly. XXX 3297 */ 3298 if (sc->flags & SC_SCRN_BLANKED) { 3299 scsplash_stick(FALSE); 3300 stop_scrn_saver(sc, current_saver); 3301 } else { 3302 if (!ISGRAPHSC(scp)) { 3303 scsplash_stick(TRUE); 3304 (*current_saver)(sc, TRUE); 3305 } 3306 } 3307 } 3308#endif /* DEV_SPLASH */ 3309 break; 3310 3311 case RBT: 3312#ifndef SC_DISABLE_REBOOT 3313 if (enable_reboot) 3314 shutdown_nice(0); 3315#endif 3316 break; 3317 3318 case HALT: 3319#ifndef SC_DISABLE_REBOOT 3320 if (enable_reboot) 3321 shutdown_nice(RB_HALT); 3322#endif 3323 break; 3324 3325 case PDWN: 3326#ifndef SC_DISABLE_REBOOT 3327 if (enable_reboot) 3328 shutdown_nice(RB_HALT|RB_POWEROFF); 3329#endif 3330 break; 3331 3332 case SUSP: 3333 power_pm_suspend(POWER_SLEEP_STATE_SUSPEND); 3334 break; 3335 case STBY: 3336 power_pm_suspend(POWER_SLEEP_STATE_STANDBY); 3337 break; 3338 3339 case DBG: 3340#ifndef SC_DISABLE_KDBKEY 3341 if (enable_kdbkey) 3342 kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 3343#endif 3344 break; 3345 3346 case PNC: 3347 if (enable_panic_key) 3348 panic("Forced by the panic key"); 3349 break; 3350 3351 case NEXT: 3352 this_scr = scp->index; 3353 for (i = (this_scr - sc->first_vty + 1)%sc->vtys; 3354 sc->first_vty + i != this_scr; 3355 i = (i + 1)%sc->vtys) { 3356 struct tty *tp = SC_DEV(sc, sc->first_vty + i); 3357 if (tty_opened(tp)) { 3358 sc_switch_scr(scp->sc, sc->first_vty + i); 3359 break; 3360 } 3361 } 3362 break; 3363 3364 case PREV: 3365 this_scr = scp->index; 3366 for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys; 3367 sc->first_vty + i != this_scr; 3368 i = (i + sc->vtys - 1)%sc->vtys) { 3369 struct tty *tp = SC_DEV(sc, sc->first_vty + i); 3370 if (tty_opened(tp)) { 3371 sc_switch_scr(scp->sc, sc->first_vty + i); 3372 break; 3373 } 3374 } 3375 break; 3376 3377 default: 3378 if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) { 3379 sc_switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR); 3380 break; 3381 } 3382 /* assert(c & FKEY) */ 3383 if (!(sc->flags & SC_SCRN_BLANKED)) 3384 return c; 3385 break; 3386 } 3387 /* goto next_code */ 3388 } else { 3389 /* regular keys (maybe MKEY is set) */ 3390 if (!(sc->flags & SC_SCRN_BLANKED)) 3391 return c; 3392 } 3393 } 3394 3395 goto next_code; 3396} 3397 3398static int 3399sctty_mmap(struct tty *tp, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 3400{ 3401 scr_stat *scp; 3402 3403 scp = sc_get_stat(tp); 3404 if (scp != scp->sc->cur_scp) 3405 return -1; 3406 return vidd_mmap(scp->sc->adp, offset, paddr, nprot); 3407} 3408 3409static int 3410save_kbd_state(scr_stat *scp) 3411{ 3412 int state; 3413 int error; 3414 3415 error = kbdd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state); 3416 if (error == ENOIOCTL) 3417 error = ENODEV; 3418 if (error == 0) { 3419 scp->status &= ~LOCK_MASK; 3420 scp->status |= state; 3421 } 3422 return error; 3423} 3424 3425static int 3426update_kbd_state(scr_stat *scp, int new_bits, int mask) 3427{ 3428 int state; 3429 int error; 3430 3431 if (mask != LOCK_MASK) { 3432 error = kbdd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state); 3433 if (error == ENOIOCTL) 3434 error = ENODEV; 3435 if (error) 3436 return error; 3437 state &= ~mask; 3438 state |= new_bits & mask; 3439 } else { 3440 state = new_bits & LOCK_MASK; 3441 } 3442 error = kbdd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state); 3443 if (error == ENOIOCTL) 3444 error = ENODEV; 3445 return error; 3446} 3447 3448static int 3449update_kbd_leds(scr_stat *scp, int which) 3450{ 3451 int error; 3452 3453 which &= LOCK_MASK; 3454 error = kbdd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which); 3455 if (error == ENOIOCTL) 3456 error = ENODEV; 3457 return error; 3458} 3459 3460int 3461set_mode(scr_stat *scp) 3462{ 3463 video_info_t info; 3464 3465 /* reject unsupported mode */ 3466 if (vidd_get_info(scp->sc->adp, scp->mode, &info)) 3467 return 1; 3468 3469 /* if this vty is not currently showing, do nothing */ 3470 if (scp != scp->sc->cur_scp) 3471 return 0; 3472 3473 /* setup video hardware for the given mode */ 3474 vidd_set_mode(scp->sc->adp, scp->mode); 3475 scp->rndr->init(scp); 3476#ifndef __sparc64__ 3477 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, 3478 (void *)scp->sc->adp->va_window, FALSE); 3479#endif 3480 3481#ifndef SC_NO_FONT_LOADING 3482 /* load appropriate font */ 3483 if (!(scp->status & GRAPHICS_MODE)) { 3484 if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) { 3485 if (scp->font_size < 14) { 3486 if (scp->sc->fonts_loaded & FONT_8) 3487 sc_load_font(scp, 0, 8, 8, scp->sc->font_8, 0, 256); 3488 } else if (scp->font_size >= 16) { 3489 if (scp->sc->fonts_loaded & FONT_16) 3490 sc_load_font(scp, 0, 16, 8, scp->sc->font_16, 0, 256); 3491 } else { 3492 if (scp->sc->fonts_loaded & FONT_14) 3493 sc_load_font(scp, 0, 14, 8, scp->sc->font_14, 0, 256); 3494 } 3495 /* 3496 * FONT KLUDGE: 3497 * This is an interim kludge to display correct font. 3498 * Always use the font page #0 on the video plane 2. 3499 * Somehow we cannot show the font in other font pages on 3500 * some video cards... XXX 3501 */ 3502 sc_show_font(scp, 0); 3503 } 3504 mark_all(scp); 3505 } 3506#endif /* !SC_NO_FONT_LOADING */ 3507 3508 sc_set_border(scp, scp->border); 3509 sc_set_cursor_image(scp); 3510 3511 return 0; 3512} 3513 3514void 3515sc_set_border(scr_stat *scp, int color) 3516{ 3517 SC_VIDEO_LOCK(scp->sc); 3518 (*scp->rndr->draw_border)(scp, color); 3519 SC_VIDEO_UNLOCK(scp->sc); 3520} 3521 3522#ifndef SC_NO_FONT_LOADING 3523void 3524sc_load_font(scr_stat *scp, int page, int size, int width, u_char *buf, 3525 int base, int count) 3526{ 3527 sc_softc_t *sc; 3528 3529 sc = scp->sc; 3530 sc->font_loading_in_progress = TRUE; 3531 vidd_load_font(sc->adp, page, size, width, buf, base, count); 3532 sc->font_loading_in_progress = FALSE; 3533} 3534 3535void 3536sc_save_font(scr_stat *scp, int page, int size, int width, u_char *buf, 3537 int base, int count) 3538{ 3539 sc_softc_t *sc; 3540 3541 sc = scp->sc; 3542 sc->font_loading_in_progress = TRUE; 3543 vidd_save_font(sc->adp, page, size, width, buf, base, count); 3544 sc->font_loading_in_progress = FALSE; 3545} 3546 3547void 3548sc_show_font(scr_stat *scp, int page) 3549{ 3550 vidd_show_font(scp->sc->adp, page); 3551} 3552#endif /* !SC_NO_FONT_LOADING */ 3553 3554void 3555sc_paste(scr_stat *scp, const u_char *p, int count) 3556{ 3557 struct tty *tp; 3558 u_char *rmap; 3559 3560 tp = SC_DEV(scp->sc, scp->sc->cur_scp->index); 3561 if (!tty_opened(tp)) 3562 return; 3563 rmap = scp->sc->scr_rmap; 3564 for (; count > 0; --count) 3565 ttydisc_rint(tp, rmap[*p++], 0); 3566 ttydisc_rint_done(tp); 3567} 3568 3569void 3570sc_respond(scr_stat *scp, const u_char *p, int count) 3571{ 3572 struct tty *tp; 3573 3574 tp = SC_DEV(scp->sc, scp->sc->cur_scp->index); 3575 if (!tty_opened(tp)) 3576 return; 3577 for (; count > 0; --count) 3578 ttydisc_rint(tp, *p++, 0); 3579#if 0 3580 /* XXX: we can't call ttydisc_rint_done() here! */ 3581 ttydisc_rint_done(tp); 3582#endif 3583} 3584 3585void 3586sc_bell(scr_stat *scp, int pitch, int duration) 3587{ 3588 if (cold || shutdown_in_progress || !enable_bell) 3589 return; 3590 3591 if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL)) 3592 return; 3593 3594 if (scp->sc->flags & SC_VISUAL_BELL) { 3595 if (scp->sc->blink_in_progress) 3596 return; 3597 scp->sc->blink_in_progress = 3; 3598 if (scp != scp->sc->cur_scp) 3599 scp->sc->blink_in_progress += 2; 3600 blink_screen(scp->sc->cur_scp); 3601 } else if (duration != 0 && pitch != 0) { 3602 if (scp != scp->sc->cur_scp) 3603 pitch *= 2; 3604 sysbeep(1193182 / pitch, duration); 3605 } 3606} 3607 3608static void 3609blink_screen(void *arg) 3610{ 3611 scr_stat *scp = arg; 3612 struct tty *tp; 3613 3614 if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) { 3615 scp->sc->blink_in_progress = 0; 3616 mark_all(scp); 3617 tp = SC_DEV(scp->sc, scp->index); 3618 if (tty_opened(tp)) 3619 sctty_outwakeup(tp); 3620 if (scp->sc->delayed_next_scr) 3621 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1); 3622 } 3623 else { 3624 (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize, 3625 scp->sc->blink_in_progress & 1); 3626 scp->sc->blink_in_progress--; 3627 timeout(blink_screen, scp, hz / 10); 3628 } 3629} 3630 3631/* 3632 * Until sc_attach_unit() gets called no dev structures will be available 3633 * to store the per-screen current status. This is the case when the 3634 * kernel is initially booting and needs access to its console. During 3635 * this early phase of booting the console's current status is kept in 3636 * one statically defined scr_stat structure, and any pointers to the 3637 * dev structures will be NULL. 3638 */ 3639 3640static scr_stat * 3641sc_get_stat(struct tty *tp) 3642{ 3643 if (tp == NULL) 3644 return (&main_console); 3645 return (SC_STAT(tp)); 3646} 3647 3648/* 3649 * Allocate active keyboard. Try to allocate "kbdmux" keyboard first, and, 3650 * if found, add all non-busy keyboards to "kbdmux". Otherwise look for 3651 * any keyboard. 3652 */ 3653 3654static int 3655sc_allocate_keyboard(sc_softc_t *sc, int unit) 3656{ 3657 int idx0, idx; 3658 keyboard_t *k0, *k; 3659 keyboard_info_t ki; 3660 3661 idx0 = kbd_allocate("kbdmux", -1, (void *)&sc->keyboard, sckbdevent, sc); 3662 if (idx0 != -1) { 3663 k0 = kbd_get_keyboard(idx0); 3664 3665 for (idx = kbd_find_keyboard2("*", -1, 0); 3666 idx != -1; 3667 idx = kbd_find_keyboard2("*", -1, idx + 1)) { 3668 k = kbd_get_keyboard(idx); 3669 3670 if (idx == idx0 || KBD_IS_BUSY(k)) 3671 continue; 3672 3673 bzero(&ki, sizeof(ki)); 3674 strcpy(ki.kb_name, k->kb_name); 3675 ki.kb_unit = k->kb_unit; 3676 3677 kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 3678 } 3679 } else 3680 idx0 = kbd_allocate("*", unit, (void *)&sc->keyboard, sckbdevent, sc); 3681 3682 return (idx0); 3683} 3684