also update spec file ...
[linux-flexiantxendom0-3.2.10.git] / kernel / early_printk.c
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>
6 #include <asm/io.h>
7 #include <asm/setup.h>
8 #include <asm/pgtable.h>
9
10 /* Simple VGA output */
11
12 #define MAX_YPOS        25
13 #define MAX_XPOS        80
14
15 static int current_ypos = 1, current_xpos = 0; 
16 extern char saved_command_line[];
17
18 static void early_vga_write(struct console *con, const char *str, unsigned n)
19 {
20         char c;
21         int  i, k, j;
22
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));
30                                 }
31                         }
32                         for(i = 0; i < MAX_XPOS; i++) {
33                                 writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
34                         }
35                         current_ypos = MAX_YPOS-1;
36                 }
37                 if (c == '\n') {
38                         current_xpos = 0;
39                         current_ypos++;
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) {
44                                 current_xpos = 0;
45                                 current_ypos++;
46                         }
47                 }
48         }
49 }
50
51 static struct console early_vga_console = {
52         .name =         "earlyvga",
53         .write =        early_vga_write,
54         .flags =        CON_PRINTBUFFER,
55         .index =        -1,
56 };
57
58 /* Serial functions losely based on a similar package from Klaus P. Gerlicher */ 
59
60 int early_serial_base;  /* ttyS0 */ 
61
62 static int early_serial_putc(unsigned char ch) 
63
64         unsigned timeout = 0xffff; 
65         while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 
66                 rep_nop(); 
67         outb(ch, early_serial_base + TXR);
68         return timeout ? 0 : -1;
69
70
71 static void early_serial_write(struct console *con, const char *s, unsigned n)
72 {
73         while (*s && n-- > 0) { 
74                 early_serial_putc(*s); 
75                 if (*s == '\n') 
76                         early_serial_putc('\r'); 
77                 s++; 
78         } 
79
80
81 static __init void early_serial_init(char *opt)
82 {
83         unsigned char c; 
84         unsigned divisor, baud = DEFAULT_BAUD;
85         static int bases[] = SERIAL_BASES;
86         char *s, *e;
87
88         early_serial_base = bases[0];
89         
90         if (*opt == ',') 
91                 ++opt;
92
93         s = strsep(&opt, ","); 
94         if (s != NULL) { 
95                 unsigned port; 
96                 if (!strncmp(s,"0x",2))
97                         early_serial_base = simple_strtoul(s, &e, 16);
98                 else {  
99                         if (!strncmp(s,"ttyS",4)) 
100                                 s+=4; 
101                         port = simple_strtoul(s, &e, 10); 
102                         if (port > (SERIAL_BASES_LEN-1) || s == e) 
103                                 port = 0; 
104                         early_serial_base = bases[port];
105                 }
106         }
107
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 */ 
112
113         s = strsep(&opt, ","); 
114         if (s != NULL) { 
115                 baud = simple_strtoul(s, &e, 0); 
116                 if (baud == 0 || s == e) 
117                         baud = DEFAULT_BAUD;
118         } 
119         
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);
126 }
127
128 static struct console early_serial_console = {
129         .name =         "earlyser",
130         .write =        early_serial_write,
131         .flags =        CON_PRINTBUFFER,
132         .index =        -1,
133 };
134
135 /* Direct interface for emergencies */
136 struct console *early_console = &early_vga_console;
137 static int early_console_initialized = 0;
138
139 void early_printk(const char *fmt, ...)
140
141         char buf[512]; 
142         int n; 
143         va_list ap;
144         va_start(ap,fmt); 
145         n = vsnprintf(buf,512,fmt,ap);
146         early_console->write(early_console,buf,n);
147         va_end(ap); 
148
149
150 static int keep_early; 
151
152 int __init setup_early_printk(void) 
153 {  
154         char *space, *s;
155         char buf[256];
156         char cmd[COMMAND_LINE_SIZE];
157         char *opt;
158
159         /* Get our own copy of the cmd line */
160         memcpy(cmd, COMMAND_LINE, COMMAND_LINE_SIZE);
161         cmd[COMMAND_LINE_SIZE-1] = '\0';
162         opt = cmd;
163         
164         s = strstr(opt, "earlyprintk=");
165         if (s == NULL)
166                 return -1;
167         opt = s+12;
168         
169         if (early_console_initialized)
170                 return -1;
171
172         strncpy(buf,opt,256); 
173         buf[255] = 0; 
174         space = strchr(buf, ' '); 
175         if (space)
176                 *space = 0; 
177
178         if (strstr(buf,"keep"))
179                 keep_early = 1; 
180
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; 
189         } else {
190                 early_console = NULL;           
191                 return -1; 
192         }
193         early_console_initialized = 1;
194         register_console(early_console);
195         printk("early printk console registered\n");
196         return 0;
197 }
198
199 void __init disable_early_printk(void)
200
201         if (!early_console_initialized || !early_console)
202                 return;
203         if (!keep_early) {
204                 printk("disabling early console...\n"); 
205                 unregister_console(early_console);
206                 early_console_initialized = 0;
207         } else { 
208                 printk("keeping early console.\n"); 
209         }
210
211
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);