diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 19d9317c82..7f25912045 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -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 diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c new file mode 100644 index 0000000000..6460d968c2 --- /dev/null +++ b/drivers/block/host-uclass.c @@ -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 + */ + +#define LOG_CATEGORY UCLASS_HOST + +#include +#include +#include +#include +#include +#include +#include +#include + +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), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1f3cf8c085..376f741cc2 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -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 */ diff --git a/include/sandbox_host.h b/include/sandbox_host.h new file mode 100644 index 0000000000..2e37ede235 --- /dev/null +++ b/include/sandbox_host.h @@ -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__ */