diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index f04d3c7f489..386ba72734d 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -25,6 +25,7 @@ rsource "led/Kconfig" rsource "input/Kconfig" rsource "mailbox/Kconfig" rsource "hwspinlock/Kconfig" +rsource "rpmsg/Kconfig" rsource "phye/Kconfig" rsource "ata/Kconfig" rsource "nvme/Kconfig" diff --git a/components/drivers/include/drivers/rpmsg.h b/components/drivers/include/drivers/rpmsg.h new file mode 100755 index 00000000000..e44dfc7537c --- /dev/null +++ b/components/drivers/include/drivers/rpmsg.h @@ -0,0 +1,142 @@ +/* + * 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 + */ + +#ifndef __RPMSG_H__ +#define __RPMSG_H__ + +#include +#include + +#include +#include +#include + +#define RT_DEVICE_CTRL_RPMSG_CREATE_EPT (RT_DEVICE_CTRL_BASE(Char) + 'R' + 1) +#define RT_DEVICE_CTRL_RPMSG_DESTROY_EPT (RT_DEVICE_CTRL_BASE(Char) + 'R' + 2) +#define RT_DEVICE_CTRL_RPMSG_DATA_OVERWRITE (RT_DEVICE_CTRL_BASE(Char) + 'R' + 3) + +struct rt_rpmsg_device_id +{ +#define RT_RPMSG_NAME_SIZE 32 + char name[RT_RPMSG_NAME_SIZE]; + + const void *data; +}; + +struct rt_rpmsg_ops; +struct rt_rpmsg_endpoint; +struct rt_rpmsg_endpoint_info; + +struct rt_rpmsg_device +{ + struct rt_device parent; + + struct rt_rpmsg_device_id id; + rt_list_t ept_nodes; + struct rt_spinlock lock; + + const struct rt_rpmsg_ops *ops; + void *priv; +}; + +struct rt_rpmsg_driver +{ + struct rt_driver parent; + + const struct rt_rpmsg_device_id *ids; + + rt_err_t (*probe)(struct rt_rpmsg_device *rdev); + rt_err_t (*remove)(struct rt_rpmsg_device *rdev); + rt_err_t (*rx_callback)(struct rt_rpmsg_device *rdev, + rt_uint32_t src, void *data, rt_size_t len); +}; + +typedef rt_err_t (*rt_rpmsg_rx_callback)(struct rt_rpmsg_device *rdev, + rt_uint32_t src, void *data, rt_size_t len); + +struct rt_rpmsg_ops +{ + rt_err_t (*create_endpoint)(struct rt_rpmsg_device *, struct rt_rpmsg_endpoint *, + struct rt_rpmsg_endpoint_info *info); + rt_err_t (*destroy_endpoint)(struct rt_rpmsg_device *, struct rt_rpmsg_endpoint *); + rt_err_t (*send)(struct rt_rpmsg_device *, rt_uint32_t src, rt_uint32_t dst, + const void *data, rt_size_t len, rt_int32_t timeout); +}; + +struct rt_rpmsg_endpoint_info +{ + char name[RT_RPMSG_NAME_SIZE]; + +#define RT_RPMSG_ADDR_ANY 0xffffffff + rt_uint32_t src; + rt_uint32_t dst; +}; + +struct rt_rpmsg_endpoint +{ + rt_list_t list; + struct rt_rpmsg_device *rdev; + + struct rt_rpmsg_endpoint_info info; + rt_rpmsg_rx_callback rx_callback; + + struct rt_spinlock lock; + void *sysdata; + void *priv; +}; + +enum rt_rpmsg_ns_flags +{ + RT_RPMSG_NS_CREATE = 0, + RT_RPMSG_NS_DESTROY = 1, +}; + +rt_packed(struct rt_rpmsg_ns_msg +{ + char name[RT_RPMSG_NAME_SIZE]; + +#define RT_RPMSG_NS_ADDR 0x35 /* 0x35 -> 53 */ + rt_uint32_t addr; + rt_uint32_t flags; +}); + +enum +{ + RT_RPMSG_MODE_MASTER, + RT_RPMSG_MODE_SLAVE, + + RT_RPMSG_MODE_MAX, +}; + +rt_uint32_t rt_rpmsg_mode(void); + +struct rt_rpmsg_endpoint *rt_rpmsg_create_endpoint(struct rt_rpmsg_device *, + struct rt_rpmsg_endpoint_info *info, rt_rpmsg_rx_callback rx_cb); +rt_err_t rt_rpmsg_destroy_endpoint(struct rt_rpmsg_device *, + struct rt_rpmsg_endpoint *); +struct rt_rpmsg_endpoint *rt_rpmsg_find_endpoint(struct rt_rpmsg_device *, + struct rt_rpmsg_endpoint_info *info); + +rt_err_t rt_rpmsg_send(struct rt_rpmsg_endpoint *, + const void *data, rt_size_t len); +rt_err_t rt_rpmsg_sendto(struct rt_rpmsg_endpoint *, rt_uint32_t dst, + const void *data, rt_size_t len); + +rt_err_t rt_rpmsg_send_wait(struct rt_rpmsg_endpoint *, + const void *data, rt_size_t len, rt_int32_t timeout); +rt_err_t rt_rpmsg_sendto_wait(struct rt_rpmsg_endpoint *, rt_uint32_t dst, + const void *data, rt_size_t len, rt_int32_t timeout); + +rt_err_t rt_rpmsg_driver_register(struct rt_rpmsg_driver *rdrv); +rt_err_t rt_rpmsg_device_register(struct rt_rpmsg_device *rdev); + +#define RT_RPMSG_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, rpmsg, BUILIN) + +#endif /* __RPMSG_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index c3a1277449c..e059828f03c 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -78,6 +78,10 @@ extern "C" { #include "drivers/hwspinlock.h" #endif /* RT_USING_HWSPINLOCK */ +#ifdef RT_USING_RPMSG +#include "drivers/rpmsg.h" +#endif /* RT_USING_RPMSG */ + #ifdef RT_USING_BLK #include "drivers/blk.h" #endif /* RT_USING_BLK */ diff --git a/components/drivers/rpmsg/Kconfig b/components/drivers/rpmsg/Kconfig new file mode 100755 index 00000000000..4d886af13c4 --- /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 00000000000..a328d68ea39 --- /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 00000000000..031507b2721 --- /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 +#include + +#include +#include +#include +#include + +#define DBG_TAG "rtdm.rpmsg" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..312eccbf636 --- /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 +#include + +#define DBG_TAG "rpmsg.char" +#define DBG_LVL DBG_INFO +#include + +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 00000000000..9383cb2fa76 --- /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 +#include + +#define DBG_TAG "rpmsg.ns" +#define DBG_LVL DBG_INFO +#include + +/* + * 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);