121 lines
2.8 KiB
C
121 lines
2.8 KiB
C
/*
|
|
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/ipc/ipc_rpmsg.h>
|
|
|
|
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
|
|
{
|
|
rpmsg_destroy_ept(ep);
|
|
}
|
|
|
|
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
|
|
{
|
|
struct rpmsg_virtio_device *p_rvdev;
|
|
struct ipc_rpmsg_instance *instance;
|
|
struct ipc_rpmsg_ept *ept;
|
|
int err;
|
|
|
|
p_rvdev = CONTAINER_OF(rdev, struct rpmsg_virtio_device, rdev);
|
|
instance = CONTAINER_OF(p_rvdev->shpool, struct ipc_rpmsg_instance, shm_pool);
|
|
|
|
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
|
ept = &instance->endpoint[i];
|
|
|
|
if (strcmp(name, ept->name) == 0) {
|
|
/*
|
|
* The destination address is 'dest' so ns_bind_cb() is
|
|
* *NOT* called on the REMOTE side. The bound_cb()
|
|
* function will eventually take care of notifying the
|
|
* REMOTE side if needed.
|
|
*/
|
|
err = rpmsg_create_ept(&ept->ep, rdev, name, RPMSG_ADDR_ANY,
|
|
dest, instance->cb, rpmsg_service_unbind);
|
|
if (err != 0) {
|
|
return;
|
|
}
|
|
|
|
ept->bound = true;
|
|
if (instance->bound_cb) {
|
|
instance->bound_cb(ept);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int ipc_rpmsg_register_ept(struct ipc_rpmsg_instance *instance, unsigned int role,
|
|
struct ipc_rpmsg_ept *ept)
|
|
{
|
|
struct rpmsg_device *rdev;
|
|
|
|
if (!instance || !ept) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
rdev = rpmsg_virtio_get_rpmsg_device(&instance->rvdev);
|
|
|
|
if (role == RPMSG_REMOTE) {
|
|
/*
|
|
* The destination address is RPMSG_ADDR_ANY, this will trigger
|
|
* the ns_bind_cb() callback function on the HOST side.
|
|
*/
|
|
return rpmsg_create_ept(&ept->ep, rdev, ept->name, RPMSG_ADDR_ANY,
|
|
RPMSG_ADDR_ANY, instance->cb, rpmsg_service_unbind);
|
|
}
|
|
|
|
return RPMSG_SUCCESS;
|
|
}
|
|
|
|
int ipc_rpmsg_init(struct ipc_rpmsg_instance *instance,
|
|
unsigned int role,
|
|
unsigned int buffer_size,
|
|
struct metal_io_region *shm_io,
|
|
struct virtio_device *vdev,
|
|
void *shb, size_t size,
|
|
rpmsg_ns_bind_cb p_bind_cb)
|
|
{
|
|
rpmsg_ns_bind_cb bind_cb = p_bind_cb;
|
|
|
|
if (!instance || !shb) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (p_bind_cb == NULL) {
|
|
bind_cb = ns_bind_cb;
|
|
}
|
|
|
|
if (role == RPMSG_HOST) {
|
|
struct rpmsg_virtio_config config = { 0 };
|
|
|
|
config.h2r_buf_size = (uint32_t) buffer_size;
|
|
config.r2h_buf_size = (uint32_t) buffer_size;
|
|
|
|
rpmsg_virtio_init_shm_pool(&instance->shm_pool, shb, size);
|
|
|
|
return rpmsg_init_vdev_with_config(&instance->rvdev, vdev, bind_cb,
|
|
shm_io, &instance->shm_pool,
|
|
&config);
|
|
} else {
|
|
return rpmsg_init_vdev(&instance->rvdev, vdev, bind_cb, shm_io, NULL);
|
|
}
|
|
}
|
|
|
|
int ipc_rpmsg_deinit(struct ipc_rpmsg_instance *instance,
|
|
unsigned int role)
|
|
{
|
|
if (!instance) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
rpmsg_deinit_vdev(&instance->rvdev);
|
|
|
|
if (role == RPMSG_HOST) {
|
|
memset(&instance->shm_pool, 0, sizeof(struct rpmsg_virtio_shm_pool));
|
|
}
|
|
|
|
return 0;
|
|
}
|