diff options
author | Hans Verkuil <hverkuil-cisco@xs4all.nl> | 2019-06-20 06:10:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2019-06-27 07:19:43 -0400 |
commit | b48cb35c6a7babdc317edb4c752ecf3da0691228 (patch) | |
tree | a61296034a488810fbca3247e131c6c0ebf63a4a | |
parent | 32a847f9fa40ec1b03ead2c514862764983ff9ca (diff) |
media: cec-notifier: add new notifier functions
In order to support multiple CEC devices for an HDMI connector,
and to support cec_connector_info, drivers should use either a
cec_notifier_conn_(un)register pair of functions (HDMI drivers)
or a cec_notifier_cec_adap_(un)register pair (CEC adapter drivers).
This replaces cec_notifier_get_conn/cec_notifier_put.
For CEC adapters it is also no longer needed to call cec_notifier_register,
cec_register_cec_notifier and cec_notifier_unregister. This is now
all handled internally by the new functions.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
-rw-r--r-- | drivers/media/cec/cec-notifier.c | 85 | ||||
-rw-r--r-- | include/media/cec-notifier.h | 78 |
2 files changed, 163 insertions, 0 deletions
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index f72b19c351dd..52a867bde15f 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -22,6 +22,7 @@ struct cec_notifier { struct list_head head; struct kref kref; struct device *hdmi_dev; + struct cec_connector_info conn_info; const char *conn_name; struct cec_adapter *cec_adap; void (*callback)(struct cec_adapter *adap, u16 pa); @@ -88,6 +89,84 @@ void cec_notifier_put(struct cec_notifier *n) } EXPORT_SYMBOL_GPL(cec_notifier_put); +struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info) +{ + struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name); + + if (!n) + return n; + + mutex_lock(&n->lock); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (conn_info) + n->conn_info = *conn_info; + else + memset(&n->conn_info, 0, sizeof(n->conn_info)); + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, conn_info); + } + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_register); + +void cec_notifier_conn_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + memset(&n->conn_info, 0, sizeof(n->conn_info)); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, NULL); + } + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister); + +struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap) +{ + struct cec_notifier *n; + + if (WARN_ON(!adap)) + return NULL; + + n = cec_notifier_get_conn(hdmi_dev, conn_name); + if (!n) + return n; + + mutex_lock(&n->lock); + n->cec_adap = adap; + adap->conn_info = n->conn_info; + adap->notifier = n; + cec_s_phys_addr(adap, n->phys_addr, false); + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register); + +void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + n->cec_adap->notifier = NULL; + n->cec_adap = NULL; + n->callback = NULL; + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_unregister); + void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) { if (n == NULL) @@ -97,6 +176,8 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) n->phys_addr = pa; if (n->callback) n->callback(n->cec_adap, n->phys_addr); + else if (n->cec_adap) + cec_s_phys_addr(n->cec_adap, n->phys_addr, false); mutex_unlock(&n->lock); } EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); @@ -131,6 +212,10 @@ EXPORT_SYMBOL_GPL(cec_notifier_register); void cec_notifier_unregister(struct cec_notifier *n) { + /* Do nothing unless cec_notifier_register was called first */ + if (!n->callback) + return; + mutex_lock(&n->lock); n->callback = NULL; mutex_unlock(&n->lock); diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h index 0e3bd3415724..f161f8a493ac 100644 --- a/include/media/cec-notifier.h +++ b/include/media/cec-notifier.h @@ -43,6 +43,60 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, void cec_notifier_put(struct cec_notifier *n); /** + * cec_notifier_conn_register - find or create a new cec_notifier for the given + * HDMI device and connector tuple. + * @hdmi_dev: HDMI device that sends the events. + * @conn_name: the connector name from which the event occurs. May be NULL + * if there is always only one HDMI connector created by the HDMI device. + * @conn_info: the connector info from which the event occurs (may be NULL) + * + * If a notifier for device @dev and connector @conn_name already exists, then + * increase the refcount and return that notifier. + * + * If it doesn't exist, then allocate a new notifier struct and return a + * pointer to that new struct. + * + * Return NULL if the memory could not be allocated. + */ +struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info); + +/** + * cec_notifier_conn_unregister - decrease refcount and delete when the + * refcount reaches 0. + * @n: notifier. If NULL, then this function does nothing. + */ +void cec_notifier_conn_unregister(struct cec_notifier *n); + +/** + * cec_notifier_cec_adap_register - find or create a new cec_notifier for the + * given device. + * @hdmi_dev: HDMI device that sends the events. + * @conn_name: the connector name from which the event occurs. May be NULL + * if there is always only one HDMI connector created by the HDMI device. + * @adap: the cec adapter that registered this notifier. + * + * If a notifier for device @dev and connector @conn_name already exists, then + * increase the refcount and return that notifier. + * + * If it doesn't exist, then allocate a new notifier struct and return a + * pointer to that new struct. + * + * Return NULL if the memory could not be allocated. + */ +struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap); + +/** + * cec_notifier_cec_adap_unregister - decrease refcount and delete when the + * refcount reaches 0. + * @n: notifier. If NULL, then this function does nothing. + */ +void cec_notifier_cec_adap_unregister(struct cec_notifier *n); + +/** * cec_notifier_set_phys_addr - set a new physical address. * @n: the CEC notifier * @pa: the CEC physical address @@ -86,6 +140,30 @@ static inline void cec_notifier_put(struct cec_notifier *n) { } +static inline struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info) +{ + /* A non-NULL pointer is expected on success */ + return (struct cec_notifier *)0xdeadfeed; +} + +static inline void cec_notifier_conn_unregister(struct cec_notifier *n) +{ +} + +static inline struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap) +{ + /* A non-NULL pointer is expected on success */ + return (struct cec_notifier *)0xdeadfeed; +} + +static inline void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +{ +} + static inline void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) { } |