summaryrefslogtreecommitdiffstats
path: root/sys/dev/vt/vt_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/vt/vt_core.c')
-rw-r--r--sys/dev/vt/vt_core.c258
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
OpenPOWER on IntegriCloud