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