Architectural Support: x86_64 (#37)
[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 #define UART_LCR_RESET \
46     (UART_rLC_STOPB | \
47      UART_rLC_PAREN | \
48      UART_rLC_PAREVN | \
49      UART_rLC_DLAB | 0b11)
50
51 static void
52 uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
53 {
54     uart->cntl_save.rie &= ~(UART_rIE_ERBFI | UART_rIE_EDSSI);
55     uart->cntl_save.rie |= (!(cflags & _CLOCAL)) * UART_rIE_EDSSI;
56     uart->cntl_save.rie |= (!!(cflags & _CREAD)) * UART_rIE_ERBFI;
57     uart_setie(uart);
58
59     uart->cntl_save.rlc &= ~UART_LCR_RESET;
60     uart->cntl_save.rlc |= (!!(cflags & _CSTOPB)) * UART_rLC_STOPB;
61     uart->cntl_save.rlc |= (!!(cflags & _CPARENB)) * UART_rLC_PAREN;
62     uart->cntl_save.rlc |= (!(cflags & _CPARODD)) * UART_rLC_PAREVN;
63     uart->cntl_save.rlc |= (cflags & _CSZ_MASK) >> 2;
64     uart_setlc(uart);
65 }
66
67 int
68 uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
69 {
70     struct uart16550* uart = UART16550(sdev);
71     switch (req) {
72         case SERIO_RXEN:
73             uart_setie(uart);
74             break;
75         case SERIO_RXDA:
76             uart_clrie(uart);
77             break;
78         case SERIO_SETBRDIV:
79             // TODO
80             break;
81         case SERIO_SETCNTRLMODE:
82             uart_set_control_mode(uart, va_arg(args, tcflag_t));
83             break;
84         default:
85             return ENOTSUP;
86     }
87     return 0;
88 }
89
90 void
91 uart_general_irq_handler(int iv, struct llist_header* ports)
92 {
93     char tmpbuf[32];
94     struct uart16550 *pos, *n;
95     llist_for_each(pos, n, ports, local_ports)
96     {
97         int is = uart_intr_identify(pos);
98         if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) {
99             goto done;
100         }
101     }
102
103     return;
104
105 done:
106     char recv;
107     int i = 0;
108     while ((recv = uart_read_byte(pos))) {
109         tmpbuf[i++] = recv;
110         if (likely(i < 32)) {
111             continue;
112         }
113
114         if (!serial_accept_buffer(pos->sdev, tmpbuf, i)) {
115             uart_clear_rxfifo(pos);
116             return;
117         }
118
119         i = 0;
120     }
121
122     serial_accept_buffer(pos->sdev, tmpbuf, i);
123     serial_accept_one(pos->sdev, 0);
124
125     serial_end_recv(pos->sdev);
126 }