]> git.sur5r.net Git - u-boot/commitdiff
API for external applications.
authorRafal Jaworowski <raj@semihalf.com>
Wed, 9 Jan 2008 18:39:36 +0000 (19:39 +0100)
committerRafal Jaworowski <raj@semihalf.com>
Wed, 9 Jan 2008 18:39:36 +0000 (19:39 +0100)
This is an API for external (standalone) applications running on top of
U-Boot, and is meant to be more extensible and robust than the existing
jumptable mechanism. It is similar to UNIX syscall approach. See api/README
for more details.

Included is the demo application using this new framework (api_examples).

Please note this is still an experimental feature, and is turned off by
default.

Signed-off-by: Rafal Jaworowski <raj@semihalf.com>
18 files changed:
Makefile
api/Makefile [new file with mode: 0644]
api/README [new file with mode: 0644]
api/api.c [new file with mode: 0644]
api/api_net.c [new file with mode: 0644]
api/api_platform-arm.c [new file with mode: 0644]
api/api_platform-ppc.c [new file with mode: 0644]
api/api_private.h [new file with mode: 0644]
api/api_storage.c [new file with mode: 0644]
api_examples/Makefile [new file with mode: 0644]
api_examples/crt0.S [new file with mode: 0644]
api_examples/demo.c [new file with mode: 0644]
api_examples/glue.c [new file with mode: 0644]
api_examples/glue.h [new file with mode: 0644]
api_examples/libgenwrap.c [new file with mode: 0644]
include/api_public.h [new file with mode: 0644]
include/common.h
lib_ppc/board.c

index 47db5b7212b4f9f9bec56dba68f9ad273bb645f7..0e94875122490c3d71cdf67c1a992c74ca4ac75d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -243,6 +243,9 @@ LIBS += $(shell if [ -d post/board/$(BOARDDIR) ]; then echo \
        "post/board/$(BOARDDIR)/libpost$(BOARD).a"; fi)
 LIBS += common/libcommon.a
 LIBS += libfdt/libfdt.a
+ifeq ($(CONFIG_API),y)
+LIBS += api/libapi.a
+endif
 
 LIBS := $(addprefix $(obj),$(LIBS))
 .PHONY : $(LIBS)
@@ -255,6 +258,10 @@ PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -
 SUBDIRS        = tools \
          examples
 
+ifeq ($(CONFIG_API),y)
+SUBDIRS += api_examples
+endif
+
 .PHONY : $(SUBDIRS)
 
 ifeq ($(CONFIG_NAND_U_BOOT),y)
@@ -2749,6 +2756,7 @@ clean:
        rm -f $(obj)board/bf537-stamp/u-boot.lds $(obj)board/bf561-ezkit/u-boot.lds
        rm -f $(obj)include/bmp_logo.h
        rm -f $(obj)nand_spl/u-boot-spl $(obj)nand_spl/u-boot-spl.map
