Add claim/release runtime debug output
[yaboot.git] / second / prom.c
index cd12279c7d413ee32d2c4b90de8a96c4d4653fcf..119d0f363cabbc971f259b6e6f4c61b27cbbaf4c 100644 (file)
@@ -1,25 +1,27 @@
 /*
-    Routines for talking to the Open Firmware PROM on
-    Power Macintosh computers.
-    Copyright (C) 1999 Benjamin Herrenschmidt
-    Copyright (C) 1999 Marius Vollmer
-    Copyright (C) 1996 Paul Mackerras.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
+ *  prom.c - Routines for talking to the Open Firmware PROM
+ *
+ *  Copyright (C) 2001, 2002 Ethan Benson
+ *
+ *  Copyright (C) 1999 Benjamin Herrenschmidt
+ *
+ *  Copyright (C) 1999 Marius Vollmer
+ *
+ *  Copyright (C) 1996 Paul Mackerras.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include "prom.h"
 #include "ctype.h"
 #include "asm/processor.h"
 #include "errors.h"
+#include "debug.h"
+#include "string.h"
 
 #define READ_BLOCKS_USE_READ   1
 
+static int yaboot_debug;
+
 prom_entry prom;
 
 ihandle prom_stdin, prom_stdout;
 
-//extern int vsprintf(char *buf, const char *fmt, va_list args);
-
 static ihandle prom_mem, prom_mmu;
 static ihandle prom_chosen, prom_options;
 
 struct prom_args {
-       const char *service;
-       int nargs;
-       int nret;
-       void *args[10];
+     const char *service;
+     int nargs;
+     int nret;
+     void *args[10];
 };
 
 void *
 call_prom (const char *service, int nargs, int nret, ...)
 {
-  va_list list;
-  int i;
-  struct prom_args prom_args;
-  
-  prom_args.service = service;
-  prom_args.nargs = nargs;
-  prom_args.nret = nret;
-  va_start (list, nret);
-  for (i = 0; i < nargs; ++i)
-    prom_args.args[i] = va_arg(list, void *);
-  va_end(list);
-  for (i = 0; i < nret; ++i)
-    prom_args.args[i + nargs] = 0;
-  prom (&prom_args);
-  if (nret > 0)
-    return prom_args.args[nargs];
-  else
-    return 0;
+     va_list list;
+     int i;
+     struct prom_args prom_args;
+
+     prom_args.service = service;
+     prom_args.nargs = nargs;
+     prom_args.nret = nret;
+     va_start (list, nret);
+     for (i = 0; i < nargs; ++i)
+         prom_args.args[i] = va_arg(list, void *);
+     va_end(list);
+     for (i = 0; i < nret; ++i)
+         prom_args.args[i + nargs] = 0;
+     prom (&prom_args);
+     if (nret > 0)
+         return prom_args.args[nargs];
+     else
+         return 0;
 }
 
 void *
 call_prom_return (const char *service, int nargs, int nret, ...)
 {
-  va_list list;
-  int i;
-  void* result;
-  struct prom_args prom_args;
-  
-  prom_args.service = service;
-  prom_args.nargs = nargs;
-  prom_args.nret = nret;
-  va_start (list, nret);
-  for (i = 0; i < nargs; ++i)
-    prom_args.args[i] = va_arg(list, void *);
-  for (i = 0; i < nret; ++i)
-    prom_args.args[i + nargs] = 0;
-  if (prom (&prom_args) != 0)
-       return PROM_INVALID_HANDLE;
-  if (nret > 0) {
-    result = prom_args.args[nargs];
-    for (i=1; i<nret; i++) {
-       void** rp = va_arg(list, void**);
-       *rp = prom_args.args[i+nargs];
-    }
-  } else
-    result = 0;
-  va_end(list);
-  return result;
+     va_list list;
+     int i;
+     void* result;
+     struct prom_args prom_args;
+
+     prom_args.service = service;
+     prom_args.nargs = nargs;
+     prom_args.nret = nret;
+     va_start (list, nret);
+     for (i = 0; i < nargs; ++i)
+         prom_args.args[i] = va_arg(list, void *);
+     for (i = 0; i < nret; ++i)
+         prom_args.args[i + nargs] = 0;
+     if (prom (&prom_args) != 0)
+         return PROM_INVALID_HANDLE;
+     if (nret > 0) {
+         result = prom_args.args[nargs];
+         for (i=1; i<nret; i++) {
+              void** rp = va_arg(list, void**);
+              *rp = prom_args.args[i+nargs];
+         }
+     } else
+         result = 0;
+     va_end(list);
+     return result;
 }
 
 static void *
 call_method_1 (char *method, prom_handle h, int nargs, ...)
 {
-  va_list list;
-  int i;
-  struct prom_args prom_args;
-  
-  prom_args.service = "call-method";
-  prom_args.nargs = nargs+2;
-  prom_args.nret = 2;
-  prom_args.args[0] = method;
-  prom_args.args[1] = h;
-  va_start (list, nargs);
-  for (i = 0; i < nargs; ++i)
-    prom_args.args[2+i] = va_arg(list, void *);
-  va_end(list);
-  prom_args.args[2+nargs] = 0;
-  prom_args.args[2+nargs+1] = 0;
-  
-  prom (&prom_args);
-
-  if (prom_args.args[2+nargs] != 0)
-    {
-      prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
-      return 0;
-    }
-  return prom_args.args[2+nargs+1];
+     va_list list;
+     int i;
+     struct prom_args prom_args;
+
+     prom_args.service = "call-method";
+     prom_args.nargs = nargs+2;
+     prom_args.nret = 2;
+     prom_args.args[0] = method;
+     prom_args.args[1] = h;
+     va_start (list, nargs);
+     for (i = 0; i < nargs; ++i)
+         prom_args.args[2+i] = va_arg(list, void *);
+     va_end(list);
+     prom_args.args[2+nargs] = 0;
+     prom_args.args[2+nargs+1] = 0;
+
+     prom (&prom_args);
+
+     if (prom_args.args[2+nargs] != 0)
+     {
+         prom_printf ("method '%s' failed %p\n", method, prom_args.args[2+nargs]);
+         return 0;
+     }
+     return prom_args.args[2+nargs+1];
 }
 
 
 prom_handle
 prom_finddevice (char *name)
 {
-  return call_prom ("finddevice", 1, 1, name);
+     return call_prom ("finddevice", 1, 1, name);
 }
 
 prom_handle
 prom_findpackage(char *path)
 {
-  return call_prom ("find-package", 1, 1, path);
+     return call_prom ("find-package", 1, 1, path);
 }
 
 int
 prom_getprop (prom_handle pack, char *name, void *mem, int len)
 {
-  return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
+     return (int)call_prom ("getprop", 4, 1, pack, name, mem, len);
+}
+
+int
+prom_getproplen(prom_handle pack, const char *name)
+{
+     return (int)call_prom("getproplen", 2, 1, pack, name);
+}
+
+int
+prom_setprop (prom_handle pack, char *name, void *mem, int len)
+{
+     return (int)call_prom ("setprop", 4, 1, pack, name, mem, len);
 }
 
 int
 prom_get_chosen (char *name, void *mem, int len)
 {
-  return prom_getprop (prom_chosen, name, mem, len);
+     return prom_getprop (prom_chosen, name, mem, len);
 }
 
 int
 prom_get_options (char *name, void *mem, int len)
 {
-  if (prom_options == (void *)-1)
-    return -1;
-  return prom_getprop (prom_options, name, mem, len);
+     if (prom_options == (void *)-1)
+         return -1;
+     return prom_getprop (prom_options, name, mem, len);
+}
+
+int
+prom_set_options (char *name, void *mem, int len)
+{
+     if (prom_options == (void *)-1)
+         return -1;
+     return prom_setprop (prom_options, name, mem, len);
+}
+
+int
+prom_get_devtype (char *device)
+{
+     phandle    dev;
+     int        result;
+     char       tmp[64];
+
+     if (strstr(device, TOK_ISCSI))
+         device = strcpy(tmp, "/vdevice/gscsi/disk");
+
+     /* Find OF device phandle */
+     dev = prom_finddevice(device);
+     if (dev == PROM_INVALID_HANDLE) {
+         return FILE_ERR_BADDEV;
+     }
+
+     /* Check the kind of device */
+     result = prom_getprop(dev, "device_type", tmp, 63);
+     if (result == -1) {
+         prom_printf("can't get <device_type> for device: %s\n", device);
+         return FILE_ERR_BADDEV;
+     }
+     tmp[result] = 0;
+     if (!strcmp(tmp, "block"))
+         return FILE_DEVICE_BLOCK;
+     else if (!strcmp(tmp, "network"))
+         return FILE_DEVICE_NET;
+     else {
+         prom_printf("Unkown device type <%s>\n", tmp);
+         return FILE_ERR_BADDEV;
+     }
 }
 
 void
 prom_init (prom_entry pp)
 {
-  prom = pp;
-
-  prom_chosen = prom_finddevice ("/chosen");
-  if (prom_chosen == (void *)-1)
-    prom_exit ();
-  prom_options = prom_finddevice ("/options");
-  if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
-    prom_exit();
-  if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0)
-    prom_abort ("\nCan't open stdin");
-  if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0)
-    prom_abort ("\nCan't get mem handle");
-  if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0)
-    prom_abort ("\nCan't get mmu handle");
+     prom = pp;
+
+     prom_chosen = prom_finddevice ("/chosen");
+     if (prom_chosen == (void *)-1)
+         prom_exit ();
+     prom_options = prom_finddevice ("/options");
+     if (prom_get_chosen ("stdout", &prom_stdout, sizeof(prom_stdout)) <= 0)
+         prom_exit();
+     if (prom_get_chosen ("stdin", &prom_stdin, sizeof(prom_stdin)) <= 0)
+         prom_abort ("\nCan't open stdin");
+     if (prom_get_chosen ("memory", &prom_mem, sizeof(prom_mem)) <= 0)
+         prom_abort ("\nCan't get mem handle");
+     if (prom_get_chosen ("mmu", &prom_mmu, sizeof(prom_mmu)) <= 0)
+         prom_abort ("\nCan't get mmu handle");
+
+     yaboot_debug = 0;
+     prom_get_options("linux,yaboot-debug", &yaboot_debug, sizeof(yaboot_debug));
 
   // move cursor to fresh line
