media: cec-pin: improve interrupt handling
The CEC pin framework needs a bit more control over the interrupt handling: make sure that the disable_irq op is called even if the device node is unregistered, log the state of the interrupt in debugfs, and disable the interrupt when the kernel thread is stopped. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
3b7dab49c4
commit
9b79d776a2
@ -183,6 +183,7 @@ struct cec_pin {
|
|||||||
u16 la_mask;
|
u16 la_mask;
|
||||||
bool monitor_all;
|
bool monitor_all;
|
||||||
bool rx_eom;
|
bool rx_eom;
|
||||||
|
bool enabled_irq;
|
||||||
bool enable_irq_failed;
|
bool enable_irq_failed;
|
||||||
enum cec_pin_state state;
|
enum cec_pin_state state;
|
||||||
struct cec_msg tx_msg;
|
struct cec_msg tx_msg;
|
||||||
|
@ -1033,8 +1033,9 @@ static int cec_pin_thread_func(void *_adap)
|
|||||||
{
|
{
|
||||||
struct cec_adapter *adap = _adap;
|
struct cec_adapter *adap = _adap;
|
||||||
struct cec_pin *pin = adap->pin;
|
struct cec_pin *pin = adap->pin;
|
||||||
bool irq_enabled = false;
|
|
||||||
|
|
||||||
|
pin->enabled_irq = false;
|
||||||
|
pin->enable_irq_failed = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
wait_event_interruptible(pin->kthread_waitq,
|
wait_event_interruptible(pin->kthread_waitq,
|
||||||
kthread_should_stop() ||
|
kthread_should_stop() ||
|
||||||
@ -1088,9 +1089,10 @@ static int cec_pin_thread_func(void *_adap)
|
|||||||
switch (atomic_xchg(&pin->work_irq_change,
|
switch (atomic_xchg(&pin->work_irq_change,
|
||||||
CEC_PIN_IRQ_UNCHANGED)) {
|
CEC_PIN_IRQ_UNCHANGED)) {
|
||||||
case CEC_PIN_IRQ_DISABLE:
|
case CEC_PIN_IRQ_DISABLE:
|
||||||
if (irq_enabled) {
|
if (pin->enabled_irq) {
|
||||||
call_void_pin_op(pin, disable_irq);
|
pin->ops->disable_irq(adap);
|
||||||
irq_enabled = false;
|
pin->enabled_irq = false;
|
||||||
|
pin->enable_irq_failed = false;
|
||||||
}
|
}
|
||||||
cec_pin_high(pin);
|
cec_pin_high(pin);
|
||||||
if (pin->state == CEC_ST_OFF)
|
if (pin->state == CEC_ST_OFF)
|
||||||
@ -1100,21 +1102,29 @@ static int cec_pin_thread_func(void *_adap)
|
|||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
break;
|
break;
|
||||||
case CEC_PIN_IRQ_ENABLE:
|
case CEC_PIN_IRQ_ENABLE:
|
||||||
if (irq_enabled)
|
if (pin->enabled_irq || !pin->ops->enable_irq ||
|
||||||
|
pin->adap->devnode.unregistered)
|
||||||
break;
|
break;
|
||||||
pin->enable_irq_failed = !call_pin_op(pin, enable_irq);
|
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
|
||||||
if (pin->enable_irq_failed) {
|
if (pin->enable_irq_failed) {
|
||||||
cec_pin_to_idle(pin);
|
cec_pin_to_idle(pin);
|
||||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
} else {
|
} else {
|
||||||
irq_enabled = true;
|
pin->enabled_irq = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pin->enabled_irq) {
|
||||||
|
pin->ops->disable_irq(pin->adap);
|
||||||
|
pin->enabled_irq = false;
|
||||||
|
pin->enable_irq_failed = false;
|
||||||
|
cec_pin_high(pin);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1215,7 +1225,9 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
|
|||||||
seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read));
|
seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read));
|
||||||
seq_printf(file, "cec pin events dropped: %u\n",
|
seq_printf(file, "cec pin events dropped: %u\n",
|
||||||
pin->work_pin_events_dropped_cnt);
|
pin->work_pin_events_dropped_cnt);
|
||||||
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
|
if (pin->ops->enable_irq)
|
||||||
|
seq_printf(file, "irq %s\n", pin->enabled_irq ? "enabled" :
|
||||||
|
(pin->enable_irq_failed ? "failed" : "disabled"));
|
||||||
if (pin->timer_100us_overruns) {
|
if (pin->timer_100us_overruns) {
|
||||||
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
seq_printf(file, "timer overruns > 100us: %u of %u\n",
|
||||||
pin->timer_100us_overruns, pin->timer_cnt);
|
pin->timer_100us_overruns, pin->timer_cnt);
|
||||||
|
Loading…
Reference in New Issue
Block a user