With driver model, -ENODEV has a specific meaning, i.e. there is no device. Return -EIO instead, since the device actually does exist in driver model, even if it is not currently connected. Remove a few error messages which we are here. Signed-off-by: Simon Glass <simon.glass@canonical.com>
171 lines
3.7 KiB
C
171 lines
3.7 KiB
C
// 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 -EIO;
|
|
|
|
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 -EIO;
|
|
|
|
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_debug("Failed to open %s (error %d)\n", priv->path, priv->fd);
|
|
free(priv->path);
|
|
return -ENOENT;
|
|
}
|
|
|
|
/* Configure serial port for raw mode */
|
|
if (os_tty_set_params(priv->fd) < 0) {
|
|
log_debug("Failed to configure serial port %s\n", priv->path);
|
|
os_close(priv->fd);
|
|
free(priv->path);
|
|
return -EIO;
|
|
}
|
|
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),
|
|
};
|