This adds an implementation of puts for DM. The implementation is not as clean as for the non-DM puts because we have to handle non-nul-terminated string. We also handle short writes (though these are probably very unusual).
Signed-off-by: Sean Anderson <sean.ander...@seco.com> --- Changes in v2: - New drivers/serial/serial_semihosting.c | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/serial/serial_semihosting.c b/drivers/serial/serial_semihosting.c index 706c1aabe1..049dca5428 100644 --- a/drivers/serial/serial_semihosting.c +++ b/drivers/serial/serial_semihosting.c @@ -5,9 +5,18 @@ #include <common.h> #include <dm.h> +#include <malloc.h> #include <serial.h> #include <semihosting.h> +/** + * struct smh_serial_priv - Semihosting serial private data + * @outfd: stdout file descriptor (or error) + */ +struct smh_serial_priv { + int outfd; +}; + #if CONFIG_IS_ENABLED(DM_SERIAL) static int smh_serial_getc(struct udevice *dev) { @@ -20,8 +29,40 @@ static int smh_serial_putc(struct udevice *dev, const char ch) return 0; } +static int smh_serial_puts(struct udevice *dev, const char *s, size_t *len) +{ + int ret; + struct smh_serial_priv *priv = dev_get_priv(dev); + unsigned long written; + + if (priv->outfd < 0) { + char *buf; + + /* Try and avoid a copy if we can */ + if (!s[*len + 1]) { + smh_puts(s); + return 0; + } + + buf = strndup(s, *len); + smh_puts(buf); + free(buf); + return 0; + } + + ret = smh_write(priv->outfd, s, *len, &written); + *len = written; + if (ret) + return ret; + + if (written != *len) + return -EAGAIN; + return 0; +} + static const struct dm_serial_ops smh_serial_ops = { .putc = smh_serial_putc, + .puts = smh_serial_puts, .getc = smh_serial_getc, }; @@ -32,10 +73,20 @@ static int smh_serial_bind(struct udevice *dev) return -ENOENT; } +static int smh_serial_probe(struct udevice *dev) +{ + struct smh_serial_priv *priv = dev_get_priv(dev); + + priv->outfd = smh_open(":tt", MODE_WRITE); + return 0; +} + U_BOOT_DRIVER(smh_serial) = { .name = "serial_semihosting", .id = UCLASS_SERIAL, .bind = smh_serial_bind, + .probe = smh_serial_probe, + .priv_auto = sizeof(struct smh_serial_priv), .ops = &smh_serial_ops, .flags = DM_FLAG_PRE_RELOC, }; -- 2.25.1