Support the new pin monitoring events API in the CEC utilities.

It needs a bit more cleanup before it is ready to be merged, and I am sure that
more work can be done to refine the analysis code. But this is a good first 
start.

Signed-off-by: Hans Verkuil <hans.verk...@cisco.com>
---
 include/linux/cec.h                     |   8 +-
 utils/cec-compliance/cec-compliance.cpp |   2 +
 utils/cec-ctl/cec-ctl.cpp               | 311 +++++++++++++++++++++++++++++++-
 utils/cec-follower/cec-follower.cpp     |   2 +
 utils/cec-follower/cec-processing.cpp   |   2 +
 5 files changed, 316 insertions(+), 9 deletions(-)

diff --git a/include/linux/cec.h b/include/linux/cec.h
index 44579a24..d87a67b0 100644
--- a/include/linux/cec.h
+++ b/include/linux/cec.h
@@ -318,6 +318,7 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask)
 #define CEC_MODE_FOLLOWER              (0x1 << 4)
 #define CEC_MODE_EXCL_FOLLOWER         (0x2 << 4)
 #define CEC_MODE_EXCL_FOLLOWER_PASSTHRU        (0x3 << 4)
+#define CEC_MODE_MONITOR_PIN           (0xd << 4)
 #define CEC_MODE_MONITOR               (0xe << 4)
 #define CEC_MODE_MONITOR_ALL           (0xf << 4)
 #define CEC_MODE_FOLLOWER_MSK          0xf0
@@ -338,6 +339,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask)
 #define CEC_CAP_MONITOR_ALL    (1 << 5)
 /* Hardware can use CEC only if the HDMI HPD pin is high. */
 #define CEC_CAP_NEEDS_HPD      (1 << 6)
+/* Hardware can monitor CEC pin transitions */
+#define CEC_CAP_MONITOR_PIN    (1 << 7)

 /**
  * struct cec_caps - CEC capabilities structure.
@@ -405,8 +408,11 @@ struct cec_log_addrs {
  * didn't empty the message queue in time
  */
 #define CEC_EVENT_LOST_MSGS            2
+#define CEC_EVENT_PIN_LOW              3
+#define CEC_EVENT_PIN_HIGH             4

 #define CEC_EVENT_FL_INITIAL_STATE     (1 << 0)
+#define CEC_EVENT_FL_DROPPED_EVENTS    (1 << 1)

 /**
  * struct cec_event_state_change - used when the CEC adapter changes state.
@@ -419,7 +425,7 @@ struct cec_event_state_change {
 };

 /**
- * struct cec_event_lost_msgs - tells you how many messages were lost due.
+ * struct cec_event_lost_msgs - tells you how many messages were lost.
  * @lost_msgs: how many messages were lost.
  */
 struct cec_event_lost_msgs {
diff --git a/utils/cec-compliance/cec-compliance.cpp 
b/utils/cec-compliance/cec-compliance.cpp
index 0dd2a54f..1badf8be 100644
--- a/utils/cec-compliance/cec-compliance.cpp
+++ b/utils/cec-compliance/cec-compliance.cpp
@@ -261,6 +261,8 @@ static std::string caps2s(unsigned caps)
                s += "\t\tMonitor All\n";
        if (caps & CEC_CAP_NEEDS_HPD)
                s += "\t\tNeeds HPD\n";
+       if (caps & CEC_CAP_MONITOR_PIN)
+               s += "\t\tMonitor Pin\n";
        return s;
 }

