diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2017-04-17 13:44:35 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-04-19 12:50:52 +0300 |
commit | 56a263aaa0a5f58d70517fae2bdd63fc1e17efec (patch) | |
tree | 12804cdac321eb61783ac32901cf13fbeabf0a3e /drivers/media/cec/cec-notifier.c | |
parent | ee0fe833d96793853335844b6d99fb76bd12cbeb (diff) | |
download | linux-56a263aaa0a5f58d70517fae2bdd63fc1e17efec.tar.xz |
[media] cec: Kconfig cleanup
The Kconfig options for the CEC subsystem were a bit messy. In
addition there were two cec sources (cec-edid.c and cec-notifier.c)
that were outside of the media/cec directory, which was weird.
Move those sources to media/cec as well.
The cec-edid and cec-notifier functionality is now part of the cec
module and these are no longer separate modules.
Also remove the MEDIA_CEC_EDID config option and include it with the
main CEC config option (which defined CEC_EDID anyway).
Added static inlines to cec-edid.h for dummy functions when CEC_CORE
isn't defined.
CEC drivers should now depend on CEC_CORE.
CEC drivers that need the cec-notifier functionality must explicitly
select CEC_NOTIFIER.
The s5p-cec and stih-cec drivers depended on VIDEO_DEV instead of
CEC_CORE, fix that as well.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/cec/cec-notifier.c')
-rw-r--r-- | drivers/media/cec/cec-notifier.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c new file mode 100644 index 000000000000..5f5209a73665 --- /dev/null +++ b/drivers/media/cec/cec-notifier.c @@ -0,0 +1,129 @@ +/* + * cec-notifier.c - notify CEC drivers of physical address changes + * + * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk> + * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/export.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/kref.h> + +#include <media/cec-notifier.h> +#include <drm/drm_edid.h> + +struct cec_notifier { + struct mutex lock; + struct list_head head; + struct kref kref; + struct device *dev; + struct cec_adapter *cec_adap; + void (*callback)(struct cec_adapter *adap, u16 pa); + + u16 phys_addr; +}; + +static LIST_HEAD(cec_notifiers); +static DEFINE_MUTEX(cec_notifiers_lock); + +struct cec_notifier *cec_notifier_get(struct device *dev) +{ + struct cec_notifier *n; + + mutex_lock(&cec_notifiers_lock); + list_for_each_entry(n, &cec_notifiers, head) { + if (n->dev == dev) { + kref_get(&n->kref); + mutex_unlock(&cec_notifiers_lock); + return n; + } + } + n = kzalloc(sizeof(*n), GFP_KERNEL); + if (!n) + goto unlock; + n->dev = dev; + n->phys_addr = CEC_PHYS_ADDR_INVALID; + mutex_init(&n->lock); + kref_init(&n->kref); + list_add_tail(&n->head, &cec_notifiers); +unlock: + mutex_unlock(&cec_notifiers_lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_get); + +static void cec_notifier_release(struct kref *kref) +{ + struct cec_notifier *n = + container_of(kref, struct cec_notifier, kref); + + list_del(&n->head); + kfree(n); +} + +void cec_notifier_put(struct cec_notifier *n) +{ + mutex_lock(&cec_notifiers_lock); + kref_put(&n->kref, cec_notifier_release); + mutex_unlock(&cec_notifiers_lock); +} +EXPORT_SYMBOL_GPL(cec_notifier_put); + +void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) +{ + mutex_lock(&n->lock); + n->phys_addr = pa; + if (n->callback) + n->callback(n->cec_adap, n->phys_addr); + mutex_unlock(&n->lock); +} +EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); + +void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, + const struct edid *edid) +{ + u16 pa = CEC_PHYS_ADDR_INVALID; + + if (edid && edid->extensions) + pa = cec_get_edid_phys_addr((const u8 *)edid, + EDID_LENGTH * (edid->extensions + 1), NULL); + cec_notifier_set_phys_addr(n, pa); +} +EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid); + +void cec_notifier_register(struct cec_notifier *n, + struct cec_adapter *adap, + void (*callback)(struct cec_adapter *adap, u16 pa)) +{ + kref_get(&n->kref); + mutex_lock(&n->lock); + n->cec_adap = adap; + n->callback = callback; + n->callback(adap, n->phys_addr); + mutex_unlock(&n->lock); +} +EXPORT_SYMBOL_GPL(cec_notifier_register); + +void cec_notifier_unregister(struct cec_notifier *n) +{ + mutex_lock(&n->lock); + n->callback = NULL; + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_unregister); |