feat: capability list to enable greater flexibility of devices
[lunaix-os.git] / lunaix-os / hal / char / uart / 16550_base.c
index 4ae45d78e1cfbf50ffb760ab0215b1f3bacc6450..d78f3cf0ff369a3db11edc89ea8ca7ab690f1fa2 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,22 @@ uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len)
     return RXTX_DONE;
 }
 
+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_rLC_STOPB | UART_rLC_PAREN | UART_rLC_PAREVN | 0b11);
+    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 +69,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,15 +89,14 @@ 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) {
-            break;
+        if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
+            goto done;
         }
     }
 
-    if (!pos) {
-        return;
-    }
+    return;
 
+done:
     char recv;
     int i = 0;
     while ((recv = uart_read_byte(pos))) {
@@ -92,5 +114,7 @@ uart_general_irq_handler(int iv, struct llist_header* ports)
     }
 
     serial_accept_buffer(pos->sdev, tmpbuf, i);
+    serial_accept_one(pos->sdev, 0);
+
     serial_end_recv(pos->sdev);
 }