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
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>
33 struct list_head head
;
36 struct cec_adapter
*cec_adap
;
37 void (*callback
)(struct cec_adapter
*adap
, u16 pa
);
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
) {
53 mutex_unlock(&cec_notifiers_lock
);
57 n
= kzalloc(sizeof(*n
), GFP_KERNEL
);
61 n
->phys_addr
= CEC_PHYS_ADDR_INVALID
;
64 list_add_tail(&n
->head
, &cec_notifiers
);
66 mutex_unlock(&cec_notifiers_lock
);
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
);
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
)
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
;
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
))
121 mutex_lock(&n
->lock
);
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
);
133 mutex_unlock(&n
->lock
);
136 EXPORT_SYMBOL_GPL(cec_notifier_unregister
);