Skip to content

Commit

Permalink
serial: use hostfs read/write on stdio as uart
Browse files Browse the repository at this point in the history
This is used to implement serial console on instruction set simulator (ISS).

Signed-off-by: chenxiaoyi <[email protected]>
  • Loading branch information
chenxiaoyi authored and xiaoxiang781216 committed Sep 28, 2024
1 parent b622567 commit 065046b
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 0 deletions.
5 changes: 5 additions & 0 deletions drivers/drivers_initialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <nuttx/segger/rtt.h>
#include <nuttx/sensors/sensor.h>
#include <nuttx/serial/pty.h>
#include <nuttx/serial/uart_hostfs.h>
#include <nuttx/serial/uart_ram.h>
#include <nuttx/syslog/syslog.h>
#include <nuttx/syslog/syslog_console.h>
Expand Down Expand Up @@ -180,6 +181,10 @@ void drivers_initialize(void)
syslog_console_init();
#endif

#ifdef CONFIG_UART_HOSTFS
uart_hostfs_init();
#endif

#ifdef CONFIG_PSEUDOTERM_SUSV1
/* Register the master pseudo-terminal multiplexor device */

Expand Down
27 changes: 27 additions & 0 deletions drivers/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,33 @@ config SERIAL_GDBSTUB_PATH
---help---
The path to the serial device that will be used for GDB stub.

config UART_HOSTFS
bool "Use hostfs read/write on UART_HOSTFS_DEVPATH as uart console"
depends on FS_HOSTFS
default n
select SERIAL_RXDMA
select SERIAL_TXDMA

config UART_HOSTFS_DEVPATH
string "The host device node that will be used by"
depends on UART_HOSTFS
default "/dev/tty"

config UART_HOSTFS_RXBUFSIZE
int "Uart hostfs receive buffer size"
default 256
depends on UART_HOSTFS

config UART_HOSTFS_TXBUFSIZE
int "Uart hostfs transmit buffer size"
default 256
depends on UART_HOSTFS

config UART_HOSTFS_DELAY_USEC
int "Uart hostfs polling interval in microseconds"
default 1000
depends on UART_HOSTFS

menuconfig UART_PL011
bool "PL011 Chip support"
default n
Expand Down
4 changes: 4 additions & 0 deletions drivers/serial/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ ifeq ($(CONFIG_RPMSG_UART),y)
CSRCS += uart_rpmsg.c
endif

ifeq ($(CONFIG_UART_HOSTFS),y)
CSRCS += uart_hostfs.c
endif

# Pseudo-terminal support

ifeq ($(CONFIG_PSEUDOTERM),y)
Expand Down
302 changes: 302 additions & 0 deletions drivers/serial/uart_hostfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
/****************************************************************************
* drivers/serial/uart_hostfs.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

/****************************************************************************
* Included Files
****************************************************************************/

#include <nuttx/clock.h>
#include <nuttx/fs/hostfs.h>
#include <nuttx/serial/serial.h>
#include <nuttx/wdog.h>

#include <debug.h>
#include <fcntl.h>
#include <unistd.h>

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#define UART_WDOG_DELAY USEC2TICK(CONFIG_UART_HOSTFS_DELAY_USEC)

/****************************************************************************
* Private Types
****************************************************************************/

struct uart_hostfs_priv_s
{
int fd;
bool rxint;
struct wdog_s wdog;
};

/****************************************************************************
* Private Function Prototypes
****************************************************************************/

static int uart_hostfs_setup(FAR struct uart_dev_s *dev);
static void uart_hostfs_shutdown(FAR struct uart_dev_s *dev);
static int uart_hostfs_attach(FAR struct uart_dev_s *dev);
static void uart_hostfs_detach(FAR struct uart_dev_s *dev);
static int uart_hostfs_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
static void uart_hostfs_rxint(FAR struct uart_dev_s *dev, bool enable);
static bool uart_hostfs_rxavailable(FAR struct uart_dev_s *dev);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool uart_hostfs_rxflowcontrol(FAR struct uart_dev_s *dev,
unsigned int nbuffered, bool upper);
#endif
static void uart_hostfs_dmatxavail(FAR struct uart_dev_s *dev);
static void uart_hostfs_dmasend(FAR struct uart_dev_s *dev);
static void uart_hostfs_dmarxfree(FAR struct uart_dev_s *dev);
static void uart_hostfs_dmareceive(FAR struct uart_dev_s *dev);
static void uart_hostfs_send(FAR struct uart_dev_s *dev, int ch);
static void uart_hostfs_txint(FAR struct uart_dev_s *dev, bool enable);
static bool uart_hostfs_txready(FAR struct uart_dev_s *dev);
static bool uart_hostfs_txempty(FAR struct uart_dev_s *dev);

/****************************************************************************
* Private Data
****************************************************************************/

static const struct uart_ops_s g_uart_hostfs_ops =
{
.setup = uart_hostfs_setup,
.shutdown = uart_hostfs_shutdown,
.attach = uart_hostfs_attach,
.detach = uart_hostfs_detach,
.ioctl = uart_hostfs_ioctl,
.rxint = uart_hostfs_rxint,
.rxavailable = uart_hostfs_rxavailable,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rxflowcontrol = uart_hostfs_rxflowcontrol,
#endif
.dmatxavail = uart_hostfs_dmatxavail,
.dmasend = uart_hostfs_dmasend,
.dmarxfree = uart_hostfs_dmarxfree,
.dmareceive = uart_hostfs_dmareceive,
.send = uart_hostfs_send,
.txint = uart_hostfs_txint,
.txready = uart_hostfs_txready,
.txempty = uart_hostfs_txempty,
};

