Linux-2.6.12-rc2
[linux-2.6] / arch / ppc / boot / common / misc-common.c
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  */