Blame src/control/hcontrol.c

Packit Service db8eaa
/**
Packit Service db8eaa
 * \file control/hcontrol.c
Packit Service db8eaa
 * \brief HCTL Interface - High Level CTL
Packit Service db8eaa
 * \author Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 * \author Abramo Bagnara <abramo@alsa-project.org>
Packit Service db8eaa
 * \date 2000
Packit Service db8eaa
 *
Packit Service db8eaa
 * HCTL interface is designed to access preloaded and sorted primitive controls.
Packit Service db8eaa
 * Callbacks may be used for event handling.
Packit Service db8eaa
 * See \ref hcontrol page for more details.
Packit Service db8eaa
 */
Packit Service db8eaa
/*
Packit Service db8eaa
 *  Control Interface - high level API
Packit Service db8eaa
 *  Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 *  Copyright (c) 2001 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
/*! \page hcontrol High level control interface
Packit Service db8eaa
Packit Service db8eaa

High level control interface is designed to access preloaded and sorted primitive controls.

Packit Service db8eaa
Packit Service db8eaa
\section hcontrol_general_overview General overview
Packit Service db8eaa
Packit Service db8eaa

High level control interface caches the accesses to primitive controls

Packit Service db8eaa
to reduce overhead accessing the real controls in kernel drivers.
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 <unistd.h>
Packit Service db8eaa
#include <string.h>
Packit Service db8eaa
#include <fcntl.h>
Packit Service db8eaa
#include <sys/ioctl.h>
Packit Service db8eaa
#include "control_local.h"
Packit Service db8eaa
#ifdef HAVE_LIBPTHREAD
Packit Service db8eaa
#include <pthread.h>
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
#define NOT_FOUND 1000000000
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
Packit Service db8eaa
				    const snd_hctl_elem_t *c2);
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Opens an HCTL
Packit Service db8eaa
 * \param hctlp Returned HCTL handle
Packit Service db8eaa
 * \param name ASCII identifier of the underlying CTL handle
Packit Service db8eaa
 * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_t *ctl;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	
Packit Service db8eaa
	if ((err = snd_ctl_open(&ctl, name, mode)) < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	err = snd_hctl_open_ctl(hctlp, ctl);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		snd_ctl_close(ctl);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Opens an HCTL
Packit Service db8eaa
 * \param hctlp Returned HCTL handle
Packit Service db8eaa
 * \param ctl underlying CTL handle
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_hctl_t *hctl;
Packit Service db8eaa
Packit Service db8eaa
	assert(hctlp);
Packit Service db8eaa
	*hctlp = NULL;
Packit Service db8eaa
	if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	INIT_LIST_HEAD(&hctl->elems);
Packit Service db8eaa
	hctl->ctl = ctl;
Packit Service db8eaa
	*hctlp = hctl;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief close HCTL handle
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Closes the specified HCTL handle and frees all associated
Packit Service db8eaa
 * resources.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_close(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	err = snd_ctl_close(hctl->ctl);
Packit Service db8eaa
	snd_hctl_free(hctl);
Packit Service db8eaa
	free(hctl);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get identifier of HCTL handle
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return ascii identifier of HCTL handle
Packit Service db8eaa
 *
Packit Service db8eaa
 * Returns the ASCII identifier of given HCTL handle. It's the same
Packit Service db8eaa
 * identifier specified in snd_hctl_open().
Packit Service db8eaa
 */
Packit Service db8eaa
const char *snd_hctl_name(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_name(hctl->ctl);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief set nonblock mode
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param nonblock 0 = block, 1 = nonblock mode
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_nonblock(hctl->ctl, nonblock);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief set async mode
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param sig Signal to raise: < 0 disable, 0 default (SIGIO)
Packit Service db8eaa
 * \param pid Process ID to signal: 0 current
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * A signal is raised when a change happens.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_async(hctl->ctl, sig, pid);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get count of poll descriptors for HCTL handle
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return count of poll descriptors
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_poll_descriptors_count(hctl->ctl);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get poll descriptors
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param pfds array of poll descriptors
Packit Service db8eaa
 * \param space space in the poll descriptor array
Packit Service db8eaa
 * \return count of filled descriptors
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_poll_descriptors(hctl->ctl, pfds, space);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get returned events from poll descriptors
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param pfds array of poll descriptors
Packit Service db8eaa
 * \param nfds count of poll descriptors
Packit Service db8eaa
 * \param revents returned events
Packit Service db8eaa
 * \return zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask,
Packit Service db8eaa
			 snd_hctl_elem_t *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	if (hctl->callback)
Packit Service db8eaa
		return hctl->callback(hctl, mask, elem);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem,
Packit Service db8eaa
			      unsigned int mask)
