[RFC v2] rtems: Add options to kernel output char handler

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Apr 25 09:22:33 UTC 2024


Make the kernel I/O output character device processing configurable
through an option set parameter.  Add RTEMS_IO_NO_OUTPUT and
RTEMS_IO_DRAIN options.  The goal of this API change is to enable
draining the kernel output device in the system termination process
before a reset is issued.  A use case for using RTEMS_NO_WAIT is the
polled processing of an input and output stream from and to the I/O
device.
---
v2:

* Do not use EARS.

* Rename RTEMS_FLUSH in RTEMS_IO_DRAIN.

* Rename RTEMS_NO_OUTPUT in RTEMS_IO_NO_TRANSMISSION.

* Add example adoption for sparc/leon3.

 bsps/sparc/leon3/console/printk_support.c | 54 +++++++++++++++++++---
 cpukit/include/rtems/bspIo.h              | 55 ++++++++++++++++++++++-
 cpukit/include/rtems/rtems/options.h      | 22 ++++++++-
 cpukit/libcsupport/src/rtems_putc.c       |  4 +-
 testsuites/validation/tc-io-put-char.c    |  8 +++-
 testsuites/validation/tr-io-kernel.c      |  4 +-
 6 files changed, 132 insertions(+), 15 deletions(-)

diff --git a/bsps/sparc/leon3/console/printk_support.c b/bsps/sparc/leon3/console/printk_support.c
index fd23a5033f..adfd653060 100644
--- a/bsps/sparc/leon3/console/printk_support.c
+++ b/bsps/sparc/leon3/console/printk_support.c
@@ -43,6 +43,7 @@
 #include <bsp/leon3.h>
 #include <rtems/bspIo.h>
 #include <rtems/sysinit.h>
+#include <rtems/dev/io.h>
 #include <grlib/apbuart.h>
 #include <grlib/io.h>
 
@@ -56,6 +57,11 @@ apbuart *leon3_debug_uart = NULL;
 
 static void bsp_debug_uart_init(void);
 
+static bool apbuart_can_transmit(apbuart *regs)
+{
+  return (grlib_load_32(&regs->status) & APBUART_STATUS_TE) != 0;
+}
+
 static void apbuart_enable_receive_and_transmit(apbuart *regs)
 {
   uint32_t ctrl;
@@ -66,10 +72,38 @@ static void apbuart_enable_receive_and_transmit(apbuart *regs)
   grlib_store_32(&regs->status, 0);
 }
 
-static void bsp_debug_uart_output_char(char c)
+static rtems_status_code bsp_debug_uart_output_char(
+  char c,
+  rtems_option option_set
+)
 {
-  apbuart_outbyte_polled(leon3_debug_uart, c);
-  apbuart_outbyte_wait(leon3_debug_uart);
+  apbuart *regs = leon3_debug_uart;
+  rtems_status_code status = RTEMS_SUCCESSFUL;
+
+  while (true) {
+    if (apbuart_can_transmit(regs)) {
+      if ((option_set & RTEMS_IO_NO_TRANSMISSION) == 0) {
+        grlib_store_32(&regs->data, (uint8_t) c);
+      }
+
+      break;
+    }
+
+    if ((option_set & RTEMS_NO_WAIT) != 0) {
+      status = RTEMS_UNSATISFIED;
+      break;
+    }
+
+    _IO_Relax();
+  }
+
+  if ((option_set & RTEMS_IO_DRAIN) != 0) {
+    while (!apbuart_can_transmit(regs)) {
+      _IO_Relax();
+    }
+  }
+
+  return status;
 }
 
 static int bsp_debug_uart_poll_char(void)
@@ -77,10 +111,13 @@ static int bsp_debug_uart_poll_char(void)
   return apbuart_inbyte_nonblocking(leon3_debug_uart);
 }
 
-static void bsp_debug_uart_pre_init_out(char c)
+static rtems_status_code bsp_debug_uart_pre_init_out(
+  char c,
+  rtems_option option_set
+)
 {
   bsp_debug_uart_init();
-  (*BSP_output_char)(c);
+  return (*BSP_output_char)(c, option_set);
 }
 
 #if defined(LEON3_APBUART_BASE)
