1 #include <linux/console.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/string.h>
5 #include <linux/early_printk.h>
8 #include <asm/pgtable.h>
10 /* Simple VGA output */
15 static int current_ypos = 1, current_xpos = 0;
16 extern char saved_command_line[];
18 static void early_vga_write(struct console *con, const char *str, unsigned n)
23 while ((c = *str++) != '\0' && n-- > 0) {
24 if (current_ypos >= MAX_YPOS) {
25 /* scroll 1 line up */
26 for(k = 1, j = 0; k < MAX_YPOS; k++, j++) {
27 for(i = 0; i < MAX_XPOS; i++) {
28 writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
29 VGABASE + 2*(MAX_XPOS*j + i));
32 for(i = 0; i < MAX_XPOS; i++) {
33 writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
35 current_ypos = MAX_YPOS-1;
40 } else if (c != '\r') {
41 writew(((0x7 << 8) | (unsigned short) c),
42 VGABASE + 2*(MAX_XPOS*current_ypos + current_xpos++));
43 if (current_xpos >= MAX_XPOS) {
51 static struct console early_vga_console = {
53 .write = early_vga_write,
54 .flags = CON_PRINTBUFFER,
58 /* Serial functions losely based on a similar package from Klaus P. Gerlicher */
60 int early_serial_base; /* ttyS0 */
62 static int early_serial_putc(unsigned char ch)
64 unsigned timeout = 0xffff;
65 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
67 outb(ch, early_serial_base + TXR);
68 return timeout ? 0 : -1;
71 static void early_serial_write(struct console *con, const char *s, unsigned n)
73 while (*s && n-- > 0) {
74 early_serial_putc(*s);
76 early_serial_putc('\r');
81 static __init void early_serial_init(char *opt)
84 unsigned divisor, baud = DEFAULT_BAUD;
85 static int bases[] = SERIAL_BASES;
88 early_serial_base = bases[0];
93 s = strsep(&opt, ",");
96 if (!strncmp(s,"0x",2))
97 early_serial_base = simple_strtoul(s, &e, 16);
99 if (!strncmp(s,"ttyS",4))
101 port = simple_strtoul(s, &e, 10);
102 if (port > (SERIAL_BASES_LEN-1) || s == e)
104 early_serial_base = bases[port];
108 outb(0x3, early_serial_base + LCR); /* 8n1 */
109 outb(0, early_serial_base + IER); /* no interrupt */
110 outb(0, early_serial_base + FCR); /* no fifo */
111 outb(0x3, early_serial_base + MCR); /* DTR + RTS */
113 s = strsep(&opt, ",");
115 baud = simple_strtoul(s, &e, 0);
116 if (baud == 0 || s == e)
120 divisor = 115200 / baud;
121 c = inb(early_serial_base + LCR);
122 outb(c | DLAB, early_serial_base + LCR);
123 outb(divisor & 0xff, early_serial_base + DLL);
124 outb((divisor >> 8) & 0xff, early_serial_base + DLH);
125 outb(c & ~DLAB, early_serial_base + LCR);
128 static struct console early_serial_console = {
130 .write = early_serial_write,
131 .flags = CON_PRINTBUFFER,
135 /* Direct interface for emergencies */
136 struct console *early_console = &early_vga_console;
137 static int early_console_initialized = 0;
139 void early_printk(const char *fmt, ...)
145 n = vsnprintf(buf,512,fmt,ap);
146 early_console->write(early_console,buf,n);
150 static int keep_early;
152 int __init setup_early_printk(void)
156 char cmd[COMMAND_LINE_SIZE];
159 /* Get our own copy of the cmd line */
160 memcpy(cmd, COMMAND_LINE, COMMAND_LINE_SIZE);
161 cmd[COMMAND_LINE_SIZE-1] = '\0';
164 s = strstr(opt, "earlyprintk=");
169 if (early_console_initialized)
172 strncpy(buf,opt,256);
174 space = strchr(buf, ' ');
178 if (strstr(buf,"keep"))
181 if (!strncmp(buf, "serial", 6)) {
182 early_serial_init(buf + 6);
183 early_console = &early_serial_console;
184 } else if (!strncmp(buf, "ttyS", 4)) {
185 early_serial_init(buf);
186 early_console = &early_serial_console;
187 } else if (!strncmp(buf, "vga", 3)) {
188 early_console = &early_vga_console;
190 early_console = NULL;
193 early_console_initialized = 1;
194 register_console(early_console);
195 printk("early printk console registered\n");
199 void __init disable_early_printk(void)
201 if (!early_console_initialized || !early_console)
204 printk("disabling early console...\n");
205 unregister_console(early_console);
206 early_console_initialized = 0;
208 printk("keeping early console.\n");
212 /* syntax: earlyprintk=vga
213 earlyprintk=serial[,ttySn[,baudrate]]
214 Append ,keep to not disable it when the real console takes over.
215 Only vga or serial at a time, not both.
216 Currently only ttyS0 and ttyS1 are supported.
217 Interaction with the standard serial driver is not very good.
218 The VGA output is eventually overwritten by the real console. */
219 __setup("earlyprintk=", setup_early_printk);