[rtems commit] bsps/sparc: Add and use shared APBUART console

Sebastian Huber sebh at rtems.org
Wed Jul 9 10:52:38 UTC 2014


Module:    rtems
Branch:    master
Commit:    21abc43fb54bb2424fb96666a014ebafee3e7320
Changeset: http://git.rtems.org/rtems/commit/?id=21abc43fb54bb2424fb96666a014ebafee3e7320

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Jun 30 09:33:36 2014 +0200

bsps/sparc: Add and use shared APBUART console

Move the APBUART console driver support to the shared SPARC area so that
it can be reused by other BSPs.  Only the console driver initialization
is now BSP specific.

---

 c/src/lib/libbsp/sparc/leon3/Makefile.am           |    7 +-
 c/src/lib/libbsp/sparc/leon3/console/console.c     |  349 ++------------------
 c/src/lib/libbsp/sparc/leon3/preinstall.am         |    4 +
 .../libbsp/sparc/shared/include/apbuart_termios.h  |   40 +++
 .../lib/libbsp/sparc/shared/uart/apbuart_termios.c |  240 ++++++++++++++
 5 files changed, 315 insertions(+), 325 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index 5dd43c3..6da563b 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -65,6 +65,7 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
 # console
+libbsp_a_SOURCES += ../../shared/console-termios.c
 libbsp_a_SOURCES += console/console.c
 # debugio
 libbsp_a_SOURCES += console/printk_support.c
@@ -109,9 +110,11 @@ libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c \
 
 # UART
 include_HEADERS += ../../sparc/shared/include/apbuart.h \
-    ../../sparc/shared/include/apbuart_pci.h
+    ../../sparc/shared/include/apbuart_pci.h \
+    ../../sparc/shared/include/apbuart_termios.h
 libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \
-    ../../sparc/shared/uart/apbuart_pci.c
+    ../../sparc/shared/uart/apbuart_pci.c \
+    ../../sparc/shared/uart/apbuart_termios.c
 
 # I2CMST
 include_HEADERS += ../../sparc/shared/include/i2cmst.h
diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c
index 989d1cf..9012492 100644
--- a/c/src/lib/libbsp/sparc/leon3/console/console.c
+++ b/c/src/lib/libbsp/sparc/leon3/console/console.c
@@ -28,34 +28,17 @@
 
 #include <bsp.h>
 #include <bsp/fatal.h>
-#include <rtems/libio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <rtems/bspIo.h>
-#include <leon.h>
-#include <rtems/termiostypes.h>
-#include <apbuart.h>
+#include <apbuart_termios.h>
 
 int syscon_uart_index __attribute__((weak)) = 0;
 
 /* body is in debugputs.c */
-
-struct apbuart_priv {
-  struct apbuart_regs *regs;
-  unsigned int freq_hz;
-#if CONSOLE_USE_INTERRUPTS
-  int irq;
-  void *cookie;
-  volatile int sending;
-  char *buf;
-#endif
-};
-static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
+static struct apbuart_context apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
 static int uarts = 0;
 
-static struct apbuart_priv *leon3_console_get_uart(int minor)
+static struct apbuart_context *leon3_console_get_uart(int minor)
 {
-  struct apbuart_priv *uart;
+  struct apbuart_context *uart;
 
   if (minor == 0)
     uart = &apbuarts[syscon_uart_index];
@@ -65,160 +48,6 @@ static struct apbuart_priv *leon3_console_get_uart(int minor)
   return uart;
 }
 
