• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

2  * \file pcm/pcm_mmap_emul.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Mmap-Emulation Plugin Interface
5 * \author Takashi Iwai <tiwai@suse.de>
6 * \date 2007
9 * PCM - Mmap-Emulation
10 * Copyright (c) 2007 by Takashi Iwai <tiwai@suse.de>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "pcm_local.h"
30 #include "pcm_generic.h"
32 #ifndef PIC
33 /* entry for static linking */
34 const char *_snd_module_pcm_mmap_emul = "";
35 #endif
37 #ifndef DOC_HIDDEN
42 typedef struct {
43 snd_pcm_generic_t gen;
44 unsigned int mmap_emul :1;
45 snd_pcm_uframes_t hw_ptr;
46 snd_pcm_uframes_t appl_ptr;
47 snd_pcm_uframes_t start_threshold;
48 } mmap_emul_t;
49 #endif
52 * here goes a really tricky part; hw_refine falls back to ACCESS_RW_* type
53 * when ACCESS_MMAP_* isn't supported by the hardware.
55 static int snd_pcm_mmap_emul_hw_refine(snd_pcm_t *pcm,
56 snd_pcm_hw_params_t *params)
58 mmap_emul_t *map = pcm->private_data;
59 int err = 0;
60 snd_pcm_access_mask_t oldmask =
61 *snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
62 snd_pcm_access_mask_t mask;
63 const snd_mask_t *pmask;
65 snd_mask_none(&mask);
66 err = snd_pcm_hw_refine(map->gen.slave, params);
67 if (err < 0) {
68 snd_pcm_hw_params_t new = *params;
70 /* try to use RW_* */
71 if (snd_pcm_access_mask_test(&oldmask,
72 SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
73 !snd_pcm_access_mask_test(&oldmask,
74 SND_PCM_ACCESS_RW_INTERLEAVED))
75 snd_pcm_access_mask_set(&mask,
76 SND_PCM_ACCESS_RW_INTERLEAVED);
77 if (snd_pcm_access_mask_test(&oldmask,
78 SND_PCM_ACCESS_MMAP_NONINTERLEAVED) &&
79 !snd_pcm_access_mask_test(&oldmask,
80 SND_PCM_ACCESS_RW_NONINTERLEAVED))
81 snd_pcm_access_mask_set(&mask,
82 SND_PCM_ACCESS_RW_NONINTERLEAVED);
83 if (snd_pcm_access_mask_empty(&mask))
84 return err;
85 pmask = snd_pcm_hw_param_get_mask(&new,
86 SND_PCM_HW_PARAM_ACCESS);
87 *(snd_mask_t *)pmask = mask;
88 err = snd_pcm_hw_refine(map->gen.slave, &new);
89 if (err < 0)
90 return err;
91 *params = new;
94 pmask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
95 if (snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_INTERLEAVED) ||
96 snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) ||
97 snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_COMPLEX))
98 return 0;
99 if (snd_pcm_access_mask_test(&mask, SND_PCM_ACCESS_RW_INTERLEAVED)) {
100 if (snd_pcm_access_mask_test(pmask,
101 SND_PCM_ACCESS_RW_INTERLEAVED))
102 snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
103 SND_PCM_ACCESS_MMAP_INTERLEAVED);
104 snd_pcm_access_mask_reset((snd_pcm_access_mask_t *)pmask,
105 SND_PCM_ACCESS_RW_INTERLEAVED);
106 params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
108 if (snd_pcm_access_mask_test(&mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
109 if (snd_pcm_access_mask_test(pmask,
110 SND_PCM_ACCESS_RW_NONINTERLEAVED))
111 snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
112 SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
113 snd_pcm_access_mask_reset((snd_pcm_access_mask_t *)pmask,
114 SND_PCM_ACCESS_RW_NONINTERLEAVED);
115 params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
117 if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) {
118 if (snd_pcm_access_mask_test(&oldmask,
119 SND_PCM_ACCESS_RW_INTERLEAVED)) {
120 if (snd_pcm_access_mask_test(pmask,
121 SND_PCM_ACCESS_RW_INTERLEAVED)) {
122 snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
123 SND_PCM_ACCESS_MMAP_INTERLEAVED);
124 params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
128 if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
129 if (snd_pcm_access_mask_test(&oldmask,
130 SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
131 if (snd_pcm_access_mask_test(pmask,
132 SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
133 snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
134 SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
135 params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
139 return 0;
143 * hw_params needs a similar hack like hw_refine, but it's much simpler
144 * because now snd_pcm_hw_params_t takes only one choice for each item.
146 * Here, when the normal hw_params call fails, it turns on the mmap_emul
147 * flag and tries to use ACCESS_RW_* mode.
149 * In mmap_emul mode, the appl_ptr and hw_ptr are handled individually
150 * from the layering slave PCM, and they are sync'ed appropriately in
151 * each read/write or avail_update/commit call.
153 static int snd_pcm_mmap_emul_hw_params(snd_pcm_t *pcm,
154 snd_pcm_hw_params_t *params)
156 mmap_emul_t *map = pcm->private_data;
157 snd_pcm_hw_params_t old = *params;
158 snd_pcm_access_t access;
159 snd_pcm_access_mask_t oldmask;
160 snd_pcm_access_mask_t *pmask;
161 int err;
163 err = _snd_pcm_hw_params(map->gen.slave, params);
164 if (err >= 0) {
165 map->mmap_emul = 0;
166 return err;
169 *params = old;
170 pmask = (snd_pcm_access_mask_t *)snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
171 oldmask = *pmask;
172 if (INTERNAL(snd_pcm_hw_params_get_access)(params, &access) < 0)
173 goto _err;
174 switch (access) {
175 case SND_PCM_ACCESS_MMAP_INTERLEAVED:
176 snd_pcm_access_mask_reset(pmask,
177 SND_PCM_ACCESS_MMAP_INTERLEAVED);
178 snd_pcm_access_mask_set(pmask, SND_PCM_ACCESS_RW_INTERLEAVED);
179 break;
180 case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
181 snd_pcm_access_mask_reset(pmask,
182 SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
183 snd_pcm_access_mask_set(pmask,
184 SND_PCM_ACCESS_RW_NONINTERLEAVED);
185 break;
186 default:
187 goto _err;
189 err = _snd_pcm_hw_params(map->gen.slave, params);
190 if (err < 0)
191 goto _err;
193 /* need to back the access type to relieve apps */
194 *pmask = oldmask;
196 /* OK, we do fake */
197 map->mmap_emul = 1;
198 map->appl_ptr = 0;
199 map->hw_ptr = 0;
200 snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0);
201 snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0);
202 return 0;
204 _err:
205 err = -errno;
206 return err;
209 static int snd_pcm_mmap_emul_sw_params(snd_pcm_t *pcm,
210 snd_pcm_sw_params_t *params)
212 mmap_emul_t *map = pcm->private_data;
213 int err;
215 if (!map->mmap_emul)
216 return snd_pcm_generic_sw_params(pcm, params);
218 map->start_threshold = params->start_threshold;
220 /* HACK: don't auto-start in the slave PCM */
221 params->start_threshold = pcm->boundary;
222 err = snd_pcm_generic_sw_params(pcm, params);
223 if (err < 0)
224 return err;
225 /* restore the value for this PCM */
226 params->start_threshold = map->start_threshold;
227 return err;
230 static int snd_pcm_mmap_emul_prepare(snd_pcm_t *pcm)
232 mmap_emul_t *map = pcm->private_data;
233 int err;
235 err = snd_pcm_generic_prepare(pcm);
236 if (err < 0)
237 return err;
238 map->hw_ptr = map->appl_ptr = 0;
239 return err;
242 static int snd_pcm_mmap_emul_reset(snd_pcm_t *pcm)
244 mmap_emul_t *map = pcm->private_data;
245 int err;
247 err = snd_pcm_generic_reset(pcm);
248 if (err < 0)
249 return err;
250 map->hw_ptr = map->appl_ptr = 0;
251 return err;
254 static snd_pcm_sframes_t
255 snd_pcm_mmap_emul_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
257 frames = snd_pcm_generic_rewind(pcm, frames);
258 if (frames > 0)
259 snd_pcm_mmap_appl_backward(pcm, frames);
260 return frames;
263 static snd_pcm_sframes_t
264 snd_pcm_mmap_emul_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
266 frames = snd_pcm_generic_forward(pcm, frames);
267 if (frames > 0)
268 snd_pcm_mmap_appl_forward(pcm, frames);
269 return frames;
272 /* write out the uncommitted chunk on mmap buffer to the slave PCM */
273 static snd_pcm_sframes_t
274 sync_slave_write(snd_pcm_t *pcm)
276 mmap_emul_t *map = pcm->private_data;
277 snd_pcm_t *slave = map->gen.slave;
278 snd_pcm_uframes_t offset;
279 snd_pcm_sframes_t size;
281 /* HACK: don't start stream automatically at commit in mmap mode */
282 pcm->start_threshold = pcm->boundary;
284 size = map->appl_ptr - *slave->appl.ptr;
285 if (size < 0)
286 size += pcm->boundary;
287 if (size) {
288 offset = *slave->appl.ptr % pcm->buffer_size;
289 size = snd_pcm_write_mmap(pcm, offset, size);
291 pcm->start_threshold = map->start_threshold; /* restore */
292 return size;
295 /* read the available chunk on the slave PCM to mmap buffer */
296 static snd_pcm_sframes_t
297 sync_slave_read(snd_pcm_t *pcm)
299 mmap_emul_t *map = pcm->private_data;
300 snd_pcm_t *slave = map->gen.slave;
301 snd_pcm_uframes_t offset;
302 snd_pcm_sframes_t size;
304 size = *slave->hw.ptr - map->hw_ptr;
305 if (size < 0)
306 size += pcm->boundary;
307 if (!size)
308 return 0;
309 offset = map->hw_ptr % pcm->buffer_size;
310 size = snd_pcm_read_mmap(pcm, offset, size);
311 if (size > 0)
312 snd_pcm_mmap_hw_forward(pcm, size);
313 return 0;
316 static snd_pcm_sframes_t
317 snd_pcm_mmap_emul_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
318 snd_pcm_uframes_t size)
320 mmap_emul_t *map = pcm->private_data;
321 snd_pcm_t *slave = map->gen.slave;
323 snd_pcm_mmap_appl_forward(pcm, size);
324 if (!map->mmap_emul)
325 return snd_pcm_mmap_commit(slave, offset, size);
326 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
327 sync_slave_write(pcm);
328 return size;
331 static snd_pcm_sframes_t snd_pcm_mmap_emul_avail_update(snd_pcm_t *pcm)
333 mmap_emul_t *map = pcm->private_data;
334 snd_pcm_t *slave = map->gen.slave;
335 snd_pcm_sframes_t avail;
337 avail = snd_pcm_avail_update(slave);
338 if (!map->mmap_emul || pcm->stream == SND_PCM_STREAM_PLAYBACK)
339 map->hw_ptr = *slave->hw.ptr;
340 else
341 sync_slave_read(pcm);
342 return snd_pcm_mmap_avail(pcm);
345 static void snd_pcm_mmap_emul_dump(snd_pcm_t *pcm, snd_output_t *out)
347 mmap_emul_t *map = pcm->private_data;
349 snd_output_printf(out, "Mmap emulation PCM\n");
350 if (pcm->setup) {
351 snd_output_printf(out, "Its setup is:\n");
352 snd_pcm_dump_setup(pcm, out);
354 snd_output_printf(out, "Slave: ");
355 snd_pcm_dump(map->gen.slave, out);
358 static const snd_pcm_ops_t snd_pcm_mmap_emul_ops = {
359 .close = snd_pcm_generic_close,
360 .info = snd_pcm_generic_info,
361 .hw_refine = snd_pcm_mmap_emul_hw_refine,
362 .hw_params = snd_pcm_mmap_emul_hw_params,
363 .hw_free = snd_pcm_generic_hw_free,
364 .sw_params = snd_pcm_mmap_emul_sw_params,
365 .channel_info = snd_pcm_generic_channel_info,
366 .dump = snd_pcm_mmap_emul_dump,
367 .nonblock = snd_pcm_generic_nonblock,
368 .async = snd_pcm_generic_async,
369 .mmap = snd_pcm_generic_mmap,
370 .munmap = snd_pcm_generic_munmap,
373 static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = {
374 .status = snd_pcm_generic_status,
375 .state = snd_pcm_generic_state,
376 .hwsync = snd_pcm_generic_hwsync,
377 .delay = snd_pcm_generic_delay,
378 .prepare = snd_pcm_mmap_emul_prepare,
379 .reset = snd_pcm_mmap_emul_reset,
380 .start = snd_pcm_generic_start,
381 .drop = snd_pcm_generic_drop,
382 .drain = snd_pcm_generic_drain,
383 .pause = snd_pcm_generic_pause,
384 .rewindable = snd_pcm_generic_rewindable,
385 .rewind = snd_pcm_mmap_emul_rewind,
386 .forwardable = snd_pcm_generic_forwardable,
387 .forward = snd_pcm_mmap_emul_forward,
388 .resume = snd_pcm_generic_resume,
389 .link = snd_pcm_generic_link,
390 .link_slaves = snd_pcm_generic_link_slaves,
391 .unlink = snd_pcm_generic_unlink,
392 .writei = snd_pcm_generic_writei,
393 .writen = snd_pcm_generic_writen,
394 .readi = snd_pcm_generic_readi,
395 .readn = snd_pcm_generic_readn,
396 .avail_update = snd_pcm_mmap_emul_avail_update,
397 .mmap_commit = snd_pcm_mmap_emul_mmap_commit,
398 .htimestamp = snd_pcm_generic_htimestamp,
399 .poll_descriptors = snd_pcm_generic_poll_descriptors,
400 .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
401 .poll_revents = snd_pcm_generic_poll_revents,
404 #ifndef DOC_HIDDEN
405 int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name,
406 snd_pcm_t *slave, int close_slave)
408 snd_pcm_t *pcm;
409 mmap_emul_t *map;
410 int err;
412 map = calloc(1, sizeof(*map));
413 if (!map)
414 return -ENOMEM;
415 map->gen.slave = slave;
416 map->gen.close_slave = close_slave;
418 err = snd_pcm_new(&pcm, SND_PCM_TYPE_MMAP_EMUL, name,
419 slave->stream, slave->mode);
420 if (err < 0) {
421 free(map);
422 return err;
424 pcm->ops = &snd_pcm_mmap_emul_ops;
425 pcm->fast_ops = &snd_pcm_mmap_emul_fast_ops;
426 pcm->private_data = map;
427 pcm->poll_fd = slave->poll_fd;
428 pcm->poll_events = slave->poll_events;
429 pcm->monotonic = slave->monotonic;
430 snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0);
431 snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0);
432 *pcmp = pcm;
434 return 0;
436 #endif
438 /*! \page pcm_plugins
440 \section pcm_plugins_mmap_emul Plugin: mmap_emul
442 \code
443 pcm.name {
444 type mmap_emul
445 slave PCM
447 \endcode
449 \subsection pcm_plugins_mmap_emul_funcref Function reference
451 <UL>
452 <LI>_snd_pcm_hw_open()
453 </UL>
458 * \brief Creates a new mmap_emul PCM
459 * \param pcmp Returns created PCM handle
460 * \param name Name of PCM
461 * \param root Root configuration node
462 * \param conf Configuration node with hw PCM description
463 * \param stream PCM Stream
464 * \param mode PCM Mode
465 * \warning Using of this function might be dangerous in the sense
466 * of compatibility reasons. The prototype might be freely
467 * changed in future.
469 int _snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name,
470 snd_config_t *root ATTRIBUTE_UNUSED,
471 snd_config_t *conf,
472 snd_pcm_stream_t stream, int mode)
474 snd_config_iterator_t i, next;
475 int err;
476 snd_pcm_t *spcm;
477 snd_config_t *slave = NULL, *sconf;
479 snd_config_for_each(i, next, conf) {
480 snd_config_t *n = snd_config_iterator_entry(i);
481 const char *id;
482 if (snd_config_get_id(n, &id) < 0)
483 continue;
484 if (snd_pcm_conf_generic_id(id))
485 continue;
486 if (strcmp(id, "slave") == 0) {
487 slave = n;
488 continue;
490 SNDERR("Unknown field %s", id);
491 return -EINVAL;
493 if (!slave) {
494 SNDERR("slave is not defined");
495 return -EINVAL;
497 err = snd_pcm_slave_conf(root, slave, &sconf, 0);
498 if (err < 0)
499 return err;
500 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
501 snd_config_delete(sconf);
502 if (err < 0)
503 return err;
504 err = __snd_pcm_mmap_emul_open(pcmp, name, spcm, 1);
505 if (err < 0)
506 snd_pcm_close(spcm);
507 return err;
510 #ifndef DOC_HIDDEN
511 SND_DLSYM_BUILD_VERSION(_snd_pcm_mmap_emul_open, SND_PCM_DLSYM_VERSION);
512 #endif