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

Reply via email to