-#if CONSOLE_USE_INTERRUPTS
-
-/* Handle UART interrupts */
-static void leon3_console_isr(void *arg)
-{
-  struct apbuart_priv *uart = arg;
-  unsigned int status;
-  char data;
-
-  /* Get all received characters */
-  while ((status=uart->regs->status) & APBUART_STATUS_DR) {
-    /* Data has arrived, get new data */
-    data = uart->regs->data;
-
-    /* Tell termios layer about new character */
-    rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
-  }
-
-  if (
-    (status & APBUART_STATUS_TE)
-      && (uart->regs->ctrl & APBUART_CTRL_TI) != 0
-  ) {
-    /* write_interrupt will get called from this function */
-    rtems_termios_dequeue_characters(uart->cookie, 1);
-  }
-}
-
-/*
- *  Console Termios Write-Buffer Support Entry Point
- *
- */
-static int leon3_console_write_support(int minor, const char *buf, size_t len)
-{
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-  int sending;
-
-  if (len > 0) {
-    /* Enable TX interrupt (interrupt is edge-triggered) */
-    uart->regs->ctrl |= APBUART_CTRL_TI;
-
-    /* start UART TX, this will result in an interrupt when done */
-    uart->regs->data = *buf;
-
-    sending = 1;
-  } else {
-    /* No more to send, disable TX interrupts */
-    uart->regs->ctrl &= ~APBUART_CTRL_TI;
-
-    /* Tell close that we sent everything */
-    sending = 0;
-  }
-
-  uart->sending = sending;
-
-  return 0;
-}
-
-#else
-
-/*
- *  Console Termios Support Entry Points
- */
-static ssize_t leon3_console_write_polled(
-  int minor,
-  const char *buf,
-  size_t len
-)
-{
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-  int nwrite = 0;
-
-  while (nwrite < len) {
-    apbuart_outbyte_polled(uart->regs, *buf++, 1, 0);
-    nwrite++;
-  }
-  return nwrite;
-}
-
-static int leon3_console_pollRead(int minor)
-{
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-
-  return apbuart_inbyte_nonblocking(uart->regs);
-}
-
-#endif
-
-static int leon3_console_set_attributes(int minor, const struct termios *t)
-{
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-  unsigned int scaler;
-  unsigned int ctrl;
-  int baud;
-
-  switch (t->c_cflag & CSIZE) {
-    default:
-    case CS5:
-    case CS6:
-    case CS7:
-      /* Hardware doesn't support other than CS8 */
-      return -1;
-    case CS8:
-      break;
-  }
-
-  /*
-   * FIXME: This read-modify-write sequence is broken since interrupts may
-   * interfere.
-   */
-
-  /* Read out current value */
-  ctrl = uart->regs->ctrl;
-
-  switch (t->c_cflag & (PARENB|PARODD)) {
-    case (PARENB|PARODD):
-      /* Odd parity */
-      ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
-      break;
-
-    case PARENB:
-      /* Even parity */
-      ctrl &= ~APBUART_CTRL_PS;
-      ctrl |= APBUART_CTRL_PE;
-      break;
-
-    default:
-    case 0:
-    case PARODD:
-      /* No Parity */
-      ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
-  }
-
-  if (!(t->c_cflag & CLOCAL)) {
-    ctrl |= APBUART_CTRL_FL;
-  } else {
-    ctrl &= ~APBUART_CTRL_FL;
-  }
-
-  /* Update new settings */
-  uart->regs->ctrl = ctrl;
-
-  /* Baud rate */
-  baud = rtems_termios_baud_to_number(t->c_cflag);
-  if (baud > 0) {
-    /* Calculate Baud rate generator "scaler" number */
-    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
-
-    /* Set new baud rate by setting scaler */
-    uart->regs->scaler = scaler;
-  }
-
-  return 0;
-}
-
 /* AMBA PP find routine. Extract AMBA PnP information into data structure. */
 static int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
 {
@@ -226,9 +55,7 @@ static int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
 
   /* Extract needed information of one APBUART */
   apbuarts[uarts].regs = (struct apbuart_regs *)apb->start;
-#if CONSOLE_USE_INTERRUPTS
   apbuarts[uarts].irq = apb->irq;
-#endif
   /* Get APBUART core frequency, it is assumed that it is the same
    * as Bus frequency where the UART is situated
    */
@@ -251,17 +78,18 @@ static void leon3_console_scan_uarts(void)
                   GAISLER_APBUART, find_matching_apbuart, NULL);
 }
 
