1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  simple printf				File: lib_printf.c
5    *
6    *  Author:  Mitch Lichtenberg
7    *
8    *  This module contains a very, very, very simple printf
9    *  suitable for use in the boot ROM.
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48#include <stdarg.h>
49#include "lib_types.h"
50#include "lib_printf.h"
51#include "cpu_config.h"	/* for CPUCFG_REGS32, evil hack! */
52
53/*  *********************************************************************
54    *  Externs								*
55    ********************************************************************* */
56
57/*  *********************************************************************
58    *  Globals								*
59    ********************************************************************* */
60
61static const char digits[17] = "0123456789ABCDEF";
62static const char ldigits[17] = "0123456789abcdef";
63
64int (*xprinthook)(const char *str) = NULL;
65
66/*  *********************************************************************
67    *  __atox(buf,num,radix,width)
68    *
69    *  Convert a number to a string
70    *
71    *  Input Parameters:
72    *      buf - where to put characters
73    *      num - number to convert
74    *      radix - radix to convert number to (usually 10 or 16)
75    *      width - width in characters
76    *
77    *  Return Value:
78    *      number of digits placed in output buffer
79    ********************************************************************* */
80static int __atox(char *buf,unsigned int num,unsigned int radix,int width,
81		     const char *digits)
82{
83    char buffer[16];
84    char *op;
85    int retval;
86
87    op = &buffer[0];
88    retval = 0;
89
90    do {
91	*op++ = digits[num % radix];
92	retval++;
93	num /= radix;
94	} while (num != 0);
95
96    if (width && (width > retval)) {
97	width = width - retval;
98	while (width) {
99	    *op++ = '0';
100	    retval++;
101	    width--;
102	    }
103	}
104
105    while (op != buffer) {
106	op--;
107	*buf++ = *op;
108	}
109
110    return retval;
111}
112
113
114/*  *********************************************************************
115    *  __llatox(buf,num,radix,width)
116    *
117    *  Convert a long number to a string
118    *
119    *  Input Parameters:
120    *      buf - where to put characters
121    *      num - number to convert
122    *      radix - radix to convert number to (usually 10 or 16)
123    *      width - width in characters
124    *
125    *  Return Value:
126    *      number of digits placed in output buffer
127    ********************************************************************* */
128static int __llatox(char *buf,unsigned long long num,unsigned int radix,
129		    int width,const char *digits)
130{
131    char buffer[16];
132    char *op;
133    int retval;
134
135    op = &buffer[0];
136    retval = 0;
137
138#if CPUCFG_REGS32
139    /*
140     * Hack: to avoid pulling in the helper library that isn't necessarily
141     * compatible with PIC code, force radix to 16, use shifts and masks
142     */
143    do {
144	*op++ = digits[num & 0x0F];
145	retval++;
146	num >>= 4;
147	} while (num != 0);
148#else
149    do {
150	*op++ = digits[num % radix];
151	retval++;
152	num /= radix;
153	} while (num != 0);
154#endif
155
156    if (width && (width > retval)) {
157	width = width - retval;
158	while (width) {
159	    *op++ = '0';
160	    retval++;
161	    width--;
162	    }
163	}
164
165    while (op != buffer) {
166	op--;
167	*buf++ = *op;
168	}
169
170    return retval;
171}
172
173/*  *********************************************************************
174    *  xvsprintf(outbuf,template,arglist)
175    *
176    *  Format a string into the output buffer
177    *
178    *  Input Parameters:
179    *	   outbuf - output buffer
180    *      template - template string
181    *      arglist - parameters
182    *
183    *  Return Value:
184    *      number of characters copied
185    ********************************************************************* */
186#define isdigit(x) (((x) >= '0') && ((x) <= '9'))
187int xvsprintf(char *outbuf,const char *templat,va_list marker)
188{
189    char *optr;
190    const char *iptr;
191    unsigned char *tmpptr;
192    long x;
193    unsigned long ux;
194    unsigned long long ulx;
195    int i;
196    long long ll;
197    int leadingzero;
198    int leadingnegsign;
199    int islong;
200    int width;
201    int width2 = 0;
202    int hashash = 0;
203
204    optr = outbuf;
205    iptr = templat;
206
207    while (*iptr) {
208	if (*iptr != '%') {*optr++ = *iptr++; continue;}
209
210	iptr++;
211
212	if (*iptr == '#') { hashash = 1; iptr++; }
213	if (*iptr == '-') {
214	    leadingnegsign = 1;
215	    iptr++;
216	    }
217	else leadingnegsign = 0;
218
219	if (*iptr == '0') leadingzero = 1;
220	else leadingzero = 0;
221
222	width = 0;
223	while (*iptr && isdigit(*iptr)) {
224	    width += (*iptr - '0');
225	    iptr++;
226	    if (isdigit(*iptr)) width *= 10;
227	    }
228	if (*iptr == '.') {
229	    iptr++;
230	    width2 = 0;
231	    while (*iptr && isdigit(*iptr)) {
232		width2 += (*iptr - '0');
233		iptr++;
234		if (isdigit(*iptr)) width2 *= 10;
235		}
236	    }
237
238	islong = 0;
239	if (*iptr == 'l') { islong++; iptr++; }
240	if (*iptr == 'l') { islong++; iptr++; }
241
242	switch (*iptr) {
243	    case 'I':
244		tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
245		optr += __atox(optr,*tmpptr++,10,0,digits);
246		*optr++ = '.';
247		optr += __atox(optr,*tmpptr++,10,0,digits);
248		*optr++ = '.';
249		optr += __atox(optr,*tmpptr++,10,0,digits);
250		*optr++ = '.';
251		optr += __atox(optr,*tmpptr++,10,0,digits);
252		break;
253	    case 's':
254		tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
255		if (!tmpptr) tmpptr = (unsigned char *) "(null)";
256		if ((width == 0) & (width2 == 0)) {
257		    while (*tmpptr) *optr++ = *tmpptr++;
258		    break;
259		    }
260		while (width && *tmpptr) {
261		    *optr++ = *tmpptr++;
262		    width--;
263		    }
264		while (width) {
265		    *optr++ = ' ';
266		    width--;
267		    }
268		break;
269	    case 'a':
270		tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
271		for (x = 0; x < 5; x++) {
272		    optr += __atox(optr,*tmpptr++,16,2,digits);
273		    *optr++ = '-';
274		    }
275		optr += __atox(optr,*tmpptr++,16,2,digits);
276		break;
277	    case 'd':
278		switch (islong) {
279		    case 0:
280		    case 1:
281			i = va_arg(marker,int);
282			if (i < 0) { *optr++='-'; i = -i;}
283			optr += __atox(optr,i,10,width,digits);
284			break;
285		    case 2:
286			ll = va_arg(marker,long long int);
287			if (ll < 0) { *optr++='-'; ll = -ll;}
288			optr += __llatox(optr,ll,10,width,digits);
289			break;
290		    }
291		break;
292	    case 'u':
293		switch (islong) {
294		    case 0:
295		    case 1:
296			ux = va_arg(marker,unsigned int);
297			optr += __atox(optr,ux,10,width,digits);
298			break;
299		    case 2:
300			ulx = va_arg(marker,unsigned long long);
301			optr += __llatox(optr,ulx,10,width,digits);
302			break;
303		    }
304		break;
305	    case 'X':
306	    case 'x':
307		switch (islong) {
308		    case 0:
309		    case 1:
310			ux = va_arg(marker,unsigned int);
311			optr += __atox(optr,ux,16,width,
312				       (*iptr == 'X') ? digits : ldigits);
313			break;
314		    case 2:
315			ulx = va_arg(marker,unsigned long long);
316			optr += __llatox(optr,ulx,16,width,
317				       (*iptr == 'X') ? digits : ldigits);
318			break;
319		    }
320		break;
321	    case 'p':
322	    case 'P':
323#ifdef __long64
324		lx = va_arg(marker,long long);
325		optr += __llatox(optr,lx,16,16,
326				 (*iptr == 'P') ? digits : ldigits);
327#else
328		x = va_arg(marker,long);
329		optr += __atox(optr,x,16,8,
330			       (*iptr == 'P') ? digits : ldigits);
331#endif
332		break;
333	    case 'w':
334		x = va_arg(marker,unsigned int);
335	        x &= 0x0000FFFF;
336		optr += __atox(optr,x,16,4,digits);
337		break;
338	    case 'b':
339		x = va_arg(marker,unsigned int);
340	        x &= 0x0000FF;
341		optr += __atox(optr,x,16,2,digits);
342		break;
343	    case 'Z':
344		x = va_arg(marker,unsigned int);
345		tmpptr = va_arg(marker,unsigned char *);
346		while (x) {
347		    optr += __atox(optr,*tmpptr++,16,2,digits);
348		    x--;
349		    }
350		break;
351	    case 'c':
352		x = va_arg(marker, int);
353		*optr++ = x & 0xff;
354		break;
355
356	    default:
357		*optr++ = *iptr;
358		break;
359	    }
360	iptr++;
361	}
362
363    *optr = '\0';
364
365    return (optr - outbuf);
366}
367
368
369/*  *********************************************************************
370    *  xsprintf(buf,template,params..)
371    *
372    *  format messages from template into a buffer.
373    *
374    *  Input Parameters:
375    *      buf - output buffer
376    *      template - template string
377    *      params... parameters
378    *
379    *  Return Value:
380    *      number of bytes copied to buffer
381    ********************************************************************* */
382int xsprintf(char *buf,const char *templat,...)
383{
384    va_list marker;
385    int count;
386
387    va_start(marker,templat);
388    count = xvsprintf(buf,templat,marker);
389    va_end(marker);
390
391    return count;
392}
393
394/*  *********************************************************************
395    *  xprintf(template,...)
396    *
397    *  A miniature printf.
398    *
399    *      %a - Ethernet address (16 bytes)
400    *      %s - unpacked string, null terminated
401    *      %x - hex word (machine size)
402    *      %w - hex word (16 bits)
403    *      %b - hex byte (8 bits)
404    *      %Z - buffer (put length first, then buffer address)
405    *
406    *  Return value:
407    *  	   number of bytes written
408    ********************************************************************* */
409
410int xprintf(const char *templat,...)
411{
412    va_list marker;
413    int count;
414    char buffer[512];
415
416    va_start(marker,templat);
417    count = xvsprintf(buffer,templat,marker);
418    va_end(marker);
419
420    if (xprinthook) (*xprinthook)(buffer);
421
422    return count;
423}
424
425
426int xvprintf(const char *templat,va_list marker)
427{
428    int count;
429    char buffer[512];
430
431    count = xvsprintf(buffer,templat,marker);
432
433    if (xprinthook) (*xprinthook)(buffer);
434
435    return count;
436}
437
438
439
440
441
442
443
444
445