Blame src/pcm/pcm_hw.c

Packit Service db8eaa
/**
Packit Service db8eaa
 * \file pcm/pcm_hw.c
Packit Service db8eaa
 * \ingroup PCM_Plugins
Packit Service db8eaa
 * \brief PCM HW Plugin Interface
Packit Service db8eaa
 * \author Abramo Bagnara <abramo@alsa-project.org>
Packit Service db8eaa
 * \author Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 * \date 2000-2001
Packit Service db8eaa
 */
Packit Service db8eaa
/*
Packit Service db8eaa
 *  PCM - Hardware
Packit Service db8eaa
 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
Packit Service db8eaa
 *
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
 *   it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
 *   published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
 *   the License, or (at your option) any later version.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This program is distributed in the hope that it will be useful,
Packit Service db8eaa
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
 *   GNU Lesser General Public License for more details.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   You should have received a copy of the GNU Lesser General Public
Packit Service db8eaa
 *   License along with this library; if not, write to the Free Software
Packit Service db8eaa
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
  
Packit Service db8eaa
#include <stdio.h>
Packit Service db8eaa
#include <stdlib.h>
Packit Service db8eaa
#include <stddef.h>
Packit Service db8eaa
#include <unistd.h>
Packit Service db8eaa
#include <stdbool.h>
Packit Service db8eaa
#include <signal.h>
Packit Service db8eaa
#include <string.h>
Packit Service db8eaa
#include <fcntl.h>
Packit Service db8eaa
#include <sys/ioctl.h>
Packit Service db8eaa
#include <sys/mman.h>
Packit Service db8eaa
#include "pcm_local.h"
Packit Service db8eaa
#include "../control/control_local.h"
Packit Service db8eaa
#include "../timer/timer_local.h"
Packit Service db8eaa
Packit Service db8eaa
//#define DEBUG_RW		/* use to debug readi/writei/readn/writen */
Packit Service db8eaa
//#define DEBUG_MMAP		/* debug mmap_commit */
Packit Service db8eaa
Packit Service db8eaa
#ifndef PIC
Packit Service db8eaa
/* entry for static linking */
Packit Service db8eaa
const char *_snd_module_pcm_hw = "";
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
Packit Service db8eaa
#ifndef F_SETSIG
Packit Service db8eaa
#define F_SETSIG 10
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
/*
Packit Service db8eaa
 *  Compatibility
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
struct sndrv_pcm_hw_params_old {
Packit Service db8eaa
	unsigned int flags;
Packit Service db8eaa
	unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
Packit Service db8eaa
			   SNDRV_PCM_HW_PARAM_ACCESS + 1];
Packit Service db8eaa
	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
Packit Service db8eaa
					SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
Packit Service db8eaa
	unsigned int rmask;
Packit Service db8eaa
	unsigned int cmask;
Packit Service db8eaa
	unsigned int info;
Packit Service db8eaa
	unsigned int msbits;
Packit Service db8eaa
	unsigned int rate_num;
Packit Service db8eaa
	unsigned int rate_den;
Packit Service db8eaa
	sndrv_pcm_uframes_t fifo_size;
Packit Service db8eaa
	unsigned char reserved[64];
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
Packit Service db8eaa
#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
Packit Service db8eaa
Packit Service db8eaa
static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
Packit Service db8eaa
static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops;
Packit Service db8eaa
static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer;
Packit Service db8eaa
Packit Service db8eaa
/*
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
typedef struct {
Packit Service db8eaa
	int version;
Packit Service db8eaa
	int fd;
Packit Service db8eaa
	int card, device, subdevice;
Packit Service db8eaa
Packit Service db8eaa
	volatile struct snd_pcm_mmap_status * mmap_status;
Packit Service db8eaa
	struct snd_pcm_mmap_control *mmap_control;
Packit Service db8eaa
	bool mmap_status_fallbacked;
Packit Service db8eaa
	bool mmap_control_fallbacked;
Packit Service db8eaa
	struct snd_pcm_sync_ptr *sync_ptr;
Packit Service db8eaa
Packit Service db8eaa
	int period_event;
Packit Service db8eaa
	snd_timer_t *period_timer;
Packit Service db8eaa
	struct pollfd period_timer_pfd;
Packit Service db8eaa
	int period_timer_need_poll;
Packit Service db8eaa
	/* restricted parameters */
Packit Service db8eaa
	snd_pcm_format_t format;
Packit Service db8eaa
	int rate;
Packit Service db8eaa
	int channels;
Packit Service db8eaa
	/* for chmap */
Packit Service db8eaa
	unsigned int chmap_caps;
Packit Service db8eaa
	snd_pcm_chmap_query_t **chmap_override;
Packit Service db8eaa
} snd_pcm_hw_t;
Packit Service db8eaa
Packit Service db8eaa
#define SNDRV_FILE_PCM_STREAM_PLAYBACK		ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
Packit Service db8eaa
#define SNDRV_FILE_PCM_STREAM_CAPTURE		ALSA_DEVICE_DIRECTORY "pcmC%iD%ic"
Packit Service db8eaa
#define SNDRV_PCM_VERSION_MAX			SNDRV_PROTOCOL_VERSION(2, 0, 9)
Packit Service db8eaa
Packit Service db8eaa
/* update appl_ptr with driver */
Packit Service db8eaa
#define FAST_PCM_STATE(hw) \
Packit Service db8eaa
	((snd_pcm_state_t) (hw)->mmap_status->state)
Packit Service db8eaa
#define FAST_PCM_TSTAMP(hw) \
Packit Service db8eaa
	((hw)->mmap_status->tstamp)
Packit Service db8eaa
Packit Service db8eaa
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	struct timespec res;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	res = FAST_PCM_TSTAMP(hw);
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version)
Packit Service db8eaa
		res.tv_nsec *= 1000L;
Packit Service db8eaa
	return res;
Packit Service db8eaa
}
Packit Service db8eaa
#endif /* DOC_HIDDEN */
Packit Service db8eaa
Packit Service db8eaa
static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	hw->sync_ptr->flags = flags;
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int issue_avail_min(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_control_fallbacked)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	/* Avoid unexpected change of applptr in kernel space. */
Packit Service db8eaa
	return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int issue_applptr(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_control_fallbacked)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	/* Avoid unexpected change of avail_min in kernel space. */
Packit Service db8eaa
	return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int request_hwsync(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_status_fallbacked)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	/*
Packit Service db8eaa
	 * Query both of control/status data to avoid unexpected change of
Packit Service db8eaa
	 * control data in kernel space.
Packit Service db8eaa
	 */