Packit Service db8eaa
{
Packit Service db8eaa
	if (elem->callback)
Packit Service db8eaa
		return elem->callback(elem, mask);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef)
Packit Service db8eaa
{
Packit Service db8eaa
	int res;
Packit Service db8eaa
Packit Service db8eaa
	for (res = 0; *names; names++, res += coef) {
Packit Service db8eaa
		if (!strncmp(*name, *names, strlen(*names))) {
Packit Service db8eaa
			*name += strlen(*names);
Packit Service db8eaa
			if (**name == ' ')
Packit Service db8eaa
				(*name)++;
Packit Service db8eaa
			return res+1;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return NOT_FOUND;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int get_compare_weight(const snd_ctl_elem_id_t *id)
Packit Service db8eaa
{
Packit Service db8eaa
	static const char *const names[] = {
Packit Service db8eaa
		"Master",
Packit Service db8eaa
		"Hardware Master",
Packit Service db8eaa
		"Headphone",
Packit Service db8eaa
		"Tone Control",
Packit Service db8eaa
		"3D Control",
Packit Service db8eaa
		"PCM",
Packit Service db8eaa
		"Front",
Packit Service db8eaa
		"Surround",
Packit Service db8eaa
		"Center",
Packit Service db8eaa
		"LFE",
Packit Service db8eaa
		"Synth",
Packit Service db8eaa
		"FM",
Packit Service db8eaa
		"Wave",
Packit Service db8eaa
		"Music",
Packit Service db8eaa
		"DSP",
Packit Service db8eaa
		"Line",
Packit Service db8eaa
		"CD",
Packit Service db8eaa
		"Mic",
Packit Service db8eaa
		"Phone",
Packit Service db8eaa
		"Video",
Packit Service db8eaa
		"Zoom Video",
Packit Service db8eaa
		"PC Speaker",
Packit Service db8eaa
		"Aux",
Packit Service db8eaa
		"Mono",
Packit Service db8eaa
		"ADC",
Packit Service db8eaa
		"Capture Source",
Packit Service db8eaa
		"Capture",
Packit Service db8eaa
		"Playback",
Packit Service db8eaa
		"Loopback",
Packit Service db8eaa
		"Analog Loopback",
Packit Service db8eaa
		"Digital Loopback",
Packit Service db8eaa
		"I2S",
Packit Service db8eaa
		"IEC958",
Packit Service db8eaa
		NULL
Packit Service db8eaa
	};
Packit Service db8eaa
	static const char *const names1[] = {
Packit Service db8eaa
		"Switch",
Packit Service db8eaa
		"Volume",
Packit Service db8eaa
		"Playback",
Packit Service db8eaa
		"Capture",
Packit Service db8eaa
		"Bypass",
Packit Service db8eaa
		"Mono",
Packit Service db8eaa
		"Front",
Packit Service db8eaa
		"Rear",
Packit Service db8eaa
		"Pan",
Packit Service db8eaa
		"Output",
Packit Service db8eaa
		"-",
Packit Service db8eaa
		NULL
Packit Service db8eaa
	};
Packit Service db8eaa
	static const char *const names2[] = {
Packit Service db8eaa
		"Switch",
Packit Service db8eaa
		"Volume",
Packit Service db8eaa
		"Bypass",
Packit Service db8eaa
		"Depth",
Packit Service db8eaa
		"Wide",
Packit Service db8eaa
		"Space",
Packit Service db8eaa
		"Level",
Packit Service db8eaa
		"Center",
Packit Service db8eaa
		NULL
Packit Service db8eaa
	};
Packit Service db8eaa
	const char *name = (char *)id->name, *name1;
Packit Service db8eaa
	int res, res1;
Packit Service db8eaa
	
Packit Service db8eaa
	if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND)
Packit Service db8eaa
		return NOT_FOUND;
Packit Service db8eaa
	if (*name == '\0')
Packit Service db8eaa
		return res;
Packit Service db8eaa
	for (name1 = name; *name1 != '\0'; name1++);
Packit Service db8eaa
	for (name1--; name1 != name && *name1 != ' '; name1--);
Packit Service db8eaa
	while (name1 != name && *name1 == ' ')
Packit Service db8eaa
		name1--;
Packit Service db8eaa
	if (name1 != name) {
Packit Service db8eaa
		for (; name1 != name && *name1 != ' '; name1--);
Packit Service db8eaa
		name = name1;
Packit Service db8eaa
		if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND)
Packit Service db8eaa
			return res;
Packit Service db8eaa
		res += res1;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		name = name1;
Packit Service db8eaa
	}
Packit Service db8eaa
	if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND)
Packit Service db8eaa
		return res;
Packit Service db8eaa
	return res + res1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int l, u;
Packit Service db8eaa
	snd_hctl_elem_t el;
Packit Service db8eaa
	int c = 0;
Packit Service db8eaa
	int idx = -1;
Packit Service db8eaa
	assert(hctl && id);
Packit Service db8eaa
	assert(hctl->compare);
Packit Service db8eaa
	el.id = *id;
Packit Service db8eaa
	el.compare_weight = get_compare_weight(id);
Packit Service db8eaa
	l = 0;
Packit Service db8eaa
	u = hctl->count;
Packit Service db8eaa
	while (l < u) {
Packit Service db8eaa
		idx = (l + u) / 2;
Packit Service db8eaa
		c = hctl->compare(&el, hctl->pelems[idx]);
Packit Service db8eaa
		if (c < 0)
Packit Service db8eaa
			u = idx;
Packit Service db8eaa
		else if (c > 0)
Packit Service db8eaa
			l = idx + 1;
Packit Service db8eaa
		else
Packit Service db8eaa
			break;
Packit Service db8eaa
	}
Packit Service db8eaa
	*dir = c;
Packit Service db8eaa
	return idx;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	int dir;
Packit Service db8eaa
	int idx; 
Packit Service db8eaa
	elem->compare_weight = get_compare_weight(&elem->id);
Packit Service db8eaa
	if (hctl->count == hctl->alloc) {
Packit Service db8eaa
		snd_hctl_elem_t **h;
Packit Service db8eaa
		hctl->alloc += 32;
Packit Service db8eaa
		h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc);
Packit Service db8eaa
		if (!h) {
Packit Service db8eaa
			hctl->alloc -= 32;
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
		}
Packit Service db8eaa
		hctl->pelems = h;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (hctl->count == 0) {
Packit Service db8eaa
		list_add_tail(&elem->list, &hctl->elems);
Packit Service db8eaa
		hctl->pelems[0] = elem;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		idx = _snd_hctl_find_elem(hctl, &elem->id, &dir;;
Packit Service db8eaa
		assert(dir != 0);
Packit Service db8eaa
		if (dir > 0) {
Packit Service db8eaa
			list_add(&elem->list, &hctl->pelems[idx]->list);
Packit Service db8eaa
			idx++;
Packit Service db8eaa
		} else {
Packit Service db8eaa
			list_add_tail(&elem->list, &hctl->pelems[idx]->list);
Packit Service db8eaa
		}
Packit Service db8eaa
		memmove(hctl->pelems + idx + 1,
Packit Service db8eaa
			hctl->pelems + idx,
Packit Service db8eaa
			(hctl->count - idx) * sizeof(snd_hctl_elem_t *));
Packit Service db8eaa
		hctl->pelems[idx] = elem;
Packit Service db8eaa
	}
Packit Service db8eaa
	hctl->count++;
Packit Service db8eaa
	return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_hctl_elem_t *elem = hctl->pelems[idx];
Packit Service db8eaa
	unsigned int m;
Packit Service db8eaa
	snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE);
Packit Service db8eaa
	list_del(&elem->list);
Packit Service db8eaa
	free(elem);
Packit Service db8eaa
	hctl->count--;
Packit Service db8eaa
	m = hctl->count - idx;
Packit Service db8eaa
	if (m > 0)
Packit Service db8eaa
		memmove(hctl->pelems + idx,
Packit Service db8eaa
			hctl->pelems + idx + 1,
Packit Service db8eaa
			m * sizeof(snd_hctl_elem_t *));
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief free HCTL loaded elements
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_free(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	while (hctl->count > 0)
Packit Service db8eaa
		snd_hctl_elem_remove(hctl, hctl->count - 1);
Packit Service db8eaa
	free(hctl->pelems);
Packit Service db8eaa
	hctl->pelems = 0;
Packit Service db8eaa
	hctl->alloc = 0;
Packit Service db8eaa
	INIT_LIST_HEAD(&hctl->elems);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_hctl_t *compare_hctl;
Packit Service db8eaa
static int hctl_compare(const void *a, const void *b) {
Packit Service db8eaa
	return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a,
Packit Service db8eaa
			     *(const snd_hctl_elem_t * const *) b);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void snd_hctl_sort(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int k;
Packit Service db8eaa
#ifdef HAVE_LIBPTHREAD
Packit Service db8eaa
	static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	assert(hctl->compare);
Packit Service db8eaa
	INIT_LIST_HEAD(&hctl->elems);
Packit Service db8eaa
Packit Service db8eaa
#ifdef HAVE_LIBPTHREAD
Packit Service db8eaa
	pthread_mutex_lock(&sync_lock);
Packit Service db8eaa
#endif
Packit Service db8eaa
	compare_hctl = hctl;
Packit Service db8eaa
	qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare);
Packit Service db8eaa
#ifdef HAVE_LIBPTHREAD
Packit Service db8eaa
	pthread_mutex_unlock(&sync_lock);
Packit Service db8eaa
#endif
Packit Service db8eaa
	for (k = 0; k < hctl->count; k++)
Packit Service db8eaa
		list_add_tail(&hctl->pelems[k]->list, &hctl->elems);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Change HCTL compare function and reorder elements
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param compare Element compare function
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	hctl->compare = compare == NULL ? snd_hctl_compare_default : compare;
Packit Service db8eaa
	snd_hctl_sort(hctl);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare
Packit Service db8eaa
 * \param c1 First HCTL element
Packit Service db8eaa
 * \param c2 Second HCTL element
Packit Service db8eaa
 * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_compare_fast(const snd_hctl_elem_t *c1,
Packit Service db8eaa
			  const snd_hctl_elem_t *c2)
Packit Service db8eaa
{
Packit Service db8eaa
	return c1->id.numid - c2->id.numid;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
Packit Service db8eaa
				    const snd_hctl_elem_t *c2)
Packit Service db8eaa
{
Packit Service db8eaa
	int res, d;
Packit Service db8eaa
Packit Service db8eaa
	d = c1->id.iface - c2->id.iface;
Packit Service db8eaa
	if (d != 0)
Packit Service db8eaa
		return d;
Packit Service db8eaa
	if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) {
Packit Service db8eaa
		d = c1->compare_weight - c2->compare_weight;
Packit Service db8eaa
		if (d != 0)
Packit Service db8eaa
			return d;
Packit Service db8eaa
	}
Packit Service db8eaa
	d = c1->id.device - c2->id.device;
Packit Service db8eaa
	if (d != 0)
Packit Service db8eaa
		return d;
Packit Service db8eaa
	d = c1->id.subdevice - c2->id.subdevice;
Packit Service db8eaa
	if (d != 0)
Packit Service db8eaa
		return d;
Packit Service db8eaa
	res = strcmp((const char *)c1->id.name, (const char *)c2->id.name);
Packit Service db8eaa
	if (res != 0)
Packit Service db8eaa
		return res;
Packit Service db8eaa
	return c1->id.index - c2->id.index;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get first element for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return pointer to first element
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	if (list_empty(&hctl->elems))
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	return list_entry(hctl->elems.next, snd_hctl_elem_t, list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get last element for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return pointer to last element
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	if (list_empty(&hctl->elems))
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	return list_entry(hctl->elems.prev, snd_hctl_elem_t, list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get next HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \return pointer to next element
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	if (elem->list.next == &elem->hctl->elems)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	return list_entry(elem->list.next, snd_hctl_elem_t, list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief get previous HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \return pointer to previous element
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	if (elem->list.prev == &elem->hctl->elems)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	return list_entry(elem->list.prev, snd_hctl_elem_t, list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Search an HCTL element
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param id Element identifier
Packit Service db8eaa
 * \return pointer to found HCTL element or NULL if it does not exists
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id)
Packit Service db8eaa
{
Packit Service db8eaa
	int dir;
Packit Service db8eaa
	int res = _snd_hctl_find_elem(hctl, id, &dir;;
Packit Service db8eaa
	if (res < 0 || dir != 0)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	return hctl->pelems[res];
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Load an HCTL with all elements and sort them
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return 0 on success otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_load(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_elem_list_t list;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
	unsigned int idx;
Packit Service db8eaa
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	assert(hctl->ctl);
Packit Service db8eaa
	assert(hctl->count == 0);
Packit Service db8eaa
	assert(list_empty(&hctl->elems));
Packit Service db8eaa
	memset(&list, 0, sizeof(list));
Packit Service db8eaa
	if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
Packit Service db8eaa
		goto _end;
Packit Service db8eaa
	while (list.count != list.used) {
Packit Service db8eaa
		err = snd_ctl_elem_list_alloc_space(&list, list.count);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto _end;
Packit Service db8eaa
		if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
Packit Service db8eaa
			goto _end;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (hctl->alloc < list.count) {
Packit Service db8eaa
		hctl->alloc = list.count;
Packit Service db8eaa
		free(hctl->pelems);
Packit Service db8eaa
		hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems));
Packit Service db8eaa
		if (!hctl->pelems) {
Packit Service db8eaa
			err = -ENOMEM;
Packit Service db8eaa
			goto _end;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	for (idx = 0; idx < list.count; idx++) {
Packit Service db8eaa
		snd_hctl_elem_t *elem;
Packit Service db8eaa
		elem = calloc(1, sizeof(snd_hctl_elem_t));
Packit Service db8eaa
		if (elem == NULL) {
Packit Service db8eaa
			snd_hctl_free(hctl);
Packit Service db8eaa
			err = -ENOMEM;
Packit Service db8eaa
			goto _end;
Packit Service db8eaa
		}
Packit Service db8eaa
		elem->id = list.pids[idx];
Packit Service db8eaa
		elem->hctl = hctl;
Packit Service db8eaa
		elem->compare_weight = get_compare_weight(&elem->id);
Packit Service db8eaa
		hctl->pelems[idx] = elem;
Packit Service db8eaa
		list_add_tail(&elem->list, &hctl->elems);
Packit Service db8eaa
		hctl->count++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (!hctl->compare)
Packit Service db8eaa
		hctl->compare = snd_hctl_compare_default;
Packit Service db8eaa
	snd_hctl_sort(hctl);
Packit Service db8eaa
	for (idx = 0; idx < hctl->count; idx++) {
Packit Service db8eaa
		int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD,
Packit Service db8eaa
					       hctl->pelems[idx]);
Packit Service db8eaa
		if (res < 0)
Packit Service db8eaa
			return res;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = snd_ctl_subscribe_events(hctl->ctl, 1);
Packit Service db8eaa
 _end:
Packit Service db8eaa
	free(list.pids);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set callback function for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param callback callback function
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	hctl->callback = callback;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set callback private value for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param callback_private callback private value
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	hctl->callback_private = callback_private;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get callback private value for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return callback private value
Packit Service db8eaa
 */
Packit Service db8eaa
void *snd_hctl_get_callback_private(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	return hctl->callback_private;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get number of loaded elements for an HCTL
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return elements count
Packit Service db8eaa
 */
Packit Service db8eaa
unsigned int snd_hctl_get_count(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	return hctl->count;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Wait for a HCTL to become ready (i.e. at least one event pending)
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \param timeout maximum time in milliseconds to wait
Packit Service db8eaa
 * \return a positive value on success otherwise a negative error code
Packit Service db8eaa
 * \retval 0 timeout occurred
Packit Service db8eaa
 * \retval 1 an event is pending
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_wait(snd_hctl_t *hctl, int timeout)
Packit Service db8eaa
{
Packit Service db8eaa
	struct pollfd *pfd;
Packit Service db8eaa
	unsigned short *revents;
Packit Service db8eaa
	int i, npfds, pollio, err, err_poll;
Packit Service db8eaa
	
Packit Service db8eaa
	npfds = snd_hctl_poll_descriptors_count(hctl);
Packit Service db8eaa
	if (npfds <= 0 || npfds >= 16) {
Packit Service db8eaa
		SNDERR("Invalid poll_fds %d\n", npfds);
Packit Service db8eaa
		return -EIO;
Packit Service db8eaa
	}
Packit Service db8eaa
	pfd = alloca(sizeof(*pfd) * npfds);
Packit Service db8eaa
	revents = alloca(sizeof(*revents) * npfds);
Packit Service db8eaa
	err = snd_hctl_poll_descriptors(hctl, pfd, npfds);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	if (err != npfds) {
Packit Service db8eaa
		SNDMSG("invalid poll descriptors %d\n", err);
Packit Service db8eaa
		return -EIO;
Packit Service db8eaa
	}
Packit Service db8eaa
	do {
Packit Service db8eaa
		pollio = 0;
Packit Service db8eaa
		err_poll = poll(pfd, npfds, timeout);
Packit Service db8eaa
		if (err_poll < 0) {
Packit Service db8eaa
			if (errno == EINTR && !CTLINABORT(hctl->ctl))
Packit Service db8eaa
				continue;
Packit Service db8eaa
			return -errno;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (! err_poll)
Packit Service db8eaa
			break;
Packit Service db8eaa
		err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		for (i = 0; i < npfds; i++) {
Packit Service db8eaa
			if (revents[i] & (POLLERR | POLLNVAL))
Packit Service db8eaa
				return -EIO;
Packit Service db8eaa
			if ((revents[i] & (POLLIN | POLLOUT)) == 0)
Packit Service db8eaa
				continue;
Packit Service db8eaa
			pollio++;
Packit Service db8eaa
		}
Packit Service db8eaa
	} while (! pollio);
Packit Service db8eaa
	return err_poll > 0 ? 1 : 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get a ctl handle associated to the given hctl handle
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return a ctl handle otherwise NULL
Packit Service db8eaa
 */
Packit Service db8eaa
snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	return hctl->ctl;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_hctl_elem_t *elem;
Packit Service db8eaa
	int res;
Packit Service db8eaa
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	assert(hctl->ctl);
Packit Service db8eaa
	switch (event->type) {
Packit Service db8eaa
	case SND_CTL_EVENT_ELEM:
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
Packit Service db8eaa
		int dir;
Packit Service db8eaa
		res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir;;
Packit Service db8eaa
		if (res < 0 || dir != 0)
Packit Service db8eaa
			return -ENOENT;
Packit Service db8eaa
		snd_hctl_elem_remove(hctl, (unsigned int) res);
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) {
Packit Service db8eaa
		elem = calloc(1, sizeof(snd_hctl_elem_t));
Packit Service db8eaa
		if (elem == NULL)
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
		elem->id = event->data.elem.id;
Packit Service db8eaa
		elem->hctl = hctl;
Packit Service db8eaa
		res = snd_hctl_elem_add(hctl, elem);
Packit Service db8eaa
		if (res < 0)
Packit Service db8eaa
			return res;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE |
Packit Service db8eaa
				     SNDRV_CTL_EVENT_MASK_INFO)) {
Packit Service db8eaa
		elem = snd_hctl_find_elem(hctl, &event->data.elem.id);
Packit Service db8eaa
		if (!elem)
Packit Service db8eaa
			return -ENOENT;
Packit Service db8eaa
		res = snd_hctl_elem_throw_event(elem, event->data.elem.mask &
Packit Service db8eaa
						(SNDRV_CTL_EVENT_MASK_VALUE |
Packit Service db8eaa
						 SNDRV_CTL_EVENT_MASK_INFO));
Packit Service db8eaa
		if (res < 0)
Packit Service db8eaa
			return res;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Handle pending HCTL events invoking callbacks
Packit Service db8eaa
 * \param hctl HCTL handle
Packit Service db8eaa
 * \return 0 otherwise a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_handle_events(snd_hctl_t *hctl)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_event_t event;
Packit Service db8eaa
	int res;
Packit Service db8eaa
	unsigned int count = 0;
Packit Service db8eaa
	
Packit Service db8eaa
	assert(hctl);
Packit Service db8eaa
	assert(hctl->ctl);
Packit Service db8eaa
	while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 &&
Packit Service db8eaa
	       res != -EAGAIN) {
Packit Service db8eaa
		if (res < 0)
Packit Service db8eaa
			return res;
Packit Service db8eaa
		res = snd_hctl_handle_event(hctl, &event);
Packit Service db8eaa
		if (res < 0)
Packit Service db8eaa
			return res;
Packit Service db8eaa
		count++;
Packit Service db8eaa
	}
Packit Service db8eaa
	return count;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get information for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param info HCTL element information
Packit Service db8eaa
 * \return 0 otherwise a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(elem->hctl);
Packit Service db8eaa
	assert(info);
Packit Service db8eaa
	info->id = elem->id;
Packit Service db8eaa
	return snd_ctl_elem_info(elem->hctl->ctl, info);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get value for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param value HCTL element value
Packit Service db8eaa
 * \return 0 otherwise a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(elem->hctl);
Packit Service db8eaa
	assert(value);
Packit Service db8eaa
	value->id = elem->id;
Packit Service db8eaa
	return snd_ctl_elem_read(elem->hctl->ctl, value);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set value for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param value HCTL element value
Packit Service db8eaa
 * \retval 0 on success
Packit Service db8eaa
 * \retval >1 on success when value was changed
Packit Service db8eaa
 * \retval <0 a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(elem->hctl);
Packit Service db8eaa
	assert(value);
Packit Service db8eaa
	value->id = elem->id;
Packit Service db8eaa
	return snd_ctl_elem_write(elem->hctl->ctl, value);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get TLV value for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param tlv TLV array for value
Packit Service db8eaa
 * \param tlv_size size of TLV array in bytes
Packit Service db8eaa
 * \return 0 otherwise a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(tlv);
Packit Service db8eaa
	assert(tlv_size >= 12);
Packit Service db8eaa
	return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set TLV value for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param tlv TLV array for value
Packit Service db8eaa
 * \retval 0 on success
Packit Service db8eaa
 * \retval >1 on success when value was changed
Packit Service db8eaa
 * \retval <0 a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(tlv);
Packit Service db8eaa
	assert(tlv[SNDRV_CTL_TLVO_LEN] >= 4);
Packit Service db8eaa
	return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set TLV value for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \param tlv TLV array for value
Packit Service db8eaa
 * \retval 0 on success
Packit Service db8eaa
 * \retval >1 on success when value was changed
Packit Service db8eaa
 * \retval <0 a negative error code on failure
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	assert(tlv);
Packit Service db8eaa
	assert(tlv[SNDRV_CTL_TLVO_LEN] >= 4);
Packit Service db8eaa
	return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get HCTL handle for an HCTL element
Packit Service db8eaa
 * \param elem HCTL element
Packit Service db8eaa
 * \return HCTL handle
Packit Service db8eaa
 */
Packit Service db8eaa
snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(elem);
Packit Service db8eaa
	return elem->hctl;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \param ptr Pointer to returned CTL element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj && ptr);
Packit Service db8eaa
	*ptr = obj->id;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get element numeric identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return element numeric identifier
Packit Service db8eaa
 */
Packit Service db8eaa
unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->id.numid;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get interface part of CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return interface part of element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->id.iface;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get device part of CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return device part of element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->id.device;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get subdevice part of CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return subdevice part of element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->id.subdevice;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get name part of CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return name part of element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return (const char *)obj->id.name;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get index part of CTL element identifier of a CTL element id/value
Packit Service db8eaa
 * \param obj CTL element id/value
Packit Service db8eaa
 * \return index part of element identifier
Packit Service db8eaa
 */
Packit Service db8eaa
unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->id.index;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set callback function for an HCTL element
Packit Service db8eaa
 * \param obj HCTL element
Packit Service db8eaa
 * \param val callback function
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	obj->callback = val;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set callback private value for an HCTL element
Packit Service db8eaa
 * \param obj HCTL element
Packit Service db8eaa
 * \param val callback private value
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	obj->callback_private = val;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get callback private value for an HCTL element
Packit Service db8eaa
 * \param obj HCTL element
Packit Service db8eaa
 * \return callback private value
Packit Service db8eaa
 */
Packit Service db8eaa
void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	assert(obj);
Packit Service db8eaa
	return obj->callback_private;
Packit Service db8eaa
}
Packit Service db8eaa