39582236364660f4a1e21144eadf27a69ffd45ff
[lunaix-os.git] / lunaix-os / hal / char / uart / 16x50_isa.c
1 #include <lunaix/device.h>
2 #include <lunaix/syslog.h>
3
4 #include <asm/x86_pmio.h>
5 #include <asm/x86_isrm.h>
6
7 #include "16x50.h"
8
9 LOG_MODULE("16x50-isa");
10
11 static DEFINE_LLIST(com_ports);
12
13 static void
14 com_irq_handler(const struct hart_state* hstate)
15 {
16     int vector = hart_vector_stamp(hstate);
17     uart_handle_irq_overlap(vector, &com_ports);
18 }
19
20 int
21 isa16x50_create_once(struct device_def* def)
22 {
23     int irq3 = 3, irq4 = 4;
24     u16_t ioports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
25     int* irqs[] = { &irq4, &irq3, &irq4, &irq3 };
26
27     struct uart16550* uart = NULL;
28     ptr_t base;
29
30     // COM 1...4
31     for (size_t i = 0; i < 4; i++) {
32
33         base = ioports[i];
34         uart = uart16x50_pmio_create(base);
35         if (!uart) {
36             WARN("port 0x%x not accessible", base);
37             continue;
38         }
39
40         int irq = *irqs[i];
41         if (irq) {
42             /*
43              *  Since these irqs are overlapped, this particular setup is needed
44              * to avoid double-bind
45              */
46             uart->iv = isrm_bindirq(irq, com_irq_handler);
47             *((volatile int*)irqs[i]) = 0;
48         }
49
50         INFO("base: 0x%x, irq=%d", 
51                 base, irq, uart->iv);
52
53         uart_create_serial(uart, &def->class, &com_ports, "S");
54     }
55
56     return 0;
57 }