Introducing LunaBuild to the build flow (#36)
[lunaix-os.git] / lunaix-os / hal / char / uart / 16550_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 "16550.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_rLC_STOPB | UART_rLC_PAREN | UART_rLC_PAREVN | 0b11);
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_general_irq_handler(int iv, struct llist_header* ports)
86 {
87     char tmpbuf[32];
88     struct uart16550 *pos, *n;
89     llist_for_each(pos, n, ports, local_ports)
90     {
91         int is = uart_intr_identify(pos);
92         if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
93             goto done;
94         }
95     }
96
97     return;
98
99 done:
100     char recv;
101     int i = 0;
102     while ((recv = uart_read_byte(pos))) {
103         tmpbuf[i++] = recv;
104         if (likely(i < 32)) {
105             continue;
106         }
107
108         if (!serial_accept_buffer(pos->sdev, tmpbuf, i)) {
109             uart_clear_rxfifo(pos);
110             return;
111         }
112
113         i = 0;
114     }
115
116     serial_accept_buffer(pos->sdev, tmpbuf, i);
117     serial_accept_one(pos->sdev, 0);
118
119     serial_end_recv(pos->sdev);
120 }