dm: sandbox: Create a new HOST uclass

Sandbox supports block devices which can access files on the host machine.
At present there is no uclass for this. The devices are attached to the
root devic. The block-device type is therefore set to UCLASS_ROOT which
is confusing.

Block devices should be attached to a 'media' device instead, something
which handles access to the actual media and provides the block driver
for the block device.

Create a new uclass to handle this. It supports two operations, to attach
and detach a file on the host machine.

For now this is not fully plumbed in.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-10-29 19:47:15 -06:00
parent 41e751091d
commit 9bd1aa8af2
4 changed files with 303 additions and 1 deletions

View File

@ -12,7 +12,7 @@ endif
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_IDE) += ide.o
endif
obj-$(CONFIG_SANDBOX) += sandbox.o
obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o
obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o

176
drivers/block/host-uclass.c Normal file
View File

@ -0,0 +1,176 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Uclass 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 <dm.h>
#include <malloc.h>
#include <sandbox_host.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct host_priv - information kept by the host uclass
*
* @cur_dev: Currently selected host device, or NULL if none
*/
struct host_priv {
struct udevice *cur_dev;
};
int host_create_device(const char *label, bool removable, struct udevice **devp)
{
char dev_name[30], *str, *label_new;
struct host_sb_plat *plat;
struct udevice *dev, *blk;
int ret;
/* unbind any existing device with this label */
dev = host_find_by_label(label);
if (dev) {
ret = host_detach_file(dev);
if (ret)
return log_msg_ret("det", ret);
ret = device_unbind(dev);
if (ret)
return log_msg_ret("unb", ret);
}
snprintf(dev_name, sizeof(dev_name), "host-%s", label);
str = strdup(dev_name);
if (!str)
return -ENOMEM;
label_new = strdup(label);
if (!label_new) {
ret = -ENOMEM;
goto no_label;
}
ret = device_bind_driver(gd->dm_root, "host_sb_drv", str, &dev);
if (ret)
goto no_dev;
device_set_name_alloced(dev);
if (!blk_find_from_parent(dev, &blk)) {
struct blk_desc *desc = dev_get_uclass_plat(blk);
desc->removable = removable;
}
plat = dev_get_plat(dev);
plat->label = label_new;
*devp = dev;
return 0;
no_dev:
free(label_new);
no_label:
free(str);
return ret;
}
int host_attach_file(struct udevice *dev, const char *filename)
{
struct host_ops *ops = host_get_ops(dev);
if (!ops->attach_file)
return -ENOSYS;
return ops->attach_file(dev, filename);
}
int host_create_attach_file(const char *label, const char *filename,
bool removable, struct udevice **devp)
{
struct udevice *dev;
int ret;
ret = host_create_device(label, removable, &dev);
if (ret)
return log_msg_ret("cre", ret);
ret = host_attach_file(dev, filename);
if (ret) {
device_unbind(dev);
return log_msg_ret("att", ret);
}
*devp = dev;
return 0;
}
int host_detach_file(struct udevice *dev)
{
struct host_ops *ops = host_get_ops(dev);
if (!ops->detach_file)
return -ENOSYS;
if (dev == host_get_cur_dev())
host_set_cur_dev(NULL);
return ops->detach_file(dev);
}
struct udevice *host_find_by_label(const char *label)
{
struct udevice *dev;
struct uclass *uc;
uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
struct host_sb_plat *plat = dev_get_plat(dev);
if (plat->label && !strcmp(label, plat->label))
return dev;
}
return NULL;
}
struct udevice *host_get_cur_dev(void)
{
struct uclass *uc = uclass_find(UCLASS_HOST);
if (uc) {
struct host_priv *priv = uclass_get_priv(uc);
return priv->cur_dev;
}
return NULL;
}
void host_set_cur_dev(struct udevice *dev)
{
struct uclass *uc = uclass_find(UCLASS_HOST);
if (uc) {
struct host_priv *priv = uclass_get_priv(uc);
priv->cur_dev = dev;
}
}
UCLASS_DRIVER(host) = {
.id = UCLASS_HOST,
.name = "host",
#if CONFIG_IS_ENABLED(OF_REAL)
.post_bind = dm_scan_fdt_dev,
#endif
.priv_auto = sizeof(struct host_priv),
};