static char g_uart_hostfs_rxbuf[CONFIG_UART_HOSTFS_RXBUFSIZE];
static char g_uart_hostfs_txbuf[CONFIG_UART_HOSTFS_TXBUFSIZE];

static struct uart_hostfs_priv_s g_uart_hostfs_priv;

static struct uart_dev_s g_uart_hostfs_dev =
{
.ops = &g_uart_hostfs_ops,
.priv = &g_uart_hostfs_priv,
.xmit =
{
.size = CONFIG_UART_HOSTFS_TXBUFSIZE,
.buffer = g_uart_hostfs_txbuf,
},
.recv =
{
.size = CONFIG_UART_HOSTFS_RXBUFSIZE,
.buffer = g_uart_hostfs_rxbuf,
},
};

/****************************************************************************
* Private Functions
****************************************************************************/

static int uart_hostfs_setup(FAR struct uart_dev_s *dev)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;

priv->fd = host_open(CONFIG_UART_HOSTFS_DEVPATH, O_RDWR | O_NONBLOCK,
0666);
return priv->fd;
}

static void uart_hostfs_shutdown(FAR struct uart_dev_s *dev)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;

if (priv->fd > 0)
{
host_close(priv->fd);
priv->fd = -1;
}
}

static int uart_hostfs_attach(FAR struct uart_dev_s *dev)
{
return OK;
}

static void uart_hostfs_detach(FAR struct uart_dev_s *dev)
{
}

static int uart_hostfs_ioctl(FAR struct file *filep, int cmd,
unsigned long arg)
{
return -ENOTTY;
}

static void uart_hostfs_wdog(wdparm_t arg)
{
FAR struct uart_dev_s *dev = (FAR struct uart_dev_s *)arg;
FAR struct uart_hostfs_priv_s *priv = dev->priv;

if (priv->rxint)
{
uart_dmarxfree(dev);
}

wd_start(&priv->wdog, UART_WDOG_DELAY, uart_hostfs_wdog, (wdparm_t)dev);
}

static void uart_hostfs_rxint(FAR struct uart_dev_s *dev, bool enable)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;

priv->rxint = enable;
if (enable)
{
wd_start(&priv->wdog, 0, uart_hostfs_wdog, (wdparm_t)dev);
}
else
{
wd_cancel(&priv->wdog);
}
}

static bool uart_hostfs_rxavailable(FAR struct uart_dev_s *dev)
{
return true;
}

#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool uart_hostfs_rxflowcontrol(FAR struct uart_dev_s *dev,
unsigned int nbuffered, bool upper)
{
FAR struct uart_buffer_s *rxbuf = &dev->recv;

return nbuffered == rxbuf->size;
}
#endif

static void uart_hostfs_dmatxavail(FAR struct uart_dev_s *dev)
{
uart_xmitchars_dma(dev);
}

static void uart_hostfs_dmasend(FAR struct uart_dev_s *dev)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;
FAR struct uart_dmaxfer_s *xfer = &dev->dmatx;
int ret;

xfer->nbytes = 0;
ret = host_write(priv->fd, xfer->buffer, xfer->length);
if (ret > 0)
{
xfer->nbytes = ret;

if (ret == xfer->length && xfer->nlength > 0)
{
ret = host_write(priv->fd, xfer->nbuffer, xfer->nlength);
if (ret > 0)
{
xfer->nbytes += ret;
}
}
}

uart_xmitchars_done(dev);
}

static void uart_hostfs_dmarxfree(FAR struct uart_dev_s *dev)
{
uart_recvchars_dma(dev);
}

static void uart_hostfs_dmareceive(FAR struct uart_dev_s *dev)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
ssize_t ret;

xfer->nbytes = 0;
ret = host_read(priv->fd, xfer->buffer, xfer->length);
if (ret > 0)
{
xfer->nbytes = ret;

if (ret == xfer->length && xfer->nlength > 0)
{
ret = host_read(priv->fd, xfer->nbuffer, xfer->nlength);
if (ret > 0)
{
xfer->nbytes += ret;
}
}
}

uart_recvchars_done(dev);
}

static void uart_hostfs_send(FAR struct uart_dev_s *dev, int ch)
{
FAR struct uart_hostfs_priv_s *priv = dev->priv;
char c = ch;

host_write(priv->fd, &c, 1);
}

static void uart_hostfs_txint(FAR struct uart_dev_s *dev, bool enable)
{
}

static bool uart_hostfs_txready(FAR struct uart_dev_s *dev)
{
return true;
}

static bool uart_hostfs_txempty(FAR struct uart_dev_s *dev)
{
return true;
}

/****************************************************************************
* Public Functions
****************************************************************************/

void uart_hostfs_init(void)
{
uart_register("/dev/console", &g_uart_hostfs_dev);
}

int up_putc(int ch)
{
FAR struct uart_dev_s *dev = &g_uart_hostfs_dev;

uart_hostfs_send(dev, ch);
return ch;
}
Loading

0 comments on commit 065046b

Please sign in to comment.