summaryrefslogtreecommitdiffstats
path: root/sys/dev/vt
diff options
context:
space:
mode:
authordumbbell <dumbbell@FreeBSD.org>2015-03-01 12:54:22 +0000
committerdumbbell <dumbbell@FreeBSD.org>2015-03-01 12:54:22 +0000
commitdf193d50d144894127e95f3263e9462596a344d2 (patch)
tree4223e3d377fb373200c2dfa239b3c43e990ff76b /sys/dev/vt
parenta8e8986092752ebcae306387f3729a8425be26be (diff)
downloadFreeBSD-src-df193d50d144894127e95f3263e9462596a344d2.zip
FreeBSD-src-df193d50d144894127e95f3263e9462596a344d2.tar.gz
vt(4): Add support to "downgrade" from eg. vt_fb to vt_vga
The main purpose of this feature is to be able to unload a KMS driver. When going back from the current vt(4) backend to the previous backend, the previous backend is reinitialized with the special VDF_DOWNGRADE flag set. Then the current driver is terminated with the new "vd_fini" callback. In the case of vt_fb and vt_vga, this allows the former to pass the vgapci device vt_fb used to vt_vga so the device can be rePOSTed. Differential Revision: https://reviews.freebsd.org/D687
Diffstat (limited to 'sys/dev/vt')
-rw-r--r--sys/dev/vt/hw/fb/vt_fb.c18
-rw-r--r--sys/dev/vt/hw/fb/vt_fb.h2
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c4
-rw-r--r--sys/dev/vt/vt.h9
-rw-r--r--sys/dev/vt/vt_core.c113
5 files changed, 120 insertions, 26 deletions
diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c
index 5a0fe4f..5d38cc7 100644
--- a/sys/dev/vt/hw/fb/vt_fb.c
+++ b/sys/dev/vt/hw/fb/vt_fb.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
static struct vt_driver vt_fb_driver = {
.vd_name = "fb",
.vd_init = vt_fb_init,
+ .vd_fini = vt_fb_fini,
.vd_blank = vt_fb_blank,
.vd_bitblt_text = vt_fb_bitblt_text,
.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
@@ -419,6 +420,7 @@ vt_fb_init(struct vt_device *vd)
info = vd->vd_softc;
vd->vd_height = info->fb_height;
vd->vd_width = info->fb_width;
+ vd->vd_video_dev = info->fb_video_dev;
if (info->fb_size == 0)
return (CN_DEAD);
@@ -442,6 +444,13 @@ vt_fb_init(struct vt_device *vd)
return (CN_INTERNAL);
}
+void
+vt_fb_fini(struct vt_device *vd, void *softc)
+{
+
+ vd->vd_video_dev = NULL;
+}
+
int
vt_fb_attach(struct fb_info *info)
{
@@ -451,6 +460,15 @@ vt_fb_attach(struct fb_info *info)
return (0);
}
+int
+vt_fb_detach(struct fb_info *info)
+{
+
+ vt_deallocate(&vt_fb_driver, info);
+
+ return (0);
+}
+
void
vt_fb_suspend(struct vt_device *vd)
{
diff --git a/sys/dev/vt/hw/fb/vt_fb.h b/sys/dev/vt/hw/fb/vt_fb.h
index ac18cff..98ecefa 100644
--- a/sys/dev/vt/hw/fb/vt_fb.h
+++ b/sys/dev/vt/hw/fb/vt_fb.h
@@ -35,8 +35,10 @@
int vt_fb_attach(struct fb_info *info);
void vt_fb_resume(struct vt_device *vd);
void vt_fb_suspend(struct vt_device *vd);
+int vt_fb_detach(struct fb_info *info);
vd_init_t vt_fb_init;
+vd_fini_t vt_fb_fini;
vd_blank_t vt_fb_blank;
vd_bitblt_text_t vt_fb_bitblt_text;
vd_bitblt_bmp_t vt_fb_bitblt_bitmap;
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 43bad8e..e939fdd 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <dev/vt/vt.h>
#include <dev/vt/hw/vga/vt_vga_reg.h>
+#include <dev/pci/pcivar.h>
#include <machine/bus.h>
@@ -1213,6 +1214,9 @@ vga_init(struct vt_device *vd)
sc = vd->vd_softc;
textmode = 0;
+ if (vd->vd_flags & VDF_DOWNGRADE && vd->vd_video_dev != NULL)
+ vga_pci_repost(vd->vd_video_dev);
+
#if defined(__amd64__) || defined(__i386__)
sc->vga_fb_tag = X86_BUS_SPACE_MEM;
sc->vga_fb_handle = KERNBASE + VGA_MEM_BASE;
diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h
index 0ad8ab5..85c0345 100644
--- a/sys/dev/vt/vt.h
+++ b/sys/dev/vt/vt.h
@@ -89,7 +89,8 @@ SYSCTL_INT(_kern_vt, OID_AUTO, _name, CTLFLAG_RWTUN, &vt_##_name, _default,\
struct vt_driver;
-void vt_allocate(struct vt_driver *, void *);
+void vt_allocate(const struct vt_driver *, void *);
+void vt_deallocate(const struct vt_driver *, void *);
typedef unsigned int vt_axis_t;
@@ -124,6 +125,9 @@ struct vt_device {
struct vt_pastebuf vd_pastebuf; /* (?) Copy/paste buf. */
const struct vt_driver *vd_driver; /* (c) Graphics driver. */
void *vd_softc; /* (u) Driver data. */
+ const struct vt_driver *vd_prev_driver;/* (?) Previous driver. */
+ void *vd_prev_softc; /* (?) Previous driver data. */
+ device_t vd_video_dev; /* (?) Video adapter. */
#ifndef SC_NO_CUTPASTE
struct vt_mouse_cursor *vd_mcursor; /* (?) Cursor bitmap. */
term_color_t vd_mcursor_fg; /* (?) Cursor fg color. */
@@ -150,6 +154,7 @@ struct vt_device {
#define VDF_INITIALIZED 0x20 /* vtterm_cnprobe already done. */
#define VDF_MOUSECURSOR 0x40 /* Mouse cursor visible. */
#define VDF_QUIET_BELL 0x80 /* Disable bell. */
+#define VDF_DOWNGRADE 0x8000 /* The driver is being downgraded. */
int vd_keyboard; /* (G) Keyboard index. */
unsigned int vd_kbstate; /* (?) Device unit. */
unsigned int vd_unit; /* (c) Device unit. */
@@ -301,6 +306,7 @@ struct vt_window {
typedef int vd_init_t(struct vt_device *vd);
typedef int vd_probe_t(struct vt_device *vd);
+typedef void vd_fini_t(struct vt_device *vd, void *softc);
typedef void vd_postswitch_t(struct vt_device *vd);
typedef void vd_blank_t(struct vt_device *vd, term_color_t color);
typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw,
@@ -323,6 +329,7 @@ struct vt_driver {
/* Console attachment. */
vd_probe_t *vd_probe;
vd_init_t *vd_init;
+ vd_fini_t *vd_fini;
/* Drawing. */
vd_blank_t *vd_blank;
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 9627849..1f8731e 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -180,6 +180,8 @@ static struct vt_window vt_conswindow;
static struct vt_device vt_consdev = {
.vd_driver = NULL,
.vd_softc = NULL,
+ .vd_prev_driver = NULL,
+ .vd_prev_softc = NULL,
.vd_flags = VDF_INVALID,
.vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, },
.vd_curwindow = &vt_conswindow,
@@ -2598,31 +2600,11 @@ vt_resize(struct vt_device *vd)
}
}
-void
-vt_allocate(struct vt_driver *drv, void *softc)
+static void
+vt_replace_backend(const struct vt_driver *drv, void *softc)
{
struct vt_device *vd;
- if (!vty_enabled(VTY_VT))
- return;
-
- 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("VT: Driver priority %d too low. Current %d\n ",
- drv->vd_priority, main_vd->vd_driver->vd_priority);
- return;
- }
- printf("VT: Replacing driver \"%s\" with new \"%s\".\n",
- main_vd->vd_driver->vd_name, drv->vd_name);
- }
vd = main_vd;
if (vd->vd_flags & VDF_ASYNC) {
@@ -2644,9 +2626,44 @@ vt_allocate(struct vt_driver *drv, void *softc)
VT_LOCK(vd);
vd->vd_flags &= ~VDF_TEXTMODE;
- vd->vd_driver = drv;
- vd->vd_softc = softc;
- vd->vd_driver->vd_init(vd);
+ if (drv != NULL) {
+ /*
+ * We want to upgrade from the current driver to the
+ * given driver.
+ */
+
+ vd->vd_prev_driver = vd->vd_driver;
+ vd->vd_prev_softc = vd->vd_softc;
+ vd->vd_driver = drv;
+ vd->vd_softc = softc;
+
+ vd->vd_driver->vd_init(vd);
+ } else if (vd->vd_prev_driver != NULL && vd->vd_prev_softc != NULL) {
+ /*
+ * No driver given: we want to downgrade to the previous
+ * driver.
+ */
+ const struct vt_driver *old_drv;
+ void *old_softc;
+
+ old_drv = vd->vd_driver;
+ old_softc = vd->vd_softc;
+
+ vd->vd_driver = vd->vd_prev_driver;
+ vd->vd_softc = vd->vd_prev_softc;
+ vd->vd_prev_driver = NULL;
+ vd->vd_prev_softc = NULL;
+
+ vd->vd_flags |= VDF_DOWNGRADE;
+
+ vd->vd_driver->vd_init(vd);
+
+ if (old_drv->vd_fini)
+ old_drv->vd_fini(vd, old_softc);
+
+ vd->vd_flags &= ~VDF_DOWNGRADE;
+ }
+
VT_UNLOCK(vd);
/* Update windows sizes and initialize last items. */
@@ -2692,6 +2709,52 @@ vt_resume_handler(void *priv)
}
void
+vt_allocate(const struct vt_driver *drv, void *softc)
+{
+
+ if (!vty_enabled(VTY_VT))
+ return;
+
+ 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("VT: Driver priority %d too low. Current %d\n ",
+ drv->vd_priority, main_vd->vd_driver->vd_priority);
+ return;
+ }
+ printf("VT: Replacing driver \"%s\" with new \"%s\".\n",
+ main_vd->vd_driver->vd_name, drv->vd_name);
+ }
+
+ vt_replace_backend(drv, softc);
+}
+
+void
+vt_deallocate(const struct vt_driver *drv, void *softc)
+{
+
+ if (!vty_enabled(VTY_VT))
+ return;
+
+ if (main_vd->vd_prev_driver == NULL ||
+ main_vd->vd_driver != drv ||
+ main_vd->vd_softc != softc)
+ return;
+
+ printf("VT: Switching back from \"%s\" to \"%s\".\n",
+ main_vd->vd_driver->vd_name, main_vd->vd_prev_driver->vd_name);
+
+ vt_replace_backend(NULL, NULL);
+}
+
+void
vt_suspend(struct vt_device *vd)
{
int error;
OpenPOWER on IntegriCloud