@@ -94,9 +131,14 @@ static void bsp_debug_uart_init(void)
 
 #else /* !LEON3_APBUART_BASE */
 
-static void bsp_debug_uart_discard(char c)
+static rtems_status_code bsp_debug_uart_discard(
+  char c,
+  rtems_option option_set
+)
 {
   (void) c;
+  (void) option_set;
+  return RTEMS_SUCCESSFUL;
 }
 
 /* Initialize the BSP system debug console layer. It will scan AMBA Plu&Play
diff --git a/cpukit/include/rtems/bspIo.h b/cpukit/include/rtems/bspIo.h
index 31580cd800..7848704992 100644
--- a/cpukit/include/rtems/bspIo.h
+++ b/cpukit/include/rtems/bspIo.h
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright (C) 2020, 2021 embedded brains GmbH & Co. KG
+ * Copyright (C) 2020, 2024 embedded brains GmbH & Co. KG
  * Copyright (C) 2015 On-Line Applications Research Corporation (OAR)
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,6 +58,8 @@
 #define _RTEMS_BSPIO_H
 
 #include <stdarg.h>
+#include <rtems/rtems/options.h>
+#include <rtems/rtems/status.h>
 #include <rtems/score/basedefs.h>
 
 #ifdef __cplusplus
@@ -89,8 +91,48 @@ extern "C" {
  * @ingroup RTEMSAPIKernelCharIO
  *
  * @brief Polled character output functions shall have this type.
+ *
+ * @param out is the character to transmit.
+ *
+ * @param option_set is the option set.
+ *
+ * The behaviour of polled character output functions can be controlled by the
+ * three options #RTEMS_NO_WAIT, #RTEMS_IO_NO_TRANSMISSION, and #RTEMS_IO_DRAIN
+ * specified in the ``option_set`` parameter.
+ *
+ * If the #RTEMS_NO_WAIT option is set in the ``option_set`` parameter and the
+ * device cannot immediately accept a character for transmission, then the
+ * character in ``out`` shall not be transmitted by the device, optionally the
+ * device shall be drained, and ::RTEMS_UNSATISFIED shall be returned.
+ *
+ * If the #RTEMS_IO_NO_TRANSMISSION option is set in the ``option_set``
+ * parameter, the character in the ``out`` parameter shall not be transmitted
+ * by the device.
+ *
+ * If the #RTEMS_NO_WAIT and #RTEMS_IO_NO_TRANSMISSION options are cleared in
+ * the ``option_set`` parameter, then the character in the ``out`` parameter
+ * shall transmitted by the device.
+ *
+ * If the #RTEMS_NO_WAIT option is set and the #RTEMS_IO_NO_TRANSMISSION option
+ * is cleared in the ``option_set`` parameter, and the device can immediately
+ * accept a character for transmission, then the character in ``out`` shall be
+ * transmitted by the device.
+ *
+ * If the #RTEMS_IO_DRAIN option is set in the ``option_set`` parameter, then
+ * the device shall be drained before the function returns.  Draining the
+ * device should ensure that all characters in transmission are visible to
+ * external consumers. For example, the device transmit FIFO and transmit shift
+ * register should be empty.
+ *
+ * @retval ::RTEMS_SUCCESSFUL The requested operation was successful.
+ *
+ * @retval ::RTEMS_UNSATISFIED The device is was not immediately ready to
+ *   transmit a character.
  */
-typedef void ( *BSP_output_char_function_type )( char );
+typedef rtems_status_code ( *BSP_output_char_function_type )(
+  char out,
+  rtems_option option_set
+);
 
 /* Generated from spec:/rtems/io/if/bsp-output-char */
 
@@ -333,6 +375,15 @@ int rtems_printk_printer( void *unused, const char *fmt, va_list ap );
  * @ingroup RTEMSAPIKernelCharIO
  *
  * @brief Polled character input functions shall have this type.
+ *
+ * If a character is available in the device, then a polled character input
+ * function shall return the least recently received character available in the
+ * device as an unsigned character, otherwise it shall return minus one.
+ *
+ * @retval -1 There was no received character available in the device.
+ *
+ * @return Returns the least recently received character available in the
+ *   device as an unsigned character.
  */
 typedef int (* BSP_polling_getchar_function_type )( void );
 
diff --git a/cpukit/include/rtems/rtems/options.h b/cpukit/include/rtems/rtems/options.h
index 44a8d6ccb8..ca6d32639c 100644
--- a/cpukit/include/rtems/rtems/options.h
+++ b/cpukit/include/rtems/rtems/options.h
@@ -9,7 +9,7 @@
  */
 
 /*
- * Copyright (C) 2020 embedded brains GmbH & Co. KG
+ * Copyright (C) 2020, 2024 embedded brains GmbH & Co. KG
  * Copyright (C) 1989, 2008 On-Line Applications Research Corporation (OAR)
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,6 +103,26 @@ extern "C" {
  */
 #define RTEMS_EVENT_ANY 0x00000002
 
+/* Generated from spec:/rtems/option/if/io-drain */
+
+/**
+ * @ingroup RTEMSAPIClassicOptions
+ *
+ * @brief This option constant indicates that an output device shall be
+ *   drained.
+ */
+#define RTEMS_IO_DRAIN 0x00000008
+
+/* Generated from spec:/rtems/option/if/io-no-transmission */
+
+/**
+ * @ingroup RTEMSAPIClassicOptions
+ *
+ * @brief This option constant indicates that nothing shall be transmitted by a
+ *   device.
+ */
+#define RTEMS_IO_NO_TRANSMISSION 0x00000004
+
 /* Generated from spec:/rtems/option/if/no-wait */
 
 /**
diff --git a/cpukit/libcsupport/src/rtems_putc.c b/cpukit/libcsupport/src/rtems_putc.c
index a9e84c0043..73bd6f1fb1 100644
--- a/cpukit/libcsupport/src/rtems_putc.c
+++ b/cpukit/libcsupport/src/rtems_putc.c
@@ -46,8 +46,8 @@ void rtems_putc( char c )
   output_char = BSP_output_char;
 
   if ( c == '\n' ) {
-    ( *output_char )( '\r' );
+    (void) ( *output_char )( '\r', RTEMS_DEFAULT_OPTIONS );
   }
 
-  ( *output_char )( c );
+  (void) ( *output_char )( c, RTEMS_DEFAULT_OPTIONS );
 }
diff --git a/testsuites/validation/tc-io-put-char.c b/testsuites/validation/tc-io-put-char.c
index 671eed9835..7df8d7f3f2 100644
--- a/testsuites/validation/tc-io-put-char.c
+++ b/testsuites/validation/tc-io-put-char.c
@@ -159,16 +159,20 @@ static void Output( int value )
   ++ctx->output_count;
 }
 
-static void WrongOutput( char c )
+static rtems_status_code WrongOutput( char c, rtems_option option_set )
 {
   (void) c;
+  (void) option_set;
   Output( -1 );
+  return RTEMS_SUCCESSFUL;
 }
 
-static void OutputChar( char c )
+static rtems_status_code OutputChar( char c, rtems_option option_set )
 {
+  (void) option_set;
   BSP_output_char = WrongOutput;
   Output( (unsigned char) c );
+  return RTEMS_SUCCESSFUL;
 }
 
 static void RtemsIoReqPutChar_Pre_Char_Prepare(
diff --git a/testsuites/validation/tr-io-kernel.c b/testsuites/validation/tr-io-kernel.c
index bbebfe5a26..99969776b6 100644
--- a/testsuites/validation/tr-io-kernel.c
+++ b/testsuites/validation/tr-io-kernel.c
@@ -83,9 +83,9 @@
 static void RtemsIoValKernel_Action_0( void )
 {
   T_report_hash_sha256_update( 'X' );
-  ( *BSP_output_char )( 'X' );
+  (void) ( *BSP_output_char )( 'X', RTEMS_DEFAULT_OPTIONS );
   T_report_hash_sha256_update( '\n' );
-  ( *BSP_output_char )( '\n' );
+  (void) ( *BSP_output_char )( '\n', RTEMS_DEFAULT_OPTIONS );
 }
 
 /**
-- 
2.35.3



More information about the devel mailing list