PCI 16x50 UART Controller, O2 Enablement (#39)
[lunaix-os.git] / lunaix-os / hal / char / uart / 16x50_isa.c
diff --git a/lunaix-os/hal/char/uart/16x50_isa.c b/lunaix-os/hal/char/uart/16x50_isa.c
new file mode 100644 (file)
index 0000000..d8d2e1b
--- /dev/null
@@ -0,0 +1,64 @@
+#include <lunaix/device.h>
+#include <lunaix/generic/isrm.h>
+#include <lunaix/syslog.h>
+
+#include <sys/port_io.h>
+
+#include "16x50.h"
+
+LOG_MODULE("16x50-isa");
+
+static DEFINE_LLIST(com_ports);
+
+static void
+com_irq_handler(const struct hart_state* hstate)
+{
+    int vector = hart_vector_stamp(hstate);
+    uart_handle_irq_overlap(vector, &com_ports);
+}
+
+static int
+upiom_init(struct device_def* def)
+{
+    int irq3 = 3, irq4 = 4;
+    u16_t ioports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
+    int* irqs[] = { &irq4, &irq3, &irq4, &irq3 };
+
+    struct uart16550* uart = NULL;
+    ptr_t base;
+
+    // COM 1...4
+    for (size_t i = 0; i < 4; i++) {
+
+        base = ioports[i];
+        uart = uart16x50_pmio_create(base);
+        if (!uart) {
+            WARN("port 0x%x not accessible", base);
+            continue;
+        }
+
+        int irq = *irqs[i];
+        if (irq) {
+            /*
+             *  Since these irqs are overlapped, this particular setup is needed
+             * to avoid double-bind
+             */
+            uart->iv = isrm_bindirq(irq, com_irq_handler);
+            *((volatile int*)irqs[i]) = 0;
+        }
+
+        INFO("base: 0x%x, irq=%d", 
+                base, irq, uart->iv);
+
+        uart_create_serial(uart, &def->class, &com_ports, "S");
+    }
+
+    return 0;
+}
+
+static struct device_def uart_pmio_def = {
+    .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_UART16550),
+    .name = "16550 UART (PIO)",
+    .init = upiom_init
+};
+EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_onboot);
\ No newline at end of file