1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9#include <stdarg.h>
10#include <linux/types.h>
11#include <linux/string.h>
12#include <linux/ctype.h>
13
14#include <asm/div64.h>
15
16int (*prom)(void *);
17
18void *chosen_handle;
19void *stdin;
20void *stdout;
21void *stderr;
22
23void exit(void);
24void *finddevice(const char *name);
25int getprop(void *phandle, const char *name, void *buf, int buflen);
26void chrpboot(int a1, int a2, void *prom);	/* in main.c */
27
28void printk(char *fmt, ...);
29
30int
31write(void *handle, void *ptr, int nb)
32{
33	struct prom_args {
34		char *service;
35		int nargs;
36		int nret;
37		void *ihandle;
38		void *addr;
39		int len;
40		int actual;
41	} args;
42
43	args.service = "write";
44	args.nargs = 3;
45	args.nret = 1;
46	args.ihandle = handle;
47	args.addr = ptr;
48	args.len = nb;
49	args.actual = -1;
50	(*prom)(&args);
51	return args.actual;
52}
53
54int
55read(void *handle, void *ptr, int nb)
56{
57	struct prom_args {
58		char *service;
59		int nargs;
60		int nret;
61		void *ihandle;
62		void *addr;
63		int len;
64		int actual;
65	} args;
66
67	args.service = "read";
68	args.nargs = 3;
69	args.nret = 1;
70	args.ihandle = handle;
71	args.addr = ptr;
72	args.len = nb;
73	args.actual = -1;
74	(*prom)(&args);
75	return args.actual;
76}
77
78void
79exit()
80{
81	struct prom_args {
82		char *service;
83	} args;
84
85	for (;;) {
86		args.service = "exit";
87		(*prom)(&args);
88	}
89}
90
91void
92pause(void)
93{
94	struct prom_args {
95		char *service;
96	} args;
97
98	args.service = "enter";
99	(*prom)(&args);
100}
101
102void *
103finddevice(const char *name)
104{
105	struct prom_args {
106		char *service;
107		int nargs;
108		int nret;
109		const char *devspec;
110		void *phandle;
111	} args;
112
113	args.service = "finddevice";
114	args.nargs = 1;
115	args.nret = 1;
116	args.devspec = name;
117	args.phandle = (void *) -1;
118	(*prom)(&args);
119	return args.phandle;
120}
121
122void *
123claim(unsigned long virt, unsigned long size, unsigned long align)
124{
125	struct prom_args {
126		char *service;
127		int nargs;
128		int nret;
129		unsigned int virt;
130		unsigned int size;
131		unsigned int align;
132		void *ret;
133	} args;
134
135	args.service = "claim";
136	args.nargs = 3;
137	args.nret = 1;
138	args.virt = virt;
139	args.size = size;
140	args.align = align;
141	(*prom)(&args);
142	return args.ret;
143}
144
145int
146getprop(void *phandle, const char *name, void *buf, int buflen)
147{
148	struct prom_args {
149		char *service;
150		int nargs;
151		int nret;
152		void *phandle;
153		const char *name;
154		void *buf;
155		int buflen;
156		int size;
157	} args;
158
159	args.service = "getprop";
160	args.nargs = 4;
161	args.nret = 1;
162	args.phandle = phandle;
163	args.name = name;
164	args.buf = buf;
165	args.buflen = buflen;
166	args.size = -1;
167	(*prom)(&args);
168	return args.size;
169}
170
171int
172putc(int c, void *f)
173{
174	char ch = c;
175
176	if (c == '\n')
177		putc('\r', f);
178	return write(f, &ch, 1) == 1? c: -1;
179}
180
181int
182putchar(int c)
183{
184	return putc(c, stdout);
185}
186
187int
188fputs(char *str, void *f)
189{
190	int n = strlen(str);
191
192	return write(f, str, n) == n? 0: -1;
193}
194
195int
196readchar(void)
197{
198	char ch;
199
200	for (;;) {
201		switch (read(stdin, &ch, 1)) {
202		case 1:
203			return ch;
204		case -1:
205			printk("read(stdin) returned -1\r\n");
206			return -1;
207		}
208	}
209}
210
211static char line[256];
212static char *lineptr;
213static int lineleft;
214
215int
216getchar(void)
217{
218	int c;
219
220	if (lineleft == 0) {
221		lineptr = line;
222		for (;;) {
223			c = readchar();
224			if (c == -1 || c == 4)
225				break;
226			if (c == '\r' || c == '\n') {
227				*lineptr++ = '\n';
228				putchar('\n');
229				break;
230			}
231			switch (c) {
232			case 0177:
233			case '\b':
234				if (lineptr > line) {
235					putchar('\b');
236					putchar(' ');
237					putchar('\b');
238					--lineptr;
239				}
240				break;
241			case 'U' & 0x1F:
242				while (lineptr > line) {
243					putchar('\b');
244					putchar(' ');
245					putchar('\b');
246					--lineptr;
247				}
248				break;
249			default:
250				if (lineptr >= &line[sizeof(line) - 1])
251					putchar('\a');
252				else {
253					putchar(c);
254					*lineptr++ = c;
255				}
256			}
257		}
258		lineleft = lineptr - line;
259		lineptr = line;
260	}
261	if (lineleft == 0)
262		return -1;
263	--lineleft;
264	return *lineptr++;
265}
266
267
268
269/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
270unsigned char _ctype[] = {
271_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
272_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
273_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
274_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
275_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
276_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
277_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
278_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
279_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
280_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
281_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
282_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
283_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
284_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
285_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
286_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
2870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
2880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
289_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
290_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
291_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
292_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
293_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
294_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
295
296size_t strnlen(const char * s, size_t count)
297{
298	const char *sc;
299
300	for (sc = s; count-- && *sc != '\0'; ++sc)
301		/* nothing */;
302	return sc - s;
303}
304
305unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
306{
307	unsigned long result = 0,value;
308
309	if (!base) {
310		base = 10;
311		if (*cp == '0') {
312			base = 8;
313			cp++;
314			if ((*cp == 'x') && isxdigit(cp[1])) {
315				cp++;
316				base = 16;
317			}
318		}
319	}
320	while (isxdigit(*cp) &&
321	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
322		result = result*base + value;
323		cp++;
324	}
325	if (endp)
326		*endp = (char *)cp;
327	return result;
328}
329
330long simple_strtol(const char *cp,char **endp,unsigned int base)
331{
332	if(*cp=='-')
333		return -simple_strtoul(cp+1,endp,base);
334	return simple_strtoul(cp,endp,base);
335}
336
337static int skip_atoi(const char **s)
338{
339	int i=0;
340
341	while (isdigit(**s))
342		i = i*10 + *((*s)++) - '0';
343	return i;
344}
345
346#define ZEROPAD	1		/* pad with zero */
347#define SIGN	2		/* unsigned/signed long */
348#define PLUS	4		/* show plus */
349#define SPACE	8		/* space if plus */
350#define LEFT	16		/* left justified */
351#define SPECIAL	32		/* 0x */
352#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
353
354static char * number(char * str, long long num, int base, int size, int precision, int type)
355{
356	char c,sign,tmp[66];
357	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
358	int i;
359
360	if (type & LARGE)
361		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
362	if (type & LEFT)
363		type &= ~ZEROPAD;
364	if (base < 2 || base > 36)
365		return 0;
366	c = (type & ZEROPAD) ? '0' : ' ';
367	sign = 0;
368	if (type & SIGN) {
369		if (num < 0) {
370			sign = '-';
371			num = -num;
372			size--;
373		} else if (type & PLUS) {
374			sign = '+';
375			size--;
376		} else if (type & SPACE) {
377			sign = ' ';
378			size--;
379		}
380	}
381	if (type & SPECIAL) {
382		if (base == 16)
383			size -= 2;
384		else if (base == 8)
385			size--;
386	}
387	i = 0;
388	if (num == 0)
389		tmp[i++]='0';
390	else while (num != 0)
391		tmp[i++] = digits[do_div(num,base)];
392	if (i > precision)
393		precision = i;
394	size -= precision;
395	if (!(type&(ZEROPAD+LEFT)))
396		while(size-->0)
397			*str++ = ' ';
398	if (sign)
399		*str++ = sign;
400	if (type & SPECIAL) {
401		if (base==8)
402			*str++ = '0';
403		else if (base==16) {
404			*str++ = '0';
405			*str++ = digits[33];
406		}
407	}
408	if (!(type & LEFT))
409		while (size-- > 0)
410			*str++ = c;
411	while (i < precision--)
412		*str++ = '0';
413	while (i-- > 0)
414		*str++ = tmp[i];
415	while (size-- > 0)
416		*str++ = ' ';
417	return str;
418}
419
420/* Forward decl. needed for IP address printing stuff... */
421int sprintf(char * buf, const char *fmt, ...);
422
423int vsprintf(char *buf, const char *fmt, va_list args)
424{
425	int len;
426	unsigned long long num;
427	int i, base;
428	char * str;
429	const char *s;
430
431	int flags;		/* flags to number() */
432
433	int field_width;	/* width of output field */
434	int precision;		/* min. # of digits for integers; max
435				   number of chars for from string */
436	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
437	                        /* 'z' support added 23/7/1999 S.H.    */
438				/* 'z' changed to 'Z' --davidm 1/25/99 */
439
440
441	for (str=buf ; *fmt ; ++fmt) {
442		if (*fmt != '%') {
443			*str++ = *fmt;
444			continue;
445		}
446
447		/* process flags */
448		flags = 0;
449		repeat:
450			++fmt;		/* this also skips first '%' */
451			switch (*fmt) {
452				case '-': flags |= LEFT; goto repeat;
453				case '+': flags |= PLUS; goto repeat;
454				case ' ': flags |= SPACE; goto repeat;
455				case '#': flags |= SPECIAL; goto repeat;
456				case '0': flags |= ZEROPAD; goto repeat;
457				}
458
459		/* get field width */
460		field_width = -1;
461		if (isdigit(*fmt))
462			field_width = skip_atoi(&fmt);
463		else if (*fmt == '*') {
464			++fmt;
465			/* it's the next argument */
466			field_width = va_arg(args, int);
467			if (field_width < 0) {
468				field_width = -field_width;
469				flags |= LEFT;
470			}
471		}
472
473		/* get the precision */
474		precision = -1;
475		if (*fmt == '.') {
476			++fmt;
477			if (isdigit(*fmt))
478				precision = skip_atoi(&fmt);
479			else if (*fmt == '*') {
480				++fmt;
481				/* it's the next argument */
482				precision = va_arg(args, int);
483			}
484			if (precision < 0)
485				precision = 0;
486		}
487
488		/* get the conversion qualifier */
489		qualifier = -1;
490		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
491			qualifier = *fmt;
492			++fmt;
493		}
494
495		/* default base */
496		base = 10;
497
498		switch (*fmt) {
499		case 'c':
500			if (!(flags & LEFT))
501				while (--field_width > 0)
502					*str++ = ' ';
503			*str++ = (unsigned char) va_arg(args, int);
504			while (--field_width > 0)
505				*str++ = ' ';
506			continue;
507
508		case 's':
509			s = va_arg(args, char *);
510			if (!s)
511				s = "<NULL>";
512
513			len = strnlen(s, precision);
514
515			if (!(flags & LEFT))
516				while (len < field_width--)
517					*str++ = ' ';
518			for (i = 0; i < len; ++i)
519				*str++ = *s++;
520			while (len < field_width--)
521				*str++ = ' ';
522			continue;
523
524		case 'p':
525			if (field_width == -1) {
526				field_width = 2*sizeof(void *);
527				flags |= ZEROPAD;
528			}
529			str = number(str,
530				(unsigned long) va_arg(args, void *), 16,
531				field_width, precision, flags);
532			continue;
533
534
535		case 'n':
536			if (qualifier == 'l') {
537				long * ip = va_arg(args, long *);
538				*ip = (str - buf);
539			} else if (qualifier == 'Z') {
540				size_t * ip = va_arg(args, size_t *);
541				*ip = (str - buf);
542			} else {
543				int * ip = va_arg(args, int *);
544				*ip = (str - buf);
545			}
546			continue;
547
548		case '%':
549			*str++ = '%';
550			continue;
551
552		/* integer number formats - set up the flags and "break" */
553		case 'o':
554			base = 8;
555			break;
556
557		case 'X':
558			flags |= LARGE;
559		case 'x':
560			base = 16;
561			break;
562
563		case 'd':
564		case 'i':
565			flags |= SIGN;
566		case 'u':
567			break;
568
569		default:
570			*str++ = '%';
571			if (*fmt)
572				*str++ = *fmt;
573			else
574				--fmt;
575			continue;
576		}
577		if (qualifier == 'L')
578			num = va_arg(args, long long);
579		else if (qualifier == 'l') {
580			num = va_arg(args, unsigned long);
581			if (flags & SIGN)
582				num = (signed long) num;
583		} else if (qualifier == 'Z') {
584			num = va_arg(args, size_t);
585		} else if (qualifier == 'h') {
586			num = (unsigned short) va_arg(args, int);
587			if (flags & SIGN)
588				num = (signed short) num;
589		} else {
590			num = va_arg(args, unsigned int);
591			if (flags & SIGN)
592				num = (signed int) num;
593		}
594		str = number(str, num, base, field_width, precision, flags);
595	}
596	*str = '\0';
597	return str-buf;
598}
599
600int sprintf(char * buf, const char *fmt, ...)
601{
602	va_list args;
603	int i;
604
605	va_start(args, fmt);
606	i=vsprintf(buf,fmt,args);
607	va_end(args);
608	return i;
609}
610
611static char sprint_buf[1024];
612
613void
614printk(char *fmt, ...)
615{
616	va_list args;
617	int n;
618
619	va_start(args, fmt);
620	n = vsprintf(sprint_buf, fmt, args);
621	va_end(args);
622	write(stdout, sprint_buf, n);
623}
624
625int
626printf(char *fmt, ...)
627{
628	va_list args;
629	int n;
630
631	va_start(args, fmt);
632	n = vsprintf(sprint_buf, fmt, args);
633	va_end(args);
634	write(stdout, sprint_buf, n);
635	return n;
636}
637