/* * Copyright (c) 2020-2021, Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include "rpmsg_backend.h" #include #include #include #include #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", name, err); } else { endpoints[i].bound = true; } return; } } LOG_ERR("Remote endpoint %s not registered locally", name); } #endif static int rpmsg_service_init(void) { int32_t err; 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", 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);