summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2017-11-22 04:12:39 -0500
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-12-08 11:11:25 -0500
commitc8959a39fd47189a1474a4e92ffa34763589d6b0 (patch)
treebcb5da7425de2bfb99c6ac1f34ed15eff7b79040
parent15ae0be9c671e912a6749d821bc69ccfff766c19 (diff)
media: cec: disable the hardware when unregistered
When the device is being unregistered disable the hardware, don't wait until cec_delete_adapter is called as the hardware may have disappeared by then. This would be the case for hotplugable devices. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reported-by: Bård Eirik Winther <bwinther@cisco.com> Tested-by: Bård Eirik Winther <bwinther@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/cec/cec-api.c11
-rw-r--r--drivers/media/cec/cec-core.c15
-rw-r--r--include/media/cec.h12
3 files changed, 25 insertions, 13 deletions
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 3eb4a069cde8..37e468074dc1 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -46,12 +46,11 @@ static inline struct cec_devnode *cec_devnode_data(struct file *filp)
static unsigned int cec_poll(struct file *filp,
struct poll_table_struct *poll)
{
- struct cec_devnode *devnode = cec_devnode_data(filp);
struct cec_fh *fh = filp->private_data;
struct cec_adapter *adap = fh->adap;
unsigned int res = 0;
- if (!devnode->registered)
+ if (!cec_is_registered(adap))
return POLLERR | POLLHUP;
mutex_lock(&adap->lock);
if (adap->is_configured &&
@@ -486,13 +485,12 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,
static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct cec_devnode *devnode = cec_devnode_data(filp);
struct cec_fh *fh = filp->private_data;
struct cec_adapter *adap = fh->adap;
bool block = !(filp->f_flags & O_NONBLOCK);
void __user *parg = (void __user *)arg;
- if (!devnode->registered)
+ if (!cec_is_registered(adap))
return -ENODEV;
switch (cmd) {
@@ -626,9 +624,8 @@ static int cec_release(struct inode *inode, struct file *filp)
mutex_lock(&devnode->lock);
list_del(&fh->list);
- if (list_empty(&devnode->fhs) &&
- !adap->needs_hpd &&
- adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
+ if (cec_is_registered(adap) && list_empty(&devnode->fhs) &&
+ !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
WARN_ON(adap->ops->adap_enable(adap, false));
}
mutex_unlock(&devnode->lock);
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index 5870da6a567f..b5845b47fe6c 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -160,8 +160,9 @@ clr_bit:
* This function can safely be called if the device node has never been
* registered or has already been unregistered.
*/
-static void cec_devnode_unregister(struct cec_devnode *devnode)
+static void cec_devnode_unregister(struct cec_adapter *adap)
{
+ struct cec_devnode *devnode = &adap->devnode;
struct cec_fh *fh;
mutex_lock(&devnode->lock);
@@ -179,6 +180,11 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)
devnode->unregistered = true;
mutex_unlock(&devnode->lock);
+ mutex_lock(&adap->lock);
+ __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false);
+ __cec_s_log_addrs(adap, NULL, false);
+ mutex_unlock(&adap->lock);
+
cdev_device_del(&devnode->cdev, &devnode->dev);
put_device(&devnode->dev);
}
@@ -192,7 +198,7 @@ static void cec_cec_notify(struct cec_adapter *adap, u16 pa)
void cec_register_cec_notifier(struct cec_adapter *adap,
struct cec_notifier *notifier)
{
- if (WARN_ON(!adap->devnode.registered))
+ if (WARN_ON(!cec_is_registered(adap)))
return;
adap->notifier = notifier;
@@ -373,7 +379,7 @@ void cec_unregister_adapter(struct cec_adapter *adap)
if (adap->notifier)
cec_notifier_unregister(adap->notifier);
#endif
- cec_devnode_unregister(&adap->devnode);
+ cec_devnode_unregister(adap);
}
EXPORT_SYMBOL_GPL(cec_unregister_adapter);
@@ -381,9 +387,6 @@ void cec_delete_adapter(struct cec_adapter *adap)
{
if (IS_ERR_OR_NULL(adap))
return;
- mutex_lock(&adap->lock);
- __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false);
- mutex_unlock(&adap->lock);
kthread_stop(adap->kthread);
if (adap->kthread_config)
kthread_stop(adap->kthread_config);
diff --git a/include/media/cec.h b/include/media/cec.h
index dd781e928b72..1c6a797cb6d4 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -230,6 +230,18 @@ static inline bool cec_is_sink(const struct cec_adapter *adap)
return adap->phys_addr == 0;
}
+/**
+ * cec_is_registered() - is the CEC adapter registered?
+ *
+ * @adap: the CEC adapter, may be NULL.
+ *
+ * Return: true if the adapter is registered, false otherwise.
+ */
+static inline bool cec_is_registered(const struct cec_adapter *adap)
+{
+ return adap && adap->devnode.registered;
+}
+
#define cec_phys_addr_exp(pa) \
((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf