4 * \brief PCM HW Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \author Jaroslav Kysela <perex@perex.cz>
11 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
14 * This library is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as
16 * published by the Free Software Foundation; either version 2.1 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37 #include <sys/ioctl.h>
40 #include "pcm_local.h"
41 #include "../control/control_local.h"
42 #include "../timer/timer_local.h"
44 //#define DEBUG_RW /* use to debug readi/writei/readn/writen */
45 //#define DEBUG_MMAP /* debug mmap_commit */
48 /* entry for static linking */
49 const char *_snd_module_pcm_hw = "";
62 struct sndrv_pcm_hw_params_old {
64 unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
65 SNDRV_PCM_HW_PARAM_ACCESS + 1];
66 struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
67 SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
72 unsigned int rate_num;
73 unsigned int rate_den;
74 sndrv_pcm_uframes_t fifo_size;
75 unsigned char reserved[64];
78 #define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
79 #define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
81 static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
82 static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
83 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops;
84 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer;
93 int card, device, subdevice;
95 volatile struct sndrv_pcm_mmap_status * mmap_status;
96 struct sndrv_pcm_mmap_control *mmap_control;
97 struct sndrv_pcm_sync_ptr *sync_ptr;
98 snd_pcm_uframes_t hw_ptr;
99 snd_pcm_uframes_t appl_ptr;
101 snd_timer_t *period_timer;
102 struct pollfd period_timer_pfd;
103 int period_timer_need_poll;
104 /* restricted parameters */
105 snd_pcm_format_t format;
110 #define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
111 #define SNDRV_FILE_PCM_STREAM_CAPTURE ALSA_DEVICE_DIRECTORY "pcmC%iD%ic"
112 #define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 9)
114 /* update appl_ptr with driver */
115 #define FAST_PCM_STATE(hw) \
116 ((enum sndrv_pcm_state) (hw)->mmap_status->state)
117 #define FAST_PCM_TSTAMP(hw) \
118 ((hw)->mmap_status->tstamp)
120 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm)
123 snd_pcm_hw_t *hw = pcm->private_data;
124 res = FAST_PCM_TSTAMP(hw);
125 if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version)
126 res.tv_nsec *= 1000L;
129 #endif /* DOC_HIDDEN */
131 static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
134 hw->sync_ptr->flags = flags;
135 err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr);
138 SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
144 static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags)
146 return hw->sync_ptr ? sync_ptr1(hw, flags) : 0;
149 static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw)
151 if (hw->period_timer_need_poll) {
152 while (poll(&hw->period_timer_pfd, 1, 0) > 0) {
153 snd_timer_tread_t rbuf[4];
154 snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
157 snd_timer_tread_t rbuf[4];
158 snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
163 static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
168 static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
170 snd_pcm_hw_t *hw = pcm->private_data;
175 pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL;
176 pfds[1].fd = hw->period_timer_pfd.fd;
177 pfds[1].events = POLLIN | POLLERR | POLLNVAL;
181 static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents)
183 snd_pcm_hw_t *hw = pcm->private_data;
186 if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd)
188 events = pfds[0].revents;
189 if (pfds[1].revents & POLLIN) {
190 snd_pcm_hw_clear_timer_queue(hw);
191 events |= pcm->poll_events & ~(POLLERR|POLLNVAL);
197 static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
200 snd_pcm_hw_t *hw = pcm->private_data;
201 int fd = hw->fd, err;
203 if ((flags = fcntl(fd, F_GETFL)) < 0) {
205 SYSMSG("F_GETFL failed (%i)", err);
211 flags &= ~O_NONBLOCK;
212 if (fcntl(fd, F_SETFL, flags) < 0) {
214 SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err);
220 static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
223 snd_pcm_hw_t *hw = pcm->private_data;
224 int fd = hw->fd, err;
226 if ((flags = fcntl(fd, F_GETFL)) < 0) {
228 SYSMSG("F_GETFL failed (%i)", err);
235 if (fcntl(fd, F_SETFL, flags) < 0) {
237 SYSMSG("F_SETFL for O_ASYNC failed (%i)", err);
242 if (fcntl(fd, F_SETSIG, (long)sig) < 0) {
244 SYSMSG("F_SETSIG failed (%i)", err);
247 if (fcntl(fd, F_SETOWN, (long)pid) < 0) {
249 SYSMSG("F_SETOWN failed (%i)", err);
255 static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
257 snd_pcm_hw_t *hw = pcm->private_data;
258 int fd = hw->fd, err;
259 if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) {
261 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err);
267 static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
269 /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
270 if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
271 return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
272 return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
275 static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
277 snd_pcm_hw_t *hw = pcm->private_data;
280 if (hw->format != SND_PCM_FORMAT_UNKNOWN) {
281 err = _snd_pcm_hw_params_set_format(params, hw->format);
285 if (hw->channels > 0) {
286 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
292 err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
293 hw->rate, 0, hw->rate + 1, -1);
298 if (hw_refine_call(hw, params) < 0) {
300 // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed");
304 if (params->info != ~0U) {
305 params->info &= ~0xf0000000;
306 params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
312 static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
314 /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
315 if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
316 return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
317 return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
320 static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
322 snd_pcm_hw_t *hw = pcm->private_data;
324 if (hw_params_call(hw, params) < 0) {
326 SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err);
329 params->info &= ~0xf0000000;
330 params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
331 err = sync_ptr(hw, 0);
334 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
335 snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd,
336 SNDRV_PCM_MMAP_OFFSET_CONTROL);
341 static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw)
343 if (hw->period_timer) {
344 snd_timer_close(hw->period_timer);
345 hw->period_timer = NULL;
349 static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable)
351 snd_pcm_hw_t *hw = pcm->private_data;
352 snd_timer_params_t *params;
353 unsigned int suspend, resume;
357 snd_timer_params_alloca(¶ms);
358 err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
360 err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK);
363 if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) {
364 snd_pcm_hw_close_timer(hw);
367 hw->period_timer_pfd.events = POLLIN;
368 hw->period_timer_pfd.revents = 0;
369 snd_timer_poll_descriptors(hw->period_timer, &hw->period_timer_pfd, 1);
370 hw->period_timer_need_poll = 0;
371 suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
372 resume = 1<<SND_TIMER_EVENT_MRESUME;
374 * hacks for older kernel drivers
378 ioctl(hw->period_timer_pfd.fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
379 /* In older versions, check via poll before read() is needed
380 * because of the confliction between TIMER_START and
383 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
384 hw->period_timer_need_poll = 1;
386 * In older versions, timer uses pause events instead
387 * suspend/resume events.
389 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
390 suspend = 1<<SND_TIMER_EVENT_MPAUSE;
391 resume = 1<<SND_TIMER_EVENT_MCONTINUE;
394 snd_timer_params_set_auto_start(params, 1);
395 snd_timer_params_set_ticks(params, 1);
396 snd_timer_params_set_filter(params, (1<<SND_TIMER_EVENT_TICK) |
398 err = snd_timer_params(hw->period_timer, params);
400 snd_pcm_hw_close_timer(hw);
403 err = snd_timer_start(hw->period_timer);
405 snd_pcm_hw_close_timer(hw);
408 pcm->fast_ops = &snd_pcm_hw_fast_ops_timer;
410 snd_pcm_hw_close_timer(hw);
411 pcm->fast_ops = &snd_pcm_hw_fast_ops;
412 hw->period_event = 0;
417 static int snd_pcm_hw_hw_free(snd_pcm_t *pcm)
419 snd_pcm_hw_t *hw = pcm->private_data;
420 int fd = hw->fd, err;
421 snd_pcm_hw_change_timer(pcm, 0);
422 if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) {
424 SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err);
430 static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
432 snd_pcm_hw_t *hw = pcm->private_data;
433 int fd = hw->fd, err;
434 int old_period_event = params->period_event;
435 params->period_event = 0;
436 if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
437 params->period_step == pcm->period_step &&
438 params->start_threshold == pcm->start_threshold &&
439 params->stop_threshold == pcm->stop_threshold &&
440 params->silence_threshold == pcm->silence_threshold &&
441 params->silence_size == pcm->silence_size &&
442 old_period_event == hw->period_event) {
443 hw->mmap_control->avail_min = params->avail_min;
444 return sync_ptr(hw, 0);
446 if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
448 SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
451 params->period_event = old_period_event;
452 hw->mmap_control->avail_min = params->avail_min;
453 if (hw->period_event != old_period_event) {
454 err = snd_pcm_hw_change_timer(pcm, old_period_event);
457 hw->period_event = old_period_event;
462 static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
464 snd_pcm_hw_t *hw = pcm->private_data;
465 struct sndrv_pcm_channel_info i;
466 int fd = hw->fd, err;
467 i.channel = info->channel;
468 if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) {
470 SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err);
473 info->channel = i.channel;
475 info->first = i.first;
477 info->type = SND_PCM_AREA_MMAP;
478 info->u.mmap.fd = fd;
479 info->u.mmap.offset = i.offset;
483 static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
485 snd_pcm_hw_t *hw = pcm->private_data;
486 int fd = hw->fd, err;
487 if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
489 SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
492 if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
493 status->tstamp.tv_nsec *= 1000L;
494 status->trigger_tstamp.tv_nsec *= 1000L;
499 static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm)
501 snd_pcm_hw_t *hw = pcm->private_data;
502 int err = sync_ptr(hw, 0);
505 return (snd_pcm_state_t) hw->mmap_status->state;
508 static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
510 snd_pcm_hw_t *hw = pcm->private_data;
511 int fd = hw->fd, err;
512 if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
514 SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err);
520 static int snd_pcm_hw_hwsync(snd_pcm_t *pcm)
522 snd_pcm_hw_t *hw = pcm->private_data;
523 int fd = hw->fd, err;
524 if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) {
526 err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC);
530 if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) {
532 SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err);
537 snd_pcm_sframes_t delay;
538 int err = snd_pcm_hw_delay(pcm, &delay);
540 switch (FAST_PCM_STATE(hw)) {
541 case SND_PCM_STATE_PREPARED:
542 case SND_PCM_STATE_SUSPENDED:
552 static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
554 snd_pcm_hw_t *hw = pcm->private_data;
555 int fd = hw->fd, err;
556 if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
558 SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err);
561 return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
564 static int snd_pcm_hw_reset(snd_pcm_t *pcm)
566 snd_pcm_hw_t *hw = pcm->private_data;
567 int fd = hw->fd, err;
568 if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) {
570 SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err);
573 return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
576 static int snd_pcm_hw_start(snd_pcm_t *pcm)
578 snd_pcm_hw_t *hw = pcm->private_data;
581 assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
582 snd_pcm_mmap_playback_hw_avail(pcm) > 0);
585 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) {
587 SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err);
590 SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm)));
597 static int snd_pcm_hw_drop(snd_pcm_t *pcm)
599 snd_pcm_hw_t *hw = pcm->private_data;
601 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) {
603 SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err);
610 static int snd_pcm_hw_drain(snd_pcm_t *pcm)
612 snd_pcm_hw_t *hw = pcm->private_data;
614 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) {
616 SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err);
622 static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
624 snd_pcm_hw_t *hw = pcm->private_data;
626 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) {
628 SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err);
634 static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
636 return snd_pcm_mmap_hw_avail(pcm);
639 static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
641 snd_pcm_hw_t *hw = pcm->private_data;
643 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) {
645 SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err);
648 err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
654 static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm)
656 return snd_pcm_mmap_avail(pcm);
659 static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
661 snd_pcm_hw_t *hw = pcm->private_data;
663 if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) {
664 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) {
666 SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err);
669 err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
674 snd_pcm_sframes_t avail;
676 err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_HWSYNC);
679 switch (FAST_PCM_STATE(hw)) {
680 case SNDRV_PCM_STATE_RUNNING:
681 case SNDRV_PCM_STATE_DRAINING:
682 case SNDRV_PCM_STATE_PAUSED:
683 case SNDRV_PCM_STATE_PREPARED:
685 case SNDRV_PCM_STATE_XRUN:
690 avail = snd_pcm_mmap_avail(pcm);
693 if (frames > (snd_pcm_uframes_t)avail)
695 snd_pcm_mmap_appl_forward(pcm, frames);
696 err = sync_ptr(hw, 0);
703 static int snd_pcm_hw_resume(snd_pcm_t *pcm)
705 snd_pcm_hw_t *hw = pcm->private_data;
706 int fd = hw->fd, err;
707 if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) {
709 SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err);
715 static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
717 snd_pcm_hw_t *hw1 = pcm1->private_data;
718 snd_pcm_hw_t *hw2 = pcm2->private_data;
719 if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
720 SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno);
726 static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
728 if (master->type != SND_PCM_TYPE_HW) {
729 SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type);
732 return hw_link(master, pcm);
735 static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
737 if (pcm2->type != SND_PCM_TYPE_HW) {
738 if (pcm2->fast_ops->link_slaves)
739 return pcm2->fast_ops->link_slaves(pcm2, pcm1);
742 return hw_link(pcm1, pcm2);
745 static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
747 snd_pcm_hw_t *hw = pcm->private_data;
749 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) {
750 SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno);
756 static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
759 snd_pcm_hw_t *hw = pcm->private_data;
761 struct sndrv_xferi xferi;
762 xferi.buf = (char*) buffer;
764 xferi.result = 0; /* make valgrind happy */
765 err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi);
766 err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
768 fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err);
771 return snd_pcm_check_error(pcm, err);
775 static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
778 snd_pcm_hw_t *hw = pcm->private_data;
780 struct sndrv_xfern xfern;
781 memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
784 err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern);
785 err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
787 fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
790 return snd_pcm_check_error(pcm, err);
794 static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
797 snd_pcm_hw_t *hw = pcm->private_data;
799 struct sndrv_xferi xferi;
802 xferi.result = 0; /* make valgrind happy */
803 err = ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi);
804 err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
806 fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err);
809 return snd_pcm_check_error(pcm, err);
813 static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
816 snd_pcm_hw_t *hw = pcm->private_data;
818 struct sndrv_xfern xfern;
819 memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
822 err = ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern);
823 err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
825 fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
828 return snd_pcm_check_error(pcm, err);
832 static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
834 snd_pcm_hw_t *hw = pcm->private_data;
835 struct sndrv_pcm_sync_ptr sync_ptr;
839 if (hw->sync_ptr_ioctl == 0)
840 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_status)),
841 PROT_READ, MAP_FILE|MAP_SHARED,
842 hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
843 if (ptr == MAP_FAILED || ptr == NULL) {
844 memset(&sync_ptr, 0, sizeof(sync_ptr));
845 sync_ptr.c.control.appl_ptr = 0;
846 sync_ptr.c.control.avail_min = 1;
847 err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr);
850 SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
853 hw->sync_ptr = calloc(1, sizeof(struct sndrv_pcm_sync_ptr));
854 if (hw->sync_ptr == NULL)
856 hw->mmap_status = &hw->sync_ptr->s.status;
857 hw->mmap_control = &hw->sync_ptr->c.control;
858 hw->sync_ptr_ioctl = 1;
860 hw->mmap_status = ptr;
862 snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct sndrv_pcm_mmap_status, hw_ptr));
866 static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
868 snd_pcm_hw_t *hw = pcm->private_data;
871 if (hw->sync_ptr == NULL) {
872 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control)),
873 PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
874 hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
875 if (ptr == MAP_FAILED || ptr == NULL) {
877 SYSMSG("control mmap failed (%i)", err);
880 hw->mmap_control = ptr;
882 hw->mmap_control->avail_min = 1;
884 snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
888 static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
890 snd_pcm_hw_t *hw = pcm->private_data;
892 if (hw->sync_ptr_ioctl) {
896 if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) {
898 SYSMSG("status munmap failed (%i)", err);
905 static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
907 snd_pcm_hw_t *hw = pcm->private_data;
909 if (hw->sync_ptr_ioctl) {
913 if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) {
915 SYSMSG("control munmap failed (%i)", err);
922 static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
927 static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
932 static int snd_pcm_hw_close(snd_pcm_t *pcm)
934 snd_pcm_hw_t *hw = pcm->private_data;
938 SYSMSG("close failed (%i)\n", err);
940 snd_pcm_hw_munmap_status(pcm);
941 snd_pcm_hw_munmap_control(pcm);
946 static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
947 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
948 snd_pcm_uframes_t size)
950 snd_pcm_hw_t *hw = pcm->private_data;
952 snd_pcm_mmap_appl_forward(pcm, size);
955 fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size);
960 static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
962 snd_pcm_hw_t *hw = pcm->private_data;
963 snd_pcm_uframes_t avail;
966 avail = snd_pcm_mmap_avail(pcm);
967 switch (FAST_PCM_STATE(hw)) {
968 case SNDRV_PCM_STATE_RUNNING:
969 if (avail >= pcm->stop_threshold) {
970 /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
971 if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
972 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0)
975 /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
979 case SNDRV_PCM_STATE_XRUN:
987 static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
988 snd_htimestamp_t *tstamp)
990 snd_pcm_sframes_t avail1;
993 /* unfortunately, loop is necessary to ensure valid timestamp */
995 avail1 = snd_pcm_hw_avail_update(pcm);
998 if (ok && (snd_pcm_uframes_t)avail1 == *avail)
1001 *tstamp = snd_pcm_hw_fast_tstamp(pcm);
1007 static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out)
1009 snd_pcm_hw_t *hw = pcm->private_data;
1011 int err = snd_card_get_name(hw->card, &name);
1013 SNDERR("cannot get card name");
1016 snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n",
1017 hw->card, name, hw->device, hw->subdevice);
1020 snd_output_printf(out, "Its setup is:\n");
1021 snd_pcm_dump_setup(pcm, out);
1022 snd_output_printf(out, " appl_ptr : %li\n", hw->mmap_control->appl_ptr);
1023 snd_output_printf(out, " hw_ptr : %li\n", hw->mmap_status->hw_ptr);
1027 static const snd_pcm_ops_t snd_pcm_hw_ops = {
1028 .close = snd_pcm_hw_close,
1029 .info = snd_pcm_hw_info,
1030 .hw_refine = snd_pcm_hw_hw_refine,
1031 .hw_params = snd_pcm_hw_hw_params,
1032 .hw_free = snd_pcm_hw_hw_free,
1033 .sw_params = snd_pcm_hw_sw_params,
1034 .channel_info = snd_pcm_hw_channel_info,
1035 .dump = snd_pcm_hw_dump,
1036 .nonblock = snd_pcm_hw_nonblock,
1037 .async = snd_pcm_hw_async,
1038 .mmap = snd_pcm_hw_mmap,
1039 .munmap = snd_pcm_hw_munmap,
1042 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
1043 .status = snd_pcm_hw_status,
1044 .state = snd_pcm_hw_state,
1045 .hwsync = snd_pcm_hw_hwsync,
1046 .delay = snd_pcm_hw_delay,
1047 .prepare = snd_pcm_hw_prepare,
1048 .reset = snd_pcm_hw_reset,
1049 .start = snd_pcm_hw_start,
1050 .drop = snd_pcm_hw_drop,
1051 .drain = snd_pcm_hw_drain,
1052 .pause = snd_pcm_hw_pause,
1053 .rewindable = snd_pcm_hw_rewindable,
1054 .rewind = snd_pcm_hw_rewind,
1055 .forwardable = snd_pcm_hw_forwardable,
1056 .forward = snd_pcm_hw_forward,
1057 .resume = snd_pcm_hw_resume,
1058 .link = snd_pcm_hw_link,
1059 .link_slaves = snd_pcm_hw_link_slaves,
1060 .unlink = snd_pcm_hw_unlink,
1061 .writei = snd_pcm_hw_writei,
1062 .writen = snd_pcm_hw_writen,
1063 .readi = snd_pcm_hw_readi,
1064 .readn = snd_pcm_hw_readn,
1065 .avail_update = snd_pcm_hw_avail_update,
1066 .mmap_commit = snd_pcm_hw_mmap_commit,
1067 .htimestamp = snd_pcm_hw_htimestamp,
1068 .poll_descriptors = NULL,
1069 .poll_descriptors_count = NULL,
1070 .poll_revents = NULL,
1073 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = {
1074 .status = snd_pcm_hw_status,
1075 .state = snd_pcm_hw_state,
1076 .hwsync = snd_pcm_hw_hwsync,
1077 .delay = snd_pcm_hw_delay,
1078 .prepare = snd_pcm_hw_prepare,
1079 .reset = snd_pcm_hw_reset,
1080 .start = snd_pcm_hw_start,
1081 .drop = snd_pcm_hw_drop,
1082 .drain = snd_pcm_hw_drain,
1083 .pause = snd_pcm_hw_pause,
1084 .rewindable = snd_pcm_hw_rewindable,
1085 .rewind = snd_pcm_hw_rewind,
1086 .forwardable = snd_pcm_hw_forwardable,
1087 .forward = snd_pcm_hw_forward,
1088 .resume = snd_pcm_hw_resume,
1089 .link = snd_pcm_hw_link,
1090 .link_slaves = snd_pcm_hw_link_slaves,
1091 .unlink = snd_pcm_hw_unlink,
1092 .writei = snd_pcm_hw_writei,
1093 .writen = snd_pcm_hw_writen,
1094 .readi = snd_pcm_hw_readi,
1095 .readn = snd_pcm_hw_readn,
1096 .avail_update = snd_pcm_hw_avail_update,
1097 .mmap_commit = snd_pcm_hw_mmap_commit,
1098 .htimestamp = snd_pcm_hw_htimestamp,
1099 .poll_descriptors = snd_pcm_hw_poll_descriptors,
1100 .poll_descriptors_count = snd_pcm_hw_poll_descriptors_count,
1101 .poll_revents = snd_pcm_hw_poll_revents,
1105 * \brief Creates a new hw PCM
1106 * \param pcmp Returns created PCM handle
1107 * \param name Name of PCM
1108 * \param fd File descriptor
1109 * \param mmap_emulation Obsoleted parameter
1110 * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl
1111 * \retval zero on success otherwise a negative error code
1112 * \warning Using of this function might be dangerous in the sense
1113 * of compatibility reasons. The prototype might be freely
1114 * changed in future.
1116 int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
1117 int fd, int mmap_emulation ATTRIBUTE_UNUSED,
1120 int ver, mode, monotonic = 0;
1122 snd_pcm_t *pcm = NULL;
1123 snd_pcm_hw_t *hw = NULL;
1124 snd_pcm_info_t info;
1129 memset(&info, 0, sizeof(info));
1130 if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1132 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1138 if ((fmode = fcntl(fd, F_GETFL)) < 0) {
1144 if (fmode & O_NONBLOCK)
1145 mode |= SND_PCM_NONBLOCK;
1146 if (fmode & O_ASYNC)
1147 mode |= SND_PCM_ASYNC;
1149 if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) {
1151 SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret);
1155 if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX))
1156 return -SND_ERROR_INCOMPATIBLE_VERSION;
1158 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1159 if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) {
1160 struct timespec timespec;
1161 if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) {
1162 int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
1163 if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
1165 SNDMSG("TTSTAMP failed\n");
1172 if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) {
1174 if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
1176 SNDMSG("TSTAMP failed\n");
1181 hw = calloc(1, sizeof(snd_pcm_hw_t));
1188 hw->card = info.card;
1189 hw->device = info.device;
1190 hw->subdevice = info.subdevice;
1192 hw->sync_ptr_ioctl = sync_ptr_ioctl;
1193 /* no restriction */
1194 hw->format = SND_PCM_FORMAT_UNKNOWN;
1198 ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode);
1205 pcm->ops = &snd_pcm_hw_ops;
1206 pcm->fast_ops = &snd_pcm_hw_fast_ops;
1207 pcm->private_data = hw;
1209 pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
1210 pcm->monotonic = monotonic;
1212 ret = snd_pcm_hw_mmap_status(pcm);
1217 ret = snd_pcm_hw_mmap_control(pcm);
1228 * \brief Creates a new hw PCM
1229 * \param pcmp Returns created PCM handle
1230 * \param name Name of PCM
1231 * \param card Number of card
1232 * \param device Number of device
1233 * \param subdevice Number of subdevice
1234 * \param stream PCM Stream
1235 * \param mode PCM Mode
1236 * \param mmap_emulation Obsoleted parameter
1237 * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures
1238 * \retval zero on success otherwise a negative error code
1239 * \warning Using of this function might be dangerous in the sense
1240 * of compatibility reasons. The prototype might be freely
1241 * changed in future.
1243 int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1244 int card, int device, int subdevice,
1245 snd_pcm_stream_t stream, int mode,
1246 int mmap_emulation ATTRIBUTE_UNUSED,
1249 char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20];
1250 const char *filefmt;
1251 int ret = 0, fd = -1;
1253 snd_pcm_info_t info;
1259 if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
1263 case SND_PCM_STREAM_PLAYBACK:
1264 filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK;
1266 case SND_PCM_STREAM_CAPTURE:
1267 filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE;
1270 SNDERR("invalid stream %d", stream);
1273 sprintf(filename, filefmt, card, device);
1276 if (attempt++ > 3) {
1280 ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
1284 if (mode & SND_PCM_NONBLOCK)
1285 fmode |= O_NONBLOCK;
1286 if (mode & SND_PCM_ASYNC)
1288 if (mode & SND_PCM_APPEND)
1290 fd = snd_open_device(filename, fmode);
1293 SYSMSG("open '%s' failed (%i)", filename, ret);
1296 if (subdevice >= 0) {
1297 memset(&info, 0, sizeof(info));
1298 if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1300 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1303 if (info.subdevice != (unsigned int) subdevice) {
1309 return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl);
1315 /*! \page pcm_plugins
1317 \section pcm_plugins_hw Plugin: hw
1319 This plugin communicates directly with the ALSA kernel driver. It is a raw
1320 communication without any conversions. The emulation of mmap access can be
1321 optionally enabled, but expect worse latency in the case.
1323 The nonblock option specifies whether the device is opened in a non-blocking
1324 manner. Note that the blocking behavior for read/write access won't be
1325 changed by this option. This influences only on the blocking behavior at
1326 opening the device. If you would like to keep the compatibility with the
1327 older ALSA stuff, turn this option off.
1331 type hw # Kernel PCM
1332 card INT/STR # Card name (string) or number (integer)
1333 [device INT] # Device number (default 0)
1334 [subdevice INT] # Subdevice number (default -1: first available)
1335 [sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
1336 [nonblock BOOL] # Force non-blocking open mode
1337 [format STR] # Restrict only to the given format
1338 [channels INT] # Restrict only to the given channels
1339 [rate INT] # Restrict only to the given rate
1343 \subsection pcm_plugins_hw_funcref Function reference
1346 <LI>snd_pcm_hw_open()
1347 <LI>_snd_pcm_hw_open()
1353 * \brief Creates a new hw PCM
1354 * \param pcmp Returns created PCM handle
1355 * \param name Name of PCM
1356 * \param root Root configuration node
1357 * \param conf Configuration node with hw PCM description
1358 * \param stream PCM Stream
1359 * \param mode PCM Mode
1360 * \warning Using of this function might be dangerous in the sense
1361 * of compatibility reasons. The prototype might be freely
1362 * changed in future.
1364 int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1365 snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
1366 snd_pcm_stream_t stream, int mode)
1368 snd_config_iterator_t i, next;
1369 long card = -1, device = 0, subdevice = -1;
1371 int err, sync_ptr_ioctl = 0;
1372 int rate = 0, channels = 0;
1373 snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
1375 int nonblock = 1; /* non-block per default */
1378 /* look for defaults.pcm.nonblock definition */
1379 if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) {
1380 err = snd_config_get_bool(n);
1384 snd_config_for_each(i, next, conf) {
1386 n = snd_config_iterator_entry(i);
1387 if (snd_config_get_id(n, &id) < 0)
1389 if (snd_pcm_conf_generic_id(id))
1391 if (strcmp(id, "card") == 0) {
1392 err = snd_config_get_integer(n, &card);
1394 err = snd_config_get_string(n, &str);
1396 SNDERR("Invalid type for %s", id);
1399 card = snd_card_get_index(str);
1401 SNDERR("Invalid value for %s", id);
1407 if (strcmp(id, "device") == 0) {
1408 err = snd_config_get_integer(n, &device);
1410 SNDERR("Invalid type for %s", id);
1415 if (strcmp(id, "subdevice") == 0) {
1416 err = snd_config_get_integer(n, &subdevice);
1418 SNDERR("Invalid type for %s", id);
1423 if (strcmp(id, "sync_ptr_ioctl") == 0) {
1424 err = snd_config_get_bool(n);
1427 sync_ptr_ioctl = err;
1430 if (strcmp(id, "nonblock") == 0) {
1431 err = snd_config_get_bool(n);
1437 if (strcmp(id, "rate") == 0) {
1439 err = snd_config_get_integer(n, &val);
1441 SNDERR("Invalid type for %s", id);
1447 if (strcmp(id, "format") == 0) {
1448 err = snd_config_get_string(n, &str);
1450 SNDERR("invalid type for %s", id);
1453 format = snd_pcm_format_value(str);
1456 if (strcmp(id, "channels") == 0) {
1458 err = snd_config_get_integer(n, &val);
1460 SNDERR("Invalid type for %s", id);
1466 SNDERR("Unknown field %s", id);
1470 SNDERR("card is not defined");
1473 err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
1474 mode | (nonblock ? SND_PCM_NONBLOCK : 0),
1478 if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
1479 /* revert to blocking mode for read/write access */
1480 snd_pcm_hw_nonblock(*pcmp, 0);
1481 (*pcmp)->mode = mode;
1483 /* make sure the SND_PCM_NO_xxx flags don't get lost on the
1485 (*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE|
1486 SND_PCM_NO_AUTO_CHANNELS|
1487 SND_PCM_NO_AUTO_FORMAT|
1488 SND_PCM_NO_SOFTVOL);
1490 hw = (*pcmp)->private_data;
1491 if (format != SND_PCM_FORMAT_UNKNOWN)
1492 hw->format = format;
1494 hw->channels = channels;
1502 SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
1506 * To be removed helpers, but keep binary compatibility at the time
1510 #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
1511 #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
1514 static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
1515 struct sndrv_pcm_hw_params_old *oparams)
1519 memset(params, 0, sizeof(*params));
1520 params->flags = oparams->flags;
1521 for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
1522 params->masks[i].bits[0] = oparams->masks[i];
1523 memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
1524 params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
1525 params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
1526 params->info = oparams->info;
1527 params->msbits = oparams->msbits;
1528 params->rate_num = oparams->rate_num;
1529 params->rate_den = oparams->rate_den;
1530 params->fifo_size = oparams->fifo_size;
1533 static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
1534 snd_pcm_hw_params_t *params,
1535 unsigned int *cmask)
1539 memset(oparams, 0, sizeof(*oparams));
1540 oparams->flags = params->flags;
1541 for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
1542 oparams->masks[i] = params->masks[i].bits[0];
1543 for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
1544 if (params->masks[i].bits[j]) {
1549 memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
1550 oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
1551 oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
1552 oparams->info = params->info;
1553 oparams->msbits = params->msbits;
1554 oparams->rate_num = params->rate_num;
1555 oparams->rate_den = params->rate_den;
1556 oparams->fifo_size = params->fifo_size;
1559 static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
1561 struct sndrv_pcm_hw_params_old oparams;
1562 unsigned int cmask = 0;
1565 snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
1566 res = ioctl(fd, cmd, &oparams);
1567 snd_pcm_hw_convert_from_old_params(params, &oparams);
1568 params->cmask |= cmask;