diff --git a/utils/cec-ctl/cec-ctl.cpp b/utils/cec-ctl/cec-ctl.cpp
index 80d4014a..7b23ab7e 100644
--- a/utils/cec-ctl/cec-ctl.cpp
+++ b/utils/cec-ctl/cec-ctl.cpp
@@ -668,6 +668,7 @@ enum Option {
        OptReplyToFollowers,
        OptTimeout,
        OptMonitorTime,
+       OptMonitorPin,
        OptListUICommands,
        OptRcTVProfile1,
        OptRcTVProfile2,
@@ -730,6 +731,7 @@ static struct option long_options[] = {
        { "clear", no_argument, 0, OptClear },
        { "monitor", no_argument, 0, OptMonitor },
        { "monitor-all", no_argument, 0, OptMonitorAll },
+       { "monitor-pin", no_argument, 0, OptMonitorPin },
        { "monitor-time", required_argument, 0, OptMonitorTime },
        { "no-reply", no_argument, 0, OptNoReply },
        { "to", required_argument, 0, OptTo },
@@ -786,6 +788,7 @@ static void usage(void)
               "  -C, --clear              Clear all logical addresses\n"
               "  -m, --monitor            Monitor CEC traffic\n"
               "  -M, --monitor-all        Monitor all CEC traffic\n"
+              "  --monitor-pin            Monitor low-level CEC pin\n"
               "  --monitor-time=<secs>    Monitor for <secs> seconds (default 
is forever)\n"
               "  -n, --no-reply           Don't wait for a reply\n"
               "  -t, --to=<la>            Send message to the given logical 
address\n"
@@ -857,6 +860,8 @@ static std::string caps2s(unsigned caps)
                s += "\t\tMonitor All\n";
        if (caps & CEC_CAP_NEEDS_HPD)
                s += "\t\tNeeds HPD\n";
+       if (caps & CEC_CAP_MONITOR_PIN)
+               s += "\t\tMonitor Pin\n";
        return s;
 }

@@ -1224,11 +1229,231 @@ static void log_unknown_msg(const struct cec_msg *msg)
        }
 }

