1 #include <linux/console.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/string.h>
8 /* Simple VGA output */
10 #define VGABASE 0xffffffff800b8000UL
15 static int current_ypos = 1, current_xpos = 0;
17 static void early_vga_write(struct console *con, const char *str, unsigned n)
22 while ((c = *str++) != '\0' && n-- > 0) {
23 if (current_ypos >= MAX_YPOS) {
24 /* scroll 1 line up */
25 for(k = 1, j = 0; k < MAX_YPOS; k++, j++) {
26 for(i = 0; i < MAX_XPOS; i++) {
27 writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
28 VGABASE + 2*(MAX_XPOS*j + i));
31 for(i = 0; i < MAX_XPOS; i++) {
32 writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
34 current_ypos = MAX_YPOS-1;
39 } else if (c != '\r') {
40 writew(((0x7 << 8) | (unsigned short) c),
41 VGABASE + 2*(MAX_XPOS*current_ypos + current_xpos++));
42 if (current_xpos >= MAX_XPOS) {
50 static struct console early_vga_console = {
52 write: early_vga_write,
53 flags: CON_PRINTBUFFER,
57 /* Serial functions losely based on a similar package from Klaus P. Gerlicher */
59 int early_serial_base = 0x3f8; /* ttyS0 */
65 #define TXR 0 /* Transmit register (WRITE) */
66 #define RXR 0 /* Receive register (READ) */
67 #define IER 1 /* Interrupt Enable */
68 #define IIR 2 /* Interrupt ID */
69 #define FCR 2 /* FIFO control */
70 #define LCR 3 /* Line control */
71 #define MCR 4 /* Modem control */
72 #define LSR 5 /* Line Status */
73 #define MSR 6 /* Modem Status */
74 #define DLL 0 /* Divisor Latch Low */
75 #define DLH 1 /* Divisor latch High */
77 static int early_serial_putc(unsigned char ch)
79 unsigned timeout = 0xffff;
80 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
82 outb(ch, early_serial_base + TXR);
83 return timeout ? 0 : -1;
86 static void early_serial_write(struct console *con, const char *s, unsigned n)
88 while (*s && n-- > 0) {
89 early_serial_putc(*s);
91 early_serial_putc('\r');
96 static __init void early_serial_init(char *opt)
99 unsigned divisor, baud = 38400;
105 s = strsep(&opt, ",");
108 if (!strncmp(s,"0x",2))
109 early_serial_base = simple_strtoul(s, &e, 16);
111 static int bases[] = { 0x3f8, 0x2f8 };
112 if (!strncmp(s,"ttyS",4))
114 port = simple_strtoul(s, &e, 10);
115 if (port > 1 || s == e)
117 early_serial_base = bases[port];
121 outb(0x3, early_serial_base + LCR); /* 8n1 */
122 outb(0, early_serial_base + IER); /* no interrupt */
123 outb(0, early_serial_base + FCR); /* no fifo */
124 outb(0x3, early_serial_base + MCR); /* DTR + RTS */
126 s = strsep(&opt, ",");
128 baud = simple_strtoul(s, &e, 0);
129 if (baud == 0 || s == e)
133 divisor = 115200 / baud;
134 c = inb(early_serial_base + LCR);
135 outb(c | DLAB, early_serial_base + LCR);
136 outb(divisor & 0xff, early_serial_base + DLL);
137 outb((divisor >> 8) & 0xff, early_serial_base + DLH);
138 outb(c & ~DLAB, early_serial_base + LCR);
141 static struct console early_serial_console = {
143 write: early_serial_write,
144 flags: CON_PRINTBUFFER,
148 /* Direct interface for emergencies */
149 struct console *early_console = &early_vga_console;
150 static int early_console_initialized = 0;
152 void early_printk(const char *fmt, ...)
158 n = vsnprintf(buf,512,fmt,ap);
159 early_console->write(early_console,buf,n);
163 static int keep_early;
165 int __init setup_early_printk(char *opt)
170 if (early_console_initialized)
173 strncpy(buf,opt,256);
175 space = strchr(buf, ' ');
179 if (strstr(buf,"keep"))
182 if (!strncmp(buf, "serial", 6)) {
183 early_serial_init(buf + 6);
184 early_console = &early_serial_console;
185 } else if (!strncmp(buf, "vga", 3)) {
186 early_console = &early_vga_console;
188 early_console = NULL;
191 early_console_initialized = 1;
192 register_console(early_console);
196 void __init disable_early_printk(void)
198 if (!early_console_initialized || !early_console)
201 printk("Disabling early console\n");
202 unregister_console(early_console);
203 early_console_initialized = 0;
207 /* syntax: earlyprintk=vga
208 earlyprintk=serial[,ttySn[,baudrate]]
209 Append ,keep to not disable it when the real console takes over.
210 Only vga or serial at a time, not both.
211 Currently only ttyS0 and ttyS1 are supported.
212 Interaction with the standard serial driver is not very good.
213 The VGA output is eventually overwritten by the real console. */
214 __setup("earlyprintk=", setup_early_printk);