summaryrefslogtreecommitdiffstats
path: root/drivers/media/cec
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/cec')
-rw-r--r--drivers/media/cec/cec-adap.c16
-rw-r--r--drivers/media/cec/cec-api.c15
2 files changed, 29 insertions, 2 deletions
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 5080d7aa6105..b0bd466f75e2 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -153,6 +153,22 @@ static void cec_queue_event(struct cec_adapter *adap,
mutex_unlock(&adap->devnode.lock);
}
+/* Notify userspace that the CEC pin changed state at the given time. */
+void cec_queue_pin_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
+{
+ struct cec_event ev = {
+ .event = is_high ? CEC_EVENT_PIN_HIGH : CEC_EVENT_PIN_LOW,
+ };
+ struct cec_fh *fh;
+
+ mutex_lock(&adap->devnode.lock);
+ list_for_each_entry(fh, &adap->devnode.fhs, list)
+ if (fh->mode_follower == CEC_MODE_MONITOR_PIN)
+ cec_queue_event_fh(fh, &ev, ktime_to_ns(ts));
+ mutex_unlock(&adap->devnode.lock);
+}
+EXPORT_SYMBOL_GPL(cec_queue_pin_event);
+
/*
* Queue a new message for this filehandle.
*
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 48bef1c718ad..14279958dca1 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -370,6 +370,10 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,
!(adap->capabilities & CEC_CAP_MONITOR_ALL))
return -EINVAL;
+ if (mode_follower == CEC_MODE_MONITOR_PIN &&
+ !(adap->capabilities & CEC_CAP_MONITOR_PIN))
+ return -EINVAL;
+
/* Follower modes should always be able to send CEC messages */
if ((mode_initiator == CEC_MODE_NO_INITIATOR ||
!(adap->capabilities & CEC_CAP_TRANSMIT)) &&
@@ -378,11 +382,11 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,
return -EINVAL;
/* Monitor modes require CEC_MODE_NO_INITIATOR */
- if (mode_initiator && mode_follower >= CEC_MODE_MONITOR)
+ if (mode_initiator && mode_follower >= CEC_MODE_MONITOR_PIN)
return -EINVAL;
/* Monitor modes require CAP_NET_ADMIN */
- if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN))
+ if (mode_follower >= CEC_MODE_MONITOR_PIN && !capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&adap->lock);
@@ -421,8 +425,13 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,
if (fh->mode_follower == CEC_MODE_FOLLOWER)
adap->follower_cnt--;
+ if (fh->mode_follower == CEC_MODE_MONITOR_PIN)
+ adap->monitor_pin_cnt--;
if (mode_follower == CEC_MODE_FOLLOWER)
adap->follower_cnt++;
+ if (mode_follower == CEC_MODE_MONITOR_PIN) {
+ adap->monitor_pin_cnt++;
+ }
if (mode_follower == CEC_MODE_EXCL_FOLLOWER ||
mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) {
adap->passthrough =
@@ -566,6 +575,8 @@ static int cec_release(struct inode *inode, struct file *filp)
}
if (fh->mode_follower == CEC_MODE_FOLLOWER)
adap->follower_cnt--;
+ if (fh->mode_follower == CEC_MODE_MONITOR_PIN)
+ adap->monitor_pin_cnt--;
if (fh->mode_follower == CEC_MODE_MONITOR_ALL)
cec_monitor_all_cnt_dec(adap);
mutex_unlock(&adap->lock);