-  prom_printf ("\n");
+     prom_printf ("\n");
 
-  /* Add a few OF methods (thanks Darwin) */
+     /* Add a few OF methods (thanks Darwin) */
 #if DEBUG
-  prom_printf ("Adding OF methods...\n");
-#endif  
-
-  prom_interpret (
-       /* All values in this forth code are in hex */
-       "hex "  
-       /* Those are a few utilities ripped from Apple */
-       ": D2NIP decode-int nip nip ;\r"        // A useful function to save space
-       ": GPP$ get-package-property 0= ;\r"    // Another useful function to save space
-       ": ^on0 0= if -1 throw then ;\r"        // Bail if result zero
-       ": $CM $call-method ;\r"
-  );
-
-  /* Some forth words used by the release method */
-  prom_interpret (
-       " \" /chosen\" find-package if "
-               "dup \" memory\" rot GPP$ if "
-                       "D2NIP swap "                            // ( MEMORY-ihandle "/chosen"-phandle )
-                       "\" mmu\" rot GPP$ if "
-                               "D2NIP "                                 // ( MEMORY-ihandle MMU-ihandle )
-                       "else "
-                               "0 "                                     // ( MEMORY-ihandle 0 )
-                       "then "
-               "else "
-                       "0 0 "                                           // ( 0 0 )
-               "then "
-       "else "
-               "0 0 "                                                   // ( 0 0 )
-       "then\r"
-       "value mmu# "
-       "value mem# "
-  );
-
-  prom_interpret (
-       ": ^mem mem# $CM ; "
-       ": ^mmu mmu# $CM ; "
-  );
+     prom_printf ("Adding OF methods...\n");
+#endif
 
