mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-25 11:37:56 +00:00
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
This commit is contained in:
parent
be440d689d
commit
76e2f97656
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=279488
@ -937,19 +937,21 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
||||
info->fb_priv = sc;
|
||||
info->enter = &vt_kms_postswitch;
|
||||
|
||||
kdev = fb_helper->dev->device;
|
||||
info->fb_video_dev = device_get_parent(kdev);
|
||||
|
||||
/* set the fb pointer */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
|
||||
}
|
||||
|
||||
if (new_fb) {
|
||||
device_t fbd;
|
||||
int ret;
|
||||
|
||||
kdev = fb_helper->dev->device;
|
||||
fbd = device_add_child(kdev, "fbd", device_get_unit(kdev));
|
||||
if (fbd != NULL)
|
||||
ret = device_probe_and_attach(fbd);
|
||||
info->fb_fbd_dev = device_add_child(kdev, "fbd",
|
||||
device_get_unit(kdev));
|
||||
if (info->fb_fbd_dev != NULL)
|
||||
ret = device_probe_and_attach(info->fb_fbd_dev);
|
||||
else
|
||||
ret = ENODEV;
|
||||
#ifdef DEV_VT
|
||||
|
@ -291,6 +291,8 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
|
||||
|
||||
if (rfbdev->helper.fbdev) {
|
||||
info = rfbdev->helper.fbdev;
|
||||
if (info->fb_fbd_dev != NULL)
|
||||
device_delete_child(dev->device, info->fb_fbd_dev);
|
||||
free(info->fb_priv, DRM_MEM_KMS);
|
||||
free(info, DRM_MEM_KMS);
|
||||
}
|
||||
|
@ -263,6 +263,8 @@ fbd_unregister(struct fb_info* info)
|
||||
LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
|
||||
if (entry->fb_info == info) {
|
||||
LIST_REMOVE(entry, fb_list);
|
||||
if (LIST_EMPTY(&fb_list_head))
|
||||
vt_fb_detach(info);
|
||||
free(entry, M_DEVBUF);
|
||||
return (0);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
@ -2691,6 +2708,52 @@ vt_resume_handler(void *priv)
|
||||
vd->vd_driver->vd_resume(vd);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -128,6 +128,9 @@ struct fb_info {
|
||||
|
||||
struct cdev *fb_cdev;
|
||||
|
||||
device_t fb_fbd_dev; /* "fbd" device. */
|
||||
device_t fb_video_dev; /* Video adapter. */
|
||||
|
||||
fb_enter_t *enter;
|
||||
fb_leave_t *leave;
|
||||
fb_setblankmode_t *setblankmode;
|
||||
|
Loading…
Reference in New Issue
Block a user