[Concept,8/8] tkey: Add a sandbox driver for real TKey hardware

Message ID 20251019072313.3235339-9-sjg@u-boot.org
State New
Headers
Series tkey: Provide basic support for Tillitis TKey |

Commit Message

Simon Glass Oct. 19, 2025, 7:23 a.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add a sandbox TKey driver that enables communication with physical TKey
devices via serial port (/dev/ttyACM0). This allows testing TKey
functionality in sandbox with real hardware.

The driver:
  - Opens the configured device path from device tree
  - Configures TTY parameters using os_tty_set_params()
  - Implements read/write operations for TKey protocol
  - Supports both read() and read_all() operations

Device tree configuration:

  tkey-test {
    compatible = "sandbox,tkey";
    sandbox,device-path = "/dev/ttyACM0";
  };

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/sandbox/dts/sandbox.dtsi |   5 +
 drivers/misc/Makefile         |   1 +
 drivers/misc/tkey_sandbox.c   | 170 ++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 drivers/misc/tkey_sandbox.c
  

Patch

diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 48e34a7aee5..e5d6be633fb 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -356,6 +356,11 @@ 
 		clock-frequency = <1000000>;
 	};
 
+	tkey-test {
+		compatible = "sandbox,tkey";
+		sandbox,device-path = "/dev/ttyACM0";
+	};
+
 	tpm {
 		compatible = "google,sandbox-tpm";
 	};
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 298bc1c0a69..cd7170986ac 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,6 +20,7 @@  obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
 ifdef CONFIG_SANDBOX
 obj-$(CONFIG_TKEY) += tkey_emul.o
+obj-$(CONFIG_TKEY) += tkey_sandbox.o
 endif
 endif
 
diff --git a/drivers/misc/tkey_sandbox.c b/drivers/misc/tkey_sandbox.c
new file mode 100644
index 00000000000..9b26bd36f1b
--- /dev/null
+++ b/drivers/misc/tkey_sandbox.c
@@ -0,0 +1,170 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Canonical Ltd
+ *
+ * Sandbox TKey driver for testing TKey functionality in sandbox
+ * Communicates with TKey devices via /dev/ttyACM0
+ */
+
+#define LOG_CATEGORY	UCLASS_TKEY
+
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <os.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+#include <tkey.h>
+
+/*
+ * struct tkey_sandbox_priv - private information about sandbox
+ *
+ * @path: Path to the tkey device, e.g. "/dev/ttyACM0"
+ * @fd: File descriptor
+ */
+struct tkey_sandbox_priv {
+	char *path;
+	int fd;
+};
+
+static int tkey_sandbox_read(struct udevice *dev, void *buffer, int len,
+			     int timeout_ms)
+{
+	struct tkey_sandbox_priv *priv = dev_get_priv(dev);
+	u8 *buf = buffer;
+	int total, ret;
+
+	if (priv->fd < 0)
+		return -ENODEV;
+
+	log_debug("Reading %d bytes...\n", len);
+
+	/* Read data in chunks until we get the full amount */
+	for (total = 0; total < len; total += ret) {
+		ret = os_read(priv->fd, buf + total, len - total);
+		log_debug("Read attempt returned: %d (total: %d/%d)\n", ret,
+			  total, len);
+
+		if (ret < 0) {
+			log_debug("Read failed with error %d\n", ret);
+			return -EIO;
+		}
+
+		if (!ret) {
+			if (!total) {
+				log_debug("Read timeout - no data received\n");
+				return -EIO;
+			}
+			/* Partial read - break and return what we got */
+			log_debug("Partial read, got %x/%x bytes\n", total,
+				  len);
+			break;
+		}
+	}
+
+	log_debug("Read %d bytes:", total);
+	for (int i = 0; i < total; i++)
+		log_debug(" %02x", buf[i]);
+	log_debug("\n");
+
+	return total;
+}
+
+static int tkey_sandbox_write(struct udevice *dev, const void *buffer, int len)
+{
+	struct tkey_sandbox_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (priv->fd < 0)
+		return -ENODEV;
+
+	log_debug("Writing %d bytes:", len);
+	for (int i = 0; i < len; i++)
+		log_debug(" %02x", ((u8*)buffer)[i]);
+	log_debug("\n");
+
+	ret = os_write(priv->fd, buffer, len);
+	if (ret < 0) {
+		log_debug("Write failed with error %d\n", ret);
+		return -EIO;
+	}
+	log_debug("Wrote %d bytes\n", ret);
+
+	return ret;
+}
+
+static int tkey_sandbox_probe(struct udevice *dev)
+{
+	struct tkey_sandbox_priv *priv = dev_get_priv(dev);
+	const char *device_path;
+
+	/* Get device path from device tree or use default */
+	device_path = dev_read_string(dev, "sandbox,device-path");
+	if (!device_path)
+		device_path = "/dev/ttyACM0";
+
+	priv->path = strdup(device_path);
+	if (!priv->path)
+		return -ENOMEM;
+
+	/* Open the serial device */
+	priv->fd = os_open(priv->path, OS_O_RDWR);
+	if (priv->fd < 0) {
+		log_err("Failed to open %s (error %d)\n", priv->path, priv->fd);
+		free(priv->path);
+		return -ENODEV;
+	}
+
+	/* Configure serial port for raw mode */
+	if (os_tty_set_params(priv->fd) < 0) {
+		log_err("Failed to configure serial port %s\n", priv->path);
+		os_close(priv->fd);
+		free(priv->path);
+		return -ENODEV;
+	}
+	log_debug("Connected to %s with serial parameters configured\n",
+		  priv->path);
+
+	return 0;
+}
+
+static int tkey_sandbox_remove(struct udevice *dev)
+{
+	struct tkey_sandbox_priv *priv = dev_get_priv(dev);
+
+	if (priv->fd >= 0) {
+		os_close(priv->fd);
+		priv->fd = -1;
+	}
+
+	if (priv->path) {
+		free(priv->path);
+		priv->path = NULL;
+	}
+	log_debug("Disconnected\n");
+
+	return 0;
+}
+
+/* TKey uclass operations */
+static const struct tkey_ops tkey_sandbox_ops = {
+	.read = tkey_sandbox_read,
+	.write = tkey_sandbox_write,
+};
+
+static const struct udevice_id tkey_sandbox_ids[] = {
+	{ .compatible = "sandbox,tkey" },
+	{ }
+};
+
+U_BOOT_DRIVER(tkey_sandbox) = {
+	.name		= "tkey_sandbox",
+	.id		= UCLASS_TKEY,
+	.of_match	= tkey_sandbox_ids,
+	.probe		= tkey_sandbox_probe,
+	.remove		= tkey_sandbox_remove,
+	.ops		= &tkey_sandbox_ops,
+	.priv_auto	= sizeof(struct tkey_sandbox_priv),
+};