media: cec: add CEC_EVENT_PIN_HPD_LOW/HIGH events
Add support for two new low-level events: PIN_HPD_LOW and PIN_HPD_HIGH. This is specifically meant for use with the upcoming cec-gpio driver and makes it possible to trace when the HPD pin changes. Some HDMI sinks do strange things with the HPD and this makes it easy to debug this. Note that this also moves the initialization of a devnode mutex and list to the allocate_adapter function: if the HPD is high, then as soon as the HPD interrupt is created an interrupt occurs and cec_queue_pin_hpd_event() is called which requires that the devnode mutex and list are initialized. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:

committed by
Mauro Carvalho Chehab

parent
da634f623e
commit
333ef6bd10
@@ -86,7 +86,7 @@ void cec_queue_event_fh(struct cec_fh *fh,
|
||||
const struct cec_event *new_ev, u64 ts)
|
||||
{
|
||||
static const u8 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 64, 64,
|
||||
1, 1, 64, 64, 8, 8,
|
||||
};
|
||||
struct cec_event_entry *entry;
|
||||
unsigned int ev_idx = new_ev->event - 1;
|
||||
@@ -170,6 +170,22 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event);
|
||||
|
||||
/* Notify userspace that the HPD pin changed state at the given time. */
|
||||
void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
{
|
||||
struct cec_event ev = {
|
||||
.event = is_high ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW,
|
||||
};
|
||||
struct cec_fh *fh;
|
||||
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list)
|
||||
cec_queue_event_fh(fh, &ev, ktime_to_ns(ts));
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event);
|
||||
|
||||
/*
|
||||
* Queue a new message for this filehandle.
|
||||
*
|
||||
|
@@ -529,7 +529,7 @@ static int cec_open(struct inode *inode, struct file *filp)
|
||||
* Initial events that are automatically sent when the cec device is
|
||||
* opened.
|
||||
*/
|
||||
struct cec_event ev_state = {
|
||||
struct cec_event ev = {
|
||||
.event = CEC_EVENT_STATE_CHANGE,
|
||||
.flags = CEC_EVENT_FL_INITIAL_STATE,
|
||||
};
|
||||
@@ -569,9 +569,19 @@ static int cec_open(struct inode *inode, struct file *filp)
|
||||
filp->private_data = fh;
|
||||
|
||||
/* 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;
|
||||
cec_queue_event_fh(fh, &ev_state, 0);
|
||||
ev.state_change.phys_addr = adap->phys_addr;
|
||||
ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
#ifdef CONFIG_CEC_PIN
|
||||
if (adap->pin && adap->pin->ops->read_hpd) {
|
||||
err = adap->pin->ops->read_hpd(adap);
|
||||
if (err >= 0) {
|
||||
ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
list_add(&fh->list, &devnode->fhs);
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
@@ -112,10 +112,6 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
||||
int minor;
|
||||
int ret;
|
||||
|
||||
/* Initialization */
|
||||
INIT_LIST_HEAD(&devnode->fhs);
|
||||
mutex_init(&devnode->lock);
|
||||
|
||||
/* Part 1: Find a free minor number */
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0);
|
||||
@@ -242,6 +238,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
INIT_LIST_HEAD(&adap->wait_queue);
|
||||
init_waitqueue_head(&adap->kthread_waitq);
|
||||
|
||||
/* adap->devnode initialization */
|
||||
INIT_LIST_HEAD(&adap->devnode.fhs);
|
||||
mutex_init(&adap->devnode.lock);
|
||||
|
||||
adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name);
|
||||
if (IS_ERR(adap->kthread)) {
|
||||
pr_err("cec-%s: kernel_thread() failed\n", name);
|
||||
|
Reference in New Issue
Block a user