PCI 16x50 UART Controller, O2 Enablement (#39)
[lunaix-os.git] / lunaix-os / hal / char / uart / 16x50_base.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/status.h>
3
4 #include <usr/lunaix/serial.h>
5 #include <usr/lunaix/term.h>
6
7 #include "16x50.h"
8
9 struct uart16550*
10 uart_alloc(ptr_t base_addr)
11 {
12     struct uart16550* uart = valloc(sizeof(struct uart16550));
13
14     // load registers default value
15     uart->cntl_save.rmc = UART_rMC_DTR | UART_rMC_RTS | UART_rMC_IEN;
16     uart->cntl_save.rie = 0;
17
18     uart->base_addr = base_addr;
19     return uart;
20 }
21
22 void
23 uart_free(struct uart16550* uart)
24 {
25     vfree(uart);
26 }
27
28 int
29 uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len)
30 {
31     struct uart16550* uart = UART16550(sdev);
32
33     size_t i = 0;
34     while (i < len) {
35         while (!uart_can_transmit(uart))
36             ;
37         uart_write_byte(uart, data[i++]);
38     }
39
40     serial_end_xmit(sdev, len);
41
42     return RXTX_DONE;
43 }
44
45 static void
46 uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
47 {
48     uart->cntl_save.rie &= ~(UART_rIE_ERBFI | UART_rIE_EDSSI);
49     uart->cntl_save.rie |= (!(cflags & _CLOCAL)) * UART_rIE_EDSSI;
50     uart->cntl_save.rie |= (!!(cflags & _CREAD)) * UART_rIE_ERBFI;
51     uart_setie(uart);
52
53     uart->cntl_save.rlc &= ~UART_LCR_RESET;
54     uart->cntl_save.rlc |= (!!(cflags & _CSTOPB)) * UART_rLC_STOPB;
55     uart->cntl_save.rlc |= (!!(cflags & _CPARENB)) * UART_rLC_PAREN;
56     uart->cntl_save.rlc |= (!(cflags & _CPARODD)) * UART_rLC_PAREVN;
57     uart->cntl_save.rlc |= (cflags & _CSZ_MASK) >> 2;
58     uart_setlc(uart);
59 }
60
61 int
62 uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
63 {
64     struct uart16550* uart = UART16550(sdev);
65     switch (req) {
66         case SERIO_RXEN:
67             uart_setie(uart);
68             break;
69         case SERIO_RXDA:
70             uart_clrie(uart);
71             break;
72         case SERIO_SETBRDIV:
73             // TODO
74             break;
75         case SERIO_SETCNTRLMODE:
76             uart_set_control_mode(uart, va_arg(args, tcflag_t));
77             break;
78         default:
79             return ENOTSUP;
80     }
81     return 0;
82 }
83
84 void
85 uart_handle_irq_overlap(int iv, struct llist_header* ports)
86 {
87     struct uart16550 *pos, *n;
88     llist_for_each(pos, n, ports, local_ports)
89     {
90         int is = uart_intr_identify(pos);
91         if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
92             goto done;
93         }
94     }
95
96     return;
97
98 done:
99     uart_handle_irq(iv, pos);
100 }
101
102 void
103 uart_handle_irq(int iv, struct uart16550 *uart)
104 {
105     char tmpbuf[32];
106     char recv;
107     int i = 0;
108     while ((recv = uart_read_byte(uart))) {
109         tmpbuf[i++] = recv;
110         if (likely(i < 32)) {
111             continue;
112         }
113
114         if (!serial_accept_buffer(uart->sdev, tmpbuf, i)) {
115             uart_clear_rxfifo(uart);
116             return;
117         }
118
119         i = 0;
120     }
121
122     serial_accept_buffer(uart->sdev, tmpbuf, i);
123     serial_accept_one(uart->sdev, 0);
124
125     serial_end_recv(uart->sdev);
126 }