View File

@ -63,6 +63,7 @@ enum uclass_id {
UCLASS_GPIO, /* Bank of general-purpose I/O pins */
UCLASS_HASH, /* Hash device */
UCLASS_HWSPINLOCK, /* Hardware semaphores */
UCLASS_HOST, /* Sandbox host device */
UCLASS_I2C, /* I2C bus */
UCLASS_I2C_EEPROM, /* I2C EEPROM device */
UCLASS_I2C_GENERIC, /* Generic I2C device */

125
include/sandbox_host.h Normal file
View File

@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* sandbox host uclass
*
* Copyright 2022 Google LLC
*/
#ifndef __SANDBOX_HOST__
#define __SANDBOX_HOST__
/**
* struct host_sb_plat - platform data for a host device
*
* @label: Label for this device (allocated)
* @filename: Name of file this is attached to, or NULL (allocated)
* @fd: File descriptor of file, or 0 for none (file is not open)
*/
struct host_sb_plat {
char *label;
char *filename;
int fd;
};
/**
* struct host_ops - operations supported by UCLASS_HOST
*
* @attach_file: Attach a new file to a device
* @detach_file: Detach a file from a device
*/
struct host_ops {
/*
* attach_file() - Attach a new file to the device
*
* @dev: Device to update
* @filename: Name of the file, e.g. "/path/to/disk.img"
* Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on
* other error
*/
int (*attach_file)(struct udevice *dev, const char *filename);
/**
* detach_file() - Detach a file from the device
*
* @dev: Device to detach from
* Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other
* error
*/
int (*detach_file)(struct udevice *dev);
};
#define host_get_ops(dev) ((struct host_ops *)(dev)->driver->ops)
/**
* host_attach_file() - Attach a new file to the device
*
* @dev: Device to update
* @filename: Name of the file, e.g. "/path/to/disk.img"
* Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on
* other error
*/
int host_attach_file(struct udevice *dev, const char *filename);
/**
* host_detach_file() - Detach a file from the device
*
* @dev: Device to detach from
* Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other
* error
*/
int host_detach_file(struct udevice *dev);
/**
* host_create_device() - Create a new host device
*
* Any existing device with the same label is removed and unbound first
*
* @label: Label of the attachment, e.g. "test1"
* @removable: true if the device should be marked as removable, false
* if it is fixed. See enum blk_flag_t
* @devp: Returns the device created, on success
* Returns: 0 if OK, -ve on error
*/
int host_create_device(const char *label, bool removable,
struct udevice **devp);
/**
* host_create_attach_file() - Create a new host device attached to a file
*
* @label: Label of the attachment, e.g. "test1"
* @filename: Name of the file, e.g. "/path/to/disk.img"
* @removable: true if the device should be marked as removable, false
* if it is fixed. See enum blk_flag_t
* @devp: Returns the device created, on success
* Returns: 0 if OK, -ve on error
*/
int host_create_attach_file(const char *label, const char *filename,
bool removable, struct udevice **devp);
/**
* host_find_by_label() - Find a host by label
*
* Searches all host devices to find one with the given label
*
* @label: Label to find
* Returns: associated device, or NULL if not found
*/
struct udevice *host_find_by_label(const char *label);
/**
* host_get_cur_dev() - Get the current device
*
* Returns current device, or NULL if none
*/
struct udevice *host_get_cur_dev(void);
/**
* host_set_cur_dev() - Set the current device
*
* Sets the current device, or clears it if @dev is NULL
*
* @dev: Device to set as the current one
*/
void host_set_cur_dev(struct udevice *dev);
#endif /* __SANDBOX_HOST__ */