Packit Service db8eaa
	return sync_ptr1(hw,
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_HWSYNC |
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_APPL |
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int query_status_and_control_data(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_control_fallbacked)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	/*
Packit Service db8eaa
	 * Query both of control/status data to avoid unexpected change of
Packit Service db8eaa
	 * control data in kernel space.
Packit Service db8eaa
	 */
Packit Service db8eaa
	return sync_ptr1(hw,
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_APPL |
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int query_status_data(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_status_fallbacked)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	/*
Packit Service db8eaa
	 * Query both of control/status data to avoid unexpected change of
Packit Service db8eaa
	 * control data in kernel space.
Packit Service db8eaa
	 */
Packit Service db8eaa
	return sync_ptr1(hw,
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_APPL |
Packit Service db8eaa
			 SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (hw->period_timer_need_poll) {
Packit Service db8eaa
		while (poll(&hw->period_timer_pfd, 1, 0) > 0) {
Packit Service db8eaa
			snd_timer_tread_t rbuf[4];
Packit Service db8eaa
			snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
Packit Service db8eaa
		}
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_timer_tread_t rbuf[4];
Packit Service db8eaa
		snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return 2;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (space < 2)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	pfds[0].fd = hw->fd;
Packit Service db8eaa
	pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL;
Packit Service db8eaa
	pfds[1].fd = hw->period_timer_pfd.fd;
Packit Service db8eaa
	pfds[1].events = POLLIN | POLLERR | POLLNVAL;
Packit Service db8eaa
	return 2;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	unsigned int events;
Packit Service db8eaa
Packit Service db8eaa
	if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	events = pfds[0].revents;
Packit Service db8eaa
	if (pfds[1].revents & POLLIN) {
Packit Service db8eaa
		snd_pcm_hw_clear_timer_queue(hw);
Packit Service db8eaa
		events |= pcm->poll_events & ~(POLLERR|POLLNVAL);
Packit Service db8eaa
	}
Packit Service db8eaa
	*revents = events;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
Packit Service db8eaa
{
Packit Service db8eaa
	long flags;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
Packit Service db8eaa
	if ((flags = fcntl(fd, F_GETFL)) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_GETFL failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (nonblock)
Packit Service db8eaa
		flags |= O_NONBLOCK;
Packit Service db8eaa
	else
Packit Service db8eaa
		flags &= ~O_NONBLOCK;
Packit Service db8eaa
	if (fcntl(fd, F_SETFL, flags) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
Packit Service db8eaa
{
Packit Service db8eaa
	long flags;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
Packit Service db8eaa
	if ((flags = fcntl(fd, F_GETFL)) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_GETFL failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (sig >= 0)
Packit Service db8eaa
		flags |= O_ASYNC;
Packit Service db8eaa
	else
Packit Service db8eaa
		flags &= ~O_ASYNC;
Packit Service db8eaa
	if (fcntl(fd, F_SETFL, flags) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_SETFL for O_ASYNC failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (sig < 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	if (fcntl(fd, F_SETSIG, (long)sig) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_SETSIG failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (fcntl(fd, F_SETOWN, (long)pid) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("F_SETOWN failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	/* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
Packit Service db8eaa
		return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
Packit Service db8eaa
	return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (hw->format != SND_PCM_FORMAT_UNKNOWN) {
Packit Service db8eaa
		err = _snd_pcm_hw_params_set_format(params, hw->format);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (hw->channels > 0) {
Packit Service db8eaa
		err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
Packit Service db8eaa
					    hw->channels, 0);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (hw->rate > 0) {
Packit Service db8eaa
		err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
Packit Service db8eaa
						   hw->rate, 0, hw->rate + 1, -1);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (hw_refine_call(hw, params) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		// SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed");
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (params->info != ~0U) {
Packit Service db8eaa
		params->info &= ~0xf0000000;
Packit Service db8eaa
		if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
Packit Service db8eaa
			params->info |= SND_PCM_INFO_MONOTONIC;
Packit Service db8eaa
	}
Packit Service db8eaa
	
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	/* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
Packit Service db8eaa
		return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
Packit Service db8eaa
	return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (hw_params_call(hw, params) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	params->info &= ~0xf0000000;
Packit Service db8eaa
	if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
Packit Service db8eaa
		params->info |= SND_PCM_INFO_MONOTONIC;
Packit Service db8eaa
	return query_status_data(hw);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (hw->period_timer) {
Packit Service db8eaa
		snd_timer_close(hw->period_timer);
Packit Service db8eaa
		hw->period_timer = NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	snd_timer_params_t params = {0};
Packit Service db8eaa
	unsigned int suspend, resume;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	
Packit Service db8eaa
	if (enable) {
Packit Service db8eaa
		err = snd_timer_hw_open(&hw->period_timer,
Packit Service db8eaa
				"hw-pcm-period-event",
Packit Service db8eaa
				SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE,
Packit Service db8eaa
				hw->card, hw->device,
Packit Service db8eaa
				(hw->subdevice << 1) | (pcm->stream & 1),
Packit Service db8eaa
				SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			err = snd_timer_hw_open(&hw->period_timer,
Packit Service db8eaa
				"hw-pcm-period-event",
Packit Service db8eaa
				SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE,
Packit Service db8eaa
				hw->card, hw->device,
Packit Service db8eaa
				(hw->subdevice << 1) | (pcm->stream & 1),
Packit Service db8eaa
				SND_TIMER_OPEN_NONBLOCK);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) {
Packit Service db8eaa
			snd_pcm_hw_close_timer(hw);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		hw->period_timer_pfd.events = POLLIN;
Packit Service db8eaa
 		hw->period_timer_pfd.revents = 0;
Packit Service db8eaa
		snd_timer_poll_descriptors(hw->period_timer,
Packit Service db8eaa
					   &hw->period_timer_pfd, 1);
Packit Service db8eaa
		hw->period_timer_need_poll = 0;
Packit Service db8eaa
		suspend = 1<
Packit Service db8eaa
		resume = 1<
Packit Service db8eaa
		/*
Packit Service db8eaa
		 * hacks for older kernel drivers
Packit Service db8eaa
		 */
Packit Service db8eaa
		{
Packit Service db8eaa
			int ver = 0;
Packit Service db8eaa
			ioctl(hw->period_timer_pfd.fd,
Packit Service db8eaa
			      SNDRV_TIMER_IOCTL_PVERSION, &ver);
Packit Service db8eaa
			/*
Packit Service db8eaa
			 * In older versions, check via poll before read() is
Packit Service db8eaa
			 * needed because of the confliction between
Packit Service db8eaa
			 * TIMER_START and FIONBIO ioctls.
Packit Service db8eaa
                         */
Packit Service db8eaa
			if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
Packit Service db8eaa
				hw->period_timer_need_poll = 1;
Packit Service db8eaa
			/*
Packit Service db8eaa
			 * In older versions, timer uses pause events instead
Packit Service db8eaa
			 * suspend/resume events.
Packit Service db8eaa
			 */
Packit Service db8eaa
			if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
Packit Service db8eaa
				suspend = 1<
Packit Service db8eaa
				resume = 1<
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
		snd_timer_params_set_auto_start(&params, 1);
Packit Service db8eaa
		snd_timer_params_set_ticks(&params, 1);
Packit Service db8eaa
		INTERNAL(snd_timer_params_set_filter)(&params, (1<
Packit Service db8eaa
					    suspend | resume);
Packit Service db8eaa
		err = snd_timer_params(hw->period_timer, &params);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			snd_pcm_hw_close_timer(hw);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		err = snd_timer_start(hw->period_timer);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			snd_pcm_hw_close_timer(hw);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		pcm->fast_ops = &snd_pcm_hw_fast_ops_timer;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_pcm_hw_close_timer(hw);
Packit Service db8eaa
		pcm->fast_ops = &snd_pcm_hw_fast_ops;
Packit Service db8eaa
		hw->period_event = 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_hw_free(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	snd_pcm_hw_change_timer(pcm, 0);
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err = 0;
Packit Service db8eaa
	int old_period_event = sw_get_period_event(params);
Packit Service db8eaa
	sw_set_period_event(params, 0);
Packit Service db8eaa
	if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
Packit Service db8eaa
	    (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type &&
Packit Service db8eaa
	    params->period_step == pcm->period_step &&
Packit Service db8eaa
	    params->start_threshold == pcm->start_threshold &&
Packit Service db8eaa
	    params->stop_threshold == pcm->stop_threshold &&
Packit Service db8eaa
	    params->silence_threshold == pcm->silence_threshold &&
Packit Service db8eaa
	    params->silence_size == pcm->silence_size &&
Packit Service db8eaa
	    old_period_event == hw->period_event) {
Packit Service db8eaa
		hw->mmap_control->avail_min = params->avail_min;
Packit Service db8eaa
		err = issue_avail_min(hw);
Packit Service db8eaa
		goto out;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW &&
Packit Service db8eaa
	    hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
Packit Service db8eaa
		SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW");
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		goto out;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC &&
Packit Service db8eaa
	    hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
Packit Service db8eaa
		SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC");
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		goto out;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
Packit Service db8eaa
		goto out;
Packit Service db8eaa
	}
Packit Service db8eaa
	if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) {
Packit Service db8eaa
		if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
Packit Service db8eaa
			int on = (snd_pcm_tstamp_type_t) params->tstamp_type ==
Packit Service db8eaa
				SND_PCM_TSTAMP_TYPE_MONOTONIC;
Packit Service db8eaa
			if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
Packit Service db8eaa
				err = -errno;
Packit Service db8eaa
				SNDMSG("TSTAMP failed\n");
Packit Service db8eaa
				goto out;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
		pcm->tstamp_type = params->tstamp_type;
Packit Service db8eaa
	}
Packit Service db8eaa
	hw->mmap_control->avail_min = params->avail_min;
Packit Service db8eaa
	if (hw->period_event != old_period_event) {
Packit Service db8eaa
		err = snd_pcm_hw_change_timer(pcm, old_period_event);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto out;
Packit Service db8eaa
		hw->period_event = old_period_event;
Packit Service db8eaa
	}
Packit Service db8eaa
 out:
Packit Service db8eaa
	sw_set_period_event(params, old_period_event);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	struct snd_pcm_channel_info i;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	i.channel = info->channel;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	info->channel = i.channel;
Packit Service db8eaa
	info->addr = 0;
Packit Service db8eaa
	info->first = i.first;
Packit Service db8eaa
	info->step = i.step;
Packit Service db8eaa
	info->type = SND_PCM_AREA_MMAP;
Packit Service db8eaa
	info->u.mmap.fd = fd;
Packit Service db8eaa
	info->u.mmap.offset = i.offset;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) {
Packit Service db8eaa
		if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
Packit Service db8eaa
			err = -errno;
Packit Service db8eaa
			SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	} else {
Packit Service db8eaa
		if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) {
Packit Service db8eaa
			err = -errno;
Packit Service db8eaa
			SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
Packit Service db8eaa
		status->tstamp.tv_nsec *= 1000L;
Packit Service db8eaa
		status->trigger_tstamp.tv_nsec *= 1000L;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err = query_status_data(hw);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return (snd_pcm_state_t) hw->mmap_status->state;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_hwsync(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) {
Packit Service db8eaa
		if (hw->mmap_status_fallbacked) {
Packit Service db8eaa
			err = request_hwsync(hw);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		} else {
Packit Service db8eaa
			if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) {
Packit Service db8eaa
				err = -errno;
Packit Service db8eaa
				SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err);
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_pcm_sframes_t delay;
Packit Service db8eaa
		int err = snd_pcm_hw_delay(pcm, &delay);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			switch (FAST_PCM_STATE(hw)) {
Packit Service db8eaa
			case SND_PCM_STATE_PREPARED:
Packit Service db8eaa
			case SND_PCM_STATE_SUSPENDED:
Packit Service db8eaa
				return 0;
Packit Service db8eaa
			default:
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return query_status_and_control_data(hw);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_reset(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return query_status_and_control_data(hw);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_start(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
#if 0
Packit Service db8eaa
	assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
Packit Service db8eaa
	       snd_pcm_mmap_playback_hw_avail(pcm) > 0);
Packit Service db8eaa
#endif
Packit Service db8eaa
	issue_applptr(hw);
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err);
Packit Service db8eaa
#if 0
Packit Service db8eaa
		if (err == -EBADFD)
Packit Service db8eaa
			SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm)));
Packit Service db8eaa
#endif
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_drop(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	} else {
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_drain(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_mmap_hw_rewindable(pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = query_status_and_control_data(hw);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return frames;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) {
Packit Service db8eaa
		if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) {
Packit Service db8eaa
			err = -errno;
Packit Service db8eaa
			SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err);
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		err = query_status_and_control_data(hw);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		return frames;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_pcm_sframes_t avail;
Packit Service db8eaa
Packit Service db8eaa
		switch (FAST_PCM_STATE(hw)) {
Packit Service db8eaa
		case SNDRV_PCM_STATE_RUNNING:
Packit Service db8eaa
		case SNDRV_PCM_STATE_DRAINING:
Packit Service db8eaa
		case SNDRV_PCM_STATE_PAUSED:
Packit Service db8eaa
		case SNDRV_PCM_STATE_PREPARED:
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SNDRV_PCM_STATE_XRUN:
Packit Service db8eaa
			return -EPIPE;
Packit Service db8eaa
		default:
Packit Service db8eaa
			return -EBADFD;
Packit Service db8eaa
		}
Packit Service db8eaa
		avail = snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
		if (avail < 0)
Packit Service db8eaa
			return 0;
Packit Service db8eaa
		if (frames > (snd_pcm_uframes_t)avail)
Packit Service db8eaa
			frames = avail;
Packit Service db8eaa
		snd_pcm_mmap_appl_forward(pcm, frames);
Packit Service db8eaa
		return frames;
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_resume(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd, err;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw1 = pcm1->private_data;
Packit Service db8eaa
	snd_pcm_hw_t *hw2 = pcm2->private_data;
Packit Service db8eaa
	if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno);
Packit Service db8eaa
		return -errno;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
Packit Service db8eaa
{
Packit Service db8eaa
	if (master->type != SND_PCM_TYPE_HW) {
Packit Service db8eaa
		SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	return hw_link(master, pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm2->type != SND_PCM_TYPE_HW) {
Packit Service db8eaa
		if (pcm2->fast_ops->link_slaves)
Packit Service db8eaa
			return pcm2->fast_ops->link_slaves(pcm2, pcm1);
Packit Service db8eaa
		return -ENOSYS;
Packit Service db8eaa
	}
Packit Service db8eaa
	return hw_link(pcm1, pcm2);
Packit Service db8eaa
 }
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) {
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno);
Packit Service db8eaa
		return -errno;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd;
Packit Service db8eaa
	struct snd_xferi xferi;
Packit Service db8eaa
	xferi.buf = (char*) buffer;
Packit Service db8eaa
	xferi.frames = size;
Packit Service db8eaa
	xferi.result = 0; /* make valgrind happy */
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0)
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
	else
Packit Service db8eaa
		err = query_status_and_control_data(hw);
Packit Service db8eaa
#ifdef DEBUG_RW
Packit Service db8eaa
	fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err);
Packit Service db8eaa
#endif
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return snd_pcm_check_error(pcm, err);
Packit Service db8eaa
	return xferi.result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd;
Packit Service db8eaa
	struct snd_xfern xfern;
Packit Service db8eaa
	memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
Packit Service db8eaa
	xfern.bufs = bufs;
Packit Service db8eaa
	xfern.frames = size;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0)
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
	else
Packit Service db8eaa
		err = query_status_and_control_data(hw);
Packit Service db8eaa
#ifdef DEBUG_RW
Packit Service db8eaa
	fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
Packit Service db8eaa
#endif
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return snd_pcm_check_error(pcm, err);
Packit Service db8eaa
	return xfern.result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd;
Packit Service db8eaa
	struct snd_xferi xferi;
Packit Service db8eaa
	xferi.buf = buffer;
Packit Service db8eaa
	xferi.frames = size;
Packit Service db8eaa
	xferi.result = 0; /* make valgrind happy */
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0)
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
	else
Packit Service db8eaa
		err = query_status_and_control_data(hw);
Packit Service db8eaa
#ifdef DEBUG_RW
Packit Service db8eaa
	fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err);
Packit Service db8eaa
#endif
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return snd_pcm_check_error(pcm, err);
Packit Service db8eaa
	return xferi.result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int fd = hw->fd;
Packit Service db8eaa
	struct snd_xfern xfern;
Packit Service db8eaa
	memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
Packit Service db8eaa
	xfern.bufs = bufs;
Packit Service db8eaa
	xfern.frames = size;
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0)
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
	else
Packit Service db8eaa
		err = query_status_and_control_data(hw);
Packit Service db8eaa
#ifdef DEBUG_RW
Packit Service db8eaa
	fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
Packit Service db8eaa
#endif
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return snd_pcm_check_error(pcm, err);
Packit Service db8eaa
	return xfern.result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr,
Packit Service db8eaa
			    bool force_fallback)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_pcm_mmap_status *mmap_status;
Packit Service db8eaa
	bool fallbacked;
Packit Service db8eaa
Packit Service db8eaa
	mmap_status = MAP_FAILED;
Packit Service db8eaa
	if (!force_fallback) {
Packit Service db8eaa
		mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)),
Packit Service db8eaa
				   PROT_READ, MAP_FILE|MAP_SHARED,
Packit Service db8eaa
				   hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (mmap_status == MAP_FAILED || mmap_status == NULL) {
Packit Service db8eaa
		mmap_status = &sync_ptr->s.status;
Packit Service db8eaa
		fallbacked = true;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		fallbacked = false;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	hw->mmap_status = mmap_status;
Packit Service db8eaa
Packit Service db8eaa
	return fallbacked;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static bool map_control_data(snd_pcm_hw_t *hw,
Packit Service db8eaa
			     struct snd_pcm_sync_ptr *sync_ptr,
Packit Service db8eaa
			     bool force_fallback)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_pcm_mmap_control *mmap_control;
Packit Service db8eaa
	bool fallbacked;
Packit Service db8eaa
Packit Service db8eaa
	mmap_control = MAP_FAILED;
Packit Service db8eaa
	if (!force_fallback) {
Packit Service db8eaa
		mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)),
Packit Service db8eaa
				    PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
Packit Service db8eaa
				    hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (mmap_control == MAP_FAILED || mmap_control == NULL) {
Packit Service db8eaa
		mmap_control = &sync_ptr->c.control;
Packit Service db8eaa
		fallbacked = true;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		fallbacked = false;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	hw->mmap_control = mmap_control;
Packit Service db8eaa
Packit Service db8eaa
	return fallbacked;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	struct snd_pcm_sync_ptr *sync_ptr;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	/* Preparation for fallback to failure of mmap(2). */
Packit Service db8eaa
	sync_ptr = malloc(sizeof(*sync_ptr));
Packit Service db8eaa
	if (sync_ptr == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	memset(sync_ptr, 0, sizeof(*sync_ptr));
Packit Service db8eaa
Packit Service db8eaa
	hw->mmap_status_fallbacked =
Packit Service db8eaa
			map_status_data(hw, sync_ptr, force_fallback);
Packit Service db8eaa
	hw->mmap_control_fallbacked =
Packit Service db8eaa
			map_control_data(hw, sync_ptr, force_fallback);
Packit Service db8eaa
Packit Service db8eaa
	/* Any fallback mode needs to keep the buffer. */
Packit Service db8eaa
	if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) {
Packit Service db8eaa
		hw->sync_ptr = sync_ptr;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		free(sync_ptr);
Packit Service db8eaa
		hw->sync_ptr = NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* do not initialize in case of append and keep the values from the
Packit Service db8eaa
	 * kernel
Packit Service db8eaa
	 */
Packit Service db8eaa
	if (!(pcm->mode & SND_PCM_APPEND)) {
Packit Service db8eaa
		/* Initialize the data. */
Packit Service db8eaa
		hw->mmap_control->appl_ptr = 0;
Packit Service db8eaa
		hw->mmap_control->avail_min = 1;
Packit Service db8eaa
	}
Packit Service db8eaa
	snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd,
Packit Service db8eaa
			   SNDRV_PCM_MMAP_OFFSET_STATUS +
Packit Service db8eaa
				offsetof(struct snd_pcm_mmap_status, hw_ptr));
Packit Service db8eaa
	snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd,
Packit Service db8eaa
			     SNDRV_PCM_MMAP_OFFSET_CONTROL);
Packit Service db8eaa
	if (hw->mmap_control_fallbacked) {
Packit Service db8eaa
		unsigned int flags = 0;
Packit Service db8eaa
		/* read appl_ptr and avail_min from kernel when device opened
Packit Service db8eaa
		 * with SND_PCM_APPEND flag
Packit Service db8eaa
		 */
Packit Service db8eaa
		if (pcm->mode & SND_PCM_APPEND)
Packit Service db8eaa
			flags = SNDRV_PCM_SYNC_PTR_APPL |
Packit Service db8eaa
				SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
Packit Service db8eaa
		err = sync_ptr1(hw, flags);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void unmap_status_data(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_status_fallbacked) {
Packit Service db8eaa
		if (munmap((void *)hw->mmap_status,
Packit Service db8eaa
			   page_align(sizeof(*hw->mmap_status))) < 0)
Packit Service db8eaa
			SYSMSG("status munmap failed (%u)", errno);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void unmap_control_data(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	if (!hw->mmap_control_fallbacked) {
Packit Service db8eaa
		if (munmap((void *)hw->mmap_control,
Packit Service db8eaa
			   page_align(sizeof(*hw->mmap_control))) < 0)
Packit Service db8eaa
			SYSMSG("control munmap failed (%u)", errno);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void unmap_status_and_control_data(snd_pcm_hw_t *hw)
Packit Service db8eaa
{
Packit Service db8eaa
	unmap_status_data(hw);
Packit Service db8eaa
	unmap_control_data(hw);
Packit Service db8eaa
Packit Service db8eaa
	if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked)
Packit Service db8eaa
		free(hw->sync_ptr);
Packit Service db8eaa
Packit Service db8eaa
	hw->mmap_status = NULL;
Packit Service db8eaa
	hw->mmap_control = NULL;
Packit Service db8eaa
	hw->mmap_status_fallbacked = false;
Packit Service db8eaa
	hw->mmap_control_fallbacked = false;
Packit Service db8eaa
	hw->sync_ptr = NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_close(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
	if (close(hw->fd)) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		SYSMSG("close failed (%i)\n", err);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	unmap_status_and_control_data(hw);
Packit Service db8eaa
Packit Service db8eaa
	free(hw);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
Packit Service db8eaa
						snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
Packit Service db8eaa
						snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_mmap_appl_forward(pcm, size);
Packit Service db8eaa
	issue_applptr(hw);
Packit Service db8eaa
#ifdef DEBUG_MMAP
Packit Service db8eaa
	fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size);
Packit Service db8eaa
#endif
Packit Service db8eaa
	return size;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	snd_pcm_uframes_t avail;
Packit Service db8eaa
Packit Service db8eaa
	query_status_data(hw);
Packit Service db8eaa
	avail = snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
	switch (FAST_PCM_STATE(hw)) {
Packit Service db8eaa
	case SNDRV_PCM_STATE_RUNNING:
Packit Service db8eaa
		if (avail >= pcm->stop_threshold) {
Packit Service db8eaa
			/* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
Packit Service db8eaa
			if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
Packit Service db8eaa
				if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0)
Packit Service db8eaa
					return -errno;
Packit Service db8eaa
			}
Packit Service db8eaa
			/* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
Packit Service db8eaa
			return -EPIPE;
Packit Service db8eaa
		}
Packit Service db8eaa
		break;
Packit Service db8eaa
	case SNDRV_PCM_STATE_XRUN:
Packit Service db8eaa
		return -EPIPE;
Packit Service db8eaa
	default:
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
	return avail;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
Packit Service db8eaa
				 snd_htimestamp_t *tstamp)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_sframes_t avail1;
Packit Service db8eaa
	int ok = 0;
Packit Service db8eaa
Packit Service db8eaa
	/* unfortunately, loop is necessary to ensure valid timestamp */
Packit Service db8eaa
	while (1) {
Packit Service db8eaa
		avail1 = snd_pcm_hw_avail_update(pcm);
Packit Service db8eaa
		if (avail1 < 0)
Packit Service db8eaa
			return avail1;
Packit Service db8eaa
		if (ok && (snd_pcm_uframes_t)avail1 == *avail)
Packit Service db8eaa
			break;
Packit Service db8eaa
		*avail = avail1;
Packit Service db8eaa
		*tstamp = snd_pcm_hw_fast_tstamp(pcm);
Packit Service db8eaa
		ok = 1;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void __fill_chmap_ctl_id(snd_ctl_elem_id_t *id, int dev, int subdev,
Packit Service db8eaa
				int stream)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
Packit Service db8eaa
	if (stream == SND_PCM_STREAM_PLAYBACK)
Packit Service db8eaa
		snd_ctl_elem_id_set_name(id, "Playback Channel Map");
Packit Service db8eaa
	else
Packit Service db8eaa
		snd_ctl_elem_id_set_name(id, "Capture Channel Map");
Packit Service db8eaa
	snd_ctl_elem_id_set_device(id, dev);
Packit Service db8eaa
	snd_ctl_elem_id_set_index(id, subdev);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	__fill_chmap_ctl_id(id, hw->device, hw->subdevice, pcm->stream);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int is_chmap_type(int type)
Packit Service db8eaa
{
Packit Service db8eaa
	return (type >= SND_CTL_TLVT_CHMAP_FIXED &&
Packit Service db8eaa
		type <= SND_CTL_TLVT_CHMAP_PAIRED);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \!brief Query the available channel maps
Packit Service db8eaa
 * \param card the card number
Packit Service db8eaa
 * \param dev the PCM device number
Packit Service db8eaa
 * \param subdev the PCM substream index
Packit Service db8eaa
 * \param stream the direction of PCM stream
Packit Service db8eaa
 * \return the NULL-terminated array of integer pointers, or NULL at error.
Packit Service db8eaa
 *
Packit Service db8eaa
 * This function works like snd_pcm_query_chmaps() but it takes the card,
Packit Service db8eaa
 * device, substream and stream numbers instead of the already opened
Packit Service db8eaa
 * snd_pcm_t instance, so that you can query available channel maps of
Packit Service db8eaa
 * a PCM before actually opening it.
Packit Service db8eaa
 *
Packit Service db8eaa
 * As the parameters stand, the query is performed only to the hw PCM
Packit Service db8eaa
 * devices, not the abstracted PCM object in alsa-lib.
Packit Service db8eaa
 */
Packit Service db8eaa
snd_pcm_chmap_query_t **
Packit Service db8eaa
snd_pcm_query_chmaps_from_hw(int card, int dev, int subdev,
Packit Service db8eaa
			     snd_pcm_stream_t stream)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_t *ctl;
Packit Service db8eaa
	snd_ctl_elem_id_t id = {0};
Packit Service db8eaa
	unsigned int tlv[2048], *start;
Packit Service db8eaa
	unsigned int type;
Packit Service db8eaa
	snd_pcm_chmap_query_t **map;
Packit Service db8eaa
	int i, ret, nums;
Packit Service db8eaa
Packit Service db8eaa
	ret = snd_ctl_hw_open(&ctl, NULL, card, 0);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		SYSMSG("Cannot open the associated CTL\n");
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	__fill_chmap_ctl_id(&id, dev, subdev, stream);
Packit Service db8eaa
	ret = snd_ctl_elem_tlv_read(ctl, &id, tlv, sizeof(tlv));
Packit Service db8eaa
	snd_ctl_close(ctl);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		SYSMSG("Cannot read Channel Map TLV\n");
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
#if 0
Packit Service db8eaa
	for (i = 0; i < 32; i++)
Packit Service db8eaa
		fprintf(stderr, "%02x: %08x\n", i, tlv[i]);
Packit Service db8eaa
#endif
Packit Service db8eaa
	/* FIXME: the parser below assumes that the TLV only contains
Packit Service db8eaa
	 * chmap-related blocks
Packit Service db8eaa
	 */
Packit Service db8eaa
	type = tlv[SNDRV_CTL_TLVO_TYPE];
Packit Service db8eaa
	if (type != SND_CTL_TLVT_CONTAINER) {
Packit Service db8eaa
		if (!is_chmap_type(type)) {
Packit Service db8eaa
			SYSMSG("Invalid TLV type %d\n", type);
Packit Service db8eaa
			return NULL;
Packit Service db8eaa
		}
Packit Service db8eaa
		start = tlv;
Packit Service db8eaa
		nums = 1;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		unsigned int *p;
Packit Service db8eaa
		int size;
Packit Service db8eaa
		start = tlv + 2;
Packit Service db8eaa
		size = tlv[SNDRV_CTL_TLVO_LEN];
Packit Service db8eaa
		nums = 0;
Packit Service db8eaa
		for (p = start; size > 0; ) {
Packit Service db8eaa
			if (!is_chmap_type(p[0])) {
Packit Service db8eaa
				SYSMSG("Invalid TLV type %d\n", p[0]);
Packit Service db8eaa
				return NULL;
Packit Service db8eaa
			}
Packit Service db8eaa
			nums++;
Packit Service db8eaa
			size -= p[1] + 8;
Packit Service db8eaa
			p += p[1] / 4 + 2;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	map = calloc(nums + 1, sizeof(int *));
Packit Service db8eaa
	if (!map)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	for (i = 0; i < nums; i++) {
Packit Service db8eaa
		map[i] = malloc(start[1] + 8);
Packit Service db8eaa
		if (!map[i]) {
Packit Service db8eaa
			snd_pcm_free_chmaps(map);
Packit Service db8eaa
			return NULL;
Packit Service db8eaa
		}
Packit Service db8eaa
		map[i]->type = start[0] - 0x100;
Packit Service db8eaa
		map[i]->map.channels = start[1] / 4;
Packit Service db8eaa
		memcpy(map[i]->map.pos, start + 2, start[1]);
Packit Service db8eaa
		start += start[1] / 4 + 2;
Packit Service db8eaa
	}
Packit Service db8eaa
	return map;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET };
Packit Service db8eaa
Packit Service db8eaa
static int chmap_caps(snd_pcm_hw_t *hw, int type)
Packit Service db8eaa
{
Packit Service db8eaa
	if (hw->chmap_caps & (1 << type))
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	if (hw->chmap_caps & (1 << (type + 8)))
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	return 1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type)
Packit Service db8eaa
{
Packit Service db8eaa
	hw->chmap_caps |= (1 << type);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type)
Packit Service db8eaa
{
Packit Service db8eaa
	hw->chmap_caps |= (1 << (type + 8));
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	snd_pcm_chmap_query_t **map;
Packit Service db8eaa
Packit Service db8eaa
	if (hw->chmap_override)
Packit Service db8eaa
		return _snd_pcm_copy_chmap_query(hw->chmap_override);
Packit Service db8eaa
Packit Service db8eaa
	if (!chmap_caps(hw, CHMAP_CTL_QUERY))
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	map = snd_pcm_query_chmaps_from_hw(hw->card, hw->device,
Packit Service db8eaa
					   hw->subdevice, pcm->stream);
Packit Service db8eaa
	if (map)
Packit Service db8eaa
		chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
Packit Service db8eaa
	else
Packit Service db8eaa
		chmap_caps_set_error(hw, CHMAP_CTL_QUERY);
Packit Service db8eaa
	return map;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	snd_pcm_chmap_t *map;
Packit Service db8eaa
	snd_ctl_t *ctl;
Packit Service db8eaa
	snd_ctl_elem_id_t id = {0};
Packit Service db8eaa
	snd_ctl_elem_value_t val = {0};
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	int ret;
Packit Service db8eaa
Packit Service db8eaa
	if (hw->chmap_override)
Packit Service db8eaa
		return _snd_pcm_choose_fixed_chmap(pcm, hw->chmap_override);
Packit Service db8eaa
Packit Service db8eaa
	if (!chmap_caps(hw, CHMAP_CTL_GET))
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	switch (FAST_PCM_STATE(hw)) {
Packit Service db8eaa
	case SNDRV_PCM_STATE_PREPARED:
Packit Service db8eaa
	case SNDRV_PCM_STATE_RUNNING:
Packit Service db8eaa
	case SNDRV_PCM_STATE_XRUN:
Packit Service db8eaa
	case SNDRV_PCM_STATE_DRAINING:
Packit Service db8eaa
	case SNDRV_PCM_STATE_PAUSED:
Packit Service db8eaa
	case SNDRV_PCM_STATE_SUSPENDED:
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		SYSMSG("Invalid PCM state for chmap_get: %s\n",
Packit Service db8eaa
		       snd_pcm_state_name(FAST_PCM_STATE(hw)));
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
	map = malloc(pcm->channels * sizeof(map->pos[0]) + sizeof(*map));
Packit Service db8eaa
	if (!map)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	map->channels = pcm->channels;
Packit Service db8eaa
	ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		free(map);
Packit Service db8eaa
		SYSMSG("Cannot open the associated CTL\n");
Packit Service db8eaa
		chmap_caps_set_error(hw, CHMAP_CTL_GET);
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
	fill_chmap_ctl_id(pcm, &id;;
Packit Service db8eaa
	snd_ctl_elem_value_set_id(&val, &id;;
Packit Service db8eaa
	ret = snd_ctl_elem_read(ctl, &val;;
Packit Service db8eaa
	snd_ctl_close(ctl);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		free(map);
Packit Service db8eaa
		SYSMSG("Cannot read Channel Map ctl\n");
Packit Service db8eaa
		chmap_caps_set_error(hw, CHMAP_CTL_GET);
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
	for (i = 0; i < pcm->channels; i++)
Packit Service db8eaa
		map->pos[i] = snd_ctl_elem_value_get_integer(&val, i);
Packit Service db8eaa
	chmap_caps_set_ok(hw, CHMAP_CTL_GET);
Packit Service db8eaa
	return map;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	snd_ctl_t *ctl;
Packit Service db8eaa
	snd_ctl_elem_id_t id = {0};
Packit Service db8eaa
	snd_ctl_elem_value_t val = {0};
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	int ret;
Packit Service db8eaa
Packit Service db8eaa
	if (hw->chmap_override)
Packit Service db8eaa
		return -ENXIO;
Packit Service db8eaa
Packit Service db8eaa
	if (!chmap_caps(hw, CHMAP_CTL_SET))
Packit Service db8eaa
		return -ENXIO;
Packit Service db8eaa
Packit Service db8eaa
	if (map->channels > 128) {
Packit Service db8eaa
		SYSMSG("Invalid number of channels %d\n", map->channels);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) {
Packit Service db8eaa
		SYSMSG("Invalid PCM state for chmap_set: %s\n",
Packit Service db8eaa
		       snd_pcm_state_name(FAST_PCM_STATE(hw)));
Packit Service db8eaa
		return -EBADFD;
Packit Service db8eaa
	}
Packit Service db8eaa
	ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		SYSMSG("Cannot open the associated CTL\n");
Packit Service db8eaa
		chmap_caps_set_error(hw, CHMAP_CTL_SET);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	fill_chmap_ctl_id(pcm, &id;;
Packit Service db8eaa
	snd_ctl_elem_value_set_id(&val, &id;;
Packit Service db8eaa
	for (i = 0; i < map->channels; i++)
Packit Service db8eaa
		snd_ctl_elem_value_set_integer(&val, i, map->pos[i]);
Packit Service db8eaa
	ret = snd_ctl_elem_write(ctl, &val;;
Packit Service db8eaa
	snd_ctl_close(ctl);
Packit Service db8eaa
	if (ret >= 0)
Packit Service db8eaa
		chmap_caps_set_ok(hw, CHMAP_CTL_SET);
Packit Service db8eaa
	else if (ret == -ENOENT || ret == -EPERM || ret == -ENXIO) {
Packit Service db8eaa
		chmap_caps_set_error(hw, CHMAP_CTL_SET);
Packit Service db8eaa
		ret = -ENXIO;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (ret < 0)
Packit Service db8eaa
		SYSMSG("Cannot write Channel Map ctl\n");
Packit Service db8eaa
	return ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_t *hw = pcm->private_data;
Packit Service db8eaa
	char *name;
Packit Service db8eaa
	int err = snd_card_get_name(hw->card, &name);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		SNDERR("cannot get card name");
Packit Service db8eaa
		return;
Packit Service db8eaa
	}
Packit Service db8eaa
	snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n",
Packit Service db8eaa
			  hw->card, name, hw->device, hw->subdevice);
Packit Service db8eaa
	free(name);
Packit Service db8eaa
	if (pcm->setup) {
Packit Service db8eaa
		snd_output_printf(out, "Its setup is:\n");
Packit Service db8eaa
		snd_pcm_dump_setup(pcm, out);
Packit Service db8eaa
		snd_output_printf(out, "  appl_ptr     : %li\n", hw->mmap_control->appl_ptr);
Packit Service db8eaa
		snd_output_printf(out, "  hw_ptr       : %li\n", hw->mmap_status->hw_ptr);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const snd_pcm_ops_t snd_pcm_hw_ops = {
Packit Service db8eaa
	.close = snd_pcm_hw_close,
Packit Service db8eaa
	.info = snd_pcm_hw_info,
Packit Service db8eaa
	.hw_refine = snd_pcm_hw_hw_refine,
Packit Service db8eaa
	.hw_params = snd_pcm_hw_hw_params,
Packit Service db8eaa
	.hw_free = snd_pcm_hw_hw_free,
Packit Service db8eaa
	.sw_params = snd_pcm_hw_sw_params,
Packit Service db8eaa
	.channel_info = snd_pcm_hw_channel_info,
Packit Service db8eaa
	.dump = snd_pcm_hw_dump,
Packit Service db8eaa
	.nonblock = snd_pcm_hw_nonblock,
Packit Service db8eaa
	.async = snd_pcm_hw_async,
Packit Service db8eaa
	.mmap = snd_pcm_hw_mmap,
Packit Service db8eaa
	.munmap = snd_pcm_hw_munmap,
Packit Service db8eaa
	.query_chmaps = snd_pcm_hw_query_chmaps,
Packit Service db8eaa
	.get_chmap = snd_pcm_hw_get_chmap,
Packit Service db8eaa
	.set_chmap = snd_pcm_hw_set_chmap,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
Packit Service db8eaa
	.status = snd_pcm_hw_status,
Packit Service db8eaa
	.state = snd_pcm_hw_state,
Packit Service db8eaa
	.hwsync = snd_pcm_hw_hwsync,
Packit Service db8eaa
	.delay = snd_pcm_hw_delay,
Packit Service db8eaa
	.prepare = snd_pcm_hw_prepare,
Packit Service db8eaa
	.reset = snd_pcm_hw_reset,
Packit Service db8eaa
	.start = snd_pcm_hw_start,
Packit Service db8eaa
	.drop = snd_pcm_hw_drop,
Packit Service db8eaa
	.drain = snd_pcm_hw_drain,
Packit Service db8eaa
	.pause = snd_pcm_hw_pause,
Packit Service db8eaa
	.rewindable = snd_pcm_hw_rewindable,
Packit Service db8eaa
	.rewind = snd_pcm_hw_rewind,
Packit Service db8eaa
	.forwardable = snd_pcm_hw_forwardable,
Packit Service db8eaa
	.forward = snd_pcm_hw_forward,
Packit Service db8eaa
	.resume = snd_pcm_hw_resume,
Packit Service db8eaa
	.link = snd_pcm_hw_link,
Packit Service db8eaa
	.link_slaves = snd_pcm_hw_link_slaves,
Packit Service db8eaa
	.unlink = snd_pcm_hw_unlink,
Packit Service db8eaa
	.writei = snd_pcm_hw_writei,
Packit Service db8eaa
	.writen = snd_pcm_hw_writen,
Packit Service db8eaa
	.readi = snd_pcm_hw_readi,
Packit Service db8eaa
	.readn = snd_pcm_hw_readn,
Packit Service db8eaa
	.avail_update = snd_pcm_hw_avail_update,
Packit Service db8eaa
	.mmap_commit = snd_pcm_hw_mmap_commit,
Packit Service db8eaa
	.htimestamp = snd_pcm_hw_htimestamp,
Packit Service db8eaa
	.poll_descriptors = NULL,
Packit Service db8eaa
	.poll_descriptors_count = NULL,
Packit Service db8eaa
	.poll_revents = NULL,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = {
Packit Service db8eaa
	.status = snd_pcm_hw_status,
Packit Service db8eaa
	.state = snd_pcm_hw_state,
Packit Service db8eaa
	.hwsync = snd_pcm_hw_hwsync,
Packit Service db8eaa
	.delay = snd_pcm_hw_delay,
Packit Service db8eaa
	.prepare = snd_pcm_hw_prepare,
Packit Service db8eaa
	.reset = snd_pcm_hw_reset,
Packit Service db8eaa
	.start = snd_pcm_hw_start,
Packit Service db8eaa
	.drop = snd_pcm_hw_drop,
Packit Service db8eaa
	.drain = snd_pcm_hw_drain,
Packit Service db8eaa
	.pause = snd_pcm_hw_pause,
Packit Service db8eaa
	.rewindable = snd_pcm_hw_rewindable,
Packit Service db8eaa
	.rewind = snd_pcm_hw_rewind,
Packit Service db8eaa
	.forwardable = snd_pcm_hw_forwardable,
Packit Service db8eaa
	.forward = snd_pcm_hw_forward,
Packit Service db8eaa
	.resume = snd_pcm_hw_resume,
Packit Service db8eaa
	.link = snd_pcm_hw_link,
Packit Service db8eaa
	.link_slaves = snd_pcm_hw_link_slaves,
Packit Service db8eaa
	.unlink = snd_pcm_hw_unlink,
Packit Service db8eaa
	.writei = snd_pcm_hw_writei,
Packit Service db8eaa
	.writen = snd_pcm_hw_writen,
Packit Service db8eaa
	.readi = snd_pcm_hw_readi,
Packit Service db8eaa
	.readn = snd_pcm_hw_readn,
Packit Service db8eaa
	.avail_update = snd_pcm_hw_avail_update,
Packit Service db8eaa
	.mmap_commit = snd_pcm_hw_mmap_commit,
Packit Service db8eaa
	.htimestamp = snd_pcm_hw_htimestamp,
Packit Service db8eaa
	.poll_descriptors = snd_pcm_hw_poll_descriptors,
Packit Service db8eaa
	.poll_descriptors_count = snd_pcm_hw_poll_descriptors_count,
Packit Service db8eaa
	.poll_revents = snd_pcm_hw_poll_revents,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Creates a new hw PCM
Packit Service db8eaa
 * \param pcmp Returns created PCM handle
Packit Service db8eaa
 * \param name Name of PCM
Packit Service db8eaa
 * \param fd File descriptor
Packit Service db8eaa
 * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl
Packit Service db8eaa
 * \retval zero on success otherwise a negative error code
Packit Service db8eaa
 * \warning Using of this function might be dangerous in the sense
Packit Service db8eaa
 *          of compatibility reasons. The prototype might be freely
Packit Service db8eaa
 *          changed in future.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd,
Packit Service db8eaa
		       int sync_ptr_ioctl)
Packit Service db8eaa
{
Packit Service db8eaa
	int ver, mode;
Packit Service db8eaa
	snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
Packit Service db8eaa
	long fmode;
Packit Service db8eaa
	snd_pcm_t *pcm = NULL;
Packit Service db8eaa
	snd_pcm_hw_t *hw = NULL;
Packit Service db8eaa
	snd_pcm_info_t info;
Packit Service db8eaa
	int ret;
Packit Service db8eaa
Packit Service db8eaa
	assert(pcmp);
Packit Service db8eaa
Packit Service db8eaa
	memset(&info, 0, sizeof(info));
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
Packit Service db8eaa
		ret = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if ((fmode = fcntl(fd, F_GETFL)) < 0) {
Packit Service db8eaa
		ret = -errno;
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
	mode = 0;
Packit Service db8eaa
	if (fmode & O_NONBLOCK)
Packit Service db8eaa
		mode |= SND_PCM_NONBLOCK;
Packit Service db8eaa
	if (fmode & O_ASYNC)
Packit Service db8eaa
		mode |= SND_PCM_ASYNC;
Packit Service db8eaa
	if (fmode & O_APPEND)
Packit Service db8eaa
		mode |= SND_PCM_APPEND;
Packit Service db8eaa
Packit Service db8eaa
	if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) {
Packit Service db8eaa
		ret = -errno;
Packit Service db8eaa
		SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret);
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX))
Packit Service db8eaa
		return -SND_ERROR_INCOMPATIBLE_VERSION;
Packit Service db8eaa
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) {
Packit Service db8eaa
		/* inform the protocol version we're supporting */
Packit Service db8eaa
		unsigned int user_ver = SNDRV_PCM_VERSION;
Packit Service db8eaa
		if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) {
Packit Service db8eaa
			ret = -errno;
Packit Service db8eaa
			SNDMSG("USER_PVERSION failed\n");
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit Service db8eaa
	if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) {
Packit Service db8eaa
		struct timespec timespec;
Packit Service db8eaa
		if (clock_gettime(CLOCK_MONOTONIC, &timespec) == 0) {
Packit Service db8eaa
			int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
Packit Service db8eaa
			if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
Packit Service db8eaa
				ret = -errno;
Packit Service db8eaa
				SNDMSG("TTSTAMP failed\n");
Packit Service db8eaa
				return ret;
Packit Service db8eaa
			}
Packit Service db8eaa
			tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
Packit Service db8eaa
		}
Packit Service db8eaa
	} else
Packit Service db8eaa
#endif
Packit Service db8eaa
	  if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) {
Packit Service db8eaa
		int on = 1;
Packit Service db8eaa
		if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
Packit Service db8eaa
			ret = -errno;
Packit Service db8eaa
			SNDMSG("TSTAMP failed\n");
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	
Packit Service db8eaa
	hw = calloc(1, sizeof(snd_pcm_hw_t));
Packit Service db8eaa
	if (!hw) {
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	hw->version = ver;
Packit Service db8eaa
	hw->card = info.card;
Packit Service db8eaa
	hw->device = info.device;
Packit Service db8eaa
	hw->subdevice = info.subdevice;
Packit Service db8eaa
	hw->fd = fd;
Packit Service db8eaa
	/* no restriction */
Packit Service db8eaa
	hw->format = SND_PCM_FORMAT_UNKNOWN;
Packit Service db8eaa
	hw->rate = 0;
Packit Service db8eaa
	hw->channels = 0;
Packit Service db8eaa
Packit Service db8eaa
	ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		free(hw);
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	pcm->ops = &snd_pcm_hw_ops;
Packit Service db8eaa
	pcm->fast_ops = &snd_pcm_hw_fast_ops;
Packit Service db8eaa
	pcm->private_data = hw;
Packit Service db8eaa
	pcm->poll_fd = fd;
Packit Service db8eaa
	pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
Packit Service db8eaa
	pcm->tstamp_type = tstamp_type;
Packit Service db8eaa
#ifdef THREAD_SAFE_API
Packit Service db8eaa
	pcm->need_lock = 0;	/* hw plugin is thread-safe */
Packit Service db8eaa
#endif
Packit Service db8eaa
	pcm->own_state_check = 1; /* skip the common state check */
Packit Service db8eaa
Packit Service db8eaa
	ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl);
Packit Service db8eaa
	if (ret < 0) {
Packit Service db8eaa
		snd_pcm_close(pcm);
Packit Service db8eaa
		return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	*pcmp = pcm;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Creates a new hw PCM
Packit Service db8eaa
 * \param pcmp Returns created PCM handle
Packit Service db8eaa
 * \param name Name of PCM
Packit Service db8eaa
 * \param card Number of card
Packit Service db8eaa
 * \param device Number of device
Packit Service db8eaa
 * \param subdevice Number of subdevice
Packit Service db8eaa
 * \param stream PCM Stream
Packit Service db8eaa
 * \param mode PCM Mode
Packit Service db8eaa
 * \param mmap_emulation Obsoleted parameter
Packit Service db8eaa
 * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures
Packit Service db8eaa
 * \retval zero on success otherwise a negative error code
Packit Service db8eaa
 * \warning Using of this function might be dangerous in the sense
Packit Service db8eaa
 *          of compatibility reasons. The prototype might be freely
Packit Service db8eaa
 *          changed in future.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
Packit Service db8eaa
		    int card, int device, int subdevice,
Packit Service db8eaa
		    snd_pcm_stream_t stream, int mode,
Packit Service db8eaa
		    int mmap_emulation ATTRIBUTE_UNUSED,
Packit Service db8eaa
		    int sync_ptr_ioctl)
Packit Service db8eaa
{
Packit Service db8eaa
	char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20];
Packit Service db8eaa
	const char *filefmt;
Packit Service db8eaa
	int ret = 0, fd = -1;
Packit Service db8eaa
	int attempt = 0;
Packit Service db8eaa
	snd_pcm_info_t info;
Packit Service db8eaa
	int fmode;
Packit Service db8eaa
	snd_ctl_t *ctl;
Packit Service db8eaa
Packit Service db8eaa
	assert(pcmp);
Packit Service db8eaa
Packit Service db8eaa
	if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
Packit Service db8eaa
		return ret;
Packit Service db8eaa
Packit Service db8eaa
	switch (stream) {
Packit Service db8eaa
	case SND_PCM_STREAM_PLAYBACK:
Packit Service db8eaa
		filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case SND_PCM_STREAM_CAPTURE:
Packit Service db8eaa
		filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE;
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		SNDERR("invalid stream %d", stream);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	sprintf(filename, filefmt, card, device);
Packit Service db8eaa
Packit Service db8eaa
      __again:
Packit Service db8eaa
      	if (attempt++ > 3) {
Packit Service db8eaa
		ret = -EBUSY;
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	}
Packit Service db8eaa
	ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
Packit Service db8eaa
	if (ret < 0)
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	fmode = O_RDWR;
Packit Service db8eaa
	if (mode & SND_PCM_NONBLOCK)
Packit Service db8eaa
		fmode |= O_NONBLOCK;
Packit Service db8eaa
	if (mode & SND_PCM_ASYNC)
Packit Service db8eaa
		fmode |= O_ASYNC;
Packit Service db8eaa
	if (mode & SND_PCM_APPEND)
Packit Service db8eaa
		fmode |= O_APPEND;
Packit Service db8eaa
	fd = snd_open_device(filename, fmode);
Packit Service db8eaa
	if (fd < 0) {
Packit Service db8eaa
		ret = -errno;
Packit Service db8eaa
		SYSMSG("open '%s' failed (%i)", filename, ret);
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (subdevice >= 0) {
Packit Service db8eaa
		memset(&info, 0, sizeof(info));
Packit Service db8eaa
		if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
Packit Service db8eaa
			ret = -errno;
Packit Service db8eaa
			SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
Packit Service db8eaa
			goto _err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (info.subdevice != (unsigned int) subdevice) {
Packit Service db8eaa
			close(fd);
Packit Service db8eaa
			fd = -1;
Packit Service db8eaa
			goto __again;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	snd_ctl_close(ctl);
Packit Service db8eaa
	return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl);
Packit Service db8eaa
       _err:
Packit Service db8eaa
	if (fd >= 0)
Packit Service db8eaa
		close(fd);
Packit Service db8eaa
	snd_ctl_close(ctl);
Packit Service db8eaa
	return ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/*! \page pcm_plugins
Packit Service db8eaa
Packit Service db8eaa
\section pcm_plugins_hw Plugin: hw
Packit Service db8eaa
Packit Service db8eaa
This plugin communicates directly with the ALSA kernel driver. It is a raw
Packit Service db8eaa
communication without any conversions. The emulation of mmap access can be
Packit Service db8eaa
optionally enabled, but expect worse latency in the case.
Packit Service db8eaa
Packit Service db8eaa
The nonblock option specifies whether the device is opened in a non-blocking
Packit Service db8eaa
manner.  Note that the blocking behavior for read/write access won't be
Packit Service db8eaa
changed by this option.  This influences only on the blocking behavior at
Packit Service db8eaa
opening the device.  If you would like to keep the compatibility with the
Packit Service db8eaa
older ALSA stuff, turn this option off.
Packit Service db8eaa
Packit Service db8eaa
\code
Packit Service db8eaa
pcm.name {
Packit Service db8eaa
	type hw			# Kernel PCM
Packit Service db8eaa
	card INT/STR		# Card name (string) or number (integer)
Packit Service db8eaa
	[device INT]		# Device number (default 0)
Packit Service db8eaa
	[subdevice INT]		# Subdevice number (default -1: first available)
Packit Service db8eaa
	[sync_ptr_ioctl BOOL]	# Use SYNC_PTR ioctl rather than the direct mmap access for control structures
Packit Service db8eaa
	[nonblock BOOL]		# Force non-blocking open mode
Packit Service db8eaa
	[format STR]		# Restrict only to the given format
Packit Service db8eaa
	[channels INT]		# Restrict only to the given channels
Packit Service db8eaa
	[rate INT]		# Restrict only to the given rate
Packit Service db8eaa
	[chmap MAP]		# Override channel maps; MAP is a string array
Packit Service db8eaa
}
Packit Service db8eaa
\endcode
Packit Service db8eaa
Packit Service db8eaa
\subsection pcm_plugins_hw_funcref Function reference
Packit Service db8eaa
Packit Service db8eaa
    Packit Service db8eaa
      
  • snd_pcm_hw_open()
  • Packit Service db8eaa
      
  • _snd_pcm_hw_open()
  • Packit Service db8eaa
    Packit Service db8eaa
    Packit Service db8eaa
    */
    Packit Service db8eaa
    Packit Service db8eaa
    /**
    Packit Service db8eaa
     * \brief Creates a new hw PCM
    Packit Service db8eaa
     * \param pcmp Returns created PCM handle
    Packit Service db8eaa
     * \param name Name of PCM
    Packit Service db8eaa
     * \param root Root configuration node
    Packit Service db8eaa
     * \param conf Configuration node with hw PCM description
    Packit Service db8eaa
     * \param stream PCM Stream
    Packit Service db8eaa
     * \param mode PCM Mode
    Packit Service db8eaa
     * \warning Using of this function might be dangerous in the sense
    Packit Service db8eaa
     *          of compatibility reasons. The prototype might be freely
    Packit Service db8eaa
     *          changed in future.
    Packit Service db8eaa
     */
    Packit Service db8eaa
    int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
    Packit Service db8eaa
    		     snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
    Packit Service db8eaa
    		     snd_pcm_stream_t stream, int mode)
    Packit Service db8eaa
    {
    Packit Service db8eaa
    	snd_config_iterator_t i, next;
    Packit Service db8eaa
    	long card = -1, device = 0, subdevice = -1;
    Packit Service db8eaa
    	const char *str;
    Packit Service db8eaa
    	int err, sync_ptr_ioctl = 0;
    Packit Service db8eaa
    	int rate = 0, channels = 0;
    Packit Service db8eaa
    	snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
    Packit Service db8eaa
    	snd_config_t *n;
    Packit Service db8eaa
    	int nonblock = 1; /* non-block per default */
    Packit Service db8eaa
    	snd_pcm_chmap_query_t **chmap = NULL;
    Packit Service db8eaa
    	snd_pcm_hw_t *hw;
    Packit Service db8eaa
    Packit Service db8eaa
    	/* look for defaults.pcm.nonblock definition */
    Packit Service db8eaa
    	if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) {
    Packit Service db8eaa
    		err = snd_config_get_bool(n);
    Packit Service db8eaa
    		if (err >= 0)
    Packit Service db8eaa
    			nonblock = err;
    Packit Service db8eaa
    	}
    Packit Service db8eaa
    	snd_config_for_each(i, next, conf) {
    Packit Service db8eaa
    		const char *id;
    Packit Service db8eaa
    		n = snd_config_iterator_entry(i);
    Packit Service db8eaa
    		if (snd_config_get_id(n, &id) < 0)
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		if (snd_pcm_conf_generic_id(id))
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		if (strcmp(id, "card") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_integer(n, &card;;
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				err = snd_config_get_string(n, &str);
    Packit Service db8eaa
    				if (err < 0) {
    Packit Service db8eaa
    					SNDERR("Invalid type for %s", id);
    Packit Service db8eaa
    					err = -EINVAL;
    Packit Service db8eaa
    					goto fail;
    Packit Service db8eaa
    				}
    Packit Service db8eaa
    				card = snd_card_get_index(str);
    Packit Service db8eaa
    				if (card < 0) {
    Packit Service db8eaa
    					SNDERR("Invalid value for %s", id);
    Packit Service db8eaa
    					err = card;
    Packit Service db8eaa
    					goto fail;
    Packit Service db8eaa
    				}
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "device") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_integer(n, &device);
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				SNDERR("Invalid type for %s", id);
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "subdevice") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_integer(n, &subdevice);
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				SNDERR("Invalid type for %s", id);
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "sync_ptr_ioctl") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_bool(n);
    Packit Service db8eaa
    			if (err < 0)
    Packit Service db8eaa
    				continue;
    Packit Service db8eaa
    			sync_ptr_ioctl = err;
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "nonblock") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_bool(n);
    Packit Service db8eaa
    			if (err < 0)
    Packit Service db8eaa
    				continue;
    Packit Service db8eaa
    			nonblock = err;
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "rate") == 0) {
    Packit Service db8eaa
    			long val;
    Packit Service db8eaa
    			err = snd_config_get_integer(n, &val;;
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				SNDERR("Invalid type for %s", id);
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			rate = val;
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "format") == 0) {
    Packit Service db8eaa
    			err = snd_config_get_string(n, &str);
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				SNDERR("invalid type for %s", id);
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			format = snd_pcm_format_value(str);
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "channels") == 0) {
    Packit Service db8eaa
    			long val;
    Packit Service db8eaa
    			err = snd_config_get_integer(n, &val;;
    Packit Service db8eaa
    			if (err < 0) {
    Packit Service db8eaa
    				SNDERR("Invalid type for %s", id);
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			channels = val;
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		if (strcmp(id, "chmap") == 0) {
    Packit Service db8eaa
    			snd_pcm_free_chmaps(chmap);
    Packit Service db8eaa
    			chmap = _snd_pcm_parse_config_chmaps(n);
    Packit Service db8eaa
    			if (!chmap) {
    Packit Service db8eaa
    				SNDERR("Invalid channel map for %s", id);
    Packit Service db8eaa
    				err = -EINVAL;
    Packit Service db8eaa
    				goto fail;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    			continue;
    Packit Service db8eaa
    		}
    Packit Service db8eaa
    		SNDERR("Unknown field %s", id);
    Packit Service db8eaa
    		err = -EINVAL;
    Packit Service db8eaa
    		goto fail;
    Packit Service db8eaa
    	}
    Packit Service db8eaa
    	if (card < 0) {
    Packit Service db8eaa
    		SNDERR("card is not defined");
    Packit Service db8eaa
    		err = -EINVAL;
    Packit Service db8eaa
    		goto fail;
    Packit Service db8eaa
    	}
    Packit Service db8eaa
    	err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
    Packit Service db8eaa
    			      mode | (nonblock ? SND_PCM_NONBLOCK : 0),
    Packit Service db8eaa
    			      0, sync_ptr_ioctl);
    Packit Service db8eaa
    	if (err < 0)
    Packit Service db8eaa
    		goto fail;
    Packit Service db8eaa
    	if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
    Packit Service db8eaa
    		/* revert to blocking mode for read/write access */
    Packit Service db8eaa
    		snd_pcm_hw_nonblock(*pcmp, 0);
    Packit Service db8eaa
    		(*pcmp)->mode = mode;
    Packit Service db8eaa
    	} else
    Packit Service db8eaa
    		/* make sure the SND_PCM_NO_xxx flags don't get lost on the
    Packit Service db8eaa
    		 * way */
    Packit Service db8eaa
    		(*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE|
    Packit Service db8eaa
    					 SND_PCM_NO_AUTO_CHANNELS|
    Packit Service db8eaa
    					 SND_PCM_NO_AUTO_FORMAT|
    Packit Service db8eaa
    					 SND_PCM_NO_SOFTVOL);
    Packit Service db8eaa
    Packit Service db8eaa
    	hw = (*pcmp)->private_data;
    Packit Service db8eaa
    	if (format != SND_PCM_FORMAT_UNKNOWN)
    Packit Service db8eaa
    		hw->format = format;
    Packit Service db8eaa
    	if (channels > 0)
    Packit Service db8eaa
    		hw->channels = channels;
    Packit Service db8eaa
    	if (rate > 0)
    Packit Service db8eaa
    		hw->rate = rate;
    Packit Service db8eaa
    	if (chmap)
    Packit Service db8eaa
    		hw->chmap_override = chmap;
    Packit Service db8eaa
    Packit Service db8eaa
    	return 0;
    Packit Service db8eaa
    Packit Service db8eaa
    fail:
    Packit Service db8eaa
            snd_pcm_free_chmaps(chmap);
    Packit Service db8eaa
            return err;
    Packit Service db8eaa
    }
    Packit Service db8eaa
    Packit Service db8eaa
    #ifndef DOC_HIDDEN
    Packit Service db8eaa
    SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
    Packit Service db8eaa
    #endif
    Packit Service db8eaa
    Packit Service db8eaa
    /*
    Packit Service db8eaa
     *  To be removed helpers, but keep binary compatibility at the time
    Packit Service db8eaa
     */
    Packit Service db8eaa
    Packit Service db8eaa
    #ifndef DOC_HIDDEN
    Packit Service db8eaa
    #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
    Packit Service db8eaa
    #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
    Packit Service db8eaa
    #endif
    Packit Service db8eaa
    Packit Service db8eaa
    static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
    Packit Service db8eaa
    					       struct sndrv_pcm_hw_params_old *oparams)
    Packit Service db8eaa
    {
    Packit Service db8eaa
    	unsigned int i;
    Packit Service db8eaa
    Packit Service db8eaa
    	memset(params, 0, sizeof(*params));
    Packit Service db8eaa
    	params->flags = oparams->flags;
    Packit Service db8eaa
    	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
    Packit Service db8eaa
    		params->masks[i].bits[0] = oparams->masks[i];
    Packit Service db8eaa
    	memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
    Packit Service db8eaa
    	params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
    Packit Service db8eaa
    	params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
    Packit Service db8eaa
    	params->info = oparams->info;
    Packit Service db8eaa
    	params->msbits = oparams->msbits;
    Packit Service db8eaa
    	params->rate_num = oparams->rate_num;
    Packit Service db8eaa
    	params->rate_den = oparams->rate_den;
    Packit Service db8eaa
    	params->fifo_size = oparams->fifo_size;
    Packit Service db8eaa
    }
    Packit Service db8eaa
    Packit Service db8eaa
    static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
    Packit Service db8eaa
    					     snd_pcm_hw_params_t *params,
    Packit Service db8eaa
    					     unsigned int *cmask)
    Packit Service db8eaa
    {
    Packit Service db8eaa
    	unsigned int i, j;
    Packit Service db8eaa
    Packit Service db8eaa
    	memset(oparams, 0, sizeof(*oparams));
    Packit Service db8eaa
    	oparams->flags = params->flags;
    Packit Service db8eaa
    	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
    Packit Service db8eaa
    		oparams->masks[i] = params->masks[i].bits[0];
    Packit Service db8eaa
    		for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
    Packit Service db8eaa
    			if (params->masks[i].bits[j]) {
    Packit Service db8eaa
    				*cmask |= 1 << i;
    Packit Service db8eaa
    				break;
    Packit Service db8eaa
    			}
    Packit Service db8eaa
    	}
    Packit Service db8eaa
    	memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
    Packit Service db8eaa
    	oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
    Packit Service db8eaa
    	oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
    Packit Service db8eaa
    	oparams->info = params->info;
    Packit Service db8eaa
    	oparams->msbits = params->msbits;
    Packit Service db8eaa
    	oparams->rate_num = params->rate_num;
    Packit Service db8eaa
    	oparams->rate_den = params->rate_den;
    Packit Service db8eaa
    	oparams->fifo_size = params->fifo_size;
    Packit Service db8eaa
    }
    Packit Service db8eaa
    Packit Service db8eaa
    static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
    Packit Service db8eaa
    {
    Packit Service db8eaa
    	struct sndrv_pcm_hw_params_old oparams;
    Packit Service db8eaa
    	unsigned int cmask = 0;
    Packit Service db8eaa
    	int res;
    Packit Service db8eaa
    	
    Packit Service db8eaa
    	snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
    Packit Service db8eaa
    	res = ioctl(fd, cmd, &oparams);
    Packit Service db8eaa
    	snd_pcm_hw_convert_from_old_params(params, &oparams);
    Packit Service db8eaa
    	params->cmask |= cmask;
    Packit Service db8eaa
    	return res;
    Packit Service db8eaa
    }