+enum cec_state {
+       CEC_ST_IDLE,
+       CEC_ST_RECEIVE_START_BIT,
+       CEC_ST_RECEIVING_DATA,
+};
+
+/* All timings are in microseconds */
+#define CEC_TIM_MARGIN                 100
+
+#define CEC_TIM_START_BIT_LOW          3700
+#define CEC_TIM_START_BIT_LOW_MIN      3500
+#define CEC_TIM_START_BIT_LOW_MAX      3900
+#define CEC_TIM_START_BIT_TOTAL                4500
+#define CEC_TIM_START_BIT_TOTAL_MIN    4300
+#define CEC_TIM_START_BIT_TOTAL_MAX    4700
+
+#define CEC_TIM_DATA_BIT_0_LOW         1500
+#define CEC_TIM_DATA_BIT_0_LOW_MIN     1300
+#define CEC_TIM_DATA_BIT_0_LOW_MAX     1700
+#define CEC_TIM_DATA_BIT_1_LOW         600
+#define CEC_TIM_DATA_BIT_1_LOW_MIN     400
+#define CEC_TIM_DATA_BIT_1_LOW_MAX     800
+#define CEC_TIM_DATA_BIT_TOTAL         2400
+#define CEC_TIM_DATA_BIT_TOTAL_MIN     2050
+#define CEC_TIM_DATA_BIT_TOTAL_MAX     2750
+#define CEC_TIM_DATA_BIT_SAMPLE                1050
+#define CEC_TIM_DATA_BIT_SAMPLE_MIN    850
+#define CEC_TIM_DATA_BIT_SAMPLE_MAX    1250
+
+#define CEC_TIM_IDLE_SAMPLE            1000
+#define CEC_TIM_IDLE_SAMPLE_MIN                500
+#define CEC_TIM_IDLE_SAMPLE_MAX                1500
+#define CEC_TIM_START_BIT_SAMPLE       500
+#define CEC_TIM_START_BIT_SAMPLE_MIN   300
+#define CEC_TIM_START_BIT_SAMPLE_MAX   700
+
+#define CEC_TIM_LOW_DRIVE_ERROR         (1.5 * CEC_TIM_DATA_BIT_TOTAL)
+#define CEC_TIM_LOW_DRIVE_ERROR_MIN     (1.4 * CEC_TIM_DATA_BIT_TOTAL)
+#define CEC_TIM_LOW_DRIVE_ERROR_MAX     (1.6 * CEC_TIM_DATA_BIT_TOTAL)
+
+static __u64 eob_ts;
+static __u64 eob_ts_max;
+
+static void cec_pin_debug(__u64 ev_ts, __u64 usecs, bool was_high, bool 
is_high)
+{
+       static enum cec_state state;
+       static __u64 ts;
+       static __u64 low_usecs;
+       static unsigned int rx_bit;
+       static __u8 byte;
+       static bool eom;
+       static bool first_byte;
+       static bool bcast;
+       __u64 usecs_min = usecs > CEC_TIM_MARGIN ? usecs - CEC_TIM_MARGIN : 0;
+
+       ts += usecs;
+
+       switch (state) {
+       case CEC_ST_RECEIVE_START_BIT:
+               if (was_high) {
+                       if (low_usecs + usecs_min > 
CEC_TIM_START_BIT_TOTAL_MAX) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: total start bit time too long 
(%.2f > %.2f ms)\n",
+                                       ts / 1000.0, (low_usecs + usecs_min) / 
1000.0,
+                                       CEC_TIM_START_BIT_TOTAL_MAX / 1000.0);
+                               break;
+                       }
+                       if (low_usecs + usecs < CEC_TIM_START_BIT_TOTAL_MIN - 
CEC_TIM_MARGIN) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: total start bit time too short 
(%.2f < %.2f ms)\n",
+                                       ts / 1000.0, (low_usecs + usecs) / 
1000.0,
+                                       CEC_TIM_START_BIT_TOTAL_MIN / 1000.0);
+                               break;
+                       }
+                       state = CEC_ST_RECEIVING_DATA;
+                       rx_bit = 0;
+                       byte = 0;
+                       eom = false;
+                       first_byte = true;
+                       bcast = false;
+               } else {
+                       if (usecs_min > CEC_TIM_START_BIT_LOW_MAX) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: start bit low too long (%.2f > 
%.2f ms)\n",
+                                       ts / 1000.0, usecs_min / 1000.0,
+                                       CEC_TIM_START_BIT_LOW_MAX / 1000.0);
+                               break;
+                       }
+                       if (usecs < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_MARGIN) 
{
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: start bit low too short (%.2f < 
%.2f ms)\n",
+                                       ts / 1000.0, usecs / 1000.0,
+                                       CEC_TIM_START_BIT_LOW_MIN / 1000.0);
+                               break;
+                       }
+                       low_usecs = usecs;
+                       eob_ts = ev_ts + 1000 * (CEC_TIM_START_BIT_TOTAL - 
low_usecs);
+                       eob_ts_max = ev_ts + 1000 * 
(CEC_TIM_START_BIT_TOTAL_MAX - low_usecs);
+               }
+               break;
+       case CEC_ST_RECEIVING_DATA:
+               if (was_high) {
+                       bool bit;
+                       bool ack = false;
+
+                       if (rx_bit < 9 && low_usecs + usecs_min > 
CEC_TIM_DATA_BIT_TOTAL_MAX) {
+                               printf("%10.2f: data bit %d total time too long 
(%.2f ms)\n",
+                                       ts / 1000.0, rx_bit, (low_usecs + 
usecs_min) / 1000.0);
+                       }
+                       if (low_usecs + usecs < CEC_TIM_DATA_BIT_TOTAL_MIN - 
CEC_TIM_MARGIN) {
+                               printf("%10.2f: data bit %d total time too 
short (%.2f ms)\n\n",
+                                       ts / 1000.0, rx_bit, (low_usecs + 
usecs) / 1000.0);
+                       }
+                       bit = low_usecs < CEC_TIM_DATA_BIT_1_LOW_MAX + 
CEC_TIM_MARGIN;
+                       if (rx_bit <= 7) {
+                               byte |= bit << (7 - rx_bit);
+                       } else if (rx_bit == 8) {
+                               eom = bit;
+                       } else {
+                               if (first_byte) {
+                                       first_byte = false;
+                                       bcast = (byte & 0xf) == 0xf;
+                               }
+                               printf("%10.2f: rx 0x%02x%s%s%s (%s)\n",
+                                      (ts - usecs) / 1000.0, byte,
+                                      eom ? " EOM" : "", (bcast ^ bit) ? " 
NACK" : " ACK",
+                                      bcast ? " (broadcast)" : "",
+                                      ts2s(ev_ts - usecs * 1000).c_str());
+                               if (show_info)
+                                       printf("\n");
+                               ack = !(bcast ^ bit);
+                       }
+                       rx_bit++;
+                       if (rx_bit == 10) {
+                               if ((!eom && ack) && low_usecs + usecs_min > 
CEC_TIM_DATA_BIT_TOTAL_MAX)
+                                       printf("%10.2f: data bit %d total time 
too long (%.2f ms)\n",
+                                               ts / 1000.0, rx_bit - 1, 
(low_usecs + usecs_min) / 1000.0);
+                               if (eom || is_high)
+                                       state = is_high ? CEC_ST_IDLE : 
CEC_ST_RECEIVE_START_BIT;
+                               if (state == CEC_ST_IDLE)
+                                       printf("\n");
+                               rx_bit = 0;
+                               byte = 0;
+                               eom = false;
+                       }
+                       break;
+               } else {
+                       low_usecs = usecs;
+                       if (usecs >= CEC_TIM_LOW_DRIVE_ERROR_MIN - 
CEC_TIM_MARGIN &&
+                           usecs <= CEC_TIM_LOW_DRIVE_ERROR_MAX + 
CEC_TIM_MARGIN) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: low drive (%.2f ms) 
detected\n\n",
+                                      ts / 1000.0, usecs / 1000.0);
+                               break;
+                       }
+                       if (usecs_min >= CEC_TIM_LOW_DRIVE_ERROR_MAX) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: low drive too long (%.2f > %.2f 
ms)\n\n",
+                                      ts / 1000.0, usecs_min / 1000.0,
+                                      CEC_TIM_LOW_DRIVE_ERROR_MAX / 1000.0);
+                               break;
+                       }
+
+                       if (rx_bit == 0 && !first_byte) {
+                               if (!rx_bit && usecs_min > 
CEC_TIM_START_BIT_LOW_MAX) {
+                                       state = CEC_ST_IDLE;
+                                       printf("%10.2f: start bit low too long 
(%.2f > %.2f ms)\n\n",
+                                               ts / 1000.0, usecs_min / 1000.0,
+                                               CEC_TIM_START_BIT_LOW_MAX / 
1000.0);
+                                       break;
+                               }
+                               if (usecs >= CEC_TIM_START_BIT_LOW_MIN - 
CEC_TIM_MARGIN) {
+                                       state = CEC_ST_RECEIVE_START_BIT;
+                                       break;
+                               }
+                       }
+                       if (usecs_min > CEC_TIM_DATA_BIT_0_LOW_MAX) {
+                               printf("%10.2f: data bit %d low too long (%.2f 
ms)\n",
+                                       ts / 1000.0, rx_bit, usecs_min / 
1000.0);
+                               if (usecs_min > CEC_TIM_DATA_BIT_TOTAL_MAX) {
+                                       state = CEC_ST_IDLE;
+                                       printf("\n");
+                               }
+                               break;
+                       }
+                       if (usecs_min > CEC_TIM_DATA_BIT_1_LOW_MAX &&
+                           usecs < CEC_TIM_DATA_BIT_0_LOW_MIN - 
CEC_TIM_MARGIN) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: data bit %d invalid 0->1 
transition (%.2f ms)\n\n",
+                                       ts / 1000.0, rx_bit, usecs / 1000.0);
+                               break;
+                       }
+                       if (usecs < CEC_TIM_DATA_BIT_1_LOW_MIN - 
CEC_TIM_MARGIN) {
+                               state = CEC_ST_IDLE;
+                               printf("%10.2f: data bit %d low too short (%.2f 
ms)\n\n",
+                                       ts / 1000.0, rx_bit, usecs / 1000.0);
+                               break;
+                       }
+
+                       eob_ts = ev_ts + 1000 * (CEC_TIM_DATA_BIT_TOTAL - 
low_usecs);
+                       eob_ts_max = ev_ts + 1000 * (CEC_TIM_DATA_BIT_TOTAL_MAX 
- low_usecs);
+               }
+               break;
+       case CEC_ST_IDLE:
+               if (!is_high)
+                       state = CEC_ST_RECEIVE_START_BIT;
+               break;
+       }
+       if (was_high && is_high)
+               state = CEC_ST_IDLE;
+}
+
 static void log_event(struct cec_event &ev)
 {
+       static __u64 last_ts;
+       static __u64 last_change_ts;
+       static __u64 last_1_to_0_ts;
+       static bool was_high = true;
+       bool is_high = ev.event == CEC_EVENT_PIN_HIGH;
        __u16 pa;

-       printf("\n");
+       if (ev.event != CEC_EVENT_PIN_LOW && ev.event != CEC_EVENT_PIN_HIGH)
+               printf("\n");
+       if (ev.flags & CEC_EVENT_FL_DROPPED_EVENTS)
+               printf("(Note: events were lost)\n");
        if (ev.flags & CEC_EVENT_FL_INITIAL_STATE)
                printf("Initial ");
        switch (ev.event) {
@@ -1242,6 +1467,52 @@ static void log_event(struct cec_event &ev)
        case CEC_EVENT_LOST_MSGS:
                printf("Event: Lost Messages\n");
                break;
+       case CEC_EVENT_PIN_LOW:
+       case CEC_EVENT_PIN_HIGH:
+               if (ev.flags & CEC_EVENT_FL_INITIAL_STATE)
+                       printf("Event: CEC Pin %s\n", is_high ? "High" : "Low");
+
+               eob_ts = eob_ts_max = 0;
+
+               if (last_change_ts == 0) {
+                       last_ts = last_change_ts = last_1_to_0_ts = ev.ts - 
CEC_TIM_DATA_BIT_TOTAL * 16000;
+                       if (is_high)
+                               break;
+               }
+               if (show_info) {
+                       if (last_change_ts)
+                               printf("%10.2f ms ", (ev.ts - last_change_ts) / 
1000000.0);
+                       else
+                               printf("%10.2f ms ", 0.0);
+                       if (last_change_ts && is_high && was_high)
+                               printf("1 -> 1 (%.2f ms, %s)\n",
+                                      (ev.ts - last_1_to_0_ts) / 1000000.0,
+                                      ts2s(ev.ts).c_str());
+                       else if (was_high)
+                               printf("1 -> 0 (%.2f ms, %s)\n",
+                                      (ev.ts - last_1_to_0_ts) / 1000000.0,
+                                      ts2s(ev.ts).c_str());
+                       else if (last_change_ts)
+                               printf("0 -> 1 (%d, %s)\n",
+                                      (ev.ts - last_change_ts) / 1000 < 
CEC_TIM_DATA_BIT_1_LOW_MAX + CEC_TIM_MARGIN,
+                                      ts2s(ev.ts).c_str());
+                       else
+                               printf("0 -> 1\n");
+                       last_change_ts = ev.ts;
+                       if (ev.event == CEC_EVENT_PIN_LOW)
+                               last_1_to_0_ts = ev.ts;
+               }
+               cec_pin_debug(ev.ts, (ev.ts - last_ts) / 1000, was_high, 
is_high);
+               if (!is_high) {
+                       float usecs = (ev.ts - last_ts) / 1000;
+                       unsigned periods = usecs / CEC_TIM_DATA_BIT_TOTAL;
+
+                       if (periods > 1 && periods < 10)
+                               printf("free signal time = %.1f bit periods\n", 
usecs / CEC_TIM_DATA_BIT_TOTAL);
+               }
+               last_ts = ev.ts;
+               was_high = is_high;
+               return;
        default:
                printf("Event: Unknown (0x%x)\n", ev.event);
                break;
@@ -2087,7 +2358,7 @@ int main(int argc, char **argv)
                }
        }
        if (node.num_log_addrs == 0) {
-               if (options[OptMonitor] || options[OptMonitorAll])
+               if (options[OptMonitor] || options[OptMonitorAll] || 
options[OptMonitorPin])
                        goto skip_la;
                return 0;
        }
