Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13 136 lines 3.5 kB view raw
1/* 2 * cec-notifier.c - notify CEC drivers of physical address changes 3 * 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. 6 * 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. 10 * 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. 19 */ 20 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> 26 27#include <media/cec.h> 28#include <media/cec-notifier.h> 29#include <drm/drm_edid.h> 30 31struct 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); 38 39 u16 phys_addr; 40}; 41 42static LIST_HEAD(cec_notifiers); 43static DEFINE_MUTEX(cec_notifiers_lock); 44 45struct cec_notifier *cec_notifier_get(struct device *dev) 46{ 47 struct cec_notifier *n; 48 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; 55 } 56 } 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); 65unlock: 66 mutex_unlock(&cec_notifiers_lock); 67 return n; 68} 69EXPORT_SYMBOL_GPL(cec_notifier_get); 70 71static void cec_notifier_release(struct kref *kref) 72{ 73 struct cec_notifier *n = 74 container_of(kref, struct cec_notifier, kref); 75 76 list_del(&n->head); 77 kfree(n); 78} 79 80void cec_notifier_put(struct cec_notifier *n) 81{ 82 mutex_lock(&cec_notifiers_lock); 83 kref_put(&n->kref, cec_notifier_release); 84 mutex_unlock(&cec_notifiers_lock); 85} 86EXPORT_SYMBOL_GPL(cec_notifier_put); 87 88void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) 89{ 90 if (n == NULL) 91 return; 92 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); 98} 99EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); 100 101void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, 102 const struct edid *edid) 103{ 104 u16 pa = CEC_PHYS_ADDR_INVALID; 105 106 if (n == NULL) 107 return; 108 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); 113} 114EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid); 115 116void cec_notifier_register(struct cec_notifier *n, 117 struct cec_adapter *adap, 118 void (*callback)(struct cec_adapter *adap, u16 pa)) 119{ 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); 126} 127EXPORT_SYMBOL_GPL(cec_notifier_register); 128 129void cec_notifier_unregister(struct cec_notifier *n) 130{ 131 mutex_lock(&n->lock); 132 n->callback = NULL; 133 mutex_unlock(&n->lock); 134 cec_notifier_put(n); 135} 136EXPORT_SYMBOL_GPL(cec_notifier_unregister);