+       rm -f $(obj)api_examples/demo
 
 clobber:       clean
        find $(OBJTREE) -type f \( -name .depend \
@@ -2762,6 +2770,8 @@ clobber:  clean
        rm -f $(obj)tools/inca-swap-bytes $(obj)cpu/mpc824x/bedbug_603e.c
        rm -f $(obj)include/asm/proc $(obj)include/asm/arch $(obj)include/asm
        [ ! -d $(OBJTREE)/nand_spl ] || find $(obj)nand_spl -lname "*" -print | xargs rm -f
+       find $(obj)api_examples -lname "*" -print | xargs rm -f
+       rm -f $(obj)api_examples/demo
 
 ifeq ($(OBJTREE),$(SRCTREE))
 mrproper \
diff --git a/api/Makefile b/api/Makefile
new file mode 100644 (file)
index 0000000..94de3dc
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# (C) Copyright 2007 Semihalf
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 Foundatio; 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 $(TOPDIR)/config.mk
+
+LIB    = $(obj)libapi.a
+
+COBJS  = api.o api_net.o api_storage.o api_platform-$(ARCH).o
+
+SRCS   := $(COBJS:.o=.c)
+OBJS   := $(addprefix $(obj),$(COBJS))
+
+all:   $(LIB)
+
+$(LIB):        $(obj).depend $(OBJS)
+       $(AR) $(ARFLAGS) $@ $(OBJS)
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/api/README b/api/README
new file mode 100644 (file)
index 0000000..c8f9c45
--- /dev/null
@@ -0,0 +1,55 @@
+U-Boot machine/arch independent API for external apps
+=====================================================
+
+1.  Main assumptions
+
+  - there is a single entry point (syscall) to the API
+
+  - per current design the syscall is a C-callable function in the U-Boot
+    text, which might evolve into a real syscall using machine exception trap
+    once this initial version proves functional
+
+  - the consumer app is responsible for producing appropriate context (call
+    number and arguments)
+
+  - upon entry, the syscall dispatches the call to other (existing) U-Boot
+    functional areas like networking or storage operations
+
+  - consumer application will recognize the API is available by searching
+    a specified (assumed by convention) range of address space for the
+    signature
+
+  - the U-Boot integral part of the API is meant to be thin and non-intrusive,
+    leaving as much processing as possible on the consumer application side,
+    for example it doesn't keep states, but relies on hints from the app and
+    so on 
+
+  - optional (CONFIG_API)
+
+
+2. Calls
+
+  - console related (getc, putc, tstc etc.)
+  - system (reset, platform info)
+  - time (delay, current)
+  - env vars (enumerate all, get, set)
+  - devices (enumerate all, open, close, read, write); currently two classes
+    of devices are recognized and supported: network and storage (ide, scsi,
+    usb etc.)
+
+
+3. Structure overview
+
+  - core API, integral part of U-Boot, mandatory
+    - implements the single entry point (mimics UNIX syscall)
+
+  - glue
+    - entry point at the consumer side, allows to make syscall, mandatory
+      part
+
+    - helper conveniency wrappers so that consumer app does not have to use
+      the syscall directly, but in a more friendly manner (a la libc calls),
+      optional part
+
+  - consumer application
+    - calls directly, or leverages the provided glue mid-layer
diff --git a/api/api.c b/api/api.c
new file mode 100644 (file)
index 0000000..10f83eb
--- /dev/null
+++ b/api/api.c
@@ -0,0 +1,670 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <config.h>
+
+#if defined(CONFIG_API)
+
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "api_private.h"
+
+#define DEBUG
+#undef DEBUG
+
+/* U-Boot routines needed */
+extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern uchar (*env_get_char)(int);
+extern uchar *env_get_addr(int);
+
+/*****************************************************************************
+ *
+ * This is the API core.
+ *
+ * API_ functions are part of U-Boot code and constitute the lowest level
+ * calls:
+ *
+ *  - they know what values they need as arguments
+ *  - their direct return value pertains to the API_ "shell" itself (0 on
+ *    success, some error code otherwise)
+ *  - if the call returns a value it is buried within arguments
+ *
+ ****************************************************************************/
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+typedef        int (*cfp_t)(va_list argp);
+
+static int calls_no;
+
+/*
+ * pseudo signature:
+ *
+ * int API_getc(int *c)
+ */
+static int API_getc(va_list ap)
+{
+       int *c;
+
+       if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       *c = getc();
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_tstc(int *c)
+ */
+static int API_tstc(va_list ap)
+{
+       int *t;
+
+       if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       *t = tstc();
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_putc(char *ch)
+ */
+static int API_putc(va_list ap)
+{
+       char *c;
+
+       if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       putc(*c);
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_puts(char **s)
+ */
+static int API_puts(va_list ap)
+{
+       char *s;
+
+       if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       puts(s);
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_reset(void)
+ */
+static int API_reset(va_list ap)
+{
+       do_reset(NULL, 0, 0, NULL);
+
+       /* NOT REACHED */
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_get_sys_info(struct sys_info *si)
+ *
+ * fill out the sys_info struct containing selected parameters about the
+ * machine
+ */
+static int API_get_sys_info(va_list ap)
+{
+       struct sys_info *si;
+
+       si = (struct sys_info *)va_arg(ap, u_int32_t);
+       if (si == NULL)
+               return API_ENOMEM;
+
+       return (platform_sys_info(si)) ? 0 : API_ENODEV;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_udelay(unsigned long *udelay)
+ */
+static int API_udelay(va_list ap)
+{
+       unsigned long *d;
+
+       if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       udelay(*d);
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_get_timer(unsigned long *current, unsigned long *base)
+ */
+static int API_get_timer(va_list ap)
+{
+       unsigned long *base, *cur;
+
+       cur = (unsigned long *)va_arg(ap, u_int32_t);
+       if (cur == NULL)
+               return API_EINVAL;
+
+       base = (unsigned long *)va_arg(ap, u_int32_t);
+       if (base == NULL)
+               return API_EINVAL;
+
+       *cur = get_timer(*base);
+       return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * pseudo signature:
+ *
+ * int API_dev_enum(struct device_info *)
+ *
+ *
+ * cookies uniqely identify the previously enumerated device instance and
+ * provide a hint for what to inspect in current enum iteration:
+ *
+ *   - net: &eth_device struct address from list pointed to by eth_devices
+ *
+ *   - storage: block_dev_desc_t struct address from &ide_dev_desc[n],
+ *     &scsi_dev_desc[n] and similar tables
+ *
+ ****************************************************************************/
+
+static int API_dev_enum(va_list ap)
+{
+       struct device_info *di;
+
+       /* arg is ptr to the device_info struct we are going to fill out */
+       di = (struct device_info *)va_arg(ap, u_int32_t);
+       if (di == NULL)
+               return API_EINVAL;
+
+       if (di->cookie == NULL) {
+               /* start over - clean up enumeration */
+               dev_enum_reset();       /* XXX shouldn't the name contain 'stor'? */
+               debugf("RESTART ENUM\n");
+               
+               /* net device enumeration first */
+               if (dev_enum_net(di))
+                       return 0;
+       }
+
+       /*
+        * The hidden assumption is there can only be one active network
+        * device and it is identified upon enumeration (re)start, so there's
+        * no point in trying to find network devices in other cases than the
+        * (re)start and hence the 'next' device can only be storage
+        */
+       if (!dev_enum_storage(di))
+               /* make sure we mark there are no more devices */
+               di->cookie = NULL;
+
+       return 0;
+}
+
+
+static int API_dev_open(va_list ap)
+{
+       struct device_info *di;
+       int err = 0;
+
+       /* arg is ptr to the device_info struct */
+       di = (struct device_info *)va_arg(ap, u_int32_t);
+       if (di == NULL)
+               return API_EINVAL;
+
+       /* Allow only one consumer of the device at a time */
+       if (di->state == DEV_STA_OPEN)
+               return API_EBUSY;
+
+       if (di->cookie == NULL)
+               return API_ENODEV;
+
+       if (di->type & DEV_TYP_STOR)
+               err = dev_open_stor(di->cookie);
+
+       else if (di->type & DEV_TYP_NET)
+               err = dev_open_net(di->cookie);
+       else
+               err = API_ENODEV;
+
+       if (!err)
+               di->state = DEV_STA_OPEN;
+
+       return err;
+}
+
+
+static int API_dev_close(va_list ap)
+{
+       struct device_info *di;
+       int err = 0;
+
+       /* arg is ptr to the device_info struct */
+       di = (struct device_info *)va_arg(ap, u_int32_t);
+       if (di == NULL)
+               return API_EINVAL;
+
+       if (di->state == DEV_STA_CLOSED)
+               return 0;
+
+       if (di->cookie == NULL)
+               return API_ENODEV;
+
+       if (di->type & DEV_TYP_STOR)
+               err = dev_close_stor(di->cookie);
+
+       else if (di->type & DEV_TYP_NET)
+               err = dev_close_net(di->cookie);
+       else
+               /*
+                * In case of unknown device we cannot change its state, so
+                * only return error code
+                */
+               err = API_ENODEV;
+
+       if (!err)
+               di->state = DEV_STA_CLOSED;
+
+       return err;
+}
+
+
+/*
+ * Notice: this is for sending network packets only, as U-Boot does not
+ * support writing to storage at the moment (12.2007)
+ *
+ * pseudo signature:
+ *
+ * int API_dev_write(
+ *     struct device_info *di,
+ *     void *buf,
+ *     int *len
+ * )
+ *
+ * buf:        ptr to buffer from where to get the data to send
+ *
+ * len: length of packet to be sent (in bytes)
+ *
+ */
+static int API_dev_write(va_list ap)
+{
+       struct device_info *di;
+       void *buf;
+       int *len;
+       int err = 0;
+
+       /* 1. arg is ptr to the device_info struct */
+       di = (struct device_info *)va_arg(ap, u_int32_t);
+       if (di == NULL)
+               return API_EINVAL;
+
+       /* XXX should we check if device is open? i.e. the ->state ? */
+
+       if (di->cookie == NULL)
+               return API_ENODEV;
+
+       /* 2. arg is ptr to buffer from where to get data to write */
+       buf = (void *)va_arg(ap, u_int32_t);
+       if (buf == NULL)
+               return API_EINVAL;
+
+       /* 3. arg is length of buffer */
+       len = (int *)va_arg(ap, u_int32_t);
+       if (len == NULL)
+               return API_EINVAL;
+       if (*len <= 0)
+               return API_EINVAL;
+
+       if (di->type & DEV_TYP_STOR)
+               /* 
+                * write to storage is currently not supported by U-Boot:
+                * no storage device implements block_write() method
+                */
+               return API_ENODEV;
+
+       else if (di->type & DEV_TYP_NET)
+               err = dev_write_net(di->cookie, buf, *len);
+       else
+               err = API_ENODEV;
+
+       return err;
+}
+
+
+/*
+ * pseudo signature:
+ *
+ * int API_dev_read(
+ *     struct device_info *di,
+ *     void *buf,
+ *     size_t *len,
+ *     unsigned long *start
+ *     size_t *act_len
+ * )
+ *
+ * buf:        ptr to buffer where to put the read data
+ *
+ * len: ptr to length to be read
+ *      - network: len of packet to read (in bytes)
+ *      - storage: # of blocks to read (can vary in size depending on define)
+ *
+ * start: ptr to start block (only used for storage devices, ignored for
+ *        network)
+ *
+ * act_len: ptr to where to put the len actually read
+ */
+static int API_dev_read(va_list ap)
+{
+       struct device_info *di;
+       void *buf;
+       lbasize_t *len_stor, *act_len_stor;
+       lbastart_t *start;
+       int *len_net, *act_len_net;
+
+       /* 1. arg is ptr to the device_info struct */
+       di = (struct device_info *)va_arg(ap, u_int32_t);
+       if (di == NULL)
+               return API_EINVAL;
+
+       /* XXX should we check if device is open? i.e. the ->state ? */
+
+       if (di->cookie == NULL)
+               return API_ENODEV;
+
+       /* 2. arg is ptr to buffer from where to put the read data */
+       buf = (void *)va_arg(ap, u_int32_t);
+       if (buf == NULL)
+               return API_EINVAL;
+
+       if (di->type & DEV_TYP_STOR) {
+               /* 3. arg - ptr to var with # of blocks to read */
+               len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+               if (!len_stor)
+                       return API_EINVAL;
+               if (*len_stor <= 0)
+                       return API_EINVAL;
+
+               /* 4. arg - ptr to var with start block */
+               start = (lbastart_t *)va_arg(ap, u_int32_t);
+
+               /* 5. arg - ptr to var where to put the len actually read */
+               act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+               if (!act_len_stor)
+                       return API_EINVAL;
+
+               *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
+
+       } else if (di->type & DEV_TYP_NET) {
+
+               /* 3. arg points to the var with length of packet to read */
+               len_net = (int *)va_arg(ap, u_int32_t);
+               if (!len_net)
+                       return API_EINVAL;
+               if (*len_net <= 0)
+                       return API_EINVAL;
+
+               /* 4. - ptr to var where to put the len actually read */
+               act_len_net = (int *)va_arg(ap, u_int32_t);
+               if (!act_len_net)
+                       return API_EINVAL;
+
+               *act_len_net = dev_read_net(di->cookie, buf, *len_net);
+
+       } else
+               return API_ENODEV;
+
+       return 0;
+}
+
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_get(const char *name, char **value)
+ *
+ * name: ptr to name of env var
+ */
+static int API_env_get(va_list ap)
+{
+       char *name, **value;
+
+       if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+       if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       *value = getenv(name);
+
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_set(const char *name, const char *value)
+ *
+ * name: ptr to name of env var
+ *
+ * value: ptr to value to be set
+ */
+static int API_env_set(va_list ap)
+{
+       char *name, *value;
+
+       if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+       if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       setenv(name, value);
+
+       return 0;
+}
+
+/*
+ * pseudo signature:
+ *
+ * int API_env_enum(const char *last, char **next)
+ *
+ * last: ptr to name of env var found in last iteration
+ */
+static int API_env_enum(va_list ap)
+{
+       int i, n;
+       char *last, **next;
+
+       last = (char *)va_arg(ap, u_int32_t);
+       
+       if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
+               return API_EINVAL;
+
+       if (last == NULL)
+               /* start over */
+               *next = ((char *)env_get_addr(0));
+       else {
+               *next = last;
+
+               for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
+                       for (n = i; env_get_char(n) != '\0'; ++n) {
+                               if (n >= CFG_ENV_SIZE) {
+                                       /* XXX shouldn't we set *next = NULL?? */
+                                       return 0;
+                               }
+                       }
+               
+                       if (envmatch((uchar *)last, i) < 0)
+                               continue;
+
+                       /* try to get next name */
+                       i = n + 1;
+                       if (env_get_char(i) == '\0') {
+                               /* no more left */
+                               *next = NULL;
+                               return 0;
+                       }
+
+                       *next = ((char *)env_get_addr(i));
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+static cfp_t calls_table[API_MAXCALL] = { NULL, };
+
+/*
+ * The main syscall entry point - this is not reentrant, only one call is
+ * serviced until finished.
+ *
+ * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
+ * 
+ * call:       syscall number
+ *
+ * retval:     points to the return value placeholder, this is the place the
+ *             syscall puts its return value, if NULL the caller does not
+ *             expect a return value
+ *
+ * ...         syscall arguments (variable number)
+ *
+ * returns:    0 if the call not found, 1 if serviced
+ */
+int syscall(int call, int *retval, ...)
+{
+       va_list ap;
+       int rv;
+
+       if (call < 0 || call >= calls_no || calls_table[call] == NULL) {
+               debugf("invalid call #%d\n", call);
+               return 0;
+       }
+
+       if (calls_table[call] == NULL) {
+               debugf("syscall #%d does not have a handler\n", call);
+               return 0;
+       }
+
+       va_start(ap, retval);
+       rv = calls_table[call](ap);
+       if (retval != NULL)
+               *retval = rv;
+
+       return 1;
+}
+
+void api_init(void)
+{
+       struct api_signature *sig = NULL;
+
+       /* TODO put this into linker set one day... */
+       calls_table[API_RSVD] = NULL;
+       calls_table[API_GETC] = &API_getc;
+       calls_table[API_PUTC] = &API_putc;
+       calls_table[API_TSTC] = &API_tstc;
+       calls_table[API_PUTS] = &API_puts;
+       calls_table[API_RESET] = &API_reset;
+       calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
+       calls_table[API_UDELAY] = &API_udelay;
+       calls_table[API_GET_TIMER] = &API_get_timer;
+       calls_table[API_DEV_ENUM] = &API_dev_enum;
+       calls_table[API_DEV_OPEN] = &API_dev_open;
+       calls_table[API_DEV_CLOSE] = &API_dev_close;
+       calls_table[API_DEV_READ] = &API_dev_read;
+       calls_table[API_DEV_WRITE] = &API_dev_write;
+       calls_table[API_ENV_GET] = &API_env_get;
+       calls_table[API_ENV_SET] = &API_env_set;
+       calls_table[API_ENV_ENUM] = &API_env_enum;
+       calls_no = API_MAXCALL;
+
+       debugf("API initialized with %d calls\n", calls_no);
+
+       dev_stor_init();
+
+       /*
+        * Produce the signature so the API consumers can find it
+        */
+       sig = malloc(sizeof(struct api_signature));
+       if (sig == NULL) {
+               printf("API: could not allocate memory for the signature!\n");
+               return;
+       }
+
+       debugf("API sig @ 0x%08x\n", sig);
+       memcpy(sig->magic, API_SIG_MAGIC, 8);
+       sig->version = API_SIG_VERSION;
+       sig->syscall = &syscall;
+       sig->checksum = 0;
+       sig->checksum = crc32(0, (unsigned char *)sig,
+                             sizeof(struct api_signature));
+       debugf("syscall entry: 0x%08x\n", sig->syscall);
+}
+
+void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
+                       int flags)
+{
+       int i;
+
+       if (!si->mr || !size || (flags == 0))
+               return;
+       
+       /* find free slot */
+       for (i = 0; i < si->mr_no; i++)
+               if (si->mr[i].flags == 0) {
+                       /* insert new mem region */
+                       si->mr[i].start = start;
+                       si->mr[i].size = size;
+                       si->mr[i].flags = flags;
+                       return;
+               }
+}
+
+#endif /* CONFIG_API */
diff --git a/api/api_net.c b/api/api_net.c
new file mode 100644 (file)
index 0000000..9b20a17
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <config.h>
+
+#if defined(CONFIG_API)
+
+#include <common.h>
+#include <net.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DEBUG
+#undef DEBUG
+
+#if !defined(CONFIG_NET_MULTI)
+#error "API/net is currently only available for platforms with CONFIG_NET_MULTI"
+#endif
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+
+static int dev_valid_net(void *cookie)
+{
+       return ((void *)eth_get_dev() == cookie) ? 1 : 0;
+}
+
+int dev_open_net(void *cookie)
+{
+       if (!dev_valid_net(cookie))
+               return API_ENODEV;
+
+       if (eth_init(gd->bd) < 0)
+               return API_EIO;
+
+       return 0;
+}
+
+int dev_close_net(void *cookie)
+{
+       if (!dev_valid_net(cookie))
+               return API_ENODEV;
+
+       eth_halt();
+       return 0;
+}
+
+/* 
+ * There can only be one active eth interface at a time - use what is
+ * currently set to eth_current
+ */
+int dev_enum_net(struct device_info *di)
+{
+       struct eth_device *eth_current = eth_get_dev();
+
+       di->type = DEV_TYP_NET;
+       di->cookie = (void *)eth_current;
+       if (di->cookie == NULL)
+               return 0;
+
+       memcpy(di->di_net.hwaddr, eth_current->enetaddr, 6);
+
+       debugf("device found, returning cookie 0x%08x\n",
+               (u_int32_t)di->cookie);
+
+       return 1;
+}
+
+int dev_write_net(void *cookie, void *buf, int len)
+{
+       /* XXX verify that cookie points to a valid net device??? */
+
+       return eth_send(buf, len);
+}
+
+int dev_read_net(void *cookie, void *buf, int len)
+{
+       /* XXX verify that cookie points to a valid net device??? */
+
+       return eth_receive(buf, len);
+}
+
+#endif /* CONFIG_API */
diff --git a/api/api_platform-arm.c b/api/api_platform-arm.c
new file mode 100644 (file)
index 0000000..ca15ca5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ *
+ * This file contains routines that fetch data from ARM-dependent sources
+ * (bd_info etc.)
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <linux/types.h>
+#include <api_public.h>
+
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#include "api_private.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Important notice: handling of individual fields MUST be kept in sync with
+ * include/asm-arm/u-boot.h and include/asm-arm/global_data.h, so any changes
+ * need to reflect their current state and layout of structures involved!
+ */
+int platform_sys_info(struct sys_info *si)
+{
+       int i;
+
+       for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
+               platform_set_mr(si, gd->bd->bi_dram[i].start,
+                               gd->bd->bi_dram[i].size, MR_ATTR_DRAM);
+
+       return 1;
+}
+
+#endif /* CONFIG_API */
diff --git a/api/api_platform-ppc.c b/api/api_platform-ppc.c
new file mode 100644 (file)
index 0000000..ca9f9a5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ *
+ * This file contains routines that fetch data from PowerPC-dependent sources
+ * (bd_info etc.)
+ *
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_API)
+
+#include <linux/types.h>
+#include <api_public.h>
+
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#include "api_private.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Important notice: handling of individual fields MUST be kept in sync with
+ * include/asm-ppc/u-boot.h and include/asm-ppc/global_data.h, so any changes
+ * need to reflect their current state and layout of structures involved!
+ */
+int platform_sys_info(struct sys_info *si)
+{
+       si->clk_bus = gd->bus_clk;
+       si->clk_cpu = gd->cpu_clk;
+
+#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) || \
+    defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define bi_bar bi_immr_base
+#elif defined(CONFIG_MPC5xxx)
+#define bi_bar bi_mbar_base
+#elif defined(CONFIG_MPC83XX)
+#define bi_bar bi_immrbar
+#elif defined(CONFIG_MPC8220)
+#define bi_bar bi_mbar_base
+#endif
+
+#if defined(bi_bar)
+       si->bar = gd->bd->bi_bar;
+#undef bi_bar
+#else
+       si->bar = NULL;
+#endif
+
+       platform_set_mr(si, gd->bd->bi_memstart, gd->bd->bi_memsize, MR_ATTR_DRAM);
+       platform_set_mr(si, gd->bd->bi_flashstart, gd->bd->bi_flashsize, MR_ATTR_FLASH);
+       platform_set_mr(si, gd->bd->bi_sramstart, gd->bd->bi_sramsize, MR_ATTR_SRAM);
+
+       return 1;
+}
+
+#endif /* CONFIG_API */
diff --git a/api/api_private.h b/api/api_private.h
new file mode 100644 (file)
index 0000000..94a7fc5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ */
+
+#ifndef _API_PRIVATE_H_
+#define _API_PRIVATE_H_
+
+void   api_init(void);
+void   platform_set_mr(struct sys_info *, unsigned long, unsigned long, int);
+int    platform_sys_info(struct sys_info *);
+
+void   dev_enum_reset(void);
+int    dev_enum_storage(struct device_info *);
+int    dev_enum_net(struct device_info *);
+
+int    dev_open_stor(void *);
+int    dev_open_net(void *);
+int    dev_close_stor(void *);
+int    dev_close_net(void *);
+
+lbasize_t      dev_read_stor(void *, void *, lbasize_t, lbastart_t);
+int            dev_read_net(void *, void *, int);
+int            dev_write_net(void *, void *, int);
+
+void dev_stor_init(void);
+
+#endif /* _API_PRIVATE_H_ */
diff --git a/api/api_storage.c b/api/api_storage.c
new file mode 100644 (file)
index 0000000..7cd4efb
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <config.h>
+
+#if defined(CONFIG_API)
+
+#include <common.h>
+#include <api_public.h>
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+
+#define ENUM_IDE       0
+#define ENUM_USB       1
+#define ENUM_SCSI      2
+#define ENUM_MMC       3
+#define ENUM_MAX       4
+
+struct stor_spec {
+       int             max_dev;
+       int             enum_started;
+       int             enum_ended;
+       int             type;           /* "external" type: DT_STOR_{IDE,USB,etc} */
+       char            name[4];
+};
+
+static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
+
+
+void dev_stor_init(void)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+       specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE;
+       specs[ENUM_IDE].enum_started = 0;
+       specs[ENUM_IDE].enum_ended = 0;
+       specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
+       specs[ENUM_IDE].name = "ide";
+#endif
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+       specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
+       specs[ENUM_USB].enum_started = 0;
+       specs[ENUM_USB].enum_ended = 0;
+       specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
+       specs[ENUM_USB].name = "usb";
+#endif
+#if (CONFIG_COMMANDS & CFG_CMD_SCSI)
+       specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE;
+       specs[ENUM_SCSI].enum_started = 0;
+       specs[ENUM_SCSI].enum_ended = 0;
+       specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
+       specs[ENUM_SCSI].name = "scsi";
+#endif
+}
+
+/*
+ * Finds next available device in the storage group
+ *
+ * type:       storage group type - ENUM_IDE, ENUM_SCSI etc.
+ *
+ * first:      if 1 the first device in the storage group is returned (if
+ *              exists), if 0 the next available device is searched
+ *
+ * more:       returns 0/1 depending if there are more devices in this group
+ *             available (for future iterations)
+ *
+ * returns:    0/1 depending if device found in this iteration
+ */
+static int dev_stor_get(int type, int first, int *more, struct device_info *di)
+{
+       int found = 0;
+       *more = 0;
+
+       int i;
+
+       block_dev_desc_t *dd;
+
+       if (first) {
+               di->cookie = (void *)get_dev(specs[type].name, 0);
+               found = 1;
+
+       } else {
+               for (i = 0; i < specs[type].max_dev; i++)
+                       if (di->cookie == (void *)get_dev(specs[type].name, i)) {
+                               /* previous cookie found -- advance to the
+                                * next device, if possible */
+
+                               if (++i >= specs[type].max_dev) {
+                                       /* out of range, no more to enum */
+                                       di->cookie = NULL;
+                                       break;
+                               }
+
+                               di->cookie = (void *)get_dev(specs[type].name, i);
+                               found = 1;
+
+                               /* provide hint if there are more devices in
+                                * this group to enumerate */
+                               if ((i + 1) < specs[type].max_dev)
+                                       *more = 1;
+
+                               break;
+                       }
+       }
+
+       if (found) {
+               di->type = specs[type].type;
+
+               if (di->cookie != NULL) {
+                       dd = (block_dev_desc_t *)di->cookie;
+                       if (dd->type == DEV_TYPE_UNKNOWN) {
+                               debugf("device instance exists, but is not active..");
+                               found = 0;
+                       } else {
+                               di->di_stor.block_count = dd->lba;
+                               di->di_stor.block_size = dd->blksz;
+                       }
+               }
+
+       } else
+               di->cookie = NULL;
+
+       return found;
+}
+
+
+/*
+ * returns:    ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
+ */
+static int dev_stor_type(block_dev_desc_t *dd)
+{
+       int i, j;
+
+       for (i = ENUM_IDE; i < ENUM_MAX; i++)
+               for (j = 0; j < specs[i].max_dev; j++)
+                       if (dd == get_dev(specs[i].name, j))
+                               return i;
+
+       return ENUM_MAX;
+}
+
+
+/*
+ * returns:    0/1 whether cookie points to some device in this group
+ */
+static int dev_is_stor(int type, struct device_info *di)
+{
+       return (dev_stor_type(di->cookie) == type) ? 1 : 0;
+}
+
+
+static int dev_enum_stor(int type, struct device_info *di)
+{
+       int found = 0, more = 0;
+
+       debugf("called, type %d\n", type);
+
+       /*
+        * Formulae for enumerating storage devices:
+        * 1. if cookie (hint from previous enum call) is NULL we start again
+        *    with enumeration, so return the first available device, done.
+        *
+        * 2. if cookie is not NULL, check if it identifies some device in
+        *    this group:
+        *
+        * 2a. if cookie is a storage device from our group (IDE, USB etc.),
+        *     return next available (if exists) in this group
+        *
+        * 2b. if it isn't device from our group, check if such devices were
+        *     ever enumerated before:
+        *     - if not, return the first available device from this group
+        *     - else return 0
+        */
+
+       if (di->cookie == NULL) {
+
+               debugf("group%d - enum restart\n", type);
+
+               /*
+                * 1. Enumeration (re-)started: take the first available
+                * device, if exists
+                */
+               found = dev_stor_get(type, 1, &more, di);
+               specs[type].enum_started = 1;
+
+       } else if (dev_is_stor(type, di)) {
+
+               debugf("group%d - enum continued for the next device\n", type);
+
+               if (specs[type].enum_ended) {
+                       debugf("group%d - nothing more to enum!\n", type);
+                       return 0;
+               }
+
+               /* 2a. Attempt to take a next available device in the group */
+               found = dev_stor_get(type, 0, &more, di);
+
+       } else {
+
+               if (specs[type].enum_ended) {
+                       debugf("group %d - already enumerated, skipping\n", type);
+                       return 0;
+               }
+
+               debugf("group%d - first time enum\n", type);
+
+               if (specs[type].enum_started == 0) {
+                       /*
+                        * 2b.  If enumerating devices in this group did not
+                        * happen before, it means the cookie pointed to a
+                        * device frome some other group (another storage
+                        * group, or network); in this case try to take the
+                        * first available device from our group
+                        */
+                       specs[type].enum_started = 1;
+
+                       /*
+                        * Attempt to take the first device in this group:
+                        *'first element' flag is set
+                        */
+                       found = dev_stor_get(type, 1, &more, di);
+
+               } else {
+                       errf("group%d - out of order iteration\n", type);
+                       found = 0;
+                       more = 0;
+               }
+       }
+
+       /*
+        * If there are no more devices in this group, consider its
+        * enumeration finished
+        */
+       specs[type].enum_ended = (!more) ? 1 : 0;
+
+       if (found)
+               debugf("device found, returning cookie 0x%08x\n",
+                       (u_int32_t)di->cookie);
+       else
+               debugf("no device found\n");
+
+       return found;
+}
+
+void dev_enum_reset(void)
+{
+       int i;
+
+       for (i = 0; i < ENUM_MAX; i ++) {
+               specs[i].enum_started = 0;
+               specs[i].enum_ended = 0;
+       }
+}
+
+int dev_enum_storage(struct device_info *di)
+{
+       int i;
+
+       /*
+        * check: ide, usb, scsi, mmc
+        */
+       for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
+               if (dev_enum_stor(i, di))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
+{
+       int i;
+
+       for (i = 0; i < specs[type].max_dev; i++)
+               if (dd == get_dev(specs[type].name, i))
+                       if (dd->type != DEV_TYPE_UNKNOWN)
+                               return 1;
+
+       return 0;
+}
+
+
+int dev_open_stor(void *cookie)
+{
+       int type = dev_stor_type(cookie);
+
+       if (type == ENUM_MAX)
+               return API_ENODEV;
+
+       if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
+               return 0;
+
+       return API_ENODEV;
+}
+
+
+int dev_close_stor(void *cookie)
+{
+       /*
+        * Not much to do as we actually do not alter storage devices upon
+        * close
+        */
+       return 0;
+}
+
+
+static int dev_stor_index(block_dev_desc_t *dd)
+{
+       int i, type;
+
+       type = dev_stor_type(dd);
+       for (i = 0; i < specs[type].max_dev; i++)
+               if (dd == get_dev(specs[type].name, i))
+                       return i;
+
+       return (specs[type].max_dev);
+}
+
+
+lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
+{
+       int type;
+       block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
+
+       if ((type = dev_stor_type(dd)) == ENUM_MAX)
+               return 0;
+
+       if (!dev_stor_is_valid(type, dd))
+               return 0;
+
+       if ((dd->block_read) == NULL) {
+               debugf("no block_read() for device 0x%08x\n");
+               return 0;
+       }
+
+       return (dd->block_read(dev_stor_index(dd), start, len, buf));
+}
+
+#endif /* CONFIG_API */
diff --git a/api_examples/Makefile b/api_examples/Makefile
new file mode 100644 (file)
index 0000000..5812bcd
--- /dev/null
@@ -0,0 +1,103 @@
+#
+# (C) Copyright 2007 Semihalf
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 Foundatio; 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
+#
+
+ifeq ($(ARCH),ppc)
+LOAD_ADDR = 0x40000
+endif
+
+#ifeq ($(ARCH),arm)
+#LOAD_ADDR = 0xc100000
+#endif
+
+include $(TOPDIR)/config.mk
+
+ELF    += demo
+BIN    += demo.bin
+
+#CFLAGS += -v
+
+COBJS  := $(ELF:=.o)
+SOBJS  := crt0.o
+ifeq ($(ARCH),ppc)
+SOBJS  += ppcstring.o
+endif
+
+LIB    = $(obj)libglue.a
+LIBCOBJS= glue.o crc32.o ctype.o string.o vsprintf.o libgenwrap.o
+
+LIBOBJS        = $(addprefix $(obj),$(SOBJS) $(LIBCOBJS))
+
+SRCS   := $(COBJS:.o=.c) $(LIBCOBJS:.o=.c) $(SOBJS:.o=.S)
+OBJS   := $(addprefix $(obj),$(COBJS))
+ELF    := $(addprefix $(obj),$(ELF))
+BIN    := $(addprefix $(obj),$(BIN))
+
+gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`)
+
+CPPFLAGS += -I..
+
+all:   $(obj).depend $(OBJS) $(LIB) $(BIN) $(ELF)
+
+#########################################################################
+$(LIB):        $(obj).depend $(LIBOBJS)
+               $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+
+$(ELF):
+$(obj)%:       $(obj)%.o $(LIB)
+               $(LD) $(obj)crt0.o -Ttext $(LOAD_ADDR) \
+                       -o $@ $< $(LIB) \
+                       -L$(gcclibdir) -lgcc
+
+$(BIN):
+$(obj)%.bin:   $(obj)%
+               $(OBJCOPY) -O binary $< $@ 2>/dev/null
+
+$(obj)crc32.c: 
+       @rm -f $(obj)crc32.c
+       ln -s $(src)../lib_generic/crc32.c $(obj)crc32.c
+
+$(obj)ctype.c:
+       @rm -f $(obj)ctype.c
+       ln -s $(src)../lib_generic/ctype.c $(obj)ctype.c
+
+$(obj)string.c:
+       @rm -f $(obj)string.c
+       ln -s $(src)../lib_generic/string.c $(obj)string.c
+
+$(obj)vsprintf.c:
+       @rm -f $(obj)vsprintf.c
+       ln -s $(src)../lib_generic/vsprintf.c $(obj)vsprintf.c
+
+ifeq ($(ARCH),ppc)
+$(obj)ppcstring.S:
+       @rm -f $(obj)ppcstring.S
+       ln -s $(src)../lib_ppc/ppcstring.S $(obj)ppcstring.S
+endif
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/api_examples/crt0.S b/api_examples/crt0.S
new file mode 100644 (file)
index 0000000..8d4f706
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ */
+
+#if defined(CONFIG_PPC)
+
+       .text
+
+       .globl _start
+_start:
+       b       main
+
+
+       .globl syscall
+syscall:
+       lis     %r11, syscall_ptr@ha
+       addi    %r11, %r11, syscall_ptr@l
+       lwz     %r11, 0(%r11)
+       mtctr   %r11
+       bctr
+
+
+       .globl syscall_ptr
+syscall_ptr:
+       .align  4
+       .long   0
+#else
+#error No support for this arch!
+#endif
diff --git a/api_examples/demo.c b/api_examples/demo.c
new file mode 100644 (file)
index 0000000..a4aeef1
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
+
+void   test_dump_si(struct sys_info *);
+void   test_dump_di(int);
+void   test_dump_sig(struct api_signature *);
+
+char buf[2048];
+
+#define WAIT_SECS 5
+
+int main(int argc, char *argv[])
+{
+       int rv = 0;
+       int h, i, j;
+       int devs_no;
+       struct api_signature *sig = NULL;
+       ulong start, now;
+       struct device_info *di;
+
+       if (!api_search_sig(&sig))
+               return -1;
+
+       syscall_ptr = sig->syscall;
+       if (syscall_ptr == NULL)
+               return -2;
+
+       if (sig->version > API_SIG_VERSION)
+               return -3;
+
+       printf("API signature found @%x\n", sig);
+       test_dump_sig(sig);
+
+       printf("\n*** Consumer API test ***\n");
+       printf("syscall ptr 0x%08x@%08x\n", syscall_ptr, &syscall_ptr);
+
+       /* console activities */
+       ub_putc('B');
+
+       printf("*** Press any key to continue ***\n");
+       printf("got char 0x%x\n", ub_getc());
+
+       /* system info */
+       test_dump_si(ub_get_sys_info());
+
+       /* timing */
+       printf("\n*** Timing - wait a couple of secs ***\n");
+       start = ub_get_timer(0);
+       printf("\ntime: start %lu\n\n", start);
+       for (i = 0; i < WAIT_SECS; i++)
+               for (j = 0; j < 1000; j++)
+                       ub_udelay(1000);        /* wait 1 ms */
+
+       /* this is the number of milliseconds that passed from ub_get_timer(0) */
+       now = ub_get_timer(start);
+       printf("\ntime: now %lu\n\n", now);
+
+       /* enumerate devices */
+       printf("\n*** Enumerate devices ***\n");
+       devs_no = ub_dev_enum();
+       
+       printf("Number of devices found: %d\n", devs_no);
+       if (devs_no == 0)
+               return -1;
+
+
+       printf("\n*** Show devices ***\n");
+       for (i = 0; i < devs_no; i++) {
+               test_dump_di(i);
+               printf("\n");
+       }
+
+       printf("\n*** Operations on devices ***\n");
+
+       /* test opening a device already opened */
+       h = 0;
+       if ((rv = ub_dev_open(h)) != 0) {
+               errf("open device %d error %d\n", h, rv);
+               return -1;
+       }
+       if ((rv = ub_dev_open(h)) != 0)
+               errf("open device %d error %d\n", h, rv);
+
+       ub_dev_close(h);
+
+       /* test storage */
+       printf("Trying storage devices...\n");
+       for (i = 0; i < devs_no; i++) {
+               di = ub_dev_get(i);
+
+               if (di->type & DEV_TYP_STOR)
+                       break;
+
+       }
+       if (i == devs_no)
+               printf("No storage devices available\n");
+       else {
+               if ((rv = ub_dev_open(i)) != 0)
+                       errf("open device %d error %d\n", i, rv);
+               else if ((rv = ub_dev_read(i, &buf, 200, 20)) != 0)
+                       errf("could not read from device %d, error %d\n", i, rv);
+
+               ub_dev_close(i);
+       }
+
+       /* test networking */
+       printf("Trying network devices...\n");
+       for (i = 0; i < devs_no; i++) {
+               di = ub_dev_get(i);
+
+               if (di->type == DEV_TYP_NET)
+                       break;
+
+       }
+       if (i == devs_no)
+               printf("No network devices available\n");
+       else {
+               if ((rv = ub_dev_open(i)) != 0)
+                       errf("open device %d error %d\n", i, rv);
+               else if ((rv = ub_dev_send(i, &buf, 2048)) != 0)
+                       errf("could not send to device %d, error %d\n", i, rv);
+
+               ub_dev_close(i);
+       }
+
+       if (ub_dev_close(h) != 0)
+               errf("could not close device %d\n", h);
+
+       printf("\n*** Env vars ***\n");
+
+       printf("ethact = %s\n", ub_env_get("ethact"));
+       printf("old fileaddr = %s\n", ub_env_get("fileaddr"));
+       ub_env_set("fileaddr", "deadbeef");
+       printf("new fileaddr = %s\n", ub_env_get("fileaddr"));
+
+       const char *env = NULL;
+
+       while ((env = ub_env_enum(env)) != NULL)
+               printf("%s = %s\n", env, ub_env_get(env));
+
+       /* reset */
+       ub_reset();
+       printf("\nHmm, reset returned...?!\n");
+
+       return rv;
+}
+
+void test_dump_sig(struct api_signature *sig)
+{
+       printf("signature:\n");
+       printf("  version\t= %d\n", sig->version);
+       printf("  checksum\t= 0x%08x\n", sig->checksum);
+       printf("  sc entry\t= 0x%08x\n", sig->syscall);
+}
+
+void test_dump_si(struct sys_info *si)
+{
+       int i;
+
+       printf("sys info:\n");
+       printf("  clkbus\t= 0x%08x\n", si->clk_bus);
+       printf("  clkcpu\t= 0x%08x\n", si->clk_cpu);
+       printf("  bar\t\t= 0x%08x\n", si->bar);
+
+       printf("---\n");
+       for (i = 0; i < si->mr_no; i++) {
+               if (si->mr[i].flags == 0)
+                       break;
+
+               printf("  start\t= 0x%08lx\n", si->mr[i].start);
+               printf("  size\t= 0x%08lx\n", si->mr[i].size);
+
+               switch(si->mr[i].flags & 0x000F) {
+                       case MR_ATTR_FLASH:
+                               printf("  type FLASH\n");
+                               break;
+                       case MR_ATTR_DRAM:
+                               printf("  type DRAM\n");
+                               break;
+                       case MR_ATTR_SRAM:
+                               printf("  type SRAM\n");
+                               break;
+                       default:
+                               printf("  type UNKNOWN\n");
+               }
+               printf("---\n");
+       }
+}
+
+static char * test_stor_typ(int type)
+{
+       if (type & DT_STOR_IDE)
+               return "IDE";
+
+       if (type & DT_STOR_SCSI)
+               return "SCSI";
+
+       if (type & DT_STOR_USB)
+               return "USB";
+
+       if (type & DT_STOR_MMC);
+               return "MMC";
+
+       return "Unknown";
+}
+
+void test_dump_di(int handle)
+{
+       int i;
+       struct device_info *di = ub_dev_get(handle);
+
+       printf("device info (%d):\n", handle);
+       printf("  cookie\t= 0x%08x\n", (uint32_t)di->cookie);
+       printf("  type\t\t= 0x%08x\n", di->type);
+
+       if (di->type == DEV_TYP_NET) {
+               printf("  hwaddr\t= ");
+               for (i = 0; i < 6; i++)
+                       printf("%02x ", di->di_net.hwaddr[i]);
+
+               printf("\n");
+
+       } else if (di->type & DEV_TYP_STOR) {
+               printf("  type\t\t= %s\n", test_stor_typ(di->type));
+               printf("  blk size\t\t= %d\n", di->di_stor.block_size);
+               printf("  blk count\t\t= %d\n", di->di_stor.block_count);
+       }
+}
diff --git a/api_examples/glue.c b/api_examples/glue.c
new file mode 100644 (file)
index 0000000..7598369
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+static int valid_sig(struct api_signature *sig)
+{
+       uint32_t checksum;
+       struct api_signature s;
+
+       if (sig == NULL)
+               return 0;
+       /*
+        * Clear the checksum field (in the local copy) so as to calculate the
+        * CRC with the same initial contents as at the time when the sig was
+        * produced
+        */
+       s = *sig;
+       s.checksum = 0;
+
+       checksum = crc32(0, (unsigned char *)&s, sizeof(struct api_signature));
+
+       if (checksum != sig->checksum)
+               return 0;
+
+       return 1;
+}
+
+/*
+ * Searches for the U-Boot API signature
+ *
+ * returns 1/0 depending on found/not found result
+ */
+int api_search_sig(struct api_signature **sig) {
+
+       unsigned char *sp;
+
+       if (sig == NULL)
+               return 0;
+
+       sp = (unsigned char *)API_SEARCH_START;
+
+       while ((sp + (int)API_SIG_MAGLEN) < (unsigned char *)API_SEARCH_END) {
+               if (!memcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
+                       *sig = (struct api_signature *)sp;
+                       if (valid_sig(*sig))
+                               return 1;
+               }
+               sp += API_SIG_MAGLEN;
+       }
+
+       *sig = NULL;
+       return 0;
+}
+
+/****************************************
+ *
+ * console
+ *
+ ****************************************/
+
+int ub_getc(void)
+{
+       int c;
+
+       if (!syscall(API_GETC, NULL, (uint32_t)&c))
+               return -1;
+
+       return c;
+}
+
+int ub_tstc(void)
+{
+       int t;
+
+       if (!syscall(API_TSTC, NULL, (uint32_t)&t))
+               return -1;
+
+       return t;
+}
+
+void ub_putc(char c)
+{
+       syscall(API_PUTC, NULL, (uint32_t)&c);
+}
+
+void ub_puts(const char *s)
+{
+       syscall(API_PUTS, NULL, (uint32_t)s);
+}
+
+/****************************************
+ *
+ * system
+ *
+ ****************************************/
+
+void ub_reset(void)
+{
+       syscall(API_RESET, NULL);
+}
+
+#define MR_MAX 5
+static struct mem_region mr[MR_MAX];
+static struct sys_info si;
+
+struct sys_info * ub_get_sys_info(void)
+{
+       int err = 0;
+
+       memset(&si, 0, sizeof(struct sys_info));
+       si.mr = mr;
+       si.mr_no = MR_MAX;
+       memset(&mr, 0, sizeof(mr));
+
+       if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
+               return NULL;
+
+       return ((err) ? NULL : &si);
+}
+
+/****************************************
+ *
+ * timing
+ *
+ ****************************************/
+void ub_udelay(unsigned long usec)
+{
+       syscall(API_UDELAY, NULL, &usec);
+}
+
+unsigned long ub_get_timer(unsigned long base)
+{
+       unsigned long cur;
+
+       if (!syscall(API_GET_TIMER, NULL, &cur, &base))
+               return 0;
+
+       return cur;
+}
+
+
+/****************************************************************************
+ *
+ * devices
+ *
+ * Devices are identified by handles: numbers 0, 1, 2, ..., MAX_DEVS-1
+ *
+ ***************************************************************************/
+
+#define MAX_DEVS 6
+
+static struct device_info devices[MAX_DEVS];
+
+struct device_info * ub_dev_get(int i)
+{
+       return ((i < 0 || i >= MAX_DEVS) ? NULL : &devices[i]);
+}
+
+/*
+ * Enumerates the devices: fills out device_info elements in the devices[]
+ * array.
+ *
+ * returns:            number of devices found
+ */
+int ub_dev_enum(void)
+{
+       struct device_info *di;
+       int n = 0;
+
+       memset(&devices, 0, sizeof(struct device_info) * MAX_DEVS);
+       di = &devices[0];
+
+       if (!syscall(API_DEV_ENUM, NULL, di))
+               return 0;
+
+       while (di->cookie != NULL) {
+
+               if (++n >= MAX_DEVS)
+                       break;
+
+               /* take another device_info */
+               di++;
+
+               /* pass on the previous cookie */
+               di->cookie = devices[n - 1].cookie;
+
+               if (!syscall(API_DEV_ENUM, NULL, di))
+                       return 0;
+       }
+
+       return n;
+}
+
+/*
+ * handle:     0-based id of the device
+ *
+ * returns:    0 when OK, err otherwise
+ */
+int ub_dev_open(int handle)
+{
+       struct device_info *di;
+       int err = 0;
+
+       if (handle < 0 || handle >= MAX_DEVS)
+               return API_EINVAL;
+
+       di = &devices[handle];
+
+       if (!syscall(API_DEV_OPEN, &err, di))
+               return -1;
+
+       return err;
+}
+
+int ub_dev_close(int handle)
+{
+       struct device_info *di;
+
+       if (handle < 0 || handle >= MAX_DEVS)
+               return API_EINVAL;
+
+       di = &devices[handle];
+       if (!syscall(API_DEV_CLOSE, NULL, di))
+               return -1;
+
+       return 0;
+}
+
+/*
+ *
+ * Validates device for read/write, it has to:
+ *
+ * - have sane handle
+ * - be opened
+ *
+ * returns:    0/1 accordingly
+ */
+static int dev_valid(int handle)
+{
+       if (handle < 0 || handle >= MAX_DEVS)
+               return 0;
+
+       if (devices[handle].state != DEV_STA_OPEN)
+               return 0;
+
+       return 1;
+}
+
+static int dev_stor_valid(int handle)
+{
+       if (!dev_valid(handle))
+               return 0;
+
+       if (!(devices[handle].type & DEV_TYP_STOR))
+               return 0;
+
+       return 1;
+}
+
+int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start)
+{
+       struct device_info *di;
+       lbasize_t act_len;
+       int err = 0;
+
+       if (!dev_stor_valid(handle))
+               return API_ENODEV;
+
+       di = &devices[handle];
+       if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
+               return -1;
+
+       if (err) 
+               return err;
+
+       if (act_len != len)
+               return API_EIO;
+
+       return 0;
+}
+
+static int dev_net_valid(int handle)
+{
+       if (!dev_valid(handle))
+               return 0;
+
+       if (devices[handle].type != DEV_TYP_NET)
+               return 0;
+
+       return 1;
+}
+
+int ub_dev_recv(int handle, void *buf, int len)
+{
+       struct device_info *di;
+       int err = 0, act_len;
+
+       if (!dev_net_valid(handle))
+               return API_ENODEV;
+
+       di = &devices[handle];
+       if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
+               return -1;
+
+       if (err)
+               return -1;
+
+       return act_len;
+}
+
+int ub_dev_send(int handle, void *buf, int len)
+{
+       struct device_info *di;
+       int err = 0;
+
+       if (!dev_net_valid(handle))
+               return API_ENODEV;
+
+       di = &devices[handle];
+       if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
+               return -1;
+
+       return err;
+}
+
+/****************************************
+ *
+ * env vars
+ *
+ ****************************************/
+
+char * ub_env_get(const char *name)
+{
+       char *value;
+
+       if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
+               return NULL;
+
+       return value;
+}
+
+void ub_env_set(const char *name, char *value)
+{
+       syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
+}
+
+
+static char env_name[256];
+
+const char * ub_env_enum(const char *last)
+{
+       const char *env, *str;
+       int i;
+
+       env = NULL;
+
+       /*
+        * It's OK to pass only the name piece as last (and not the whole
+        * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
+        * internally, which handles such case
+        */
+       if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
+               return NULL;
+
+       if (!env)
+               /* no more env. variables to enumerate */
+               return NULL;
+
+       /* next enumerated env var */
+       memset(env_name, 0, 256);
+       for (i = 0, str = env; *str != '=' && *str != '\0';)
+               env_name[i++] = *str++;
+
+       env_name[i] = '\0';
+
+       return env_name;
+}
diff --git a/api_examples/glue.h b/api_examples/glue.h
new file mode 100644 (file)
index 0000000..a82f783
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ */
+
+/*
+ * This is the header file for conveniency wrapper routines (API glue)
+ */
+
+#ifndef _API_GLUE_H_
+#define _API_GLUE_H_
+
+#define API_SEARCH_START       (255 * 1024 * 1024)     /* start at 1MB below top RAM */
+#define API_SEARCH_END         (256 * 1024 * 1024 - 1) /* ...and search to the end */
+
+int    syscall(int, int *, ...);
+void * syscall_ptr;
+
+int    api_search_sig(struct api_signature **sig);
+
+/*
+ * ub_ library calls are part of the application, not U-Boot code!  They are
+ * front-end wrappers that are used by the consumer application: they prepare
+ * arguments for particular syscall and jump to the low level syscall()
+ */
+
+/* console */
+int    ub_getc(void);
+int    ub_tstc(void);
+void   ub_putc(char c);
+void   ub_puts(const char *s);
+
+/* system */
+void                   ub_reset(void);
+struct sys_info *      ub_get_sys_info(void);
+
+/* time */
+void           ub_udelay(unsigned long);
+unsigned long  ub_get_timer(unsigned long);
+
+/* env vars */
+char *         ub_env_get(const char *name);
+void           ub_env_set(const char *name, char *value);
+const char *   ub_env_enum(const char *last);
+
+/* devices */
+int                    ub_dev_enum(void);
+int                    ub_dev_open(int handle);
+int                    ub_dev_close(int handle);
+int                    ub_dev_read(int handle, void *buf,
+                               lbasize_t len, lbastart_t start);
+int                    ub_dev_send(int handle, void *buf, int len);
+int                    ub_dev_recv(int handle, void *buf, int len);
+struct device_info *   ub_dev_get(int);
+
+#endif /* _API_GLUE_H_ */
diff --git a/api_examples/libgenwrap.c b/api_examples/libgenwrap.c
new file mode 100644 (file)
index 0000000..df62633
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ *
+ * This is is a set of wrappers/stubs that allow to use certain routines from
+ * U-Boot's lib_generic in the standalone app. This way way we can re-use
+ * existing code e.g. operations on strings and similar.
+ *
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <api_public.h>
+
+#include "glue.h"
+
+/*
+ * printf() and vprintf() are stolen from u-boot/common/console.c
+ */
+void printf (const char *fmt, ...)
+{
+       va_list args;
+       uint i;
+       char printbuffer[256];
+
+       va_start (args, fmt);
+
+       /* For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsprintf (printbuffer, fmt, args);
+       va_end (args);
+
+       /* Print the string */
+       ub_puts (printbuffer);
+}
+
+void vprintf (const char *fmt, va_list args)
+{
+       uint i;
+       char printbuffer[256];
+
+       /* For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsprintf (printbuffer, fmt, args);
+
+       /* Print the string */
+       ub_puts (printbuffer);
+}
+
+void putc (const char c)
+{
+       ub_putc(c);
+}
+
+void udelay(unsigned long usec)
+{
+       ub_udelay(usec);
+}
+
+void do_reset (void)
+{
+       ub_reset();
+}
+
+void *malloc(size_t len)
+{
+       return NULL;
+}
diff --git a/include/api_public.h b/include/api_public.h
new file mode 100644 (file)
index 0000000..690975e
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _API_PUBLIC_H_
+#define _API_PUBLIC_H_
+
+#define API_EINVAL             1       /* invalid argument(s)  */
+#define API_ENODEV             2       /* no device            */
+#define API_ENOMEM             3       /* no memory            */
+#define API_EBUSY              4       /* busy, occupied etc.  */
+#define API_EIO                        5       /* I/O error            */
+
+typedef        int (*scp_t)(int, int *, ...);
+
+#define API_SIG_VERSION        1
+#define API_SIG_MAGIC  "UBootAPI"
+#define API_SIG_MAGLEN 8
+
+struct api_signature {
+       char            magic[API_SIG_MAGLEN];  /* magic string */
+       uint16_t        version;                /* API version */
+       uint32_t        checksum;               /* checksum of this sig struct */
+       scp_t           syscall;                /* entry point to the API */
+};
+
+enum {
+       API_RSVD = 0,
+       API_GETC,
+       API_PUTC,
+       API_TSTC,
+       API_PUTS,
+       API_RESET,
+       API_GET_SYS_INFO,
+       API_UDELAY,
+       API_GET_TIMER,
+       API_DEV_ENUM,
+       API_DEV_OPEN,
+       API_DEV_CLOSE,
+       API_DEV_READ,
+       API_DEV_WRITE,
+       API_ENV_ENUM,
+       API_ENV_GET,
+       API_ENV_SET,
+       API_MAXCALL
+};
+
+#define MR_ATTR_FLASH  0x0001
+#define MR_ATTR_DRAM   0x0002
+#define MR_ATTR_SRAM   0x0003
+
+struct mem_region {
+       unsigned long   start;
+       unsigned long   size;
+       int             flags;
+};
+
+struct sys_info {
+       unsigned long           clk_bus;
+       unsigned long           clk_cpu;
+       unsigned long           bar;
+       struct mem_region       *mr;
+       int                     mr_no;  /* number of memory regions */
+};
+
+#undef CFG_64BIT_LBA
+#ifdef CFG_64BIT_LBA
+typedef        u_int64_t lbasize_t;
+#else
+typedef unsigned long lbasize_t;
+#endif
+typedef unsigned long lbastart_t;
+
+#define DEV_TYP_NONE   0x0000
+#define DEV_TYP_NET    0x0001
+
+#define DEV_TYP_STOR   0x0002
+#define DT_STOR_IDE    0x0010
+#define DT_STOR_SCSI   0x0020
+#define DT_STOR_USB    0x0040
+#define DT_STOR_MMC    0x0080
+
+#define DEV_STA_CLOSED 0x0000          /* invalid, closed */
+#define DEV_STA_OPEN   0x0001          /* open i.e. active */
+
+struct device_info {
+       int     type;
+       void    *cookie;
+
+       union {
+               struct {
+                       lbasize_t       block_count;    /* no of blocks */
+                       unsigned long   block_size;     /* size of one block */
+               } storage;
+
+               struct {
+                       unsigned char   hwaddr[6];
+               } net;
+       } info;
+#define di_stor info.storage
+#define di_net info.net
+
+       int     state;
+};
+
+#endif /* _API_PUBLIC_H_ */
index da2f01b464deff91c8ca86609cbc574d5437e56e..169bd2cd949fc2951a657e4aabae68ed97560e2e 100644 (file)
@@ -279,6 +279,9 @@ int misc_init_r   (void);
 /* common/exports.c */
 void   jumptable_init(void);
 
+/* api/api.c */
+void   api_init (void);
+
 /* common/memsize.c */
 long   get_ram_size  (volatile long *, long);
 
index 9aa67f93c0f66a6e5764cc1ee31a856da701f924..071974506662559317844ebc70235069092f1f80 100644 (file)
@@ -928,6 +928,11 @@ void board_init_r (gd_t *id, ulong dest_addr)
        /* Initialize the jump table for applications */
        jumptable_init ();
 
+#if defined(CONFIG_API)
+       /* Initialize API */
+       api_init ();
+#endif
+
        /* Initialize the console (after the relocation and devices init) */
        console_init_r ();