linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Diffs between the upcoming v19 series and the cec-topic branch
@ 2016-06-25 12:39 Hans Verkuil
  0 siblings, 0 replies; only message in thread
From: Hans Verkuil @ 2016-06-25 12:39 UTC (permalink / raw)
  To: Linux Media Mailing List

Hi Mauro,

This patch is the diff between the cec-topic branch and the upcoming v19 patch series,
but without the split up of cec.c since that's not a functional change (and that would
make this diff impossible to review).

Besides fixing your comments about cec.c and cec-edid.c, it also makes some documentation
improvements and a few additional fixes:

- new messages were queued at the beginning of the message queue instead of at the end.
  I hadn't noticed before because normally there is at most only one message queued up.
- adap->timeout wasn't zeroed in cec_transmit_done if the transmit failed or the adapter
  is no longer configured. This caused the result of such a transmit to be unnecessarily
  delayed by 'timeout' ms.
- adap->rc->driver_name wasn't set, which caused a (null) driver name when running ir-keymap.

I also double-checked with the USB CEC dongle that unplugging the usb device while /dev/cec0
was still open works correctly and that the cec_adapter struct is freed only when the last
open file handle is closed.

Regards,

	Hans

diff --git a/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml b/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml
index 87d4f29..697dde5 100644
--- a/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml
@@ -61,7 +61,7 @@
     <para>The internal event queues are per-filehandle and per-event type. If there is
     no more room in a queue then the last event is overwritten with the new one. This
     means that intermediate results can be thrown away but that the latest event is always
-    available. This also mean that is it possible to read two successive events that have
+    available. This also means that is it possible to read two successive events that have
     the same value (e.g. two CEC_EVENT_STATE_CHANGE events with the same state). In that
     case the intermediate state changes were lost but it is guaranteed that the state
     did change in between the two events.</para>
@@ -95,7 +95,14 @@
 	    <entry><structfield>lost_msgs</structfield></entry>
 	    <entry>Set to the number of lost messages since the filehandle
 	    was opened or since the last time this event was dequeued for
-	    this filehandle.</entry>
+	    this filehandle. The messages lost are the oldest messages. So
+	    when a new message arrives and there is no more room, then the
+	    oldest message is discarded to make room for the new one. The
+	    internal size of the message queue guarantees that all messages
+	    received in the last two seconds will be stored. Since messages
+	    should be replied to within a second according to the CEC
+	    specification, this is more than enough.
+	    </entry>
 	  </row>
 	</tbody>
       </tgroup>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-receive.xml b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
index 4da7239..fde9f86 100644
--- a/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
+++ b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
@@ -96,9 +96,12 @@
 	  <row>
 	    <entry>__u32</entry>
 	    <entry><structfield>timeout</structfield></entry>
-	    <entry>The timeout in milliseconds. This is the time we wait for a message to
-	    be received. If it is set to 0, then we wait indefinitely.
-	    It is ignored by <constant>CEC_TRANSMIT</constant>.</entry>
+	    <entry>The timeout in milliseconds. This is the time the device will wait for a message to
+	    be received before timing out. If it is set to 0, then it will wait indefinitely when it
+	    is called by <constant>CEC_RECEIVE</constant>. If it is 0 and it is called by
+	    <constant>CEC_TRANSMIT</constant>, then it will be replaced by 1000 if the
+	    <structfield>reply</structfield> is non-zero or ignored if <structfield>reply</structfield>
+	    is 0.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -143,10 +146,16 @@
 	    <entry>__u8</entry>
 	    <entry><structfield>reply</structfield></entry>
 	    <entry>Wait until this message is replied. If <structfield>reply</structfield>
-	    is 0, then don't wait for a reply but return after transmitting the
-	    message. If there was an error as indicated by a non-zero <structfield>status</structfield>
-	    field, then <structfield>reply</structfield> is set to 0 by the driver.
-	    Ignored by <constant>CEC_RECEIVE</constant>.</entry>
+	    is 0 and the <structfield>timeout</structfield> is 0, then don't wait for a reply but
+	    return after transmitting the message. If there was an error as indicated by a non-zero
+	    <structfield>tx_status</structfield> field, then <structfield>reply</structfield> and
+	    <structfield>timeout</structfield> are both set to 0 by the driver. Ignored by
+	    <constant>CEC_RECEIVE</constant>. The case where <structfield>reply</structfield> is 0
+	    (this is the opcode for the Feature Abort message) and <structfield>timeout</structfield>
+	    is non-zero is specifically allowed to send a message and wait up to <structfield>timeout</structfield>
+	    milliseconds for a Feature Abort reply. In this case <structfield>rx_status</structfield>
+	    will either be set to <constant>CEC_RX_STATUS_TIMEOUT</constant> or
+	    <constant>CEC_RX_STATUS_FEATURE_ABORT</constant>.</entry>
 	  </row>
 	  <row>
 	    <entry>__u8</entry>
diff --git a/drivers/media/cec-edid.c b/drivers/media/cec-edid.c
index ce3b915..7001824 100644
--- a/drivers/media/cec-edid.c
+++ b/drivers/media/cec-edid.c
@@ -22,30 +22,59 @@
 #include <linux/types.h>
 #include <media/cec-edid.h>