-#if DEBUG
-  prom_printf ("OF interface initialized.\n");
-#endif  
+     prom_interpret (
+         /* All values in this forth code are in hex */
+         "hex "
+         /* Those are a few utilities ripped from Apple */
+         ": D2NIP decode-int nip nip ;\r"      // A useful function to save space
+         ": GPP$ get-package-property 0= ;\r"  // Another useful function to save space
+         ": ^on0 0= if -1 throw then ;\r"      // Bail if result zero
+         ": $CM $call-method ;\r"
+         );
+
+     /* Some forth words used by the release method */
+     prom_interpret (
+         " \" /chosen\" find-package if "
+                "dup \" memory\" rot GPP$ if "
+                        "D2NIP swap "                           // ( MEMORY-ihandle "/chosen"-phandle )
+                        "\" mmu\" rot GPP$ if "
+                                "D2NIP "                                // ( MEMORY-ihandle MMU-ihandle )
+                        "else "
+                                "0 "                                    // ( MEMORY-ihandle 0 )
+                        "then "
+                "else "
+                        "0 0 "                                          // ( 0 0 )
+                "then "
+         "else "
+                "0 0 "                                                  // ( 0 0 )
+         "then\r"
+         "value mmu# "
+         "value mem# "
+         );
+
+     prom_interpret (
+         ": ^mem mem# $CM ; "
+         ": ^mmu mmu# $CM ; "
+         );
+
+     DEBUG_F("OF interface initialized.\n");
 }
 
 prom_handle
 prom_open (char *spec)
 {
-  return call_prom ("open", 1, 1, spec, strlen(spec));
+     return call_prom ("open", 1, 1, spec, strlen(spec));
 }
 
 void
 prom_close (prom_handle file)
 {
-  call_prom ("close", 1, 0, file);
+     call_prom ("close", 1, 0, file);
 }
 
 int
 prom_read (prom_handle file, void *buf, int n)
 {
-  int result = 0;
-  int retries = 10;
-  
-  if (n == 0)
-       return 0;
-  while(--retries) {
-       result = (int)call_prom ("read", 3, 1, file, buf, n);
-       if (result != 0)
-           break;
-       call_prom("interpret", 1, 1, " 10 ms");
-  }
-  
-  return result;
+     int result = 0;
+     int retries = 10;
+
+     if (n == 0)
+         return 0;
+     while(--retries) {
+         result = (int)call_prom ("read", 3, 1, file, buf, n);
+         if (result != 0)
+              break;
+         call_prom("interpret", 1, 1, " 10 ms");
+     }
+
+     return result;
 }
 
 int
 prom_write (prom_handle file, void *buf, int n)
 {
-  return (int)call_prom ("write", 3, 1, file, buf, n);
+     return (int)call_prom ("write", 3, 1, file, buf, n);
 }
 
 int
 prom_seek (prom_handle file, int pos)
 {
-  int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
-  return status == 0 || status == 1;
+     int status = (int)call_prom ("seek", 3, 1, file, 0, pos);
+     return status == 0 || status == 1;
 }
 
 int
 prom_lseek (prom_handle file, unsigned long long pos)
 {
-  int status = (int)call_prom ("seek", 3, 1, file,
-       (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL));
-  return status == 0 || status == 1;
+     int status = (int)call_prom ("seek", 3, 1, file,
+                                 (unsigned int)(pos >> 32), (unsigned int)(pos & 0xffffffffUL));
+     return status == 0 || status == 1;
 }
 
 int
 prom_loadmethod (prom_handle device, void* addr)
 {
-  return (int)call_method_1 ("load", device, 1, addr);
+     return (int)call_method_1 ("load", device, 1, addr);
 }
 
 int
 prom_getblksize (prom_handle file)
 {
-  return (int)call_method_1 ("block-size", file, 0);
+     return (int)call_method_1 ("block-size", file, 0);
 }
 
 int
 prom_readblocks (prom_handle dev, int blockNum, int blockCount, void *buffer)
 {
 #if READ_BLOCKS_USE_READ
-  int status;
-  unsigned int blksize;
-  
-  blksize = prom_getblksize(dev);
-  if (blksize <= 1)
-       blksize = 512;
-  status = prom_seek(dev, blockNum * blksize);
-  if (status != 1) {
-       return 0;
-       prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
-  }
-       
-  status = prom_read(dev, buffer, blockCount * blksize);
+     int status;
+     unsigned int blksize;
+
+     blksize = prom_getblksize(dev);
+     if (blksize <= 1)
+         blksize = 512;
+     status = prom_seek(dev, blockNum * blksize);
+     if (status != 1) {
+         return 0;
+         prom_printf("Can't seek to 0x%x\n", blockNum * blksize);
+     }
+
+     status = prom_read(dev, buffer, blockCount * blksize);
 //  prom_printf("prom_readblocks, bl: %d, cnt: %d, status: %d\n",
 //     blockNum, blockCount, status);
 
-  return status == (blockCount * blksize);
-#else 
-  int result;
-  int retries = 10;
-  
-  if (blockCount == 0)
-       return blockCount;
-  while(--retries) {
-       result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
-       if (result != 0)
-           break;
-       call_prom("interpret", 1, 1, " 10 ms");
-  }
-  
-  return result;
-#endif  
+     return status == (blockCount * blksize);
+#else
+     int result;
+     int retries = 10;
+
+     if (blockCount == 0)
+         return blockCount;
+     while(--retries) {
+         result = call_method_1 ("read-blocks", dev, 3, buffer, blockNum, blockCount);
+         if (result != 0)
+              break;
+         call_prom("interpret", 1, 1, " 10 ms");
+     }
+
+     return result;
+#endif
 }
 
 int
 prom_getchar ()
 {
-  char c[4];
-  int a;
+     char c;
+     int a;
 
-  while ((a = (int)call_prom ("read", 3, 1, prom_stdin, c, 4)) == 0)
-    ;
-  if (a == -1)
-    prom_abort ("EOF on console\n");
-  if (a == 3 && c[0] == '\e' && c[1] == '[')
-    return 0x100 | c[2];
-  return c[0];
+     while ((a = (int)call_prom ("read", 3, 1, prom_stdin, &c, 1)) == 0)
+         ;
+     if (a == -1)
+         prom_abort ("EOF on console\n");
+     return c;
 }
 
 int
 prom_nbgetchar()
 {
-    char ch;
+     char ch;
 
-    return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
+     return (int) call_prom("read", 3, 1, prom_stdin, &ch, 1) > 0? ch: -1;
 }
 
 void
 prom_putchar (char c)
 {
-  if (c == '\n')
-    call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
-  else
-    call_prom ("write", 3, 1, prom_stdout, &c, 1);
+     if (c == '\n')
+         call_prom ("write", 3, 1, prom_stdout, "\r\n", 2);
+     else
+         call_prom ("write", 3, 1, prom_stdout, &c, 1);
 }
 
 void
 prom_puts (prom_handle file, char *s)
 {
-  const char *p, *q;
-
-  for (p = s; *p != 0; p = q) 
-    {
-      for (q = p; *q != 0 && *q != '\n'; ++q)
-       ;
-      if (q > p)
-       call_prom ("write", 3, 1, file, p, q - p);
-      if (*q != 0) 
-       {
-         ++q;
-         call_prom ("write", 3, 1, file, "\r\n", 2);
-       }
-    }
-}
+     const char *p, *q;
+
+     for (p = s; *p != 0; p = q)
+     {
+         for (q = p; *q != 0 && *q != '\n'; ++q)
+              ;
+         if (q > p)
+              call_prom ("write", 3, 1, file, p, q - p);
+         if (*q != 0)
+         {
+              ++q;
+              call_prom ("write", 3, 1, file, "\r\n", 2);
+         }
+     }
+}
+
 void
 prom_vfprintf (prom_handle file, char *fmt, va_list ap)
 {
-  static char printf_buf[1536];
-  vsprintf (printf_buf, fmt, ap);
-  prom_puts (file, printf_buf);
+     static char printf_buf[2048];
+     vsprintf (printf_buf, fmt, ap);
+     prom_puts (file, printf_buf);
 }
 
 void
 prom_vprintf (char *fmt, va_list ap)
 {
-  static char printf_buf[1536];
-  vsprintf (printf_buf, fmt, ap);
-  prom_puts (prom_stdout, printf_buf);
+     static char printf_buf[2048];
+     vsprintf (printf_buf, fmt, ap);
+     prom_puts (prom_stdout, printf_buf);
 }
 
 void
 prom_fprintf (prom_handle file, char *fmt, ...)
 {
-  va_list ap;
-  va_start (ap, fmt);
-  prom_vfprintf (file, fmt, ap);
-  va_end (ap);
+     va_list ap;
+     va_start (ap, fmt);
+     prom_vfprintf (file, fmt, ap);
+     va_end (ap);
 }
 
 void
 prom_printf (char *fmt, ...)
 {
-  va_list ap;
-  va_start (ap, fmt);
-  prom_vfprintf (prom_stdout, fmt, ap);
-  va_end (ap);
+     va_list ap;
+     va_start (ap, fmt);
+     prom_vfprintf (prom_stdout, fmt, ap);
+     va_end (ap);
+}
+
+void
+prom_debug (char *fmt, ...)
+{
+     va_list ap;
+
+     if (!yaboot_debug)
+          return;
+
+     va_start (ap, fmt);
+     prom_vfprintf (prom_stdout, fmt, ap);
+     va_end (ap);
 }
 
 void
