media: cec: add core support for low-level CEC pin monitoring
authorHans Verkuil <hans.verkuil@cisco.com>
Tue, 11 Jul 2017 06:30:41 +0000 (03:30 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Tue, 18 Jul 2017 15:55:38 +0000 (12:55 -0300)
Add support for the new MONITOR_PIN mode.

Add the cec_pin_event function that the CEC pin code will call to queue pin
change events.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/cec/cec-adap.c
drivers/media/cec/cec-api.c
include/media/cec.h

index 5080d7aa6105facc3f9584b97b176155e15639c3..b0bd466f75e2d8efcdf6164931c8f33d9211edd8 100644 (file)
@@ -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.
  *
index 48bef1c718ad3077c67b4dcf625afbd6adfa9a9d..14279958dca15b413be8fea882e3a7ef3fda47d2 100644 (file)
@@ -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);
index 6cc862af74e5da2fadfb15efbaccac7bc931376c..d983960b37ad8257b399e29de21f0d6be43e9ecd 100644 (file)
@@ -177,6 +177,7 @@ struct cec_adapter {
        bool is_configuring;
        bool is_configured;
        u32 monitor_all_cnt;
+       u32 monitor_pin_cnt;
        u32 follower_cnt;
        struct cec_fh *cec_follower;
        struct cec_fh *cec_initiator;
@@ -271,6 +272,16 @@ static inline void cec_received_msg(struct cec_adapter *adap,
        cec_received_msg_ts(adap, msg, ktime_get());
 }
 
+/**
+ * cec_queue_pin_event() - queue a pin event with a given timestamp.
+ *
+ * @adap:      pointer to the cec adapter
+ * @is_high:   when true the pin is high, otherwise it is low
+ * @ts:                the timestamp for this event
+ *
+ */
+void cec_queue_pin_event(struct cec_adapter *adap, bool is_high, ktime_t ts);
+
 /**
  * cec_get_edid_phys_addr() - find and return the physical address
  *