summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/uart
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-06-30 09:33:36 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-07-09 12:07:49 +0200
commit21abc43fb54bb2424fb96666a014ebafee3e7320 (patch)
treed02d45e9a869921e8be4e6e51feade305953c837 /c/src/lib/libbsp/sparc/shared/uart
parentbsps: Basic console driver for Termios devices (diff)
downloadrtems-21abc43fb54bb2424fb96666a014ebafee3e7320.tar.bz2
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.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/uart')
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c240
1 files changed, 240 insertions, 0 deletions
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 0000000000..4b69e1b3d2
--- /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
+};