diff options
Diffstat (limited to 'arch/x86/boot/tty.c')
-rw-r--r-- | arch/x86/boot/tty.c | 111 |
1 files changed, 105 insertions, 6 deletions
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c index 01ec69c901c7..f3ceee20ff12 100644 --- a/arch/x86/boot/tty.c +++ b/arch/x86/boot/tty.c | |||
@@ -10,23 +10,51 @@ | |||
10 | * ----------------------------------------------------------------------- */ | 10 | * ----------------------------------------------------------------------- */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * Very simple screen I/O | 13 | * Very simple screen and serial I/O |
14 | * XXX: Probably should add very simple serial I/O? | ||
15 | */ | 14 | */ |
16 | 15 | ||
17 | #include "boot.h" | 16 | #include "boot.h" |
18 | 17 | ||
18 | #define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */ | ||
19 | |||
20 | static int early_serial_base; | ||
21 | |||
22 | #define XMTRDY 0x20 | ||
23 | |||
24 | #define DLAB 0x80 | ||
25 | |||
26 | #define TXR 0 /* Transmit register (WRITE) */ | ||
27 | #define RXR 0 /* Receive register (READ) */ | ||
28 | #define IER 1 /* Interrupt Enable */ | ||
29 | #define IIR 2 /* Interrupt ID */ | ||
30 | #define FCR 2 /* FIFO control */ | ||
31 | #define LCR 3 /* Line control */ | ||
32 | #define MCR 4 /* Modem control */ | ||
33 | #define LSR 5 /* Line Status */ | ||
34 | #define MSR 6 /* Modem Status */ | ||
35 | #define DLL 0 /* Divisor Latch Low */ | ||
36 | #define DLH 1 /* Divisor latch High */ | ||
37 | |||
38 | #define DEFAULT_BAUD 9600 | ||
39 | |||
19 | /* | 40 | /* |
20 | * These functions are in .inittext so they can be used to signal | 41 | * These functions are in .inittext so they can be used to signal |
21 | * error during initialization. | 42 | * error during initialization. |
22 | */ | 43 | */ |
23 | 44 | ||
24 | void __attribute__((section(".inittext"))) putchar(int ch) | 45 | static void __attribute__((section(".inittext"))) serial_putchar(int ch) |
25 | { | 46 | { |
26 | struct biosregs ireg; | 47 | unsigned timeout = 0xffff; |
27 | 48 | ||
28 | if (ch == '\n') | 49 | while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) |
29 | putchar('\r'); /* \n -> \r\n */ | 50 | cpu_relax(); |
51 | |||
52 | outb(ch, early_serial_base + TXR); | ||
53 | } | ||
54 | |||
55 | static void __attribute__((section(".inittext"))) bios_putchar(int ch) | ||
56 | { | ||
57 | struct biosregs ireg; | ||
30 | 58 | ||
31 | initregs(&ireg); | 59 | initregs(&ireg); |
32 | ireg.bx = 0x0007; | 60 | ireg.bx = 0x0007; |
@@ -36,6 +64,17 @@ void __attribute__((section(".inittext"))) putchar(int ch) | |||
36 | intcall(0x10, &ireg, NULL); | 64 | intcall(0x10, &ireg, NULL); |
37 | } | 65 | } |
38 | 66 | ||
67 | void __attribute__((section(".inittext"))) putchar(int ch) | ||
68 | { | ||
69 | if (ch == '\n') | ||
70 | putchar('\r'); /* \n -> \r\n */ | ||
71 | |||
72 | bios_putchar(ch); | ||
73 | |||
74 | if (early_serial_base != 0) | ||
75 | serial_putchar(ch); | ||
76 | } | ||
77 | |||
39 | void __attribute__((section(".inittext"))) puts(const char *str) | 78 | void __attribute__((section(".inittext"))) puts(const char *str) |
40 | { | 79 | { |
41 | while (*str) | 80 | while (*str) |
@@ -112,3 +151,63 @@ int getchar_timeout(void) | |||
112 | 151 | ||
113 | return 0; /* Timeout! */ | 152 | return 0; /* Timeout! */ |
114 | } | 153 | } |
154 | |||
155 | static void early_serial_init(int baud) | ||
156 | { | ||
157 | unsigned char c; | ||
158 | unsigned divisor; | ||
159 | |||
160 | outb(0x3, early_serial_base + LCR); /* 8n1 */ | ||
161 | outb(0, early_serial_base + IER); /* no interrupt */ | ||
162 | outb(0, early_serial_base + FCR); /* no fifo */ | ||
163 | outb(0x3, early_serial_base + MCR); /* DTR + RTS */ | ||
164 | |||
165 | divisor = 115200 / baud; | ||
166 | c = inb(early_serial_base + LCR); | ||
167 | outb(c | DLAB, early_serial_base + LCR); | ||
168 | outb(divisor & 0xff, early_serial_base + DLL); | ||
169 | outb((divisor >> 8) & 0xff, early_serial_base + DLH); | ||
170 | outb(c & ~DLAB, early_serial_base + LCR); | ||
171 | } | ||
172 | |||
173 | void console_init(void) | ||
174 | { | ||
175 | int baud = DEFAULT_BAUD; | ||
176 | char arg[32]; | ||
177 | int pos = 0; | ||
178 | |||
179 | if (cmdline_find_option("earlyprintk", arg, sizeof arg) > 0) { | ||
180 | char *e; | ||
181 | |||
182 | if (!strncmp(arg, "serial", 6)) { | ||
183 | early_serial_base = DEFAULT_SERIAL_PORT; | ||
184 | pos += 6; | ||
185 | } | ||
186 | |||
187 | if (arg[pos] == ',') | ||
188 | pos++; | ||
189 | |||
190 | if (!strncmp(arg, "ttyS", 4)) { | ||
191 | static const int bases[] = { 0x3f8, 0x2f8 }; | ||
192 | int port = 0; | ||
193 | |||
194 | if (!strncmp(arg + pos, "ttyS", 4)) | ||
195 | pos += 4; | ||
196 | |||
197 | if (arg[pos++] == '1') | ||
198 | port = 1; | ||
199 | |||
200 | early_serial_base = bases[port]; | ||
201 | } | ||
202 | |||
203 | if (arg[pos] == ',') | ||
204 | pos++; | ||
205 | |||
206 | baud = simple_strtoull(arg + pos, &e, 0); | ||
207 | if (baud == 0 || arg + pos == e) | ||
208 | baud = DEFAULT_BAUD; | ||
209 | } | ||
210 | |||
211 | if (early_serial_base != 0) | ||
212 | early_serial_init(baud); | ||
213 | } | ||