diff options
author | Jassi Brar <jaswinder.singh@linaro.org> | 2011-06-22 20:40:01 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-06-22 20:40:01 +0100 |
commit | 871a559dff12896a006e0b4af54b48265636b72c (patch) | |
tree | 0bc31b21c4128558e1c170268e13741dde59f2b1 | |
parent | b26b8d7d1b15bcb2eeeafcda0b1ae5c0f7166838 (diff) |
Subject: [PATCH 01/19] OMAP4: DSS: add generic notifier mechanism
A callback can be registered by the dssdev client in order to be
notified of resolution changes, for example an external monitor
that is hot-plugged.
Multiple clients can now register for notification from one
dssdev, and the notification mechanism can be extended in the
future to add other events.
This is a port of Rob Clark's <rob@ti.com> original patch.
Signed-off-by: Sebastien Jan <s-jan@ti.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r-- | drivers/video/omap2/dss/core.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/display.c | 48 | ||||
-rw-r--r-- | include/video/omapdss.h | 14 |
3 files changed, 65 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 3da426719dd..7a213c8dbbb 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -492,6 +492,9 @@ static int omap_dss_register_device(struct omap_dss_device *dssdev) dssdev->dev.parent = &dss_bus; dssdev->dev.release = omap_dss_dev_release; dev_set_name(&dssdev->dev, "display%d", dev_num++); + + BLOCKING_INIT_NOTIFIER_HEAD(&dssdev->notifier); + return device_register(&dssdev->dev); } diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index c2dfc8c5005..9d0c7e4cbf1 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <video/omapdss.h> #include "dss.h" @@ -628,3 +629,50 @@ void omap_dss_stop_device(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omap_dss_stop_device); +/* since omap_dss_update_size can be called in irq context, schedule work from + * work-queue to deliver notification to client.. + */ +struct notify_work { + struct work_struct work; + struct omap_dss_device *dssdev; + enum omap_dss_event evt; +}; + +static void notify_worker(struct work_struct *work) +{ + struct notify_work *nw = + container_of(work, struct notify_work, work); + struct omap_dss_device *dssdev = nw->dssdev; + blocking_notifier_call_chain(&dssdev->notifier, nw->evt, dssdev); + kfree(work); +} + +/** + * Called by lower level driver to notify about a change in resolution, etc. + */ +void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt) +{ + struct notify_work *nw = + kmalloc(sizeof(struct notify_work), GFP_KERNEL); + if (nw) { + INIT_WORK(&nw->work, notify_worker); + nw->dssdev = dssdev; + nw->evt = evt; + schedule_work(&nw->work); + } +} +EXPORT_SYMBOL(omap_dss_notify); + +void omap_dss_add_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_register(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_add_notify); + +void omap_dss_remove_notify(struct omap_dss_device *dssdev, + struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&dssdev->notifier, nb); +} +EXPORT_SYMBOL(omap_dss_remove_notify); diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 892b97f8e15..2a94d66db90 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -21,6 +21,7 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/device.h> +#include <linux/notifier.h> #include <linux/platform_device.h> #include <asm/atomic.h> @@ -506,6 +507,7 @@ struct omap_dss_device { struct omap_overlay_manager *manager; enum omap_dss_display_state state; + struct blocking_notifier_head notifier; /* platform specific */ int (*platform_enable)(struct omap_dss_device *dssdev); @@ -578,6 +580,18 @@ struct omap_dss_device *omap_dss_find_device(void *data, int omap_dss_start_device(struct omap_dss_device *dssdev); void omap_dss_stop_device(struct omap_dss_device *dssdev); +/* the event id of the event that occurred is passed in as the second arg + * to the notifier function, and the dssdev is passed as the third. + */ +enum omap_dss_event { + OMAP_DSS_SIZE_CHANGE + /* possibly add additional events, like hot-plug connect/disconnect */ +}; + +void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt); +void omap_dss_add_notify(struct omap_dss_device *dssdev, struct notifier_block *nb); +void omap_dss_remove_notify(struct omap_dss_device *dssdev, struct notifier_block *nb); + int omap_dss_get_num_overlay_managers(void); struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); |