diff options
Diffstat (limited to 'arch/ppc/boot/common/misc-common.c')
-rw-r--r-- | arch/ppc/boot/common/misc-common.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c new file mode 100644 index 000000000000..e79e6b3f276e --- /dev/null +++ b/arch/ppc/boot/common/misc-common.c | |||
@@ -0,0 +1,553 @@ | |||
1 | /* | ||
2 | * arch/ppc/boot/common/misc-common.c | ||
3 | * | ||
4 | * Misc. bootloader code (almost) all platforms can use | ||
5 | * | ||
6 | * Author: Johnnie Peters <jpeters@mvista.com> | ||
7 | * Editor: Tom Rini <trini@mvista.com> | ||
8 | * | ||
9 | * Derived from arch/ppc/boot/prep/misc.c | ||
10 | * | ||
11 | * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under | ||
12 | * the terms of the GNU General Public License version 2. This program | ||
13 | * is licensed "as is" without any warranty of any kind, whether express | ||
14 | * or implied. | ||
15 | */ | ||
16 | |||
17 | #include <stdarg.h> /* for va_ bits */ | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/zlib.h> | ||
21 | #include "nonstdio.h" | ||
22 | |||
23 | /* If we're on a PReP, assume we have a keyboard controller | ||
24 | * Also note, if we're not PReP, we assume you are a serial | ||
25 | * console - Tom */ | ||
26 | #if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE) | ||
27 | extern void cursor(int x, int y); | ||
28 | extern void scroll(void); | ||
29 | extern char *vidmem; | ||
30 | extern int lines, cols; | ||
31 | extern int orig_x, orig_y; | ||
32 | extern int keyb_present; | ||
33 | extern int CRT_tstc(void); | ||
34 | extern int CRT_getc(void); | ||
35 | #else | ||
36 | int cursor(int x, int y) {return 0;} | ||
37 | void scroll(void) {} | ||
38 | char vidmem[1]; | ||
39 | #define lines 0 | ||
40 | #define cols 0 | ||
41 | int orig_x = 0; | ||
42 | int orig_y = 0; | ||
43 | #define keyb_present 0 | ||
44 | int CRT_tstc(void) {return 0;} | ||
45 | int CRT_getc(void) {return 0;} | ||
46 | #endif | ||
47 | |||
48 | extern char *avail_ram; | ||
49 | extern char *end_avail; | ||
50 | extern char _end[]; | ||
51 | |||
52 | void puts(const char *); | ||
53 | void putc(const char c); | ||
54 | void puthex(unsigned long val); | ||
55 | void gunzip(void *, int, unsigned char *, int *); | ||
56 | static int _cvt(unsigned long val, char *buf, long radix, char *digits); | ||
57 | |||
58 | void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap); | ||
59 | unsigned char *ISA_io = NULL; | ||
60 | |||
61 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
62 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
63 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
64 | extern unsigned long com_port; | ||
65 | |||
66 | extern int serial_tstc(unsigned long com_port); | ||
67 | extern unsigned char serial_getc(unsigned long com_port); | ||
68 | extern void serial_putc(unsigned long com_port, unsigned char c); | ||
69 | #endif | ||
70 | |||
71 | void pause(void) | ||
72 | { | ||
73 | puts("pause\n"); | ||
74 | } | ||
75 | |||
76 | void exit(void) | ||
77 | { | ||
78 | puts("exit\n"); | ||
79 | while(1); | ||
80 | } | ||
81 | |||
82 | int tstc(void) | ||
83 | { | ||
84 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
85 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
86 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
87 | if(keyb_present) | ||
88 | return (CRT_tstc() || serial_tstc(com_port)); | ||
89 | else | ||
90 | return (serial_tstc(com_port)); | ||
91 | #else | ||
92 | return CRT_tstc(); | ||
93 | #endif | ||
94 | } | ||
95 | |||
96 | int getc(void) | ||
97 | { | ||
98 | while (1) { | ||
99 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
100 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
101 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
102 | if (serial_tstc(com_port)) | ||
103 | return (serial_getc(com_port)); | ||
104 | #endif /* serial console */ | ||
105 | if (keyb_present) | ||
106 | if(CRT_tstc()) | ||
107 | return (CRT_getc()); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void | ||
112 | putc(const char c) | ||
113 | { | ||
114 | int x,y; | ||
115 | |||
116 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
117 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
118 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
119 | serial_putc(com_port, c); | ||
120 | if ( c == '\n' ) | ||
121 | serial_putc(com_port, '\r'); | ||
122 | #endif /* serial console */ | ||
123 | |||
124 | x = orig_x; | ||
125 | y = orig_y; | ||
126 | |||
127 | if ( c == '\n' ) { | ||
128 | x = 0; | ||
129 | if ( ++y >= lines ) { | ||
130 | scroll(); | ||
131 | y--; | ||
132 | } | ||
133 | } else if (c == '\r') { | ||
134 | x = 0; | ||
135 | } else if (c == '\b') { | ||
136 | if (x > 0) { | ||
137 | x--; | ||
138 | } | ||
139 | } else { | ||
140 | vidmem [ ( x + cols * y ) * 2 ] = c; | ||
141 | if ( ++x >= cols ) { | ||
142 | x = 0; | ||
143 | if ( ++y >= lines ) { | ||
144 | scroll(); | ||
145 | y--; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | cursor(x, y); | ||
151 | |||
152 | orig_x = x; | ||
153 | orig_y = y; | ||
154 | } | ||
155 | |||
156 | void puts(const char *s) | ||
157 | { | ||
158 | int x,y; | ||
159 | char c; | ||
160 | |||
161 | x = orig_x; | ||
162 | y = orig_y; | ||
163 | |||
164 | while ( ( c = *s++ ) != '\0' ) { | ||
165 | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \ | ||
166 | || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
167 | || defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
168 | serial_putc(com_port, c); | ||
169 | if ( c == '\n' ) serial_putc(com_port, '\r'); | ||
170 | #endif /* serial console */ | ||
171 | |||
172 | if ( c == '\n' ) { | ||
173 | x = 0; | ||
174 | if ( ++y >= lines ) { | ||
175 | scroll(); | ||
176 | y--; | ||
177 | } | ||
178 | } else if (c == '\b') { | ||
179 | if (x > 0) { | ||
180 | x--; | ||
181 | } | ||
182 | } else { | ||
183 | vidmem [ ( x + cols * y ) * 2 ] = c; | ||
184 | if ( ++x >= cols ) { | ||
185 | x = 0; | ||
186 | if ( ++y >= lines ) { | ||
187 | scroll(); | ||
188 | y--; | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | cursor(x, y); | ||
195 | |||
196 | orig_x = x; | ||
197 | orig_y = y; | ||
198 | } | ||
199 | |||
200 | void error(char *x) | ||
201 | { | ||
202 | puts("\n\n"); | ||
203 | puts(x); | ||
204 | puts("\n\n -- System halted"); | ||
205 | |||
206 | while(1); /* Halt */ | ||
207 | } | ||
208 | |||
209 | static void *zalloc(unsigned size) | ||
210 | { | ||
211 | void *p = avail_ram; | ||
212 | |||
213 | size = (size + 7) & -8; | ||
214 | avail_ram += size; | ||
215 | if (avail_ram > end_avail) { | ||
216 | puts("oops... out of memory\n"); | ||
217 | pause(); | ||
218 | } | ||
219 | return p; | ||
220 | } | ||
221 | |||
222 | #define HEAD_CRC 2 | ||
223 | #define EXTRA_FIELD 4 | ||
224 | #define ORIG_NAME 8 | ||
225 | #define COMMENT 0x10 | ||
226 | #define RESERVED 0xe0 | ||
227 | |||
228 | void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) | ||
229 | { | ||
230 | z_stream s; | ||
231 | int r, i, flags; | ||
232 | |||
233 | /* skip header */ | ||
234 | i = 10; | ||
235 | flags = src[3]; | ||
236 | if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { | ||
237 | puts("bad gzipped data\n"); | ||
238 | exit(); | ||
239 | } | ||
240 | if ((flags & EXTRA_FIELD) != 0) | ||
241 | i = 12 + src[10] + (src[11] << 8); | ||
242 | if ((flags & ORIG_NAME) != 0) | ||
243 | while (src[i++] != 0) | ||
244 | ; | ||
245 | if ((flags & COMMENT) != 0) | ||
246 | while (src[i++] != 0) | ||
247 | ; | ||
248 | if ((flags & HEAD_CRC) != 0) | ||
249 | i += 2; | ||
250 | if (i >= *lenp) { | ||
251 | puts("gunzip: ran out of data in header\n"); | ||
252 | exit(); | ||
253 | } | ||
254 | |||
255 | /* Initialize ourself. */ | ||
256 | s.workspace = zalloc(zlib_inflate_workspacesize()); | ||
257 | r = zlib_inflateInit2(&s, -MAX_WBITS); | ||
258 | if (r != Z_OK) { | ||
259 | puts("zlib_inflateInit2 returned "); puthex(r); puts("\n"); | ||
260 | exit(); | ||
261 | } | ||
262 | s.next_in = src + i; | ||
263 | s.avail_in = *lenp - i; | ||
264 | s.next_out = dst; | ||
265 | s.avail_out = dstlen; | ||
266 | r = zlib_inflate(&s, Z_FINISH); | ||
267 | if (r != Z_OK && r != Z_STREAM_END) { | ||
268 | puts("inflate returned "); puthex(r); puts("\n"); | ||
269 | exit(); | ||
270 | } | ||
271 | *lenp = s.next_out - (unsigned char *) dst; | ||
272 | zlib_inflateEnd(&s); | ||
273 | } | ||
274 | |||
275 | void | ||
276 | puthex(unsigned long val) | ||
277 | { | ||
278 | |||
279 | unsigned char buf[10]; | ||
280 | int i; | ||
281 | for (i = 7; i >= 0; i--) | ||
282 | { | ||
283 | buf[i] = "0123456789ABCDEF"[val & 0x0F]; | ||
284 | val >>= 4; | ||
285 | } | ||
286 | buf[8] = '\0'; | ||
287 | puts(buf); | ||
288 | } | ||
289 | |||
290 | #define FALSE 0 | ||
291 | #define TRUE 1 | ||
292 | |||
293 | void | ||
294 | _printk(char const *fmt, ...) | ||
295 | { | ||
296 | va_list ap; | ||
297 | |||
298 | va_start(ap, fmt); | ||
299 | _vprintk(putc, fmt, ap); | ||
300 | va_end(ap); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | #define is_digit(c) ((c >= '0') && (c <= '9')) | ||
305 | |||
306 | void | ||
307 | _vprintk(void(*putc)(const char), const char *fmt0, va_list ap) | ||
308 | { | ||
309 | char c, sign, *cp = 0; | ||
310 | int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right; | ||
311 | char buf[32]; | ||
312 | long val; | ||
313 | while ((c = *fmt0++)) | ||
314 | { | ||
315 | if (c == '%') | ||
316 | { | ||
317 | c = *fmt0++; | ||
318 | left_prec = right_prec = pad_on_right = 0; | ||
319 | if (c == '-') | ||
320 | { | ||
321 | c = *fmt0++; | ||
322 | pad_on_right++; | ||
323 | } | ||
324 | if (c == '0') | ||
325 | { | ||
326 | zero_fill = TRUE; | ||
327 | c = *fmt0++; | ||
328 | } else | ||
329 | { | ||
330 | zero_fill = FALSE; | ||
331 | } | ||
332 | while (is_digit(c)) | ||
333 | { | ||
334 | left_prec = (left_prec * 10) + (c - '0'); | ||
335 | c = *fmt0++; | ||
336 | } | ||
337 | if (c == '.') | ||
338 | { | ||
339 | c = *fmt0++; | ||
340 | zero_fill++; | ||
341 | while (is_digit(c)) | ||
342 | { | ||
343 | right_prec = (right_prec * 10) + (c - '0'); | ||
344 | c = *fmt0++; | ||
345 | } | ||
346 | } else | ||
347 | { | ||
348 | right_prec = left_prec; | ||
349 | } | ||
350 | sign = '\0'; | ||
351 | switch (c) | ||
352 | { | ||
353 | case 'd': | ||
354 | case 'x': | ||
355 | case 'X': | ||
356 | val = va_arg(ap, long); | ||
357 | switch (c) | ||
358 | { | ||
359 | case 'd': | ||
360 | if (val < 0) | ||
361 | { | ||
362 | sign = '-'; | ||
363 | val = -val; | ||
364 | } | ||
365 | length = _cvt(val, buf, 10, "0123456789"); | ||
366 | break; | ||
367 | case 'x': | ||
368 | length = _cvt(val, buf, 16, "0123456789abcdef"); | ||
369 | break; | ||
370 | case 'X': | ||
371 | length = _cvt(val, buf, 16, "0123456789ABCDEF"); | ||
372 | break; | ||
373 | } | ||
374 | cp = buf; | ||
375 | break; | ||
376 | case 's': | ||
377 | cp = va_arg(ap, char *); | ||
378 | length = strlen(cp); | ||
379 | break; | ||
380 | case 'c': | ||
381 | c = va_arg(ap, long /*char*/); | ||
382 | (*putc)(c); | ||
383 | continue; | ||
384 | default: | ||
385 | (*putc)('?'); | ||
386 | } | ||
387 | pad = left_prec - length; | ||
388 | if (sign != '\0') | ||
389 | { | ||
390 | pad--; | ||
391 | } | ||
392 | if (zero_fill) | ||
393 | { | ||
394 | c = '0'; | ||
395 | if (sign != '\0') | ||
396 | { | ||
397 | (*putc)(sign); | ||
398 | sign = '\0'; | ||
399 | } | ||
400 | } else | ||
401 | { | ||
402 | c = ' '; | ||
403 | } | ||
404 | if (!pad_on_right) | ||
405 | { | ||
406 | while (pad-- > 0) | ||
407 | { | ||
408 | (*putc)(c); | ||
409 | } | ||
410 | } | ||
411 | if (sign != '\0') | ||
412 | { | ||
413 | (*putc)(sign); | ||
414 | } | ||
415 | while (length-- > 0) | ||
416 | { | ||
417 | (*putc)(c = *cp++); | ||
418 | if (c == '\n') | ||
419 | { | ||
420 | (*putc)('\r'); | ||
421 | } | ||
422 | } | ||
423 | if (pad_on_right) | ||
424 | { | ||
425 | while (pad-- > 0) | ||
426 | { | ||
427 | (*putc)(c); | ||
428 | } | ||
429 | } | ||
430 | } else | ||
431 | { | ||
432 | (*putc)(c); | ||
433 | if (c == '\n') | ||
434 | { | ||
435 | (*putc)('\r'); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | int | ||
442 | _cvt(unsigned long val, char *buf, long radix, char *digits) | ||
443 | { | ||
444 | char temp[80]; | ||
445 | char *cp = temp; | ||
446 | int length = 0; | ||
447 | if (val == 0) | ||
448 | { /* Special case */ | ||
449 | *cp++ = '0'; | ||
450 | } else | ||
451 | while (val) | ||
452 | { | ||
453 | *cp++ = digits[val % radix]; | ||
454 | val /= radix; | ||
455 | } | ||
456 | while (cp != temp) | ||
457 | { | ||
458 | *buf++ = *--cp; | ||
459 | length++; | ||
460 | } | ||
461 | *buf = '\0'; | ||
462 | return (length); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) | ||
467 | { | ||
468 | int i, c; | ||
469 | if ((unsigned int)s > (unsigned int)p) | ||
470 | { | ||
471 | s = (unsigned int)s - (unsigned int)p; | ||
472 | } | ||
473 | while (s > 0) | ||
474 | { | ||
475 | if (base) | ||
476 | { | ||
477 | _printk("%06X: ", (int)p - (int)base); | ||
478 | } else | ||
479 | { | ||
480 | _printk("%06X: ", p); | ||
481 | } | ||
482 | for (i = 0; i < 16; i++) | ||
483 | { | ||
484 | if (i < s) | ||
485 | { | ||
486 | _printk("%02X", p[i] & 0xFF); | ||
487 | } else | ||
488 | { | ||
489 | _printk(" "); | ||
490 | } | ||
491 | if ((i % 2) == 1) _printk(" "); | ||
492 | if ((i % 8) == 7) _printk(" "); | ||
493 | } | ||
494 | _printk(" |"); | ||
495 | for (i = 0; i < 16; i++) | ||
496 | { | ||
497 | if (i < s) | ||
498 | { | ||
499 | c = p[i] & 0xFF; | ||
500 | if ((c < 0x20) || (c >= 0x7F)) c = '.'; | ||
501 | } else | ||
502 | { | ||
503 | c = ' '; | ||
504 | } | ||
505 | _printk("%c", c); | ||
506 | } | ||
507 | _printk("|\n"); | ||
508 | s -= 16; | ||
509 | p += 16; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | void | ||
514 | _dump_buf(unsigned char *p, int s) | ||
515 | { | ||
516 | _printk("\n"); | ||
517 | _dump_buf_with_offset(p, s, 0); | ||
518 | } | ||
519 | |||
520 | /* Very simple inb/outb routines. We declare ISA_io to be 0 above, and | ||
521 | * then modify it on platforms which need to. We do it like this | ||
522 | * because on some platforms we give inb/outb an exact location, and | ||
523 | * on others it's an offset from a given location. -- Tom | ||
524 | */ | ||
525 | |||
526 | void ISA_init(unsigned long base) | ||
527 | { | ||
528 | ISA_io = (unsigned char *)base; | ||
529 | } | ||
530 | |||
531 | void | ||
532 | outb(int port, unsigned char val) | ||
533 | { | ||
534 | /* Ensure I/O operations complete */ | ||
535 | __asm__ volatile("eieio"); | ||
536 | ISA_io[port] = val; | ||
537 | } | ||
538 | |||
539 | unsigned char | ||
540 | inb(int port) | ||
541 | { | ||
542 | /* Ensure I/O operations complete */ | ||
543 | __asm__ volatile("eieio"); | ||
544 | return (ISA_io[port]); | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Local variables: | ||
549 | * c-indent-level: 8 | ||
550 | * c-basic-offset: 8 | ||
551 | * tab-width: 8 | ||
552 | * End: | ||
553 | */ | ||