diff options
Diffstat (limited to 'drivers/video/fbdev/hyperv_fb.c')
-rw-r--r-- | drivers/video/fbdev/hyperv_fb.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index e23392ec5af3..569e7562fa3d 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -224,6 +224,11 @@ struct hvfb_par { u32 pseudo_palette[16]; u8 init_buf[MAX_VMBUS_PKT_SIZE]; u8 recv_buf[MAX_VMBUS_PKT_SIZE]; + + /* If true, the VSC notifies the VSP on every framebuffer change */ + bool synchronous_fb; + + struct notifier_block hvfb_panic_nb; }; static uint screen_width = HVFB_WIDTH; @@ -532,6 +537,19 @@ static void hvfb_update_work(struct work_struct *w) schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY); } +static int hvfb_on_panic(struct notifier_block *nb, + unsigned long e, void *p) +{ + struct hvfb_par *par; + struct fb_info *info; + + par = container_of(nb, struct hvfb_par, hvfb_panic_nb); + par->synchronous_fb = true; + info = par->info; + synthvid_update(info); + + return NOTIFY_DONE; +} /* Framebuffer operation handlers */ @@ -582,14 +600,44 @@ static int hvfb_blank(int blank, struct fb_info *info) return 1; /* get fb_blank to set the colormap to all black */ } +static void hvfb_cfb_fillrect(struct fb_info *p, + const struct fb_fillrect *rect) +{ + struct hvfb_par *par = p->par; + + cfb_fillrect(p, rect); + if (par->synchronous_fb) + synthvid_update(p); +} + +static void hvfb_cfb_copyarea(struct fb_info *p, + const struct fb_copyarea *area) +{ + struct hvfb_par *par = p->par; + + cfb_copyarea(p, area); + if (par->synchronous_fb) + synthvid_update(p); +} + +static void hvfb_cfb_imageblit(struct fb_info *p, + const struct fb_image *image) +{ + struct hvfb_par *par = p->par; + + cfb_imageblit(p, image); + if (par->synchronous_fb) + synthvid_update(p); +} + static struct fb_ops hvfb_ops = { .owner = THIS_MODULE, .fb_check_var = hvfb_check_var, .fb_set_par = hvfb_set_par, .fb_setcolreg = hvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = hvfb_cfb_fillrect, + .fb_copyarea = hvfb_cfb_copyarea, + .fb_imageblit = hvfb_cfb_imageblit, .fb_blank = hvfb_blank, }; @@ -801,6 +849,11 @@ static int hvfb_probe(struct hv_device *hdev, par->fb_ready = true; + par->synchronous_fb = false; + par->hvfb_panic_nb.notifier_call = hvfb_on_panic; + atomic_notifier_chain_register(&panic_notifier_list, + &par->hvfb_panic_nb); + return 0; error: @@ -820,6 +873,9 @@ static int hvfb_remove(struct hv_device *hdev) struct fb_info *info = hv_get_drvdata(hdev); struct hvfb_par *par = info->par; + atomic_notifier_chain_unregister(&panic_notifier_list, + &par->hvfb_panic_nb); + par->update = false; par->fb_ready = false; |