@@ -428,7 +497,7 @@ prom_perror (int error, char *filename)
      else if (error == FILE_IOERR)
          prom_printf("%s: Input/output error\n", filename);
      else if (error == FILE_BAD_PATH)
-         prom_printf("%s: Path too long\n", filename); 
+         prom_printf("%s: Path too long\n", filename);
      else if (error == FILE_ERR_BAD_TYPE)
          prom_printf("%s: Not a regular file\n", filename);
      else if (error == FILE_ERR_NOTDIR)
@@ -450,59 +519,57 @@ prom_perror (int error, char *filename)
 void
 prom_readline (char *prompt, char *buf, int len)
 {
-  int i = 0;
-  int c;
-
-  if (prompt)
-    prom_puts (prom_stdout, prompt);
-
-  while (i < len-1 && (c = prom_getchar ()) != '\r')
-    {
-      if (c >= 0x100)
-       continue;
-      if (c == 8)
-       {
-         if (i > 0)
-           {
-             prom_puts (prom_stdout, "\b \b");
-             i--;
-           }
+     int i = 0;
+     int c;
+
+     if (prompt)
+         prom_puts (prom_stdout, prompt);
+
+     while (i < len-1 && (c = prom_getchar ()) != '\r')
+     {
+         if (c == 8)
+         {
+              if (i > 0)
+              {
+                   prom_puts (prom_stdout, "\b \b");
+                   i--;
+              }
+              else
+                   prom_putchar ('\a');
+         }
+         else if (isprint (c))
+         {
+              prom_putchar (c);
+              buf[i++] = c;
+         }
          else
-           prom_putchar ('\a');
-       }
-      else if (isprint (c))
-       {
-         prom_putchar (c);
-         buf[i++] = c;
-       }
-      else
-       prom_putchar ('\a');
-    }
-  prom_putchar ('\n');
-  buf[i] = 0;
+              prom_putchar ('\a');
+     }
+     prom_putchar ('\n');
+     buf[i] = 0;
 }
 
 #ifdef CONFIG_SET_COLORMAP
 int prom_set_color(prom_handle device, int color, int r, int g, int b)
 {
-  return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
+     return (int)call_prom( "call-method", 6, 1, "color!", device, color, b, g, r );
 }
 #endif /* CONFIG_SET_COLORMAP */
 
 void
 prom_exit ()
 {
-  call_prom ("exit", 0, 0);
+     call_prom ("exit", 0, 0);
 }
 
 void
 prom_abort (char *fmt, ...)
 {
-  va_list ap;
-  va_start (ap, fmt);
-  prom_vfprintf (prom_stdout, fmt, ap);
-  va_end (ap);
-  prom_exit ();
+     va_list ap;
+     va_start (ap, fmt);
+     prom_vfprintf (prom_stdout, fmt, ap);
+     va_end (ap);
+     prom_exit ();
 }
 
 void
