mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-17 02:08:38 +00:00
143 lines
2.9 KiB
C
143 lines
2.9 KiB
C
|
// SPDX-License-Identifier: GPL-2.0+
|
||
|
/*
|
||
|
* Driver for sandbox host interface, used to access files on the host which
|
||
|
* contain partitions and filesystem
|
||
|
*
|
||
|
* Copyright 2022 Google LLC
|
||
|
* Written by Simon Glass <sjg@chromium.org>
|
||
|
*/
|
||
|
|
||
|
#define LOG_CATEGORY UCLASS_HOST
|
||
|
|
||
|
#include <common.h>
|
||
|
#include <blk.h>
|
||
|
#include <bootdev.h>
|
||
|
#include <dm.h>
|
||
|
#include <log.h>
|
||
|
#include <malloc.h>
|
||
|
#include <os.h>
|
||
|
#include <sandbox_host.h>
|
||
|
#include <dm/device-internal.h>
|
||
|
|
||
|
static int host_sb_attach_file(struct udevice *dev, const char *filename)
|
||
|
{
|
||
|
struct host_sb_plat *plat = dev_get_plat(dev);
|
||
|
struct blk_desc *desc;
|
||
|
struct udevice *blk;
|
||
|
int ret, fd, size;
|
||
|
char *fname;
|
||
|
|
||
|
if (!filename)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (plat->fd)
|
||
|
return log_msg_ret("fd", -EEXIST);
|
||
|
|
||
|
/* Sanity check that host_sb_bind() has been used */
|
||
|
ret = blk_find_from_parent(dev, &blk);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
fd = os_open(filename, OS_O_RDWR);
|
||
|
if (fd == -1) {
|
||
|
printf("Failed to access host backing file '%s', trying read-only\n",
|
||
|
filename);
|
||
|
fd = os_open(filename, OS_O_RDONLY);
|
||
|
if (fd == -1) {
|
||
|
printf("- still failed\n");
|
||
|
return log_msg_ret("open", -ENOENT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fname = strdup(filename);
|
||
|
if (!fname) {
|
||
|
ret = -ENOMEM;
|
||
|
goto err_fname;
|
||
|
}
|
||
|
|
||
|
size = os_filesize(fd);
|
||
|
desc = dev_get_uclass_plat(blk);
|
||
|
desc->lba = size / desc->blksz;
|
||
|
|
||
|
/* write this in last, when nothing can go wrong */
|
||
|
plat = dev_get_plat(dev);
|
||
|
plat->fd = fd;
|
||
|
plat->filename = fname;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
err_fname:
|
||
|
os_close(fd);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int host_sb_detach_file(struct udevice *dev)
|
||
|
{
|
||
|
struct host_sb_plat *plat = dev_get_plat(dev);
|
||
|
int ret;
|
||
|
|
||
|
if (!plat->fd)
|
||
|
return log_msg_ret("fd", -ENOENT);
|
||
|
|
||
|
ret = device_remove(dev, DM_REMOVE_NORMAL);
|
||
|
if (ret)
|
||
|
return log_msg_ret("rem", ret);
|
||
|
|
||
|
/* Unbind all children */
|
||
|
ret = device_chld_unbind(dev, NULL);
|
||
|
if (ret)
|
||
|
return log_msg_ret("unb", ret);
|
||
|
|
||
|
os_close(plat->fd);
|
||
|
plat->fd = 0;
|
||
|
free(plat->filename);
|
||
|
free(plat->label);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int host_sb_bind(struct udevice *dev)
|
||
|
{
|
||
|
struct udevice *blk, *bdev;
|
||
|
struct blk_desc *desc;
|
||
|
int ret;
|
||
|
|
||
|
ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
|
||
|
dev_seq(dev), 512, 0, &blk);
|
||
|
if (ret)
|
||
|
return log_msg_ret("blk", ret);
|
||
|
|
||
|
desc = dev_get_uclass_plat(blk);
|
||
|
snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
|
||
|
snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
|
||
|
snprintf(desc->revision, BLK_REV_SIZE, "1.0");
|
||
|
|
||
|
if (CONFIG_IS_ENABLED(BOOTSTD)) {
|
||
|
ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev);
|
||
|
if (ret)
|
||
|
return log_msg_ret("bd", ret);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct host_ops host_sb_ops = {
|
||
|
.attach_file = host_sb_attach_file,
|
||
|
.detach_file = host_sb_detach_file,
|
||
|
};
|
||
|
|
||
|
static const struct udevice_id host_ids[] = {
|
||
|
{ .compatible = "sandbox,host" },
|
||
|
{ }
|
||
|
};
|
||
|
|
||
|
U_BOOT_DRIVER(host_sb_drv) = {
|
||
|
.name = "host_sb_drv",
|
||
|
.id = UCLASS_HOST,
|
||
|
.of_match = host_ids,
|
||
|
.ops = &host_sb_ops,
|
||
|
.bind = host_sb_bind,
|
||
|
.plat_auto = sizeof(struct host_sb_plat),
|
||
|
};
|