aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/boot/tty.c')
-rw-r--r--arch/x86/boot/tty.c111
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
20static 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
24void __attribute__((section(".inittext"))) putchar(int ch) 45static 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
55static 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
67void __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
39void __attribute__((section(".inittext"))) puts(const char *str) 78void __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
155static 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
173void 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}