[rtems commit] leon, apbuart: support termios task driven mode

Daniel Hellstrom danielh at rtems.org
Tue May 2 10:38:43 UTC 2017


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

Author:    Martin Aberg <maberg at gaisler.com>
Date:      Mon Mar 13 10:53:47 2017 +0100

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.

---

 c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c | 64 +++++++++++++++++------
 1 file 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 3b74ae1..6591cd8 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);
 		}




More information about the vc mailing list