1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_hw.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM HW Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 7d5ac70f0Sopenharmony_ci * \date 2000-2001 8d5ac70f0Sopenharmony_ci */ 9d5ac70f0Sopenharmony_ci/* 10d5ac70f0Sopenharmony_ci * PCM - Hardware 11d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * 14d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 15d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 16d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 17d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 20d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 21d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 25d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 26d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27d5ac70f0Sopenharmony_ci * 28d5ac70f0Sopenharmony_ci */ 29d5ac70f0Sopenharmony_ci 30d5ac70f0Sopenharmony_ci#include "pcm_local.h" 31d5ac70f0Sopenharmony_ci#include "../control/control_local.h" 32d5ac70f0Sopenharmony_ci#include "../timer/timer_local.h" 33d5ac70f0Sopenharmony_ci#include <stdio.h> 34d5ac70f0Sopenharmony_ci#include <stdlib.h> 35d5ac70f0Sopenharmony_ci#include <stddef.h> 36d5ac70f0Sopenharmony_ci#include <unistd.h> 37d5ac70f0Sopenharmony_ci#include <stdbool.h> 38d5ac70f0Sopenharmony_ci#include <signal.h> 39d5ac70f0Sopenharmony_ci#include <string.h> 40d5ac70f0Sopenharmony_ci#include <fcntl.h> 41d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 42d5ac70f0Sopenharmony_ci#include <sys/mman.h> 43d5ac70f0Sopenharmony_ci 44d5ac70f0Sopenharmony_ci//#define DEBUG_RW /* use to debug readi/writei/readn/writen */ 45d5ac70f0Sopenharmony_ci//#define DEBUG_MMAP /* debug mmap_commit */ 46d5ac70f0Sopenharmony_ci 47d5ac70f0Sopenharmony_ci#ifndef PIC 48d5ac70f0Sopenharmony_ci/* entry for static linking */ 49d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_hw = ""; 50d5ac70f0Sopenharmony_ci#endif 51d5ac70f0Sopenharmony_ci 52d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 53d5ac70f0Sopenharmony_ci 54d5ac70f0Sopenharmony_ci#ifndef F_SETSIG 55d5ac70f0Sopenharmony_ci#define F_SETSIG 10 56d5ac70f0Sopenharmony_ci#endif 57d5ac70f0Sopenharmony_ci 58d5ac70f0Sopenharmony_ci/* 59d5ac70f0Sopenharmony_ci * Compatibility 60d5ac70f0Sopenharmony_ci */ 61d5ac70f0Sopenharmony_ci 62d5ac70f0Sopenharmony_cistruct sndrv_pcm_hw_params_old { 63d5ac70f0Sopenharmony_ci unsigned int flags; 64d5ac70f0Sopenharmony_ci unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - 65d5ac70f0Sopenharmony_ci SNDRV_PCM_HW_PARAM_ACCESS + 1]; 66d5ac70f0Sopenharmony_ci struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - 67d5ac70f0Sopenharmony_ci SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; 68d5ac70f0Sopenharmony_ci unsigned int rmask; 69d5ac70f0Sopenharmony_ci unsigned int cmask; 70d5ac70f0Sopenharmony_ci unsigned int info; 71d5ac70f0Sopenharmony_ci unsigned int msbits; 72d5ac70f0Sopenharmony_ci unsigned int rate_num; 73d5ac70f0Sopenharmony_ci unsigned int rate_den; 74d5ac70f0Sopenharmony_ci sndrv_pcm_uframes_t fifo_size; 75d5ac70f0Sopenharmony_ci unsigned char reserved[64]; 76d5ac70f0Sopenharmony_ci}; 77d5ac70f0Sopenharmony_ci 78d5ac70f0Sopenharmony_ci#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) 79d5ac70f0Sopenharmony_ci#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) 80d5ac70f0Sopenharmony_ci 81d5ac70f0Sopenharmony_cistatic int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params); 82d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm); 83d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops; 84d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer; 85d5ac70f0Sopenharmony_ci 86d5ac70f0Sopenharmony_ci/* 87d5ac70f0Sopenharmony_ci * 88d5ac70f0Sopenharmony_ci */ 89d5ac70f0Sopenharmony_ci 90d5ac70f0Sopenharmony_citypedef struct { 91d5ac70f0Sopenharmony_ci int version; 92d5ac70f0Sopenharmony_ci int fd; 93d5ac70f0Sopenharmony_ci int card, device, subdevice; 94d5ac70f0Sopenharmony_ci 95d5ac70f0Sopenharmony_ci volatile struct snd_pcm_mmap_status * mmap_status; 96d5ac70f0Sopenharmony_ci struct snd_pcm_mmap_control *mmap_control; 97d5ac70f0Sopenharmony_ci bool mmap_status_fallbacked; 98d5ac70f0Sopenharmony_ci bool mmap_control_fallbacked; 99d5ac70f0Sopenharmony_ci struct snd_pcm_sync_ptr *sync_ptr; 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_ci bool prepare_reset_sw_params; 102d5ac70f0Sopenharmony_ci bool perfect_drain; 103d5ac70f0Sopenharmony_ci 104d5ac70f0Sopenharmony_ci int period_event; 105d5ac70f0Sopenharmony_ci snd_timer_t *period_timer; 106d5ac70f0Sopenharmony_ci struct pollfd period_timer_pfd; 107d5ac70f0Sopenharmony_ci int period_timer_need_poll; 108d5ac70f0Sopenharmony_ci /* restricted parameters */ 109d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 110d5ac70f0Sopenharmony_ci struct { 111d5ac70f0Sopenharmony_ci int min; 112d5ac70f0Sopenharmony_ci int max; 113d5ac70f0Sopenharmony_ci } rates; 114d5ac70f0Sopenharmony_ci int channels; 115d5ac70f0Sopenharmony_ci int drain_silence; 116d5ac70f0Sopenharmony_ci /* for chmap */ 117d5ac70f0Sopenharmony_ci unsigned int chmap_caps; 118d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **chmap_override; 119d5ac70f0Sopenharmony_ci} snd_pcm_hw_t; 120d5ac70f0Sopenharmony_ci 121d5ac70f0Sopenharmony_ci#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip" 122d5ac70f0Sopenharmony_ci#define SNDRV_FILE_PCM_STREAM_CAPTURE ALSA_DEVICE_DIRECTORY "pcmC%iD%ic" 123d5ac70f0Sopenharmony_ci#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 9) 124d5ac70f0Sopenharmony_ci 125d5ac70f0Sopenharmony_ci/* update appl_ptr with driver */ 126d5ac70f0Sopenharmony_ci#define FAST_PCM_STATE(hw) \ 127d5ac70f0Sopenharmony_ci ((snd_pcm_state_t) (hw)->mmap_status->state) 128d5ac70f0Sopenharmony_ci#define FAST_PCM_TSTAMP(hw) \ 129d5ac70f0Sopenharmony_ci ((hw)->mmap_status->tstamp) 130d5ac70f0Sopenharmony_ci 131d5ac70f0Sopenharmony_cistruct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm) 132d5ac70f0Sopenharmony_ci{ 133d5ac70f0Sopenharmony_ci struct timespec res; 134d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 135d5ac70f0Sopenharmony_ci res = FAST_PCM_TSTAMP(hw); 136d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) 137d5ac70f0Sopenharmony_ci res.tv_nsec *= 1000L; 138d5ac70f0Sopenharmony_ci return res; 139d5ac70f0Sopenharmony_ci} 140d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 141d5ac70f0Sopenharmony_ci 142d5ac70f0Sopenharmony_cistatic int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) 143d5ac70f0Sopenharmony_ci{ 144d5ac70f0Sopenharmony_ci int err; 145d5ac70f0Sopenharmony_ci hw->sync_ptr->flags = flags; 146d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { 147d5ac70f0Sopenharmony_ci err = -errno; 148d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); 149d5ac70f0Sopenharmony_ci return err; 150d5ac70f0Sopenharmony_ci } 151d5ac70f0Sopenharmony_ci return 0; 152d5ac70f0Sopenharmony_ci} 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_cistatic int issue_avail_min(snd_pcm_hw_t *hw) 155d5ac70f0Sopenharmony_ci{ 156d5ac70f0Sopenharmony_ci if (!hw->mmap_control_fallbacked) 157d5ac70f0Sopenharmony_ci return 0; 158d5ac70f0Sopenharmony_ci 159d5ac70f0Sopenharmony_ci /* Avoid unexpected change of applptr in kernel space. */ 160d5ac70f0Sopenharmony_ci return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL); 161d5ac70f0Sopenharmony_ci} 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_cistatic int issue_applptr(snd_pcm_hw_t *hw) 164d5ac70f0Sopenharmony_ci{ 165d5ac70f0Sopenharmony_ci if (!hw->mmap_control_fallbacked) 166d5ac70f0Sopenharmony_ci return 0; 167d5ac70f0Sopenharmony_ci 168d5ac70f0Sopenharmony_ci /* Avoid unexpected change of avail_min in kernel space. */ 169d5ac70f0Sopenharmony_ci return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN); 170d5ac70f0Sopenharmony_ci} 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_cistatic int request_hwsync(snd_pcm_hw_t *hw) 173d5ac70f0Sopenharmony_ci{ 174d5ac70f0Sopenharmony_ci if (!hw->mmap_status_fallbacked) 175d5ac70f0Sopenharmony_ci return 0; 176d5ac70f0Sopenharmony_ci 177d5ac70f0Sopenharmony_ci /* 178d5ac70f0Sopenharmony_ci * Query both of control/status data to avoid unexpected change of 179d5ac70f0Sopenharmony_ci * control data in kernel space. 180d5ac70f0Sopenharmony_ci */ 181d5ac70f0Sopenharmony_ci return sync_ptr1(hw, 182d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_HWSYNC | 183d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_APPL | 184d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_AVAIL_MIN); 185d5ac70f0Sopenharmony_ci} 186d5ac70f0Sopenharmony_ci 187d5ac70f0Sopenharmony_cistatic int query_status_and_control_data(snd_pcm_hw_t *hw) 188d5ac70f0Sopenharmony_ci{ 189d5ac70f0Sopenharmony_ci if (!hw->mmap_control_fallbacked) 190d5ac70f0Sopenharmony_ci return 0; 191d5ac70f0Sopenharmony_ci 192d5ac70f0Sopenharmony_ci /* 193d5ac70f0Sopenharmony_ci * Query both of control/status data to avoid unexpected change of 194d5ac70f0Sopenharmony_ci * control data in kernel space. 195d5ac70f0Sopenharmony_ci */ 196d5ac70f0Sopenharmony_ci return sync_ptr1(hw, 197d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_APPL | 198d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_AVAIL_MIN); 199d5ac70f0Sopenharmony_ci} 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_cistatic int query_status_data(snd_pcm_hw_t *hw) 202d5ac70f0Sopenharmony_ci{ 203d5ac70f0Sopenharmony_ci if (!hw->mmap_status_fallbacked) 204d5ac70f0Sopenharmony_ci return 0; 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_ci /* 207d5ac70f0Sopenharmony_ci * Query both of control/status data to avoid unexpected change of 208d5ac70f0Sopenharmony_ci * control data in kernel space. 209d5ac70f0Sopenharmony_ci */ 210d5ac70f0Sopenharmony_ci return sync_ptr1(hw, 211d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_APPL | 212d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_AVAIL_MIN); 213d5ac70f0Sopenharmony_ci} 214d5ac70f0Sopenharmony_ci 215d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) 216d5ac70f0Sopenharmony_ci{ 217d5ac70f0Sopenharmony_ci if (hw->period_timer_need_poll) { 218d5ac70f0Sopenharmony_ci while (poll(&hw->period_timer_pfd, 1, 0) > 0) { 219d5ac70f0Sopenharmony_ci snd_timer_tread_t rbuf[4]; 220d5ac70f0Sopenharmony_ci snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf)); 221d5ac70f0Sopenharmony_ci } 222d5ac70f0Sopenharmony_ci } else { 223d5ac70f0Sopenharmony_ci snd_timer_tread_t rbuf[4]; 224d5ac70f0Sopenharmony_ci snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf)); 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci return 0; 227d5ac70f0Sopenharmony_ci} 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 230d5ac70f0Sopenharmony_ci{ 231d5ac70f0Sopenharmony_ci return 2; 232d5ac70f0Sopenharmony_ci} 233d5ac70f0Sopenharmony_ci 234d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) 235d5ac70f0Sopenharmony_ci{ 236d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 237d5ac70f0Sopenharmony_ci 238d5ac70f0Sopenharmony_ci if (space < 2) 239d5ac70f0Sopenharmony_ci return -ENOMEM; 240d5ac70f0Sopenharmony_ci pfds[0].fd = hw->fd; 241d5ac70f0Sopenharmony_ci pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL; 242d5ac70f0Sopenharmony_ci pfds[1].fd = hw->period_timer_pfd.fd; 243d5ac70f0Sopenharmony_ci pfds[1].events = POLLIN | POLLERR | POLLNVAL; 244d5ac70f0Sopenharmony_ci return 2; 245d5ac70f0Sopenharmony_ci} 246d5ac70f0Sopenharmony_ci 247d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents) 248d5ac70f0Sopenharmony_ci{ 249d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 250d5ac70f0Sopenharmony_ci unsigned int events; 251d5ac70f0Sopenharmony_ci 252d5ac70f0Sopenharmony_ci if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd) 253d5ac70f0Sopenharmony_ci return -EINVAL; 254d5ac70f0Sopenharmony_ci events = pfds[0].revents; 255d5ac70f0Sopenharmony_ci if (pfds[1].revents & POLLIN) { 256d5ac70f0Sopenharmony_ci snd_pcm_hw_clear_timer_queue(hw); 257d5ac70f0Sopenharmony_ci events |= pcm->poll_events & ~(POLLERR|POLLNVAL); 258d5ac70f0Sopenharmony_ci } 259d5ac70f0Sopenharmony_ci *revents = events; 260d5ac70f0Sopenharmony_ci return 0; 261d5ac70f0Sopenharmony_ci} 262d5ac70f0Sopenharmony_ci 263d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock) 264d5ac70f0Sopenharmony_ci{ 265d5ac70f0Sopenharmony_ci long flags; 266d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 267d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 268d5ac70f0Sopenharmony_ci 269d5ac70f0Sopenharmony_ci if ((flags = fcntl(fd, F_GETFL)) < 0) { 270d5ac70f0Sopenharmony_ci err = -errno; 271d5ac70f0Sopenharmony_ci SYSMSG("F_GETFL failed (%i)", err); 272d5ac70f0Sopenharmony_ci return err; 273d5ac70f0Sopenharmony_ci } 274d5ac70f0Sopenharmony_ci if (nonblock) 275d5ac70f0Sopenharmony_ci flags |= O_NONBLOCK; 276d5ac70f0Sopenharmony_ci else 277d5ac70f0Sopenharmony_ci flags &= ~O_NONBLOCK; 278d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) { 279d5ac70f0Sopenharmony_ci err = -errno; 280d5ac70f0Sopenharmony_ci SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err); 281d5ac70f0Sopenharmony_ci return err; 282d5ac70f0Sopenharmony_ci } 283d5ac70f0Sopenharmony_ci return 0; 284d5ac70f0Sopenharmony_ci} 285d5ac70f0Sopenharmony_ci 286d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid) 287d5ac70f0Sopenharmony_ci{ 288d5ac70f0Sopenharmony_ci long flags; 289d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 290d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 291d5ac70f0Sopenharmony_ci 292d5ac70f0Sopenharmony_ci if ((flags = fcntl(fd, F_GETFL)) < 0) { 293d5ac70f0Sopenharmony_ci err = -errno; 294d5ac70f0Sopenharmony_ci SYSMSG("F_GETFL failed (%i)", err); 295d5ac70f0Sopenharmony_ci return err; 296d5ac70f0Sopenharmony_ci } 297d5ac70f0Sopenharmony_ci if (sig >= 0) 298d5ac70f0Sopenharmony_ci flags |= O_ASYNC; 299d5ac70f0Sopenharmony_ci else 300d5ac70f0Sopenharmony_ci flags &= ~O_ASYNC; 301d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) { 302d5ac70f0Sopenharmony_ci err = -errno; 303d5ac70f0Sopenharmony_ci SYSMSG("F_SETFL for O_ASYNC failed (%i)", err); 304d5ac70f0Sopenharmony_ci return err; 305d5ac70f0Sopenharmony_ci } 306d5ac70f0Sopenharmony_ci if (sig < 0) 307d5ac70f0Sopenharmony_ci return 0; 308d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETSIG, (long)sig) < 0) { 309d5ac70f0Sopenharmony_ci err = -errno; 310d5ac70f0Sopenharmony_ci SYSMSG("F_SETSIG failed (%i)", err); 311d5ac70f0Sopenharmony_ci return err; 312d5ac70f0Sopenharmony_ci } 313d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETOWN, (long)pid) < 0) { 314d5ac70f0Sopenharmony_ci err = -errno; 315d5ac70f0Sopenharmony_ci SYSMSG("F_SETOWN failed (%i)", err); 316d5ac70f0Sopenharmony_ci return err; 317d5ac70f0Sopenharmony_ci } 318d5ac70f0Sopenharmony_ci return 0; 319d5ac70f0Sopenharmony_ci} 320d5ac70f0Sopenharmony_ci 321d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info) 322d5ac70f0Sopenharmony_ci{ 323d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 324d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 325d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) { 326d5ac70f0Sopenharmony_ci err = -errno; 327d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err); 328d5ac70f0Sopenharmony_ci return err; 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci /* may be configurable (optional) */ 331d5ac70f0Sopenharmony_ci if (__snd_pcm_info_eld_fixup_check(info)) 332d5ac70f0Sopenharmony_ci return __snd_pcm_info_eld_fixup(info); 333d5ac70f0Sopenharmony_ci return 0; 334d5ac70f0Sopenharmony_ci} 335d5ac70f0Sopenharmony_ci 336d5ac70f0Sopenharmony_cistatic inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) 337d5ac70f0Sopenharmony_ci{ 338d5ac70f0Sopenharmony_ci /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */ 339d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version) 340d5ac70f0Sopenharmony_ci return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params); 341d5ac70f0Sopenharmony_ci return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params); 342d5ac70f0Sopenharmony_ci} 343d5ac70f0Sopenharmony_ci 344d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 345d5ac70f0Sopenharmony_ci{ 346d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 347d5ac70f0Sopenharmony_ci int err; 348d5ac70f0Sopenharmony_ci 349d5ac70f0Sopenharmony_ci if (hw->format != SND_PCM_FORMAT_UNKNOWN) { 350d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_format(params, hw->format); 351d5ac70f0Sopenharmony_ci if (err < 0) 352d5ac70f0Sopenharmony_ci return err; 353d5ac70f0Sopenharmony_ci } 354d5ac70f0Sopenharmony_ci if (hw->channels > 0) { 355d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, 356d5ac70f0Sopenharmony_ci hw->channels, 0); 357d5ac70f0Sopenharmony_ci if (err < 0) 358d5ac70f0Sopenharmony_ci return err; 359d5ac70f0Sopenharmony_ci } 360d5ac70f0Sopenharmony_ci if (hw->rates.min > 0) { 361d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE, 362d5ac70f0Sopenharmony_ci hw->rates.min, 0, hw->rates.max + 1, -1); 363d5ac70f0Sopenharmony_ci if (err < 0) 364d5ac70f0Sopenharmony_ci return err; 365d5ac70f0Sopenharmony_ci } 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_ci if (hw_refine_call(hw, params) < 0) { 368d5ac70f0Sopenharmony_ci err = -errno; 369d5ac70f0Sopenharmony_ci // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed"); 370d5ac70f0Sopenharmony_ci return err; 371d5ac70f0Sopenharmony_ci } 372d5ac70f0Sopenharmony_ci 373d5ac70f0Sopenharmony_ci if (params->info != ~0U) { 374d5ac70f0Sopenharmony_ci params->info &= ~0xf0000000; 375d5ac70f0Sopenharmony_ci if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) 376d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_MONOTONIC; 377d5ac70f0Sopenharmony_ci } 378d5ac70f0Sopenharmony_ci 379d5ac70f0Sopenharmony_ci return 0; 380d5ac70f0Sopenharmony_ci} 381d5ac70f0Sopenharmony_ci 382d5ac70f0Sopenharmony_ci#define hw_param_mask(params,var) \ 383d5ac70f0Sopenharmony_ci &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK]) 384d5ac70f0Sopenharmony_ci 385d5ac70f0Sopenharmony_cistatic int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) 386d5ac70f0Sopenharmony_ci{ 387d5ac70f0Sopenharmony_ci int err; 388d5ac70f0Sopenharmony_ci 389d5ac70f0Sopenharmony_ci /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */ 390d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version) 391d5ac70f0Sopenharmony_ci err = ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params); 392d5ac70f0Sopenharmony_ci else 393d5ac70f0Sopenharmony_ci err = use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params); 394d5ac70f0Sopenharmony_ci if (err >= 0 && pcm_hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 17) && params->msbits > 0) { 395d5ac70f0Sopenharmony_ci snd_mask_t *m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 396d5ac70f0Sopenharmony_ci if (snd_mask_single(m)) { 397d5ac70f0Sopenharmony_ci snd_pcm_format_t format = snd_mask_min(m); 398d5ac70f0Sopenharmony_ci int width = snd_pcm_format_width(format); 399d5ac70f0Sopenharmony_ci if (width > 0 && params->msbits > (unsigned int)width) 400d5ac70f0Sopenharmony_ci params->msbits = width; 401d5ac70f0Sopenharmony_ci } 402d5ac70f0Sopenharmony_ci } 403d5ac70f0Sopenharmony_ci return err; 404d5ac70f0Sopenharmony_ci} 405d5ac70f0Sopenharmony_ci 406d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 407d5ac70f0Sopenharmony_ci{ 408d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 409d5ac70f0Sopenharmony_ci int err; 410d5ac70f0Sopenharmony_ci if (hw_params_call(hw, params) < 0) { 411d5ac70f0Sopenharmony_ci err = -errno; 412d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err); 413d5ac70f0Sopenharmony_ci return err; 414d5ac70f0Sopenharmony_ci } 415d5ac70f0Sopenharmony_ci params->info &= ~0xf0000000; 416d5ac70f0Sopenharmony_ci if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) 417d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_MONOTONIC; 418d5ac70f0Sopenharmony_ci hw->perfect_drain = !!(params->info & SND_PCM_INFO_PERFECT_DRAIN) || 419d5ac70f0Sopenharmony_ci !!(params->flags & SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE); 420d5ac70f0Sopenharmony_ci return query_status_data(hw); 421d5ac70f0Sopenharmony_ci} 422d5ac70f0Sopenharmony_ci 423d5ac70f0Sopenharmony_cistatic void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) 424d5ac70f0Sopenharmony_ci{ 425d5ac70f0Sopenharmony_ci if (hw->period_timer) { 426d5ac70f0Sopenharmony_ci snd_timer_close(hw->period_timer); 427d5ac70f0Sopenharmony_ci hw->period_timer = NULL; 428d5ac70f0Sopenharmony_ci } 429d5ac70f0Sopenharmony_ci} 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable) 432d5ac70f0Sopenharmony_ci{ 433d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 434d5ac70f0Sopenharmony_ci snd_timer_params_t params = {0}; 435d5ac70f0Sopenharmony_ci unsigned int suspend, resume; 436d5ac70f0Sopenharmony_ci int err; 437d5ac70f0Sopenharmony_ci 438d5ac70f0Sopenharmony_ci if (enable) { 439d5ac70f0Sopenharmony_ci err = snd_timer_hw_open(&hw->period_timer, 440d5ac70f0Sopenharmony_ci "hw-pcm-period-event", 441d5ac70f0Sopenharmony_ci SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, 442d5ac70f0Sopenharmony_ci hw->card, hw->device, 443d5ac70f0Sopenharmony_ci (hw->subdevice << 1) | (pcm->stream & 1), 444d5ac70f0Sopenharmony_ci SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD); 445d5ac70f0Sopenharmony_ci if (err < 0) { 446d5ac70f0Sopenharmony_ci err = snd_timer_hw_open(&hw->period_timer, 447d5ac70f0Sopenharmony_ci "hw-pcm-period-event", 448d5ac70f0Sopenharmony_ci SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, 449d5ac70f0Sopenharmony_ci hw->card, hw->device, 450d5ac70f0Sopenharmony_ci (hw->subdevice << 1) | (pcm->stream & 1), 451d5ac70f0Sopenharmony_ci SND_TIMER_OPEN_NONBLOCK); 452d5ac70f0Sopenharmony_ci return err; 453d5ac70f0Sopenharmony_ci } 454d5ac70f0Sopenharmony_ci if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) { 455d5ac70f0Sopenharmony_ci snd_pcm_hw_close_timer(hw); 456d5ac70f0Sopenharmony_ci return -EINVAL; 457d5ac70f0Sopenharmony_ci } 458d5ac70f0Sopenharmony_ci hw->period_timer_pfd.events = POLLIN; 459d5ac70f0Sopenharmony_ci hw->period_timer_pfd.revents = 0; 460d5ac70f0Sopenharmony_ci snd_timer_poll_descriptors(hw->period_timer, 461d5ac70f0Sopenharmony_ci &hw->period_timer_pfd, 1); 462d5ac70f0Sopenharmony_ci hw->period_timer_need_poll = 0; 463d5ac70f0Sopenharmony_ci suspend = 1<<SND_TIMER_EVENT_MSUSPEND; 464d5ac70f0Sopenharmony_ci resume = 1<<SND_TIMER_EVENT_MRESUME; 465d5ac70f0Sopenharmony_ci /* 466d5ac70f0Sopenharmony_ci * hacks for older kernel drivers 467d5ac70f0Sopenharmony_ci */ 468d5ac70f0Sopenharmony_ci { 469d5ac70f0Sopenharmony_ci int ver = 0; 470d5ac70f0Sopenharmony_ci ioctl(hw->period_timer_pfd.fd, 471d5ac70f0Sopenharmony_ci SNDRV_TIMER_IOCTL_PVERSION, &ver); 472d5ac70f0Sopenharmony_ci /* 473d5ac70f0Sopenharmony_ci * In older versions, check via poll before read() is 474d5ac70f0Sopenharmony_ci * needed because of the confliction between 475d5ac70f0Sopenharmony_ci * TIMER_START and FIONBIO ioctls. 476d5ac70f0Sopenharmony_ci */ 477d5ac70f0Sopenharmony_ci if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4)) 478d5ac70f0Sopenharmony_ci hw->period_timer_need_poll = 1; 479d5ac70f0Sopenharmony_ci /* 480d5ac70f0Sopenharmony_ci * In older versions, timer uses pause events instead 481d5ac70f0Sopenharmony_ci * suspend/resume events. 482d5ac70f0Sopenharmony_ci */ 483d5ac70f0Sopenharmony_ci if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { 484d5ac70f0Sopenharmony_ci suspend = 1<<SND_TIMER_EVENT_MPAUSE; 485d5ac70f0Sopenharmony_ci resume = 1<<SND_TIMER_EVENT_MCONTINUE; 486d5ac70f0Sopenharmony_ci } 487d5ac70f0Sopenharmony_ci } 488d5ac70f0Sopenharmony_ci snd_timer_params_set_auto_start(¶ms, 1); 489d5ac70f0Sopenharmony_ci snd_timer_params_set_ticks(¶ms, 1); 490d5ac70f0Sopenharmony_ci INTERNAL(snd_timer_params_set_filter)(¶ms, (1<<SND_TIMER_EVENT_TICK) | 491d5ac70f0Sopenharmony_ci suspend | resume); 492d5ac70f0Sopenharmony_ci err = snd_timer_params(hw->period_timer, ¶ms); 493d5ac70f0Sopenharmony_ci if (err < 0) { 494d5ac70f0Sopenharmony_ci snd_pcm_hw_close_timer(hw); 495d5ac70f0Sopenharmony_ci return err; 496d5ac70f0Sopenharmony_ci } 497d5ac70f0Sopenharmony_ci err = snd_timer_start(hw->period_timer); 498d5ac70f0Sopenharmony_ci if (err < 0) { 499d5ac70f0Sopenharmony_ci snd_pcm_hw_close_timer(hw); 500d5ac70f0Sopenharmony_ci return err; 501d5ac70f0Sopenharmony_ci } 502d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_hw_fast_ops_timer; 503d5ac70f0Sopenharmony_ci } else { 504d5ac70f0Sopenharmony_ci snd_pcm_hw_close_timer(hw); 505d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_hw_fast_ops; 506d5ac70f0Sopenharmony_ci hw->period_event = 0; 507d5ac70f0Sopenharmony_ci } 508d5ac70f0Sopenharmony_ci return 0; 509d5ac70f0Sopenharmony_ci} 510d5ac70f0Sopenharmony_ci 511d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_hw_free(snd_pcm_t *pcm) 512d5ac70f0Sopenharmony_ci{ 513d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 514d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 515d5ac70f0Sopenharmony_ci snd_pcm_hw_change_timer(pcm, 0); 516d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) { 517d5ac70f0Sopenharmony_ci err = -errno; 518d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err); 519d5ac70f0Sopenharmony_ci return err; 520d5ac70f0Sopenharmony_ci } 521d5ac70f0Sopenharmony_ci return 0; 522d5ac70f0Sopenharmony_ci} 523d5ac70f0Sopenharmony_ci 524d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) 525d5ac70f0Sopenharmony_ci{ 526d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 527d5ac70f0Sopenharmony_ci int fd = hw->fd, err = 0; 528d5ac70f0Sopenharmony_ci int old_period_event = sw_get_period_event(params); 529d5ac70f0Sopenharmony_ci sw_set_period_event(params, 0); 530d5ac70f0Sopenharmony_ci if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && 531d5ac70f0Sopenharmony_ci (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type && 532d5ac70f0Sopenharmony_ci params->period_step == pcm->period_step && 533d5ac70f0Sopenharmony_ci params->start_threshold == pcm->start_threshold && 534d5ac70f0Sopenharmony_ci params->stop_threshold == pcm->stop_threshold && 535d5ac70f0Sopenharmony_ci params->silence_threshold == pcm->silence_threshold && 536d5ac70f0Sopenharmony_ci params->silence_size == pcm->silence_size && 537d5ac70f0Sopenharmony_ci old_period_event == hw->period_event) { 538d5ac70f0Sopenharmony_ci hw->mmap_control->avail_min = params->avail_min; 539d5ac70f0Sopenharmony_ci err = issue_avail_min(hw); 540d5ac70f0Sopenharmony_ci goto out; 541d5ac70f0Sopenharmony_ci } 542d5ac70f0Sopenharmony_ci if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW && 543d5ac70f0Sopenharmony_ci hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { 544d5ac70f0Sopenharmony_ci SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW"); 545d5ac70f0Sopenharmony_ci err = -EINVAL; 546d5ac70f0Sopenharmony_ci goto out; 547d5ac70f0Sopenharmony_ci } 548d5ac70f0Sopenharmony_ci if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC && 549d5ac70f0Sopenharmony_ci hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { 550d5ac70f0Sopenharmony_ci SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC"); 551d5ac70f0Sopenharmony_ci err = -EINVAL; 552d5ac70f0Sopenharmony_ci goto out; 553d5ac70f0Sopenharmony_ci } 554d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { 555d5ac70f0Sopenharmony_ci err = -errno; 556d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); 557d5ac70f0Sopenharmony_ci goto out; 558d5ac70f0Sopenharmony_ci } 559d5ac70f0Sopenharmony_ci hw->prepare_reset_sw_params = false; 560d5ac70f0Sopenharmony_ci if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) { 561d5ac70f0Sopenharmony_ci if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { 562d5ac70f0Sopenharmony_ci int on = (snd_pcm_tstamp_type_t) params->tstamp_type == 563d5ac70f0Sopenharmony_ci SND_PCM_TSTAMP_TYPE_MONOTONIC; 564d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) { 565d5ac70f0Sopenharmony_ci err = -errno; 566d5ac70f0Sopenharmony_ci SNDMSG("TSTAMP failed"); 567d5ac70f0Sopenharmony_ci goto out; 568d5ac70f0Sopenharmony_ci } 569d5ac70f0Sopenharmony_ci } 570d5ac70f0Sopenharmony_ci pcm->tstamp_type = params->tstamp_type; 571d5ac70f0Sopenharmony_ci } 572d5ac70f0Sopenharmony_ci hw->mmap_control->avail_min = params->avail_min; 573d5ac70f0Sopenharmony_ci if (hw->period_event != old_period_event) { 574d5ac70f0Sopenharmony_ci err = snd_pcm_hw_change_timer(pcm, old_period_event); 575d5ac70f0Sopenharmony_ci if (err < 0) 576d5ac70f0Sopenharmony_ci goto out; 577d5ac70f0Sopenharmony_ci hw->period_event = old_period_event; 578d5ac70f0Sopenharmony_ci } 579d5ac70f0Sopenharmony_ci out: 580d5ac70f0Sopenharmony_ci sw_set_period_event(params, old_period_event); 581d5ac70f0Sopenharmony_ci return err; 582d5ac70f0Sopenharmony_ci} 583d5ac70f0Sopenharmony_ci 584d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) 585d5ac70f0Sopenharmony_ci{ 586d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 587d5ac70f0Sopenharmony_ci struct snd_pcm_channel_info i; 588d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 589d5ac70f0Sopenharmony_ci i.channel = info->channel; 590d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) { 591d5ac70f0Sopenharmony_ci err = -errno; 592d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err); 593d5ac70f0Sopenharmony_ci return err; 594d5ac70f0Sopenharmony_ci } 595d5ac70f0Sopenharmony_ci info->channel = i.channel; 596d5ac70f0Sopenharmony_ci info->addr = 0; 597d5ac70f0Sopenharmony_ci info->first = i.first; 598d5ac70f0Sopenharmony_ci info->step = i.step; 599d5ac70f0Sopenharmony_ci info->type = SND_PCM_AREA_MMAP; 600d5ac70f0Sopenharmony_ci info->u.mmap.fd = fd; 601d5ac70f0Sopenharmony_ci info->u.mmap.offset = i.offset; 602d5ac70f0Sopenharmony_ci return 0; 603d5ac70f0Sopenharmony_ci} 604d5ac70f0Sopenharmony_ci 605d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 606d5ac70f0Sopenharmony_ci{ 607d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 608d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 609d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) { 610d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) { 611d5ac70f0Sopenharmony_ci err = -errno; 612d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err); 613d5ac70f0Sopenharmony_ci return err; 614d5ac70f0Sopenharmony_ci } 615d5ac70f0Sopenharmony_ci } else { 616d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) { 617d5ac70f0Sopenharmony_ci err = -errno; 618d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err); 619d5ac70f0Sopenharmony_ci return err; 620d5ac70f0Sopenharmony_ci } 621d5ac70f0Sopenharmony_ci } 622d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) { 623d5ac70f0Sopenharmony_ci status->tstamp.tv_nsec *= 1000L; 624d5ac70f0Sopenharmony_ci status->trigger_tstamp.tv_nsec *= 1000L; 625d5ac70f0Sopenharmony_ci } 626d5ac70f0Sopenharmony_ci return 0; 627d5ac70f0Sopenharmony_ci} 628d5ac70f0Sopenharmony_ci 629d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm) 630d5ac70f0Sopenharmony_ci{ 631d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 632d5ac70f0Sopenharmony_ci /* the -ENODEV may come from the snd_disconnect_ioctl() or 633d5ac70f0Sopenharmony_ci snd_power_wait() in kernel */ 634d5ac70f0Sopenharmony_ci if (query_status_data(hw) == -ENODEV) 635d5ac70f0Sopenharmony_ci return SND_PCM_STATE_DISCONNECTED; 636d5ac70f0Sopenharmony_ci return (snd_pcm_state_t) hw->mmap_status->state; 637d5ac70f0Sopenharmony_ci} 638d5ac70f0Sopenharmony_ci 639d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 640d5ac70f0Sopenharmony_ci{ 641d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 642d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 643d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) { 644d5ac70f0Sopenharmony_ci err = -errno; 645d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err); 646d5ac70f0Sopenharmony_ci return err; 647d5ac70f0Sopenharmony_ci } 648d5ac70f0Sopenharmony_ci return 0; 649d5ac70f0Sopenharmony_ci} 650d5ac70f0Sopenharmony_ci 651d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_hwsync(snd_pcm_t *pcm) 652d5ac70f0Sopenharmony_ci{ 653d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 654d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 655d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { 656d5ac70f0Sopenharmony_ci if (hw->mmap_status_fallbacked) { 657d5ac70f0Sopenharmony_ci err = request_hwsync(hw); 658d5ac70f0Sopenharmony_ci if (err < 0) 659d5ac70f0Sopenharmony_ci return err; 660d5ac70f0Sopenharmony_ci } else { 661d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) { 662d5ac70f0Sopenharmony_ci err = -errno; 663d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err); 664d5ac70f0Sopenharmony_ci return err; 665d5ac70f0Sopenharmony_ci } 666d5ac70f0Sopenharmony_ci } 667d5ac70f0Sopenharmony_ci } else { 668d5ac70f0Sopenharmony_ci snd_pcm_sframes_t delay; 669d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_delay(pcm, &delay); 670d5ac70f0Sopenharmony_ci if (err < 0) { 671d5ac70f0Sopenharmony_ci switch (FAST_PCM_STATE(hw)) { 672d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 673d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 674d5ac70f0Sopenharmony_ci return 0; 675d5ac70f0Sopenharmony_ci default: 676d5ac70f0Sopenharmony_ci return err; 677d5ac70f0Sopenharmony_ci } 678d5ac70f0Sopenharmony_ci } 679d5ac70f0Sopenharmony_ci } 680d5ac70f0Sopenharmony_ci return 0; 681d5ac70f0Sopenharmony_ci} 682d5ac70f0Sopenharmony_ci 683d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_prepare(snd_pcm_t *pcm) 684d5ac70f0Sopenharmony_ci{ 685d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 686d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw_params; 687d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 688d5ac70f0Sopenharmony_ci 689d5ac70f0Sopenharmony_ci if (hw->prepare_reset_sw_params) { 690d5ac70f0Sopenharmony_ci snd_pcm_sw_params_current_no_lock(pcm, &sw_params); 691d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params) < 0) { 692d5ac70f0Sopenharmony_ci err = -errno; 693d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); 694d5ac70f0Sopenharmony_ci return err; 695d5ac70f0Sopenharmony_ci } 696d5ac70f0Sopenharmony_ci hw->prepare_reset_sw_params = false; 697d5ac70f0Sopenharmony_ci } 698d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) { 699d5ac70f0Sopenharmony_ci err = -errno; 700d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err); 701d5ac70f0Sopenharmony_ci return err; 702d5ac70f0Sopenharmony_ci } 703d5ac70f0Sopenharmony_ci return query_status_and_control_data(hw); 704d5ac70f0Sopenharmony_ci} 705d5ac70f0Sopenharmony_ci 706d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_reset(snd_pcm_t *pcm) 707d5ac70f0Sopenharmony_ci{ 708d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 709d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 710d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) { 711d5ac70f0Sopenharmony_ci err = -errno; 712d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err); 713d5ac70f0Sopenharmony_ci return err; 714d5ac70f0Sopenharmony_ci } 715d5ac70f0Sopenharmony_ci return query_status_and_control_data(hw); 716d5ac70f0Sopenharmony_ci} 717d5ac70f0Sopenharmony_ci 718d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_start(snd_pcm_t *pcm) 719d5ac70f0Sopenharmony_ci{ 720d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 721d5ac70f0Sopenharmony_ci int err; 722d5ac70f0Sopenharmony_ci#if 0 723d5ac70f0Sopenharmony_ci assert(pcm->stream != SND_PCM_STREAM_PLAYBACK || 724d5ac70f0Sopenharmony_ci snd_pcm_mmap_playback_hw_avail(pcm) > 0); 725d5ac70f0Sopenharmony_ci#endif 726d5ac70f0Sopenharmony_ci issue_applptr(hw); 727d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) { 728d5ac70f0Sopenharmony_ci err = -errno; 729d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err); 730d5ac70f0Sopenharmony_ci#if 0 731d5ac70f0Sopenharmony_ci if (err == -EBADFD) 732d5ac70f0Sopenharmony_ci SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm))); 733d5ac70f0Sopenharmony_ci#endif 734d5ac70f0Sopenharmony_ci return err; 735d5ac70f0Sopenharmony_ci } 736d5ac70f0Sopenharmony_ci return 0; 737d5ac70f0Sopenharmony_ci} 738d5ac70f0Sopenharmony_ci 739d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_drop(snd_pcm_t *pcm) 740d5ac70f0Sopenharmony_ci{ 741d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 742d5ac70f0Sopenharmony_ci int err; 743d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) { 744d5ac70f0Sopenharmony_ci err = -errno; 745d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err); 746d5ac70f0Sopenharmony_ci return err; 747d5ac70f0Sopenharmony_ci } else { 748d5ac70f0Sopenharmony_ci } 749d5ac70f0Sopenharmony_ci return 0; 750d5ac70f0Sopenharmony_ci} 751d5ac70f0Sopenharmony_ci 752d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_drain(snd_pcm_t *pcm) 753d5ac70f0Sopenharmony_ci{ 754d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 755d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw_params; 756d5ac70f0Sopenharmony_ci snd_pcm_uframes_t silence_size; 757d5ac70f0Sopenharmony_ci int err; 758d5ac70f0Sopenharmony_ci 759d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_PLAYBACK) 760d5ac70f0Sopenharmony_ci goto __skip_silence; 761d5ac70f0Sopenharmony_ci /* stream probably in SETUP, prevent divide by zero */ 762d5ac70f0Sopenharmony_ci if (pcm->period_size == 0) 763d5ac70f0Sopenharmony_ci goto __skip_silence; 764d5ac70f0Sopenharmony_ci if (hw->drain_silence == 0 || hw->perfect_drain) 765d5ac70f0Sopenharmony_ci goto __skip_silence; 766d5ac70f0Sopenharmony_ci snd_pcm_sw_params_current_no_lock(pcm, &sw_params); 767d5ac70f0Sopenharmony_ci if (hw->drain_silence > 0) { 768d5ac70f0Sopenharmony_ci silence_size = (pcm->rate * hw->drain_silence) / 1000; 769d5ac70f0Sopenharmony_ci goto __manual_silence; 770d5ac70f0Sopenharmony_ci } 771d5ac70f0Sopenharmony_ci /* compute end silence size, align to period size + extra time */ 772d5ac70f0Sopenharmony_ci if ((pcm->boundary % pcm->period_size) == 0) { 773d5ac70f0Sopenharmony_ci silence_size = pcm->period_size - (*pcm->appl.ptr % pcm->period_size); 774d5ac70f0Sopenharmony_ci if (silence_size == pcm->period_size) 775d5ac70f0Sopenharmony_ci silence_size = 0; 776d5ac70f0Sopenharmony_ci } else { 777d5ac70f0Sopenharmony_ci /* it not not easy to compute the period crossing point 778d5ac70f0Sopenharmony_ci * in this case because the period is not aligned to the boundary 779d5ac70f0Sopenharmony_ci * - use the full range (one period) in this case 780d5ac70f0Sopenharmony_ci */ 781d5ac70f0Sopenharmony_ci silence_size = pcm->period_size; 782d5ac70f0Sopenharmony_ci } 783d5ac70f0Sopenharmony_ci silence_size += pcm->rate / 10; /* 1/10th of second */ 784d5ac70f0Sopenharmony_ci__manual_silence: 785d5ac70f0Sopenharmony_ci if (sw_params.silence_size < silence_size) { 786d5ac70f0Sopenharmony_ci /* fill the silence soon as possible (in the bellow ioctl 787d5ac70f0Sopenharmony_ci * or the next period wake up) 788d5ac70f0Sopenharmony_ci */ 789d5ac70f0Sopenharmony_ci sw_params.silence_threshold = pcm->buffer_size; 790d5ac70f0Sopenharmony_ci if (silence_size > pcm->buffer_size) 791d5ac70f0Sopenharmony_ci silence_size = pcm->buffer_size; 792d5ac70f0Sopenharmony_ci sw_params.silence_size = silence_size; 793d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params) < 0) { 794d5ac70f0Sopenharmony_ci err = -errno; 795d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); 796d5ac70f0Sopenharmony_ci return err; 797d5ac70f0Sopenharmony_ci } 798d5ac70f0Sopenharmony_ci hw->prepare_reset_sw_params = true; 799d5ac70f0Sopenharmony_ci } 800d5ac70f0Sopenharmony_ci__skip_silence: 801d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) { 802d5ac70f0Sopenharmony_ci err = -errno; 803d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err); 804d5ac70f0Sopenharmony_ci return err; 805d5ac70f0Sopenharmony_ci } 806d5ac70f0Sopenharmony_ci return 0; 807d5ac70f0Sopenharmony_ci} 808d5ac70f0Sopenharmony_ci 809d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable) 810d5ac70f0Sopenharmony_ci{ 811d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 812d5ac70f0Sopenharmony_ci int err; 813d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) { 814d5ac70f0Sopenharmony_ci err = -errno; 815d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err); 816d5ac70f0Sopenharmony_ci return err; 817d5ac70f0Sopenharmony_ci } 818d5ac70f0Sopenharmony_ci return 0; 819d5ac70f0Sopenharmony_ci} 820d5ac70f0Sopenharmony_ci 821d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm) 822d5ac70f0Sopenharmony_ci{ 823d5ac70f0Sopenharmony_ci return snd_pcm_mmap_hw_rewindable(pcm); 824d5ac70f0Sopenharmony_ci} 825d5ac70f0Sopenharmony_ci 826d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 827d5ac70f0Sopenharmony_ci{ 828d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 829d5ac70f0Sopenharmony_ci int err; 830d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) { 831d5ac70f0Sopenharmony_ci err = -errno; 832d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err); 833d5ac70f0Sopenharmony_ci return err; 834d5ac70f0Sopenharmony_ci } 835d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 836d5ac70f0Sopenharmony_ci if (err < 0) 837d5ac70f0Sopenharmony_ci return err; 838d5ac70f0Sopenharmony_ci return frames; 839d5ac70f0Sopenharmony_ci} 840d5ac70f0Sopenharmony_ci 841d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm) 842d5ac70f0Sopenharmony_ci{ 843d5ac70f0Sopenharmony_ci return snd_pcm_mmap_avail(pcm); 844d5ac70f0Sopenharmony_ci} 845d5ac70f0Sopenharmony_ci 846d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 847d5ac70f0Sopenharmony_ci{ 848d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 849d5ac70f0Sopenharmony_ci int err; 850d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) { 851d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) { 852d5ac70f0Sopenharmony_ci err = -errno; 853d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err); 854d5ac70f0Sopenharmony_ci return err; 855d5ac70f0Sopenharmony_ci } 856d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 857d5ac70f0Sopenharmony_ci if (err < 0) 858d5ac70f0Sopenharmony_ci return err; 859d5ac70f0Sopenharmony_ci return frames; 860d5ac70f0Sopenharmony_ci } else { 861d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 862d5ac70f0Sopenharmony_ci 863d5ac70f0Sopenharmony_ci switch (FAST_PCM_STATE(hw)) { 864d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 865d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 866d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PAUSED: 867d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 868d5ac70f0Sopenharmony_ci break; 869d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 870d5ac70f0Sopenharmony_ci return -EPIPE; 871d5ac70f0Sopenharmony_ci default: 872d5ac70f0Sopenharmony_ci return -EBADFD; 873d5ac70f0Sopenharmony_ci } 874d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 875d5ac70f0Sopenharmony_ci if (avail < 0) 876d5ac70f0Sopenharmony_ci return 0; 877d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 878d5ac70f0Sopenharmony_ci frames = avail; 879d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 880d5ac70f0Sopenharmony_ci return frames; 881d5ac70f0Sopenharmony_ci } 882d5ac70f0Sopenharmony_ci} 883d5ac70f0Sopenharmony_ci 884d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_resume(snd_pcm_t *pcm) 885d5ac70f0Sopenharmony_ci{ 886d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 887d5ac70f0Sopenharmony_ci int fd = hw->fd, err; 888d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) { 889d5ac70f0Sopenharmony_ci err = -errno; 890d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err); 891d5ac70f0Sopenharmony_ci return err; 892d5ac70f0Sopenharmony_ci } 893d5ac70f0Sopenharmony_ci return 0; 894d5ac70f0Sopenharmony_ci} 895d5ac70f0Sopenharmony_ci 896d5ac70f0Sopenharmony_cistatic int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) 897d5ac70f0Sopenharmony_ci{ 898d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw1 = pcm1->private_data; 899d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw2 = pcm2->private_data; 900d5ac70f0Sopenharmony_ci if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) { 901d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno); 902d5ac70f0Sopenharmony_ci return -errno; 903d5ac70f0Sopenharmony_ci } 904d5ac70f0Sopenharmony_ci return 0; 905d5ac70f0Sopenharmony_ci} 906d5ac70f0Sopenharmony_ci 907d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master) 908d5ac70f0Sopenharmony_ci{ 909d5ac70f0Sopenharmony_ci if (master->type != SND_PCM_TYPE_HW) { 910d5ac70f0Sopenharmony_ci SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type); 911d5ac70f0Sopenharmony_ci return -EINVAL; 912d5ac70f0Sopenharmony_ci } 913d5ac70f0Sopenharmony_ci return hw_link(master, pcm); 914d5ac70f0Sopenharmony_ci} 915d5ac70f0Sopenharmony_ci 916d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) 917d5ac70f0Sopenharmony_ci{ 918d5ac70f0Sopenharmony_ci if (pcm2->type != SND_PCM_TYPE_HW) { 919d5ac70f0Sopenharmony_ci if (pcm2->fast_ops->link_slaves) 920d5ac70f0Sopenharmony_ci return pcm2->fast_ops->link_slaves(pcm2->fast_op_arg, pcm1); 921d5ac70f0Sopenharmony_ci return -ENOSYS; 922d5ac70f0Sopenharmony_ci } 923d5ac70f0Sopenharmony_ci return hw_link(pcm1, pcm2); 924d5ac70f0Sopenharmony_ci } 925d5ac70f0Sopenharmony_ci 926d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_unlink(snd_pcm_t *pcm) 927d5ac70f0Sopenharmony_ci{ 928d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 929d5ac70f0Sopenharmony_ci 930d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) { 931d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno); 932d5ac70f0Sopenharmony_ci return -errno; 933d5ac70f0Sopenharmony_ci } 934d5ac70f0Sopenharmony_ci return 0; 935d5ac70f0Sopenharmony_ci} 936d5ac70f0Sopenharmony_ci 937d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) 938d5ac70f0Sopenharmony_ci{ 939d5ac70f0Sopenharmony_ci int err; 940d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 941d5ac70f0Sopenharmony_ci int fd = hw->fd; 942d5ac70f0Sopenharmony_ci struct snd_xferi xferi; 943d5ac70f0Sopenharmony_ci xferi.buf = (char*) buffer; 944d5ac70f0Sopenharmony_ci xferi.frames = size; 945d5ac70f0Sopenharmony_ci xferi.result = 0; /* make valgrind happy */ 946d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0) 947d5ac70f0Sopenharmony_ci err = -errno; 948d5ac70f0Sopenharmony_ci else 949d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 950d5ac70f0Sopenharmony_ci#ifdef DEBUG_RW 951d5ac70f0Sopenharmony_ci fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err); 952d5ac70f0Sopenharmony_ci#endif 953d5ac70f0Sopenharmony_ci if (err < 0) 954d5ac70f0Sopenharmony_ci return snd_pcm_check_error(pcm, err); 955d5ac70f0Sopenharmony_ci return xferi.result; 956d5ac70f0Sopenharmony_ci} 957d5ac70f0Sopenharmony_ci 958d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 959d5ac70f0Sopenharmony_ci{ 960d5ac70f0Sopenharmony_ci int err; 961d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 962d5ac70f0Sopenharmony_ci int fd = hw->fd; 963d5ac70f0Sopenharmony_ci struct snd_xfern xfern; 964d5ac70f0Sopenharmony_ci memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ 965d5ac70f0Sopenharmony_ci xfern.bufs = bufs; 966d5ac70f0Sopenharmony_ci xfern.frames = size; 967d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0) 968d5ac70f0Sopenharmony_ci err = -errno; 969d5ac70f0Sopenharmony_ci else 970d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 971d5ac70f0Sopenharmony_ci#ifdef DEBUG_RW 972d5ac70f0Sopenharmony_ci fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err); 973d5ac70f0Sopenharmony_ci#endif 974d5ac70f0Sopenharmony_ci if (err < 0) 975d5ac70f0Sopenharmony_ci return snd_pcm_check_error(pcm, err); 976d5ac70f0Sopenharmony_ci return xfern.result; 977d5ac70f0Sopenharmony_ci} 978d5ac70f0Sopenharmony_ci 979d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) 980d5ac70f0Sopenharmony_ci{ 981d5ac70f0Sopenharmony_ci int err; 982d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 983d5ac70f0Sopenharmony_ci int fd = hw->fd; 984d5ac70f0Sopenharmony_ci struct snd_xferi xferi; 985d5ac70f0Sopenharmony_ci xferi.buf = buffer; 986d5ac70f0Sopenharmony_ci xferi.frames = size; 987d5ac70f0Sopenharmony_ci xferi.result = 0; /* make valgrind happy */ 988d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0) 989d5ac70f0Sopenharmony_ci err = -errno; 990d5ac70f0Sopenharmony_ci else 991d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 992d5ac70f0Sopenharmony_ci#ifdef DEBUG_RW 993d5ac70f0Sopenharmony_ci fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err); 994d5ac70f0Sopenharmony_ci#endif 995d5ac70f0Sopenharmony_ci if (err < 0) 996d5ac70f0Sopenharmony_ci return snd_pcm_check_error(pcm, err); 997d5ac70f0Sopenharmony_ci return xferi.result; 998d5ac70f0Sopenharmony_ci} 999d5ac70f0Sopenharmony_ci 1000d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 1001d5ac70f0Sopenharmony_ci{ 1002d5ac70f0Sopenharmony_ci int err; 1003d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1004d5ac70f0Sopenharmony_ci int fd = hw->fd; 1005d5ac70f0Sopenharmony_ci struct snd_xfern xfern; 1006d5ac70f0Sopenharmony_ci memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ 1007d5ac70f0Sopenharmony_ci xfern.bufs = bufs; 1008d5ac70f0Sopenharmony_ci xfern.frames = size; 1009d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0) 1010d5ac70f0Sopenharmony_ci err = -errno; 1011d5ac70f0Sopenharmony_ci else 1012d5ac70f0Sopenharmony_ci err = query_status_and_control_data(hw); 1013d5ac70f0Sopenharmony_ci#ifdef DEBUG_RW 1014d5ac70f0Sopenharmony_ci fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err); 1015d5ac70f0Sopenharmony_ci#endif 1016d5ac70f0Sopenharmony_ci if (err < 0) 1017d5ac70f0Sopenharmony_ci return snd_pcm_check_error(pcm, err); 1018d5ac70f0Sopenharmony_ci return xfern.result; 1019d5ac70f0Sopenharmony_ci} 1020d5ac70f0Sopenharmony_ci 1021d5ac70f0Sopenharmony_cistatic bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr, 1022d5ac70f0Sopenharmony_ci bool force_fallback) 1023d5ac70f0Sopenharmony_ci{ 1024d5ac70f0Sopenharmony_ci struct snd_pcm_mmap_status *mmap_status; 1025d5ac70f0Sopenharmony_ci bool fallbacked; 1026d5ac70f0Sopenharmony_ci 1027d5ac70f0Sopenharmony_ci mmap_status = MAP_FAILED; 1028d5ac70f0Sopenharmony_ci if (!force_fallback) { 1029d5ac70f0Sopenharmony_ci mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)), 1030d5ac70f0Sopenharmony_ci PROT_READ, MAP_FILE|MAP_SHARED, 1031d5ac70f0Sopenharmony_ci hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); 1032d5ac70f0Sopenharmony_ci } 1033d5ac70f0Sopenharmony_ci 1034d5ac70f0Sopenharmony_ci if (mmap_status == MAP_FAILED || mmap_status == NULL) { 1035d5ac70f0Sopenharmony_ci mmap_status = &sync_ptr->s.status; 1036d5ac70f0Sopenharmony_ci fallbacked = true; 1037d5ac70f0Sopenharmony_ci } else { 1038d5ac70f0Sopenharmony_ci fallbacked = false; 1039d5ac70f0Sopenharmony_ci } 1040d5ac70f0Sopenharmony_ci 1041d5ac70f0Sopenharmony_ci hw->mmap_status = mmap_status; 1042d5ac70f0Sopenharmony_ci 1043d5ac70f0Sopenharmony_ci return fallbacked; 1044d5ac70f0Sopenharmony_ci} 1045d5ac70f0Sopenharmony_ci 1046d5ac70f0Sopenharmony_cistatic bool map_control_data(snd_pcm_hw_t *hw, 1047d5ac70f0Sopenharmony_ci struct snd_pcm_sync_ptr *sync_ptr, 1048d5ac70f0Sopenharmony_ci bool force_fallback) 1049d5ac70f0Sopenharmony_ci{ 1050d5ac70f0Sopenharmony_ci struct snd_pcm_mmap_control *mmap_control; 1051d5ac70f0Sopenharmony_ci bool fallbacked; 1052d5ac70f0Sopenharmony_ci 1053d5ac70f0Sopenharmony_ci mmap_control = MAP_FAILED; 1054d5ac70f0Sopenharmony_ci if (!force_fallback) { 1055d5ac70f0Sopenharmony_ci mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), 1056d5ac70f0Sopenharmony_ci PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 1057d5ac70f0Sopenharmony_ci hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); 1058d5ac70f0Sopenharmony_ci } 1059d5ac70f0Sopenharmony_ci 1060d5ac70f0Sopenharmony_ci if (mmap_control == MAP_FAILED || mmap_control == NULL) { 1061d5ac70f0Sopenharmony_ci mmap_control = &sync_ptr->c.control; 1062d5ac70f0Sopenharmony_ci fallbacked = true; 1063d5ac70f0Sopenharmony_ci } else { 1064d5ac70f0Sopenharmony_ci fallbacked = false; 1065d5ac70f0Sopenharmony_ci } 1066d5ac70f0Sopenharmony_ci 1067d5ac70f0Sopenharmony_ci hw->mmap_control = mmap_control; 1068d5ac70f0Sopenharmony_ci 1069d5ac70f0Sopenharmony_ci return fallbacked; 1070d5ac70f0Sopenharmony_ci} 1071d5ac70f0Sopenharmony_ci 1072d5ac70f0Sopenharmony_cistatic int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) 1073d5ac70f0Sopenharmony_ci{ 1074d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1075d5ac70f0Sopenharmony_ci struct snd_pcm_sync_ptr *sync_ptr; 1076d5ac70f0Sopenharmony_ci int err; 1077d5ac70f0Sopenharmony_ci 1078d5ac70f0Sopenharmony_ci /* Preparation for fallback to failure of mmap(2). */ 1079d5ac70f0Sopenharmony_ci sync_ptr = malloc(sizeof(*sync_ptr)); 1080d5ac70f0Sopenharmony_ci if (sync_ptr == NULL) 1081d5ac70f0Sopenharmony_ci return -ENOMEM; 1082d5ac70f0Sopenharmony_ci memset(sync_ptr, 0, sizeof(*sync_ptr)); 1083d5ac70f0Sopenharmony_ci 1084d5ac70f0Sopenharmony_ci hw->mmap_status_fallbacked = 1085d5ac70f0Sopenharmony_ci map_status_data(hw, sync_ptr, force_fallback); 1086d5ac70f0Sopenharmony_ci hw->mmap_control_fallbacked = 1087d5ac70f0Sopenharmony_ci map_control_data(hw, sync_ptr, force_fallback); 1088d5ac70f0Sopenharmony_ci 1089d5ac70f0Sopenharmony_ci /* Any fallback mode needs to keep the buffer. */ 1090d5ac70f0Sopenharmony_ci if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) { 1091d5ac70f0Sopenharmony_ci hw->sync_ptr = sync_ptr; 1092d5ac70f0Sopenharmony_ci } else { 1093d5ac70f0Sopenharmony_ci free(sync_ptr); 1094d5ac70f0Sopenharmony_ci hw->sync_ptr = NULL; 1095d5ac70f0Sopenharmony_ci } 1096d5ac70f0Sopenharmony_ci 1097d5ac70f0Sopenharmony_ci /* do not initialize in case of append and keep the values from the 1098d5ac70f0Sopenharmony_ci * kernel 1099d5ac70f0Sopenharmony_ci */ 1100d5ac70f0Sopenharmony_ci if (!(pcm->mode & SND_PCM_APPEND)) { 1101d5ac70f0Sopenharmony_ci /* Initialize the data. */ 1102d5ac70f0Sopenharmony_ci hw->mmap_control->appl_ptr = 0; 1103d5ac70f0Sopenharmony_ci hw->mmap_control->avail_min = 1; 1104d5ac70f0Sopenharmony_ci } 1105d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, 1106d5ac70f0Sopenharmony_ci SNDRV_PCM_MMAP_OFFSET_STATUS + 1107d5ac70f0Sopenharmony_ci offsetof(struct snd_pcm_mmap_status, hw_ptr)); 1108d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, 1109d5ac70f0Sopenharmony_ci SNDRV_PCM_MMAP_OFFSET_CONTROL); 1110d5ac70f0Sopenharmony_ci if (hw->mmap_control_fallbacked) { 1111d5ac70f0Sopenharmony_ci unsigned int flags = 0; 1112d5ac70f0Sopenharmony_ci /* read appl_ptr and avail_min from kernel when device opened 1113d5ac70f0Sopenharmony_ci * with SND_PCM_APPEND flag 1114d5ac70f0Sopenharmony_ci */ 1115d5ac70f0Sopenharmony_ci if (pcm->mode & SND_PCM_APPEND) 1116d5ac70f0Sopenharmony_ci flags = SNDRV_PCM_SYNC_PTR_APPL | 1117d5ac70f0Sopenharmony_ci SNDRV_PCM_SYNC_PTR_AVAIL_MIN; 1118d5ac70f0Sopenharmony_ci err = sync_ptr1(hw, flags); 1119d5ac70f0Sopenharmony_ci if (err < 0) 1120d5ac70f0Sopenharmony_ci return err; 1121d5ac70f0Sopenharmony_ci } 1122d5ac70f0Sopenharmony_ci 1123d5ac70f0Sopenharmony_ci return 0; 1124d5ac70f0Sopenharmony_ci} 1125d5ac70f0Sopenharmony_ci 1126d5ac70f0Sopenharmony_cistatic void unmap_status_data(snd_pcm_hw_t *hw) 1127d5ac70f0Sopenharmony_ci{ 1128d5ac70f0Sopenharmony_ci if (!hw->mmap_status_fallbacked) { 1129d5ac70f0Sopenharmony_ci if (munmap((void *)hw->mmap_status, 1130d5ac70f0Sopenharmony_ci page_align(sizeof(*hw->mmap_status))) < 0) 1131d5ac70f0Sopenharmony_ci SYSMSG("status munmap failed (%u)", errno); 1132d5ac70f0Sopenharmony_ci } 1133d5ac70f0Sopenharmony_ci} 1134d5ac70f0Sopenharmony_ci 1135d5ac70f0Sopenharmony_cistatic void unmap_control_data(snd_pcm_hw_t *hw) 1136d5ac70f0Sopenharmony_ci{ 1137d5ac70f0Sopenharmony_ci if (!hw->mmap_control_fallbacked) { 1138d5ac70f0Sopenharmony_ci if (munmap((void *)hw->mmap_control, 1139d5ac70f0Sopenharmony_ci page_align(sizeof(*hw->mmap_control))) < 0) 1140d5ac70f0Sopenharmony_ci SYSMSG("control munmap failed (%u)", errno); 1141d5ac70f0Sopenharmony_ci } 1142d5ac70f0Sopenharmony_ci} 1143d5ac70f0Sopenharmony_ci 1144d5ac70f0Sopenharmony_cistatic void unmap_status_and_control_data(snd_pcm_hw_t *hw) 1145d5ac70f0Sopenharmony_ci{ 1146d5ac70f0Sopenharmony_ci unmap_status_data(hw); 1147d5ac70f0Sopenharmony_ci unmap_control_data(hw); 1148d5ac70f0Sopenharmony_ci 1149d5ac70f0Sopenharmony_ci if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) 1150d5ac70f0Sopenharmony_ci free(hw->sync_ptr); 1151d5ac70f0Sopenharmony_ci 1152d5ac70f0Sopenharmony_ci hw->mmap_status = NULL; 1153d5ac70f0Sopenharmony_ci hw->mmap_control = NULL; 1154d5ac70f0Sopenharmony_ci hw->mmap_status_fallbacked = false; 1155d5ac70f0Sopenharmony_ci hw->mmap_control_fallbacked = false; 1156d5ac70f0Sopenharmony_ci hw->sync_ptr = NULL; 1157d5ac70f0Sopenharmony_ci} 1158d5ac70f0Sopenharmony_ci 1159d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 1160d5ac70f0Sopenharmony_ci{ 1161d5ac70f0Sopenharmony_ci return 0; 1162d5ac70f0Sopenharmony_ci} 1163d5ac70f0Sopenharmony_ci 1164d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 1165d5ac70f0Sopenharmony_ci{ 1166d5ac70f0Sopenharmony_ci return 0; 1167d5ac70f0Sopenharmony_ci} 1168d5ac70f0Sopenharmony_ci 1169d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_close(snd_pcm_t *pcm) 1170d5ac70f0Sopenharmony_ci{ 1171d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1172d5ac70f0Sopenharmony_ci int err = 0; 1173d5ac70f0Sopenharmony_ci if (close(hw->fd)) { 1174d5ac70f0Sopenharmony_ci err = -errno; 1175d5ac70f0Sopenharmony_ci SYSMSG("close failed (%i)", err); 1176d5ac70f0Sopenharmony_ci } 1177d5ac70f0Sopenharmony_ci 1178d5ac70f0Sopenharmony_ci unmap_status_and_control_data(hw); 1179d5ac70f0Sopenharmony_ci 1180d5ac70f0Sopenharmony_ci free(hw); 1181d5ac70f0Sopenharmony_ci return err; 1182d5ac70f0Sopenharmony_ci} 1183d5ac70f0Sopenharmony_ci 1184d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, 1185d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 1186d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 1187d5ac70f0Sopenharmony_ci{ 1188d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1189d5ac70f0Sopenharmony_ci 1190d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 1191d5ac70f0Sopenharmony_ci issue_applptr(hw); 1192d5ac70f0Sopenharmony_ci#ifdef DEBUG_MMAP 1193d5ac70f0Sopenharmony_ci fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); 1194d5ac70f0Sopenharmony_ci#endif 1195d5ac70f0Sopenharmony_ci return size; 1196d5ac70f0Sopenharmony_ci} 1197d5ac70f0Sopenharmony_ci 1198d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) 1199d5ac70f0Sopenharmony_ci{ 1200d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1201d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail; 1202d5ac70f0Sopenharmony_ci 1203d5ac70f0Sopenharmony_ci query_status_data(hw); 1204d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 1205d5ac70f0Sopenharmony_ci switch (FAST_PCM_STATE(hw)) { 1206d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 1207d5ac70f0Sopenharmony_ci if (avail >= pcm->stop_threshold) { 1208d5ac70f0Sopenharmony_ci /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ 1209d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) { 1210d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0) 1211d5ac70f0Sopenharmony_ci return -errno; 1212d5ac70f0Sopenharmony_ci } 1213d5ac70f0Sopenharmony_ci /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */ 1214d5ac70f0Sopenharmony_ci return -EPIPE; 1215d5ac70f0Sopenharmony_ci } 1216d5ac70f0Sopenharmony_ci break; 1217d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 1218d5ac70f0Sopenharmony_ci return -EPIPE; 1219d5ac70f0Sopenharmony_ci default: 1220d5ac70f0Sopenharmony_ci break; 1221d5ac70f0Sopenharmony_ci } 1222d5ac70f0Sopenharmony_ci return avail; 1223d5ac70f0Sopenharmony_ci} 1224d5ac70f0Sopenharmony_ci 1225d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, 1226d5ac70f0Sopenharmony_ci snd_htimestamp_t *tstamp) 1227d5ac70f0Sopenharmony_ci{ 1228d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail1; 1229d5ac70f0Sopenharmony_ci int ok = 0; 1230d5ac70f0Sopenharmony_ci 1231d5ac70f0Sopenharmony_ci /* unfortunately, loop is necessary to ensure valid timestamp */ 1232d5ac70f0Sopenharmony_ci while (1) { 1233d5ac70f0Sopenharmony_ci avail1 = snd_pcm_hw_avail_update(pcm); 1234d5ac70f0Sopenharmony_ci if (avail1 < 0) 1235d5ac70f0Sopenharmony_ci return avail1; 1236d5ac70f0Sopenharmony_ci if (ok && (snd_pcm_uframes_t)avail1 == *avail) 1237d5ac70f0Sopenharmony_ci break; 1238d5ac70f0Sopenharmony_ci *avail = avail1; 1239d5ac70f0Sopenharmony_ci *tstamp = snd_pcm_hw_fast_tstamp(pcm); 1240d5ac70f0Sopenharmony_ci ok = 1; 1241d5ac70f0Sopenharmony_ci } 1242d5ac70f0Sopenharmony_ci return 0; 1243d5ac70f0Sopenharmony_ci} 1244d5ac70f0Sopenharmony_ci 1245d5ac70f0Sopenharmony_cistatic void __fill_chmap_ctl_id(snd_ctl_elem_id_t *id, int dev, int subdev, 1246d5ac70f0Sopenharmony_ci int stream) 1247d5ac70f0Sopenharmony_ci{ 1248d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); 1249d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_PLAYBACK) 1250d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_name(id, "Playback Channel Map"); 1251d5ac70f0Sopenharmony_ci else 1252d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_name(id, "Capture Channel Map"); 1253d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_device(id, dev); 1254d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_index(id, subdev); 1255d5ac70f0Sopenharmony_ci} 1256d5ac70f0Sopenharmony_ci 1257d5ac70f0Sopenharmony_cistatic void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id) 1258d5ac70f0Sopenharmony_ci{ 1259d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1260d5ac70f0Sopenharmony_ci __fill_chmap_ctl_id(id, hw->device, hw->subdevice, pcm->stream); 1261d5ac70f0Sopenharmony_ci} 1262d5ac70f0Sopenharmony_ci 1263d5ac70f0Sopenharmony_cistatic int is_chmap_type(int type) 1264d5ac70f0Sopenharmony_ci{ 1265d5ac70f0Sopenharmony_ci return (type >= SND_CTL_TLVT_CHMAP_FIXED && 1266d5ac70f0Sopenharmony_ci type <= SND_CTL_TLVT_CHMAP_PAIRED); 1267d5ac70f0Sopenharmony_ci} 1268d5ac70f0Sopenharmony_ci 1269d5ac70f0Sopenharmony_ci/** 1270d5ac70f0Sopenharmony_ci * \!brief Query the available channel maps 1271d5ac70f0Sopenharmony_ci * \param card the card number 1272d5ac70f0Sopenharmony_ci * \param dev the PCM device number 1273d5ac70f0Sopenharmony_ci * \param subdev the PCM substream index 1274d5ac70f0Sopenharmony_ci * \param stream the direction of PCM stream 1275d5ac70f0Sopenharmony_ci * \return the NULL-terminated array of integer pointers, or NULL at error. 1276d5ac70f0Sopenharmony_ci * 1277d5ac70f0Sopenharmony_ci * This function works like snd_pcm_query_chmaps() but it takes the card, 1278d5ac70f0Sopenharmony_ci * device, substream and stream numbers instead of the already opened 1279d5ac70f0Sopenharmony_ci * snd_pcm_t instance, so that you can query available channel maps of 1280d5ac70f0Sopenharmony_ci * a PCM before actually opening it. 1281d5ac70f0Sopenharmony_ci * 1282d5ac70f0Sopenharmony_ci * As the parameters stand, the query is performed only to the hw PCM 1283d5ac70f0Sopenharmony_ci * devices, not the abstracted PCM object in alsa-lib. 1284d5ac70f0Sopenharmony_ci */ 1285d5ac70f0Sopenharmony_cisnd_pcm_chmap_query_t ** 1286d5ac70f0Sopenharmony_cisnd_pcm_query_chmaps_from_hw(int card, int dev, int subdev, 1287d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream) 1288d5ac70f0Sopenharmony_ci{ 1289d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 1290d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t id = {0}; 1291d5ac70f0Sopenharmony_ci unsigned int tlv[2048], *start; 1292d5ac70f0Sopenharmony_ci unsigned int type; 1293d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **map; 1294d5ac70f0Sopenharmony_ci int i, ret, nums; 1295d5ac70f0Sopenharmony_ci 1296d5ac70f0Sopenharmony_ci ret = snd_ctl_hw_open(&ctl, NULL, card, 0); 1297d5ac70f0Sopenharmony_ci if (ret < 0) { 1298d5ac70f0Sopenharmony_ci SYSMSG("Cannot open the associated CTL"); 1299d5ac70f0Sopenharmony_ci return NULL; 1300d5ac70f0Sopenharmony_ci } 1301d5ac70f0Sopenharmony_ci 1302d5ac70f0Sopenharmony_ci __fill_chmap_ctl_id(&id, dev, subdev, stream); 1303d5ac70f0Sopenharmony_ci ret = snd_ctl_elem_tlv_read(ctl, &id, tlv, sizeof(tlv)); 1304d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 1305d5ac70f0Sopenharmony_ci if (ret < 0) { 1306d5ac70f0Sopenharmony_ci SYSMSG("Cannot read Channel Map TLV"); 1307d5ac70f0Sopenharmony_ci return NULL; 1308d5ac70f0Sopenharmony_ci } 1309d5ac70f0Sopenharmony_ci 1310d5ac70f0Sopenharmony_ci#if 0 1311d5ac70f0Sopenharmony_ci for (i = 0; i < 32; i++) 1312d5ac70f0Sopenharmony_ci fprintf(stderr, "%02x: %08x\n", i, tlv[i]); 1313d5ac70f0Sopenharmony_ci#endif 1314d5ac70f0Sopenharmony_ci /* FIXME: the parser below assumes that the TLV only contains 1315d5ac70f0Sopenharmony_ci * chmap-related blocks 1316d5ac70f0Sopenharmony_ci */ 1317d5ac70f0Sopenharmony_ci type = tlv[SNDRV_CTL_TLVO_TYPE]; 1318d5ac70f0Sopenharmony_ci if (type != SND_CTL_TLVT_CONTAINER) { 1319d5ac70f0Sopenharmony_ci if (!is_chmap_type(type)) { 1320d5ac70f0Sopenharmony_ci SYSMSG("Invalid TLV type %d", type); 1321d5ac70f0Sopenharmony_ci return NULL; 1322d5ac70f0Sopenharmony_ci } 1323d5ac70f0Sopenharmony_ci start = tlv; 1324d5ac70f0Sopenharmony_ci nums = 1; 1325d5ac70f0Sopenharmony_ci } else { 1326d5ac70f0Sopenharmony_ci unsigned int *p; 1327d5ac70f0Sopenharmony_ci int size; 1328d5ac70f0Sopenharmony_ci start = tlv + 2; 1329d5ac70f0Sopenharmony_ci size = tlv[SNDRV_CTL_TLVO_LEN]; 1330d5ac70f0Sopenharmony_ci nums = 0; 1331d5ac70f0Sopenharmony_ci for (p = start; size > 0; ) { 1332d5ac70f0Sopenharmony_ci if (!is_chmap_type(p[0])) { 1333d5ac70f0Sopenharmony_ci SYSMSG("Invalid TLV type %d", p[0]); 1334d5ac70f0Sopenharmony_ci return NULL; 1335d5ac70f0Sopenharmony_ci } 1336d5ac70f0Sopenharmony_ci nums++; 1337d5ac70f0Sopenharmony_ci size -= p[1] + 8; 1338d5ac70f0Sopenharmony_ci p += p[1] / 4 + 2; 1339d5ac70f0Sopenharmony_ci } 1340d5ac70f0Sopenharmony_ci } 1341d5ac70f0Sopenharmony_ci map = calloc(nums + 1, sizeof(int *)); 1342d5ac70f0Sopenharmony_ci if (!map) 1343d5ac70f0Sopenharmony_ci return NULL; 1344d5ac70f0Sopenharmony_ci for (i = 0; i < nums; i++) { 1345d5ac70f0Sopenharmony_ci map[i] = malloc(start[1] + 8); 1346d5ac70f0Sopenharmony_ci if (!map[i]) { 1347d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(map); 1348d5ac70f0Sopenharmony_ci return NULL; 1349d5ac70f0Sopenharmony_ci } 1350d5ac70f0Sopenharmony_ci map[i]->type = start[0] - 0x100; 1351d5ac70f0Sopenharmony_ci map[i]->map.channels = start[1] / 4; 1352d5ac70f0Sopenharmony_ci memcpy(map[i]->map.pos, start + 2, start[1]); 1353d5ac70f0Sopenharmony_ci start += start[1] / 4 + 2; 1354d5ac70f0Sopenharmony_ci } 1355d5ac70f0Sopenharmony_ci return map; 1356d5ac70f0Sopenharmony_ci} 1357d5ac70f0Sopenharmony_ci 1358d5ac70f0Sopenharmony_cienum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET }; 1359d5ac70f0Sopenharmony_ci 1360d5ac70f0Sopenharmony_cistatic int chmap_caps(snd_pcm_hw_t *hw, int type) 1361d5ac70f0Sopenharmony_ci{ 1362d5ac70f0Sopenharmony_ci if (hw->chmap_caps & (1 << type)) 1363d5ac70f0Sopenharmony_ci return 1; 1364d5ac70f0Sopenharmony_ci if (hw->chmap_caps & (1 << (type + 8))) 1365d5ac70f0Sopenharmony_ci return 0; 1366d5ac70f0Sopenharmony_ci return 1; 1367d5ac70f0Sopenharmony_ci} 1368d5ac70f0Sopenharmony_ci 1369d5ac70f0Sopenharmony_cistatic void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type) 1370d5ac70f0Sopenharmony_ci{ 1371d5ac70f0Sopenharmony_ci hw->chmap_caps |= (1 << type); 1372d5ac70f0Sopenharmony_ci} 1373d5ac70f0Sopenharmony_ci 1374d5ac70f0Sopenharmony_cistatic void chmap_caps_set_error(snd_pcm_hw_t *hw, int type) 1375d5ac70f0Sopenharmony_ci{ 1376d5ac70f0Sopenharmony_ci hw->chmap_caps |= (1 << (type + 8)); 1377d5ac70f0Sopenharmony_ci} 1378d5ac70f0Sopenharmony_ci 1379d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm) 1380d5ac70f0Sopenharmony_ci{ 1381d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1382d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **map; 1383d5ac70f0Sopenharmony_ci 1384d5ac70f0Sopenharmony_ci if (hw->chmap_override) 1385d5ac70f0Sopenharmony_ci return _snd_pcm_copy_chmap_query(hw->chmap_override); 1386d5ac70f0Sopenharmony_ci 1387d5ac70f0Sopenharmony_ci if (!chmap_caps(hw, CHMAP_CTL_QUERY)) 1388d5ac70f0Sopenharmony_ci return NULL; 1389d5ac70f0Sopenharmony_ci 1390d5ac70f0Sopenharmony_ci map = snd_pcm_query_chmaps_from_hw(hw->card, hw->device, 1391d5ac70f0Sopenharmony_ci hw->subdevice, pcm->stream); 1392d5ac70f0Sopenharmony_ci if (map) 1393d5ac70f0Sopenharmony_ci chmap_caps_set_ok(hw, CHMAP_CTL_QUERY); 1394d5ac70f0Sopenharmony_ci else 1395d5ac70f0Sopenharmony_ci chmap_caps_set_error(hw, CHMAP_CTL_QUERY); 1396d5ac70f0Sopenharmony_ci return map; 1397d5ac70f0Sopenharmony_ci} 1398d5ac70f0Sopenharmony_ci 1399d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm) 1400d5ac70f0Sopenharmony_ci{ 1401d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1402d5ac70f0Sopenharmony_ci snd_pcm_chmap_t *map; 1403d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 1404d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t id = {0}; 1405d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t val = {0}; 1406d5ac70f0Sopenharmony_ci unsigned int i; 1407d5ac70f0Sopenharmony_ci int ret; 1408d5ac70f0Sopenharmony_ci 1409d5ac70f0Sopenharmony_ci if (hw->chmap_override) 1410d5ac70f0Sopenharmony_ci return _snd_pcm_choose_fixed_chmap(pcm, hw->chmap_override); 1411d5ac70f0Sopenharmony_ci 1412d5ac70f0Sopenharmony_ci if (!chmap_caps(hw, CHMAP_CTL_GET)) 1413d5ac70f0Sopenharmony_ci return NULL; 1414d5ac70f0Sopenharmony_ci 1415d5ac70f0Sopenharmony_ci switch (FAST_PCM_STATE(hw)) { 1416d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 1417d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 1418d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 1419d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 1420d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PAUSED: 1421d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 1422d5ac70f0Sopenharmony_ci break; 1423d5ac70f0Sopenharmony_ci default: 1424d5ac70f0Sopenharmony_ci SYSMSG("Invalid PCM state for chmap_get: %s", 1425d5ac70f0Sopenharmony_ci snd_pcm_state_name(FAST_PCM_STATE(hw))); 1426d5ac70f0Sopenharmony_ci return NULL; 1427d5ac70f0Sopenharmony_ci } 1428d5ac70f0Sopenharmony_ci map = malloc(pcm->channels * sizeof(map->pos[0]) + sizeof(*map)); 1429d5ac70f0Sopenharmony_ci if (!map) 1430d5ac70f0Sopenharmony_ci return NULL; 1431d5ac70f0Sopenharmony_ci map->channels = pcm->channels; 1432d5ac70f0Sopenharmony_ci ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); 1433d5ac70f0Sopenharmony_ci if (ret < 0) { 1434d5ac70f0Sopenharmony_ci free(map); 1435d5ac70f0Sopenharmony_ci SYSMSG("Cannot open the associated CTL"); 1436d5ac70f0Sopenharmony_ci chmap_caps_set_error(hw, CHMAP_CTL_GET); 1437d5ac70f0Sopenharmony_ci return NULL; 1438d5ac70f0Sopenharmony_ci } 1439d5ac70f0Sopenharmony_ci fill_chmap_ctl_id(pcm, &id); 1440d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_id(&val, &id); 1441d5ac70f0Sopenharmony_ci ret = snd_ctl_elem_read(ctl, &val); 1442d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 1443d5ac70f0Sopenharmony_ci if (ret < 0) { 1444d5ac70f0Sopenharmony_ci free(map); 1445d5ac70f0Sopenharmony_ci SYSMSG("Cannot read Channel Map ctl"); 1446d5ac70f0Sopenharmony_ci chmap_caps_set_error(hw, CHMAP_CTL_GET); 1447d5ac70f0Sopenharmony_ci return NULL; 1448d5ac70f0Sopenharmony_ci } 1449d5ac70f0Sopenharmony_ci for (i = 0; i < pcm->channels; i++) 1450d5ac70f0Sopenharmony_ci map->pos[i] = snd_ctl_elem_value_get_integer(&val, i); 1451d5ac70f0Sopenharmony_ci chmap_caps_set_ok(hw, CHMAP_CTL_GET); 1452d5ac70f0Sopenharmony_ci return map; 1453d5ac70f0Sopenharmony_ci} 1454d5ac70f0Sopenharmony_ci 1455d5ac70f0Sopenharmony_cistatic int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) 1456d5ac70f0Sopenharmony_ci{ 1457d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1458d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 1459d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t id = {0}; 1460d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t val = {0}; 1461d5ac70f0Sopenharmony_ci unsigned int i; 1462d5ac70f0Sopenharmony_ci int ret; 1463d5ac70f0Sopenharmony_ci 1464d5ac70f0Sopenharmony_ci if (hw->chmap_override) 1465d5ac70f0Sopenharmony_ci return -ENXIO; 1466d5ac70f0Sopenharmony_ci 1467d5ac70f0Sopenharmony_ci if (!chmap_caps(hw, CHMAP_CTL_SET)) 1468d5ac70f0Sopenharmony_ci return -ENXIO; 1469d5ac70f0Sopenharmony_ci 1470d5ac70f0Sopenharmony_ci if (map->channels > 128) { 1471d5ac70f0Sopenharmony_ci SYSMSG("Invalid number of channels %d", map->channels); 1472d5ac70f0Sopenharmony_ci return -EINVAL; 1473d5ac70f0Sopenharmony_ci } 1474d5ac70f0Sopenharmony_ci if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) { 1475d5ac70f0Sopenharmony_ci SYSMSG("Invalid PCM state for chmap_set: %s", 1476d5ac70f0Sopenharmony_ci snd_pcm_state_name(FAST_PCM_STATE(hw))); 1477d5ac70f0Sopenharmony_ci return -EBADFD; 1478d5ac70f0Sopenharmony_ci } 1479d5ac70f0Sopenharmony_ci ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); 1480d5ac70f0Sopenharmony_ci if (ret < 0) { 1481d5ac70f0Sopenharmony_ci SYSMSG("Cannot open the associated CTL"); 1482d5ac70f0Sopenharmony_ci chmap_caps_set_error(hw, CHMAP_CTL_SET); 1483d5ac70f0Sopenharmony_ci return ret; 1484d5ac70f0Sopenharmony_ci } 1485d5ac70f0Sopenharmony_ci 1486d5ac70f0Sopenharmony_ci fill_chmap_ctl_id(pcm, &id); 1487d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_id(&val, &id); 1488d5ac70f0Sopenharmony_ci for (i = 0; i < map->channels; i++) 1489d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&val, i, map->pos[i]); 1490d5ac70f0Sopenharmony_ci ret = snd_ctl_elem_write(ctl, &val); 1491d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 1492d5ac70f0Sopenharmony_ci if (ret >= 0) 1493d5ac70f0Sopenharmony_ci chmap_caps_set_ok(hw, CHMAP_CTL_SET); 1494d5ac70f0Sopenharmony_ci else if (ret == -ENOENT || ret == -EPERM || ret == -ENXIO) { 1495d5ac70f0Sopenharmony_ci chmap_caps_set_error(hw, CHMAP_CTL_SET); 1496d5ac70f0Sopenharmony_ci ret = -ENXIO; 1497d5ac70f0Sopenharmony_ci } 1498d5ac70f0Sopenharmony_ci if (ret < 0) 1499d5ac70f0Sopenharmony_ci SYSMSG("Cannot write Channel Map ctl"); 1500d5ac70f0Sopenharmony_ci return ret; 1501d5ac70f0Sopenharmony_ci} 1502d5ac70f0Sopenharmony_ci 1503d5ac70f0Sopenharmony_cistatic void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out) 1504d5ac70f0Sopenharmony_ci{ 1505d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = pcm->private_data; 1506d5ac70f0Sopenharmony_ci char *name; 1507d5ac70f0Sopenharmony_ci int err = snd_card_get_name(hw->card, &name); 1508d5ac70f0Sopenharmony_ci if (err < 0) { 1509d5ac70f0Sopenharmony_ci SNDERR("cannot get card name"); 1510d5ac70f0Sopenharmony_ci return; 1511d5ac70f0Sopenharmony_ci } 1512d5ac70f0Sopenharmony_ci snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n", 1513d5ac70f0Sopenharmony_ci hw->card, name, hw->device, hw->subdevice); 1514d5ac70f0Sopenharmony_ci free(name); 1515d5ac70f0Sopenharmony_ci if (pcm->setup) { 1516d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 1517d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 1518d5ac70f0Sopenharmony_ci snd_output_printf(out, " appl_ptr : %li\n", hw->mmap_control->appl_ptr); 1519d5ac70f0Sopenharmony_ci snd_output_printf(out, " hw_ptr : %li\n", hw->mmap_status->hw_ptr); 1520d5ac70f0Sopenharmony_ci } 1521d5ac70f0Sopenharmony_ci} 1522d5ac70f0Sopenharmony_ci 1523d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_hw_ops = { 1524d5ac70f0Sopenharmony_ci .close = snd_pcm_hw_close, 1525d5ac70f0Sopenharmony_ci .info = snd_pcm_hw_info, 1526d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_hw_hw_refine, 1527d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_hw_hw_params, 1528d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_hw_hw_free, 1529d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_hw_sw_params, 1530d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_hw_channel_info, 1531d5ac70f0Sopenharmony_ci .dump = snd_pcm_hw_dump, 1532d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_hw_nonblock, 1533d5ac70f0Sopenharmony_ci .async = snd_pcm_hw_async, 1534d5ac70f0Sopenharmony_ci .mmap = snd_pcm_hw_mmap, 1535d5ac70f0Sopenharmony_ci .munmap = snd_pcm_hw_munmap, 1536d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_hw_query_chmaps, 1537d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_hw_get_chmap, 1538d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_hw_set_chmap, 1539d5ac70f0Sopenharmony_ci}; 1540d5ac70f0Sopenharmony_ci 1541d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { 1542d5ac70f0Sopenharmony_ci .status = snd_pcm_hw_status, 1543d5ac70f0Sopenharmony_ci .state = snd_pcm_hw_state, 1544d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_hw_hwsync, 1545d5ac70f0Sopenharmony_ci .delay = snd_pcm_hw_delay, 1546d5ac70f0Sopenharmony_ci .prepare = snd_pcm_hw_prepare, 1547d5ac70f0Sopenharmony_ci .reset = snd_pcm_hw_reset, 1548d5ac70f0Sopenharmony_ci .start = snd_pcm_hw_start, 1549d5ac70f0Sopenharmony_ci .drop = snd_pcm_hw_drop, 1550d5ac70f0Sopenharmony_ci .drain = snd_pcm_hw_drain, 1551d5ac70f0Sopenharmony_ci .pause = snd_pcm_hw_pause, 1552d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_hw_rewindable, 1553d5ac70f0Sopenharmony_ci .rewind = snd_pcm_hw_rewind, 1554d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_hw_forwardable, 1555d5ac70f0Sopenharmony_ci .forward = snd_pcm_hw_forward, 1556d5ac70f0Sopenharmony_ci .resume = snd_pcm_hw_resume, 1557d5ac70f0Sopenharmony_ci .link = snd_pcm_hw_link, 1558d5ac70f0Sopenharmony_ci .link_slaves = snd_pcm_hw_link_slaves, 1559d5ac70f0Sopenharmony_ci .unlink = snd_pcm_hw_unlink, 1560d5ac70f0Sopenharmony_ci .writei = snd_pcm_hw_writei, 1561d5ac70f0Sopenharmony_ci .writen = snd_pcm_hw_writen, 1562d5ac70f0Sopenharmony_ci .readi = snd_pcm_hw_readi, 1563d5ac70f0Sopenharmony_ci .readn = snd_pcm_hw_readn, 1564d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_hw_avail_update, 1565d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_hw_mmap_commit, 1566d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_hw_htimestamp, 1567d5ac70f0Sopenharmony_ci .poll_descriptors = NULL, 1568d5ac70f0Sopenharmony_ci .poll_descriptors_count = NULL, 1569d5ac70f0Sopenharmony_ci .poll_revents = NULL, 1570d5ac70f0Sopenharmony_ci}; 1571d5ac70f0Sopenharmony_ci 1572d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = { 1573d5ac70f0Sopenharmony_ci .status = snd_pcm_hw_status, 1574d5ac70f0Sopenharmony_ci .state = snd_pcm_hw_state, 1575d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_hw_hwsync, 1576d5ac70f0Sopenharmony_ci .delay = snd_pcm_hw_delay, 1577d5ac70f0Sopenharmony_ci .prepare = snd_pcm_hw_prepare, 1578d5ac70f0Sopenharmony_ci .reset = snd_pcm_hw_reset, 1579d5ac70f0Sopenharmony_ci .start = snd_pcm_hw_start, 1580d5ac70f0Sopenharmony_ci .drop = snd_pcm_hw_drop, 1581d5ac70f0Sopenharmony_ci .drain = snd_pcm_hw_drain, 1582d5ac70f0Sopenharmony_ci .pause = snd_pcm_hw_pause, 1583d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_hw_rewindable, 1584d5ac70f0Sopenharmony_ci .rewind = snd_pcm_hw_rewind, 1585d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_hw_forwardable, 1586d5ac70f0Sopenharmony_ci .forward = snd_pcm_hw_forward, 1587d5ac70f0Sopenharmony_ci .resume = snd_pcm_hw_resume, 1588d5ac70f0Sopenharmony_ci .link = snd_pcm_hw_link, 1589d5ac70f0Sopenharmony_ci .link_slaves = snd_pcm_hw_link_slaves, 1590d5ac70f0Sopenharmony_ci .unlink = snd_pcm_hw_unlink, 1591d5ac70f0Sopenharmony_ci .writei = snd_pcm_hw_writei, 1592d5ac70f0Sopenharmony_ci .writen = snd_pcm_hw_writen, 1593d5ac70f0Sopenharmony_ci .readi = snd_pcm_hw_readi, 1594d5ac70f0Sopenharmony_ci .readn = snd_pcm_hw_readn, 1595d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_hw_avail_update, 1596d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_hw_mmap_commit, 1597d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_hw_htimestamp, 1598d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_hw_poll_descriptors, 1599d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_pcm_hw_poll_descriptors_count, 1600d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_hw_poll_revents, 1601d5ac70f0Sopenharmony_ci}; 1602d5ac70f0Sopenharmony_ci 1603d5ac70f0Sopenharmony_ci/** 1604d5ac70f0Sopenharmony_ci * \brief Creates a new hw PCM 1605d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1606d5ac70f0Sopenharmony_ci * \param name Name of PCM 1607d5ac70f0Sopenharmony_ci * \param fd File descriptor 1608d5ac70f0Sopenharmony_ci * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl 1609d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1610d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1611d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1612d5ac70f0Sopenharmony_ci * changed in future. 1613d5ac70f0Sopenharmony_ci */ 1614d5ac70f0Sopenharmony_ciint snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, 1615d5ac70f0Sopenharmony_ci int sync_ptr_ioctl) 1616d5ac70f0Sopenharmony_ci{ 1617d5ac70f0Sopenharmony_ci int ver, mode; 1618d5ac70f0Sopenharmony_ci snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; 1619d5ac70f0Sopenharmony_ci long fmode; 1620d5ac70f0Sopenharmony_ci snd_pcm_t *pcm = NULL; 1621d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw = NULL; 1622d5ac70f0Sopenharmony_ci snd_pcm_info_t info; 1623d5ac70f0Sopenharmony_ci int ret; 1624d5ac70f0Sopenharmony_ci 1625d5ac70f0Sopenharmony_ci assert(pcmp); 1626d5ac70f0Sopenharmony_ci 1627d5ac70f0Sopenharmony_ci memset(&info, 0, sizeof(info)); 1628d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) { 1629d5ac70f0Sopenharmony_ci ret = -errno; 1630d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); 1631d5ac70f0Sopenharmony_ci close(fd); 1632d5ac70f0Sopenharmony_ci return ret; 1633d5ac70f0Sopenharmony_ci 1634d5ac70f0Sopenharmony_ci } 1635d5ac70f0Sopenharmony_ci 1636d5ac70f0Sopenharmony_ci if ((fmode = fcntl(fd, F_GETFL)) < 0) { 1637d5ac70f0Sopenharmony_ci ret = -errno; 1638d5ac70f0Sopenharmony_ci close(fd); 1639d5ac70f0Sopenharmony_ci return ret; 1640d5ac70f0Sopenharmony_ci } 1641d5ac70f0Sopenharmony_ci mode = 0; 1642d5ac70f0Sopenharmony_ci if (fmode & O_NONBLOCK) 1643d5ac70f0Sopenharmony_ci mode |= SND_PCM_NONBLOCK; 1644d5ac70f0Sopenharmony_ci if (fmode & O_ASYNC) 1645d5ac70f0Sopenharmony_ci mode |= SND_PCM_ASYNC; 1646d5ac70f0Sopenharmony_ci if (fmode & O_APPEND) 1647d5ac70f0Sopenharmony_ci mode |= SND_PCM_APPEND; 1648d5ac70f0Sopenharmony_ci 1649d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) { 1650d5ac70f0Sopenharmony_ci ret = -errno; 1651d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret); 1652d5ac70f0Sopenharmony_ci close(fd); 1653d5ac70f0Sopenharmony_ci return ret; 1654d5ac70f0Sopenharmony_ci } 1655d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX)) 1656d5ac70f0Sopenharmony_ci return -SND_ERROR_INCOMPATIBLE_VERSION; 1657d5ac70f0Sopenharmony_ci 1658d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) { 1659d5ac70f0Sopenharmony_ci /* inform the protocol version we're supporting */ 1660d5ac70f0Sopenharmony_ci unsigned int user_ver = SNDRV_PCM_VERSION; 1661d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) { 1662d5ac70f0Sopenharmony_ci ret = -errno; 1663d5ac70f0Sopenharmony_ci SNDMSG("USER_PVERSION failed"); 1664d5ac70f0Sopenharmony_ci return ret; 1665d5ac70f0Sopenharmony_ci } 1666d5ac70f0Sopenharmony_ci } 1667d5ac70f0Sopenharmony_ci 1668d5ac70f0Sopenharmony_ci#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 1669d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) { 1670d5ac70f0Sopenharmony_ci struct timespec timespec; 1671d5ac70f0Sopenharmony_ci if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) { 1672d5ac70f0Sopenharmony_ci int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; 1673d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) { 1674d5ac70f0Sopenharmony_ci ret = -errno; 1675d5ac70f0Sopenharmony_ci SNDMSG("TTSTAMP failed"); 1676d5ac70f0Sopenharmony_ci return ret; 1677d5ac70f0Sopenharmony_ci } 1678d5ac70f0Sopenharmony_ci tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; 1679d5ac70f0Sopenharmony_ci } 1680d5ac70f0Sopenharmony_ci } else 1681d5ac70f0Sopenharmony_ci#endif 1682d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) { 1683d5ac70f0Sopenharmony_ci int on = 1; 1684d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) { 1685d5ac70f0Sopenharmony_ci ret = -errno; 1686d5ac70f0Sopenharmony_ci SNDMSG("TSTAMP failed"); 1687d5ac70f0Sopenharmony_ci return ret; 1688d5ac70f0Sopenharmony_ci } 1689d5ac70f0Sopenharmony_ci } 1690d5ac70f0Sopenharmony_ci 1691d5ac70f0Sopenharmony_ci hw = calloc(1, sizeof(snd_pcm_hw_t)); 1692d5ac70f0Sopenharmony_ci if (!hw) { 1693d5ac70f0Sopenharmony_ci close(fd); 1694d5ac70f0Sopenharmony_ci return -ENOMEM; 1695d5ac70f0Sopenharmony_ci } 1696d5ac70f0Sopenharmony_ci 1697d5ac70f0Sopenharmony_ci hw->version = ver; 1698d5ac70f0Sopenharmony_ci hw->card = info.card; 1699d5ac70f0Sopenharmony_ci hw->device = info.device; 1700d5ac70f0Sopenharmony_ci hw->subdevice = info.subdevice; 1701d5ac70f0Sopenharmony_ci hw->fd = fd; 1702d5ac70f0Sopenharmony_ci /* no restriction */ 1703d5ac70f0Sopenharmony_ci hw->format = SND_PCM_FORMAT_UNKNOWN; 1704d5ac70f0Sopenharmony_ci hw->rates.min = hw->rates.max = 0; 1705d5ac70f0Sopenharmony_ci hw->channels = 0; 1706d5ac70f0Sopenharmony_ci 1707d5ac70f0Sopenharmony_ci ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode); 1708d5ac70f0Sopenharmony_ci if (ret < 0) { 1709d5ac70f0Sopenharmony_ci free(hw); 1710d5ac70f0Sopenharmony_ci close(fd); 1711d5ac70f0Sopenharmony_ci return ret; 1712d5ac70f0Sopenharmony_ci } 1713d5ac70f0Sopenharmony_ci 1714d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_hw_ops; 1715d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_hw_fast_ops; 1716d5ac70f0Sopenharmony_ci pcm->private_data = hw; 1717d5ac70f0Sopenharmony_ci pcm->poll_fd = fd; 1718d5ac70f0Sopenharmony_ci pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; 1719d5ac70f0Sopenharmony_ci pcm->tstamp_type = tstamp_type; 1720d5ac70f0Sopenharmony_ci#ifdef THREAD_SAFE_API 1721d5ac70f0Sopenharmony_ci pcm->need_lock = 0; /* hw plugin is thread-safe */ 1722d5ac70f0Sopenharmony_ci#endif 1723d5ac70f0Sopenharmony_ci pcm->own_state_check = 1; /* skip the common state check */ 1724d5ac70f0Sopenharmony_ci 1725d5ac70f0Sopenharmony_ci ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl); 1726d5ac70f0Sopenharmony_ci if (ret < 0) { 1727d5ac70f0Sopenharmony_ci snd_pcm_close(pcm); 1728d5ac70f0Sopenharmony_ci return ret; 1729d5ac70f0Sopenharmony_ci } 1730d5ac70f0Sopenharmony_ci 1731d5ac70f0Sopenharmony_ci *pcmp = pcm; 1732d5ac70f0Sopenharmony_ci return 0; 1733d5ac70f0Sopenharmony_ci} 1734d5ac70f0Sopenharmony_ci 1735d5ac70f0Sopenharmony_ci/** 1736d5ac70f0Sopenharmony_ci * \brief Creates a new hw PCM 1737d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1738d5ac70f0Sopenharmony_ci * \param name Name of PCM 1739d5ac70f0Sopenharmony_ci * \param card Number of card 1740d5ac70f0Sopenharmony_ci * \param device Number of device 1741d5ac70f0Sopenharmony_ci * \param subdevice Number of subdevice 1742d5ac70f0Sopenharmony_ci * \param stream PCM Stream 1743d5ac70f0Sopenharmony_ci * \param mode PCM Mode 1744d5ac70f0Sopenharmony_ci * \param mmap_emulation Obsoleted parameter 1745d5ac70f0Sopenharmony_ci * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures 1746d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1747d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1748d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1749d5ac70f0Sopenharmony_ci * changed in future. 1750d5ac70f0Sopenharmony_ci */ 1751d5ac70f0Sopenharmony_ciint snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, 1752d5ac70f0Sopenharmony_ci int card, int device, int subdevice, 1753d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode, 1754d5ac70f0Sopenharmony_ci int mmap_emulation ATTRIBUTE_UNUSED, 1755d5ac70f0Sopenharmony_ci int sync_ptr_ioctl) 1756d5ac70f0Sopenharmony_ci{ 1757d5ac70f0Sopenharmony_ci char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20]; 1758d5ac70f0Sopenharmony_ci const char *filefmt; 1759d5ac70f0Sopenharmony_ci int ret = 0, fd = -1; 1760d5ac70f0Sopenharmony_ci int attempt = 0; 1761d5ac70f0Sopenharmony_ci snd_pcm_info_t info; 1762d5ac70f0Sopenharmony_ci int fmode; 1763d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 1764d5ac70f0Sopenharmony_ci 1765d5ac70f0Sopenharmony_ci assert(pcmp); 1766d5ac70f0Sopenharmony_ci 1767d5ac70f0Sopenharmony_ci if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) 1768d5ac70f0Sopenharmony_ci return ret; 1769d5ac70f0Sopenharmony_ci 1770d5ac70f0Sopenharmony_ci switch (stream) { 1771d5ac70f0Sopenharmony_ci case SND_PCM_STREAM_PLAYBACK: 1772d5ac70f0Sopenharmony_ci filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK; 1773d5ac70f0Sopenharmony_ci break; 1774d5ac70f0Sopenharmony_ci case SND_PCM_STREAM_CAPTURE: 1775d5ac70f0Sopenharmony_ci filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE; 1776d5ac70f0Sopenharmony_ci break; 1777d5ac70f0Sopenharmony_ci default: 1778d5ac70f0Sopenharmony_ci SNDERR("invalid stream %d", stream); 1779d5ac70f0Sopenharmony_ci return -EINVAL; 1780d5ac70f0Sopenharmony_ci } 1781d5ac70f0Sopenharmony_ci sprintf(filename, filefmt, card, device); 1782d5ac70f0Sopenharmony_ci 1783d5ac70f0Sopenharmony_ci __again: 1784d5ac70f0Sopenharmony_ci if (attempt++ > 3) { 1785d5ac70f0Sopenharmony_ci ret = -EBUSY; 1786d5ac70f0Sopenharmony_ci goto _err; 1787d5ac70f0Sopenharmony_ci } 1788d5ac70f0Sopenharmony_ci ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice); 1789d5ac70f0Sopenharmony_ci if (ret < 0) 1790d5ac70f0Sopenharmony_ci goto _err; 1791d5ac70f0Sopenharmony_ci fmode = O_RDWR; 1792d5ac70f0Sopenharmony_ci if (mode & SND_PCM_NONBLOCK) 1793d5ac70f0Sopenharmony_ci fmode |= O_NONBLOCK; 1794d5ac70f0Sopenharmony_ci if (mode & SND_PCM_ASYNC) 1795d5ac70f0Sopenharmony_ci fmode |= O_ASYNC; 1796d5ac70f0Sopenharmony_ci if (mode & SND_PCM_APPEND) 1797d5ac70f0Sopenharmony_ci fmode |= O_APPEND; 1798d5ac70f0Sopenharmony_ci fd = snd_open_device(filename, fmode); 1799d5ac70f0Sopenharmony_ci if (fd < 0) { 1800d5ac70f0Sopenharmony_ci ret = -errno; 1801d5ac70f0Sopenharmony_ci SYSMSG("open '%s' failed (%i)", filename, ret); 1802d5ac70f0Sopenharmony_ci goto _err; 1803d5ac70f0Sopenharmony_ci } 1804d5ac70f0Sopenharmony_ci if (subdevice >= 0) { 1805d5ac70f0Sopenharmony_ci memset(&info, 0, sizeof(info)); 1806d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) { 1807d5ac70f0Sopenharmony_ci ret = -errno; 1808d5ac70f0Sopenharmony_ci SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); 1809d5ac70f0Sopenharmony_ci goto _err; 1810d5ac70f0Sopenharmony_ci } 1811d5ac70f0Sopenharmony_ci if (info.subdevice != (unsigned int) subdevice) { 1812d5ac70f0Sopenharmony_ci close(fd); 1813d5ac70f0Sopenharmony_ci fd = -1; 1814d5ac70f0Sopenharmony_ci goto __again; 1815d5ac70f0Sopenharmony_ci } 1816d5ac70f0Sopenharmony_ci } 1817d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 1818d5ac70f0Sopenharmony_ci return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl); 1819d5ac70f0Sopenharmony_ci _err: 1820d5ac70f0Sopenharmony_ci if (fd >= 0) 1821d5ac70f0Sopenharmony_ci close(fd); 1822d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 1823d5ac70f0Sopenharmony_ci return ret; 1824d5ac70f0Sopenharmony_ci} 1825d5ac70f0Sopenharmony_ci 1826d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 1827d5ac70f0Sopenharmony_ci 1828d5ac70f0Sopenharmony_ci\section pcm_plugins_hw Plugin: hw 1829d5ac70f0Sopenharmony_ci 1830d5ac70f0Sopenharmony_ciThis plugin communicates directly with the ALSA kernel driver. It is a raw 1831d5ac70f0Sopenharmony_cicommunication without any conversions. The emulation of mmap access can be 1832d5ac70f0Sopenharmony_cioptionally enabled, but expect worse latency in the case. 1833d5ac70f0Sopenharmony_ci 1834d5ac70f0Sopenharmony_ciThe nonblock option specifies whether the device is opened in a non-blocking 1835d5ac70f0Sopenharmony_cimanner. Note that the blocking behavior for read/write access won't be 1836d5ac70f0Sopenharmony_cichanged by this option. This influences only on the blocking behavior at 1837d5ac70f0Sopenharmony_ciopening the device. If you would like to keep the compatibility with the 1838d5ac70f0Sopenharmony_ciolder ALSA stuff, turn this option off. 1839d5ac70f0Sopenharmony_ci 1840d5ac70f0Sopenharmony_ci\code 1841d5ac70f0Sopenharmony_cipcm.name { 1842d5ac70f0Sopenharmony_ci type hw # Kernel PCM 1843d5ac70f0Sopenharmony_ci card INT/STR # Card name (string) or number (integer) 1844d5ac70f0Sopenharmony_ci [device INT] # Device number (default 0) 1845d5ac70f0Sopenharmony_ci [subdevice INT] # Subdevice number (default -1: first available) 1846d5ac70f0Sopenharmony_ci [sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures 1847d5ac70f0Sopenharmony_ci [nonblock BOOL] # Force non-blocking open mode 1848d5ac70f0Sopenharmony_ci [format STR] # Restrict only to the given format 1849d5ac70f0Sopenharmony_ci [channels INT] # Restrict only to the given channels 1850d5ac70f0Sopenharmony_ci [rate INT] # Restrict only to the given rate 1851d5ac70f0Sopenharmony_ci or [rate [INT INT]] # Restrict only to the given rate range (min max) 1852d5ac70f0Sopenharmony_ci [chmap MAP] # Override channel maps; MAP is a string array 1853d5ac70f0Sopenharmony_ci [drain_silence INT] # Add silence in drain (-1 = auto /default/, 0 = off, > 0 milliseconds) 1854d5ac70f0Sopenharmony_ci} 1855d5ac70f0Sopenharmony_ci\endcode 1856d5ac70f0Sopenharmony_ci 1857d5ac70f0Sopenharmony_ci\subsection pcm_plugins_hw_funcref Function reference 1858d5ac70f0Sopenharmony_ci 1859d5ac70f0Sopenharmony_ci<UL> 1860d5ac70f0Sopenharmony_ci <LI>snd_pcm_hw_open() 1861d5ac70f0Sopenharmony_ci <LI>_snd_pcm_hw_open() 1862d5ac70f0Sopenharmony_ci</UL> 1863d5ac70f0Sopenharmony_ci 1864d5ac70f0Sopenharmony_ci*/ 1865d5ac70f0Sopenharmony_ci 1866d5ac70f0Sopenharmony_ci/** 1867d5ac70f0Sopenharmony_ci * \brief Creates a new hw PCM 1868d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1869d5ac70f0Sopenharmony_ci * \param name Name of PCM 1870d5ac70f0Sopenharmony_ci * \param root Root configuration node 1871d5ac70f0Sopenharmony_ci * \param conf Configuration node with hw PCM description 1872d5ac70f0Sopenharmony_ci * \param stream PCM Stream 1873d5ac70f0Sopenharmony_ci * \param mode PCM Mode 1874d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1875d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1876d5ac70f0Sopenharmony_ci * changed in future. 1877d5ac70f0Sopenharmony_ci */ 1878d5ac70f0Sopenharmony_ciint _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, 1879d5ac70f0Sopenharmony_ci snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, 1880d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1881d5ac70f0Sopenharmony_ci{ 1882d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1883d5ac70f0Sopenharmony_ci long card = -1, device = 0, subdevice = -1; 1884d5ac70f0Sopenharmony_ci const char *str; 1885d5ac70f0Sopenharmony_ci int err, sync_ptr_ioctl = 0; 1886d5ac70f0Sopenharmony_ci int min_rate = 0, max_rate = 0, channels = 0, drain_silence = -1; 1887d5ac70f0Sopenharmony_ci snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; 1888d5ac70f0Sopenharmony_ci snd_config_t *n; 1889d5ac70f0Sopenharmony_ci int nonblock = 1; /* non-block per default */ 1890d5ac70f0Sopenharmony_ci snd_pcm_chmap_query_t **chmap = NULL; 1891d5ac70f0Sopenharmony_ci snd_pcm_hw_t *hw; 1892d5ac70f0Sopenharmony_ci 1893d5ac70f0Sopenharmony_ci /* look for defaults.pcm.nonblock definition */ 1894d5ac70f0Sopenharmony_ci if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) { 1895d5ac70f0Sopenharmony_ci err = snd_config_get_bool(n); 1896d5ac70f0Sopenharmony_ci if (err >= 0) 1897d5ac70f0Sopenharmony_ci nonblock = err; 1898d5ac70f0Sopenharmony_ci } 1899d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 1900d5ac70f0Sopenharmony_ci const char *id; 1901d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1902d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1903d5ac70f0Sopenharmony_ci continue; 1904d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 1905d5ac70f0Sopenharmony_ci continue; 1906d5ac70f0Sopenharmony_ci if (strcmp(id, "card") == 0) { 1907d5ac70f0Sopenharmony_ci err = snd_config_get_card(n); 1908d5ac70f0Sopenharmony_ci if (err < 0) 1909d5ac70f0Sopenharmony_ci goto fail; 1910d5ac70f0Sopenharmony_ci card = err; 1911d5ac70f0Sopenharmony_ci continue; 1912d5ac70f0Sopenharmony_ci } 1913d5ac70f0Sopenharmony_ci if (strcmp(id, "device") == 0) { 1914d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &device); 1915d5ac70f0Sopenharmony_ci if (err < 0) { 1916d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1917d5ac70f0Sopenharmony_ci goto fail; 1918d5ac70f0Sopenharmony_ci } 1919d5ac70f0Sopenharmony_ci continue; 1920d5ac70f0Sopenharmony_ci } 1921d5ac70f0Sopenharmony_ci if (strcmp(id, "subdevice") == 0) { 1922d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &subdevice); 1923d5ac70f0Sopenharmony_ci if (err < 0) { 1924d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1925d5ac70f0Sopenharmony_ci goto fail; 1926d5ac70f0Sopenharmony_ci } 1927d5ac70f0Sopenharmony_ci continue; 1928d5ac70f0Sopenharmony_ci } 1929d5ac70f0Sopenharmony_ci if (strcmp(id, "sync_ptr_ioctl") == 0) { 1930d5ac70f0Sopenharmony_ci err = snd_config_get_bool(n); 1931d5ac70f0Sopenharmony_ci if (err < 0) 1932d5ac70f0Sopenharmony_ci continue; 1933d5ac70f0Sopenharmony_ci sync_ptr_ioctl = err; 1934d5ac70f0Sopenharmony_ci continue; 1935d5ac70f0Sopenharmony_ci } 1936d5ac70f0Sopenharmony_ci if (strcmp(id, "nonblock") == 0) { 1937d5ac70f0Sopenharmony_ci err = snd_config_get_bool(n); 1938d5ac70f0Sopenharmony_ci if (err < 0) 1939d5ac70f0Sopenharmony_ci continue; 1940d5ac70f0Sopenharmony_ci nonblock = err; 1941d5ac70f0Sopenharmony_ci continue; 1942d5ac70f0Sopenharmony_ci } 1943d5ac70f0Sopenharmony_ci if (strcmp(id, "rate") == 0) { 1944d5ac70f0Sopenharmony_ci long val; 1945d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND && 1946d5ac70f0Sopenharmony_ci snd_config_is_array(n)) { 1947d5ac70f0Sopenharmony_ci snd_config_t *m; 1948d5ac70f0Sopenharmony_ci err = snd_config_search(n, "0", &m); 1949d5ac70f0Sopenharmony_ci if (err < 0) { 1950d5ac70f0Sopenharmony_ci SNDERR("array expected for rate compound"); 1951d5ac70f0Sopenharmony_ci goto fail; 1952d5ac70f0Sopenharmony_ci } 1953d5ac70f0Sopenharmony_ci err = snd_config_get_integer(m, &val); 1954d5ac70f0Sopenharmony_ci if (err < 0) { 1955d5ac70f0Sopenharmony_ci SNDERR("Invalid type for rate.0"); 1956d5ac70f0Sopenharmony_ci goto fail; 1957d5ac70f0Sopenharmony_ci } 1958d5ac70f0Sopenharmony_ci min_rate = max_rate = val; 1959d5ac70f0Sopenharmony_ci err = snd_config_search(n, "1", &m); 1960d5ac70f0Sopenharmony_ci if (err >= 0) { 1961d5ac70f0Sopenharmony_ci err = snd_config_get_integer(m, &val); 1962d5ac70f0Sopenharmony_ci if (err < 0) { 1963d5ac70f0Sopenharmony_ci SNDERR("Invalid type for rate.0"); 1964d5ac70f0Sopenharmony_ci goto fail; 1965d5ac70f0Sopenharmony_ci } 1966d5ac70f0Sopenharmony_ci max_rate = val; 1967d5ac70f0Sopenharmony_ci } 1968d5ac70f0Sopenharmony_ci } else { 1969d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &val); 1970d5ac70f0Sopenharmony_ci if (err < 0) { 1971d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1972d5ac70f0Sopenharmony_ci goto fail; 1973d5ac70f0Sopenharmony_ci } 1974d5ac70f0Sopenharmony_ci min_rate = max_rate = val; 1975d5ac70f0Sopenharmony_ci } 1976d5ac70f0Sopenharmony_ci continue; 1977d5ac70f0Sopenharmony_ci } 1978d5ac70f0Sopenharmony_ci if (strcmp(id, "min_rate") == 0) { 1979d5ac70f0Sopenharmony_ci long val; 1980d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &val); 1981d5ac70f0Sopenharmony_ci if (err < 0) { 1982d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1983d5ac70f0Sopenharmony_ci goto fail; 1984d5ac70f0Sopenharmony_ci } 1985d5ac70f0Sopenharmony_ci min_rate = val; 1986d5ac70f0Sopenharmony_ci continue; 1987d5ac70f0Sopenharmony_ci } 1988d5ac70f0Sopenharmony_ci if (strcmp(id, "max_rate") == 0) { 1989d5ac70f0Sopenharmony_ci long val; 1990d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &val); 1991d5ac70f0Sopenharmony_ci if (err < 0) { 1992d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1993d5ac70f0Sopenharmony_ci goto fail; 1994d5ac70f0Sopenharmony_ci } 1995d5ac70f0Sopenharmony_ci max_rate = val; 1996d5ac70f0Sopenharmony_ci continue; 1997d5ac70f0Sopenharmony_ci } 1998d5ac70f0Sopenharmony_ci if (strcmp(id, "format") == 0) { 1999d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &str); 2000d5ac70f0Sopenharmony_ci if (err < 0) { 2001d5ac70f0Sopenharmony_ci SNDERR("invalid type for %s", id); 2002d5ac70f0Sopenharmony_ci goto fail; 2003d5ac70f0Sopenharmony_ci } 2004d5ac70f0Sopenharmony_ci format = snd_pcm_format_value(str); 2005d5ac70f0Sopenharmony_ci continue; 2006d5ac70f0Sopenharmony_ci } 2007d5ac70f0Sopenharmony_ci if (strcmp(id, "channels") == 0) { 2008d5ac70f0Sopenharmony_ci long val; 2009d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &val); 2010d5ac70f0Sopenharmony_ci if (err < 0) { 2011d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 2012d5ac70f0Sopenharmony_ci goto fail; 2013d5ac70f0Sopenharmony_ci } 2014d5ac70f0Sopenharmony_ci channels = val; 2015d5ac70f0Sopenharmony_ci continue; 2016d5ac70f0Sopenharmony_ci } 2017d5ac70f0Sopenharmony_ci if (strcmp(id, "chmap") == 0) { 2018d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmap); 2019d5ac70f0Sopenharmony_ci chmap = _snd_pcm_parse_config_chmaps(n); 2020d5ac70f0Sopenharmony_ci if (!chmap) { 2021d5ac70f0Sopenharmony_ci SNDERR("Invalid channel map for %s", id); 2022d5ac70f0Sopenharmony_ci err = -EINVAL; 2023d5ac70f0Sopenharmony_ci goto fail; 2024d5ac70f0Sopenharmony_ci } 2025d5ac70f0Sopenharmony_ci continue; 2026d5ac70f0Sopenharmony_ci } 2027d5ac70f0Sopenharmony_ci if (strcmp(id, "drain_silence") == 0) { 2028d5ac70f0Sopenharmony_ci long val; 2029d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &val); 2030d5ac70f0Sopenharmony_ci if (err < 0) { 2031d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 2032d5ac70f0Sopenharmony_ci goto fail; 2033d5ac70f0Sopenharmony_ci } 2034d5ac70f0Sopenharmony_ci drain_silence = val; 2035d5ac70f0Sopenharmony_ci continue; 2036d5ac70f0Sopenharmony_ci } 2037d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 2038d5ac70f0Sopenharmony_ci err = -EINVAL; 2039d5ac70f0Sopenharmony_ci goto fail; 2040d5ac70f0Sopenharmony_ci } 2041d5ac70f0Sopenharmony_ci if (card < 0) { 2042d5ac70f0Sopenharmony_ci SNDERR("card is not defined"); 2043d5ac70f0Sopenharmony_ci err = -EINVAL; 2044d5ac70f0Sopenharmony_ci goto fail; 2045d5ac70f0Sopenharmony_ci } 2046d5ac70f0Sopenharmony_ci if ((min_rate < 0) || (max_rate < min_rate)) { 2047d5ac70f0Sopenharmony_ci SNDERR("min_rate - max_rate configuration invalid"); 2048d5ac70f0Sopenharmony_ci err = -EINVAL; 2049d5ac70f0Sopenharmony_ci goto fail; 2050d5ac70f0Sopenharmony_ci } 2051d5ac70f0Sopenharmony_ci err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, 2052d5ac70f0Sopenharmony_ci mode | (nonblock ? SND_PCM_NONBLOCK : 0), 2053d5ac70f0Sopenharmony_ci 0, sync_ptr_ioctl); 2054d5ac70f0Sopenharmony_ci if (err < 0) 2055d5ac70f0Sopenharmony_ci goto fail; 2056d5ac70f0Sopenharmony_ci if (nonblock && ! (mode & SND_PCM_NONBLOCK)) { 2057d5ac70f0Sopenharmony_ci /* revert to blocking mode for read/write access */ 2058d5ac70f0Sopenharmony_ci snd_pcm_hw_nonblock(*pcmp, 0); 2059d5ac70f0Sopenharmony_ci (*pcmp)->mode = mode; 2060d5ac70f0Sopenharmony_ci } else 2061d5ac70f0Sopenharmony_ci /* make sure the SND_PCM_NO_xxx flags don't get lost on the 2062d5ac70f0Sopenharmony_ci * way */ 2063d5ac70f0Sopenharmony_ci (*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE| 2064d5ac70f0Sopenharmony_ci SND_PCM_NO_AUTO_CHANNELS| 2065d5ac70f0Sopenharmony_ci SND_PCM_NO_AUTO_FORMAT| 2066d5ac70f0Sopenharmony_ci SND_PCM_NO_SOFTVOL); 2067d5ac70f0Sopenharmony_ci 2068d5ac70f0Sopenharmony_ci hw = (*pcmp)->private_data; 2069d5ac70f0Sopenharmony_ci if (format != SND_PCM_FORMAT_UNKNOWN) 2070d5ac70f0Sopenharmony_ci hw->format = format; 2071d5ac70f0Sopenharmony_ci if (channels > 0) 2072d5ac70f0Sopenharmony_ci hw->channels = channels; 2073d5ac70f0Sopenharmony_ci if (min_rate > 0) { 2074d5ac70f0Sopenharmony_ci hw->rates.min = min_rate; 2075d5ac70f0Sopenharmony_ci hw->rates.max = max_rate; 2076d5ac70f0Sopenharmony_ci } 2077d5ac70f0Sopenharmony_ci if (chmap) 2078d5ac70f0Sopenharmony_ci hw->chmap_override = chmap; 2079d5ac70f0Sopenharmony_ci hw->drain_silence = drain_silence; 2080d5ac70f0Sopenharmony_ci 2081d5ac70f0Sopenharmony_ci return 0; 2082d5ac70f0Sopenharmony_ci 2083d5ac70f0Sopenharmony_cifail: 2084d5ac70f0Sopenharmony_ci snd_pcm_free_chmaps(chmap); 2085d5ac70f0Sopenharmony_ci return err; 2086d5ac70f0Sopenharmony_ci} 2087d5ac70f0Sopenharmony_ci 2088d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 2089d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION); 2090d5ac70f0Sopenharmony_ci#endif 2091d5ac70f0Sopenharmony_ci 2092d5ac70f0Sopenharmony_ci/* 2093d5ac70f0Sopenharmony_ci * To be removed helpers, but keep binary compatibility at the time 2094d5ac70f0Sopenharmony_ci */ 2095d5ac70f0Sopenharmony_ci 2096d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 2097d5ac70f0Sopenharmony_ci#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) 2098d5ac70f0Sopenharmony_ci#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) 2099d5ac70f0Sopenharmony_ci#endif 2100d5ac70f0Sopenharmony_ci 2101d5ac70f0Sopenharmony_cistatic void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, 2102d5ac70f0Sopenharmony_ci struct sndrv_pcm_hw_params_old *oparams) 2103d5ac70f0Sopenharmony_ci{ 2104d5ac70f0Sopenharmony_ci unsigned int i; 2105d5ac70f0Sopenharmony_ci 2106d5ac70f0Sopenharmony_ci memset(params, 0, sizeof(*params)); 2107d5ac70f0Sopenharmony_ci params->flags = oparams->flags; 2108d5ac70f0Sopenharmony_ci for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) 2109d5ac70f0Sopenharmony_ci params->masks[i].bits[0] = oparams->masks[i]; 2110d5ac70f0Sopenharmony_ci memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); 2111d5ac70f0Sopenharmony_ci params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); 2112d5ac70f0Sopenharmony_ci params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); 2113d5ac70f0Sopenharmony_ci params->info = oparams->info; 2114d5ac70f0Sopenharmony_ci params->msbits = oparams->msbits; 2115d5ac70f0Sopenharmony_ci params->rate_num = oparams->rate_num; 2116d5ac70f0Sopenharmony_ci params->rate_den = oparams->rate_den; 2117d5ac70f0Sopenharmony_ci params->fifo_size = oparams->fifo_size; 2118d5ac70f0Sopenharmony_ci} 2119d5ac70f0Sopenharmony_ci 2120d5ac70f0Sopenharmony_cistatic void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, 2121d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 2122d5ac70f0Sopenharmony_ci unsigned int *cmask) 2123d5ac70f0Sopenharmony_ci{ 2124d5ac70f0Sopenharmony_ci unsigned int i, j; 2125d5ac70f0Sopenharmony_ci 2126d5ac70f0Sopenharmony_ci memset(oparams, 0, sizeof(*oparams)); 2127d5ac70f0Sopenharmony_ci oparams->flags = params->flags; 2128d5ac70f0Sopenharmony_ci for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) { 2129d5ac70f0Sopenharmony_ci oparams->masks[i] = params->masks[i].bits[0]; 2130d5ac70f0Sopenharmony_ci for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++) 2131d5ac70f0Sopenharmony_ci if (params->masks[i].bits[j]) { 2132d5ac70f0Sopenharmony_ci *cmask |= 1 << i; 2133d5ac70f0Sopenharmony_ci break; 2134d5ac70f0Sopenharmony_ci } 2135d5ac70f0Sopenharmony_ci } 2136d5ac70f0Sopenharmony_ci memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); 2137d5ac70f0Sopenharmony_ci oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); 2138d5ac70f0Sopenharmony_ci oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); 2139d5ac70f0Sopenharmony_ci oparams->info = params->info; 2140d5ac70f0Sopenharmony_ci oparams->msbits = params->msbits; 2141d5ac70f0Sopenharmony_ci oparams->rate_num = params->rate_num; 2142d5ac70f0Sopenharmony_ci oparams->rate_den = params->rate_den; 2143d5ac70f0Sopenharmony_ci oparams->fifo_size = params->fifo_size; 2144d5ac70f0Sopenharmony_ci} 2145d5ac70f0Sopenharmony_ci 2146d5ac70f0Sopenharmony_cistatic int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params) 2147d5ac70f0Sopenharmony_ci{ 2148d5ac70f0Sopenharmony_ci struct sndrv_pcm_hw_params_old oparams; 2149d5ac70f0Sopenharmony_ci unsigned int cmask = 0; 2150d5ac70f0Sopenharmony_ci int res; 2151d5ac70f0Sopenharmony_ci 2152d5ac70f0Sopenharmony_ci snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask); 2153d5ac70f0Sopenharmony_ci res = ioctl(fd, cmd, &oparams); 2154d5ac70f0Sopenharmony_ci snd_pcm_hw_convert_from_old_params(params, &oparams); 2155d5ac70f0Sopenharmony_ci params->cmask |= cmask; 2156d5ac70f0Sopenharmony_ci return res; 2157d5ac70f0Sopenharmony_ci} 2158