Commit 04d2a95e authored by Alessandro Rubini's avatar Alessandro Rubini

sdb-lib: copied from sdbfs project (commit 75126783)

This is the library that we really should use for SDB access.
Houwever, it still misses subdirectory support, so it is not
actually used at this point (even after the commits that build it).

I'm hopeful for the future, but only after the upcoming release.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 18b4b1d1
LINUX ?= /lib/modules/$(shell uname -r)/build
# If we compile for the kernel, we need to include real kernel headers.
# The thing is enough a mess that I moved it to a different file
include Makefile.arch
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
# calculate endianness at compile time
ENDIAN := $(shell ./check-endian $(CC))
CFLAGS = -Wall -ggdb -O2
CFLAGS += -I../include/linux # for <sdb.h>
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -Wno-pointer-sign
CFLAGS += $(ENDIAN) $(LINUXINCLUDE)
LIB = libsdbfs.a
OBJS = glue.o access.o
all: $(LIB)
$(OBJS): $(wildcard *.h)
$(LIB): $(OBJS)
$(AR) r $@ $(OBJS)
clean:
rm -f $(OBJS) $(LIB) *~ core
# add the other unused targets, so the rule in ../Makefile works
modules install modules_install:
srctree = $(LINUX)
#
# This set of contortions comes from the kernel Makefile. We need this
# in order to properly compile libsdbfs for the kernel without being
# in a kernel build environment (for example, to check for compile errors).
#
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ )
SRCARCH := $(ARCH)
# Additional ARCH settings for x86
ifeq ($(ARCH),i386)
SRCARCH := x86
endif
ifeq ($(ARCH),x86_64)
SRCARCH := x86
endif
# Additional ARCH settings for sparc
ifeq ($(ARCH),sparc32)
SRCARCH := sparc
endif
ifeq ($(ARCH),sparc64)
SRCARCH := sparc
endif
# Additional ARCH settings for sh
ifeq ($(ARCH),sh64)
SRCARCH := sh
endif
# Additional ARCH settings for tile
ifeq ($(ARCH),tilepro)
SRCARCH := tile
endif
ifeq ($(ARCH),tilegx)
SRCARCH := tile
endif
# Where to locate arch specific headers
hdr-arch := $(SRCARCH)
ifeq ($(ARCH),m68knommu)
hdr-arch := m68k
endif
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
LINUXINCLUDE := -I$(srctree)/arch/$(hdr-arch)/include \
-Iarch/$(hdr-arch)/include/generated \
-I$(srctree)/include
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
/* To avoid many #ifdef and associated mess, all headers are included there */
#include "libsdbfs.h"
int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return)
{
if (!fs->currentp)
return -ENOENT;
memcpy(record_return, fs->currentp, sizeof(*record_return));
return 0;
}
int sdbfs_fread(struct sdbfs *fs, int offset, char *buf, int count)
{
if (!fs->currentp)
return -ENOENT;
if (offset < 0)
offset = fs->read_offset;
if (offset + count > fs->f_len)
count = fs->f_len - offset;
if (fs->data)
memcpy(buf, fs->data + fs->f_offset + offset, count);
else
fs->read(fs, fs->f_offset + offset, buf, count);
fs->read_offset = offset + count;
return count;
}
int sdbfs_fwrite(struct sdbfs *fs, int offset, char *buf, int count)
{
return -ENOSYS;
}
#!/bin/bash
# Check endianness at compile time, so we can pass the -D to CFLAGS
CC=$1
if [ "x$CC" == "x" ]; then
echo "$0: pass the compiler path (\$CC) as argument" >& 2
exit 1
fi
# Check endianness, by making an object file
TMPC=$(mktemp /tmp/endian-c-XXXXXX)
TMPO=$(mktemp /tmp/endian-o-XXXXXX)
echo "int i = 0xbbee;" > $TMPC
$CC -x c -c $TMPC -o $TMPO
OBJCOPY=$(echo $CC | sed 's/gcc$/objcopy/')
if $OBJCOPY -O binary $TMPO /dev/stdout | od -t x1 -An | \
grep -q 'bb ee'; then
echo " -DSDBFS_BIG_ENDIAN"
else
echo " -DSDBFS_LITTLE_ENDIAN"
fi
rm -f $TMPC $TMPO
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
/* To avoid many #ifdef and associated mess, all headers are included there */
#include "libsdbfs.h"
static struct sdbfs *sdbfs_list;
/* All fields unused by the caller are expected to be zeroed */
int sdbfs_dev_create(struct sdbfs *fs, int verbose)
{
unsigned int magic;
/* First, check we have the magic */
if (fs->data)
magic = *(unsigned int *)(fs->data + fs->entrypoint);
else
fs->read(fs, fs->entrypoint, &magic, sizeof(magic));
if (htonl(magic) != SDB_MAGIC)
return -ENOTDIR;
if (verbose)
fs->flags |= SDBFS_F_VERBOSE;
fs->next = sdbfs_list;
sdbfs_list = fs;
return 0;
}
int sdbfs_dev_destroy(struct sdbfs *fs)
{
struct sdbfs **p;
for (p = &sdbfs_list; *p && *p != fs; p = &(*p)->next)
;
if (!*p)
return -ENOENT;
*p = fs->next;
return 0;
}
struct sdbfs *sdbfs_dev_find(const char *name)
{
struct sdbfs *l;
for (l = sdbfs_list; l && strcmp(l->name, name); l = l->next)
;
if (!l)
return NULL;
return l;
}
/*
* To open by name or by ID we need to scan the tree. The scan
* function is also exported in order for "sdb-ls" to use it
*/
static struct sdb_device *sdbfs_readentry(struct sdbfs *fs,
unsigned long offset)
{
/*
* This function reads an entry from a known good offset. It
* returns the pointer to the entry, which may be stored in
* the fs structure itself. Only touches fs->current_record
*/
if (fs->data)
return (struct sdb_device *)(fs->data + offset);
fs->read(fs, offset, &fs->current_record, sizeof(fs->current_record));
return &fs->current_record;
}
struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan)
{
/*
* This returns a pointer to the next sdb record, or a new one.
* Subdirectories are not supported. Uses all internal fields
*/
struct sdb_device *ret;
struct sdb_interconnect *i;
if (newscan) {
fs->f_offset = fs->entrypoint;
} else {
fs->f_offset += sizeof(struct sdb_device);
if (!fs->nleft)
return NULL;
}
ret = sdbfs_readentry(fs, fs->f_offset);
if (newscan) {
i = (typeof(i))ret;
fs->nleft = ntohs(i->sdb_records) - 1;
} else {
fs->nleft--;
}
return ret;
}
static void __open(struct sdbfs *fs)
{
fs->f_offset = htonll(fs->currentp->sdb_component.addr_first);
fs->f_len = htonll(fs->currentp->sdb_component.addr_last)
+ 1 - fs->f_offset;
fs->read_offset = 0;
}
int sdbfs_open_name(struct sdbfs *fs, const char *name)
{
struct sdb_device *d;
int len = strlen(name);
if (len > 19)
return -ENOENT;
sdbfs_scan(fs, 1); /* new scan: get the interconnect and igore it */
while ( (d = sdbfs_scan(fs, 0)) != NULL) {
if (strncmp(name, d->sdb_component.product.name, len))
continue;
if (len < 19 && d->sdb_component.product.name[len] != ' ')
continue;
fs->currentp = d;
__open(fs);
return 0;
}
return -ENOENT;
}
int sdbfs_open_id(struct sdbfs *fs, uint64_t vid, uint32_t did)
{
struct sdb_device *d;
sdbfs_scan(fs, 1); /* new scan: get the interconnect and igore it */
while ( (d = sdbfs_scan(fs, 0)) != NULL) {
if (vid != d->sdb_component.product.vendor_id)
continue;
if (did != d->sdb_component.product.device_id)
continue;
fs->currentp = d;
__open(fs);
return 0;
}
return -ENOENT;
}
int sdbfs_close(struct sdbfs *fs)
{
fs->currentp = NULL;
return 0;
}
/* Though freestanding, some minimal headers are expected to exist */
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#define SDB_KERNEL 0
#define SDB_USER 0
#define SDB_FREESTAND 1
#ifdef SDBFS_BIG_ENDIAN
# define ntohs(x) (x)
# define htons(x) (x)
# define ntohl(x) (x)
# define htonl(x) (x)
#else
# error "No support, yet, for little-endian freestanding library"
#endif
#include <linux/types.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <asm/byteorder.h>
/*
* The default installed /usr/include/linux stuff misses the __KERNEL__ parts.
* For libsdbfs it means we won't get uint32_t and similar types.
*
* 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
* is not installed in /usr/include/linux/types.h, so use it to check.
*/
#ifndef DECLARE_BITMAP
# error "Please point LINUX to a source tree if you define __KERNEL__"
#endif
#define SDB_KERNEL 1
#define SDB_USER 0
#define SDB_FREESTAND 0
#define sdb_print(format, ...) printk(format, __VA_ARGS__)
#ifndef __LIBSDBFS_USER_H__
#define __LIBSDBFS_USER_H__
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h> /* htonl */
#define SDB_KERNEL 0
#define SDB_USER 1
#define SDB_FREESTAND 0
#define sdb_print(format, ...) fprintf(stderr, format, __VA_ARGS__)
#endif /* __LIBSDBFS_USER_H__ */
#ifndef __LIBSDBFS_H__
#define __LIBSDBFS_H__
/* The library can work in three different environments */
#ifdef __KERNEL__
# include "libsdbfs-kernel.h"
#elif defined(__unix__)
# include "libsdbfs-user.h"
#else
# include "libsdbfs-freestanding.h"
#endif
#include <sdb.h> /* Please point your "-I" to some sensible place */
/*
* Data structures: please not that the library intself doesn't use
* malloc, so it's the caller who must deal withallocation/removal.
* For this reason we can have no opaque structures, but some fields
* are private
*/
struct sdbfs {
/* Some fields are informative */
char *name; /* may be null */
void *drvdata; /* driver may need some detail.. */
int blocksize;
unsigned long entrypoint;
/* The "driver" must offer some methods */
void *data; /* Use this if directly mapped */
unsigned long datalen; /* Length of the above array */
int (*read)(struct sdbfs *fs, int offset, void *buf, int count);
int (*write)(struct sdbfs *fs, int offset, void *buf, int count);
int (*erase)(struct sdbfs *fs, int offset, int count);
/* The following fields are library-private */
struct sdb_device current_record;
struct sdb_device *currentp;
int nleft;
unsigned long f_offset;
unsigned long f_len;
unsigned long read_offset;
unsigned long flags;
struct sdbfs *next;
};
#define SDBFS_F_VERBOSE 0x0001
/* Defined in glue.c */
int sdbfs_dev_create(struct sdbfs *fs, int verbose);
int sdbfs_dev_destroy(struct sdbfs *fs);
struct sdbfs *sdbfs_dev_find(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_close(struct sdbfs *fs);
struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan);
/* Defined in access.c */
int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return);
int sdbfs_fread(struct sdbfs *fs, int offset, char *buf, int count);
int sdbfs_fwrite(struct sdbfs *fs, int offset, char *buf, int count);
/* This is needed to convert endianness. Hoping it is not defined elsewhere */
static inline uint64_t htonll(uint64_t ll)
{
uint64_t res;
if (htonl(1) == 1)
return ll;
res = htonl(ll >> 32);
res |= (uint64_t)(htonl((uint32_t)ll)) << 32;
return res;
}
static inline uint64_t ntohll(uint64_t ll)
{
return htonll(ll);
}
#endif /* __LIBSDBFS_H__ */
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