summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Aberg <maberg@gaisler.com>2017-03-13 10:53:47 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2017-05-02 12:34:46 +0200
commit3df67108c2807d4c49d9ccbfcf97b6675d8911cc (patch)
treef8d84ff5db09f0bdddc1673e3a9f63ba54d6deb9
parentleon, apbuart: Inherit HW parameters on sysconsole (diff)
downloadrtems-3df67108c2807d4c49d9ccbfcf97b6675d8911cc.tar.bz2
leon, apbuart: support termios task driven mode
The APBUART control register can be updated from both ISR and task context so the device must be locked when manipulating the register. There is also a scenario with RX FIFO interrupts where a few characters can be in the FIFO without generating interrupt.
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c64
1 files changed, 48 insertions, 16 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
index 3b74ae1f5d..6591cd88fd 100644
--- a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
@@ -358,8 +358,8 @@ static int apbuart_info(
if (priv->mode == TERMIOS_POLLED)
str1 = "TERMIOS_POLLED";
- else if (priv->mode == TERMIOS_TASK_DRIVEN)
- str1 = "TERMIOS_TASK_DRIVEN";
+ else if (priv->mode == TERMIOS_IRQ_DRIVEN)
+ str1 = "TERMIOS_IRQ_DRIVEN";
else if (priv->mode == TERMIOS_TASK_DRIVEN)
str1 = "TERMIOS_TASK_DRIVEN";
else
@@ -489,7 +489,8 @@ static void last_close(
if (uart->mode != TERMIOS_POLLED) {
/* Turn off RX interrupts */
rtems_termios_device_lock_acquire(base, &lock_context);
- uart->regs->ctrl &= ~(APBUART_CTRL_RI | APBUART_CTRL_RF);
+ uart->regs->ctrl &=
+ ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
rtems_termios_device_lock_release(base, &lock_context);
/**** Flush device ****/
@@ -515,29 +516,50 @@ static int read_polled(rtems_termios_device_context *base)
return apbuart_inbyte_nonblocking(uart->regs);
}
+/* This function is called from TERMIOS rxdaemon task without device lock. */
static int read_task(rtems_termios_device_context *base)
{
+ rtems_interrupt_lock_context lock_context;
struct apbuart_priv *uart = base_get_priv(base);
- int c, tot;
- char buf[32];
+ struct apbuart_regs *regs = uart->regs;
+ int cnt;
+ char buf[33];
struct rtems_termios_tty *tty;
+ uint32_t ctrl_add;
+ ctrl_add = APBUART_CTRL_RI;
+ if (uart->cap & CAP_DI) {
+ ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
+ }
tty = uart->tty;
- tot = 0;
- while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
- buf[tot] = c;
- tot++;
- if (tot > 31) {
- rtems_termios_enqueue_raw_characters(tty, buf, tot);
- tot = 0;
+ do {
+ cnt = 0;
+ while (
+ (regs->status & APBUART_STATUS_DR) &&
+ (cnt < sizeof(buf))
+ ) {
+ buf[cnt] = regs->data;
+ cnt++;
+ }
+ if (0 < cnt) {
+ /* Tell termios layer about new characters */
+ rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
}
- }
- if (tot > 0)
- rtems_termios_enqueue_raw_characters(tty, buf, tot);
+
+ /*
+ * Turn on RX interrupts. A new character in FIFO now may not
+ * cause interrupt so we must check data ready again
+ * afterwards.
+ */
+ rtems_termios_device_lock_acquire(base, &lock_context);
+ regs->ctrl |= ctrl_add;
+ rtems_termios_device_lock_release(base, &lock_context);
+ } while (regs->status & APBUART_STATUS_DR);
return EOF;
}
+
struct apbuart_baud {
unsigned int num;
unsigned int baud;
@@ -779,6 +801,7 @@ static void write_interrupt(
static void apbuart_cons_isr(void *arg)
{
rtems_termios_tty *tty = arg;
+ rtems_termios_device_context *base;
struct console_dev *condev = rtems_termios_get_device_context(tty);
struct apbuart_priv *uart = condev_get_priv(condev);
struct apbuart_regs *regs = uart->regs;
@@ -787,7 +810,16 @@ static void apbuart_cons_isr(void *arg)
int cnt;
if (uart->mode == TERMIOS_TASK_DRIVEN) {
- if ((status=regs->status) & APBUART_STATUS_DR) {
+ if ((status = regs->status) & APBUART_STATUS_DR) {
+ rtems_interrupt_lock_context lock_context;
+
+ /* Turn off RX interrupts */
+ base = rtems_termios_get_device_context(tty);
+ rtems_termios_device_lock_acquire(base, &lock_context);
+ regs->ctrl &=
+ ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
+ APBUART_CTRL_RF);
+ rtems_termios_device_lock_release(base, &lock_context);
/* Activate termios RX daemon task */
rtems_termios_rxirq_occured(tty);
}