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