This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 65207ae1c53d804dd9e25b96ee564caeaeac5fee Author: Maarten Zanders <[email protected]> AuthorDate: Thu Feb 19 15:44:46 2026 +0100 serial/uart_rpmsg: add _raw version of driver Mainline Linux doesn't use data encapsuation or flow control in its tty_rpmsg driver. Create a NuttX counterpart which matches this implementation. This driver uses the static "rpmsg-tty" name to connect with the remote service. Signed-off-by: Maarten Zanders <[email protected]> --- arch/arm/src/common/arm_internal.h | 3 + arch/arm64/src/common/arm64_internal.h | 3 + arch/tricore/src/common/tricore_internal.h | 3 + drivers/drivers_initialize.c | 7 +- drivers/serial/CMakeLists.txt | 4 + drivers/serial/Kconfig | 24 ++ drivers/serial/Make.defs | 4 + drivers/serial/uart_rpmsg_raw.c | 380 +++++++++++++++++++++++++++++ include/nuttx/drivers/drivers.h | 10 + include/nuttx/serial/uart_rpmsg_raw.h | 57 +++++ 10 files changed, 494 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h index a37058d332f..16c32751f5e 100644 --- a/arch/arm/src/common/arm_internal.h +++ b/arch/arm/src/common/arm_internal.h @@ -64,6 +64,9 @@ # elif defined(CONFIG_RPMSG_UART_CONSOLE) # undef USE_SERIALDRIVER # undef USE_EARLYSERIALINIT +# elif defined(CONFIG_RPMSG_UART_RAW_CONSOLE) +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT # else # define USE_SERIALDRIVER 1 # define USE_EARLYSERIALINIT 1 diff --git a/arch/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h index a99491ab26c..52f53be16a7 100644 --- a/arch/arm64/src/common/arm64_internal.h +++ b/arch/arm64/src/common/arm64_internal.h @@ -64,6 +64,9 @@ # elif defined(CONFIG_RPMSG_UART_CONSOLE) # undef USE_SERIALDRIVER # undef USE_EARLYSERIALINIT +# elif defined(CONFIG_RPMSG_UART_RAW_CONSOLE) +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT # else # define USE_SERIALDRIVER 1 # define USE_EARLYSERIALINIT 1 diff --git a/arch/tricore/src/common/tricore_internal.h b/arch/tricore/src/common/tricore_internal.h index f467b32a20f..cc83ff0957a 100644 --- a/arch/tricore/src/common/tricore_internal.h +++ b/arch/tricore/src/common/tricore_internal.h @@ -69,6 +69,9 @@ # elif defined(CONFIG_RPMSG_UART_CONSOLE) # undef USE_SERIALDRIVER # undef USE_EARLYSERIALINIT +# elif defined(CONFIG_RPMSG_UART_RAW_CONSOLE) +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT # else # define USE_SERIALDRIVER 1 # define USE_EARLYSERIALINIT 1 diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index 7393f37d93d..968abaf2821 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -71,7 +71,8 @@ #if (defined(CONFIG_LWL_CONSOLE) + defined(CONFIG_SERIAL_CONSOLE) + \ defined(CONFIG_CDCACM_CONSOLE) + defined(CONFIG_PL2303_CONSOLE) + \ - defined(CONFIG_SERIAL_RTT_CONSOLE) + defined(CONFIG_RPMSG_UART_CONSOLE)) > 1 + defined(CONFIG_SERIAL_RTT_CONSOLE) + defined(CONFIG_RPMSG_UART_CONSOLE) + \ + defined(CONFIG_RPMSG_UART_RAW_CONSOLE) ) > 1 # error More than one console driver selected. Check your configuration ! #endif @@ -174,6 +175,10 @@ void drivers_initialize(void) rpmsg_serialinit(); #endif +#ifdef CONFIG_RPMSG_UART_RAW + rpmsg_serialrawinit(); +#endif + #ifdef CONFIG_RAM_UART ram_serialinit(); #endif diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 3dbd4bc9d3e..74f9f9d6415 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -50,6 +50,10 @@ if(CONFIG_RPMSG_UART) list(APPEND SRCS uart_rpmsg.c) endif() +if(CONFIG_RPMSG_UART_RAW) + list(APPEND SRCS uart_rpmsg_raw.c) +endif() + if(CONFIG_UART_HOSTFS) list(APPEND SRCS uart_hostfs.c) endif() diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ebc4b1dee28..def241f7934 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -169,6 +169,30 @@ config RPMSG_UART_CONSOLE NOTE: support for this option must be implemented in the board logic by setting the \"isconsole\" argument in the uart_rpmsg_init() function to true. +config RPMSG_UART_RAW + bool "UART RPMSG RAW support" + default n + depends on RPMSG + select ARCH_HAVE_SERIAL_TERMIOS + select SERIAL_RXDMA + select SERIAL_TXDMA + select SERIAL_REMOVABLE + ---help--- + Similar to RPMSG_UART but using data transfer without encapsulation or + flow control. This implementation is compatible with the upstream linux + implementation of tty_rpmsg. This connects to a static service name + (rpmsg-tty), independent from the local name. + +config RPMSG_UART_RAW_CONSOLE + bool "UART RPMSG RAW console support" + default n + depends on RPMSG_UART_RAW + ---help--- + Register the RAW UART RPMSG device as /dev/console so that is will be used + as the console device. + NOTE: support for this option must be implemented in the board logic by + setting the \"isconsole\" argument in the uart_rpmsg_raw_init() function to true. + # # Standard serial driver configuration # diff --git a/drivers/serial/Make.defs b/drivers/serial/Make.defs index 8843bde2c92..b9ca98dbff8 100644 --- a/drivers/serial/Make.defs +++ b/drivers/serial/Make.defs @@ -50,6 +50,10 @@ ifeq ($(CONFIG_RPMSG_UART),y) CSRCS += uart_rpmsg.c endif +ifeq ($(CONFIG_RPMSG_UART_RAW),y) + CSRCS += uart_rpmsg_raw.c +endif + ifeq ($(CONFIG_UART_HOSTFS),y) CSRCS += uart_hostfs.c endif diff --git a/drivers/serial/uart_rpmsg_raw.c b/drivers/serial/uart_rpmsg_raw.c new file mode 100644 index 00000000000..a658b3f61d3 --- /dev/null +++ b/drivers/serial/uart_rpmsg_raw.c @@ -0,0 +1,380 @@ +/**************************************************************************** + * drivers/serial/uart_rpmsg_raw.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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/config.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <nuttx/fs/ioctl.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mutex.h> +#include <nuttx/rpmsg/rpmsg.h> +#include <nuttx/serial/serial.h> +#include <nuttx/serial/uart_rpmsg_raw.h> + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +#define UART_RPMSG_DEV_CONSOLE "/dev/console" +#define UART_RPMSG_DEV_PREFIX "/dev/tty" +#define UART_RPMSG_EPT "rpmsg-tty" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct uart_rpmsg_priv_s +{ + struct rpmsg_endpoint ept; + mutex_t lock; + FAR const char *devname; + FAR const char *cpuname; + FAR void *recv_data; + size_t recv_len; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int uart_rpmsg_raw_setup(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_shutdown(FAR struct uart_dev_s *dev); +static int uart_rpmsg_raw_attach(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_detach(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_rxint(FAR struct uart_dev_s *dev, bool enable); +static void uart_rpmsg_raw_dmasend(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_dmareceive(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_dmarxfree(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_dmatxavail(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_send(FAR struct uart_dev_s *dev, int ch); +static void uart_rpmsg_raw_txint(FAR struct uart_dev_s *dev, bool enable); +static bool uart_rpmsg_raw_txready(FAR struct uart_dev_s *dev); +static bool uart_rpmsg_raw_txempty(FAR struct uart_dev_s *dev); +static void uart_rpmsg_raw_device_created(FAR struct rpmsg_device *rdev, + FAR void *priv_); +static void uart_rpmsg_raw_device_destroy(FAR struct rpmsg_device *rdev, + FAR void *priv_); +static int uart_rpmsg_raw_ept_cb(struct rpmsg_endpoint *ept, FAR void *data, + size_t len, uint32_t src, FAR void *priv_); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct uart_ops_s g_uart_rpmsg_ops = +{ + .setup = uart_rpmsg_raw_setup, + .shutdown = uart_rpmsg_raw_shutdown, + .attach = uart_rpmsg_raw_attach, + .detach = uart_rpmsg_raw_detach, + .rxint = uart_rpmsg_raw_rxint, + .dmasend = uart_rpmsg_raw_dmasend, + .dmareceive = uart_rpmsg_raw_dmareceive, + .dmarxfree = uart_rpmsg_raw_dmarxfree, + .dmatxavail = uart_rpmsg_raw_dmatxavail, + .send = uart_rpmsg_raw_send, + .txint = uart_rpmsg_raw_txint, + .txready = uart_rpmsg_raw_txready, + .txempty = uart_rpmsg_raw_txempty, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int uart_rpmsg_raw_setup(FAR struct uart_dev_s *dev) +{ + return OK; +} + +static void uart_rpmsg_raw_shutdown(FAR struct uart_dev_s *dev) +{ +} + +static int uart_rpmsg_raw_attach(FAR struct uart_dev_s *dev) +{ + return OK; +} + +static void uart_rpmsg_raw_detach(FAR struct uart_dev_s *dev) +{ +} + +static void uart_rpmsg_raw_rxint(FAR struct uart_dev_s *dev, bool enable) +{ +} + +static void uart_rpmsg_raw_dmasend(FAR struct uart_dev_s *dev) +{ + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + FAR struct uart_dmaxfer_s *xfer = &dev->dmatx; + size_t len = xfer->length + xfer->nlength; + FAR uint8_t *buf; + uint32_t space; + int ret; + + buf = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true); + if (!buf) + { + return; + } + + if (len > space) + { + len = space; + } + + if (len > xfer->length) + { + memcpy(buf, xfer->buffer, xfer->length); + memcpy(buf + xfer->length, xfer->nbuffer, len - xfer->length); + } + else + { + memcpy(buf, xfer->buffer, len); + } + + ret = rpmsg_send_nocopy(&priv->ept, buf, len); + + if (ret < 0) + { + rpmsg_release_tx_buffer(&priv->ept, buf); + dev->dmatx.nbytes = 0; + } + else + { + dev->dmatx.nbytes = len; + } + + uart_xmitchars_done(dev); +} + +static void uart_rpmsg_raw_dmareceive(FAR struct uart_dev_s *dev) +{ + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; + FAR char *data = priv->recv_data; + size_t len = priv->recv_len; + size_t space = xfer->length + xfer->nlength; + + if (len > space) + { + len = space; + } + + if (len > xfer->length) + { + memcpy(xfer->buffer, data, xfer->length); + memcpy(xfer->nbuffer, data + xfer->length, len - xfer->length); + } + else + { + memcpy(xfer->buffer, data, len); + } + + xfer->nbytes = len; + uart_recvchars_done(dev); +} + +static void uart_rpmsg_raw_dmarxfree(FAR struct uart_dev_s *dev) +{ +} + +static void uart_rpmsg_raw_dmatxavail(FAR struct uart_dev_s *dev) +{ + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + + nxmutex_lock(&priv->lock); + + if (is_rpmsg_ept_ready(&priv->ept) && dev->dmatx.length == 0) + { + uart_xmitchars_dma(dev); + } + + nxmutex_unlock(&priv->lock); +} + +static void uart_rpmsg_raw_send(FAR struct uart_dev_s *dev, int ch) +{ + int nexthead; + + nexthead = dev->xmit.head + 1; + if (nexthead >= dev->xmit.size) + { + nexthead = 0; + } + + if (nexthead != dev->xmit.tail) + { + /* No.. not full. Add the character to the TX buffer and return. */ + + dev->xmit.buffer[dev->xmit.head] = ch; + dev->xmit.head = nexthead; + } + + uart_rpmsg_raw_dmatxavail(dev); +} + +static void uart_rpmsg_raw_txint(FAR struct uart_dev_s *dev, bool enable) +{ +} + +static bool uart_rpmsg_raw_txready(FAR struct uart_dev_s *dev) +{ + int nexthead; + + nexthead = dev->xmit.head + 1; + if (nexthead >= dev->xmit.size) + { + nexthead = 0; + } + + return nexthead != dev->xmit.tail; +} + +static bool uart_rpmsg_raw_txempty(FAR struct uart_dev_s *dev) +{ + return true; +} + +static void uart_rpmsg_raw_device_created(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct uart_dev_s *dev = priv_; + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + + if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0) + { + priv->ept.priv = dev; + rpmsg_create_ept(&priv->ept, rdev, UART_RPMSG_EPT, + RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, + uart_rpmsg_raw_ept_cb, NULL); + } +} + +static void uart_rpmsg_raw_device_destroy(FAR struct rpmsg_device *rdev, + FAR void *priv_) +{ + FAR struct uart_dev_s *dev = priv_; + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + + if (priv->ept.priv != NULL && + strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0) + { + rpmsg_destroy_ept(&priv->ept); + } + + dev->dmatx.nbytes = dev->dmatx.length + dev->dmatx.nlength; + uart_xmitchars_done(dev); +} + +static int uart_rpmsg_raw_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv_) +{ + FAR struct uart_dev_s *dev = priv_; + FAR struct uart_rpmsg_priv_s *priv = dev->priv; + + if (len > 0) + { + nxmutex_lock(&dev->recv.lock); + + priv->recv_data = data; + priv->recv_len = len; + + uart_recvchars_dma(dev); + + priv->recv_data = NULL; + priv->recv_len = 0; + + nxmutex_unlock(&dev->recv.lock); + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int uart_rpmsg_raw_init(FAR const char *cpuname, FAR const char *devname, + int buf_size, bool isconsole) +{ + FAR struct uart_rpmsg_priv_s *priv; + FAR struct uart_dev_s *dev; + char name[32]; + int ret; + + dev = kmm_zalloc(sizeof(struct uart_dev_s) + + sizeof(struct uart_rpmsg_priv_s) + + buf_size * 2); + if (dev == NULL) + { + return -ENOMEM; + } + + dev->ops = &g_uart_rpmsg_ops; + dev->isconsole = isconsole; + dev->recv.size = buf_size; + dev->xmit.size = buf_size; + dev->priv = dev + 1; + dev->recv.buffer = (FAR char *)dev->priv + + sizeof(struct uart_rpmsg_priv_s); + dev->xmit.buffer = dev->recv.buffer + buf_size; + priv = dev->priv; + priv->cpuname = cpuname; + priv->devname = devname; + + nxmutex_init(&priv->lock); + + ret = rpmsg_register_callback(dev, + uart_rpmsg_raw_device_created, + uart_rpmsg_raw_device_destroy, + NULL, + NULL); + if (ret < 0) + { + nxmutex_destroy(&priv->lock); + kmm_free(dev); + return ret; + } + + snprintf(name, sizeof(name), "%s%s", + UART_RPMSG_DEV_PREFIX, devname); + uart_register(name, dev); + +#ifdef CONFIG_RPMSG_UART_RAW_CONSOLE + if (dev->isconsole) + { + uart_register(UART_RPMSG_DEV_CONSOLE, dev); + } +#endif + + return 0; +} diff --git a/include/nuttx/drivers/drivers.h b/include/nuttx/drivers/drivers.h index 07c9b005030..7f0c00f7ec0 100644 --- a/include/nuttx/drivers/drivers.h +++ b/include/nuttx/drivers/drivers.h @@ -274,6 +274,16 @@ void lwlconsole_init(void); void rpmsg_serialinit(void); +/**************************************************************************** + * Name: rpmsg_serialrawinit + * + * Description: + * Register rpmsg serial driver + * + ****************************************************************************/ + +void rpmsg_serialrawinit(void); + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/nuttx/serial/uart_rpmsg_raw.h b/include/nuttx/serial/uart_rpmsg_raw.h new file mode 100644 index 00000000000..f353b7b8738 --- /dev/null +++ b/include/nuttx/serial/uart_rpmsg_raw.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * include/nuttx/serial/uart_rpmsg_raw.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SERIAL_UART_RPMSG_RAW_H +#define __INCLUDE_NUTTX_SERIAL_UART_RPMSG_RAW_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdbool.h> + +#ifdef CONFIG_RPMSG_UART_RAW + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +int uart_rpmsg_raw_init(FAR const char *cpuname, FAR const char *devname, + int buf_size, bool isconsole); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_RPMSG_UART_RAW */ +#endif /* __INCLUDE_NUTTX_SERIAL_UART_RPMSG_RAW_H */
