-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserial.c
140 lines (119 loc) · 3.7 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "io.h"
#include "serial.h"
/* ------------------------------------------------------------------------- */
/* ---------------------- Serial ports --------------------------------------*/
/* ------------------------------------------------------------------------- */
/** serial_configure_baud_rate:
* Sets the speed of the data being sent. The default speed of a serial
* port is 115200 bits/s. The argument is a divisor of that number, hence
* the resulting speed becomes (115200 / divisor) bits/s.
*
* @param com The COM port to configure
* @param divisor The divisor
*/
void serial_configure_baud_rate(unsigned short com, unsigned short divisor)
{
outb(SERIAL_LINE_COMMAND_PORT(com), SERIAL_LINE_ENABLE_DLAB);
outb(SERIAL_DATA_PORT(com), (divisor >> 8) & 0x00FF);
outb(SERIAL_DATA_PORT(com), divisor & 0x00FF);
}
/** serial_configure_line:
* Configures the line of the given serial port. The port is set (0x03) to have a
* data length of 8 bits, no parity bits, one stop bit and break control
* disabled.
*
* d Enables (d = 1) or disables (d = 0) DLAB (Divisor Latch Access Bit)
* b If break control is enabled (b = 1) or disabled (b = 0)
* 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
*
* @param com The serial port to configure
*/
void serial_configure_line(unsigned short com)
{
/* Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 |
* Content: | d | b | prty | s | dl |
* Value: | 0 | 0 | 0 0 0 | 0 | 1 1 | = 0x03
*/
outb(SERIAL_LINE_COMMAND_PORT(com), 0x03);
}
/** serial_is_transmit_fifo_empty:
* Checks whether the transmit FIFO queue is empty or not for the given COM
* port.
*
* @param com The COM port
* @return 0 if the transmit FIFO queue is not empty
* 1 if the transmit FIFO queue is empty
*/
int serial_is_transmit_fifo_empty(unsigned int com)
{
/* 0x20 = 0010 0000 */
return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20;
}
void serial_write_char(unsigned int com, char a)
{
while (serial_is_transmit_fifo_empty(com) == 0);
outb(SERIAL_DATA_PORT(com), a);
}
void serial_write(const char* data, int len)
{
int i = 0;
for (i = 0; i < len; i++) {
serial_write_char(SERIAL_COM1_BASE, data[i]);
}
}
void test_serial_port()
{
serial_configure_baud_rate(SERIAL_COM1_BASE, 4);
serial_configure_line(SERIAL_COM1_BASE);
char str[] = "test serial port\n";
serial_write(str, 17);
char fmt[] = "serial_printf Expected -30 Actual %d\n";
serial_printf(fmt, -30);
}
/*
* Only decimals expected at the moment.
* Example:
* char fmt[] = "serial_printf Expected -30 Actual %d\n";
* serial_printf(fmt, -30);
*/
void serial_printf(char* fmt, int args) {
serial_configure_baud_rate(SERIAL_COM1_BASE, 4);
serial_configure_line(SERIAL_COM1_BASE);
char decimals[] = "0123456789-";
int *current_arg = &args;
while(fmt[0]) {
if(fmt[0] == '%') { // Start to handle the next variadic argument.
fmt++;
switch(fmt[0]){
case 'd': // Decimal number.
if(current_arg[0] < 0){ // Handle negative numbers.
serial_write(&decimals[10], 1);
current_arg[0] *= -1;
}
// Calculate lenght of the string representation of the number.
int length = 0;
int tmp = current_arg[0];
while(tmp) {
length++;
tmp /= 10;
}
// Write out the string representation of the number
char number_as_str[length - 1];
int cur = length;
while(cur) {
cur--;
number_as_str[cur] = decimals[current_arg[0] % 10];
current_arg[0] /= 10;
}
serial_write(number_as_str, length);
current_arg++;
break;
}
} else {
serial_write(fmt, 1);
}
fmt++;
}
}