Architectural Support: x86_64 (#37)
[lunaix-os.git] / lunaix-os / hal / char / uart / 16550_base.c
index e3dda36e48823b7d704dfe2b8e16f4c9da3137fb..a84e3d0d0c88f9e9e01e8b6b7591d3fc3a3a6651 100644 (file)
@@ -2,6 +2,7 @@
 #include <lunaix/status.h>
 
 #include <usr/lunaix/serial.h>
+#include <usr/lunaix/term.h>
 
 #include "16550.h"
 
@@ -41,6 +42,28 @@ uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len)
     return RXTX_DONE;
 }
 
+#define UART_LCR_RESET \
+    (UART_rLC_STOPB | \
+     UART_rLC_PAREN | \
+     UART_rLC_PAREVN | \
+     UART_rLC_DLAB | 0b11)
+
+static void
+uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
+{
+    uart->cntl_save.rie &= ~(UART_rIE_ERBFI | UART_rIE_EDSSI);
+    uart->cntl_save.rie |= (!(cflags & _CLOCAL)) * UART_rIE_EDSSI;
+    uart->cntl_save.rie |= (!!(cflags & _CREAD)) * UART_rIE_ERBFI;
+    uart_setie(uart);
+
+    uart->cntl_save.rlc &= ~UART_LCR_RESET;
+    uart->cntl_save.rlc |= (!!(cflags & _CSTOPB)) * UART_rLC_STOPB;
+    uart->cntl_save.rlc |= (!!(cflags & _CPARENB)) * UART_rLC_PAREN;
+    uart->cntl_save.rlc |= (!(cflags & _CPARODD)) * UART_rLC_PAREVN;
+    uart->cntl_save.rlc |= (cflags & _CSZ_MASK) >> 2;
+    uart_setlc(uart);
+}
+
 int
 uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
 {
@@ -52,6 +75,12 @@ uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
         case SERIO_RXDA:
             uart_clrie(uart);
             break;
+        case SERIO_SETBRDIV:
+            // TODO
+            break;
+        case SERIO_SETCNTRLMODE:
+            uart_set_control_mode(uart, va_arg(args, tcflag_t));
+            break;
         default:
             return ENOTSUP;
     }
@@ -66,7 +95,7 @@ uart_general_irq_handler(int iv, struct llist_header* ports)
     llist_for_each(pos, n, ports, local_ports)
     {
         int is = uart_intr_identify(pos);
-        if (iv == pos->iv && (is == UART_DATA_OK || is == UART_CHR_TIMEOUT)) {
+        if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
             goto done;
         }
     }
@@ -91,5 +120,7 @@ done:
     }
 
     serial_accept_buffer(pos->sdev, tmpbuf, i);
+    serial_accept_one(pos->sdev, 0);
+
     serial_end_recv(pos->sdev);
 }