[U-Boot-Users] [PATCH 5/7] Core API (U-Boot side)

Rafal Jaworowski raj at semihalf.com
Wed Oct 3 12:07:01 CEST 2007


diff -upr --new-file --exclude=.git /src/u-boot/api/api.c u-boot/api/api.c
--- /src/u-boot/api/api.c	1970-01-01 01:00:00.000000000 +0100
+++ u-boot/api/api.c	2007-10-02 17:13:55.000000000 +0200
@@ -0,0 +1,670 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj at 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>
+
+#undef DEBUG
+#define DEBUG
+
+void api_init(void);
+
+extern void dev_enum_reset(void);
+extern int dev_enum_storage(struct device_info *);
+extern int dev_enum_net(struct device_info *);
+
+extern int dev_open_stor(void *);
+extern int dev_open_net(void *);
+extern int dev_close_stor(void *);
+extern int dev_close_net(void *);
+
+extern lbasize_t dev_read_stor(void *, void *, lbasize_t, lbastart_t);
+extern int dev_read_net(void *, void *, int);
+
+extern int dev_write_net(void *, void *, int);
+
+extern void dev_stor_init(void);
+extern int platform_sys_info(struct sys_info *);
+
+/* 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);
+extern int envmatch(uchar*, 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 (07.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);
+}
+
+#endif /* CONFIG_API */
diff -upr --new-file --exclude=.git /src/u-boot/api/api_net.c u-boot/api/api_net.c
--- /src/u-boot/api/api_net.c	1970-01-01 01:00:00.000000000 +0100
+++ u-boot/api/api_net.c	2007-10-02 14:16:52.000000000 +0200
@@ -0,0 +1,114 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj at 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))
+		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 -upr --new-file --exclude=.git /src/u-boot/api/api_platform.c u-boot/api/api_platform.c
--- /src/u-boot/api/api_platform.c	1970-01-01 01:00:00.000000000 +0100
+++ u-boot/api/api_platform.c	2007-10-02 13:47:13.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj at 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 potentially
+ * platform/arch-dependent sources. Keep all such in one place.
+ *
+ */
+
+#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>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void 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;
+		}
+}
+
+int platform_sys_info(struct sys_info *si)
+{
+	si->clk_bus = gd->bus_clk;
+	si->clk_cpu = gd->cpu_clk;
+	si->bar = gd->bd->bi_bar;
+
+	set_mr(si, gd->bd->bi_memstart, gd->bd->bi_memsize, MR_ATTR_DRAM);
+	set_mr(si, gd->bd->bi_flashstart, gd->bd->bi_flashsize, MR_ATTR_FLASH);
+	set_mr(si, gd->bd->bi_sramstart, gd->bd->bi_sramsize, MR_ATTR_SRAM);
+
+	return 1;
+}
+
+#endif /* CONFIG_API */
diff -upr --new-file --exclude=.git /src/u-boot/api/api_storage.c u-boot/api/api_storage.c
--- /src/u-boot/api/api_storage.c	1970-01-01 01:00:00.000000000 +0100
+++ u-boot/api/api_storage.c	2007-10-02 16:25:49.000000000 +0200
@@ -0,0 +1,370 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj at 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>
+
+#undef DEBUG
+#define 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 -upr --new-file --exclude=.git /src/u-boot/api/Makefile u-boot/api/Makefile
--- /src/u-boot/api/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ u-boot/api/Makefile	2007-10-02 13:48:29.000000000 +0200
@@ -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.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




More information about the U-Boot mailing list