1 /*
2  * Copyright (c) 2012 Corey Tabaka
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <dev/driver.h>
10 #include <dev/class/uart.h>
11 #include <lk/debug.h>
12 #include <assert.h>
13 #include <malloc.h>
14 #include <lk/err.h>
15 #include <lib/cbuf.h>
16 #include <platform/uart.h>
17 #include <arch/x86.h>
18 #include <kernel/thread.h>
19 #include <platform/interrupts.h>
20 
21 struct device_class uart_device_class = {
22     .name = "uart",
23 };
24 
25 struct uart_driver_state {
26     struct cbuf rx_buf;
27     struct cbuf tx_buf;
28 };
29 
30 static status_t uart_init(struct device *dev);
31 
32 static enum handler_return uart_irq_handler(void *arg);
33 static int uart_write_thread(void *arg);
34 
35 static ssize_t uart_read(struct device *dev, void *buf, size_t len);
36 static ssize_t uart_write(struct device *dev, const void *buf, size_t len);
37 
38 static struct uart_ops the_ops = {
39     .std = {
40         .device_class = &uart_device_class,
41         .init = uart_init,
42     },
43     .read = uart_read,
44     .write = uart_write,
45 };
46 
47 DRIVER_EXPORT(uart, &the_ops.std);
48 
uart_init(struct device * dev)49 static status_t uart_init(struct device *dev) {
50     status_t res = NO_ERROR;
51 
52     if (!dev)
53         return ERR_INVALID_ARGS;
54 
55     if (!dev->config)
56         return ERR_NOT_CONFIGURED;
57 
58     const struct platform_uart_config *config = dev->config;
59 
60     struct uart_driver_state *state = malloc(sizeof(struct uart_driver_state));
61     if (!state) {
62         res = ERR_NO_MEMORY;
63         goto done;
64     }
65 
66     dev->state = state;
67 
68     /* set up the driver state */
69     cbuf_initialize(&state->rx_buf, config->rx_buf_len);
70     cbuf_initialize(&state->tx_buf, config->tx_buf_len);
71 
72     /* configure the uart */
73     int divisor = 115200 / config->baud_rate;
74 
75     outp(config->io_port + 3, 0x80); // set up to load divisor latch
76     outp(config->io_port + 0, divisor & 0xff); // lsb
77     outp(config->io_port + 1, divisor >> 8); // msb
78     outp(config->io_port + 3, 3); // 8N1
79     outp(config->io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
80 
81     register_int_handler(config->irq, uart_irq_handler, dev);
82     unmask_interrupt(config->irq);
83 
84     //outp(config->io_port + 1, 0x3); // enable rx data available and tx holding empty interrupts
85     outp(config->io_port + 1, 0x1); // enable rx data available interrupts
86 
87     thread_resume(thread_create("[uart writer]", uart_write_thread, dev, DEFAULT_PRIORITY,
88                                 DEFAULT_STACK_SIZE));
89 
90 done:
91     return res;
92 }
93 
uart_irq_handler(void * arg)94 static enum handler_return uart_irq_handler(void *arg) {
95     bool resched = false;
96     struct device *dev = arg;
97 
98     DEBUG_ASSERT(dev);
99     DEBUG_ASSERT(dev->config);
100     DEBUG_ASSERT(dev->state);
101 
102     const struct platform_uart_config *config = dev->config;
103     struct uart_driver_state *state = dev->state;
104 
105     while (inp(config->io_port + 5) & (1<<0)) {
106         char c = inp(config->io_port + 0);
107         cbuf_write(&state->rx_buf, &c, 1, false);
108         resched = true;
109     }
110 
111     return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
112 }
113 
uart_write_thread(void * arg)114 static int uart_write_thread(void *arg) {
115     struct device *dev = arg;
116 
117     DEBUG_ASSERT(dev);
118     DEBUG_ASSERT(dev->config);
119     DEBUG_ASSERT(dev->state);
120 
121     const struct platform_uart_config *config = dev->config;
122     struct uart_driver_state *state = dev->state;
123 
124     return 0;
125 
126     while (true) {
127         char c = cbuf_read(&state->tx_buf, &c, 1, true);
128 
129         while ((inp(config->io_port + 5) & (1<<6)) == 0)
130             ;
131 
132         outp(config->io_port + 0, c);
133     }
134 
135     return 0;
136 }
137 
uart_read(struct device * dev,void * buf,size_t len)138 static ssize_t uart_read(struct device *dev, void *buf, size_t len) {
139     if (!dev || !buf)
140         return ERR_INVALID_ARGS;
141 
142     DEBUG_ASSERT(dev->state);
143     struct uart_driver_state *state = dev->state;
144 
145     return cbuf_read(&state->rx_buf, buf, len, true);
146 }
147 
uart_write(struct device * dev,const void * buf,size_t len)148 static ssize_t uart_write(struct device *dev, const void *buf, size_t len) {
149     if (!dev || !buf)
150         return ERR_INVALID_ARGS;
151 
152     DEBUG_ASSERT(dev->state);
153     struct uart_driver_state *state = dev->state;
154 
155     return cbuf_write(&state->tx_buf, buf, len, true);
156 }
157 
158