diff options
author | Sebastien Jan <s-jan@ti.com> | 2011-05-03 12:18:21 +0800 |
---|---|---|
committer | Ricardo Salveti de Araujo <ricardo.salveti@canonical.com> | 2011-05-16 22:42:11 -0300 |
commit | 3590438fd5c7f3b301cda61ce3ff8200556a0d02 (patch) | |
tree | f0c48d75914f02a8b170dc6708e84cdfeab0265a /drivers | |
parent | f32697546c88f34ec4e490ce1b93fac0c902746a (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505ec667204..f99e2ee16ce 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -29,6 +29,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/omapfb.h> +#include <linux/console.h> #include <plat/display.h> #include <plat/vram.h> @@ -1902,6 +1903,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; @@ -2227,6 +2306,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) { @@ -2235,7 +2315,12 @@ 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) goto cleanup; |