Commit d7b938d7 authored by Alessandro Rubini's avatar Alessandro Rubini

sdb-lib: new upstream commit a3f065e

This makes the binary size 500 bytes bigger for gsi_defconfig
(the configuration already using the library) and strangely a little
smaller for etherbone_defconfig.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 32dd97e9
...@@ -21,7 +21,7 @@ int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return) ...@@ -21,7 +21,7 @@ int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return)
int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count) int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count)
{ {
int ret = count; int ret;
if (!fs->currentp) if (!fs->currentp)
return -ENOENT; return -ENOENT;
...@@ -29,6 +29,7 @@ int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count) ...@@ -29,6 +29,7 @@ int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count)
offset = fs->read_offset; offset = fs->read_offset;
if (offset + count > fs->f_len) if (offset + count > fs->f_len)
count = fs->f_len - offset; count = fs->f_len - offset;
ret = count;
if (fs->data) if (fs->data)
memcpy(buf, fs->data + fs->f_offset + offset, count); memcpy(buf, fs->data + fs->f_offset + offset, count);
else else
...@@ -40,7 +41,7 @@ int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count) ...@@ -40,7 +41,7 @@ int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count)
int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count) int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count)
{ {
int ret = count; int ret;
if (!fs->currentp) if (!fs->currentp)
return -ENOENT; return -ENOENT;
...@@ -48,6 +49,7 @@ int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count) ...@@ -48,6 +49,7 @@ int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count)
offset = fs->read_offset; offset = fs->read_offset;
if (offset + count > fs->f_len) if (offset + count > fs->f_len)
count = fs->f_len - offset; count = fs->f_len - offset;
ret = count;
if (fs->data) if (fs->data)
memcpy(buf, fs->data + fs->f_offset + offset, count); memcpy(buf, fs->data + fs->f_offset + offset, count);
else else
......
/* /*
* Copyright (C) 2012 CERN (www.cern.ch) * Copyright (C) 2012,2014 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com> * Author: Alessandro Rubini <rubini@gnudd.com>
* *
* Released according to the GNU GPL, version 2 or any later version. * Released according to the GNU GPL, version 2 or any later version.
...@@ -14,21 +14,24 @@ ...@@ -14,21 +14,24 @@
static struct sdbfs *sdbfs_list; static struct sdbfs *sdbfs_list;
/* All fields unused by the caller are expected to be zeroed */ /* All fields unused by the caller are expected to be zeroed */
int sdbfs_dev_create(struct sdbfs *fs, int verbose) int sdbfs_dev_create(struct sdbfs *fs)
{ {
unsigned int magic; unsigned int magic;
/* First, check we have the magic */ /* First, check we have the magic */
if (fs->data) if (fs->data || (fs->flags & SDBFS_F_ZEROBASED))
magic = *(unsigned int *)(fs->data + fs->entrypoint); magic = *(unsigned int *)(fs->data + fs->entrypoint);
else else
fs->read(fs, fs->entrypoint, &magic, sizeof(magic)); fs->read(fs, fs->entrypoint, &magic, sizeof(magic));
if (htonl(magic) != SDB_MAGIC) if (magic == SDB_MAGIC) {
/* Uh! If we are little-endian, we must convert */
if (ntohl(1) != 1)
fs->flags |= SDBFS_F_CONVERT32;
} else if (htonl(magic) == SDB_MAGIC) {
/* ok, don't convert */
} else {
return -ENOTDIR; return -ENOTDIR;
}
if (verbose)
fs->flags |= SDBFS_F_VERBOSE;
fs->next = sdbfs_list; fs->next = sdbfs_list;
sdbfs_list = fs; sdbfs_list = fs;
...@@ -70,47 +73,120 @@ static struct sdb_device *sdbfs_readentry(struct sdbfs *fs, ...@@ -70,47 +73,120 @@ static struct sdb_device *sdbfs_readentry(struct sdbfs *fs,
/* /*
* This function reads an entry from a known good offset. It * This function reads an entry from a known good offset. It
* returns the pointer to the entry, which may be stored in * returns the pointer to the entry, which may be stored in
* the fs structure itself. Only touches fs->current_record * the fs structure itself. Only touches fs->current_record.
*/ */
if (fs->data) if (fs->data || (fs->flags & SDBFS_F_ZEROBASED)) {
return (struct sdb_device *)(fs->data + offset); if (!(fs->flags & SDBFS_F_CONVERT32))
if (!fs->read) return (struct sdb_device *)(fs->data + offset);
return NULL; /* copy to local storage for conversion */
fs->read(fs, offset, &fs->current_record, sizeof(fs->current_record)); memcpy(&fs->current_record, fs->data + offset,
sizeof(fs->current_record));
} else {
if (!fs->read)
return NULL;
fs->read(fs, offset, &fs->current_record,
sizeof(fs->current_record));
}
if (fs->flags & SDBFS_F_CONVERT32) {
uint32_t *p = (void *)&fs->current_record;
int i;
for (i = 0; i < sizeof(fs->current_record) / sizeof(*p); i++)
p[i] = ntohl(p[i]);
}
return &fs->current_record; return &fs->current_record;
} }
/* Helper for scanning: we enter a new directory, and we must validate */
static struct sdb_device *scan_newdir(struct sdbfs *fs, int depth)
{
struct sdb_device *dev;
struct sdb_interconnect *intercon;
dev = fs->currentp = sdbfs_readentry(fs, fs->this[depth]);
if (dev->sdb_component.product.record_type != sdb_type_interconnect)
return NULL;
intercon = (typeof(intercon))dev;
if (ntohl(intercon->sdb_magic) != SDB_MAGIC)
return NULL;
fs->nleft[depth] = ntohs(intercon->sdb_records) - 1;
fs->this[depth] += sizeof(*intercon);
fs->depth = depth;
return dev;
}
struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan) struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan)
{ {
/* /*
* This returns a pointer to the next sdb record, or a new one. * This returns a pointer to the next sdb record, or the first one.
* Subdirectories are not supported. Uses all internal fields * Subdirectories (bridges) are returned before their contents.
* It only uses internal fields.
*/ */
struct sdb_device *ret; struct sdb_device *dev;
struct sdb_interconnect *i; struct sdb_bridge *bridge;
int depth, type, newdir = 0; /* check there's the magic */
if (newscan) { if (newscan) {
fs->f_offset = fs->entrypoint; fs->base[0] = 0;
} else { fs->this[0] = fs->entrypoint;
fs->f_offset += sizeof(struct sdb_device); depth = fs->depth = 0;
if (!fs->nleft) newdir = 1;
return NULL; goto scan;
} }
ret = sdbfs_readentry(fs, fs->f_offset);
if (newscan) { /* If we already returned a bridge, go inside it (check type) */
i = (typeof(i))ret; depth = fs->depth;
fs->nleft = ntohs(i->sdb_records) - 1; type = fs->currentp->sdb_component.product.record_type;
} else {
fs->nleft--; if (type == sdb_type_bridge && depth + 1 < SDBFS_DEPTH) {
bridge = (typeof(bridge))fs->currentp;
fs->this[depth + 1] = fs->base[depth]
+ ntohll(bridge->sdb_child);
fs->base[depth + 1] = fs->base[depth]
+ ntohll(bridge->sdb_component.addr_first);
depth++;
newdir++;
}
scan:
/* If entering a new directory, verify magic and set nleft */
if (newdir) {
dev = scan_newdir(fs, depth);
if (dev)
goto out;
/* Otherwise the directory is not there: no intercon */
if (!depth)
return NULL; /* no entries at all */
depth--;
}
while (fs->nleft[depth] == 0) {
/* No more at this level, "cd .." if possible */
if (!depth)
return NULL;
fs->depth = --depth;
} }
return ret;
/* so, read the next entry */
dev = fs->currentp = sdbfs_readentry(fs, fs->this[depth]);
fs->this[depth] += sizeof(*dev);
fs->nleft[depth]--;
out:
fs->f_offset = fs->base[fs->depth]
+ htonll(fs->currentp->sdb_component.addr_first);
return dev;
} }
static void __open(struct sdbfs *fs) static void __open(struct sdbfs *fs)
{ {
fs->f_offset = htonll(fs->currentp->sdb_component.addr_first); fs->f_offset = fs->base[fs->depth]
+ htonll(fs->currentp->sdb_component.addr_first);
fs->f_len = htonll(fs->currentp->sdb_component.addr_last) fs->f_len = htonll(fs->currentp->sdb_component.addr_last)
+ 1 - fs->f_offset; + 1 - htonll(fs->currentp->sdb_component.addr_first);
fs->read_offset = 0; fs->read_offset = 0;
} }
...@@ -157,3 +233,31 @@ int sdbfs_close(struct sdbfs *fs) ...@@ -157,3 +233,31 @@ int sdbfs_close(struct sdbfs *fs)
return 0; return 0;
} }
/* to "find" a device, open it, get the current offset, then close */
unsigned long sdbfs_find_name(struct sdbfs *fs, const char *name)
{
unsigned long offset;
int ret;
ret = sdbfs_open_name(fs, name);
if (ret < 0)
return (unsigned long)ret;
offset = fs->f_offset;
sdbfs_close(fs);
return offset;
}
unsigned long sdbfs_find_id(struct sdbfs *fs, uint64_t vid, uint32_t did)
{
unsigned long offset;
int ret;
ret = sdbfs_open_id(fs, vid, did);
if (ret < 0)
return (unsigned long)ret;
offset = fs->f_offset;
sdbfs_close(fs);
return offset;
}
/*
* This supports both the Linux kernel and barebox, that is similar
* by design, and defines __KERNEL__ too.
*/
#ifdef __BAREBOX__
# include <errno.h>
#else /* really linux */
# include <linux/errno.h>
#endif
#include <linux/types.h> #include <linux/types.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
/* /*
...@@ -11,8 +19,12 @@ ...@@ -11,8 +19,12 @@
* So, check if we got the information we need before strange errors happen. * So, check if we got the information we need before strange errors happen.
* The DECLARE_BITMAP macro is in <linux/types.h> since the epoch, but it * The DECLARE_BITMAP macro is in <linux/types.h> since the epoch, but it
* is not installed in /usr/include/linux/types.h, so use it to check. * is not installed in /usr/include/linux/types.h, so use it to check.
*
* If building for barebox, we miss the macro, but we are sure that
* we are picking the correct header, because the library is only built
* within the barebox source tree.
*/ */
#ifndef DECLARE_BITMAP #if !defined(DECLARE_BITMAP) && !defined(__BAREBOX__)
# error "Please point LINUX to a source tree if you define __KERNEL__" # error "Please point LINUX to a source tree if you define __KERNEL__"
#endif #endif
...@@ -20,5 +32,4 @@ ...@@ -20,5 +32,4 @@
#define SDB_USER 0 #define SDB_USER 0
#define SDB_FREESTAND 0 #define SDB_FREESTAND 0
#define sdb_print(format, ...) printk(format, __VA_ARGS__) #define sdb_print(format, ...) printk(format, __VA_ARGS__)
#ifndef __LIBSDBFS_H__ #ifndef __LIBSDBFS_H__
#define __LIBSDBFS_H__ #define __LIBSDBFS_H__
/* The library can work in three different environments */ /* The library can work in different environments, take care of them */
#ifdef __KERNEL__ #ifdef __KERNEL__
# include "libsdbfs-kernel.h" # include "libsdbfs-kernel.h"
#elif defined(__unix__) #elif defined(__unix__)
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <sdb.h> /* Please point your "-I" to some sensible place */ #include <sdb.h> /* Please point your "-I" to some sensible place */
#define SDBFS_DEPTH 4 /* Max number of subdirectory depth */
/* /*
* Data structures: please not that the library intself doesn't use * Data structures: please not that the library intself doesn't use
* malloc, so it's the caller who must deal withallocation/removal. * malloc, so it's the caller who must deal withallocation/removal.
...@@ -24,8 +25,9 @@ struct sdbfs { ...@@ -24,8 +25,9 @@ struct sdbfs {
/* Some fields are informative */ /* Some fields are informative */
char *name; /* may be null */ char *name; /* may be null */
void *drvdata; /* driver may need some detail.. */ void *drvdata; /* driver may need some detail.. */
int blocksize; unsigned long blocksize;
unsigned long entrypoint; unsigned long entrypoint;
unsigned long flags;
/* The "driver" must offer some methods */ /* The "driver" must offer some methods */
void *data; /* Use this if directly mapped */ void *data; /* Use this if directly mapped */
...@@ -35,23 +37,30 @@ struct sdbfs { ...@@ -35,23 +37,30 @@ struct sdbfs {
int (*erase)(struct sdbfs *fs, int offset, int count); int (*erase)(struct sdbfs *fs, int offset, int count);
/* The following fields are library-private */ /* The following fields are library-private */
struct sdb_device current_record;
struct sdb_device *currentp; struct sdb_device *currentp;
int nleft; struct sdb_device current_record;
unsigned long f_offset;
unsigned long f_len; unsigned long f_len;
unsigned long read_offset; unsigned long f_offset; /* start of file */
unsigned long flags; unsigned long read_offset; /* current location */
struct sdbfs *next; struct sdbfs *next;
/* The following ones are directory-aware */
unsigned long base[SDBFS_DEPTH]; /* for relative addresses */
unsigned long this[SDBFS_DEPTH]; /* current sdb record */
int nleft[SDBFS_DEPTH];
int depth;
}; };
#define SDBFS_F_VERBOSE 0x0001 /* Some flags are set by the user, some (convert32) by the library */
#define SDBFS_F_VERBOSE 0x0001 /* not really used yet */
#define SDBFS_F_CONVERT32 0x0002 /* swap SDB words as they are read */
#define SDBFS_F_ZEROBASED 0x0004 /* zero is a valid data pointer */
/* Defined in glue.c */ /* Defined in glue.c */
int sdbfs_dev_create(struct sdbfs *fs, int verbose); int sdbfs_dev_create(struct sdbfs *fs);
int sdbfs_dev_destroy(struct sdbfs *fs); int sdbfs_dev_destroy(struct sdbfs *fs);
struct sdbfs *sdbfs_dev_find(const char *name); struct sdbfs *sdbfs_dev_find(const char *name);
unsigned long sdbfs_find_name(struct sdbfs *fs, const char *name);
unsigned long sdbfs_find_id(struct sdbfs *fs, uint64_t vid, uint32_t did);
int sdbfs_open_name(struct sdbfs *fs, const char *name); int sdbfs_open_name(struct sdbfs *fs, const char *name);
int sdbfs_open_id(struct sdbfs *fs, uint64_t vid, uint32_t did); int sdbfs_open_id(struct sdbfs *fs, uint64_t vid, uint32_t did);
int sdbfs_close(struct sdbfs *fs); int sdbfs_close(struct sdbfs *fs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment