u-boot/drivers/serial/serial_semihosting.c
Tom Rini d678a59d2d Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay
Ethernet"' I failed to notice that b4 noticed it was based on next and
so took that as the base commit and merged that part of next to master.

This reverts commit c8ffd1356d, reversing
changes made to 2ee6f3a5f7.

Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
2024-05-19 08:16:36 -06:00

204 lines
3.6 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <serial.h>
#include <semihosting.h>
/**
* struct smh_serial_priv - Semihosting serial private data
* @infd: stdin file descriptor (or error)
* @outfd: stdout file descriptor (or error)
* @counter: Counter used to fake pending every other call
*/
struct smh_serial_priv {
int infd;
int outfd;
unsigned counter;
};
#if CONFIG_IS_ENABLED(DM_SERIAL)
static int smh_serial_getc(struct udevice *dev)
{
char ch = 0;
struct smh_serial_priv *priv = dev_get_priv(dev);
if (priv->infd < 0)
return smh_getc();
smh_read(priv->infd, &ch, sizeof(ch));
return ch;
}
static int smh_serial_putc(struct udevice *dev, const char ch)
{
smh_putc(ch);
return 0;
}
static ssize_t 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 len;
}
buf = strndup(s, len);
if (!buf)
return -ENOMEM;
smh_puts(buf);
free(buf);
return len;
}
ret = smh_write(priv->outfd, s, len, &written);
if (written)
return written;
return ret;
}
static int smh_serial_pending(struct udevice *dev, bool input)
{
struct smh_serial_priv *priv = dev_get_priv(dev);
if (input)
return priv->counter++ & 1;
return false;
}
static const struct dm_serial_ops smh_serial_ops = {
.putc = smh_serial_putc,
.puts = smh_serial_puts,
.getc = smh_serial_getc,
.pending = smh_serial_pending,
};
static int smh_serial_bind(struct udevice *dev)
{
if (semihosting_enabled())
return 0;
return -ENOENT;
}
static int smh_serial_probe(struct udevice *dev)
{
struct smh_serial_priv *priv = dev_get_priv(dev);
priv->infd = smh_open(":tt", MODE_READ);
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,
};
U_BOOT_DRVINFO(smh_serial) = {
.name = "serial_semihosting",
};
#else /* DM_SERIAL */
static int infd = -ENODEV;
static int outfd = -ENODEV;
static unsigned counter = 1;
static int smh_serial_start(void)
{
infd = smh_open(":tt", MODE_READ);
outfd = smh_open(":tt", MODE_WRITE);
return 0;
}
static int smh_serial_stop(void)
{
if (outfd >= 0)
smh_close(outfd);
return 0;
}
static void smh_serial_setbrg(void)
{
}
static int smh_serial_getc(void)
{
char ch = 0;
if (infd < 0)
return smh_getc();
smh_read(infd, &ch, sizeof(ch));
return ch;
}
static int smh_serial_tstc(void)
{
return counter++ & 1;
}
static void smh_serial_puts(const char *s)
{
ulong unused;
if (outfd < 0)
smh_puts(s);
else
smh_write(outfd, s, strlen(s), &unused);
}
struct serial_device serial_smh_device = {
.name = "serial_smh",
.start = smh_serial_start,
.stop = smh_serial_stop,
.setbrg = smh_serial_setbrg,
.getc = smh_serial_getc,
.tstc = smh_serial_tstc,
.putc = smh_putc,
.puts = smh_serial_puts,
};
void smh_serial_initialize(void)
{
if (semihosting_enabled())
serial_register(&serial_smh_device);
}
__weak struct serial_device *default_serial_console(void)
{
return &serial_smh_device;
}
#endif
#ifdef CONFIG_DEBUG_UART_SEMIHOSTING
#include <debug_uart.h>
static inline void _debug_uart_init(void)
{
}
static inline void _debug_uart_putc(int c)
{
smh_putc(c);
}
DEBUG_UART_FUNCS
#endif