-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserial.c
118 lines (108 loc) · 3.61 KB
/
serial.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
#include "serial.h"
#include "io.h"
void serial_cfg_baudrate(unsigned short com, unsigned short divisor){
/*
* Tell the serial controller that we are about to
* set the divisor of the baudrate. This is done
* by writing to the data register and interrupt
* enabling register. These two bytes will hold the
* divisor data WHILE the DLAB bit is set.
*/
outb(SERIAL_LINE_CMD_PORT(com), SERIAL_LINE_ENABLE_DLAB);
outb(SERIAL_DATA_PORT(com), (divisor >> 8) & 0x00FF);
outb(SERIAL_DATA_PORT(com), divisor & 0x00FF);
outb(SERIAL_LINE_CMD_PORT(com), 0x0);
}
void serial_cfg_line(unsigned short com){
/*
* Line control register layout:
*
* | 7 | 6 | 5 4 3 | 2 | 1 0 |
* | d | b | pty | s | dl |
*
* Where:
* + d => Enables the DLAB
* + b => Enables break control
* + prty => The number of parity bits to use
* + s => The number of stop bits to use
* (s = 0 equals 1, s = 1 equals 1.5 or 2)
* + dl => Describes the length of the data
*
* The most commonly used value is 8 bits lenght, no
* parity bit, 1 stop bit and break control disabled,
* i.e. 0x03.
*/
outb(SERIAL_LINE_CMD_PORT(com), 0x03);
}
void serial_cfg_buf(unsigned short com){
/*
* Buffer config register layout:
*
* | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* | lvl | bs | r | dma | clt | clr | e |
*
* Where:
* + lvl => Size of the buffer in bytes
* + bs => Enables 64 byte FIFO
* + r => Reserved for future use
* + dma => DMA mode selection
* + clt => Clear the transmission FIFO
* + clr => Clear the reception FIFO
* + e => Enables or disables the FIFO buffer
*
* The default value by convention, for now, will be
* one which enables the FIFO, clears both buffers and
* uses 14 bytes of size, i.e. 0xC7.
*/
outb(SERIAL_FIFO_CMD_PORT(com), 0xC7);
}
void serial_cfg_modem(unsigned short com){
/*
* Modem control register:
*
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* | r | r | af | lb | ao2 | ao1 | rts | dtr |
*
* Where:
* + r => Reserved
* + af => Enables autoflow control (not used)
* + lb => Enables loopback mode. In loopback mode
* the controller disconnects the receiver
* serial input and redirects it to the
* transmitter. Used for debugging
* + ao2 => Auxiliary output 2, used for receiving
* interrupts
* + ao1 => Auxiliary output 1
* + rts => Ready to transmit (RTS) bit
* + dtr => Data terminal ready (DTR) bit
*
* The default value to use will be 0x03
*/
outb(SERIAL_MODEM_CMD_PORT(com), 0x03);
}
void serial_init(void){
struct com_port com1 = { SERIAL_COM1_BASE, 1 };
serial_cfg_port(&com1);
}
void serial_cfg_port(const struct com_port *p){
serial_cfg_baudrate(p->com, p->divisor);
serial_cfg_line(p->com);
serial_cfg_buf(p->com);
serial_cfg_modem(p->com);
}
unsigned char serial_is_tx_fifo_empty(unsigned short com){
/* bit 5 of line status register indicates if queue is empty */
return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20;
}
void serial_write(unsigned char *b, unsigned short len){
unsigned int i = 0;
/*
* TODO: Since there is no wait-queue or event dispatching
* mechanism yet, we will spin until data is available on
* a given COM port.
*/
while (!serial_is_tx_fifo_empty(SERIAL_COM1_BASE));
while (i < len){
outb(SERIAL_COM1_BASE, b[i++]);
}
}