+/*
+ * This EDID is expected to be a CEA-861 compliant, which means that there are
+ * at least two blocks and one or more of the extensions blocks are CEA-861
+ * blocks.
+ *
+ * The returned location is guaranteed to be < size - 1.
+ */
 static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
 {
+	unsigned int blocks = size / 128;
+	unsigned int block;
 	u8 d;

-	if (size < 256)
-		return 0;
-
-	if (edid[0x7e] != 1 || edid[0x80] != 0x02 || edid[0x81] != 0x03)
+	/* Sanity check: at least 2 blocks and a multiple of the block size */
+	if (blocks < 2 || size % 128)
 		return 0;

-	/* search Vendor Specific Data Block (tag 3) */
-	d = edid[0x82] & 0x7f;
-	if (d > 4) {
-		int i = 0x84;
-		int end = 0x80 + d;
-
-		do {
-			u8 tag = edid[i] >> 5;
-			u8 len = edid[i] & 0x1f;
-
-			if (tag == 3 && len >= 5)
-				return i + 4;
-			i += len + 1;
-		} while (i < end);
+	/*
+	 * If there are fewer extension blocks than the size, then update
+	 * 'blocks'. It is allowed to have more extension blocks than the size,
+	 * since some hardware can only read e.g. 256 bytes of the EDID, even
+	 * though more blocks are present. The first CEA-861 extension block
+	 * should normally be in block 1 anyway.
+	 */
+	if (edid[0x7e] + 1 < blocks)
+		blocks = edid[0x7e] + 1;
+
+	for (block = 1; block < blocks; block++) {
+		unsigned int offset = block * 128;
+
+		/* Skip any non-CEA-861 extension blocks */
+		if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
+			continue;
+
+		/* search Vendor Specific Data Block (tag 3) */
+		d = edid[offset + 2] & 0x7f;
+		/* Check if there are Data Blocks */
+		if (d <= 4)
+			continue;
+		if (d > 4) {
+			unsigned int i = offset + 4;
+			unsigned int end = offset + d;
+
+			/* Note: 'end' is always < 'size' */
+			do {
+				u8 tag = edid[i] >> 5;
+				u8 len = edid[i] & 0x1f;
+
+				if (tag == 3 && len >= 5 && i + len <= end)
+					return i + 4;
+				i += len + 1;
+			} while (i < end);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/staging/media/cec/Kconfig b/drivers/staging/media/cec/Kconfig
index 3297a54..8a7acee 100644
--- a/drivers/staging/media/cec/Kconfig
+++ b/drivers/staging/media/cec/Kconfig
@@ -6,3 +6,9 @@ config MEDIA_CEC

 	  To compile this driver as a module, choose M here: the
 	  module will be called cec.
+
+config MEDIA_CEC_DEBUG
+	bool "CEC debugfs interface (EXPERIMENTAL)"
+	depends on MEDIA_CEC && DEBUG_FS
+	---help---
+	  Turns on the DebugFS interface for CEC devices.
diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO
index e3c384a..a8f4b7d 100644
--- a/drivers/staging/media/cec/TODO
+++ b/drivers/staging/media/cec/TODO
@@ -19,5 +19,9 @@ Other TODOs:
   is only sent to the filehandle that transmitted the original message
   and not to any followers. Should this behavior change or perhaps
   controlled through a cec_msg flag?
+- Should CEC_LOG_ADDR_TYPE_SPECIFIC be replaced by TYPE_2ND_TV and TYPE_PROCESSOR?
+  And also TYPE_SWITCH and TYPE_CDC_ONLY in addition to the TYPE_UNREGISTERED?
+  This should give the framework more information about the device type
+  since SPECIFIC and UNREGISTERED give no useful information.

 Hans Verkuil <hans.verkuil@cisco.com>
diff --git a/drivers/staging/media/cec/cec.c b/drivers/staging/media/cec/cec.c
index 8634773..4eb087e 100644
--- a/drivers/staging/media/cec/cec.c
+++ b/drivers/staging/media/cec/cec.c
@@ -104,64 +104,48 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
 	return adap->log_addrs.primary_device_type[i < 0 ? 0 : i];
 }

-/* Initialize the event queues for the filehandle. */
-static int cec_queue_event_init(struct cec_fh *fh)
-{
-	/* This has the size of the event queue for each event type. */
-	static const unsigned int queue_sizes[CEC_NUM_EVENTS] = {
-		2,	/* CEC_EVENT_STATE_CHANGE */
-		1,	/* CEC_EVENT_LOST_MSGS */
-	};
-	unsigned int i;
-
-	for (i = 0; i < CEC_NUM_EVENTS; i++) {
-		fh->evqueue[i].events = kcalloc(queue_sizes[i],
-				sizeof(struct cec_event), GFP_KERNEL);
-		if (!fh->evqueue[i].events) {
-			while (i--) {
-				kfree(fh->evqueue[i].events);
-				fh->evqueue[i].events = NULL;
-				fh->evqueue[i].elems = 0;
-			}
-			return -ENOMEM;
-		}
-		fh->evqueue[i].elems = queue_sizes[i];
-	}
-	return 0;
-}
-
-static void cec_queue_event_free(struct cec_fh *fh)
-{
-	unsigned int i;
-
-	for (i = 0; i < CEC_NUM_EVENTS; i++)
-		kfree(fh->evqueue[i].events);
-}
-
 /*
  * Queue a new event for this filehandle. If ts == 0, then set it
  * to the current time.
+ *
+ * The two events that are currently defined do not need to keep track
+ * of intermediate events, so no actual queue of events is needed,
+ * instead just store the latest state and the total number of lost
+ * messages.
+ *
+ * Should new events be added in the future that require intermediate
+ * results to be queued as well, then a proper queue data structure is
+ * required. But until then, just keep it simple.
  */
 static void cec_queue_event_fh(struct cec_fh *fh,
 			       const struct cec_event *new_ev, u64 ts)
 {
-	struct cec_event_queue *evq = &fh->evqueue[new_ev->event - 1];
-	struct cec_event *ev;
+	struct cec_event *ev = &fh->events[new_ev->event - 1];

 	if (ts == 0)
 		ts = ktime_get_ns();

 	mutex_lock(&fh->lock);
-	ev = evq->events + evq->num_events;
-	/* Overwrite the last event if there is no more room for the new event */
-	if (evq->num_events == evq->elems) {
-		ev--;
-	} else {
-		evq->num_events++;
-		fh->events++;
+	if (new_ev->event == CEC_EVENT_LOST_MSGS &&
+	    fh->pending_events & (1 << new_ev->event)) {
+		/*
+		 * If there is already a lost_msgs event, then just
+		 * update the lost_msgs count. This effectively
+		 * merges the old and new events into one.
+		 */
+		ev->lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs;
+		goto unlock;
 	}
+
+	/*
+	 * Intermediate states are not interesting, so just
+	 * overwrite any older event.
+	 */
 	*ev = *new_ev;
 	ev->ts = ts;
+	fh->pending_events |= 1 << new_ev->event;
+
+unlock:
 	mutex_unlock(&fh->lock);
 	wake_up_interruptible(&fh->wait);
 }
@@ -185,27 +169,35 @@ static void cec_queue_event(struct cec_adapter *adap,
  */
 static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg)
 {
-	struct cec_event ev_lost_msg = {
+	static const struct cec_event ev_lost_msg = {
 		.event = CEC_EVENT_LOST_MSGS,
+		.lost_msgs.lost_msgs = 1,
 	};
 	struct cec_msg_entry *entry;

 	mutex_lock(&fh->lock);
-	if (fh->queued_msgs == CEC_MAX_MSG_QUEUE_SZ)
-		goto lost_msgs;
 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
 		goto lost_msgs;

 	entry->msg = *msg;
-	list_add(&entry->list, &fh->msgs);
+	/* Add new msg at the end of the queue */
+	list_add_tail(&entry->list, &fh->msgs);
+
+	/*
+	 * if the queue now has more than CEC_MAX_MSG_QUEUE_SZ
+	 * messages, drop the oldest one and send a lost message event.
+	 */
+	if (fh->queued_msgs == CEC_MAX_MSG_QUEUE_SZ) {
+		list_del(&entry->list);
+		goto lost_msgs;
+	}
 	fh->queued_msgs++;
 	mutex_unlock(&fh->lock);
 	wake_up_interruptible(&fh->wait);
 	return;

 lost_msgs:
-	ev_lost_msg.lost_msgs.lost_msgs = ++fh->lost_msgs;
 	mutex_unlock(&fh->lock);
 	cec_queue_event_fh(fh, &ev_lost_msg, 0);
 }
@@ -548,12 +540,13 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
 	cec_queue_msg_monitor(adap, msg, 1);

 	/*
-	 * Clear reply on error of if the adapter is no longer
-	 * configured. It makes no sense to wait for a reply in
-	 * this case.
+	 * Clear reply and timeout on error or if the adapter is no longer
+	 * configured. It makes no sense to wait for a reply in that case.
 	 */
-	if (!(status & CEC_TX_STATUS_OK) || !adap->is_configured)
+	if (!(status & CEC_TX_STATUS_OK) || !adap->is_configured) {
 		msg->reply = 0;
+		msg->timeout = 0;
+	}

 	if (msg->timeout) {
 		/*
@@ -908,7 +901,7 @@ static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx)
 	msg.msg[3] = las->all_device_types[la_idx];

 	/* Write RC Profiles first, then Device Features */
-	for (idx = 0; idx < sizeof(las->features[0]); idx++) {
+	for (idx = 0; idx < ARRAY_SIZE(las->features[0]); idx++) {
 		msg.msg[msg.len++] = features[idx];
 		if ((features[idx] & CEC_OP_FEAT_EXT) == 0) {
 			if (op_is_dev_features)
@@ -1543,14 +1536,15 @@ static int __cec_s_log_addrs(struct cec_adapter *adap,
 		if (log_addrs->cec_version < CEC_OP_CEC_VERSION_2_0)
 			continue;

-		for (i = 0; i < sizeof(log_addrs->features[0]); i++) {
+		for (i = 0; i < ARRAY_SIZE(log_addrs->features[0]); i++) {
 			if ((features[i] & 0x80) == 0) {
 				if (op_is_dev_features)
 					break;
 				op_is_dev_features = true;
 			}
 		}
-		if (!op_is_dev_features || i == sizeof(log_addrs->features[0])) {
+		if (!op_is_dev_features ||
+		    i == ARRAY_SIZE(log_addrs->features[0])) {
 			dprintk(1, "malformed features\n");
 			return -EINVAL;
 		}
@@ -1596,6 +1590,7 @@ int cec_s_log_addrs(struct cec_adapter *adap,
 }
 EXPORT_SYMBOL_GPL(cec_s_log_addrs);

+#ifdef CONFIG_MEDIA_CEC_DEBUG
 /*
  * Log the current state of the CEC adapter.
  * Very useful for debugging.
@@ -1637,6 +1632,7 @@ static int cec_status(struct seq_file *file, void *priv)
 	mutex_unlock(&adap->lock);
 	return 0;
 }
+#endif

 /* CEC file operations */

@@ -1655,7 +1651,7 @@ static unsigned int cec_poll(struct file *filp,
 		res |= POLLOUT | POLLWRNORM;
 	if (fh->queued_msgs)
 		res |= POLLIN | POLLRDNORM;
-	if (fh->events)
+	if (fh->pending_events)
 		res |= POLLPRI;
 	poll_wait(filp, &fh->wait, poll);
 	mutex_unlock(&adap->lock);
@@ -1685,6 +1681,149 @@ static void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
 		WARN_ON(call_op(adap, adap_monitor_all_enable, 0));
 }

+static bool cec_is_busy(const struct cec_adapter *adap,
+			const struct cec_fh *fh)
+{
+	bool valid_initiator = adap->cec_initiator && adap->cec_initiator == fh;
+	bool valid_follower = adap->cec_follower && adap->cec_follower == fh;
+
+	/*
+	 * Exclusive initiators and followers can always access the CEC adapter
+	 */
+	if (valid_initiator || valid_follower)
+		return false;
+	/*
+	 * All others can only access the CEC adapter if there is no
+	 * exclusive initiator and they are in INITIATOR mode.
+	 */
+	return adap->cec_initiator ||
+	       fh->mode_initiator == CEC_MODE_NO_INITIATOR;
+}
+
+static long cec_adap_g_caps(struct cec_adapter *adap,
+			    struct cec_caps __user *parg)
+{
+	struct cec_caps caps = {};
+
+	strlcpy(caps.driver, adap->devnode.parent->driver->name,
+		sizeof(caps.driver));
+	strlcpy(caps.name, adap->name, sizeof(caps.name));
+	caps.available_log_addrs = adap->available_log_addrs;
+	caps.capabilities = adap->capabilities;
+	caps.version = LINUX_VERSION_CODE;
+	if (copy_to_user(parg, &caps, sizeof(caps)))
+		return -EFAULT;
+	return 0;
+}
+
+static long cec_adap_g_phys_addr(struct cec_adapter *adap,
+				 __u16 __user *parg)
+{
+	u16 phys_addr;
+
+	mutex_lock(&adap->lock);
+	phys_addr = adap->phys_addr;
+	mutex_unlock(&adap->lock);
+	if (copy_to_user(parg, &phys_addr, sizeof(phys_addr)))
+		return -EFAULT;
+	return 0;
+}
+
+static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh,
+				 bool block, __u16 __user *parg)
+{
+	u16 phys_addr;
+	long err;
+
+	if (!(adap->capabilities & CEC_CAP_PHYS_ADDR))
+		return -ENOTTY;
+	if (copy_from_user(&phys_addr, parg, sizeof(phys_addr)))
+		return -EFAULT;
+
+	err = cec_phys_addr_validate(phys_addr, NULL, NULL);
+	if (err)
+		return err;
+	mutex_lock(&adap->lock);
+	if (cec_is_busy(adap, fh))
+		err = -EBUSY;
+	else
+		__cec_s_phys_addr(adap, phys_addr, block);
+	mutex_unlock(&adap->lock);
+	return err;
+}
+
+static long cec_adap_g_log_addrs(struct cec_adapter *adap,
+				 struct cec_log_addrs __user *parg)
+{
+	struct cec_log_addrs log_addrs;
+
+	mutex_lock(&adap->lock);
+	log_addrs = adap->log_addrs;
+	if (!adap->is_configured)
+		memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID,
+		       sizeof(log_addrs.log_addr));
+	mutex_unlock(&adap->lock);
+
+	if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
+		return -EFAULT;
+	return 0;
+}
+
+static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh,
+				 bool block, struct cec_log_addrs __user *parg)
+{
+	struct cec_log_addrs log_addrs;
+	long err = -EBUSY;
+
+	if (!(adap->capabilities & CEC_CAP_LOG_ADDRS))
+		return -ENOTTY;
+	if (copy_from_user(&log_addrs, parg, sizeof(log_addrs)))
+		return -EFAULT;
+	log_addrs.flags = 0;
+	mutex_lock(&adap->lock);
+	if (!adap->is_configuring &&
+	    (!log_addrs.num_log_addrs || !adap->is_configured) &&
+	    !cec_is_busy(adap, fh)) {
+		err = __cec_s_log_addrs(adap, &log_addrs, block);
+		if (!err)
+			log_addrs = adap->log_addrs;
+	}
+	mutex_unlock(&adap->lock);
+	if (err)
+		return err;
+	if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
+		return -EFAULT;
+	return 0;
+}
+
+static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh,
+			 bool block, struct cec_msg __user *parg)
+{
+	struct cec_msg msg = {};
+	long err = 0;
+
+	if (!(adap->capabilities & CEC_CAP_TRANSMIT))
+		return -ENOTTY;
+	if (copy_from_user(&msg, parg, sizeof(msg)))
+		return -EFAULT;
+	mutex_lock(&adap->lock);
+	if (!adap->is_configured) {
+		err = -ENONET;
+	} else if (cec_is_busy(adap, fh)) {
+		err = -EBUSY;
+	} else {
+		if (!block || !msg.reply)
+			fh = NULL;
+		err = cec_transmit_msg_fh(adap, &msg, fh, block);
+	}
+	mutex_unlock(&adap->lock);
+	if (err)
+		return err;
+	if (copy_to_user(parg, &msg, sizeof(msg)))
+		return -EFAULT;
+	return 0;
+}
+
 /* Called by CEC_RECEIVE: wait for a message to arrive */
 static int cec_receive_msg(struct cec_fh *fh, struct cec_msg *msg, bool block)
 {
@@ -1703,15 +1842,16 @@ static int cec_receive_msg(struct cec_fh *fh, struct cec_msg *msg, bool block)
 			*msg = entry->msg;
 			kfree(entry);
 			fh->queued_msgs--;
-			res = 0;
-		} else {
-			/* No, return EAGAIN in non-blocking mode or wait */
-			res = -EAGAIN;
+			mutex_unlock(&fh->lock);
+			return 0;
 		}
+
+		/* No, return EAGAIN in non-blocking mode or wait */
 		mutex_unlock(&fh->lock);
-		/* Return when in non-blocking mode or if we have a message */
-		if (!block || !res)
-			break;
+
+		/* Return when in non-blocking mode */
+		if (!block)
+			return -EAGAIN;

 		if (msg->timeout) {
 			/* The user specified a timeout */
@@ -1732,322 +1872,222 @@ static int cec_receive_msg(struct cec_fh *fh, struct cec_msg *msg, bool block)
 	return res;
 }

-static bool cec_is_busy(const struct cec_adapter *adap,
-			const struct cec_fh *fh)
+static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh,
+			bool block, struct cec_msg __user *parg)
 {
-	bool valid_initiator = adap->cec_initiator && adap->cec_initiator == fh;
-	bool valid_follower = adap->cec_follower && adap->cec_follower == fh;
+	struct cec_msg msg = {};
+	long err = 0;

-	/*
-	 * Exclusive initiators and followers can always access the CEC adapter
-	 */
-	if (valid_initiator || valid_follower)
-		return false;
-	/*
-	 * All others can only access the CEC adapter if there is no
-	 * exclusive initiator and they are in INITIATOR mode.
-	 */
-	return adap->cec_initiator ||
-	       fh->mode_initiator == CEC_MODE_NO_INITIATOR;
+	if (copy_from_user(&msg, parg, sizeof(msg)))
+		return -EFAULT;
+	mutex_lock(&adap->lock);
+	if (!adap->is_configured)
+		err = -ENONET;
+	mutex_unlock(&adap->lock);
+	if (err)
+		return err;
+
+	err = cec_receive_msg(fh, &msg, block);
+	if (err)
+		return err;
+	if (copy_to_user(parg, &msg, sizeof(msg)))
+		return -EFAULT;
+	return 0;
 }

-static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh,
+			bool block, struct cec_event __user *parg)
 {
-	struct cec_devnode *devnode = cec_devnode_data(filp);
-	struct cec_fh *fh = filp->private_data;
-	struct cec_adapter *adap = fh->adap;
-	bool block = !(filp->f_flags & O_NONBLOCK);
-	void __user *parg = (void __user *)arg;
-	int err = 0;
-
-	if (!devnode->registered)
-		return -EIO;
+	struct cec_event *ev = NULL;
+	u64 ts = ~0ULL;
+	unsigned int i;
+	long err = 0;

-	switch (cmd) {
-	case CEC_ADAP_G_CAPS: {
-		struct cec_caps caps = {};
-
-		strlcpy(caps.driver, adap->devnode.parent->driver->name,
-			sizeof(caps.driver));
-		strlcpy(caps.name, adap->name, sizeof(caps.name));
-		caps.available_log_addrs = adap->available_log_addrs;
-		caps.capabilities = adap->capabilities;
-		caps.version = LINUX_VERSION_CODE;
-		if (copy_to_user(parg, &caps, sizeof(caps)))
-			return -EFAULT;
-		break;
+	mutex_lock(&fh->lock);
+	while (!fh->pending_events && block) {
+		mutex_unlock(&fh->lock);
+		err = wait_event_interruptible(fh->wait, fh->pending_events);
+		if (err)
+			return err;
+		mutex_lock(&fh->lock);
 	}

-	case CEC_TRANSMIT: {
-		struct cec_msg msg = {};
-
-		if (!(adap->capabilities & CEC_CAP_TRANSMIT))
-			return -ENOTTY;
-		if (copy_from_user(&msg, parg, sizeof(msg)))
-			return -EFAULT;
-		mutex_lock(&adap->lock);
-		if (!adap->is_configured) {
-			err = -ENONET;
-		} else if (cec_is_busy(adap, fh)) {
-			err = -EBUSY;
-		} else {
-			if (!block || !msg.reply)
-				fh = NULL;
-			err = cec_transmit_msg_fh(adap, &msg, fh, block);
+	/* Find the oldest event */
+	for (i = 0; i < CEC_NUM_EVENTS; i++) {
+		if (fh->pending_events & (1 << (i + 1)) &&
+		    fh->events[i].ts <= ts) {
+			ev = &fh->events[i];
+			ts = ev->ts;
 		}
-		mutex_unlock(&adap->lock);
-		if (err)
-			return err;
-		if (copy_to_user(parg, &msg, sizeof(msg)))
-			return -EFAULT;
-		break;
+	}
+	if (!ev) {
+		err = -EAGAIN;
+		goto unlock;
 	}

-	case CEC_RECEIVE: {
-		struct cec_msg msg = {};
+	if (copy_to_user(parg, ev, sizeof(*ev))) {
+		err = -EFAULT;
+		goto unlock;
+	}

-		if (copy_from_user(&msg, parg, sizeof(msg)))
-			return -EFAULT;
-		mutex_lock(&adap->lock);
-		if (!adap->is_configured)
-			err = -ENONET;
-		mutex_unlock(&adap->lock);
-		if (err)
-			return err;
+	fh->pending_events &= ~(1 << ev->event);

-		err = cec_receive_msg(fh, &msg, block);
-		if (err)
-			return err;
-		if (copy_to_user(parg, &msg, sizeof(msg)))
-			return -EFAULT;
-		break;
-	}
+unlock:
+	mutex_unlock(&fh->lock);
+	return err;
+}

-	case CEC_DQEVENT: {
-		struct cec_event_queue *evq = NULL;
-		struct cec_event *ev = NULL;
-		u64 ts = ~0ULL;
-		unsigned int i;
+static long cec_g_mode(struct cec_adapter *adap, struct cec_fh *fh,
+		       u32 __user *parg)
+{
+	u32 mode = fh->mode_initiator | fh->mode_follower;

-		mutex_lock(&fh->lock);
-		while (!fh->events && block) {
-			mutex_unlock(&fh->lock);
-			err = wait_event_interruptible(fh->wait, fh->events);
-			if (err)
-				return err;
-			mutex_lock(&fh->lock);
-		}
+	if (copy_to_user(parg, &mode, sizeof(mode)))
+		return -EFAULT;
+	return 0;
+}

-		/* Find the oldest event */
-		for (i = 0; i < CEC_NUM_EVENTS; i++) {
-			struct cec_event_queue *q = fh->evqueue + i;
+static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,
+		       u32 __user *parg)
+{
+	u32 mode;
+	u8 mode_initiator;
+	u8 mode_follower;
+	long err = 0;
+
+	if (copy_from_user(&mode, parg, sizeof(mode)))
+		return -EFAULT;
+	if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK))
+		return -EINVAL;

-			if (q->num_events && q->events->ts <= ts) {
-				evq = q;
-				ev = q->events;
-				ts = ev->ts;
-			}
-		}
-		err = -EAGAIN;
-		if (ev) {
-			if (copy_to_user(parg, ev, sizeof(*ev))) {
-				err = -EFAULT;
-			} else {
-				unsigned int j;
-
-				evq->num_events--;
-				fh->events--;
-				/*
-				 * Reset lost message counter after returning
-				 * this event.
-				 */
-				if (ev->event == CEC_EVENT_LOST_MSGS)
-					fh->lost_msgs = 0;
-				for (j = 0; j < evq->num_events; j++)
-					evq->events[j] = evq->events[j + 1];
-				err = 0;
-			}
-		}
-		mutex_unlock(&fh->lock);
-		return err;
-	}
+	mode_initiator = mode & CEC_MODE_INITIATOR_MSK;
+	mode_follower = mode & CEC_MODE_FOLLOWER_MSK;

-	case CEC_ADAP_G_PHYS_ADDR: {
-		u16 phys_addr;
+	if (mode_initiator > CEC_MODE_EXCL_INITIATOR ||
+	    mode_follower > CEC_MODE_MONITOR_ALL)
+		return -EINVAL;

-		mutex_lock(&adap->lock);
-		phys_addr = adap->phys_addr;
-		if (copy_to_user(parg, &phys_addr, sizeof(adap->phys_addr)))
-			err = -EFAULT;
-		mutex_unlock(&adap->lock);
-		break;
-	}
+	if (mode_follower == CEC_MODE_MONITOR_ALL &&
+	    !(adap->capabilities & CEC_CAP_MONITOR_ALL))
+		return -EINVAL;

-	case CEC_ADAP_S_PHYS_ADDR: {
-		u16 phys_addr;
+	/* Follower modes should always be able to send CEC messages */
+	if ((mode_initiator == CEC_MODE_NO_INITIATOR ||
+	     !(adap->capabilities & CEC_CAP_TRANSMIT)) &&
+	    mode_follower >= CEC_MODE_FOLLOWER &&
+	    mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU)
+		return -EINVAL;

-		if (!(adap->capabilities & CEC_CAP_PHYS_ADDR))
-			return -ENOTTY;
-		if (copy_from_user(&phys_addr, parg, sizeof(phys_addr)))
-			return -EFAULT;
+	/* Monitor modes require CEC_MODE_NO_INITIATOR */
+	if (mode_initiator && mode_follower >= CEC_MODE_MONITOR)
+		return -EINVAL;

-		err = cec_phys_addr_validate(phys_addr, NULL, NULL);
-		if (err)
-			return err;
-		mutex_lock(&adap->lock);
-		if (cec_is_busy(adap, fh))
-			err = -EBUSY;
-		else
-			__cec_s_phys_addr(adap, phys_addr, block);
-		mutex_unlock(&adap->lock);
-		break;
-	}
+	/* Monitor modes require CAP_NET_ADMIN */
+	if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN))
+		return -EPERM;

-	case CEC_ADAP_G_LOG_ADDRS: {
-		struct cec_log_addrs log_addrs;
+	mutex_lock(&adap->lock);
+	/*
+	 * You can't become exclusive follower if someone else already
+	 * has that job.
+	 */
+	if ((mode_follower == CEC_MODE_EXCL_FOLLOWER ||
+	     mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) &&
+	    adap->cec_follower && adap->cec_follower != fh)
+		err = -EBUSY;
+	/*
+	 * You can't become exclusive initiator if someone else already
+	 * has that job.
+	 */
+	if (mode_initiator == CEC_MODE_EXCL_INITIATOR &&
+	    adap->cec_initiator && adap->cec_initiator != fh)
+		err = -EBUSY;

-		mutex_lock(&adap->lock);
-		log_addrs = adap->log_addrs;
-		if (!adap->is_configured)
-			memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID,
-			       sizeof(log_addrs.log_addr));
-		mutex_unlock(&adap->lock);
+	if (!err) {
+		bool old_mon_all = fh->mode_follower == CEC_MODE_MONITOR_ALL;
+		bool new_mon_all = mode_follower == CEC_MODE_MONITOR_ALL;

-		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
-			return -EFAULT;
-		break;
+		if (old_mon_all != new_mon_all) {
+			if (new_mon_all)
+				err = cec_monitor_all_cnt_inc(adap);
+			else
+				cec_monitor_all_cnt_dec(adap);
+		}
 	}

-	case CEC_ADAP_S_LOG_ADDRS: {
-		struct cec_log_addrs log_addrs;
-
-		if (!(adap->capabilities & CEC_CAP_LOG_ADDRS))
-			return -ENOTTY;
-		if (copy_from_user(&log_addrs, parg, sizeof(log_addrs)))
-			return -EFAULT;
-		log_addrs.flags = 0;
-		mutex_lock(&adap->lock);
-		if (adap->is_configuring)
-			err = -EBUSY;
-		else if (log_addrs.num_log_addrs && adap->is_configured)
-			err = -EBUSY;
-		else if (cec_is_busy(adap, fh))
-			err = -EBUSY;
-		else
-			err = __cec_s_log_addrs(adap, &log_addrs, block);
-		if (!err)
-			log_addrs = adap->log_addrs;
+	if (err) {
 		mutex_unlock(&adap->lock);
-		if (!err && copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
-			return -EFAULT;
-		break;
+		return err;
 	}

-	case CEC_G_MODE: {
-		u32 mode = fh->mode_initiator | fh->mode_follower;
-
-		if (copy_to_user(parg, &mode, sizeof(mode)))
-			return -EFAULT;
-		break;
+	if (fh->mode_follower == CEC_MODE_FOLLOWER)
+		adap->follower_cnt--;
+	if (mode_follower == CEC_MODE_FOLLOWER)
+		adap->follower_cnt++;
+	if (mode_follower == CEC_MODE_EXCL_FOLLOWER ||
+	    mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) {
+		adap->passthrough =
+			mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
+		adap->cec_follower = fh;
+	} else if (adap->cec_follower == fh) {
+		adap->passthrough = false;
+		adap->cec_follower = NULL;
 	}
+	if (mode_initiator == CEC_MODE_EXCL_INITIATOR)
+		adap->cec_initiator = fh;
+	else if (adap->cec_initiator == fh)
+		adap->cec_initiator = NULL;
+	fh->mode_initiator = mode_initiator;
+	fh->mode_follower = mode_follower;
+	mutex_unlock(&adap->lock);
+	return 0;
+}

-	case CEC_S_MODE: {
-		u32 mode;
-		u8 mode_initiator;
-		u8 mode_follower;
+static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct cec_devnode *devnode = cec_devnode_data(filp);
+	struct cec_fh *fh = filp->private_data;
+	struct cec_adapter *adap = fh->adap;
+	bool block = !(filp->f_flags & O_NONBLOCK);
+	void __user *parg = (void __user *)arg;

-		if (copy_from_user(&mode, parg, sizeof(mode)))
-			return -EFAULT;
-		if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK))
-			return -EINVAL;
+	if (!devnode->registered)
+		return -EIO;

-		mode_initiator = mode & CEC_MODE_INITIATOR_MSK;
-		mode_follower = mode & CEC_MODE_FOLLOWER_MSK;
+	switch (cmd) {
+	case CEC_ADAP_G_CAPS:
+		return cec_adap_g_caps(adap, parg);

-		if (mode_initiator > CEC_MODE_EXCL_INITIATOR ||
-		    mode_follower > CEC_MODE_MONITOR_ALL)
-			return -EINVAL;
+	case CEC_ADAP_G_PHYS_ADDR:
+		return cec_adap_g_phys_addr(adap, parg);

-		if (mode_follower == CEC_MODE_MONITOR_ALL &&
-		    !(adap->capabilities & CEC_CAP_MONITOR_ALL))
-			return -EINVAL;
+	case CEC_ADAP_S_PHYS_ADDR:
+		return cec_adap_s_phys_addr(adap, fh, block, parg);

-		/* Follower modes should always be able to send CEC messages */
-		if ((mode_initiator == CEC_MODE_NO_INITIATOR ||
-		     !(adap->capabilities & CEC_CAP_TRANSMIT)) &&
-		    mode_follower >= CEC_MODE_FOLLOWER &&
-		    mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU)
-			return -EINVAL;
+	case CEC_ADAP_G_LOG_ADDRS:
+		return cec_adap_g_log_addrs(adap, parg);

-		/* Monitor modes require CEC_MODE_NO_INITIATOR */
-		if (mode_initiator && mode_follower >= CEC_MODE_MONITOR)
-			return -EINVAL;
+	case CEC_ADAP_S_LOG_ADDRS:
+		return cec_adap_s_log_addrs(adap, fh, block, parg);

-		/* Monitor modes require CAP_NET_ADMIN */
-		if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN))
-			return -EPERM;
+	case CEC_TRANSMIT:
+		return cec_transmit(adap, fh, block, parg);

-		mutex_lock(&adap->lock);
-		/*
-		 * You can't become exclusive follower if someone else already
-		 * has that job.
-		 */
-		if ((mode_follower == CEC_MODE_EXCL_FOLLOWER ||
-		     mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) &&
-		    adap->cec_follower && adap->cec_follower != fh)
-			err = -EBUSY;
-		/*
-		 * You can't become exclusive initiator if someone else already
-		 * has that job.
-		 */
-		if (mode_initiator == CEC_MODE_EXCL_INITIATOR &&
-		    adap->cec_initiator && adap->cec_initiator != fh)
-			err = -EBUSY;
-
-		if (!err) {
-			bool old_mon_all = fh->mode_follower == CEC_MODE_MONITOR_ALL;
-			bool new_mon_all = mode_follower == CEC_MODE_MONITOR_ALL;
-
-			if (old_mon_all != new_mon_all) {
-				if (new_mon_all)
-					err = cec_monitor_all_cnt_inc(adap);
-				else
-					cec_monitor_all_cnt_dec(adap);
-			}
-		}
+	case CEC_RECEIVE:
+		return cec_receive(adap, fh, block, parg);

-		if (err) {
-			mutex_unlock(&adap->lock);
-			break;
-		}
+	case CEC_DQEVENT:
+		return cec_dqevent(adap, fh, block, parg);

-		if (fh->mode_follower == CEC_MODE_FOLLOWER)
-			adap->follower_cnt--;
-		if (mode_follower == CEC_MODE_FOLLOWER)
-			adap->follower_cnt++;
-		if (mode_follower == CEC_MODE_EXCL_FOLLOWER ||
-		    mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) {
-			adap->passthrough =
-				mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
-			adap->cec_follower = fh;
-		} else if (adap->cec_follower == fh) {
-			adap->passthrough = false;
-			adap->cec_follower = NULL;
-		}
-		if (mode_initiator == CEC_MODE_EXCL_INITIATOR)
-			adap->cec_initiator = fh;
-		else if (adap->cec_initiator == fh)
-			adap->cec_initiator = NULL;
-		fh->mode_initiator = mode_initiator;
-		fh->mode_follower = mode_follower;
-		mutex_unlock(&adap->lock);
-		break;
-	}
+	case CEC_G_MODE:
+		return cec_g_mode(adap, fh, parg);
+
+	case CEC_S_MODE:
+		return cec_s_mode(adap, fh, parg);

 	default:
 		return -ENOTTY;
 	}
-	return err;
 }

 static int cec_open(struct inode *inode, struct file *filp)
@@ -2064,18 +2104,10 @@ static int cec_open(struct inode *inode, struct file *filp)
 		.event = CEC_EVENT_STATE_CHANGE,
 		.flags = CEC_EVENT_FL_INITIAL_STATE,
 	};
-	int ret;

 	if (!fh)
 		return -ENOMEM;

-	ret = cec_queue_event_init(fh);
-
-	if (ret) {
-		kfree(fh);
-		return ret;
-	}
-
 	INIT_LIST_HEAD(&fh->msgs);
 	INIT_LIST_HEAD(&fh->xfer_list);
 	mutex_init(&fh->lock);
@@ -2098,7 +2130,6 @@ static int cec_open(struct inode *inode, struct file *filp)
 	 */
 	if (!devnode->registered) {
 		mutex_unlock(&cec_devnode_lock);
-		cec_queue_event_free(fh);
 		kfree(fh);
 		return -ENXIO;
 	}
@@ -2162,7 +2193,6 @@ static int cec_release(struct inode *inode, struct file *filp)
 		list_del(&entry->list);
 		kfree(entry);
 	}
-	cec_queue_event_free(fh);
 	kfree(fh);

 	/*
@@ -2201,9 +2231,8 @@ static struct bus_type cec_bus_type = {
 	.name = CEC_NAME,
 };

-/**
- * cec_devnode_register - register a cec device node
- * @devnode: cec device node structure we want to register
+/*
+ * Register a cec device node
  *
  * The registration code assigns minor numbers and registers the new device node
  * with the kernel. An error is returned if no free minor number can be found,
@@ -2267,13 +2296,11 @@ cdev_del:
 	cdev_del(&devnode->cdev);
 clr_bit:
 	clear_bit(devnode->minor, cec_devnode_nums);
-	put_device(&devnode->dev);
 	return ret;
 }

-/**
- * cec_devnode_unregister - unregister a cec device node
- * @devnode: the device node to unregister
+/*
+ * Unregister a cec device node
  *
  * This unregisters the passed device. Future open calls will be met with
  * errors.
@@ -2371,6 +2398,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
 	adap->rc->input_id.version = 1;
 	adap->rc->dev.parent = parent;
 	adap->rc->driver_type = RC_DRIVER_SCANCODE;
+	adap->rc->driver_name = CEC_NAME;
 	adap->rc->allowed_protocols = RC_BIT_CEC;
 	adap->rc->priv = adap;
 	adap->rc->map_name = RC_MAP_CEC;
@@ -2404,16 +2432,17 @@ int cec_register_adapter(struct cec_adapter *adap)
 #endif

 	res = cec_devnode_register(&adap->devnode, adap->owner);
-#if IS_ENABLED(CONFIG_RC_CORE)
 	if (res) {
+#if IS_ENABLED(CONFIG_RC_CORE)
 		/* Note: rc_unregister also calls rc_free */
 		rc_unregister_device(adap->rc);
 		adap->rc = NULL;
+#endif
 		return res;
 	}
-#endif

 	dev_set_drvdata(&adap->devnode.dev, adap);
+#ifdef CONFIG_MEDIA_CEC_DEBUG
 	if (!top_cec_dir)
 		return 0;

@@ -2429,6 +2458,7 @@ int cec_register_adapter(struct cec_adapter *adap)
 		debugfs_remove_recursive(adap->cec_dir);
 		adap->cec_dir = NULL;
 	}
+#endif
 	return 0;
 }
 EXPORT_SYMBOL_GPL(cec_register_adapter);
@@ -2481,11 +2511,13 @@ static int __init cec_devnode_init(void)
 		return ret;
 	}

+#ifdef CONFIG_MEDIA_CEC_DEBUG
 	top_cec_dir = debugfs_create_dir("cec", NULL);
 	if (IS_ERR_OR_NULL(top_cec_dir)) {
 		pr_warn("cec: Failed to create debugfs cec dir\n");
 		top_cec_dir = NULL;
 	}
+#endif

 	ret = bus_register(&cec_bus_type);
 	if (ret < 0) {
diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h
index 155f6b9..8ee1029 100644
--- a/include/linux/cec-funcs.h
+++ b/include/linux/cec-funcs.h
@@ -17,6 +17,12 @@
  * SOFTWARE.
  */

+/*
+ * Note: this framework is still in staging and it is likely the API
+ * will change before it goes out of staging.
+ *
+ * Once it is moved out of staging this header will move to uapi.
+ */
 #ifndef _CEC_UAPI_FUNCS_H
 #define _CEC_UAPI_FUNCS_H

diff --git a/include/linux/cec.h b/include/linux/cec.h
index 0fd0e31..40924e7 100644
--- a/include/linux/cec.h
+++ b/include/linux/cec.h
@@ -17,6 +17,12 @@
  * SOFTWARE.
  */

+/*
+ * Note: this framework is still in staging and it is likely the API
+ * will change before it goes out of staging.
+ *
+ * Once it is moved out of staging this header will move to uapi.
+ */
 #ifndef _CEC_UAPI_H
 #define _CEC_UAPI_H

diff --git a/include/media/cec.h b/include/media/cec.h
index 25d89b1..9a791c0 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -85,12 +85,6 @@ struct cec_msg_entry {

 #define CEC_NUM_EVENTS		CEC_EVENT_LOST_MSGS

-struct cec_event_queue {
-	unsigned int		elems;
-	unsigned int		num_events;
-	struct cec_event	*events;
-};
-
 struct cec_fh {
 	struct list_head	list;
 	struct list_head	xfer_list;
@@ -100,12 +94,11 @@ struct cec_fh {

 	/* Events */
 	wait_queue_head_t	wait;
-	unsigned int		events;
-	struct cec_event_queue	evqueue[CEC_NUM_EVENTS];
+	unsigned int		pending_events;
+	struct cec_event	events[CEC_NUM_EVENTS];
 	struct mutex		lock;
 	struct list_head	msgs; /* queued messages */
 	unsigned int		queued_msgs;
-	unsigned int		lost_msgs;
 };

 #define CEC_SIGNAL_FREE_TIME_RETRY		3
@@ -133,9 +126,12 @@ struct cec_adap_ops {
  * With a transfer rate of at most 36 bytes per second this makes 18 messages
  * per second worst case.
  *
- * We queue at most 10 seconds worth of messages.
+ * We queue at most 3 seconds worth of messages. The CEC specification requires
+ * that messages are replied to within a second, so 3 seconds should give more
+ * than enough margin. Since most messages are actually more than 2 bytes, this
+ * is in practice a lot more than 3 seconds.
  */
-#define CEC_MAX_MSG_QUEUE_SZ		(18 * 10)
+#define CEC_MAX_MSG_QUEUE_SZ		(18 * 3)

 struct cec_adapter {
 	struct module *owner;

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-06-25 12:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-25 12:39 [PATCH] Diffs between the upcoming v19 series and the cec-topic branch Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).