zephyr/subsys/ipc/rpmsg_service/rpmsg_service.c

165 lines
3.2 KiB
C

/*
* Copyright (c) 2020-2021, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ipc/rpmsg_service.h>
#include "rpmsg_backend.h"
#include <zephyr.h>
#include <device.h>
#include <logging/log.h>
#include <openamp/open_amp.h>
#define LOG_MODULE_NAME rpmsg_service
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_RPMSG_SERVICE_LOG_LEVEL);
#define MASTER IS_ENABLED(CONFIG_RPMSG_SERVICE_MODE_MASTER)
static struct virtio_device vdev;
static struct rpmsg_virtio_device rvdev;
static struct metal_io_region *io;
static bool ep_crt_started;
#if MASTER
static struct rpmsg_virtio_shm_pool shpool;
#endif
static struct {
const char *name;
rpmsg_ept_cb cb;
struct rpmsg_endpoint ep;
volatile bool bound;
} endpoints[CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS];
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
{
rpmsg_destroy_ept(ep);
}
#if MASTER
static void ns_bind_cb(struct rpmsg_device *rdev,
const char *name,
uint32_t dest)
{
int err;
for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
if (strcmp(name, endpoints[i].name) == 0) {
err = rpmsg_create_ept(&endpoints[i].ep,
rdev,
name,
RPMSG_ADDR_ANY,
dest,
endpoints[i].cb,
rpmsg_service_unbind);
if (err != 0) {
LOG_ERR("Creating remote endpoint %s"
" failed wirh error %d", log_strdup(name), err);
} else {
endpoints[i].bound = true;
}
return;
}
}
LOG_ERR("Remote endpoint %s not registered locally", log_strdup(name));
}
#endif
static int rpmsg_service_init(const struct device *dev)
{
int32_t err;
(void)dev;
LOG_DBG("RPMsg service initialization start");
err = rpmsg_backend_init(&io, &vdev);
if (err) {
LOG_ERR("RPMsg backend init failed with error %d", err);
return err;
}
#if MASTER
rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE);
err = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool);
#else
err = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
#endif
if (err) {
LOG_ERR("rpmsg_init_vdev failed %d", err);
return err;
}
ep_crt_started = true;
#if !MASTER
struct rpmsg_device *rdev;
rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
if (endpoints[i].name) {
err = rpmsg_create_ept(&endpoints[i].ep,
rdev,
endpoints[i].name,
RPMSG_ADDR_ANY,
RPMSG_ADDR_ANY,
endpoints[i].cb,
rpmsg_service_unbind);
if (err) {
LOG_ERR("rpmsg_create_ept failed %d", err);
return err;
}
}
}
#endif
LOG_DBG("RPMsg service initialized");
return 0;
}
int rpmsg_service_register_endpoint(const char *name, rpmsg_ept_cb cb)
{
if (ep_crt_started) {
return -EINPROGRESS;
}
for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
if (!endpoints[i].name) {
endpoints[i].name = name;
endpoints[i].cb = cb;
return i;
}
}
LOG_ERR("No free slots to register endpoint %s", log_strdup(name));
return -ENOMEM;
}
bool rpmsg_service_endpoint_is_bound(int endpoint_id)
{
return endpoints[endpoint_id].bound;
}
int rpmsg_service_send(int endpoint_id, const void *data, size_t len)
{
return rpmsg_send(&endpoints[endpoint_id].ep, data, len);
}
SYS_INIT(rpmsg_service_init, POST_KERNEL, CONFIG_RPMSG_SERVICE_INIT_PRIORITY);