source: mainline/uspace/lib/drv/generic/remote_audio_pcm_buffer.c@ 722912e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 722912e was 722912e, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

Fix mainline merge breakage.

  • Property mode set to 100644
File size: 15.7 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/** @addtogroup libdrv
29 * @{
30 */
31/** @file
32 */
33
34#include <async.h>
35#include <errno.h>
36#include <assert.h>
37#include <str.h>
38#include <as.h>
39#include <sys/mman.h>
40
41#include "audio_pcm_buffer_iface.h"
42#include "ddf/driver.h"
43
44typedef enum {
45 IPC_M_AUDIO_PCM_GET_INFO_STR,
46 IPC_M_AUDIO_PCM_GET_BUFFER,
47 IPC_M_AUDIO_PCM_RELEASE_BUFFER,
48 IPC_M_AUDIO_PCM_START_PLAYBACK,
49 IPC_M_AUDIO_PCM_STOP_PLAYBACK,
50 IPC_M_AUDIO_PCM_START_RECORD,
51 IPC_M_AUDIO_PCM_STOP_RECORD,
52} audio_pcm_iface_funcs_t;
53
54/*
55 * CLIENT SIDE
56 */
57int audio_pcm_buffer_get_info_str(async_exch_t *exch, const char **name)
58{
59 if (!exch)
60 return EINVAL;
61 sysarg_t name_size;
62 const int ret = async_req_1_1(exch,
63 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
64 IPC_M_AUDIO_PCM_GET_INFO_STR, &name_size);
65 if (ret == EOK && name) {
66 char *name_place = calloc(1, name_size);
67 if (!name_place) {
68 /* Make the other side fail
69 * as it waits for read request */
70 async_data_read_start(exch, (void*)-1, 0);
71 return ENOMEM;
72 }
73 const int ret =
74 async_data_read_start(exch, name_place, name_size);
75 if (ret != EOK) {
76 free(name_place);
77 return ret;
78 }
79 *name = name_place;
80 }
81 return ret;
82}
83/*----------------------------------------------------------------------------*/
84int audio_pcm_buffer_get_buffer(async_exch_t *exch, void **buffer, size_t *size,
85 unsigned *id)
86{
87 if (!exch || !buffer || !size)
88 return EINVAL;
89 sysarg_t buffer_size, buffer_id;
90 const int ret = async_req_1_2(exch,
91 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_GET_BUFFER,
92 &buffer_size, &buffer_id);
93 if (ret == EOK) {
94 void *dst = NULL;
95 const int ret =
96 async_share_in_start_0_0(exch, buffer_size, &dst);
97 if (ret != EOK) {
98 return ret;
99 }
100 *buffer = dst;
101 *size = buffer_size;
102 }
103 if (ret == EOK && id)
104 *id = buffer_id;
105 return ret;
106}
107/*----------------------------------------------------------------------------*/
108int audio_pcm_buffer_release_buffer(async_exch_t *exch, unsigned id)
109{
110 if (!exch)
111 return EINVAL;
112 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
113 IPC_M_AUDIO_PCM_RELEASE_BUFFER, id);
114}
115/*----------------------------------------------------------------------------*/
116int audio_pcm_buffer_start_playback(async_exch_t *exch, unsigned id,
117 unsigned sample_rate, uint16_t sample_size, uint8_t channels, bool sign)
118{
119 if (!exch)
120 return EINVAL;
121 sysarg_t packed =
122 (sample_size << 16) | (channels << 8) | (sign ? 1 : 0);
123 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
124 IPC_M_AUDIO_PCM_START_PLAYBACK, id, sample_rate, packed);
125}
126/*----------------------------------------------------------------------------*/
127int audio_pcm_buffer_stop_playback(async_exch_t *exch, unsigned id)
128{
129 if (!exch)
130 return EINVAL;
131 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
132 IPC_M_AUDIO_PCM_STOP_PLAYBACK, id);
133}
134/*----------------------------------------------------------------------------*/
135int audio_pcm_buffer_start_record(async_exch_t *exch, unsigned id,
136 unsigned sample_rate, unsigned sample_size, unsigned channels, bool sign)
137{
138 if (!exch || sample_size > UINT16_MAX || channels > (UINT16_MAX >> 1))
139 return EINVAL;
140 sysarg_t packed = sample_size << 16 | channels << 1 | sign ? 1 : 0;
141 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
142 IPC_M_AUDIO_PCM_START_RECORD, id, sample_rate, packed);
143}
144/*----------------------------------------------------------------------------*/
145int audio_pcm_buffer_stop_record(async_exch_t *exch, unsigned id)
146{
147 if (!exch)
148 return EINVAL;
149 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
150 IPC_M_AUDIO_PCM_STOP_RECORD, id);
151}
152
153/*
154 * SERVER SIDE
155 */
156static void remote_audio_pcm_get_info_str(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
157static void remote_audio_pcm_get_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
158static void remote_audio_pcm_release_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
159static void remote_audio_pcm_start_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
160static void remote_audio_pcm_stop_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
161static void remote_audio_pcm_start_record(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
162static void remote_audio_pcm_stop_record(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
163
164/** Remote audio pcm buffer interface operations. */
165static remote_iface_func_ptr_t remote_audio_pcm_iface_ops[] = {
166 [IPC_M_AUDIO_PCM_GET_INFO_STR] = remote_audio_pcm_get_info_str,
167 [IPC_M_AUDIO_PCM_GET_BUFFER] = remote_audio_pcm_get_buffer,
168 [IPC_M_AUDIO_PCM_RELEASE_BUFFER] = remote_audio_pcm_release_buffer,
169 [IPC_M_AUDIO_PCM_START_PLAYBACK] = remote_audio_pcm_start_playback,
170 [IPC_M_AUDIO_PCM_STOP_PLAYBACK] = remote_audio_pcm_stop_playback,
171 [IPC_M_AUDIO_PCM_START_RECORD] = remote_audio_pcm_start_record,
172 [IPC_M_AUDIO_PCM_STOP_RECORD] = remote_audio_pcm_stop_record,
173};
174
175/** Remote audio mixer interface structure. */
176remote_iface_t remote_audio_pcm_buffer_iface = {
177 .method_count = sizeof(remote_audio_pcm_iface_ops) /
178 sizeof(remote_audio_pcm_iface_ops[0]),
179 .methods = remote_audio_pcm_iface_ops
180};
181/*----------------------------------------------------------------------------*/
182void remote_audio_pcm_get_info_str(ddf_fun_t *fun, void *iface,
183 ipc_callid_t callid, ipc_call_t *call)
184{
185 const audio_pcm_buffer_iface_t *pcm_iface = iface;
186
187 if (!pcm_iface->get_info_str) {
188 async_answer_0(callid, ENOTSUP);
189 return;
190 }
191 const char *name = NULL;
192 const int ret = pcm_iface->get_info_str(fun, &name);
193 const size_t name_size = name ? str_size(name) + 1 : 0;
194 async_answer_1(callid, ret, name_size);
195 /* Send the string. */
196 if (ret == EOK && name_size > 0) {
197 size_t size;
198 ipc_callid_t name_id;
199 if (!async_data_read_receive(&name_id, &size)) {
200 async_answer_0(name_id, EPARTY);
201 return;
202 }
203 if (size != name_size) {
204 async_answer_0(name_id, ELIMIT);
205 return;
206 }
207 async_data_read_finalize(name_id, name, name_size);
208 }
209}
210/*----------------------------------------------------------------------------*/
211void remote_audio_pcm_get_buffer(ddf_fun_t *fun, void *iface,
212 ipc_callid_t callid, ipc_call_t *call)
213{
214 const audio_pcm_buffer_iface_t *pcm_iface = iface;
215
216 if (!pcm_iface->get_buffer) {
217 async_answer_0(callid, ENOTSUP);
218 return;
219 }
220 void *buffer = NULL;
221 size_t size = 0;
222 unsigned id = 0;
223 const int ret = pcm_iface->get_buffer(fun, &buffer, &size, &id);
224 async_answer_2(callid, ret, size, id);
225 /* Share the buffer. */
226 if (ret == EOK && size > 0) {
227 size_t share_size;
228 ipc_callid_t name_id;
229 if (!async_share_in_receive(&name_id, &share_size)) {
230 async_answer_0(name_id, EPARTY);
231 return;
232 }
233 if (share_size != size) {
234 async_answer_0(name_id, ELIMIT);
235 return;
236 }
237 async_share_in_finalize(name_id, buffer, PROTO_READ | PROTO_WRITE);
238 }
239}
240/*----------------------------------------------------------------------------*/
241void remote_audio_pcm_release_buffer(ddf_fun_t *fun, void *iface,
242 ipc_callid_t callid, ipc_call_t *call)
243{
244 const audio_pcm_buffer_iface_t *pcm_iface = iface;
245
246 const unsigned id = DEV_IPC_GET_ARG1(*call);
247 const int ret = pcm_iface->release_buffer ?
248 pcm_iface->release_buffer(fun, id) : ENOTSUP;
249 async_answer_0(callid, ret);
250}
251/*----------------------------------------------------------------------------*/
252void remote_audio_pcm_start_playback(ddf_fun_t *fun, void *iface,
253 ipc_callid_t callid, ipc_call_t *call)
254{
255 const audio_pcm_buffer_iface_t *pcm_iface = iface;
256
257 const unsigned id = DEV_IPC_GET_ARG1(*call);
258 const unsigned rate = DEV_IPC_GET_ARG2(*call);
259 const unsigned size = DEV_IPC_GET_ARG3(*call) >> 16;
260 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 8) && UINT8_MAX;
261 const bool sign = (bool)(DEV_IPC_GET_ARG3(*call) & 1);
262
263 const int ret = pcm_iface->start_playback
264 ? pcm_iface->start_playback(fun, id, rate, size, channels, sign)
265 : ENOTSUP;
266 async_answer_0(callid, ret);
267}
268/*----------------------------------------------------------------------------*/
269void remote_audio_pcm_stop_playback(ddf_fun_t *fun, void *iface,
270 ipc_callid_t callid, ipc_call_t *call)
271{
272 const audio_pcm_buffer_iface_t *pcm_iface = iface;
273
274 const unsigned id = DEV_IPC_GET_ARG1(*call);
275 const int ret = pcm_iface->stop_playback ?
276 pcm_iface->stop_playback(fun, id) : ENOTSUP;
277 async_answer_0(callid, ret);
278}
279/*----------------------------------------------------------------------------*/
280void remote_audio_pcm_start_record(ddf_fun_t *fun, void *iface,
281 ipc_callid_t callid, ipc_call_t *call)
282{
283 const audio_pcm_buffer_iface_t *pcm_iface = iface;
284
285 const unsigned id = DEV_IPC_GET_ARG1(*call);
286 const unsigned rate = DEV_IPC_GET_ARG2(*call);
287 const unsigned size = DEV_IPC_GET_ARG3(*call) >> 16;
288 const unsigned channels = (DEV_IPC_GET_ARG3(*call) & UINT16_MAX) >> 1;
289 const bool sign = (bool)(DEV_IPC_GET_ARG3(*call) & 1);
290
291 const int ret = pcm_iface->start_record
292 ? pcm_iface->start_record(fun, id, rate, size, channels, sign)
293 : ENOTSUP;
294 async_answer_0(callid, ret);
295}
296/*----------------------------------------------------------------------------*/
297void remote_audio_pcm_stop_record(ddf_fun_t *fun, void *iface,
298 ipc_callid_t callid, ipc_call_t *call)
299{
300 const audio_pcm_buffer_iface_t *pcm_iface = iface;
301
302 const unsigned id = DEV_IPC_GET_ARG1(*call);
303 const int ret = pcm_iface->stop_record ?
304 pcm_iface->stop_record(fun, id) : ENOTSUP;
305 async_answer_0(callid, ret);
306}
307
308#if 0
309/*----------------------------------------------------------------------------*/
310void remote_audio_mixer_get_info(
311 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
312{
313 audio_mixer_iface_t *mixer_iface = iface;
314
315 if (!mixer_iface->get_info) {
316 async_answer_0(callid, ENOTSUP);
317 return;
318 }
319 const char *name = NULL;
320 unsigned items = 0;
321 const int ret = mixer_iface->get_info(fun, &name, &items);
322 const size_t name_size = name ? str_size(name) + 1 : 0;
323 async_answer_2(callid, ret, name_size, items);
324 /* Send the name. */
325 if (ret == EOK && name_size > 0) {
326 size_t size;
327 ipc_callid_t name_id;
328 if (!async_data_read_receive(&name_id, &size)) {
329 async_answer_0(name_id, EPARTY);
330 return;
331 }
332 if (size != name_size) {
333 async_answer_0(name_id, ELIMIT);
334 return;
335 }
336 async_data_read_finalize(name_id, name, name_size);
337 }
338}
339/*----------------------------------------------------------------------------*/
340void remote_audio_mixer_get_item_info(
341 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
342{
343 audio_mixer_iface_t *mixer_iface = iface;
344
345 if (!mixer_iface->get_item_info) {
346 async_answer_0(callid, ENOTSUP);
347 return;
348 }
349
350 const unsigned item = DEV_IPC_GET_ARG1(*call);
351 const char *name = NULL;
352 unsigned channels = 0;
353 const int ret = mixer_iface->get_item_info(fun, item, &name, &channels);
354 const size_t name_size = name ? str_size(name) + 1 : 0;
355 async_answer_2(callid, ret, name_size, channels);
356 /* Send the name. */
357 if (ret == EOK && name_size > 0) {
358 size_t size;
359 ipc_callid_t name_id;
360 if (!async_data_read_receive(&name_id, &size)) {
361 async_answer_0(name_id, EPARTY);
362 return;
363 }
364 if (size != name_size) {
365 async_answer_0(name_id, ELIMIT);
366 return;
367 }
368 async_data_read_finalize(name_id, name, name_size);
369 }
370}
371/*----------------------------------------------------------------------------*/
372void remote_audio_mixer_get_channel_info(
373 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
374{
375 audio_mixer_iface_t *mixer_iface = iface;
376
377 if (!mixer_iface->get_channel_info) {
378 async_answer_0(callid, ENOTSUP);
379 return;
380 }
381
382 const unsigned item = DEV_IPC_GET_ARG1(*call);
383 const unsigned channel = DEV_IPC_GET_ARG2(*call);
384 const char *name = NULL;
385 unsigned levels = 0;
386 const int ret =
387 mixer_iface->get_channel_info(fun, item, channel, &name, &levels);
388 const size_t name_size = name ? str_size(name) + 1 : 0;
389 async_answer_2(callid, ret, name_size, levels);
390 /* Send the name. */
391 if (ret == EOK && name_size > 0) {
392 size_t size;
393 ipc_callid_t name_id;
394 if (!async_data_read_receive(&name_id, &size)) {
395 async_answer_0(name_id, EPARTY);
396 return;
397 }
398 if (size != name_size) {
399 async_answer_0(name_id, ELIMIT);
400 return;
401 }
402 async_data_read_finalize(name_id, name, name_size);
403 }
404}
405/*----------------------------------------------------------------------------*/
406void remote_audio_mixer_channel_mute_set(
407 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
408{
409 audio_mixer_iface_t *mixer_iface = iface;
410
411 if (!mixer_iface->channel_mute_set) {
412 async_answer_0(callid, ENOTSUP);
413 return;
414 }
415 const unsigned item = DEV_IPC_GET_ARG1(*call);
416 const unsigned channel = DEV_IPC_GET_ARG2(*call);
417 const bool mute = DEV_IPC_GET_ARG3(*call);
418 const int ret = mixer_iface->channel_mute_set(fun, item, channel, mute);
419 async_answer_0(callid, ret);
420}
421/*----------------------------------------------------------------------------*/
422void remote_audio_mixer_channel_mute_get(
423 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
424{
425 audio_mixer_iface_t *mixer_iface = iface;
426
427 if (!mixer_iface->channel_mute_get) {
428 async_answer_0(callid, ENOTSUP);
429 return;
430 }
431 const unsigned item = DEV_IPC_GET_ARG1(*call);
432 const unsigned channel = DEV_IPC_GET_ARG2(*call);
433 bool mute = false;
434 const int ret =
435 mixer_iface->channel_mute_get(fun, item, channel, &mute);
436 async_answer_1(callid, ret, mute);
437}
438/*----------------------------------------------------------------------------*/
439void remote_audio_mixer_channel_volume_set(
440 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
441{
442 audio_mixer_iface_t *mixer_iface = iface;
443
444 if (!mixer_iface->channel_volume_set) {
445 async_answer_0(callid, ENOTSUP);
446 return;
447 }
448 const unsigned item = DEV_IPC_GET_ARG1(*call);
449 const unsigned channel = DEV_IPC_GET_ARG2(*call);
450 const unsigned level = DEV_IPC_GET_ARG3(*call);
451 const int ret =
452 mixer_iface->channel_volume_set(fun, item, channel, level);
453 async_answer_0(callid, ret);
454}
455/*----------------------------------------------------------------------------*/
456void remote_audio_mixer_channel_volume_get(
457 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
458{
459 audio_mixer_iface_t *mixer_iface = iface;
460
461 if (!mixer_iface->channel_volume_get) {
462 async_answer_0(callid, ENOTSUP);
463 return;
464 }
465 const unsigned item = DEV_IPC_GET_ARG1(*call);
466 const unsigned channel = DEV_IPC_GET_ARG2(*call);
467 unsigned current = 0, max = 0;
468 const int ret =
469 mixer_iface->channel_volume_get(fun, item, channel, &current, &max);
470 async_answer_2(callid, ret, current, max);
471}
472#endif
473
474/**
475 * @}
476 */
477
Note: See TracBrowser for help on using the repository browser.