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>
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 1f3cf8c..376f741 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -63,6 +63,7 @@
 	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 0000000..2e37ede
--- /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__ */