forked from RIOT-OS/RIOT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathx86_uart.c
136 lines (120 loc) · 3.31 KB
/
x86_uart.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Copyright (C) 2014 René Kijewski <rene.kijewski@fu-berlin.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @ingroup x86-irq
* @{
*
* @file
* @brief UART reading and writing.
*
* @author René Kijewski <rene.kijewski@fu-berlin.de>
*
* @}
*/
#include "board.h"
#include "x86_ports.h"
#include "x86_uart.h"
#include <cpu.h>
#include <board_uart0.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
void x86_early_init_uart(void)
{
outb(UART_PORT + IER, 0x00); /* Disable all interrupts */
outb(UART_PORT + LCR, LCR_DLAB);
outb(UART_PORT + DLL, BAUD_LL); /* Set divisor (lo byte) */
outb(UART_PORT + DLH, BAUD_HL); /* (hi byte) */
outb(UART_PORT + LCR, LCR_WORD_BITS_8 | LCR_PAR_NONE | LCR_STOP_BITS_1);
outb(UART_PORT + FCR, FCR_ENABLE | FCR_CLR_RECV | FCR_CLR_SEND | FCR_TRIGGER_16);
outb(UART_PORT + MCR, MCR_DSR | MCR_RTS | MCR_AUX2);
}
static bool is_output_empty(void)
{
uint8_t data = inb(UART_PORT + LSR);
return (data & 0x20) != 0;
}
static bool is_input_empty(void)
{
uint8_t data = inb(UART_PORT + LSR);
return (data & 0x01) == 0;
}
ssize_t x86_uart_write(const char *buf, size_t len)
{
if (!UART_PORT) {
return -1;
}
(void) buf;
size_t written = 0;
while (written < len) {
while (!is_output_empty()) {
asm volatile ("pause");
}
outb(UART_PORT + THR, buf[written]);
++written;
}
return written;
}
ssize_t x86_uart_read(char *buf, size_t len)
{
if (!UART_PORT) {
return -1;
}
size_t read = 0;
while (read < len) {
while (!is_input_empty()) {
asm volatile ("pause");
}
buf[read] = inb(UART_PORT + RBR);
++read;
}
return read;
}
#ifdef MODULE_UART0
static void com_handler(uint8_t irq_num)
{
(void) irq_num; /* == UART_IRQ */
switch (inb(UART_PORT + IIR) & IIR_INT_MASK) {
case IIR_INT_BR: {
while (is_input_empty()) {
asm volatile ("pause");
}
do {
uint8_t c = inb(UART_PORT + RBR);
uart0_handle_incoming(c);
} while (!is_input_empty());
uart0_notify_thread();
break;
}
case IIR_INT_TH:
case IIR_INT_LS:
case IIR_INT_TO:
default:
break;
}
}
#endif /* ifdef MODULE_UART0 */
void x86_init_uart(void)
{
#ifdef MODULE_UART0
x86_pic_set_handler(UART_IRQ, com_handler);
x86_pic_enable_irq(UART_IRQ);
outb(UART_PORT + IER, IER_RECV); /* Enable receive interrupt */
puts("UART initialized");
#endif
}