diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 421472b492ee..78a85c44d96e 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -367,7 +367,6 @@ int cec_thread_func(void *_adap) */ err = wait_event_interruptible_timeout(adap->kthread_waitq, kthread_should_stop() || - (!adap->is_configured && !adap->is_configuring) || (!adap->transmitting && !list_empty(&adap->transmit_queue)), msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); @@ -382,8 +381,7 @@ int cec_thread_func(void *_adap) mutex_lock(&adap->lock); - if ((!adap->is_configured && !adap->is_configuring) || - kthread_should_stop()) { + if (kthread_should_stop()) { cec_flush(adap); goto unlock; } @@ -414,6 +412,7 @@ int cec_thread_func(void *_adap) struct cec_data, list); list_del_init(&data->list); adap->transmit_queue_sz--; + /* Make this the current transmitting message */ adap->transmitting = data; @@ -647,7 +646,8 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, cec_msg_initiator(msg)); return -EINVAL; } - if (!adap->is_configured && !adap->is_configuring) + if (!adap->is_configured && !adap->is_configuring && + (msg->msg[0] != 0xf0 || msg->reply)) return -ENONET; if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) @@ -696,6 +696,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (fh) list_add_tail(&data->xfer_list, &fh->xfer_list); + list_add_tail(&data->list, &adap->transmit_queue); adap->transmit_queue_sz++; if (!adap->transmitting) @@ -1121,6 +1122,7 @@ static void cec_adap_unconfigure(struct cec_adapter *adap) adap->is_configuring = false; adap->is_configured = false; memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); + cec_flush(adap); wake_up_interruptible(&adap->kthread_waitq); cec_post_state_event(adap); } @@ -1352,19 +1354,30 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) /* Disabling monitor all mode should always succeed */ if (adap->monitor_all_cnt) WARN_ON(call_op(adap, adap_monitor_all_enable, false)); - WARN_ON(adap->ops->adap_enable(adap, false)); + mutex_lock(&adap->devnode.lock); + if (list_empty(&adap->devnode.fhs)) + WARN_ON(adap->ops->adap_enable(adap, false)); + mutex_unlock(&adap->devnode.lock); if (phys_addr == CEC_PHYS_ADDR_INVALID) return; } - if (adap->ops->adap_enable(adap, true)) + mutex_lock(&adap->devnode.lock); + if (list_empty(&adap->devnode.fhs) && + adap->ops->adap_enable(adap, true)) { + mutex_unlock(&adap->devnode.lock); return; + } if (adap->monitor_all_cnt && call_op(adap, adap_monitor_all_enable, true)) { - WARN_ON(adap->ops->adap_enable(adap, false)); + if (list_empty(&adap->devnode.fhs)) + WARN_ON(adap->ops->adap_enable(adap, false)); + mutex_unlock(&adap->devnode.lock); return; } + mutex_unlock(&adap->devnode.lock); + adap->phys_addr = phys_addr; cec_post_state_event(adap); if (adap->log_addrs.num_log_addrs) diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 8950b6c9d6a9..627cdf7b12d1 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -198,7 +198,9 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, return -EINVAL; mutex_lock(&adap->lock); - if (!adap->is_configured) + if (adap->is_configuring) + err = -ENONET; + else if (!adap->is_configured && (msg.msg[0] != 0xf0 || msg.reply)) err = -ENONET; else if (cec_is_busy(adap, fh)) err = -EBUSY; @@ -515,9 +517,18 @@ static int cec_open(struct inode *inode, struct file *filp) return err; } + mutex_lock(&devnode->lock); + if (list_empty(&devnode->fhs) && + adap->phys_addr == CEC_PHYS_ADDR_INVALID) { + err = adap->ops->adap_enable(adap, true); + if (err) { + mutex_unlock(&devnode->lock); + kfree(fh); + return err; + } + } filp->private_data = fh; - mutex_lock(&devnode->lock); /* Queue up initial state events */ ev_state.state_change.phys_addr = adap->phys_addr; ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; @@ -551,6 +562,10 @@ static int cec_release(struct inode *inode, struct file *filp) mutex_lock(&devnode->lock); list_del(&fh->list); + if (list_empty(&devnode->fhs) && + adap->phys_addr == CEC_PHYS_ADDR_INVALID) { + WARN_ON(adap->ops->adap_enable(adap, false)); + } mutex_unlock(&devnode->lock); /* Unhook pending transmits from this filehandle. */