[dm][rpmsg] support Remote Processor Messaging (RPMSG)

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2026-05-09 13:30:10 +08:00
committed by Rbb666
parent ecf2409904
commit 46b90df247
8 changed files with 1042 additions and 0 deletions
+1
View File
@@ -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"
+142
View File
@@ -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 <rthw.h>
#include <rtthread.h>
#include <drivers/core/dm.h>
#include <drivers/core/driver.h>
#include <drivers/byteorder.h>
#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__ */
+4
View File
@@ -79,6 +79,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 */
+19
View File
@@ -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
+15
View File
@@ -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')
+327
View File
@@ -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);
+412
View File
@@ -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);
+122
View File
@@ -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);