1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/ipc/ipc_service.h>
9 #include <zephyr/ipc/ipc_service_backend.h>
10
11 #include <zephyr/logging/log.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14
15 LOG_MODULE_REGISTER(ipc_service, CONFIG_IPC_SERVICE_LOG_LEVEL);
16
ipc_service_open_instance(const struct device * instance)17 int ipc_service_open_instance(const struct device *instance)
18 {
19 const struct ipc_service_backend *backend;
20
21 if (!instance) {
22 LOG_ERR("Invalid instance");
23 return -EINVAL;
24 }
25
26 backend = (const struct ipc_service_backend *) instance->api;
27
28 if (!backend) {
29 LOG_ERR("Invalid backend configuration");
30 return -EIO;
31 }
32
33 if (!backend->open_instance) {
34 /* maybe not needed on backend */
35 return 0;
36 }
37
38 return backend->open_instance(instance);
39 }
40
ipc_service_close_instance(const struct device * instance)41 int ipc_service_close_instance(const struct device *instance)
42 {
43 const struct ipc_service_backend *backend;
44
45 if (!instance) {
46 LOG_ERR("Invalid instance");
47 return -EINVAL;
48 }
49
50 backend = (const struct ipc_service_backend *) instance->api;
51
52 if (!backend) {
53 LOG_ERR("Invalid backend configuration");
54 return -EIO;
55 }
56
57 if (!backend->close_instance) {
58 /* maybe not needed on backend */
59 return 0;
60 }
61
62 return backend->close_instance(instance);
63 }
64
ipc_service_register_endpoint(const struct device * instance,struct ipc_ept * ept,const struct ipc_ept_cfg * cfg)65 int ipc_service_register_endpoint(const struct device *instance,
66 struct ipc_ept *ept,
67 const struct ipc_ept_cfg *cfg)
68 {
69 const struct ipc_service_backend *backend;
70
71 if (!instance || !ept || !cfg) {
72 LOG_ERR("Invalid instance, endpoint or configuration");
73 return -EINVAL;
74 }
75
76 backend = (const struct ipc_service_backend *) instance->api;
77
78 if (!backend || !backend->register_endpoint) {
79 LOG_ERR("Invalid backend configuration");
80 return -EIO;
81 }
82
83 LOG_DBG("Register endpoint %s", cfg->name ? cfg->name : "");
84
85 ept->instance = instance;
86
87 return backend->register_endpoint(instance, &ept->token, cfg);
88 }
89
ipc_service_deregister_endpoint(struct ipc_ept * ept)90 int ipc_service_deregister_endpoint(struct ipc_ept *ept)
91 {
92 const struct ipc_service_backend *backend;
93 int err;
94
95 if (!ept) {
96 LOG_ERR("Invalid endpoint");
97 return -EINVAL;
98 }
99
100 if (!ept->instance) {
101 LOG_ERR("Endpoint not registered\n");
102 return -ENOENT;
103 }
104
105 backend = ept->instance->api;
106
107 if (!backend || !backend->deregister_endpoint) {
108 LOG_ERR("Invalid backend configuration");
109 return -EIO;
110 }
111
112 err = backend->deregister_endpoint(ept->instance, ept->token);
113 if (err != 0) {
114 return err;
115 }
116
117 ept->instance = 0;
118
119 return 0;
120 }
121
122
ipc_service_send(struct ipc_ept * ept,const void * data,size_t len)123 int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len)
124 {
125 const struct ipc_service_backend *backend;
126
127 if (!ept) {
128 LOG_ERR("Invalid endpoint");
129 return -EINVAL;
130 }
131
132 if (!ept->instance) {
133 LOG_ERR("Endpoint not registered\n");
134 return -ENOENT;
135 }
136
137 backend = ept->instance->api;
138
139 if (!backend || !backend->send) {
140 LOG_ERR("Invalid backend configuration");
141 return -EIO;
142 }
143
144 return backend->send(ept->instance, ept->token, data, len);
145 }
146
ipc_service_get_tx_buffer_size(struct ipc_ept * ept)147 int ipc_service_get_tx_buffer_size(struct ipc_ept *ept)
148 {
149 const struct ipc_service_backend *backend;
150
151 if (!ept) {
152 LOG_ERR("Invalid endpoint");
153 return -EINVAL;
154 }
155
156 if (!ept->instance) {
157 LOG_ERR("Endpoint not registered\n");
158 return -ENOENT;
159 }
160
161 backend = ept->instance->api;
162
163 if (!backend) {
164 LOG_ERR("Invalid backend configuration");
165 return -EIO;
166 }
167
168 if (!backend->get_tx_buffer_size) {
169 LOG_ERR("No-copy feature not available");
170 return -EIO;
171 }
172
173 return backend->get_tx_buffer_size(ept->instance, ept->token);
174 }
175
ipc_service_get_tx_buffer(struct ipc_ept * ept,void ** data,uint32_t * len,k_timeout_t wait)176 int ipc_service_get_tx_buffer(struct ipc_ept *ept, void **data, uint32_t *len, k_timeout_t wait)
177 {
178 const struct ipc_service_backend *backend;
179
180 if (!ept || !data || !len) {
181 LOG_ERR("Invalid endpoint, data or len pointer");
182 return -EINVAL;
183 }
184
185 if (!ept->instance) {
186 LOG_ERR("Endpoint not registered\n");
187 return -ENOENT;
188 }
189
190 backend = ept->instance->api;
191
192 if (!backend) {
193 LOG_ERR("Invalid backend configuration");
194 return -EIO;
195 }
196
197 if (!backend->send_nocopy || !backend->get_tx_buffer) {
198 LOG_ERR("No-copy feature not available");
199 return -EIO;
200 }
201
202 return backend->get_tx_buffer(ept->instance, ept->token, data, len, wait);
203 }
204
ipc_service_drop_tx_buffer(struct ipc_ept * ept,const void * data)205 int ipc_service_drop_tx_buffer(struct ipc_ept *ept, const void *data)
206 {
207 const struct ipc_service_backend *backend;
208
209 if (!ept || !data) {
210 LOG_ERR("Invalid endpoint or data pointer");
211 return -EINVAL;
212 }
213
214 if (!ept->instance) {
215 LOG_ERR("Endpoint not registered\n");
216 return -ENOENT;
217 }
218
219 backend = ept->instance->api;
220
221 if (!backend) {
222 LOG_ERR("Invalid backend configuration");
223 return -EIO;
224 }
225
226 if (!backend->drop_tx_buffer) {
227 LOG_ERR("No-copy feature not available");
228 return -EIO;
229 }
230
231 return backend->drop_tx_buffer(ept->instance, ept->token, data);
232 }
233
ipc_service_send_nocopy(struct ipc_ept * ept,const void * data,size_t len)234 int ipc_service_send_nocopy(struct ipc_ept *ept, const void *data, size_t len)
235 {
236 const struct ipc_service_backend *backend;
237
238 if (!ept) {
239 LOG_ERR("Invalid endpoint");
240 return -EINVAL;
241 }
242
243 if (!ept->instance) {
244 LOG_ERR("Endpoint not registered\n");
245 return -ENOENT;
246 }
247
248 backend = ept->instance->api;
249
250 if (!backend) {
251 LOG_ERR("Invalid backend configuration");
252 return -EIO;
253 }
254
255 if (!backend->get_tx_buffer || !backend->send_nocopy) {
256 LOG_ERR("No-copy feature not available");
257 return -EIO;
258 }
259
260 return backend->send_nocopy(ept->instance, ept->token, data, len);
261 }
262
ipc_service_hold_rx_buffer(struct ipc_ept * ept,void * data)263 int ipc_service_hold_rx_buffer(struct ipc_ept *ept, void *data)
264 {
265 const struct ipc_service_backend *backend;
266
267 if (!ept) {
268 LOG_ERR("Invalid endpoint");
269 return -EINVAL;
270 }
271
272 if (!ept->instance) {
273 LOG_ERR("Endpoint not registered\n");
274 return -ENOENT;
275 }
276
277 backend = ept->instance->api;
278
279 if (!backend) {
280 LOG_ERR("Invalid backend configuration");
281 return -EIO;
282 }
283
284 /* We also need the release function */
285 if (!backend->release_rx_buffer || !backend->hold_rx_buffer) {
286 LOG_ERR("No-copy feature not available");
287 return -EIO;
288 }
289
290 return backend->hold_rx_buffer(ept->instance, ept->token, data);
291 }
ipc_service_release_rx_buffer(struct ipc_ept * ept,void * data)292 int ipc_service_release_rx_buffer(struct ipc_ept *ept, void *data)
293 {
294 const struct ipc_service_backend *backend;
295
296 if (!ept) {
297 LOG_ERR("Invalid endpoint");
298 return -EINVAL;
299 }
300
301 if (!ept->instance) {
302 LOG_ERR("Endpoint not registered\n");
303 return -ENOENT;
304 }
305
306 backend = ept->instance->api;
307
308 if (!backend) {
309 LOG_ERR("Invalid backend configuration");
310 return -EIO;
311 }
312
313 /* We also need the hold function */
314 if (!backend->hold_rx_buffer || !backend->release_rx_buffer) {
315 LOG_ERR("No-copy feature not available");
316 return -EIO;
317 }
318
319 return backend->release_rx_buffer(ept->instance, ept->token, data);
320 }
321