source: mainline/uspace/lib/drv/generic/remote_audio_mixer.c

Last change on this file was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <errno.h>
37#include <assert.h>
38#include <str.h>
39#include <macros.h>
40
41#include "audio_mixer_iface.h"
42#include "ddf/driver.h"
43
44typedef enum {
45 /** Asks for basic mixer info: Mixer name and number of controllable
46 * items.
47 * Answer:
48 * - ENOTSUP - call not supported
49 * - EOK - call successful, info is valid
50 * Answer arguments:
51 * - Mixer name
52 * - Number of controllable items
53 */
54 IPC_M_AUDIO_MIXER_GET_INFO,
55
56 /** Asks for item mixer info: Item name and number of controllable
57 * channels.
58 * Answer:
59 * - ENOTSUP - call not supported
60 * - ENOENT - no such item
61 * - EOK - call successful, info is valid
62 * Answer arguments:
63 * - Item name
64 * - Number of controllable channels
65 */
66 IPC_M_AUDIO_MIXER_GET_ITEM_INFO,
67
68 /** Set new control item setting
69 * Answer:
70 * - ENOTSUP - call not supported
71 * - ENOENT - no such control item
72 * - EOK - call successful, info is valid
73 */
74 IPC_M_AUDIO_MIXER_SET_ITEM_LEVEL,
75
76 /** Get control item setting
77 * Answer:
78 * - ENOTSUP - call not supported
79 * - ENOENT - no such control item
80 * - EOK - call successful, info is valid
81 */
82 IPC_M_AUDIO_MIXER_GET_ITEM_LEVEL,
83} audio_mixer_iface_funcs_t;
84
85/*
86 * CLIENT SIDE
87 */
88
89/**
90 * Query audio mixer for basic info (name and items count).
91 * @param[in] exch IPC exchange connected to the device
92 * @param[out] name Audio mixer string identifier
93 * @param[out] items Number of items controlled by the mixer.
94 * @return Error code.
95 */
96errno_t audio_mixer_get_info(async_exch_t *exch, char **name, unsigned *items)
97{
98 if (!exch)
99 return EINVAL;
100 sysarg_t name_size, itemc;
101 const errno_t ret = async_req_1_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
102 IPC_M_AUDIO_MIXER_GET_INFO, &name_size, &itemc);
103 if (ret == EOK && name) {
104 char *name_place = calloc(1, name_size);
105 if (!name_place) {
106 /*
107 * Make the other side fail
108 * as it waits for read request
109 */
110 async_data_read_start(exch, (void *)-1, 0);
111 return ENOMEM;
112 }
113 const errno_t ret =
114 async_data_read_start(exch, name_place, name_size);
115 if (ret != EOK) {
116 free(name_place);
117 return ret;
118 }
119 *name = name_place;
120 }
121 if (ret == EOK && items)
122 *items = itemc;
123 return ret;
124}
125
126/**
127 * Query audio mixer for item specific info (name and channels count).
128 * @param[in] exch IPC exchange connected to the device
129 * @param[in] item The control item
130 * @param[out] name Control item string identifier.
131 * @param[out] channles Number of channels associated with this control item.
132 * @return Error code.
133 */
134errno_t audio_mixer_get_item_info(async_exch_t *exch, unsigned item,
135 char **name, unsigned *levels)
136{
137 if (!exch)
138 return EINVAL;
139 sysarg_t name_size, lvls;
140 const errno_t ret = async_req_2_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
141 IPC_M_AUDIO_MIXER_GET_ITEM_INFO, item, &name_size, &lvls);
142 if (ret == EOK && name) {
143 char *name_place = calloc(1, name_size);
144 if (!name_place) {
145 /*
146 * Make the other side fail
147 * as it waits for read request
148 */
149 async_data_read_start(exch, (void *)-1, 0);
150 return ENOMEM;
151 }
152 const errno_t ret =
153 async_data_read_start(exch, name_place, name_size);
154 if (ret != EOK) {
155 free(name_place);
156 return ret;
157 }
158 *name = name_place;
159 }
160 if (ret == EOK && levels)
161 *levels = lvls;
162 return ret;
163}
164
165/**
166 * Set control item to a new level.
167 * @param[in] exch IPC exchange connected to the device.
168 * @param[in] item The control item controlling the channel.
169 * @param[in] level The new value.
170 * @return Error code.
171 */
172errno_t audio_mixer_set_item_level(async_exch_t *exch, unsigned item,
173 unsigned level)
174{
175 if (!exch)
176 return EINVAL;
177 return async_req_3_0(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
178 IPC_M_AUDIO_MIXER_SET_ITEM_LEVEL, item, level);
179}
180
181/**
182 * Get current level of a control item.
183 * @param[in] exch IPC exchange connected to the device.
184 * @param[in] item The control item controlling the channel.
185 * @param[in] channel The channel index.
186 * @param[out] level Currently set value.
187 * @return Error code.
188 */
189errno_t audio_mixer_get_item_level(async_exch_t *exch, unsigned item,
190 unsigned *level)
191{
192 if (!exch)
193 return EINVAL;
194 sysarg_t current;
195 const errno_t ret = async_req_2_1(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
196 IPC_M_AUDIO_MIXER_GET_ITEM_LEVEL, item, &current);
197 if (ret == EOK && level)
198 *level = current;
199 return ret;
200}
201
202/*
203 * SERVER SIDE
204 */
205static void remote_audio_mixer_get_info(ddf_fun_t *, void *, ipc_call_t *);
206static void remote_audio_mixer_get_item_info(ddf_fun_t *, void *, ipc_call_t *);
207static void remote_audio_mixer_get_item_level(ddf_fun_t *, void *, ipc_call_t *);
208static void remote_audio_mixer_set_item_level(ddf_fun_t *, void *, ipc_call_t *);
209
210/** Remote audio mixer interface operations. */
211static const remote_iface_func_ptr_t remote_audio_mixer_iface_ops[] = {
212 [IPC_M_AUDIO_MIXER_GET_INFO] = remote_audio_mixer_get_info,
213 [IPC_M_AUDIO_MIXER_GET_ITEM_INFO] = remote_audio_mixer_get_item_info,
214 [IPC_M_AUDIO_MIXER_GET_ITEM_LEVEL] = remote_audio_mixer_get_item_level,
215 [IPC_M_AUDIO_MIXER_SET_ITEM_LEVEL] = remote_audio_mixer_set_item_level,
216};
217
218/** Remote audio mixer interface structure. */
219const remote_iface_t remote_audio_mixer_iface = {
220 .method_count = ARRAY_SIZE(remote_audio_mixer_iface_ops),
221 .methods = remote_audio_mixer_iface_ops
222};
223
224void remote_audio_mixer_get_info(ddf_fun_t *fun, void *iface, ipc_call_t *icall)
225{
226 audio_mixer_iface_t *mixer_iface = iface;
227
228 if (!mixer_iface->get_info) {
229 async_answer_0(icall, ENOTSUP);
230 return;
231 }
232
233 const char *name = NULL;
234 unsigned items = 0;
235 const errno_t ret = mixer_iface->get_info(fun, &name, &items);
236 const size_t name_size = name ? str_size(name) + 1 : 0;
237 async_answer_2(icall, ret, name_size, items);
238
239 /* Send the name. */
240 if (ret == EOK && name_size > 0) {
241 ipc_call_t call;
242 size_t size;
243 if (!async_data_read_receive(&call, &size)) {
244 async_answer_0(&call, EPARTY);
245 return;
246 }
247
248 if (size != name_size) {
249 async_answer_0(&call, ELIMIT);
250 return;
251 }
252
253 async_data_read_finalize(&call, name, name_size);
254 }
255}
256
257void remote_audio_mixer_get_item_info(ddf_fun_t *fun, void *iface,
258 ipc_call_t *icall)
259{
260 audio_mixer_iface_t *mixer_iface = iface;
261
262 if (!mixer_iface->get_item_info) {
263 async_answer_0(icall, ENOTSUP);
264 return;
265 }
266
267 const unsigned item = DEV_IPC_GET_ARG1(*icall);
268 const char *name = NULL;
269 unsigned values = 0;
270 const errno_t ret = mixer_iface->get_item_info(fun, item, &name, &values);
271 const size_t name_size = name ? str_size(name) + 1 : 0;
272 async_answer_2(icall, ret, name_size, values);
273
274 /* Send the name. */
275 if (ret == EOK && name_size > 0) {
276 ipc_call_t call;
277 size_t size;
278 if (!async_data_read_receive(&call, &size)) {
279 async_answer_0(&call, EPARTY);
280 return;
281 }
282
283 if (size != name_size) {
284 async_answer_0(&call, ELIMIT);
285 return;
286 }
287
288 async_data_read_finalize(&call, name, name_size);
289 }
290}
291
292void remote_audio_mixer_set_item_level(ddf_fun_t *fun, void *iface,
293 ipc_call_t *icall)
294{
295 audio_mixer_iface_t *mixer_iface = iface;
296
297 if (!mixer_iface->set_item_level) {
298 async_answer_0(icall, ENOTSUP);
299 return;
300 }
301
302 const unsigned item = DEV_IPC_GET_ARG1(*icall);
303 const unsigned value = DEV_IPC_GET_ARG2(*icall);
304 const errno_t ret = mixer_iface->set_item_level(fun, item, value);
305 async_answer_0(icall, ret);
306}
307
308void remote_audio_mixer_get_item_level(ddf_fun_t *fun, void *iface,
309 ipc_call_t *icall)
310{
311 audio_mixer_iface_t *mixer_iface = iface;
312
313 if (!mixer_iface->get_item_level) {
314 async_answer_0(icall, ENOTSUP);
315 return;
316 }
317
318 const unsigned item = DEV_IPC_GET_ARG1(*icall);
319 unsigned current = 0;
320 const errno_t ret =
321 mixer_iface->get_item_level(fun, item, &current);
322 async_answer_1(icall, ret, current);
323}
324
325/**
326 * @}
327 */
Note: See TracBrowser for help on using the repository browser.