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