vt(4): Use power_{suspend,resume} event handlers to implement

suspend/resume

The goal is to avoid that the vt(4) resume happens before the video
display is resumed. The original patch was provided by Andriy Gapon.

This new patch registers the handlers in vt_upgrade(). This is done
once, thanks to the VDF_ASYNC flag. I abused this flag because it was
already abused by the keyboard allocation. The event handlers then call
the backend if it provides callbacks for suspend/resume.

Differential Revision:	https://reviews.freebsd.org/D1004
On behalf of:	dumbbell
MFC after:	2 weeks
This commit is contained in:
Andriy Gapon 2015-01-27 15:28:46 +00:00
parent cda374fe00
commit 6dfa4578d6
5 changed files with 61 additions and 34 deletions

View File

@ -332,22 +332,6 @@ fbd_detach(device_t dev)
return (err);
}
static int
fbd_suspend(device_t dev)
{
vt_fb_suspend();
return (bus_generic_suspend(dev));
}
static int
fbd_resume(device_t dev)
{
vt_fb_resume();
return (bus_generic_resume(dev));
}
static device_method_t fbd_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fbd_probe),
@ -355,8 +339,6 @@ static device_method_t fbd_methods[] = {
DEVMETHOD(device_detach, fbd_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, fbd_suspend),
DEVMETHOD(device_resume, fbd_resume),
{ 0, 0 }
};

View File

@ -53,6 +53,8 @@ static struct vt_driver vt_fb_driver = {
.vd_priority = VD_PRIORITY_GENERIC+10,
.vd_fb_ioctl = vt_fb_ioctl,
.vd_fb_mmap = vt_fb_mmap,
.vd_suspend = vt_fb_suspend,
.vd_resume = vt_fb_resume,
};
VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
@ -450,15 +452,15 @@ vt_fb_attach(struct fb_info *info)
}
void
vt_fb_resume(void)
vt_fb_suspend(struct vt_device *vd)
{
vt_resume();
vt_suspend(vd);
}
void
vt_fb_suspend(void)
vt_fb_resume(struct vt_device *vd)
{
vt_suspend();
vt_resume(vd);
}

View File

@ -33,8 +33,8 @@
#define _DEV_VT_HW_FB_VT_FB_H_
/* Generic framebuffer interface call vt_fb_attach to init VT(9) */
int vt_fb_attach(struct fb_info *info);
void vt_fb_resume(void);
void vt_fb_suspend(void);
void vt_fb_resume(struct vt_device *vd);
void vt_fb_suspend(struct vt_device *vd);
vd_init_t vt_fb_init;
vd_blank_t vt_fb_blank;

View File

@ -90,8 +90,6 @@ SYSCTL_INT(_kern_vt, OID_AUTO, _name, CTLFLAG_RWTUN, &vt_##_name, _default,\
struct vt_driver;
void vt_allocate(struct vt_driver *, void *);
void vt_resume(void);
void vt_suspend(void);
typedef unsigned int vt_axis_t;
@ -162,6 +160,9 @@ struct vt_device {
#define VD_PASTEBUFSZ(vd) ((vd)->vd_pastebuf.vpb_bufsz)
#define VD_PASTEBUFLEN(vd) ((vd)->vd_pastebuf.vpb_len)
void vt_resume(struct vt_device *vd);
void vt_suspend(struct vt_device *vd);
/*
* Per-window terminal screen buffer.
*
@ -314,6 +315,8 @@ typedef int vd_fb_mmap_t(struct vt_device *, vm_ooffset_t, vm_paddr_t *, int,
typedef void vd_drawrect_t(struct vt_device *, int, int, int, int, int,
term_color_t);
typedef void vd_setpixel_t(struct vt_device *, int, int, term_color_t);
typedef void vd_suspend_t(struct vt_device *);
typedef void vd_resume_t(struct vt_device *);
struct vt_driver {
char vd_name[16];
@ -337,6 +340,10 @@ struct vt_driver {
/* Update display setting on vt switch. */
vd_postswitch_t *vd_postswitch;
/* Suspend/resume handlers. */
vd_suspend_t *vd_suspend;
vd_resume_t *vd_resume;
/* Priority to know which one can override */
int vd_priority;
#define VD_PRIORITY_DUMB 10

View File

@ -167,6 +167,8 @@ static void vt_update_static(void *);
#ifndef SC_NO_CUTPASTE
static void vt_mouse_paste(void);
#endif
static void vt_suspend_handler(void *priv);
static void vt_resume_handler(void *priv);
SET_DECLARE(vt_drv_set, struct vt_driver);
@ -2552,6 +2554,12 @@ vt_upgrade(struct vt_device *vd)
vd->vd_flags |= VDF_ASYNC;
callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd);
vd->vd_timer_armed = 1;
/* Register suspend/resume handlers. */
EVENTHANDLER_REGISTER(power_suspend, vt_suspend_handler, vd,
EVENTHANDLER_PRI_ANY);
EVENTHANDLER_REGISTER(power_resume, vt_resume_handler, vd,
EVENTHANDLER_PRI_ANY);
}
VT_UNLOCK(vd);
@ -2655,26 +2663,54 @@ vt_allocate(struct vt_driver *drv, void *softc)
termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal);
}
void
vt_suspend()
static void
vt_suspend_handler(void *priv)
{
struct vt_device *vd;
vd = priv;
if (vd->vd_driver != NULL && vd->vd_driver->vd_suspend != NULL)
vd->vd_driver->vd_suspend(vd);
}
static void
vt_resume_handler(void *priv)
{
struct vt_device *vd;
vd = priv;
if (vd->vd_driver != NULL && vd->vd_driver->vd_resume != NULL)
vd->vd_driver->vd_resume(vd);
}
void
vt_suspend(struct vt_device *vd)
{
int error;
if (vt_suspendswitch == 0)
return;
/* Save current window. */
main_vd->vd_savedwindow = main_vd->vd_curwindow;
vd->vd_savedwindow = vd->vd_curwindow;
/* Ask holding process to free window and switch to console window */
vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]);
vt_proc_window_switch(vd->vd_windows[VT_CONSWINDOW]);
/* Wait for the window switch to complete. */
error = 0;
VT_LOCK(vd);
while (vd->vd_curwindow != vd->vd_windows[VT_CONSWINDOW] && error == 0)
error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
VT_UNLOCK(vd);
}
void
vt_resume()
vt_resume(struct vt_device *vd)
{
if (vt_suspendswitch == 0)
return;
/* Switch back to saved window */
if (main_vd->vd_savedwindow != NULL)
vt_proc_window_switch(main_vd->vd_savedwindow);
main_vd->vd_savedwindow = NULL;
if (vd->vd_savedwindow != NULL)
vt_proc_window_switch(vd->vd_savedwindow);
vd->vd_savedwindow = NULL;
}