Commit 75d8a181 authored by Alessandro Rubini's avatar Alessandro Rubini Committed by Federico Vaga

sdbfs: removed all kernel/ subdir, it's going to be a bus, not a filesystem

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent e09cc617
LINUX ?= /lib/modules/$(shell uname -r)/build
# get sdb.h from ../include/linux/
ccflags-y = -I$M/../include
obj-m = sdbfs.o
obj-m += sdb-fakedev.o
obj-m += sdb-iomem.o
sdbfs-y = sdbfs-core.o
sdbfs-y += sdbfs-file.o
sdbfs-y += sdbfs-inode.o
sdbfs-y += sdbfs-client.o
all: modules
install: modules_install
modules clean modules_install:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) $@
/*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/firmware.h>
#include "sdbfs.h"
/* We register up to 8 filesystems getting the names as module parameters */
static int fakedev_nimg;
static char *fakedev_fsimg[8];
module_param_array_named(fsimg, fakedev_fsimg, charp, &fakedev_nimg, 0444);
struct fakedev {
struct sdbfs_dev sd;
const struct firmware *fw;
};
static struct fakedev fakedev_devs[8];
static struct device fakedev_device;
static ssize_t fakedev_read(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count)
{
struct fakedev *fd;
int len;
printk("%s: %08x - %i\n", __func__, (int)begin, count);
fd = container_of(sd, struct fakedev, sd);
len = fd->fw->size;
if (begin > len)
return -EINVAL;
if (begin + count > len)
count = len - begin;
memcpy(buf, fd->fw->data + begin, count);
return count;
}
static struct sdbfs_dev_ops fakedev_ops = {
.owner = THIS_MODULE,
.erase = NULL,
.read = fakedev_read,
.write = NULL,
};
static int fakedev_init(void)
{
struct fakedev *d;
int i;
/* we need a device to request a firmware image */
dev_set_name(&fakedev_device, KBUILD_MODNAME);
device_initialize(&fakedev_device);
i = device_add(&fakedev_device);
if (i < 0) {
printk("%s: failed to init device (error %i)\n",
KBUILD_MODNAME, i);
return i;
}
for (i = 0; i < fakedev_nimg; i++) {
d = fakedev_devs + i;
if (request_firmware(&d->fw, fakedev_fsimg[i],
&fakedev_device) < 0) {
dev_err(&fakedev_device, "can't load %s\n",
fakedev_fsimg[i]);
continue;
}
d->sd.name = fakedev_fsimg[i];
d->sd.blocksize = 64; /* bah! */
d->sd.size = d->fw->size;
d->sd.ops = &fakedev_ops;
if (sdbfs_register_device(&d->sd) < 0) {
dev_err(&fakedev_device, "can't register %s\n",
fakedev_fsimg[i]);
release_firmware(d->fw);
d->fw = NULL;
}
}
return 0;
}
static void fakedev_exit(void)
{
struct fakedev *d;
int i;
for (i = 0; i < fakedev_nimg; i++) {
d = fakedev_devs + i;
if (!d->fw)
continue;
sdbfs_unregister_device(&d->sd);
release_firmware(d->fw);
}
device_del(&fakedev_device);
}
module_init(fakedev_init);
module_exit(fakedev_exit);
MODULE_LICENSE("GPL");
/*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/sdb.h>
#include "sdbfs.h"
struct sdbmem {
struct sdbfs_dev sd;
void __iomem *address;
size_t datalen;
int ready;
};
/* We register up to 8 filesystems getting the description at insmod */
static int sdbmem_narea;
static char *sdbmem_area[8];
module_param_array_named(area, sdbmem_area, charp, &sdbmem_narea, 0444);
/*
* area=<name>@<address>-<address>[=<entrypoint>]
* area=<name>@<address>+<lenght>[=<entrypoint>]
*/
static int sdbmem_parse(char *desc, struct sdbmem *d)
{
unsigned long addr, size;
char *at;
int i;
char c;
memset(d, 0, sizeof(*d));
at = strchr(desc, '@');
if (!at)
return -EINVAL;
i = sscanf(at,"@%lx+%lx=%lx%c", &addr, &size,
&d->sd.entrypoint, &c);
if (i == 1) {
i = sscanf(at,"@%lx-%lx=%lx%c", &addr, &size,
&d->sd.entrypoint, &c);
size -= addr;
}
if (i < 2 || i > 3) {
pr_err("%s: wrong argument \"%s\"\n", KBUILD_MODNAME,
desc);
pr_err("Use \"<name>@<addr>[-+]<addr>[=<entrypoint>\"\n");
return -EINVAL;
}
/* So, the name is the first one and there is the '@' sign */
*at = '\0';
d->sd.name = desc;
d->address = ioremap(addr, size);
if (!d->address)
return -ENOMEM;
d->sd.size = d->datalen = size;
return 0;
}
static struct sdbmem sdbmem_devs[8];
static ssize_t sdbmem_read(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count)
{
struct sdbmem *fd;
size_t len;
printk("%s: %08x - %i\n", __func__, (int)begin, count);
fd = container_of(sd, struct sdbmem, sd);
len = fd->datalen;
if (begin > len)
return -EINVAL;
if (begin + count > len)
count = len - begin;
memcpy_fromio(buf, fd->address + begin, count);
return count;
}
static struct sdbfs_dev_ops sdbmem_ops = {
.owner = THIS_MODULE,
.erase = NULL,
.read = sdbmem_read,
.write = NULL,
};
/* FIXME: export the register and unregister functions for external users */
static int sdbmem_init(void)
{
struct sdbmem *d;
int i, done = 0;
uint32_t magic;
for (i = 0; i < sdbmem_narea; i++) {
d = sdbmem_devs + i;
if (sdbmem_parse(sdbmem_area[i], d) < 0)
continue;
/* Check the magic number, so we fail ASAP */
magic = readl(d->address + d->sd.entrypoint);
if (magic != SDB_MAGIC && magic != ntohl(SDB_MAGIC)) {
iounmap(d->address);
pr_err("%s: wrong magic 0x%08x at 0x%lx\n", __func__,
magic, d->sd.entrypoint);
continue;
}
d->sd.blocksize = 4; /* bah! */
d->sd.ops = &sdbmem_ops;
if (sdbfs_register_device(&d->sd) < 0) {
pr_err("%s: can't register area %s\n", KBUILD_MODNAME,
d->sd.name);
continue;
}
done++;
d->ready = 1;
}
if (done)
return 0;
return -ENODEV;
}
static void sdbmem_exit(void)
{
struct sdbmem *d;
int i;
for (i = 0; i < sdbmem_narea; i++) {
d = sdbmem_devs + i;
if (!d->ready)
continue;
sdbfs_unregister_device(&d->sd);
iounmap(d->address);
}
}
module_init(sdbmem_init);
module_exit(sdbmem_exit);
MODULE_LICENSE("GPL");
/*
* 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.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/sdb.h> /* in ../include, by now */
#include "sdbfs.h"
#include "sdbfs-int.h"
static LIST_HEAD(sdbfs_devlist);
struct sdbfs_dev *sdbfs_get_by_name(char *name)
{
struct sdbfs_dev *sd;
list_for_each_entry(sd, &sdbfs_devlist, list)
if (!strcmp(sd->name, name))
goto found;
return ERR_PTR(-ENOENT);
found:
if (try_module_get(sd->ops->owner)) {
printk("%s: %p\n", __func__, sd);
return sd;
}
return ERR_PTR(-ENOENT);
}
void sdbfs_put(struct sdbfs_dev *sd)
{
printk("%s: %p\n", __func__, sd);
module_put(sd->ops->owner);
}
/* Exported functions */
int sdbfs_register_device(struct sdbfs_dev *sd)
{
struct sdbfs_dev *osd;
list_for_each_entry(osd, &sdbfs_devlist, list)
if (!strcmp(osd->name, sd->name))
return -EBUSY;
list_add(&sd->list, &sdbfs_devlist);
list_for_each_entry(osd, &sdbfs_devlist, list)
printk("list entry %p\n", osd);
return 0;
}
EXPORT_SYMBOL(sdbfs_register_device);
void sdbfs_unregister_device(struct sdbfs_dev *sd)
{
struct sdbfs_dev *osd;
list_for_each_entry(osd, &sdbfs_devlist, list)
printk("list entry %p\n", osd);
printk("removing %p\n", sd);
list_for_each_entry(osd, &sdbfs_devlist, list)
if (osd == sd)
break;
if (osd == sd)
list_del(&sd->list);
}
EXPORT_SYMBOL(sdbfs_unregister_device);
/*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/sdb.h> /* in ../include, by now */
#include "sdbfs-int.h"
static const struct super_operations sdbfs_super_ops = {
.alloc_inode = sdbfs_alloc_inode,
.destroy_inode = sdbfs_destroy_inode,
};
static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
struct sdbfs_dev *sd;
uint32_t magic;
printk("%s\n", __func__);
/* HACK: this data is really a name */
sd = sdbfs_get_by_name(data);
if (IS_ERR(sd))
return PTR_ERR(sd);
sb->s_fs_info = sd;
/* Check magic number first */
sd->ops->read(sd, sd->entrypoint, &magic, 4);
if (magic == ntohl(SDB_MAGIC)) {
/* all right: we are big endian or byte-level connected */
} else if (magic == SDB_MAGIC) {
/* looks like we are little-endian on a 32-bit-only bus */
sd->flags |= SDBFS_F_FIXENDIAN;
} else {
printk("%s: wrong magic at 0x%lx (%08x is not %08x)\n",
__func__, sd->entrypoint, magic, SDB_MAGIC);
return -EINVAL;
}
/* All of our data is organized as 64-byte blocks */
sb->s_blocksize = 64;
sb->s_blocksize_bits = 6;
sb->s_magic = SDB_MAGIC;
sb->s_op = &sdbfs_super_ops;
/* The root inode is 1. It is a fake bridge and has no parent. */
inode = sdbfs_iget(NULL, sb, SDBFS_ROOT);
if (IS_ERR(inode)) {
sdbfs_put(sd);
return PTR_ERR(inode);
}
/*
* Instantiate and link root dentry. d_make_root only exists
* after 3.2, but d_alloc_root was killed soon after 3.3
*/
root = d_make_root(inode);
if (!root) {
sdbfs_put(sd);
/* FIXME: release inode? */
return -ENOMEM;
}
root->d_fsdata = NULL; /* FIXME: d_fsdata */
sb->s_root = root;
return 0;
}
static struct dentry *sdbfs_mount(struct file_system_type *type, int flags,
const char *name, void *data)
{
struct dentry *ret;
char *fakedata = (char *)name;
/* HACK: use "name" as data, to use the mount_single helper */
ret = mount_single(type, flags, fakedata, sdbfs_fill_super);
printk("%s: %p\n", __func__, ret);
return ret;
}
static void sdbfs_kill_sb(struct super_block *sb)
{
struct sdbfs_dev *sd = sb->s_fs_info;
printk("%s\n", __func__);
kill_anon_super(sb);
if (sd)
sdbfs_put(sd);
}
static struct file_system_type sdbfs_fs_type = {
.owner = THIS_MODULE,
.name = "sdbfs",
.mount = sdbfs_mount, /* 2.6.37 and later only */
.kill_sb = sdbfs_kill_sb,
};
struct kmem_cache *sdbfs_inode_cache;
static int __init sdbfs_init(void)
{
sdbfs_inode_cache = KMEM_CACHE(sdbfs_inode, 0);
if (!sdbfs_inode_cache)
return -ENOMEM;
return register_filesystem(&sdbfs_fs_type);
return 0;
}
static void __exit sdbfs_exit(void)
{
unregister_filesystem(&sdbfs_fs_type);
kmem_cache_destroy(sdbfs_inode_cache);
}
module_init(sdbfs_init);
module_exit(sdbfs_exit);
MODULE_LICENSE("GPL");
/*
* 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.
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "sdbfs-int.h"
static ssize_t sdbfs_read(struct file *f, char __user *buf, size_t count,
loff_t *offp)
{
struct inode *ino = f->f_dentry->d_inode;
struct super_block *sb = ino->i_sb;
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode;
char kbuf[16];
unsigned long start, size;
ssize_t i, done;
inode = container_of(ino, struct sdbfs_inode, ino);
start = be64_to_cpu(inode->info.s_d.sdb_component.addr_first);
size = be64_to_cpu(inode->info.s_d.sdb_component.addr_last) + 1 - start;
if (*offp > size)
return 0;
if (*offp + count > size)
count = size - *offp;
done = 0;
while (done < count) {
/* Horribly inefficient, just copy a few bytes at a time */
int n = sizeof(kbuf) > count ? count : sizeof(kbuf);
/* FIXME: error checking */
i = sd->ops->read(sd, start + *offp, kbuf, n);
if (i < 0) {
if (done)
return done;
return i;
}
if (copy_to_user(buf, kbuf, i))
return -EFAULT;
buf += i;
done += i;
if (i != n) {
/* Partial read: done for this time */
break;
}
}
*offp += done;
return done;
}
const struct file_operations sdbfs_fops = {
.read = sdbfs_read,
};
/*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/sdb.h> /* in ../include, by now */
#include "sdbfs-int.h"
static void sdbfs_fix_endian(struct sdbfs_dev *sd, void *ptr, int len)
{
uint32_t *p = ptr;
int i;
if (!(sd->flags & SDBFS_F_FIXENDIAN))
return;
if (len & 3)
return; /* Hmmm... */
for (i = 0; i < len / 4; i++)
p[i] = htonl(p[i]);
}
/* This is called by readdir and by lookup, when needed */
static int sdbfs_read_whole_dir(struct sdbfs_inode *inode)
{
struct sdbfs_info *info;
struct super_block *sb = inode->ino.i_sb;
struct sdbfs_dev *sd = sb->s_fs_info;
unsigned long offset;
int i, j, n;
if (inode->nfiles)
return 0;
printk("%s\n", __func__);
/* Get the interconnect and see how many */
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
n = sd->ops->read(sd, inode->base_sdb, &info->s_i, SDB_SIZE);
if (n != SDB_SIZE) {
kfree(info);
return -EIO;
}
sdbfs_fix_endian(sd, &info->s_i, SDB_SIZE);
if (info->s_i.sdb_magic != htonl(SDB_MAGIC)) {
pr_err("%s: wrong magic (%08x) at offset 0x%lx\n", __func__,
info->s_i.sdb_magic, inode->base_sdb);
kfree(info);
return -EINVAL;
}
inode->nfiles = be16_to_cpu(info->s_i.sdb_records);
kfree(info);
printk("nfiles %i\n", inode->nfiles);
info = kmalloc(sizeof(*info) * inode->nfiles, GFP_KERNEL);
if (!info) {
inode->nfiles = 0;
return -ENOMEM;
}
offset = inode->base_sdb;
printk("reading at 0x%lx\n", offset);
inode->files = info;
for (i = 0; i < inode->nfiles; i++) {
info = inode->files + i;
n = sd->ops->read(sd, offset, &info->s_d, SDB_SIZE);
if (n != SDB_SIZE) {
/* FIXME: iput? */
kfree(inode->files);
inode->nfiles = 0;
return -EIO;
}
sdbfs_fix_endian(sd, &info->s_d, SDB_SIZE);
strncpy(info->name,
info->s_d.sdb_component.product.name, 19);
for (j = 19; j; j--) {
info->name[j] = '\0';
if (info->name[j-1] != ' ')
break;
}
info->namelen = j;
offset += SDB_SIZE;
}
return 0;
}
static int sdbfs_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
struct inode *ino = filp->f_dentry->d_inode;
struct sdbfs_inode *inode;
struct sdbfs_info *info;
unsigned long offset;
int i, type, done = 0;
printk("%s\n", __func__);
/* dot and dotdot are special */
if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, 0, ino->i_ino, DT_DIR) < 0)
return done;
done++;
filp->f_pos++;
}
if (filp->f_pos == 1) {
if (filldir(dirent, "..", 2, 1,
parent_ino(filp->f_dentry), DT_DIR) < 0)
return done;
done++;
filp->f_pos++;
}
/* Then our stuff */
inode = container_of(ino, struct sdbfs_inode, ino);
sdbfs_read_whole_dir(inode);
offset = inode->base_sdb;
for (i = filp->f_pos - 2; i < inode->nfiles; i++) {
info = inode->files + i;
if (info->s_e.record_type == sdb_type_bridge)
type = DT_DIR;
else
type = DT_REG;
if (filldir(dirent, info->name, info->namelen,
SDBFS_INO(offset), i + 2 /* ? */, type) < 0)
return done;
filp->f_pos++;
done++;
}
return done;
}
static const struct file_operations sdbfs_dir_fops = {
.read = generic_read_dir,
.readdir = sdbfs_readdir,
.llseek = default_llseek,
};
static struct dentry *sdbfs_lookup(struct inode *dir,
struct dentry *dentry, struct nameidata *nd)
{
struct inode *ino = NULL;
struct sdbfs_inode *inode = container_of(dir, struct sdbfs_inode, ino);
struct sdbfs_info *info;
unsigned long offset = inode->base_sdb;
int i, n, len;
printk("%s\n", __func__);
sdbfs_read_whole_dir(inode);
n = inode->nfiles;
len = dentry->d_name.len;
for (i = 0; i < n; i++) {
info = inode->files + i;
if (info->namelen != len)
continue;
if (!strncmp(info->name, dentry->d_name.name, len))
break;
}
if (i != n) {
offset = offset + SDB_SIZE * i;
ino = sdbfs_iget(inode, dir->i_sb, SDBFS_INO(offset));
}
d_add(dentry, ino);
return 0;
}
static const struct inode_operations sdbfs_dir_iops = {
.lookup = sdbfs_lookup,
};
struct inode *sdbfs_alloc_inode(struct super_block *sb)
{
struct sdbfs_inode *inode;
printk("%s\n", __func__);
inode = kmem_cache_alloc(sdbfs_inode_cache, GFP_KERNEL);
if (!inode)
return NULL;
inode_init_once(&inode->ino);
printk("%s: return %p\n", __func__, &inode->ino);
return &inode->ino;
}
void sdbfs_destroy_inode(struct inode *ino)
{
struct sdbfs_inode *inode;
inode = container_of(ino, struct sdbfs_inode, ino);
kfree(inode->files);
kmem_cache_free(sdbfs_inode_cache, inode);
}
static struct inode *sdbfs_iget_root(struct super_block *sb,
struct inode *ino)
{
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode = container_of(ino, struct sdbfs_inode, ino);
struct sdb_bridge *b = &inode->info.s_b;
/* The root directory is a fake "bridge" structure */
memset(b, 0, sizeof(*b));
b->sdb_child = cpu_to_be64(sd->entrypoint);
b->sdb_component.addr_first = 0;
b->sdb_component.addr_last = cpu_to_be64(sd->size);
b->sdb_component.product.record_type = sdb_type_bridge;
/* So, this is a directory, and it links to the first interconnect */
inode->base_data = 0;
inode->base_sdb = sd->entrypoint;
ino->i_size = sd->size;
ino->i_mode = S_IFDIR | 0555;
ino->i_op = &sdbfs_dir_iops;
ino->i_fop = &sdbfs_dir_fops;
return ino;
}
struct inode *sdbfs_iget(struct sdbfs_inode *parent,
struct super_block *sb, unsigned long inum)
{
struct inode *ino;
struct sdbfs_dev *sd = sb->s_fs_info;
struct sdbfs_inode *inode;
uint32_t offset;
unsigned long size, base_data; /* target offset */
int n;
int type;
printk("%s: inum 0x%lx\n", __func__, inum);
ino = iget_locked(sb, inum);
if (!ino)
return ERR_PTR(-ENOMEM);
if (!(ino->i_state & I_NEW))
return ino;
/* general setup; no link concept: the structure is immutable */
set_nlink(ino, 1);
ino->i_mtime.tv_sec = ino->i_atime.tv_sec = ino->i_ctime.tv_sec = 0;
ino->i_mtime.tv_nsec = ino->i_atime.tv_nsec = ino->i_ctime.tv_nsec = 0;
if (unlikely(!parent)) { /* inum == SDBFS_ROOT */
sdbfs_iget_root(sb, ino);
unlock_new_inode(ino);
return ino;
}
inode = container_of(ino, struct sdbfs_inode, ino);
offset = SDBFS_OFFSET(inum);
n = sd->ops->read(sd, offset, &inode->info.s_d, SDB_SIZE);
if (n != SDB_SIZE)
return ERR_PTR(-EIO);
sdbfs_fix_endian(sd, &inode->info.s_d, SDB_SIZE);
base_data = be64_to_cpu(inode->info.s_d.sdb_component.addr_first);
size = be64_to_cpu(inode->info.s_d.sdb_component.addr_last)
- base_data + 1;
type = inode->info.s_e.record_type;
switch (type) {
case sdb_type_interconnect:
case sdb_type_device:
/* You can access internal registers/data */
ino->i_fop = &sdbfs_fops; /* FIXME: Which bus type? */
ino->i_mode = S_IFREG | 0444;
ino->i_size = size;
inode->base_data = parent->base_data + base_data;
break;
case sdb_type_bridge:
/* A bridge is a subdirectory */
ino->i_mode = S_IFDIR | 0555;
ino->i_op = &sdbfs_dir_iops;
ino->i_fop = &sdbfs_dir_fops;
inode->base_data = parent->base_data + base_data;
inode->base_sdb = parent->base_data
+ be64_to_cpu(inode->info.s_b.sdb_child);
break;
default:
if (type & 0x80) /* informative only */
pr_info("%s: ignoring unknown record 0x%02x\n",
__func__, type);
else
pr_err("%s: unsupported record 0x%02x\n",
__func__, type);
break;
}
unlock_new_inode(ino);
return ino;
}
/*
* 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.
*/
#ifndef __SDBFS_INT_H__
#define __SDBFS_INT_H__
#include <linux/fs.h>
#include <linux/sdb.h>
#include "sdbfs.h"
/* This is our mapping of inode numbers */
#define SDBFS_ROOT 1
#define SDBFS_INO(offset) ((offset) + 2)
#define SDBFS_OFFSET(ino) ((ino) & ~15)
#define SDB_SIZE (sizeof(struct sdb_device))
struct sdbfs_info {
/* unnamed union to save typing */
union {
struct sdb_device s_d;
struct sdb_interconnect s_i;
struct sdb_bridge s_b;
struct sdb_empty s_e;
};
char name[20]; /* 19 + terminator */
int namelen;
};
struct sdbfs_inode {
struct sdbfs_info info;
int nfiles;
struct sdbfs_info *files; /* for directories */
struct inode ino;
/* below, the former is the base for relative addresses */
unsigned long base_data;
unsigned long base_sdb;
};
/* 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);
}
/* Material in sdbfs-file.c */
extern const struct file_operations sdbfs_fops;
/* Material in sdbfs-inode.c */
struct inode *sdbfs_alloc_inode(struct super_block *sb);
void sdbfs_destroy_inode(struct inode *ino);
struct inode *sdbfs_iget(struct sdbfs_inode *parent,
struct super_block *sb, unsigned long inum);
extern struct kmem_cache *sdbfs_inode_cache;
#endif /* __SDBFS_INT_H__ */
/*
* 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.
*/
#ifndef __SDBFS_H__
#define __SDBFS_H__
struct sdbfs_dev;
/*
* Client modules register sdbfs-capable devices, and several of them
* may use the same hardware abstraction, so separate it. We use 32-bit
* addresses, being aware of potential issues, but our target is small
* devices accessed by a soft-core. If the need arises, we'll add erase64
* and similar methods.
*/
struct sdbfs_dev_ops {
struct module *owner;
int (*erase)(struct sdbfs_dev *sd, uint32_t begin, uint32_t end);
ssize_t (*read)(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count);
ssize_t (*write)(struct sdbfs_dev *sd, uint32_t begin, void *buf,
size_t count);
};
struct sdbfs_dev {
char *name;
unsigned long flags;
int blocksize;
unsigned long entrypoint;
struct sdbfs_dev_ops *ops;
struct list_head list;
unsigned long size;
/* Following is private to the FS code */
unsigned long ino_base;
};
/* flags */
#define SDBFS_F_FIXENDIAN 0x0001
/* Internal inter-file calls */
struct sdbfs_dev *sdbfs_get_by_name(char *name);
void sdbfs_put(struct sdbfs_dev *sd);
/* Exported to other modules */
int sdbfs_register_device(struct sdbfs_dev *sd);
void sdbfs_unregister_device(struct sdbfs_dev *sd);
#endif /* __SDBFS_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