-/*
- *  Console Device Driver Entry Points
- *
- */
-
 rtems_device_driver console_initialize(
   rtems_device_major_number  major,
   rtems_device_minor_number  minor,
   void                      *arg
 )
 {
+  const rtems_termios_device_handler *handler =
+#if CONSOLE_USE_INTERRUPTS
+    &apbuart_handler_interrupt;
+#else
+    &apbuart_handler_polled;
+#endif
   rtems_status_code status;
   int i;
   char console_name[16];
@@ -297,7 +125,14 @@ rtems_device_driver console_initialize(
    * On a MP system one should not open UARTs that other OS instances use.
    */
   if (syscon_uart_index < uarts) {
-    status = rtems_io_register_name("/dev/console", major, 0);
+    minor = 0;
+    status = rtems_termios_device_install(
+      CONSOLE_DEVICE_NAME,
+      major,
+      minor,
+      handler,
+      leon3_console_get_uart(syscon_uart_index)
+    );
     if (status != RTEMS_SUCCESSFUL)
       bsp_fatal(LEON3_FATAL_CONSOLE_REGISTER_DEV);
   }
@@ -306,147 +141,15 @@ rtems_device_driver console_initialize(
     if (i == syscon_uart_index)
       continue; /* skip UART that is registered as /dev/console */
     console_name[13] = 'a' + i;
-    rtems_io_register_name( console_name, major, i+1);
+    minor = i + 1;
+    rtems_termios_device_install(
+      console_name,
+      major,
+      minor,
+      handler,
+      leon3_console_get_uart(syscon_uart_index)
+    );
   }
 
   return RTEMS_SUCCESSFUL;
 }
-
-#if CONSOLE_USE_INTERRUPTS
-static struct rtems_termios_tty *leon3_console_get_tty(
-  rtems_libio_open_close_args_t *args
-)
-{
-  return args->iop->data1;
-}
-#endif
-
-static int leon3_console_first_open(int major, int minor, void *arg)
-{
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-
-#if CONSOLE_USE_INTERRUPTS
-  rtems_status_code sc;
-
-  uart->cookie = leon3_console_get_tty(arg);
-
-  /* Register Interrupt handler */
-  sc = rtems_interrupt_handler_install(uart->irq, "console",
-                                       RTEMS_INTERRUPT_SHARED,
-                                       leon3_console_isr,
-                                       uart);
-  if (sc != RTEMS_SUCCESSFUL)
-    return -1;
-
-  uart->sending = 0;
-  /* Enable Receiver and transmitter and Turn on RX interrupts */
-  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE |
-                      APBUART_CTRL_RI;
-#else
-  /* Initialize UART on opening */
-  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
-#endif
-  uart->regs->status = 0;
-
-  return 0;
-}
-
-#if CONSOLE_USE_INTERRUPTS
-static int leon3_console_last_close(int major, int minor, void *arg)
-{
-  struct rtems_termios_tty *tty = leon3_console_get_tty(arg);
-  struct apbuart_priv *uart = leon3_console_get_uart(minor);
-  rtems_interrupt_lock_context lock_ctx;
-
-  /* Turn off RX interrupts */
-  rtems_termios_interrupt_lock_acquire(tty, &lock_ctx);
-  uart->regs->ctrl &= ~(APBUART_CTRL_RI);
-  rtems_termios_interrupt_lock_release(tty, &lock_ctx);
-
-  /**** Flush device ****/
-  while (uart->sending) {
-    /* Wait until all data has been sent */
-  }
-
-  /* uninstall ISR */
-  rtems_interrupt_handler_remove(uart->irq, leon3_console_isr, uart);
-
-  return 0;
-}
-#endif
-
-rtems_device_driver console_open(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void                    * arg
-)
-{
-#if CONSOLE_USE_INTERRUPTS
-  /* Interrupt mode routines */
-  static const rtems_termios_callbacks Callbacks = {
-    leon3_console_first_open,    /* firstOpen */
-    leon3_console_last_close,    /* lastClose */
-    NULL,                        /* pollRead */
-    leon3_console_write_support, /* write */
-    leon3_console_set_attributes,/* setAttributes */
-    NULL,                        /* stopRemoteTx */
-    NULL,                        /* startRemoteTx */
-    1                            /* outputUsesInterrupts */
-  };
-#else
-  /* Polling mode routines */
-  static const rtems_termios_callbacks Callbacks = {
-    leon3_console_first_open,    /* firstOpen */
-    NULL,                        /* lastClose */
-    leon3_console_pollRead,      /* pollRead */
-    leon3_console_write_polled,  /* write */
-    leon3_console_set_attributes,/* setAttributes */
-    NULL,                        /* stopRemoteTx */
-    NULL,                        /* startRemoteTx */
-    0                            /* outputUsesInterrupts */
-  };
-#endif
-
-  assert(minor <= uarts);
-  if (minor > uarts || minor == (syscon_uart_index + 1))
-    return RTEMS_INVALID_NUMBER;
-
-  return rtems_termios_open(major, minor, arg, &Callbacks);
-}
-
-rtems_device_driver console_close(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void                    * arg
-)
-{
-  return rtems_termios_close(arg);
-}
-
-rtems_device_driver console_read(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void                    * arg
-)
-{
-  return rtems_termios_read(arg);
-}
-
-rtems_device_driver console_write(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void                    * arg
-)
-{
-  return rtems_termios_write(arg);
-}
-
-rtems_device_driver console_control(
-  rtems_device_major_number major,
-  rtems_device_minor_number minor,
-  void                    * arg
-)
-{
-  return rtems_termios_ioctl(arg);
-}
-
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index 33e9041..210558e 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -157,6 +157,10 @@ $(PROJECT_INCLUDE)/apbuart_pci.h: ../../sparc/shared/include/apbuart_pci.h $(PRO
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_pci.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_pci.h
 
+$(PROJECT_INCLUDE)/apbuart_termios.h: ../../sparc/shared/include/apbuart_termios.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_termios.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_termios.h
+
 $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h b/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h
new file mode 100644
index 0000000..4b54252
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h
@@ -0,0 +1,40 @@
+/*
+ *  COPYRIGHT (c) 1989-1998.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  Modified for LEON3 BSP.
+ *  COPYRIGHT (c) 2004.
+ *  Gaisler Research.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef APBUART_TERMIOS_H
+#define APBUART_TERMIOS_H
+
+#include <rtems/termiostypes.h>
+#include <grlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct apbuart_context {
+  struct apbuart_regs *regs;
+  unsigned int freq_hz;
+  rtems_vector_number irq;
+  volatile int sending;
+  char *buf;
+};
+
+const rtems_termios_device_handler apbuart_handler_interrupt;
+
+const rtems_termios_device_handler apbuart_handler_polled;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* APBUART_TERMIOS_H */
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c
new file mode 100644
index 0000000..4b69e1b
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c
@@ -0,0 +1,240 @@
+/*
+ *  COPYRIGHT (c) 1989-1998.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  Modified for LEON3 BSP.
+ *  COPYRIGHT (c) 2004.
+ *  Gaisler Research.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <apbuart_termios.h>
+#include <apbuart.h>
+#include <bsp.h>
+
+static void apbuart_isr(void *arg)
+{
+  rtems_termios_tty *tty = arg;
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  unsigned int status;
+  char data;
+
+  /* Get all received characters */
+  while ((status=uart->regs->status) & APBUART_STATUS_DR) {
+    /* Data has arrived, get new data */
+    data = uart->regs->data;
+
+    /* Tell termios layer about new character */
+    rtems_termios_enqueue_raw_characters(tty, &data, 1);
+  }
+
+  if (
+    (status & APBUART_STATUS_TE)
+      && (uart->regs->ctrl & APBUART_CTRL_TI) != 0
+  ) {
+    /* write_interrupt will get called from this function */
+    rtems_termios_dequeue_characters(tty, 1);
+  }
+}
+
+static void apbuart_write_support(
+  rtems_termios_tty *tty,
+  const char *buf,
+  size_t len
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  int sending;
+
+  if (len > 0) {
+    /* Enable TX interrupt (interrupt is edge-triggered) */
+    uart->regs->ctrl |= APBUART_CTRL_TI;
+
+    /* start UART TX, this will result in an interrupt when done */
+    uart->regs->data = *buf;
+
+    sending = 1;
+  } else {
+    /* No more to send, disable TX interrupts */
+    uart->regs->ctrl &= ~APBUART_CTRL_TI;
+
+    /* Tell close that we sent everything */
+    sending = 0;
+  }
+
+  uart->sending = sending;
+}
+
+static void apbuart_write_polled(
+  rtems_termios_tty *tty,
+  const char *buf,
+  size_t len
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  size_t nwrite = 0;
+
+  while (nwrite < len) {
+    apbuart_outbyte_polled(uart->regs, *buf++, 1, 0);
+    nwrite++;
+  }
+}
+
+static int apbuart_poll_read(rtems_termios_tty *tty)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+
+  return apbuart_inbyte_nonblocking(uart->regs);
+}
+
+static bool apbuart_set_attributes(
+  rtems_termios_tty *tty,
+  const struct termios *t
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  rtems_interrupt_lock_context lock_context;
+  unsigned int scaler;
+  unsigned int ctrl;
+  int baud;
+
+  switch (t->c_cflag & CSIZE) {
+    default:
+    case CS5:
+    case CS6:
+    case CS7:
+      /* Hardware doesn't support other than CS8 */
+      return false;
+    case CS8:
+      break;
+  }
+
+  rtems_termios_interrupt_lock_acquire(tty, &lock_context);
+
+  /* Read out current value */
+  ctrl = uart->regs->ctrl;
+
+  switch (t->c_cflag & (PARENB|PARODD)) {
+    case (PARENB|PARODD):
+      /* Odd parity */
+      ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
+      break;
+
+    case PARENB:
+      /* Even parity */
+      ctrl &= ~APBUART_CTRL_PS;
+      ctrl |= APBUART_CTRL_PE;
+      break;
+
+    default:
+    case 0:
+    case PARODD:
+      /* No Parity */
+      ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
+  }
+
+  if (!(t->c_cflag & CLOCAL)) {
+    ctrl |= APBUART_CTRL_FL;
+  } else {
+    ctrl &= ~APBUART_CTRL_FL;
+  }
+
+  /* Update new settings */
+  uart->regs->ctrl = ctrl;
+
+  rtems_termios_interrupt_lock_release(tty, &lock_context);
+
+  /* Baud rate */
+  baud = rtems_termios_baud_to_number(t->c_cflag);
+  if (baud > 0) {
+    /* Calculate Baud rate generator "scaler" number */
+    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
+
+    /* Set new baud rate by setting scaler */
+    uart->regs->scaler = scaler;
+  }
+
+  return true;
+}
+
+static bool apbuart_first_open_polled(
+  rtems_termios_tty *tty,
+  rtems_libio_open_close_args_t *args
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+
+  /* Initialize UART on opening */
+  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
+  uart->regs->status = 0;
+
+  return true;
+}
+
+static bool apbuart_first_open_interrupt(
+  rtems_termios_tty *tty,
+  rtems_libio_open_close_args_t *args
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  rtems_status_code sc;
+
+  /* Register Interrupt handler */
+  sc = rtems_interrupt_handler_install(uart->irq, "console",
+                                       RTEMS_INTERRUPT_SHARED,
+                                       apbuart_isr,
+                                       tty);
+  if (sc != RTEMS_SUCCESSFUL)
+    return false;
+
+  uart->sending = 0;
+  /* Enable Receiver and transmitter and Turn on RX interrupts */
+  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE |
+                      APBUART_CTRL_RI;
+  /* Initialize UART on opening */
+  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
+  uart->regs->status = 0;
+
+  return true;
+}
+
+static void apbuart_last_close_interrupt(
+  rtems_termios_tty *tty,
+  rtems_libio_open_close_args_t *args
+)
+{
+  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
+  rtems_interrupt_lock_context lock_context;
+
+  /* Turn off RX interrupts */
+  rtems_termios_interrupt_lock_acquire(tty, &lock_context);
+  uart->regs->ctrl &= ~(APBUART_CTRL_RI);
+  rtems_termios_interrupt_lock_release(tty, &lock_context);
+
+  /**** Flush device ****/
+  while (uart->sending) {
+    /* Wait until all data has been sent */
+  }
+
+  /* uninstall ISR */
+  rtems_interrupt_handler_remove(uart->irq, apbuart_isr, tty);
+}
+
+const rtems_termios_device_handler apbuart_handler_interrupt = {
+  .first_open = apbuart_first_open_interrupt,
+  .last_close = apbuart_last_close_interrupt,
+  .write = apbuart_write_support,
+  .set_attributes = apbuart_set_attributes,
+  .mode = TERMIOS_IRQ_DRIVEN
+};
+
+const rtems_termios_device_handler apbuart_handler_polled = {
+  .first_open = apbuart_first_open_polled,
+  .poll_read = apbuart_poll_read,
+  .write = apbuart_write_polled,
+  .set_attributes = apbuart_set_attributes,
+  .mode = TERMIOS_POLLED
+};



More information about the vc mailing list