1 // SPDX-License-Identifier: GPL-2.0-only
3 * cec-notifier.c - notify CEC drivers of physical address changes
5 * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
6 * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
9 #include <linux/export.h>
10 #include <linux/string.h>
11 #include <linux/slab.h>
12 #include <linux/list.h>
13 #include <linux/kref.h>
15 #include <media/cec.h>
16 #include <media/cec-notifier.h>
17 #include <drm/drm_edid.h>
21 struct list_head head
;
25 struct cec_adapter
*cec_adap
;
26 void (*callback
)(struct cec_adapter
*adap
, u16 pa
);
31 static LIST_HEAD(cec_notifiers
);
32 static DEFINE_MUTEX(cec_notifiers_lock
);
34 struct cec_notifier
*cec_notifier_get_conn(struct device
*dev
, const char *conn
)
36 struct cec_notifier
*n
;
38 mutex_lock(&cec_notifiers_lock
);
39 list_for_each_entry(n
, &cec_notifiers
, head
) {
41 (!conn
|| !strcmp(n
->conn
, conn
))) {
43 mutex_unlock(&cec_notifiers_lock
);
47 n
= kzalloc(sizeof(*n
), GFP_KERNEL
);
52 n
->conn
= kstrdup(conn
, GFP_KERNEL
);
53 n
->phys_addr
= CEC_PHYS_ADDR_INVALID
;
56 list_add_tail(&n
->head
, &cec_notifiers
);
58 mutex_unlock(&cec_notifiers_lock
);
61 EXPORT_SYMBOL_GPL(cec_notifier_get_conn
);
63 static void cec_notifier_release(struct kref
*kref
)
65 struct cec_notifier
*n
=
66 container_of(kref
, struct cec_notifier
, kref
);
73 void cec_notifier_put(struct cec_notifier
*n
)
75 mutex_lock(&cec_notifiers_lock
);
76 kref_put(&n
->kref
, cec_notifier_release
);
77 mutex_unlock(&cec_notifiers_lock
);
79 EXPORT_SYMBOL_GPL(cec_notifier_put
);
81 void cec_notifier_set_phys_addr(struct cec_notifier
*n
, u16 pa
)
89 n
->callback(n
->cec_adap
, n
->phys_addr
);
90 mutex_unlock(&n
->lock
);
92 EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr
);
94 void cec_notifier_set_phys_addr_from_edid(struct cec_notifier
*n
,
95 const struct edid
*edid
)
97 u16 pa
= CEC_PHYS_ADDR_INVALID
;
102 if (edid
&& edid
->extensions
)
103 pa
= cec_get_edid_phys_addr((const u8
*)edid
,
104 EDID_LENGTH
* (edid
->extensions
+ 1), NULL
);
105 cec_notifier_set_phys_addr(n
, pa
);
107 EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid
);
109 void cec_notifier_register(struct cec_notifier
*n
,
110 struct cec_adapter
*adap
,
111 void (*callback
)(struct cec_adapter
*adap
, u16 pa
))
114 mutex_lock(&n
->lock
);
116 n
->callback
= callback
;
117 n
->callback(adap
, n
->phys_addr
);
118 mutex_unlock(&n
->lock
);
120 EXPORT_SYMBOL_GPL(cec_notifier_register
);
122 void cec_notifier_unregister(struct cec_notifier
*n
)
124 mutex_lock(&n
->lock
);
126 n
->cec_adap
->notifier
= NULL
;
128 mutex_unlock(&n
->lock
);
131 EXPORT_SYMBOL_GPL(cec_notifier_unregister
);