diff options
Diffstat (limited to 'sys/dev/vt/vt_core.c')
-rw-r--r-- | sys/dev/vt/vt_core.c | 258 |
1 files changed, 194 insertions, 64 deletions
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index eb2843e..80aa777 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -120,9 +120,10 @@ VT_SYSCTL_INT(debug, 0, "vt(9) debug level"); VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend"); +static struct vt_device vt_consdev; static unsigned int vt_unit = 0; static MALLOC_DEFINE(M_VT, "vt", "vt device"); -struct vt_device *main_vd = NULL; +struct vt_device *main_vd = &vt_consdev; /* Boot logo. */ extern unsigned int vt_logo_width; @@ -144,6 +145,85 @@ static int vt_window_switch(struct vt_window *); static int vt_late_window_switch(struct vt_window *); static int vt_proc_alive(struct vt_window *); static void vt_resize(struct vt_device *); +static void vt_update_static(void *); + +SET_DECLARE(vt_drv_set, struct vt_driver); + +#define _VTDEFH MAX(100, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)) +#define _VTDEFW MAX(200, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)) + +static struct terminal vt_consterm; +static struct vt_window vt_conswindow; +static struct vt_device vt_consdev = { + .vd_driver = NULL, + .vd_softc = NULL, + .vd_flags = VDF_INVALID, + .vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, }, + .vd_curwindow = &vt_conswindow, + .vd_markedwin = NULL, + .vd_kbstate = 0, +}; +static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)]; +static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE]; +static struct vt_window vt_conswindow = { + .vw_number = VT_CONSWINDOW, + .vw_flags = VWF_CONSOLE, + .vw_buf = { + .vb_buffer = vt_constextbuf, + .vb_rows = vt_constextbufrows, + .vb_history_size = VBF_DEFAULT_HISTORY_SIZE, + .vb_curroffset = 0, + .vb_roffset = 0, + .vb_flags = VBF_STATIC, + .vb_mark_start = {.tp_row = 0, .tp_col = 0,}, + .vb_mark_end = {.tp_row = 0, .tp_col = 0,}, + .vb_scr_size = { + .tp_row = _VTDEFH, + .tp_col = _VTDEFW, + }, + }, + .vw_device = &vt_consdev, + .vw_terminal = &vt_consterm, + .vw_kbdmode = K_XLATE, +}; +static struct terminal vt_consterm = { + .tm_class = &vt_termclass, + .tm_softc = &vt_conswindow, + .tm_flags = TF_CONS, +}; +static struct consdev vt_consterm_consdev = { + .cn_ops = &termcn_cnops, + .cn_arg = &vt_consterm, + .cn_name = "ttyv0", +}; + +/* Add to set of consoles. */ +DATA_SET(cons_set, vt_consterm_consdev); + +/* + * Right after kmem is done to allow early drivers to use locking and allocate + * memory. + */ +SYSINIT(vt_update_static, SI_SUB_KMEM, SI_ORDER_ANY, vt_update_static, + &vt_consdev); +/* Delay until all devices attached, to not waste time. */ +SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade, + &vt_consdev); + +/* Initialize locks/mem depended members. */ +static void +vt_update_static(void *dummy) +{ + + if (main_vd->vd_driver != NULL) + printf("VT: running with driver \"%s\".\n", + main_vd->vd_driver->vd_name); + else + printf("VT: init without driver.\n"); + + mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); + cv_init(&main_vd->vd_winswitch, "vtwswt"); +} static void vt_switch_timer(void *arg) @@ -203,12 +283,12 @@ vt_proc_window_switch(struct vt_window *vw) struct vt_device *vd; int ret; - if (vw->vw_flags & VWF_VTYLOCK) - return (EBUSY); - vd = vw->vw_device; curvw = vd->vd_curwindow; + if (curvw->vw_flags & VWF_VTYLOCK) + return (EBUSY); + /* Ask current process permitions to switch away. */ if (curvw->vw_smode.mode == VT_PROCESS) { DPRINTF(30, "%s: VT_PROCESS ", __func__); @@ -556,11 +636,9 @@ vt_allocate_keyboard(struct vt_device *vd) keyboard_t *k0, *k; keyboard_info_t ki; - idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard, - vt_kbdevent, vd); - /* XXX: kb_token lost */ + idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd); vd->vd_keyboard = idx0; - if (idx0 != -1) { + if (idx0 >= 0) { DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); k0 = kbd_get_keyboard(idx0); @@ -580,8 +658,11 @@ vt_allocate_keyboard(struct vt_device *vd) } } else { DPRINTF(20, "%s: no kbdmux allocated\n", __func__); - idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard, - vt_kbdevent, vd); + idx0 = kbd_allocate("*", -1, vd, vt_kbdevent, vd); + if (idx0 < 0) { + DPRINTF(10, "%s: No keyboard found.\n", __func__); + return (-1); + } } DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); @@ -601,6 +682,22 @@ vtterm_bell(struct terminal *tm) } static void +vtterm_beep(struct terminal *tm, u_int param) +{ + u_int freq, period; + + if ((param == 0) || ((param & 0xffff) == 0)) { + vtterm_bell(tm); + return; + } + + period = ((param >> 16) & 0xffff) * hz / 1000; + freq = 1193182 / (param & 0xffff); + + sysbeep(freq, period); +} + +static void vtterm_cursor(struct terminal *tm, const term_pos_t *p) { struct vt_window *vw = tm->tm_softc; @@ -775,7 +872,7 @@ vt_flush(struct vt_device *vd) if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) == VDF_MOUSECURSOR) { m = &vt_default_mouse_pointer; - bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */ + bpl = (m->w + 7) >> 3; /* Bytes per source line. */ w = m->w; h = m->h; @@ -851,9 +948,11 @@ vtterm_splash(struct vt_device *vd) } #endif + static void vtterm_cnprobe(struct terminal *tm, struct consdev *cp) { + struct vt_driver *vtd, **vtdlist, *vtdbest = NULL; struct vt_window *vw = tm->tm_softc; struct vt_device *vd = vw->vw_device; struct winsize wsz; @@ -862,10 +961,27 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp) /* Initialization already done. */ return; - cp->cn_pri = vd->vd_driver->vd_init(vd); + SET_FOREACH(vtdlist, vt_drv_set) { + vtd = *vtdlist; + if (vtd->vd_probe == NULL) + continue; + if (vtd->vd_probe(vd) == CN_DEAD) + continue; + if ((vtdbest == NULL) || + (vtd->vd_priority > vtdbest->vd_priority)) + vtdbest = vtd; + } + if (vtdbest == NULL) { + cp->cn_pri = CN_DEAD; + vd->vd_flags |= VDF_DEAD; + } else { + vd->vd_driver = vtdbest; + cp->cn_pri = vd->vd_driver->vd_init(vd); + } + + /* Check if driver's vt_init return CN_DEAD. */ if (cp->cn_pri == CN_DEAD) { vd->vd_flags |= VDF_DEAD; - return; } /* Initialize any early-boot keyboard drivers */ @@ -875,6 +991,7 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp) vd->vd_windows[VT_CONSWINDOW] = vw; sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); + /* Attach default font if not in TEXTMODE. */ if (!(vd->vd_flags & VDF_TEXTMODE)) vw->vw_font = vtfont_ref(&vt_font_default); @@ -882,12 +999,12 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp) vt_winsize(vd, vw->vw_font, &wsz); terminal_set_winsize(tm, &wsz); + if (vtdbest != NULL) { #ifdef DEV_SPLASH - vtterm_splash(vd); + vtterm_splash(vd); #endif - - vd->vd_flags |= VDF_INITIALIZED; - main_vd = vd; + vd->vd_flags |= VDF_INITIALIZED; + } } static int @@ -1058,22 +1175,27 @@ static int vt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c) { struct vt_device *vd = vw->vw_device; - int l, r, t, b, w, h; + int x, y, off_x, off_y; if (vd->vd_driver->vd_drawrect == NULL) return (ENOTSUP); - w = vd->vd_width - 1; - h = vd->vd_height - 1; - l = vd->vd_offset.tp_col - 1; - r = w - l; - t = vd->vd_offset.tp_row - 1; - b = h - t; - - vd->vd_driver->vd_drawrect(vd, 0, 0, w, t, 1, c); /* Top bar. */ - vd->vd_driver->vd_drawrect(vd, 0, t, l, b, 1, c); /* Left bar. */ - vd->vd_driver->vd_drawrect(vd, r, t, w, b, 1, c); /* Right bar. */ - vd->vd_driver->vd_drawrect(vd, 0, b, w, h, 1, c); /* Bottom bar. */ + x = vd->vd_width - 1; + y = vd->vd_height - 1; + off_x = vd->vd_offset.tp_col; + off_y = vd->vd_offset.tp_row; + + /* Top bar. */ + if (off_y > 0) + vd->vd_driver->vd_drawrect(vd, 0, 0, x, off_y - 1, 1, c); + /* Left bar. */ + if (off_x > 0) + vd->vd_driver->vd_drawrect(vd, 0, off_y, off_x - 1, y - off_y, + 1, c); + /* Right bar. May be 1 pixel wider than necessary due to rounding. */ + vd->vd_driver->vd_drawrect(vd, x - off_x, off_y, x, y - off_y, 1, c); + /* Bottom bar. May be 1 mixel taller than necessary due to rounding. */ + vd->vd_driver->vd_drawrect(vd, 0, y - off_y, x, y, 1, c); return (0); } @@ -1636,7 +1758,7 @@ skip_thunk: #endif return (0); case KDMKTONE: /* sound the bell */ - /* TODO */ + vtterm_beep(tm, *(u_int *)data); return (0); case KIOCSOUND: /* make tone (*data) hz */ /* TODO */ @@ -1701,10 +1823,13 @@ skip_thunk: return (0); case VT_LOCKSWITCH: /* TODO: Check current state, switching can be in progress. */ - if ((*(int *)data) & 0x01) + if ((*(int *)data) == 0x01) vw->vw_flags |= VWF_VTYLOCK; - else + else if ((*(int *)data) == 0x02) vw->vw_flags &= ~VWF_VTYLOCK; + else + return (EINVAL); + return (0); case VT_OPENQRY: VT_LOCK(vd); for (i = 0; i < VT_MAXWINDOWS; i++) { @@ -1866,43 +1991,45 @@ vt_upgrade(struct vt_device *vd) struct vt_window *vw; unsigned int i; - /* Device didn't pass vd_init() or already upgraded. */ - if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD)) - return; - vd->vd_flags |= VDF_ASYNC; - - mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); - cv_init(&vd->vd_winswitch, "vtwswt"); - - /* Init 25 Hz timer. */ - callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); - for (i = 0; i < VT_MAXWINDOWS; i++) { vw = vd->vd_windows[i]; if (vw == NULL) { /* New window. */ vw = vt_allocate_window(vd, i); - } else if (vw->vw_flags & VWF_CONSOLE) { - /* For existing console window. */ - callout_init(&vw->vw_proc_dead_timer, 0); } - if (i == VT_CONSWINDOW) { - /* Console window. */ - EVENTHANDLER_REGISTER(shutdown_pre_sync, - vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); + if (!(vw->vw_flags & VWF_READY)) { + callout_init(&vw->vw_proc_dead_timer, 0); + terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); + vw->vw_flags |= VWF_READY; + if (vw->vw_flags & VWF_CONSOLE) { + /* For existing console window. */ + EVENTHANDLER_REGISTER(shutdown_pre_sync, + vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); + } } - terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); } + VT_LOCK(vd); if (vd->vd_curwindow == NULL) vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; + if (!(vd->vd_flags & VDF_ASYNC)) { /* Attach keyboard. */ vt_allocate_keyboard(vd); DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); - /* Start timer when everything ready. */ - callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); + /* Init 25 Hz timer. */ + callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); + + /* Start timer when everything ready. */ + vd->vd_flags |= VDF_ASYNC; + callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); + } + + VT_UNLOCK(vd); + + /* Refill settings with new sizes. */ + vt_resize(vd); } static void @@ -1913,9 +2040,11 @@ vt_resize(struct vt_device *vd) for (i = 0; i < VT_MAXWINDOWS; i++) { vw = vd->vd_windows[i]; + VT_LOCK(vd); /* Assign default font to window, if not textmode. */ if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) vw->vw_font = vtfont_ref(&vt_font_default); + VT_UNLOCK(vd); /* Resize terminal windows */ vt_change_font(vw, vw->vw_font); } @@ -1927,23 +2056,25 @@ vt_allocate(struct vt_driver *drv, void *softc) struct vt_device *vd; struct winsize wsz; - if (main_vd == NULL) { - main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); - printf("%s: VT initialize with new VT driver.\n", __func__); + if (main_vd->vd_driver == NULL) { + main_vd->vd_driver = drv; + printf("VT: initialize with new VT driver \"%s\".\n", + drv->vd_name); } else { /* * Check if have rights to replace current driver. For example: * it is bad idea to replace KMS driver with generic VGA one. */ if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { - printf("%s: Driver priority %d too low. Current %d\n ", - __func__, drv->vd_priority, - main_vd->vd_driver->vd_priority); + printf("VT: Driver priority %d too low. Current %d\n ", + drv->vd_priority, main_vd->vd_driver->vd_priority); return; } - printf("%s: Replace existing VT driver.\n", __func__); + printf("VT: Replacing driver \"%s\" with new \"%s\".\n", + main_vd->vd_driver->vd_name, drv->vd_name); } vd = main_vd; + VT_LOCK(vd); if (drv->vd_maskbitbltchr == NULL) drv->vd_maskbitbltchr = drv->vd_bitbltchr; @@ -1966,12 +2097,10 @@ vt_allocate(struct vt_driver *drv, void *softc) vd->vd_driver = drv; vd->vd_softc = softc; vd->vd_driver->vd_init(vd); + VT_UNLOCK(vd); vt_upgrade(vd); - /* Refill settings with new sizes. */ - vt_resize(vd); - #ifdef DEV_SPLASH if (vd->vd_flags & VDF_SPLASH) vtterm_splash(vd); @@ -1986,7 +2115,8 @@ vt_allocate(struct vt_driver *drv, void *softc) /* Update console window sizes to actual. */ vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz); - terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz); + terminal_set_winsize_blank(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, + &wsz, 0); } void |