@@ -513,87 +580,270 @@ prom_sleep (int seconds)
      while (prom_getms() <= end);
 }
 
+/* if address given is claimed look for other addresses to get the needed
+ * space before giving up
+ */
+void *
+prom_claim_chunk(void *virt, unsigned int size, unsigned int align)
+{
+     void *found, *addr;
+     for(addr=virt; addr <= (void*)PROM_CLAIM_MAX_ADDR;
+         addr+=(0x100000/sizeof(addr))) {
+          found = call_prom("claim", 3, 1, addr, size, 0);
+          if (found != (void *)-1) {
+               prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)addr, (int)found);
+               return(found);
+          }
+     }
+     prom_printf("ERROR: claim of 0x%x in range 0x%x-0x%x failed\n", size, (int)virt, PROM_CLAIM_MAX_ADDR);
+     return((void*)-1);
+}
+
 void *
 prom_claim (void *virt, unsigned int size, unsigned int align)
 {
-  return call_prom ("claim", 3, 1, virt, size, align);
+     void *ret;
+
+     ret = call_prom ("claim", 3, 1, virt, size, align);
+     if (ret == (void *)-1)
+          prom_printf("ERROR: claim of 0x%x at 0x%x failed\n", size, (int)virt);
+     else
+          prom_debug("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
+
+     return ret;
 }
 
 void
 prom_release(void *virt, unsigned int size)
 {
-//  call_prom ("release", 2, 1, virt, size);
-  /* release in not enough, it needs also an unmap call. This bit of forth
-   * code inspired from Darwin's bootloader but could be replaced by direct
-   * calls to the MMU package if needed
-   */
-  call_prom ("interpret", 3, 1,
-#if DEBUG
-               ".\" ReleaseMem:\" 2dup . . cr "
-#endif
-               "over \" translate\" ^mmu "             // Find out physical base
-               "^on0 "                                 // Bail if translation failed
-               "drop "                                 // Leaving phys on top of stack
-               "2dup \" unmap\" ^mmu "                 // Unmap the space first
-               "2dup \" release\" ^mmu "               // Then free the virtual pages
-               "\" release\" ^mem "                    // Then free the physical pages
-               ,size, virt 
-       );
+     void *ret;
+
+     ret = call_prom ("release", 2, 0, virt, size);
+     prom_debug("release of 0x%x at 0x%x returned 0x%x\n", size, (int)virt, (int)ret);
 }
 
 void
 prom_map (void *phys, void *virt, int size)
 {
-  unsigned long msr = mfmsr();
+     unsigned long msr = mfmsr();
 
-  /* Only create a mapping if we're running with relocation enabled. */
-  if ( (msr & MSR_IR) && (msr & MSR_DR) )
-    call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
+     /* Only create a mapping if we're running with relocation enabled. */
+     if ( (msr & MSR_IR) && (msr & MSR_DR) )
+         call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
 }
 
 void
 prom_unmap (void *phys, void *virt, int size)
 {
-  unsigned long msr = mfmsr();
+     unsigned long msr = mfmsr();
 
-  /* Only unmap if we're running with relocation enabled. */
-  if ( (msr & MSR_IR) && (msr & MSR_DR) )
-    call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
+     /* Only unmap if we're running with relocation enabled. */
+     if ( (msr & MSR_IR) && (msr & MSR_DR) )
+         call_method_1 ("map", prom_mmu, 4, -1, size, virt, phys);
 }
 
 char *
 prom_getargs ()
 {
-  static char args[256];
-  int l;
+     static char args[256];
+     int l;
 
-  l = prom_get_chosen ("bootargs", args, 255);
-  args[l] = '\0';
-  return args;
+     l = prom_get_chosen ("bootargs", args, 255);
+     args[l] = '\0';
+     return args;
 }
 
 void
 prom_setargs (char *args)
 {
-  int l = strlen (args)+1;
-  if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
-    prom_printf ("can't set args\n");
+     int l = strlen (args)+1;
+     if ((int)call_prom ("setprop", 4, 1, prom_chosen, "bootargs", args, l) != l)
+         prom_printf ("can't set args\n");
 }
 
 int prom_interpret (char *forth)
 {
-  return (int)call_prom("interpret", 1, 1, forth);
+     return (int)call_prom("interpret", 1, 1, forth);
 }
 
 int
 prom_getms(void)
 {
-    return (int) call_prom("milliseconds", 0, 1);
+     return (int) call_prom("milliseconds", 0, 1);
 }
 
 void
 prom_pause(void)
 {
-    call_prom("enter", 0, 0);
+     prom_print_available();
+     call_prom("enter", 0, 0);
+}
+
+/*
+ * prom_get_netinfo()
+ * returns the packet with all needed info for netboot
+ */
+struct bootp_packet * prom_get_netinfo (void)
+{
+     void *bootp_response = NULL;
+     char *propname;
+     struct bootp_packet *packet;
+     /* struct bootp_packet contains a VLA, so sizeof won't work.
+        the VLA /must/ be the last field in the structure so use it's
+        offset as a good estimate of the packet size */
+     size_t packet_size = offsetof(struct bootp_packet, options);
+     int i = 0, size, offset = 0;
+     prom_handle chosen;
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+     chosen = prom_finddevice("/chosen");
+     if (chosen < 0) {
+          DEBUG_F("chosen=%d\n", chosen);
+      return 0;
+     }
+
+     for (i = 0; i < ARRAY_SIZE(bootp_response_properties); i++) {
+         propname = bootp_response_properties[i].name;
+         size = prom_getproplen(chosen, propname);
+         if (size <= 0)
+             continue;
+
+         DEBUG_F("using /chosen/%s\n", propname);
+         offset = bootp_response_properties[i].offset;
+         break;
+     }
+
+     if (size <= 0)
+         return NULL;
+
+     if (packet_size > size - offset) {
+         prom_printf("Malformed %s property?\n", propname);
+         return NULL;
+     }
+
+     bootp_response = malloc(size);
+     if (!bootp_response)
+         return NULL;
+
+     if (prom_getprop(chosen, propname, bootp_response, size) < 0)
+         return NULL;
+
+     packet = bootp_response + offset;
+     return packet;
 }
 
+/*
+ * prom_get_mac()
+ * returns the mac addr of an net card
+ */
+char * prom_get_mac (struct bootp_packet * packet)
+{
+     char * conf_path;
+     int i;
+
+     if (!packet)
+        return NULL;
+
+     /* 3 chars per byte in chaddr + \0 */
+     conf_path = malloc(packet->hlen * 3 + 1);
+     if (!conf_path)
+         return NULL;
+     sprintf(conf_path, "%02x", packet->chaddr[0]);
+
+     for (i = 1; i < packet->hlen; i++) {
+      char tmp[4];
+      sprintf(tmp, "-%02x", packet->chaddr[i]);
+      strcat(conf_path, tmp);
+     }
+
+     return conf_path;
+}
+
+/*
+ * prom_get_ip()
+ * returns the ip addr of an net card
+ */
+char * prom_get_ip (struct bootp_packet * packet)
+{
+     char * conf_path;
+
+     if (!packet)
+        return NULL;
+
+     /* 8 chars in yiaddr + \0 */
+     conf_path = malloc(9);
+     if (!conf_path)
+         return NULL;
+     sprintf(conf_path, "%08x", packet->yiaddr);
+
+     return conf_path;
+}
+
+/* We call this too early to use malloc, 128 cells should be large enough */
+#define NR_AVAILABLE 128
+
+void prom_print_available(void)
+{
+     prom_handle root;
+     unsigned int addr_cells, size_cells;
+     ihandle mem;
+     unsigned int available[NR_AVAILABLE];
+     unsigned int len;
+     unsigned int *p;
+
+     if (!yaboot_debug)
+          return;
+
+     root = prom_finddevice("/");
+     if (!root)
+          return;
+
+     addr_cells = 2;
+     prom_getprop(root, "#address-cells", &addr_cells, sizeof(addr_cells));
+
+     size_cells = 1;
+     prom_getprop(root, "#size-cells", &size_cells, sizeof(size_cells));
+
+     mem = prom_finddevice("/memory@0");
+     if (mem == PROM_INVALID_HANDLE)
+          return;
+
+     len = prom_getprop(mem, "available", available, sizeof(available));
+     if (len == -1)
+          return;
+     len /= 4;
+
+     prom_printf("\nAvailable memory ranges:\n");
+
+     p = available;
+     while (len > 0) {
+          unsigned int addr, size;
+
+          /*
+           * Since we are in 32bit mode it should be safe to only print the
+           * bottom 32bits of each range.
+           */
+          p += (addr_cells - 1);
+          addr = *p;
+          p++;
+
+          p += (size_cells - 1);
+          size = *p;
+          p++;
+
+          if (size)
+               prom_printf("0x%08x-0x%08x (%3d MB)\n", addr, addr + size,
+                           size/1024/1024);
+
+          len -= (addr_cells + size_cells);
+     }
+
+     prom_printf("\n");
+}
+
+/*
+ * Local variables:
+ * c-file-style: "k&r"
+ * c-basic-offset: 5
+ * End:
+ */