diff options
Diffstat (limited to 'arch/sandbox/board/hostfile.c')
-rw-r--r-- | arch/sandbox/board/hostfile.c | 118 |
1 files changed, 94 insertions, 24 deletions
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c index 5f0d7e0a4b..63530bd25e 100644 --- a/arch/sandbox/board/hostfile.c +++ b/arch/sandbox/board/hostfile.c @@ -16,6 +16,8 @@ #include <common.h> #include <driver.h> +#include <block.h> +#include <disks.h> #include <malloc.h> #include <mach/linux.h> #include <init.h> @@ -27,14 +29,16 @@ #include <linux/err.h> struct hf_priv { - struct cdev cdev; + union { + struct block_device blk; + struct cdev cdev; + }; const char *filename; int fd; }; -static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) +static ssize_t hf_read(struct hf_priv *priv, void *buf, size_t count, loff_t offset, ulong flags) { - struct hf_priv *priv= cdev->priv; int fd = priv->fd; if (linux_lseek(fd, offset) != offset) @@ -43,9 +47,8 @@ static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset return linux_read(fd, buf, count); } -static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) +static ssize_t hf_write(struct hf_priv *priv, const void *buf, size_t count, loff_t offset, ulong flags) { - struct hf_priv *priv = cdev->priv; int fd = priv->fd; if (linux_lseek(fd, offset) != offset) @@ -54,6 +57,40 @@ static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t return linux_write(fd, buf, count); } +static ssize_t hf_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) +{ + return hf_read(cdev->priv, buf, count, offset, flags); +} + +static ssize_t hf_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) +{ + return hf_write(cdev->priv, buf, count, offset, flags); +} + +static struct cdev_operations hf_cdev_ops = { + .read = hf_cdev_read, + .write = hf_cdev_write, +}; + +static int hf_blk_read(struct block_device *blk, void *buf, int block, int num_blocks) +{ + ssize_t ret = hf_read(container_of(blk, struct hf_priv, blk), buf, + num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0); + return ret > 0 ? 0 : ret; +} + +static int hf_blk_write(struct block_device *blk, const void *buf, int block, int num_blocks) +{ + ssize_t ret = hf_write(container_of(blk, struct hf_priv, blk), buf, + num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0); + return ret > 0 ? 0 : ret; +} + +static struct block_device_ops hf_blk_ops = { + .read = hf_blk_read, + .write = hf_blk_write, +}; + static void hf_info(struct device_d *dev) { struct hf_priv *priv = dev->priv; @@ -61,29 +98,28 @@ static void hf_info(struct device_d *dev) printf("file: %s\n", priv->filename); } -static struct cdev_operations hf_fops = { - .read = hf_read, - .write = hf_write, -}; - static int hf_probe(struct device_d *dev) { + struct device_node *np = dev->device_node; struct hf_priv *priv = xzalloc(sizeof(*priv)); struct resource *res; + struct cdev *cdev; + bool is_blockdev; + resource_size_t size; int err; res = dev_get_resource(dev, IORESOURCE_MEM, 0); if (IS_ERR(res)) return PTR_ERR(res); - priv->cdev.size = resource_size(res); + size = resource_size(res); - if (!dev->device_node) + if (!np) return -ENODEV; - of_property_read_u32(dev->device_node, "barebox,fd", &priv->fd); + of_property_read_u32(np, "barebox,fd", &priv->fd); - err = of_property_read_string(dev->device_node, "barebox,filename", + err = of_property_read_string(np, "barebox,filename", &priv->filename); if (err) return err; @@ -91,20 +127,50 @@ static int hf_probe(struct device_d *dev) if (!priv->fd) priv->fd = linux_open(priv->filename, true); - priv->cdev.name = dev->device_node->name; - priv->cdev.dev = dev; - priv->cdev.ops = &hf_fops; - priv->cdev.priv = priv; + if (priv->fd < 0) + return priv->fd; dev->info = hf_info; dev->priv = priv; - err = devfs_create(&priv->cdev); - if (err) - return err; + is_blockdev = of_property_read_bool(np, "barebox,blockdev"); + + cdev = is_blockdev ? &priv->blk.cdev : &priv->cdev; + + cdev->device_node = np; + + if (is_blockdev) { + cdev->name = np->name; + priv->blk.dev = dev; + priv->blk.ops = &hf_blk_ops; + priv->blk.blockbits = SECTOR_SHIFT; + priv->blk.num_blocks = size / SECTOR_SIZE; - of_parse_partitions(&priv->cdev, dev->device_node); - of_partitions_register_fixup(&priv->cdev); + err = blockdevice_register(&priv->blk); + if (err) + return err; + + err = parse_partition_table(&priv->blk); + if (err) + dev_warn(dev, "No partition table found\n"); + + dev_info(dev, "registered as block device\n"); + } else { + cdev->name = np->name; + cdev->dev = dev; + cdev->ops = &hf_cdev_ops; + cdev->size = size; + cdev->priv = priv; + + err = devfs_create(cdev); + if (err) + return err; + + dev_info(dev, "registered as character device\n"); + } + + of_parse_partitions(cdev, np); + of_partitions_register_fixup(cdev); return 0; } @@ -122,7 +188,7 @@ static struct driver_d hf_drv = { .of_compatible = DRV_OF_COMPAT(hostfile_dt_ids), .probe = hf_probe, }; -coredevice_platform_driver(hf_drv); +device_platform_driver(hf_drv); static int of_hostfile_fixup(struct device_node *root, void *ctx) { @@ -131,6 +197,7 @@ static int of_hostfile_fixup(struct device_node *root, void *ctx) uint32_t reg[] = { hf->base >> 32, hf->base, + hf->size >> 32, hf->size }; int ret; @@ -151,6 +218,9 @@ static int of_hostfile_fixup(struct device_node *root, void *ctx) ret = of_property_write_string(node, "barebox,filename", hf->filename); + if (hf->is_blockdev) + ret = of_property_write_bool(node, "barebox,blockdev", true); + return ret; } |