From f4d8de48f5a2aa1885daa0d425b8c0568a2ccb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Nordstr=C3=B6m?= Date: Sun, 10 Nov 2013 10:26:56 -0700 Subject: sandbox: block driver using host file/device as backing store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a way to use any host file or device as a block device in U-Boot. This can be used to provide filesystem access within U-Boot to an ext2 image file on the host, for example. The support is plumbed into the filesystem and partition interfaces. We don't want to print a message in the driver every time we find a missing device. Pass the information back to the caller where a message can be printed if desired. Signed-off-by: Henrik Nordström Signed-off-by: Simon Glass - Removed change to part.c get_device_and_partition() Signed-off-by: Simon Glass Reviewed-by: Simon Glass --- drivers/block/Makefile | 1 + drivers/block/sandbox.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 drivers/block/sandbox.c (limited to 'drivers') diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 4e94378388..8697da4262 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc.o obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_IDE_SIL680) += sil680.o +obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o obj-$(CONFIG_SYSTEMACE) += systemace.o diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c new file mode 100644 index 0000000000..73f4c4a9e9 --- /dev/null +++ b/drivers/block/sandbox.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2013 Henrik Nordstrom + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES]; + +static struct host_block_dev *find_host_device(int dev) +{ + if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES) + return &host_devices[dev]; + + return NULL; +} + +static unsigned long host_block_read(int dev, unsigned long start, + lbaint_t blkcnt, void *buffer) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -1; + if (os_lseek(host_dev->fd, + start * host_dev->blk_dev.blksz, + OS_SEEK_SET) == -1) { + printf("ERROR: Invalid position\n"); + return -1; + } + ssize_t len = os_read(host_dev->fd, buffer, + blkcnt * host_dev->blk_dev.blksz); + if (len >= 0) + return len / host_dev->blk_dev.blksz; + return -1; +} + +static unsigned long host_block_write(int dev, unsigned long start, + lbaint_t blkcnt, const void *buffer) +{ + struct host_block_dev *host_dev = find_host_device(dev); + if (os_lseek(host_dev->fd, + start * host_dev->blk_dev.blksz, + OS_SEEK_SET) == -1) { + printf("ERROR: Invalid position\n"); + return -1; + } + ssize_t len = os_write(host_dev->fd, buffer, blkcnt * + host_dev->blk_dev.blksz); + if (len >= 0) + return len / host_dev->blk_dev.blksz; + return -1; +} + +int host_dev_bind(int dev, char *filename) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -1; + if (host_dev->blk_dev.priv) { + os_close(host_dev->fd); + host_dev->blk_dev.priv = NULL; + } + if (host_dev->filename) + free(host_dev->filename); + if (filename && *filename) { + host_dev->filename = strdup(filename); + } else { + host_dev->filename = NULL; + return 0; + } + + host_dev->fd = os_open(host_dev->filename, OS_O_RDWR); + if (host_dev->fd == -1) { + printf("Failed to access host backing file '%s'\n", + host_dev->filename); + return 1; + } + + block_dev_desc_t *blk_dev = &host_dev->blk_dev; + blk_dev->if_type = IF_TYPE_HOST; + blk_dev->priv = host_dev; + blk_dev->blksz = 512; + blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz; + blk_dev->block_read = host_block_read; + blk_dev->block_write = host_block_write; + blk_dev->dev = dev; + blk_dev->part_type = PART_TYPE_UNKNOWN; + init_part(blk_dev); + + return 0; +} + +int host_get_dev_err(int dev, block_dev_desc_t **blk_devp) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -ENODEV; + + if (!host_dev->blk_dev.priv) + return -ENOENT; + + *blk_devp = &host_dev->blk_dev; + return 0; +} + +block_dev_desc_t *host_get_dev(int dev) +{ + block_dev_desc_t *blk_dev; + + if (host_get_dev_err(dev, &blk_dev)) + return NULL; + + return blk_dev; +} -- cgit v1.2.3