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