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>
This commit is contained in:
Родитель
15ae0be9c6
Коммит
c8959a39fd
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче