This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit e00a3a0a2f6419d6c1f9dedb1098eb2879878296
Author: Jorge Guzman <[email protected]>
AuthorDate: Thu Jul 30 15:08:21 2026 -0300

    drivers/input: add a byte stream mode to the keyboard upper half
    
    The USB HID keyboard driver is about to report through the upper half
    rather than through a character device of its own, which changes what
    read() returns from a byte stream to struct keyboard_event_s.  Ten
    in-tree configurations have an application that consumes the byte
    stream.
    
    Add INPUT_KEYBOARD_BYTESTREAM, which renders each event with the
    keyboard codec instead of copying the event structure, so those
    applications keep working while they are converted.
    
    Only the press events are rendered.  A byte stream has no way to say
    that a key came up, which is exactly what a keyboard reporting through a
    character device has always delivered, so this reproduces the previous
    behaviour rather than adding to it.
    
    Signed-off-by: Jorge Guzman <[email protected]>
---
 drivers/input/Kconfig          | 28 +++++++++++--
 drivers/input/keyboard_upper.c | 95 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index bf769337398..59d2d989088 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -89,6 +89,25 @@ config INPUT_KEYBOARD
        bool
        default n
 
+config INPUT_KEYBOARD_BYTESTREAM
+       bool "Deliver a byte stream instead of keyboard events"
+       default n
+       depends on INPUT_KEYBOARD && LIBC_KBDCODEC
+       ---help---
+               By default a keyboard device delivers struct keyboard_event_s
+               events on read().  Select this to make it deliver the byte 
stream
+               defined by include/nuttx/input/kbd_codec.h instead, which is 
what
+               the USB HID keyboard driver provided before it moved to the
+               keyboard upper half.
+
+               This is meant for applications that have not been converted yet.
+               The byte stream cannot express a key release, so an application
+               that needs one has to read the events.
+
+               This applies to every keyboard in the build, so it cannot be 
used
+               to mix a byte stream consumer and an event consumer in the same
+               configuration.
+
 config INPUT_UINPUT
        bool
        default n
@@ -723,7 +742,7 @@ config INPUT_SPQ10KBD
        select I2C
        ---help---
                Enable the Solder Party Q10 BlackBerry Keyboard support.  This
-               exposes itself as a standard keyboard at /dev/keypadN.
+               exposes itself as a standard keyboard at /dev/kbdN.
                This keyboard exists both as a standalone module and integrated
                into the Solder Party Keyboard FeatherWing.  Information on this
                can be found at https://www.solder.party/docs/keyboard-pmod/
@@ -783,9 +802,12 @@ config INPUT_KMATRIX_DEBOUNCE
 
 config INPUT_KMATRIX_DEVPATH
        string "Device path"
-       default "/dev/keypad0"
+       default "/dev/kbd0"
        ---help---
-               Path where the keyboard matrix device will be registered. 
Default: /dev/keypad0
+               Path where the keyboard matrix device will be registered.  This 
is
+               the name that applications expect a keyboard to have, so keep 
the
+               /dev/kbdN form unless the board has a reason to differ.
+               Default: /dev/kbd0
 
 config INPUT_KMATRIX_I2C
        bool "Keyboard Matrix via I2C GPIO Expander"
diff --git a/drivers/input/keyboard_upper.c b/drivers/input/keyboard_upper.c
index 994190e57d1..2291b62f3be 100644
--- a/drivers/input/keyboard_upper.c
+++ b/drivers/input/keyboard_upper.c
@@ -33,6 +33,7 @@
 
 #include <nuttx/input/keyboard.h>
 #include <nuttx/input/kbd_codec.h>
+#include <nuttx/streams.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/list.h>
 #include <nuttx/circbuf.h>
@@ -42,6 +43,16 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM
+
+/* The longest sequence that one event can produce in the byte stream.  A
+ * normal key is a single byte; a special key is the four byte escape
+ * sequence emitted by kbd_specpress().
+ */
+
+#  define KEYBOARD_BYTESTREAM_MAX 4
+#endif
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -384,6 +395,66 @@ int keyboard_unregister(FAR struct keyboard_lowerhalf_s 
*lower,
   return 0;
 }
 
+/****************************************************************************
+ * Name: keyboard_encode
+ *
+ * Description:
+ *   Render one keyboard event as the byte stream that the keyboard codec
+ *   defines, for applications that consume characters rather than events.
+ *
+ *   Only the press events are rendered.  A byte stream has no way to say
+ *   that a key came up:  a normal key contributes its character and nothing
+ *   more, which is what a keyboard reporting through a character device has
+ *   always delivered.  An application that needs key releases has to read
+ *   the events instead.
+ *
+ * Input Parameters:
+ *   stream  - Memory stream to render into
+ *   buf     - Buffer of KEYBOARD_BYTESTREAM_MAX bytes backing the stream
+ *   keycode - The key
+ *   type    - The event type
+ *
+ * Returned Value:
+ *   The number of bytes rendered, zero if this event has no representation
+ *   in the byte stream.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM
+static size_t keyboard_encode(FAR struct lib_memoutstream_s *stream,
+                              FAR char *buf, uint32_t keycode, uint32_t type)
+{
+  lib_memoutstream(stream, buf, KEYBOARD_BYTESTREAM_MAX);
+
+  switch (type)
+    {
+      case KEYBOARD_PRESS:
+        kbd_press(keycode, &stream->common);
+        break;
+
+      case KEYBOARD_SPECPRESS:
+
+        /* Out of range keycodes would trip an assertion in the codec.  A
+         * lower half that reports something the codec does not know about
+         * simply does not appear in the byte stream.
+         */
+
+        if (keycode < FIRST_KEYCODE || keycode > LAST_KEYCODE)
+          {
+            return 0;
+          }
+
+        kbd_specpress(keycode, &stream->common);
+        break;
+
+      default:
+        return 0;
+    }
+
+  return stream->common.nput;
+}
+#endif
+
 /****************************************************************************
  * keyboard_event
  ****************************************************************************/
@@ -393,22 +464,42 @@ void keyboard_event(FAR struct keyboard_lowerhalf_s 
*lower, uint32_t keycode,
 {
   FAR struct keyboard_upperhalf_s *upper = lower->priv;
   FAR struct keyboard_opriv_s     *opriv;
-  struct keyboard_event_s          key;
   int semcount;
 
-  if (nxmutex_lock(&upper->lock) < 0)
+#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM
+  struct lib_memoutstream_s stream;
+  char buf[KEYBOARD_BYTESTREAM_MAX];
+  size_t buflen;
+
+  buflen = keyboard_encode(&stream, buf, keycode, type);
+  if (buflen == 0)
     {
+      /* This event has no representation in the byte stream */
+
       return;
     }
+#else
+  struct keyboard_event_s key;
 
   key.code = keycode;
   key.type = type;
+#endif
+
+  if (nxmutex_lock(&upper->lock) < 0)
+    {
+      return;
+    }
+
   list_for_every_entry(&upper->head, opriv, struct keyboard_opriv_s, node)
     {
       if (nxmutex_lock(&opriv->lock) == 0)
         {
+#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM
+          circbuf_overwrite(&opriv->circ, buf, buflen);
+#else
           circbuf_overwrite(&opriv->circ, &key,
                             sizeof(struct keyboard_event_s));
+#endif
           nxsem_get_value(&opriv->waitsem, &semcount);
           if (semcount < 1)
             {

Reply via email to