summaryrefslogtreecommitdiff
path: root/components/drivers/rpmsg
diff options
context:
space:
mode:
Diffstat (limited to 'components/drivers/rpmsg')
-rwxr-xr-xcomponents/drivers/rpmsg/Kconfig19
-rwxr-xr-xcomponents/drivers/rpmsg/SConscript15
-rwxr-xr-xcomponents/drivers/rpmsg/rpmsg.c327
-rwxr-xr-xcomponents/drivers/rpmsg/rpmsg_char.c412
-rwxr-xr-xcomponents/drivers/rpmsg/rpmsg_ns.c122
5 files changed, 895 insertions, 0 deletions
diff --git a/components/drivers/rpmsg/Kconfig b/components/drivers/rpmsg/Kconfig
new file mode 100755
index 0000000000..4d886af13c
--- /dev/null
+++ b/components/drivers/rpmsg/Kconfig
@@ -0,0 +1,19 @@
+menuconfig RT_USING_RPMSG
+ bool "Using Remote Processor Messaging (RPMSG)"
+ select RT_USING_DEVICE_IPC
+ select RT_USING_SYSTEM_WORKQUEUE
+ default n
+
+config RT_RPMSG_CHAR_MSG_MAX
+ int "Char device message receive max"
+ depends on RT_USING_RPMSG
+ default 64
+
+config RT_RPMSG_CHAR_MSG_SIZE_MAX
+ int "Char device message size max"
+ depends on RT_USING_RPMSG
+ default 256
+
+if RT_USING_RPMSG
+ osource "$(SOC_DM_RPMSG_DIR)/Kconfig"
+endif
diff --git a/components/drivers/rpmsg/SConscript b/components/drivers/rpmsg/SConscript
new file mode 100755
index 0000000000..a328d68ea3
--- /dev/null
+++ b/components/drivers/rpmsg/SConscript
@@ -0,0 +1,15 @@
+from building import *
+
+group = []
+
+if not GetDepend(['RT_USING_RPMSG']):
+ Return('group')
+
+cwd = GetCurrentDir()
+CPPPATH = [cwd + '/../include']
+
+src = ['rpmsg.c', 'rpmsg_char.c', 'rpmsg_ns.c']
+
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/rpmsg/rpmsg.c b/components/drivers/rpmsg/rpmsg.c
new file mode 100755
index 0000000000..031507b272
--- /dev/null
+++ b/components/drivers/rpmsg/rpmsg.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-02-25 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <drivers/ofw.h>
+#include <drivers/rpmsg.h>
+#include <drivers/core/bus.h>
+#include <drivers/core/power_domain.h>
+
+#define DBG_TAG "rtdm.rpmsg"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static rt_uint32_t rpmsg_mode = RT_RPMSG_MODE_SLAVE;
+
+static int rpmsg_mode_setup(void)
+{
+ const char *mode = RT_NULL;
+
+#ifdef RT_USING_OFW
+ mode = rt_ofw_bootargs_select("rpmsg.mode=", 0);
+#endif
+
+ if (!mode)
+ {
+ goto _end;
+ }
+
+ if (!rt_strcmp(mode, "master"))
+ {
+ rpmsg_mode = RT_RPMSG_MODE_MASTER;
+ }
+ else if (!rt_strcmp(mode, "slave"))
+ {
+ rpmsg_mode = RT_RPMSG_MODE_SLAVE;
+ }
+ else
+ {
+ LOG_W("Unknown mode of RPMsg: %s", mode);
+
+ return (int)-RT_EINVAL;
+ }
+
+_end:
+ LOG_D("RPMsg mode: %s", rpmsg_mode == RT_RPMSG_MODE_MASTER ? "master" : "slave");
+
+ return 0;
+}
+INIT_CORE_EXPORT(rpmsg_mode_setup);
+
+rt_uint32_t rt_rpmsg_mode(void)
+{
+ return rpmsg_mode;
+}
+
+struct rt_rpmsg_endpoint *rt_rpmsg_create_endpoint(struct rt_rpmsg_device *rdev,
+ struct rt_rpmsg_endpoint_info *info, rt_rpmsg_rx_callback rx_cb)
+{
+ rt_err_t err;
+ rt_ubase_t level;
+ struct rt_rpmsg_endpoint *ept;
+
+ RT_ASSERT(rdev != RT_NULL);
+ RT_ASSERT(info != RT_NULL);
+
+ ept = rt_calloc(1, sizeof(*ept));
+
+ if (!ept)
+ {
+ return rt_err_ptr(-RT_ENOMEM);
+ }
+ ept->rdev = rdev;
+
+ rt_memcpy(&ept->info, info, sizeof(ept->info));
+ ept->rx_callback = rx_cb ? : rt_container_of(rdev->parent.drv,
+ struct rt_rpmsg_driver, parent)->rx_callback;
+
+ RT_ASSERT(ept->rx_callback != RT_NULL);
+
+ err = rdev->ops->create_endpoint(rdev, ept, info);
+
+ if (err)
+ {
+ rt_free(ept);
+ return rt_err_ptr(err);
+ }
+
+ rt_spin_lock_init(&ept->lock);
+
+ rt_list_init(&ept->list);
+ level = rt_spin_lock_irqsave(&rdev->lock);
+ rt_list_insert_before(&rdev->ept_nodes, &ept->list);
+ rt_spin_unlock_irqrestore(&rdev->lock, level);
+
+ return ept;
+}
+
+rt_err_t rt_rpmsg_destroy_endpoint(struct rt_rpmsg_device *rdev,
+ struct rt_rpmsg_endpoint *ept)
+{
+ rt_err_t err;
+ rt_ubase_t level;
+
+ RT_ASSERT(rdev != RT_NULL);
+ RT_ASSERT(ept != RT_NULL);
+
+ err = rdev->ops->destroy_endpoint(rdev, ept);
+
+ if (err)
+ {
+ return err;
+ }
+
+ level = rt_spin_lock_irqsave(&rdev->lock);
+ rt_list_remove(&ept->list);
+ rt_spin_unlock_irqrestore(&rdev->lock, level);
+
+ rt_free(ept);
+
+ return RT_EOK;
+}
+
+struct rt_rpmsg_endpoint *rt_rpmsg_find_endpoint(struct rt_rpmsg_device *rdev,
+ struct rt_rpmsg_endpoint_info *info)
+{
+ rt_ubase_t level;
+ struct rt_rpmsg_endpoint *ept = RT_NULL, *ept_tmp;
+
+ RT_ASSERT(rdev != RT_NULL);
+ RT_ASSERT(info != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&rdev->lock);
+
+ rt_list_for_each_entry(ept_tmp, &rdev->ept_nodes, list)
+ {
+ if (info->src != RT_RPMSG_ADDR_ANY && info->src != ept_tmp->info.src)
+ {
+ continue;
+ }
+
+ if (info->dst != RT_RPMSG_ADDR_ANY && info->dst != ept_tmp->info.dst)
+ {
+ continue;
+ }
+
+ if (info->name[0] &&
+ rt_strncmp(info->name, ept_tmp->info.name, RT_RPMSG_NAME_SIZE))
+ {
+ continue;
+ }
+
+ ept = ept_tmp;
+ break;
+ }
+
+ rt_spin_unlock_irqrestore(&rdev->lock, level);
+
+ return ept;
+}
+
+rt_err_t rt_rpmsg_send(struct rt_rpmsg_endpoint *ept,
+ const void *data, rt_size_t len)
+{
+ RT_ASSERT(ept != RT_NULL);
+
+ return rt_rpmsg_sendto(ept, ept->info.dst, data, len);
+}
+
+rt_err_t rt_rpmsg_sendto(struct rt_rpmsg_endpoint *ept, rt_uint32_t dst,
+ const void *data, rt_size_t len)
+{
+ RT_ASSERT(ept != RT_NULL);
+
+ return rt_rpmsg_sendto_wait(ept, dst, data, len, 0);
+}
+
+rt_err_t rt_rpmsg_send_wait(struct rt_rpmsg_endpoint *ept,
+ const void *data, rt_size_t len, rt_int32_t timeout)
+{
+ RT_ASSERT(ept != RT_NULL);
+
+ return rt_rpmsg_sendto_wait(ept, ept->info.dst, data, len, timeout);
+}
+
+rt_err_t rt_rpmsg_sendto_wait(struct rt_rpmsg_endpoint *ept, rt_uint32_t dst,
+ const void *data, rt_size_t len, rt_int32_t timeout)
+{
+ rt_err_t err;
+ struct rt_rpmsg_device *rdev;
+
+ RT_ASSERT(ept != RT_NULL);
+ rdev = ept->rdev;
+
+ rt_hw_spin_lock(&ept->lock.lock);
+
+ err = rdev->ops->send(rdev, ept->info.src, dst, data, len, timeout);
+
+ rt_hw_spin_unlock(&ept->lock.lock);
+
+ return err;
+}
+
+static struct rt_bus rpmsg_bus;
+
+rt_err_t rt_rpmsg_driver_register(struct rt_rpmsg_driver *rdrv)
+{
+ RT_ASSERT(rdrv != RT_NULL);
+
+ rdrv->parent.bus = &rpmsg_bus;
+
+ return rt_driver_register(&rdrv->parent);
+}
+
+rt_err_t rt_rpmsg_device_register(struct rt_rpmsg_device *rdev)
+{
+ rt_err_t err;
+
+ if ((err = rt_dm_dev_set_name_auto(&rdev->parent, rdev->id.name)) < 0)
+ {
+ return err;
+ }
+
+ rt_list_init(&rdev->ept_nodes);
+ rt_spin_lock_init(&rdev->lock);
+
+ return rt_bus_add_device(&rpmsg_bus, &rdev->parent);
+}
+
+static rt_bool_t rpmsg_match(rt_driver_t drv, rt_device_t dev)
+{
+ const struct rt_rpmsg_device_id *id;
+ struct rt_rpmsg_driver *rdrv = rt_container_of(drv, struct rt_rpmsg_driver, parent);
+ struct rt_rpmsg_device *rdev = rt_container_of(dev, struct rt_rpmsg_device, parent);
+
+ for (id = rdrv->ids; id->name[0]; ++id)
+ {
+ if (!rt_strncmp(id->name, rdev->id.name, RT_RPMSG_NAME_SIZE))
+ {
+ rdev->id.data = id->data;
+
+ return RT_TRUE;
+ }
+ }
+
+ return RT_FALSE;
+}
+
+static rt_err_t rpmsg_probe(rt_device_t dev)
+{
+ rt_err_t err;
+ struct rt_rpmsg_driver *rdrv = rt_container_of(dev->drv, struct rt_rpmsg_driver, parent);
+ struct rt_rpmsg_device *rdev = rt_container_of(dev, struct rt_rpmsg_device, parent);
+
+ err = rt_dm_power_domain_attach(dev, RT_TRUE);
+
+ if (err && err != -RT_EEMPTY)
+ {
+ LOG_E("Attach power domain error = %s in device %s",
+ rt_strerror(err), rt_dm_dev_get_name(dev));
+
+ return err;
+ }
+
+ err = rdrv->probe(rdev);
+
+ if (err)
+ {
+ rt_dm_power_domain_detach(dev, RT_TRUE);
+ }
+
+ return err;
+}
+
+static rt_err_t rpmsg_remove(rt_device_t dev)
+{
+ rt_ubase_t level;
+ struct rt_rpmsg_endpoint *ept, *ept_next;
+ struct rt_rpmsg_driver *rdrv = rt_container_of(dev->drv, struct rt_rpmsg_driver, parent);
+ struct rt_rpmsg_device *rdev = rt_container_of(dev, struct rt_rpmsg_device, parent);
+
+ level = rt_spin_lock_irqsave(&rdev->lock);
+
+ rt_list_for_each_entry_safe(ept, ept_next, &rdev->ept_nodes, list)
+ {
+ rt_spin_unlock_irqrestore(&rdev->lock, level);
+
+ rt_rpmsg_destroy_endpoint(rdev, ept);
+
+ level = rt_spin_lock_irqsave(&rdev->lock);
+ }
+
+ rt_spin_unlock_irqrestore(&rdev->lock, level);
+
+ if (rdrv && rdrv->remove)
+ {
+ rdrv->remove(rdev);
+ }
+
+ rt_dm_power_domain_detach(dev, RT_TRUE);
+
+ return RT_EOK;
+}
+
+static struct rt_bus rpmsg_bus =
+{
+ .name = "rpmsg",
+ .match = rpmsg_match,
+ .probe = rpmsg_probe,
+ .remove = rpmsg_remove,
+};
+
+static int rpmsg_bus_init(void)
+{
+ rt_bus_register(&rpmsg_bus);
+
+ return 0;
+}
+INIT_CORE_EXPORT(rpmsg_bus_init);
diff --git a/components/drivers/rpmsg/rpmsg_char.c b/components/drivers/rpmsg/rpmsg_char.c
new file mode 100755
index 0000000000..312eccbf63
--- /dev/null
+++ b/components/drivers/rpmsg/rpmsg_char.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-02-25 GuEe-GUI the first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "rpmsg.char"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct rpmsg_char_ctrl;
+
+struct rpmsg_char
+{
+ struct rt_device parent;
+ rt_list_t list;
+
+ struct rpmsg_char_ctrl *rchc;
+ struct rt_rpmsg_endpoint *ept;
+
+ rt_bool_t is_overwrite;
+ struct rt_ringbuffer msg_ring;
+ rt_uint8_t msg_pool[RT_RPMSG_CHAR_MSG_SIZE_MAX * RT_RPMSG_CHAR_MSG_MAX];
+};
+
+struct rpmsg_char_ctrl
+{
+ struct rt_device parent;
+
+ struct rt_rpmsg_device *rdev;
+
+ rt_list_t ept_nodes;
+ rt_list_t del_ept_nodes;
+ struct rt_spinlock lock;
+ struct rt_work del_ept_work;
+};
+
+#define raw_to_rpmsg_char(raw) rt_container_of(raw, struct rpmsg_char, parent)
+#define raw_to_rpmsg_char_ctrl(raw) rt_container_of(raw, struct rpmsg_char_ctrl, parent)
+
+static struct rt_dm_ida rpmsg_ept_ida = RT_DM_IDA_INIT(RPMSG_EPT);
+static struct rt_dm_ida rpmsg_char_ida = RT_DM_IDA_INIT(RPMSG_CHAR);
+
+static rt_err_t rpmsg_char_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ rt_ubase_t level;
+ rt_err_t err = RT_EOK;
+ struct rpmsg_char_ctrl *rchc;
+ struct rpmsg_char *this_rch = raw_to_rpmsg_char(dev), *rch, *rch_next;
+
+ rchc = this_rch->rchc;
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+
+ rt_list_for_each_entry_safe(rch, rch_next, &rchc->del_ept_nodes, list)
+ {
+ if (rch == this_rch)
+ {
+ /* It's been cleaned. Don't open it. */
+ err = -RT_EIO;
+ break;
+ }
+ }
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ return err;
+}
+
+static rt_ssize_t rpmsg_char_read(rt_device_t dev,
+ rt_off_t pos, void *buffer, rt_size_t size)
+{
+ struct rpmsg_char *rch = raw_to_rpmsg_char(dev);
+
+ return rt_ringbuffer_get(&rch->msg_ring, buffer, size);
+}
+
+static rt_ssize_t rpmsg_char_write(rt_device_t dev,
+ rt_off_t pos, const void *buffer, rt_size_t size)
+{
+ struct rpmsg_char *rch = raw_to_rpmsg_char(dev);
+
+ return rt_rpmsg_send(rch->ept, buffer, size) ? : size;
+}
+
+static rt_err_t rpmsg_char_control(rt_device_t dev, int cmd, void *args)
+{
+ struct rpmsg_char *rch = raw_to_rpmsg_char(dev);
+
+ if (cmd == RT_DEVICE_CTRL_RPMSG_DESTROY_EPT)
+ {
+ if (dev->ref_count == 1)
+ {
+ rt_ubase_t level;
+
+ level = rt_spin_lock_irqsave(&rch->rchc->lock);
+ rt_list_remove(&rch->list);
+ rt_list_insert_before(&rch->rchc->del_ept_nodes, &rch->list);
+ rt_spin_unlock_irqrestore(&rch->rchc->lock, level);
+
+ rt_work_submit(&rch->rchc->del_ept_work,
+ RT_SCHED_PRIV(rt_thread_self()).remaining_tick);
+ }
+
+ return RT_EOK;
+ }
+
+ if (cmd == RT_DEVICE_CTRL_RPMSG_DATA_OVERWRITE)
+ {
+ rch->is_overwrite = !!args;
+
+ return RT_EOK;
+ }
+
+ return -RT_EINVAL;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops rpmsg_char_ops =
+{
+ .open = rpmsg_char_open,
+ .read = rpmsg_char_read,
+ .write = rpmsg_char_write,
+ .control = rpmsg_char_control,
+};
+#endif
+
+static rt_err_t rpmsg_char_rx_callback(struct rt_rpmsg_device *rdev,
+ rt_uint32_t src, void *data, rt_size_t len)
+{
+ rt_size_t res_size;
+ struct rpmsg_char *rch;
+ struct rt_rpmsg_endpoint *ept;
+ struct rt_rpmsg_endpoint_info info;
+
+ RT_ASSERT(len <= RT_RPMSG_CHAR_MSG_SIZE_MAX);
+
+ info.src = RT_RPMSG_ADDR_ANY;
+ info.dst = src;
+ info.name[0] = '\0';
+ ept = rt_rpmsg_find_endpoint(rdev, &info);
+
+ if (ept)
+ {
+ rch = ept->priv;
+
+ if (rch->is_overwrite)
+ {
+ res_size = rt_ringbuffer_put_force(&rch->msg_ring, data, len);
+ }
+ else
+ {
+ res_size = rt_ringbuffer_put(&rch->msg_ring, data, len);
+ }
+ }
+ else
+ {
+ return -RT_EINVAL;
+ }
+
+ return res_size ? RT_EOK : -RT_ENOMEM;
+}
+
+static void rpmsg_char_ctrl_del_ept_work(struct rt_work *work, void *work_data)
+{
+ rt_ubase_t level;
+ rt_size_t clean_count = 0;
+ struct rpmsg_char *rch, *rch_next;
+ struct rpmsg_char_ctrl *rchc = work_data;
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+
+ rt_list_for_each_entry_safe(rch, rch_next, &rchc->del_ept_nodes, list)
+ {
+ if (rch->parent.open_flag == RT_DEVICE_OFLAG_CLOSE)
+ {
+ rt_list_remove(&rch->list);
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ rt_rpmsg_destroy_endpoint(rchc->rdev, rch->ept);
+
+ rt_dm_ida_free(&rpmsg_ept_ida, rch->parent.device_id);
+
+ rt_device_unregister(&rch->parent);
+ rt_free(rch);
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+
+ ++clean_count;
+ }
+ }
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ if (!clean_count)
+ {
+ /* Try again */
+ rt_work_submit(&rchc->del_ept_work, RT_TICK_PER_SECOND);
+ }
+}
+
+static rt_err_t rpmsg_char_ctrl_control(rt_device_t dev, int cmd, void *args)
+{
+ struct rpmsg_char_ctrl *rchc = raw_to_rpmsg_char_ctrl(dev);
+
+ if (cmd == RT_DEVICE_CTRL_RPMSG_CREATE_EPT && args)
+ {
+ int device_id;
+ rt_ubase_t level;
+ struct rpmsg_char *rch;
+ struct rt_rpmsg_endpoint *ept;
+ struct rt_rpmsg_endpoint_info *info = args;
+
+ if (!info->name[0])
+ {
+ rt_strncpy(info->name, "rpmsg-raw", RT_RPMSG_NAME_SIZE);
+ }
+
+ ept = rt_rpmsg_create_endpoint(rchc->rdev, info, &rpmsg_char_rx_callback);
+
+ if (rt_is_err(ept))
+ {
+ return rt_ptr_err(ept);
+ }
+
+ rch = rt_calloc(1, sizeof(*rch));
+
+ if (!rch)
+ {
+ rt_rpmsg_destroy_endpoint(rchc->rdev, ept);
+ return -RT_ENOMEM;
+ }
+
+ if ((device_id = rt_dm_ida_alloc(&rpmsg_ept_ida)) < 0)
+ {
+ rt_free(rch);
+ rt_rpmsg_destroy_endpoint(rchc->rdev, ept);
+ return -RT_EFULL;
+ }
+
+ ept->priv = rch;
+ rch->ept = ept;
+ rch->rchc = rchc;
+
+ rch->parent.type = RT_Device_Class_Char;
+ #ifdef RT_USING_DEVICE_OPS
+ rch->parent.ops = &rpmsg_char_ops;
+ #else
+ rch->parent.read = rpmsg_char_read;
+ rch->parent.write = rpmsg_char_write;
+ rch->parent.control = rpmsg_char_control;
+ #endif
+ rch->parent.master_id = rpmsg_ept_ida.master_id;
+ rch->parent.device_id = device_id;
+
+ rt_ringbuffer_init(&rch->msg_ring, rch->msg_pool, sizeof(rch->msg_pool));
+ rt_dm_dev_set_name(&rch->parent, "rpmsg_%ux%u", ept->info.src, ept->info.dst);
+
+ rt_list_init(&rch->list);
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+ rt_list_insert_before(&rchc->ept_nodes, &rch->list);
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ rt_device_register(&rch->parent, rt_dm_dev_get_name(&rch->parent),
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
+
+ return RT_EOK;
+ }
+
+ return -RT_EINVAL;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops rpmsg_char_ctrl_ops =
+{
+ .control = rpmsg_char_ctrl_control,
+};
+#endif
+
+static rt_err_t rpmsg_char_probe(struct rt_rpmsg_device *rdev)
+{
+ rt_err_t err;
+ int device_id;
+ struct rpmsg_char_ctrl *rchc = rt_calloc(1, sizeof(*rchc));
+
+ if (!rchc)
+ {
+ return -RT_ENOMEM;
+ }
+
+ if ((device_id = rt_dm_ida_alloc(&rpmsg_char_ida)) < 0)
+ {
+ err = -RT_EFULL;
+ goto _free_dev;
+ }
+
+ rchc->rdev = rdev;
+ rdev->parent.user_data = rchc;
+
+ rt_list_init(&rchc->ept_nodes);
+ rt_list_init(&rchc->del_ept_nodes);
+ rt_spin_lock_init(&rchc->lock);
+ rt_work_init(&rchc->del_ept_work, rpmsg_char_ctrl_del_ept_work, rchc);
+
+ rt_dm_dev_set_name(&rchc->parent, "rpmsg_char%u", device_id);
+
+ rchc->parent.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ rchc->parent.ops = &rpmsg_char_ctrl_ops;
+#else
+ rchc->parent.control = rpmsg_char_ctrl_control;
+#endif
+ rchc->parent.master_id = rpmsg_char_ida.master_id;
+ rchc->parent.device_id = device_id;
+
+ if ((err = rt_device_register(&rchc->parent, rt_dm_dev_get_name(&rchc->parent),
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_dm_ida_free(&rpmsg_char_ida, device_id);
+_free_dev:
+ rt_free(rchc);
+
+ return err;
+}
+
+static rt_err_t rpmsg_char_remove(struct rt_rpmsg_device *rdev)
+{
+ rt_ubase_t level;
+ struct rpmsg_char *rch, *rch_next;
+ struct rpmsg_char_ctrl *rchc = rdev->parent.user_data;
+
+ rt_work_cancel(&rchc->del_ept_work);
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+
+ rt_list_for_each_entry_safe(rch, rch_next, &rchc->ept_nodes, list)
+ {
+ rt_list_remove(&rch->list);
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ rt_rpmsg_destroy_endpoint(rchc->rdev, rch->ept);
+
+ rt_dm_ida_free(&rpmsg_ept_ida, rch->parent.device_id);
+
+ rt_device_unregister(&rch->parent);
+ rt_free(rch);
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+ }
+
+ rt_list_for_each_entry_safe(rch, rch_next, &rchc->del_ept_nodes, list)
+ {
+ rt_list_remove(&rch->list);
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ rt_rpmsg_destroy_endpoint(rchc->rdev, rch->ept);
+
+ rt_dm_ida_free(&rpmsg_ept_ida, rch->parent.device_id);
+
+ rt_device_unregister(&rch->parent);
+ rt_free(rch);
+
+ level = rt_spin_lock_irqsave(&rchc->lock);
+ }
+
+ rt_spin_unlock_irqrestore(&rchc->lock, level);
+
+ rt_dm_ida_free(&rpmsg_char_ida, rchc->parent.device_id);
+
+ rt_device_unregister(&rchc->parent);
+
+ rt_free(rchc);
+
+ return RT_EOK;
+}
+
+static struct rt_rpmsg_device_id rpmsg_char_ids[] =
+{
+ { .name = "rpmsg-raw" },
+ { .name = "rpmsg-char" },
+ { /* sentinel */ }
+};
+
+static struct rt_rpmsg_driver rpmsg_char_driver =
+{
+ .parent.parent =
+ {
+ .name = "rpmsg-char",
+ },
+ .ids = rpmsg_char_ids,
+
+ .probe = rpmsg_char_probe,
+ .remove = rpmsg_char_remove,
+};
+RT_RPMSG_DRIVER_EXPORT(rpmsg_char_driver);
diff --git a/components/drivers/rpmsg/rpmsg_ns.c b/components/drivers/rpmsg/rpmsg_ns.c
new file mode 100755
index 0000000000..9383cb2fa7
--- /dev/null
+++ b/components/drivers/rpmsg/rpmsg_ns.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-02-25 GuEe-GUI the first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "rpmsg.ns"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+/*
+ * Used when rt_rpmsg_create_endpoint(..., RT_NULL) (e.g. remote NS announce);
+ * application traffic should be bound via a higher layer later.
+ */
+static rt_err_t rpmsg_ns_remote_default_rx(struct rt_rpmsg_device *rdev,
+ rt_uint32_t src, void *data, rt_size_t len)
+{
+ LOG_D("%s: remote endpoint rx (no user cb), src=%u len=%u", rt_dm_dev_get_name(&rdev->parent), src, len);
+
+ return RT_EOK;
+}
+
+static rt_err_t rpmsg_ns_rx_callback(struct rt_rpmsg_device *rdev,
+ rt_uint32_t src, void *data, rt_size_t len)
+{
+ rt_err_t err = RT_EOK;
+ struct rt_rpmsg_ns_msg *msg = data;
+ struct rt_rpmsg_endpoint *ept;
+ struct rt_rpmsg_endpoint_info info;
+
+ if (len != sizeof(*msg))
+ {
+ LOG_E("Invalid MSG size = %d", len);
+
+ return -RT_EINVAL;
+ }
+
+ /* Fixup the name */
+ msg->name[RT_RPMSG_NAME_SIZE - 1] = '\0';
+ rt_strncpy(info.name, msg->name, RT_RPMSG_NAME_SIZE);
+ info.src = RT_RPMSG_ADDR_ANY;
+ info.dst = rt_le32_to_cpu(msg->addr);
+
+ LOG_D("%s: name: %s, src: %u, dst: %u", rt_dm_dev_get_name(&rdev->parent),
+ info.name, info.src, info.dst);
+
+ if (rt_le32_to_cpu(msg->flags) & RT_RPMSG_NS_DESTROY)
+ {
+ ept = rt_rpmsg_find_endpoint(rdev, &info);
+
+ if (ept)
+ {
+ err = rt_rpmsg_destroy_endpoint(rdev, ept);
+ }
+ else
+ {
+ err = -RT_EEMPTY;
+ }
+ }
+ else if (rt_le32_to_cpu(msg->flags) == RT_RPMSG_NS_CREATE)
+ {
+ ept = rt_rpmsg_create_endpoint(rdev, &info, RT_NULL);
+
+ if (rt_is_err(ept))
+ {
+ err = rt_ptr_err(ept);
+ }
+ }
+ else
+ {
+ LOG_E("Unsupported flags = %x", rt_le32_to_cpu(msg->flags));
+ }
+
+ if (err)
+ {
+ LOG_E("%s: name = %s, addr = %x flags = %d error = %s",
+ rt_dm_dev_get_name(&rdev->parent),
+ msg->name, msg->addr, msg->flags, rt_strerror(err));
+ }
+
+ return err;
+}
+
+static rt_err_t rpmsg_ns_probe(struct rt_rpmsg_device *rdev)
+{
+ struct rt_rpmsg_endpoint *ep;
+ struct rt_rpmsg_endpoint_info info;
+
+ rt_strncpy(info.name, "name-service", RT_RPMSG_NAME_SIZE);
+ info.src = RT_RPMSG_NS_ADDR;
+ info.dst = RT_RPMSG_NS_ADDR;
+
+ ep = rt_rpmsg_create_endpoint(rdev, &info, &rpmsg_ns_rx_callback);
+
+ return rt_is_err(ep) ? rt_ptr_err(ep) : RT_EOK;
+}
+
+static struct rt_rpmsg_device_id rpmsg_ns_ids[] =
+{
+ { .name = "rpmsg-name-service" },
+ { /* sentinel */ }
+};
+
+static struct rt_rpmsg_driver rpmsg_ns_driver =
+{
+ .parent.parent =
+ {
+ .name = "rpmsg-ns",
+ },
+ .ids = rpmsg_ns_ids,
+
+ .probe = rpmsg_ns_probe,
+ .rx_callback = rpmsg_ns_remote_default_rx,
+};
+RT_RPMSG_DRIVER_EXPORT(rpmsg_ns_driver);