3
3
#include "kernel/util/spinlock/spinlock.h"
4
4
#include <kernel/smp.h>
5
5
6
+ // Ref: https://www.lookrs232.com/rs232/fcr.htm
7
+
6
8
//COM 1
7
9
#define PORT 0x3F8
8
10
9
- #define BUF_SIZE 1028*8
10
- static char buffer [BUF_SIZE ];
11
+ // Only valid when DLAB is unset
12
+ #define DATA_REGISTER (PORT + 0)
13
+ #define INTERRUPT_ENABLE_REGISTER (PORT + 1)
14
+
15
+ // Only valid when DLAB is set
16
+ #define DLAB_DATA_BYTE_LOW_REGISTER (PORT + 0)
17
+ #define DLAB_DATA_BYTE_HIGH_REGISTER (PORT + 1)
18
+
19
+ #define INTERRUPT_AND_FIFO_CONTROL_REGISTER (PORT + 2)
20
+ #define LINE_CONTROL_REGISTER (PORT + 3)
21
+ #define MODEM_CONTROL_REGISTER (PORT + 4)
22
+
23
+ #define BUF_SIZE (1028*8)
24
+ static char buffer [BUF_SIZE ] = {0 };
11
25
static int idx = 0 ;
12
26
13
27
int serial_waiting () {
@@ -25,7 +39,10 @@ bool is_transmitting() {
25
39
26
40
void __serial_putchar (char c ) {
27
41
while (is_transmitting () == 0 );
28
- if (c == '\n' ) outb (PORT , '\r' );
42
+ if (c == '\n' ) {
43
+ // Add an extra carriage return
44
+ outb (PORT , '\r' );
45
+ }
29
46
outb (PORT , c );
30
47
}
31
48
@@ -38,7 +55,8 @@ void __serial_writestring(char* str) {
38
55
39
56
static void serial_flush () {
40
57
__serial_writestring (buffer );
41
- memset (buffer , 0 , BUF_SIZE );
58
+ // It's only necessary to memset up to where we last wrote
59
+ memset (buffer , 0 , idx );
42
60
idx = 0 ;
43
61
}
44
62
@@ -49,7 +67,7 @@ void serial_putchar(char c) {
49
67
}
50
68
//append c to buffer
51
69
buffer [idx + 0 ] = c ;
52
- buffer [idx + 1 ] = '\0' ;
70
+ // buffer[idx+1] = '\0';
53
71
idx ++ ;
54
72
//also flush on newline
55
73
if (c == '\n' ) {
@@ -95,11 +113,48 @@ void serial_init() {
95
113
96
114
memset (buffer , 0 , BUF_SIZE );
97
115
98
- outb (PORT + 1 , 0x00 ); //interrupts off
99
- outb (PORT + 3 , 0x80 ); //baud rate
100
- outb (PORT + 0 , 0x03 ); //divisor to 3
101
- outb (PORT + 1 , 0x00 );
102
- outb (PORT + 3 , 0x03 ); //1 byte, no parity, 1 stop bit
103
- outb (PORT + 2 , 0xC7 ); //FIFO, 14-byte threshold
104
- outb (PORT + 4 , 0x0B ); //irq on, RTS/DSR set
116
+ // Disable interrupts
117
+ outb (INTERRUPT_ENABLE_REGISTER , 0x00 );
118
+
119
+ // Enable DLAB bit, as we'll set the frequency divisor next
120
+ outb (LINE_CONTROL_REGISTER , 0x80 );
121
+ // Set divisor to 1, so we transmit at the serial clock speed
122
+ // Low divisor byte
123
+ outb (DLAB_DATA_BYTE_LOW_REGISTER , 0x01 );
124
+ // High divisor byte
125
+ outb (DLAB_DATA_BYTE_HIGH_REGISTER , 0x00 );
126
+
127
+ // Bit pattern:
128
+ // [0, 1]: Set 7 data bits (we're just sending ASCII so this should work out cleanly)
129
+ // 2: Set 1 stop bit
130
+ // 3: No parity bit
131
+ outb (LINE_CONTROL_REGISTER , 0b0010 );
132
+
133
+ // Bit pattern:
134
+ // 0: Enable FIFO's
135
+ // 1: Clear receive FIFO
136
+ // 2: Clear transmit FIFO
137
+ // 3: DMA mode-select
138
+ // 4: Reserved
139
+ // 5: Disable model-specific 64-byte FIFO
140
+ // [6-7]: Set interrupt trigger level to 14 bytes
141
+ outb (INTERRUPT_AND_FIFO_CONTROL_REGISTER , 0b11000111 );
142
+
143
+ // Bit pattern:
144
+ // 0: Data Terminal Ready
145
+ // 1: Request to Send
146
+ // 2: OUT1, unused in PC implementations
147
+ // 3: Set the OUT2 hardware pin which is used to enable the IRQ in PC implementations
148
+ // 4: Disable loopback
149
+ // [5-7]: Unused
150
+ outb (MODEM_CONTROL_REGISTER , 0b00001011 );
151
+
152
+ // TODO(PT): Switch to an interrupt-based model for this controller, instead of polling
153
+ /*
154
+ // Enable interrupts.
155
+ // Bit pattern:
156
+ // : Interrupt when the transmitter is empty (so we know when we can send more)
157
+ interrupt_setup_callback(INT_VECTOR_APIC_4, (int_callback_t)_handle_irq);
158
+ outb(INTERRUPT_ENABLE_REGISTER, 0b10);
159
+ */
105
160
}
0 commit comments