1 /*
2  * Copyright (c) 2021, L&T Technology Services Ltd.
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <errno.h>
9 #include <openamp/rpmsg_rpc_client_server.h>
10 
11 static int rpmsg_endpoint_client_cb(struct rpmsg_endpoint *, void *, size_t,
12 				    uint32_t, void *);
13 
rpmsg_service_client_unbind(struct rpmsg_endpoint * ept)14 static void rpmsg_service_client_unbind(struct rpmsg_endpoint *ept)
15 {
16 	struct rpmsg_rpc_clt *rpc;
17 	(void)ept;
18 
19 	rpc = metal_container_of(ept, struct rpmsg_rpc_clt, ept);
20 	rpmsg_destroy_ept(&rpc->ept);
21 	if (rpc->shutdown_cb)
22 		rpc->shutdown_cb(rpc);
23 }
24 
rpmsg_rpc_client_init(struct rpmsg_rpc_clt * rpc,struct rpmsg_device * rdev,rpmsg_rpc_shutdown_cb shutdown_cb,const struct rpmsg_rpc_client_services * services,int len)25 int rpmsg_rpc_client_init(struct rpmsg_rpc_clt *rpc,
26 			  struct rpmsg_device *rdev,
27 			  rpmsg_rpc_shutdown_cb shutdown_cb,
28 			  const struct rpmsg_rpc_client_services *services,
29 			  int len)
30 {
31 	int ret;
32 
33 	if (!rpc || !rdev)
34 		return -EINVAL;
35 
36 	rpc->services = services;
37 	rpc->n_services = len;
38 
39 	rpc->shutdown_cb = shutdown_cb;
40 
41 	ret = rpmsg_create_ept(&rpc->ept, rdev,
42 			       RPMSG_RPC_SERVICE_NAME, RPMSG_ADDR_ANY,
43 			       RPMSG_ADDR_ANY,
44 			       rpmsg_endpoint_client_cb,
45 			       rpmsg_service_client_unbind);
46 
47 	return ret;
48 }
49 
rpmsg_rpc_client_send(struct rpmsg_rpc_clt * rpc,uint32_t rpc_id,void * request_param,size_t req_param_size)50 int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc,
51 			  uint32_t rpc_id, void *request_param,
52 			  size_t req_param_size)
53 {
54 	unsigned char tmpbuf[MAX_BUF_LEN];
55 
56 	if (!rpc)
57 		return -EINVAL;
58 
59 	/* to optimize with the zero copy API */
60 	memcpy(tmpbuf, &rpc_id, MAX_FUNC_ID_LEN);
61 	memcpy(&tmpbuf[MAX_FUNC_ID_LEN], request_param, req_param_size);
62 	return rpmsg_send(&rpc->ept, tmpbuf, MAX_FUNC_ID_LEN + req_param_size);
63 }
64 
find_service(struct rpmsg_rpc_clt * rpc,uint32_t id)65 static const struct rpmsg_rpc_client_services *find_service(struct
66 							    rpmsg_rpc_clt * rpc,
67 							    uint32_t id)
68 {
69 	const struct rpmsg_rpc_client_services *service;
70 
71 	for (unsigned int i = 0; i < rpc->n_services; i++) {
72 		service = &rpc->services[i];
73 
74 		if (service->id == id) {
75 			return service;
76 		}
77 	}
78 	return NULL;
79 }
80 
rpmsg_rpc_client_release(struct rpmsg_rpc_clt * rpc)81 void rpmsg_rpc_client_release(struct rpmsg_rpc_clt *rpc)
82 {
83 	if (!rpc)
84 		return;
85 	rpmsg_destroy_ept(&rpc->ept);
86 
87 }
88 
rpmsg_endpoint_client_cb(struct rpmsg_endpoint * ept,void * data,size_t len,uint32_t src,void * priv)89 static int rpmsg_endpoint_client_cb(struct rpmsg_endpoint *ept,
90 				    void *data, size_t len,
91 				    uint32_t src, void *priv)
92 {
93 	struct rpmsg_rpc_clt *rpc;
94 	const struct rpmsg_rpc_client_services *service;
95 	struct rpmsg_rpc_answer *msg;
96 	(void)priv;
97 	(void)src;
98 
99 	if (!data || !ept)
100 		return -EINVAL;
101 
102 	msg = (struct rpmsg_rpc_answer *)data;
103 
104 	rpc = metal_container_of(ept,
105 				 struct rpmsg_rpc_clt,
106 				 ept);
107 	service = find_service(rpc, msg->id);
108 	if (!service)
109 		return -EINVAL;
110 
111 	/* Invoke the callback function of the rpc */
112 	service->cb(rpc, msg->status, msg->params, len);
113 
114 	return RPMSG_SUCCESS;
115 }
116