1 /*
2  * Copyright (c) 2009 Corey Tabaka
3  * Copyright (c) 2015 Travis Geiselbrecht
4  *
5  * Use of this source code is governed by a MIT-style
6  * license that can be found in the LICENSE file or at
7  * https://opensource.org/licenses/MIT
8  */
9 #include <stdarg.h>
10 #include <lk/reg.h>
11 #include <lk/trace.h>
12 #include <lk/err.h>
13 #include <stdio.h>
14 #include <kernel/thread.h>
15 #include <lib/cbuf.h>
16 #include <dev/uart.h>
17 #include <platform/interrupts.h>
18 #include <platform/qemu-mips.h>
19 
20 static int uart_baud_rate = 115200;
21 static int uart_io_port = 0x3f8;
22 
23 static cbuf_t uart_rx_buf;
24 
uart_irq_handler(void * arg)25 static enum handler_return uart_irq_handler(void *arg) {
26     unsigned char c;
27     bool resched = false;
28 
29     while (isa_read_8(uart_io_port + 5) & (1<<0)) {
30         c = isa_read_8(uart_io_port + 0);
31         cbuf_write_char(&uart_rx_buf, c, false);
32         resched = true;
33     }
34 
35     return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
36 }
37 
uart_init_early(void)38 void uart_init_early(void) {
39     /* configure the uart */
40     int divisor = 115200 / uart_baud_rate;
41 
42     /* get basic config done so that tx functions */
43     isa_write_8(uart_io_port + 3, 0x80); // set up to load divisor latch
44     isa_write_8(uart_io_port + 0, divisor & 0xff); // lsb
45     isa_write_8(uart_io_port + 1, divisor >> 8); // msb
46     isa_write_8(uart_io_port + 3, 3); // 8N1
47     isa_write_8(uart_io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
48 }
49 
uart_init(void)50 void uart_init(void) {
51     /* finish uart init to get rx going */
52     cbuf_initialize(&uart_rx_buf, 16);
53 
54     register_int_handler(0x4, uart_irq_handler, NULL);
55     unmask_interrupt(0x4);
56 
57     isa_write_8(uart_io_port + 1, 0x1); // enable receive data available interrupt
58 }
59 
uart_putc(int port,char c)60 int uart_putc(int port, char c) {
61     while ((isa_read_8(uart_io_port + 5) & (1<<6)) == 0)
62         ;
63     isa_write_8(uart_io_port + 0, c);
64     return 0;
65 }
66 
uart_getc(int port,bool wait)67 int uart_getc(int port, bool wait) {
68     char c;
69     if (cbuf_read_char(&uart_rx_buf, &c, wait) == 1) {
70         return c;
71     } else {
72         return -1;
73     }
74 }
75 
platform_dputc(char c)76 void platform_dputc(char c) {
77     if (c == '\n')
78         platform_dputc('\r');
79 #if WITH_CGA_CONSOLE
80     cputc(c);
81 #else
82     uart_putc(0, c);
83 #endif
84 }
85 
platform_dgetc(char * c,bool wait)86 int platform_dgetc(char *c, bool wait) {
87 #if WITH_CGA_CONSOLE
88     int ret =  platform_read_key(c);
89     //if (ret < 0)
90     //  arch_idle();
91 #else
92     int ret = uart_getc(0, wait);
93     if (ret >= 0) {
94         *c = ret;
95     }
96 #endif
97 
98     return ret;
99 }
100