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