diff --git a/sdbfs/kernel/sdb-fakedev.c b/sdbfs/kernel/sdb-fakedev.c index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d4d9f34a3707412e399ff71edf0217e09038e8ed 100644 --- a/sdbfs/kernel/sdb-fakedev.c +++ b/sdbfs/kernel/sdb-fakedev.c @@ -0,0 +1,105 @@ +/* + * 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 nimg; +static char *fsimg[8]; +module_param_array(fsimg, charp, &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, u8 *buf, + size_t count) +{ + struct fakedev *fd; + int len; + + 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, "sdbfs-fakedev"); + 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 < nimg; i++) { + d = fakedev_devs + i; + if (request_firmware(&d->fw, fsimg[i], &fakedev_device) < 0) { + printk("%s: can't load %s\n", KBUILD_MODNAME, + fsimg[i]); + continue; + } + d->sd.name = fsimg[i]; + d->sd.blocksize = 64; /* bah! */ + d->sd.ops = &fakedev_ops; + if (sdbfs_register_device(&d->sd) < 0) { + printk("%s: can't register %s\n", KBUILD_MODNAME, + 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 < 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);