Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
333ef6bd da634f62

+52 -10
+17 -1
drivers/media/cec/cec-adap.c
··· 86 86 const struct cec_event *new_ev, u64 ts) 87 87 { 88 88 static const u8 max_events[CEC_NUM_EVENTS] = { 89 - 1, 1, 64, 64, 89 + 1, 1, 64, 64, 8, 8, 90 90 }; 91 91 struct cec_event_entry *entry; 92 92 unsigned int ev_idx = new_ev->event - 1; ··· 169 169 mutex_unlock(&adap->devnode.lock); 170 170 } 171 171 EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event); 172 + 173 + /* Notify userspace that the HPD pin changed state at the given time. */ 174 + void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts) 175 + { 176 + struct cec_event ev = { 177 + .event = is_high ? CEC_EVENT_PIN_HPD_HIGH : 178 + CEC_EVENT_PIN_HPD_LOW, 179 + }; 180 + struct cec_fh *fh; 181 + 182 + mutex_lock(&adap->devnode.lock); 183 + list_for_each_entry(fh, &adap->devnode.fhs, list) 184 + cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); 185 + mutex_unlock(&adap->devnode.lock); 186 + } 187 + EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event); 172 188 173 189 /* 174 190 * Queue a new message for this filehandle.
+14 -4
drivers/media/cec/cec-api.c
··· 529 529 * Initial events that are automatically sent when the cec device is 530 530 * opened. 531 531 */ 532 - struct cec_event ev_state = { 532 + struct cec_event ev = { 533 533 .event = CEC_EVENT_STATE_CHANGE, 534 534 .flags = CEC_EVENT_FL_INITIAL_STATE, 535 535 }; ··· 569 569 filp->private_data = fh; 570 570 571 571 /* Queue up initial state events */ 572 - ev_state.state_change.phys_addr = adap->phys_addr; 573 - ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; 574 - cec_queue_event_fh(fh, &ev_state, 0); 572 + ev.state_change.phys_addr = adap->phys_addr; 573 + ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; 574 + cec_queue_event_fh(fh, &ev, 0); 575 + #ifdef CONFIG_CEC_PIN 576 + if (adap->pin && adap->pin->ops->read_hpd) { 577 + err = adap->pin->ops->read_hpd(adap); 578 + if (err >= 0) { 579 + ev.event = err ? CEC_EVENT_PIN_HPD_HIGH : 580 + CEC_EVENT_PIN_HPD_LOW; 581 + cec_queue_event_fh(fh, &ev, 0); 582 + } 583 + } 584 + #endif 575 585 576 586 list_add(&fh->list, &devnode->fhs); 577 587 mutex_unlock(&devnode->lock);
+4 -4
drivers/media/cec/cec-core.c
··· 112 112 int minor; 113 113 int ret; 114 114 115 - /* Initialization */ 116 - INIT_LIST_HEAD(&devnode->fhs); 117 - mutex_init(&devnode->lock); 118 - 119 115 /* Part 1: Find a free minor number */ 120 116 mutex_lock(&cec_devnode_lock); 121 117 minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); ··· 237 241 INIT_LIST_HEAD(&adap->transmit_queue); 238 242 INIT_LIST_HEAD(&adap->wait_queue); 239 243 init_waitqueue_head(&adap->kthread_waitq); 244 + 245 + /* adap->devnode initialization */ 246 + INIT_LIST_HEAD(&adap->devnode.fhs); 247 + mutex_init(&adap->devnode.lock); 240 248 241 249 adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); 242 250 if (IS_ERR(adap->kthread)) {
+4
include/media/cec-pin.h
··· 97 97 * @free: optional. Free any allocated resources. Called when the 98 98 * adapter is deleted. 99 99 * @status: optional, log status information. 100 + * @read_hpd: read the HPD pin. Return true if high, false if low or 101 + * an error if negative. If NULL or -ENOTTY is returned, 102 + * then this is not supported. 100 103 * 101 104 * These operations are used by the cec pin framework to manipulate 102 105 * the CEC pin. ··· 112 109 void (*disable_irq)(struct cec_adapter *adap); 113 110 void (*free)(struct cec_adapter *adap); 114 111 void (*status)(struct cec_adapter *adap, struct seq_file *file); 112 + int (*read_hpd)(struct cec_adapter *adap); 115 113 }; 116 114 117 115 #define CEC_NUM_PIN_EVENTS 128
+11 -1
include/media/cec.h
··· 91 91 }; 92 92 93 93 #define CEC_NUM_CORE_EVENTS 2 94 - #define CEC_NUM_EVENTS CEC_EVENT_PIN_CEC_HIGH 94 + #define CEC_NUM_EVENTS CEC_EVENT_PIN_HPD_HIGH 95 95 96 96 struct cec_fh { 97 97 struct list_head list; ··· 295 295 */ 296 296 void cec_queue_pin_cec_event(struct cec_adapter *adap, 297 297 bool is_high, ktime_t ts); 298 + 299 + /** 300 + * cec_queue_pin_hpd_event() - queue a pin event with a given timestamp. 301 + * 302 + * @adap: pointer to the cec adapter 303 + * @is_high: when true the HPD pin is high, otherwise it is low 304 + * @ts: the timestamp for this event 305 + * 306 + */ 307 + void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts); 298 308 299 309 /** 300 310 * cec_get_edid_phys_addr() - find and return the physical address
+2
include/uapi/linux/cec.h
··· 410 410 #define CEC_EVENT_LOST_MSGS 2 411 411 #define CEC_EVENT_PIN_CEC_LOW 3 412 412 #define CEC_EVENT_PIN_CEC_HIGH 4 413 + #define CEC_EVENT_PIN_HPD_LOW 5 414 + #define CEC_EVENT_PIN_HPD_HIGH 6 413 415 414 416 #define CEC_EVENT_FL_INITIAL_STATE (1 << 0) 415 417 #define CEC_EVENT_FL_DROPPED_EVENTS (1 << 1)