@@ -2137,9 +2408,10 @@ int main(int argc, char **argv)
        fflush(stdout);

 skip_la:
-       if (options[OptMonitor] || options[OptMonitorAll]) {
+       if (options[OptMonitor] || options[OptMonitorAll] || 
options[OptMonitorPin]) {
                __u32 monitor = options[OptMonitorAll] ?
-                       CEC_MODE_MONITOR_ALL : CEC_MODE_MONITOR;
+                       CEC_MODE_MONITOR_ALL : (options[OptMonitorPin] ? 
CEC_MODE_MONITOR_PIN :
+                                               CEC_MODE_MONITOR);
                fd_set rd_fds;
                fd_set ex_fds;
                int fd = node.fd;
@@ -2151,6 +2423,11 @@ skip_la:
                        printf("Monitor All mode is not supported, falling back 
to regular monitoring\n");
                        monitor = CEC_MODE_MONITOR;
                }
+               if (!(node.caps & CEC_CAP_MONITOR_PIN) &&
+                   monitor == CEC_MODE_MONITOR_PIN) {
+                       printf("Monitor Pin mode is not supported, falling back 
to regular monitoring\n");
+                       monitor = CEC_MODE_MONITOR;
+               }
                if (doioctl(&node, CEC_S_MODE, &monitor)) {
                        printf("Selecting monitor mode failed, you may have to 
run this as root.\n");
                        goto skip_mon;
@@ -2158,8 +2435,9 @@ skip_la:

                fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
                t = time(NULL) + monitor_time;
-               while (1) {
-                       struct timeval tv = { t - time(NULL), 0 };
+               while (!monitor_time || time(NULL) < t) {
+                       struct timeval tv = { 1, 0 };
+                       bool pin_event = false;
                        int res;

                        fflush(stdout);
@@ -2167,8 +2445,8 @@ skip_la:
                        FD_ZERO(&ex_fds);
                        FD_SET(fd, &rd_fds);
                        FD_SET(fd, &ex_fds);
-                       res = select(fd + 1, &rd_fds, NULL, &ex_fds, 
monitor_time ? &tv : NULL);
-                       if (res <= 0)
+                       res = select(fd + 1, &rd_fds, NULL, &ex_fds, &tv);
+                       if (res < 0)
                                break;
                        if (FD_ISSET(fd, &rd_fds)) {
                                struct cec_msg msg = { };
@@ -2203,8 +2481,25 @@ skip_la:

                                if (doioctl(&node, CEC_DQEVENT, &ev))
                                        continue;
+                               if (ev.event == CEC_EVENT_PIN_LOW ||
+                                   ev.event == CEC_EVENT_PIN_HIGH)
+                                       pin_event = true;
                                log_event(ev);
                        }
+                       if (!pin_event && eob_ts) {
+                               struct timespec ts;
+                               __u64 ts64;
+
+                               clock_gettime(CLOCK_MONOTONIC, &ts);
+                               ts64 = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+                               if (ts64 >= eob_ts_max) {
+                                       struct cec_event ev = {
+                                               .ts = eob_ts,
+                                               .event = CEC_EVENT_PIN_HIGH,
+                                       };
+                                       log_event(ev);
+                               }
+                       }
                }
        }
        fflush(stdout);
diff --git a/utils/cec-follower/cec-follower.cpp 
b/utils/cec-follower/cec-follower.cpp
index 70ff7e74..fafad84a 100644
--- a/utils/cec-follower/cec-follower.cpp
+++ b/utils/cec-follower/cec-follower.cpp
@@ -123,6 +123,8 @@ static std::string caps2s(unsigned caps)
                s += "\t\tMonitor All\n";
        if (caps & CEC_CAP_NEEDS_HPD)
                s += "\t\tNeeds HPD\n";
+       if (caps & CEC_CAP_MONITOR_PIN)
+               s += "\t\tMonitor Pin\n";
        return s;
 }

diff --git a/utils/cec-follower/cec-processing.cpp 
b/utils/cec-follower/cec-processing.cpp
index 1e4527bb..88ab8286 100644
--- a/utils/cec-follower/cec-processing.cpp
+++ b/utils/cec-follower/cec-processing.cpp
@@ -176,6 +176,8 @@ static void log_event(struct cec_event &ev)
 {
        __u16 pa;

+       if (ev.flags & CEC_EVENT_FL_DROPPED_EVENTS)
+               printf("(Note: events were lost)\n");
        if (ev.flags & CEC_EVENT_FL_INITIAL_STATE)
                printf("Initial ");
        switch (ev.event) {
-- 
2.11.0

Reply via email to