diff --git a/sdbfs/kernel/Makefile b/sdbfs/kernel/Makefile
index ed29311c6227068dc13f4e7e75381591ea7881a4..44f5de2c4ddb88098436234de04bbc97eb773661 100644
--- a/sdbfs/kernel/Makefile
+++ b/sdbfs/kernel/Makefile
@@ -9,8 +9,8 @@ obj-m += sdb-iomem.o
 
 sdbfs-y = sdbfs-core.o
 sdbfs-y += sdbfs-file.o
-sdbfs-y += sdbfs-devmem.o
-sdbfs-y += sdbfs-device.o
+sdbfs-y += sdbfs-inode.o
+sdbfs-y += sdbfs-client.o
 
 all: modules
 
diff --git a/sdbfs/kernel/sdbfs-device.c b/sdbfs/kernel/sdbfs-client.c
similarity index 100%
rename from sdbfs/kernel/sdbfs-device.c
rename to sdbfs/kernel/sdbfs-client.c
diff --git a/sdbfs/kernel/sdbfs-core.c b/sdbfs/kernel/sdbfs-core.c
index 63be89c3ccd6ea5e048eb3aea9a0fdaa487d0b73..aa9d16dbae8c62d1641b84292f6bc89712d20c77 100644
--- a/sdbfs/kernel/sdbfs-core.c
+++ b/sdbfs/kernel/sdbfs-core.c
@@ -14,361 +14,14 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/sdb.h> /* in ../include, by now */
-#include <linux/uaccess.h>
 
-#include "sdbfs.h"
 #include "sdbfs-int.h"
 
-#define SDB_SIZE (sizeof(struct sdb_device))
-
-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 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;
-}
-
-static const struct file_operations sdbfs_fops = {
-	.read		= sdbfs_read,
-};
-static struct inode *sdbfs_iget(struct sdbfs_inode *parent,
-				struct super_block *sb, unsigned long inum);
-
-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,
-};
-
-static struct kmem_cache *sdbfs_inode_cache;
-
-static 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;
-}
-
-static 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 const struct super_operations sdbfs_super_ops = {
 	.alloc_inode    = sdbfs_alloc_inode,
 	.destroy_inode  = sdbfs_destroy_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;
-}
-
-static 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;
-}
-
 static int sdbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
@@ -454,7 +107,9 @@ static struct file_system_type sdbfs_fs_type = {
 	.kill_sb	= sdbfs_kill_sb,
 };
 
-static int sdbfs_init(void)
+struct kmem_cache *sdbfs_inode_cache;
+
+static int __init sdbfs_init(void)
 {
 	sdbfs_inode_cache = KMEM_CACHE(sdbfs_inode, 0);
 	if (!sdbfs_inode_cache)
@@ -463,7 +118,7 @@ static int sdbfs_init(void)
 	return 0;
 }
 
-static void sdbfs_exit(void)
+static void __exit sdbfs_exit(void)
 {
 	unregister_filesystem(&sdbfs_fs_type);
 	kmem_cache_destroy(sdbfs_inode_cache);
diff --git a/sdbfs/kernel/sdbfs-devmem.c b/sdbfs/kernel/sdbfs-devmem.c
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/sdbfs/kernel/sdbfs-file.c b/sdbfs/kernel/sdbfs-file.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..15a742f8ec4d3aa0598d3d22a23ab398afeb4bb9 100644
--- a/sdbfs/kernel/sdbfs-file.c
+++ b/sdbfs/kernel/sdbfs-file.c
@@ -0,0 +1,62 @@
+/*
+ * 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,
+};
diff --git a/sdbfs/kernel/sdbfs-inode.c b/sdbfs/kernel/sdbfs-inode.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f21b5838453a4c8cce8d2090e37a4e3e520a032
--- /dev/null
+++ b/sdbfs/kernel/sdbfs-inode.c
@@ -0,0 +1,309 @@
+/*
+ * 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;
+}
diff --git a/sdbfs/kernel/sdbfs-int.h b/sdbfs/kernel/sdbfs-int.h
index 05a54f79748fe29b58105d318042fe451ce258a6..f20cdb9a3bffc548f76c5fad3d7518039171f812 100644
--- a/sdbfs/kernel/sdbfs-int.h
+++ b/sdbfs/kernel/sdbfs-int.h
@@ -12,11 +12,16 @@
 #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 {
@@ -55,4 +60,18 @@ 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__ */