Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / media / cec / cec-notifier.c
blob08b619d0ea1ef7f24f93771471366a340517b764
1 /*
2 * cec-notifier.c - notify CEC drivers of physical address changes
4 * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
5 * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
7 * This program is free software; you may redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
15 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
21 #include <linux/export.h>
22 #include <linux/string.h>
23 #include <linux/slab.h>
24 #include <linux/list.h>
25 #include <linux/kref.h>
27 #include <media/cec.h>
28 #include <media/cec-notifier.h>
29 #include <drm/drm_edid.h>
31 struct cec_notifier {
32 struct mutex lock;
33 struct list_head head;
34 struct kref kref;
35 struct device *dev;
36 struct cec_adapter *cec_adap;
37 void (*callback)(struct cec_adapter *adap, u16 pa);
39 u16 phys_addr;
42 static LIST_HEAD(cec_notifiers);
43 static DEFINE_MUTEX(cec_notifiers_lock);
45 struct cec_notifier *cec_notifier_get(struct device *dev)
47 struct cec_notifier *n;
49 mutex_lock(&cec_notifiers_lock);
50 list_for_each_entry(n, &cec_notifiers, head) {
51 if (n->dev == dev) {
52 kref_get(&n->kref);
53 mutex_unlock(&cec_notifiers_lock);
54 return n;
57 n = kzalloc(sizeof(*n), GFP_KERNEL);
58 if (!n)
59 goto unlock;
60 n->dev = dev;
61 n->phys_addr = CEC_PHYS_ADDR_INVALID;
62 mutex_init(&n->lock);
63 kref_init(&n->kref);
64 list_add_tail(&n->head, &cec_notifiers);
65 unlock:
66 mutex_unlock(&cec_notifiers_lock);
67 return n;
69 EXPORT_SYMBOL_GPL(cec_notifier_get);
71 static void cec_notifier_release(struct kref *kref)
73 struct cec_notifier *n =
74 container_of(kref, struct cec_notifier, kref);
76 list_del(&n->head);
77 kfree(n);
80 void cec_notifier_put(struct cec_notifier *n)
82 mutex_lock(&cec_notifiers_lock);
83 kref_put(&n->kref, cec_notifier_release);
84 mutex_unlock(&cec_notifiers_lock);
86 EXPORT_SYMBOL_GPL(cec_notifier_put);
88 void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
90 if (n == NULL)
91 return;
93 mutex_lock(&n->lock);
94 n->phys_addr = pa;
95 if (n->callback)
96 n->callback(n->cec_adap, n->phys_addr);
97 mutex_unlock(&n->lock);
99 EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
101 void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
102 const struct edid *edid)
104 u16 pa = CEC_PHYS_ADDR_INVALID;
106 if (n == NULL)
107 return;
109 if (edid && edid->extensions)
110 pa = cec_get_edid_phys_addr((const u8 *)edid,
111 EDID_LENGTH * (edid->extensions + 1), NULL);
112 cec_notifier_set_phys_addr(n, pa);
114 EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);
116 void cec_notifier_register(struct cec_notifier *n,
117 struct cec_adapter *adap,
118 void (*callback)(struct cec_adapter *adap, u16 pa))
120 kref_get(&n->kref);
121 mutex_lock(&n->lock);
122 n->cec_adap = adap;
123 n->callback = callback;
124 n->callback(adap, n->phys_addr);
125 mutex_unlock(&n->lock);
127 EXPORT_SYMBOL_GPL(cec_notifier_register);
129 void cec_notifier_unregister(struct cec_notifier *n)
131 mutex_lock(&n->lock);
132 n->callback = NULL;
133 mutex_unlock(&n->lock);
134 cec_notifier_put(n);
136 EXPORT_SYMBOL_GPL(cec_notifier_unregister);