diff options
author | Sebastien Jan <s-jan@ti.com> | 2011-06-22 20:40:27 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-06-22 20:40:27 +0100 |
commit | 1f476b5dd902edcd7c8997d5aa89af952734b341 (patch) | |
tree | 658be695319176baf503096b9d4e7802b001e873 | |
parent | b393466b014fa5e40ca95ac687bfb0260462db19 (diff) |
Subject: [PATCH 16/19] OMAP4: OMAPFB: register callback to get notified of resolution change
Protect fb_set_var() with console-sem to avoid making console
driver unhappy. Supports more than one framebuffer.
This is a port from Rob Clark <rob@ti.com> patch.
Signed-off-by: Sebastien Jan <s-jan@ti.com>
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index d099badcb24..65b9ecd7685 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1870,6 +1870,84 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) kfree(fbdev); } +static void size_notify(struct fb_info *fbi, int w, int h) +{ + struct fb_var_screeninfo var = fbi->var; + struct fb_var_screeninfo saved_var = fbi->var; + int orig_flags; + + DBG("size_notify: %dx%d\n", w, h); + + var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_ALL | FB_ACTIVATE_NOW; + var.xres = w; + var.yres = h; + var.xres_virtual = w; + var.yres_virtual = h; + + console_lock(); + + /* this ensures fbdev clients, like the console driver, get notified about + * the change: + */ + orig_flags = fbi->flags; + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(fbi, &var); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + + /* now delete old mode: + */ + saved_var.activate |= FB_ACTIVATE_INV_MODE; + fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(fbi, &saved_var); + fbi->flags = orig_flags; + + console_unlock(); +} + +struct omapfb_notifier_block { + struct notifier_block notifier; + struct omapfb2_device *fbdev; +}; + +static int omapfb_notifier(struct notifier_block *nb, + unsigned long evt, void *arg) +{ + struct omapfb_notifier_block *notifier = + container_of(nb, struct omapfb_notifier_block, notifier); + struct omap_dss_device *dssdev = arg; + struct omapfb2_device *fbdev = notifier->fbdev; + int keep = false; + int i; + + /* figure out if this event pertains to this omapfb device: + */ + for (i = 0; i < fbdev->num_managers; i++) { + if (fbdev->managers[i]->device == dssdev) { + keep = true; + break; + } + } + + if (!keep) + return NOTIFY_DONE; + + /* the event pertains to us.. see if we care: + */ + switch (evt) { + case OMAP_DSS_SIZE_CHANGE: { + u16 w, h; + dssdev->driver->get_resolution(dssdev, &w, &h); + for (i = 0; i < fbdev->num_fbs; i++) + size_notify(fbdev->fbs[i], w, h); + break; + } + default: /* don't care about other events for now */ + break; + } + + return NOTIFY_OK; +} + static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) { int r, i; @@ -2308,6 +2386,7 @@ static int omapfb_probe(struct platform_device *pdev) fbdev->num_displays = 0; dssdev = NULL; for_each_dss_dev(dssdev) { + struct omapfb_notifier_block *notifier; omap_dss_get_device(dssdev); if (!dssdev->driver) { @@ -2316,6 +2395,11 @@ static int omapfb_probe(struct platform_device *pdev) } fbdev->displays[fbdev->num_displays++] = dssdev; + + notifier = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL); + notifier->notifier.notifier_call = omapfb_notifier; + notifier->fbdev = fbdev; + omap_dss_add_notify(dssdev, ¬ifier->notifier); } if (r) |