1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file mixer/mixer.c
3d5ac70f0Sopenharmony_ci * \brief Mixer Interface
4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz>
5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org>
6d5ac70f0Sopenharmony_ci * \date 2001
7d5ac70f0Sopenharmony_ci *
8d5ac70f0Sopenharmony_ci * Mixer interface is designed to access mixer elements.
9d5ac70f0Sopenharmony_ci * Callbacks may be used for event handling.
10d5ac70f0Sopenharmony_ci */
11d5ac70f0Sopenharmony_ci/*
12d5ac70f0Sopenharmony_ci *  Mixer Interface - main file
13d5ac70f0Sopenharmony_ci *  Copyright (c) 1998/1999/2000 by Jaroslav Kysela <perex@perex.cz>
14d5ac70f0Sopenharmony_ci *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
15d5ac70f0Sopenharmony_ci *
16d5ac70f0Sopenharmony_ci *
17d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
18d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
19d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
20d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
21d5ac70f0Sopenharmony_ci *
22d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
23d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
24d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
26d5ac70f0Sopenharmony_ci *
27d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
28d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
29d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
30d5ac70f0Sopenharmony_ci *
31d5ac70f0Sopenharmony_ci */
32d5ac70f0Sopenharmony_ci
33d5ac70f0Sopenharmony_ci/*! \page mixer Mixer interface
34d5ac70f0Sopenharmony_ci
35d5ac70f0Sopenharmony_ci<P>Mixer interface is designed to access the abstracted mixer controls.
36d5ac70f0Sopenharmony_ciThis is an abstraction layer over the hcontrol layer.
37d5ac70f0Sopenharmony_ci
38d5ac70f0Sopenharmony_ci\section mixer_general_overview General overview
39d5ac70f0Sopenharmony_ci
40d5ac70f0Sopenharmony_ci*/
41d5ac70f0Sopenharmony_ci
42d5ac70f0Sopenharmony_ci#include "mixer_local.h"
43d5ac70f0Sopenharmony_ci#include <stdio.h>
44d5ac70f0Sopenharmony_ci#include <stdlib.h>
45d5ac70f0Sopenharmony_ci#include <unistd.h>
46d5ac70f0Sopenharmony_ci#include <string.h>
47d5ac70f0Sopenharmony_ci#include <fcntl.h>
48d5ac70f0Sopenharmony_ci#include <sys/ioctl.h>
49d5ac70f0Sopenharmony_ci
50d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
51d5ac70f0Sopenharmony_citypedef struct _snd_mixer_slave {
52d5ac70f0Sopenharmony_ci	snd_hctl_t *hctl;
53d5ac70f0Sopenharmony_ci	struct list_head list;
54d5ac70f0Sopenharmony_ci} snd_mixer_slave_t;
55d5ac70f0Sopenharmony_ci
56d5ac70f0Sopenharmony_ci#endif
57d5ac70f0Sopenharmony_ci
58d5ac70f0Sopenharmony_cistatic int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
59d5ac70f0Sopenharmony_ci				     const snd_mixer_elem_t *c2);
60d5ac70f0Sopenharmony_ci
61d5ac70f0Sopenharmony_ci
62d5ac70f0Sopenharmony_ci/**
63d5ac70f0Sopenharmony_ci * \brief Opens an empty mixer
64d5ac70f0Sopenharmony_ci * \param mixerp Returned mixer handle
65d5ac70f0Sopenharmony_ci * \param mode Open mode
66d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
67d5ac70f0Sopenharmony_ci */
68d5ac70f0Sopenharmony_ciint snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED)
69d5ac70f0Sopenharmony_ci{
70d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer;
71d5ac70f0Sopenharmony_ci	assert(mixerp);
72d5ac70f0Sopenharmony_ci	mixer = calloc(1, sizeof(*mixer));
73d5ac70f0Sopenharmony_ci	if (mixer == NULL)
74d5ac70f0Sopenharmony_ci		return -ENOMEM;
75d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&mixer->slaves);
76d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&mixer->classes);
77d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&mixer->elems);
78d5ac70f0Sopenharmony_ci	mixer->compare = snd_mixer_compare_default;
79d5ac70f0Sopenharmony_ci	*mixerp = mixer;
80d5ac70f0Sopenharmony_ci	return 0;
81d5ac70f0Sopenharmony_ci}
82d5ac70f0Sopenharmony_ci
83d5ac70f0Sopenharmony_ci/**
84d5ac70f0Sopenharmony_ci * \brief Attach an HCTL element to a mixer element
85d5ac70f0Sopenharmony_ci * \param melem Mixer element
86d5ac70f0Sopenharmony_ci * \param helem HCTL element
87d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
88d5ac70f0Sopenharmony_ci *
89d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
90d5ac70f0Sopenharmony_ci *
91d5ac70f0Sopenharmony_ci * The implementation of mixer class typically calls it at #SND_CTL_EVENT_MASK_ADD event. Once
92d5ac70f0Sopenharmony_ci * attaching, the implementation should make sure to detach it by call of #snd_mixer_elem_detach()
93d5ac70f0Sopenharmony_ci * at #SND_CTL_EVENT_MASK_REMOVE event. Unless detaching, mixer API internal hits assertion due
94d5ac70f0Sopenharmony_ci * to unsatisfied postcondition after the event.
95d5ac70f0Sopenharmony_ci */
96d5ac70f0Sopenharmony_ciint snd_mixer_elem_attach(snd_mixer_elem_t *melem,
97d5ac70f0Sopenharmony_ci			  snd_hctl_elem_t *helem)
98d5ac70f0Sopenharmony_ci{
99d5ac70f0Sopenharmony_ci	bag_t *bag = snd_hctl_elem_get_callback_private(helem);
100d5ac70f0Sopenharmony_ci	int err;
101d5ac70f0Sopenharmony_ci	err = bag_add(bag, melem);
102d5ac70f0Sopenharmony_ci	if (err < 0)
103d5ac70f0Sopenharmony_ci		return err;
104d5ac70f0Sopenharmony_ci	return bag_add(&melem->helems, helem);
105d5ac70f0Sopenharmony_ci}
106d5ac70f0Sopenharmony_ci
107d5ac70f0Sopenharmony_ci/**
108d5ac70f0Sopenharmony_ci * \brief Detach an HCTL element from a mixer element
109d5ac70f0Sopenharmony_ci * \param melem Mixer element
110d5ac70f0Sopenharmony_ci * \param helem HCTL element
111d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
112d5ac70f0Sopenharmony_ci *
113d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
114d5ac70f0Sopenharmony_ci *
115d5ac70f0Sopenharmony_ci * The implementation of mixer class typically calls it at #SND_CTL_EVENT_MASK_REMOVE event for
116d5ac70f0Sopenharmony_ci * attached mixer element at #SND_CTL_EVENT_MASK_ADD. Unless detaching, mixer API internal hits
117d5ac70f0Sopenharmony_ci * assertion due to unsatisfied postcondition after the event.
118d5ac70f0Sopenharmony_ci */
119d5ac70f0Sopenharmony_ciint snd_mixer_elem_detach(snd_mixer_elem_t *melem,
120d5ac70f0Sopenharmony_ci			  snd_hctl_elem_t *helem)
121d5ac70f0Sopenharmony_ci{
122d5ac70f0Sopenharmony_ci	bag_t *bag = snd_hctl_elem_get_callback_private(helem);
123d5ac70f0Sopenharmony_ci	int err;
124d5ac70f0Sopenharmony_ci	err = bag_del(bag, melem);
125d5ac70f0Sopenharmony_ci	assert(err >= 0);
126d5ac70f0Sopenharmony_ci	err = bag_del(&melem->helems, helem);
127d5ac70f0Sopenharmony_ci	assert(err >= 0);
128d5ac70f0Sopenharmony_ci	return 0;
129d5ac70f0Sopenharmony_ci}
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_ci/**
132d5ac70f0Sopenharmony_ci * \brief Return true if a mixer element does not contain any HCTL elements
133d5ac70f0Sopenharmony_ci * \param melem Mixer element
134d5ac70f0Sopenharmony_ci * \return 0 if not empty, 1 if empty
135d5ac70f0Sopenharmony_ci *
136d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
137d5ac70f0Sopenharmony_ci */
138d5ac70f0Sopenharmony_ciint snd_mixer_elem_empty(snd_mixer_elem_t *melem)
139d5ac70f0Sopenharmony_ci{
140d5ac70f0Sopenharmony_ci	return bag_empty(&melem->helems);
141d5ac70f0Sopenharmony_ci}
142d5ac70f0Sopenharmony_ci
143d5ac70f0Sopenharmony_cistatic int hctl_elem_event_handler(snd_hctl_elem_t *helem,
144d5ac70f0Sopenharmony_ci				   unsigned int mask)
145d5ac70f0Sopenharmony_ci{
146d5ac70f0Sopenharmony_ci	bag_t *bag = snd_hctl_elem_get_callback_private(helem);
147d5ac70f0Sopenharmony_ci	if (mask == SND_CTL_EVENT_MASK_REMOVE) {
148d5ac70f0Sopenharmony_ci		int res = 0;
149d5ac70f0Sopenharmony_ci		int err;
150d5ac70f0Sopenharmony_ci		bag_iterator_t i, n;
151d5ac70f0Sopenharmony_ci		bag_for_each_safe(i, n, bag) {
152d5ac70f0Sopenharmony_ci			snd_mixer_elem_t *melem = bag_iterator_entry(i);
153d5ac70f0Sopenharmony_ci			snd_mixer_class_t *class = melem->class;
154d5ac70f0Sopenharmony_ci			err = class->event(class, mask, helem, melem);
155d5ac70f0Sopenharmony_ci			if (err < 0)
156d5ac70f0Sopenharmony_ci				res = err;
157d5ac70f0Sopenharmony_ci		}
158d5ac70f0Sopenharmony_ci		// NOTE: Unsatisfied postcondition. Typically, some of registerd implementation of
159d5ac70f0Sopenharmony_ci		// mixer class forget to detach mixer element from hcontrol element which has been
160d5ac70f0Sopenharmony_ci		// attached at ADD event.
161d5ac70f0Sopenharmony_ci		assert(bag_empty(bag));
162d5ac70f0Sopenharmony_ci		bag_free(bag);
163d5ac70f0Sopenharmony_ci		return res;
164d5ac70f0Sopenharmony_ci	}
165d5ac70f0Sopenharmony_ci	if (mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO)) {
166d5ac70f0Sopenharmony_ci		int err = 0;
167d5ac70f0Sopenharmony_ci		bag_iterator_t i, n;
168d5ac70f0Sopenharmony_ci		bag_for_each_safe(i, n, bag) {
169d5ac70f0Sopenharmony_ci			snd_mixer_elem_t *melem = bag_iterator_entry(i);
170d5ac70f0Sopenharmony_ci			snd_mixer_class_t *class = melem->class;
171d5ac70f0Sopenharmony_ci			err = class->event(class, mask, helem, melem);
172d5ac70f0Sopenharmony_ci			if (err < 0)
173d5ac70f0Sopenharmony_ci				return err;
174d5ac70f0Sopenharmony_ci		}
175d5ac70f0Sopenharmony_ci	}
176d5ac70f0Sopenharmony_ci	return 0;
177d5ac70f0Sopenharmony_ci}
178d5ac70f0Sopenharmony_ci
179d5ac70f0Sopenharmony_cistatic int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask,
180d5ac70f0Sopenharmony_ci			      snd_hctl_elem_t *elem)
181d5ac70f0Sopenharmony_ci{
182d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl);
183d5ac70f0Sopenharmony_ci	int res = 0;
184d5ac70f0Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_ADD) {
185d5ac70f0Sopenharmony_ci		struct list_head *pos;
186d5ac70f0Sopenharmony_ci		bag_t *bag;
187d5ac70f0Sopenharmony_ci		int err = bag_new(&bag);
188d5ac70f0Sopenharmony_ci		if (err < 0)
189d5ac70f0Sopenharmony_ci			return err;
190d5ac70f0Sopenharmony_ci		snd_hctl_elem_set_callback(elem, hctl_elem_event_handler);
191d5ac70f0Sopenharmony_ci		snd_hctl_elem_set_callback_private(elem, bag);
192d5ac70f0Sopenharmony_ci		list_for_each(pos, &mixer->classes) {
193d5ac70f0Sopenharmony_ci			snd_mixer_class_t *c;
194d5ac70f0Sopenharmony_ci			c = list_entry(pos, snd_mixer_class_t, list);
195d5ac70f0Sopenharmony_ci			err = c->event(c, mask, elem, NULL);
196d5ac70f0Sopenharmony_ci			if (err < 0)
197d5ac70f0Sopenharmony_ci				res = err;
198d5ac70f0Sopenharmony_ci		}
199d5ac70f0Sopenharmony_ci	}
200d5ac70f0Sopenharmony_ci	return res;
201d5ac70f0Sopenharmony_ci}
202d5ac70f0Sopenharmony_ci
203d5ac70f0Sopenharmony_ci
204d5ac70f0Sopenharmony_ci/**
205d5ac70f0Sopenharmony_ci * \brief Attach an HCTL specified with the CTL device name to an opened mixer
206d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
207d5ac70f0Sopenharmony_ci * \param name HCTL name (see #snd_hctl_open)
208d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
209d5ac70f0Sopenharmony_ci */
210d5ac70f0Sopenharmony_ciint snd_mixer_attach(snd_mixer_t *mixer, const char *name)
211d5ac70f0Sopenharmony_ci{
212d5ac70f0Sopenharmony_ci	snd_hctl_t *hctl;
213d5ac70f0Sopenharmony_ci	int err;
214d5ac70f0Sopenharmony_ci
215d5ac70f0Sopenharmony_ci	err = snd_hctl_open(&hctl, name, 0);
216d5ac70f0Sopenharmony_ci	if (err < 0)
217d5ac70f0Sopenharmony_ci		return err;
218d5ac70f0Sopenharmony_ci	err = snd_mixer_attach_hctl(mixer, hctl);
219d5ac70f0Sopenharmony_ci	if (err < 0)
220d5ac70f0Sopenharmony_ci		return err;
221d5ac70f0Sopenharmony_ci	return 0;
222d5ac70f0Sopenharmony_ci}
223d5ac70f0Sopenharmony_ci
224d5ac70f0Sopenharmony_ci/**
225d5ac70f0Sopenharmony_ci * \brief Attach an HCTL to an opened mixer
226d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
227d5ac70f0Sopenharmony_ci * \param hctl the HCTL to be attached
228d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
229d5ac70f0Sopenharmony_ci *
230d5ac70f0Sopenharmony_ci * Upon error, this function closes the given hctl handle automatically.
231d5ac70f0Sopenharmony_ci */
232d5ac70f0Sopenharmony_ciint snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
233d5ac70f0Sopenharmony_ci{
234d5ac70f0Sopenharmony_ci	snd_mixer_slave_t *slave;
235d5ac70f0Sopenharmony_ci	int err;
236d5ac70f0Sopenharmony_ci
237d5ac70f0Sopenharmony_ci	assert(hctl);
238d5ac70f0Sopenharmony_ci	slave = calloc(1, sizeof(*slave));
239d5ac70f0Sopenharmony_ci	if (slave == NULL) {
240d5ac70f0Sopenharmony_ci		snd_hctl_close(hctl);
241d5ac70f0Sopenharmony_ci		return -ENOMEM;
242d5ac70f0Sopenharmony_ci	}
243d5ac70f0Sopenharmony_ci	err = snd_hctl_nonblock(hctl, 1);
244d5ac70f0Sopenharmony_ci	if (err < 0) {
245d5ac70f0Sopenharmony_ci		snd_hctl_close(hctl);
246d5ac70f0Sopenharmony_ci		free(slave);
247d5ac70f0Sopenharmony_ci		return err;
248d5ac70f0Sopenharmony_ci	}
249d5ac70f0Sopenharmony_ci	snd_hctl_set_callback(hctl, hctl_event_handler);
250d5ac70f0Sopenharmony_ci	snd_hctl_set_callback_private(hctl, mixer);
251d5ac70f0Sopenharmony_ci	slave->hctl = hctl;
252d5ac70f0Sopenharmony_ci	list_add_tail(&slave->list, &mixer->slaves);
253d5ac70f0Sopenharmony_ci	return 0;
254d5ac70f0Sopenharmony_ci}
255d5ac70f0Sopenharmony_ci
256d5ac70f0Sopenharmony_ci/**
257d5ac70f0Sopenharmony_ci * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
258d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
259d5ac70f0Sopenharmony_ci * \param name HCTL previously attached
260d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
261d5ac70f0Sopenharmony_ci */
262d5ac70f0Sopenharmony_ciint snd_mixer_detach(snd_mixer_t *mixer, const char *name)
263d5ac70f0Sopenharmony_ci{
264d5ac70f0Sopenharmony_ci	struct list_head *pos;
265d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
266d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
267d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
268d5ac70f0Sopenharmony_ci		if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
269d5ac70f0Sopenharmony_ci			snd_hctl_close(s->hctl);
270d5ac70f0Sopenharmony_ci			list_del(pos);
271d5ac70f0Sopenharmony_ci			free(s);
272d5ac70f0Sopenharmony_ci			return 0;
273d5ac70f0Sopenharmony_ci		}
274d5ac70f0Sopenharmony_ci	}
275d5ac70f0Sopenharmony_ci	return -ENOENT;
276d5ac70f0Sopenharmony_ci}
277d5ac70f0Sopenharmony_ci
278d5ac70f0Sopenharmony_ci/**
279d5ac70f0Sopenharmony_ci * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
280d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
281d5ac70f0Sopenharmony_ci * \param hctl HCTL previously attached
282d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
283d5ac70f0Sopenharmony_ci *
284d5ac70f0Sopenharmony_ci * Note: The hctl handle is not closed!
285d5ac70f0Sopenharmony_ci */
286d5ac70f0Sopenharmony_ciint snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
287d5ac70f0Sopenharmony_ci{
288d5ac70f0Sopenharmony_ci	struct list_head *pos;
289d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
290d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
291d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
292d5ac70f0Sopenharmony_ci		if (hctl == s->hctl) {
293d5ac70f0Sopenharmony_ci			list_del(pos);
294d5ac70f0Sopenharmony_ci			free(s);
295d5ac70f0Sopenharmony_ci			return 0;
296d5ac70f0Sopenharmony_ci		}
297d5ac70f0Sopenharmony_ci	}
298d5ac70f0Sopenharmony_ci	return -ENOENT;
299d5ac70f0Sopenharmony_ci}
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_ci/**
302d5ac70f0Sopenharmony_ci * \brief Obtain a HCTL pointer associated to given name
303d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
304d5ac70f0Sopenharmony_ci * \param name HCTL previously attached
305d5ac70f0Sopenharmony_ci * \param hctl HCTL pointer
306d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
307d5ac70f0Sopenharmony_ci */
308d5ac70f0Sopenharmony_ciint snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl)
309d5ac70f0Sopenharmony_ci{
310d5ac70f0Sopenharmony_ci	struct list_head *pos;
311d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
312d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
313d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
314d5ac70f0Sopenharmony_ci		if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
315d5ac70f0Sopenharmony_ci			*hctl = s->hctl;
316d5ac70f0Sopenharmony_ci			return 0;
317d5ac70f0Sopenharmony_ci		}
318d5ac70f0Sopenharmony_ci	}
319d5ac70f0Sopenharmony_ci	return -ENOENT;
320d5ac70f0Sopenharmony_ci}
321d5ac70f0Sopenharmony_ci
322d5ac70f0Sopenharmony_cistatic int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask,
323d5ac70f0Sopenharmony_ci			  snd_mixer_elem_t *elem)
324d5ac70f0Sopenharmony_ci{
325d5ac70f0Sopenharmony_ci	mixer->events++;
326d5ac70f0Sopenharmony_ci	if (mixer->callback)
327d5ac70f0Sopenharmony_ci		return mixer->callback(mixer, mask, elem);
328d5ac70f0Sopenharmony_ci	return 0;
329d5ac70f0Sopenharmony_ci}
330d5ac70f0Sopenharmony_ci
331d5ac70f0Sopenharmony_cistatic int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask)
332d5ac70f0Sopenharmony_ci{
333d5ac70f0Sopenharmony_ci	elem->class->mixer->events++;
334d5ac70f0Sopenharmony_ci	if (elem->callback)
335d5ac70f0Sopenharmony_ci		return elem->callback(elem, mask);
336d5ac70f0Sopenharmony_ci	return 0;
337d5ac70f0Sopenharmony_ci}
338d5ac70f0Sopenharmony_ci
339d5ac70f0Sopenharmony_cistatic int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir)
340d5ac70f0Sopenharmony_ci{
341d5ac70f0Sopenharmony_ci	unsigned int l, u;
342d5ac70f0Sopenharmony_ci	int c = 0;
343d5ac70f0Sopenharmony_ci	int idx = -1;
344d5ac70f0Sopenharmony_ci	assert(mixer && elem);
345d5ac70f0Sopenharmony_ci	assert(mixer->compare);
346d5ac70f0Sopenharmony_ci	l = 0;
347d5ac70f0Sopenharmony_ci	u = mixer->count;
348d5ac70f0Sopenharmony_ci	while (l < u) {
349d5ac70f0Sopenharmony_ci		idx = (l + u) / 2;
350d5ac70f0Sopenharmony_ci		c = mixer->compare(elem, mixer->pelems[idx]);
351d5ac70f0Sopenharmony_ci		if (c < 0)
352d5ac70f0Sopenharmony_ci			u = idx;
353d5ac70f0Sopenharmony_ci		else if (c > 0)
354d5ac70f0Sopenharmony_ci			l = idx + 1;
355d5ac70f0Sopenharmony_ci		else
356d5ac70f0Sopenharmony_ci			break;
357d5ac70f0Sopenharmony_ci	}
358d5ac70f0Sopenharmony_ci	*dir = c;
359d5ac70f0Sopenharmony_ci	return idx;
360d5ac70f0Sopenharmony_ci}
361d5ac70f0Sopenharmony_ci
362d5ac70f0Sopenharmony_ci/**
363d5ac70f0Sopenharmony_ci * \brief Get private data associated to give mixer element
364d5ac70f0Sopenharmony_ci * \param elem Mixer element
365d5ac70f0Sopenharmony_ci * \return private data
366d5ac70f0Sopenharmony_ci *
367d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
368d5ac70f0Sopenharmony_ci */
369d5ac70f0Sopenharmony_civoid *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem)
370d5ac70f0Sopenharmony_ci{
371d5ac70f0Sopenharmony_ci	return elem->private_data;
372d5ac70f0Sopenharmony_ci}
373d5ac70f0Sopenharmony_ci
374d5ac70f0Sopenharmony_ci/**
375d5ac70f0Sopenharmony_ci * \brief Allocate a new mixer element
376d5ac70f0Sopenharmony_ci * \param elem Returned mixer element
377d5ac70f0Sopenharmony_ci * \param type Mixer element type
378d5ac70f0Sopenharmony_ci * \param compare_weight Mixer element compare weight
379d5ac70f0Sopenharmony_ci * \param private_data Private data
380d5ac70f0Sopenharmony_ci * \param private_free Private data free callback
381d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
382d5ac70f0Sopenharmony_ci *
383d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
384d5ac70f0Sopenharmony_ci */
385d5ac70f0Sopenharmony_ciint snd_mixer_elem_new(snd_mixer_elem_t **elem,
386d5ac70f0Sopenharmony_ci		       snd_mixer_elem_type_t type,
387d5ac70f0Sopenharmony_ci		       int compare_weight,
388d5ac70f0Sopenharmony_ci		       void *private_data,
389d5ac70f0Sopenharmony_ci		       void (*private_free)(snd_mixer_elem_t *elem))
390d5ac70f0Sopenharmony_ci{
391d5ac70f0Sopenharmony_ci	snd_mixer_elem_t *melem = calloc(1, sizeof(*melem));
392d5ac70f0Sopenharmony_ci	if (melem == NULL)
393d5ac70f0Sopenharmony_ci		return -ENOMEM;
394d5ac70f0Sopenharmony_ci	melem->type = type;
395d5ac70f0Sopenharmony_ci	melem->compare_weight = compare_weight;
396d5ac70f0Sopenharmony_ci	melem->private_data = private_data;
397d5ac70f0Sopenharmony_ci	melem->private_free = private_free;
398d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&melem->helems);
399d5ac70f0Sopenharmony_ci	*elem = melem;
400d5ac70f0Sopenharmony_ci	return 0;
401d5ac70f0Sopenharmony_ci}
402d5ac70f0Sopenharmony_ci
403d5ac70f0Sopenharmony_ci/**
404d5ac70f0Sopenharmony_ci * \brief Add an element for a registered mixer element class
405d5ac70f0Sopenharmony_ci * \param elem Mixer element
406d5ac70f0Sopenharmony_ci * \param class Mixer element class
407d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
408d5ac70f0Sopenharmony_ci *
409d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
410d5ac70f0Sopenharmony_ci */
411d5ac70f0Sopenharmony_ciint snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
412d5ac70f0Sopenharmony_ci{
413d5ac70f0Sopenharmony_ci	int dir, idx;
414d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer = class->mixer;
415d5ac70f0Sopenharmony_ci	elem->class = class;
416d5ac70f0Sopenharmony_ci
417d5ac70f0Sopenharmony_ci	if (mixer->count == mixer->alloc) {
418d5ac70f0Sopenharmony_ci		snd_mixer_elem_t **m;
419d5ac70f0Sopenharmony_ci		mixer->alloc += 32;
420d5ac70f0Sopenharmony_ci		m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc);
421d5ac70f0Sopenharmony_ci		if (!m) {
422d5ac70f0Sopenharmony_ci			mixer->alloc -= 32;
423d5ac70f0Sopenharmony_ci			return -ENOMEM;
424d5ac70f0Sopenharmony_ci		}
425d5ac70f0Sopenharmony_ci		mixer->pelems = m;
426d5ac70f0Sopenharmony_ci	}
427d5ac70f0Sopenharmony_ci	if (mixer->count == 0) {
428d5ac70f0Sopenharmony_ci		list_add_tail(&elem->list, &mixer->elems);
429d5ac70f0Sopenharmony_ci		mixer->pelems[0] = elem;
430d5ac70f0Sopenharmony_ci	} else {
431d5ac70f0Sopenharmony_ci		idx = _snd_mixer_find_elem(mixer, elem, &dir);
432d5ac70f0Sopenharmony_ci		assert(dir != 0);
433d5ac70f0Sopenharmony_ci		if (dir > 0) {
434d5ac70f0Sopenharmony_ci			list_add(&elem->list, &mixer->pelems[idx]->list);
435d5ac70f0Sopenharmony_ci			idx++;
436d5ac70f0Sopenharmony_ci		} else {
437d5ac70f0Sopenharmony_ci			list_add_tail(&elem->list, &mixer->pelems[idx]->list);
438d5ac70f0Sopenharmony_ci		}
439d5ac70f0Sopenharmony_ci		memmove(mixer->pelems + idx + 1,
440d5ac70f0Sopenharmony_ci			mixer->pelems + idx,
441d5ac70f0Sopenharmony_ci			(mixer->count - idx) * sizeof(snd_mixer_elem_t *));
442d5ac70f0Sopenharmony_ci		mixer->pelems[idx] = elem;
443d5ac70f0Sopenharmony_ci	}
444d5ac70f0Sopenharmony_ci	mixer->count++;
445d5ac70f0Sopenharmony_ci	return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem);
446d5ac70f0Sopenharmony_ci}
447d5ac70f0Sopenharmony_ci
448d5ac70f0Sopenharmony_ci/**
449d5ac70f0Sopenharmony_ci * \brief Remove a mixer element
450d5ac70f0Sopenharmony_ci * \param elem Mixer element
451d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
452d5ac70f0Sopenharmony_ci *
453d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
454d5ac70f0Sopenharmony_ci */
455d5ac70f0Sopenharmony_ciint snd_mixer_elem_remove(snd_mixer_elem_t *elem)
456d5ac70f0Sopenharmony_ci{
457d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer = elem->class->mixer;
458d5ac70f0Sopenharmony_ci	bag_iterator_t i, n;
459d5ac70f0Sopenharmony_ci	int err, idx, dir;
460d5ac70f0Sopenharmony_ci	unsigned int m;
461d5ac70f0Sopenharmony_ci	assert(elem);
462d5ac70f0Sopenharmony_ci	assert(mixer->count);
463d5ac70f0Sopenharmony_ci	idx = _snd_mixer_find_elem(mixer, elem, &dir);
464d5ac70f0Sopenharmony_ci	if (dir != 0)
465d5ac70f0Sopenharmony_ci		return -EINVAL;
466d5ac70f0Sopenharmony_ci	bag_for_each_safe(i, n, &elem->helems) {
467d5ac70f0Sopenharmony_ci		snd_hctl_elem_t *helem = bag_iterator_entry(i);
468d5ac70f0Sopenharmony_ci		snd_mixer_elem_detach(elem, helem);
469d5ac70f0Sopenharmony_ci	}
470d5ac70f0Sopenharmony_ci	err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
471d5ac70f0Sopenharmony_ci	list_del(&elem->list);
472d5ac70f0Sopenharmony_ci	snd_mixer_elem_free(elem);
473d5ac70f0Sopenharmony_ci	mixer->count--;
474d5ac70f0Sopenharmony_ci	m = mixer->count - idx;
475d5ac70f0Sopenharmony_ci	if (m > 0)
476d5ac70f0Sopenharmony_ci		memmove(mixer->pelems + idx,
477d5ac70f0Sopenharmony_ci			mixer->pelems + idx + 1,
478d5ac70f0Sopenharmony_ci			m * sizeof(snd_mixer_elem_t *));
479d5ac70f0Sopenharmony_ci	return err;
480d5ac70f0Sopenharmony_ci}
481d5ac70f0Sopenharmony_ci
482d5ac70f0Sopenharmony_ci/**
483d5ac70f0Sopenharmony_ci * \brief Free a mixer element
484d5ac70f0Sopenharmony_ci * \param elem Mixer element
485d5ac70f0Sopenharmony_ci *
486d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
487d5ac70f0Sopenharmony_ci */
488d5ac70f0Sopenharmony_civoid snd_mixer_elem_free(snd_mixer_elem_t *elem)
489d5ac70f0Sopenharmony_ci{
490d5ac70f0Sopenharmony_ci	if (elem->private_free)
491d5ac70f0Sopenharmony_ci		elem->private_free(elem);
492d5ac70f0Sopenharmony_ci	free(elem);
493d5ac70f0Sopenharmony_ci}
494d5ac70f0Sopenharmony_ci
495d5ac70f0Sopenharmony_ci/**
496d5ac70f0Sopenharmony_ci * \brief Mixer element informations are changed
497d5ac70f0Sopenharmony_ci * \param elem Mixer element
498d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
499d5ac70f0Sopenharmony_ci *
500d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
501d5ac70f0Sopenharmony_ci */
502d5ac70f0Sopenharmony_ciint snd_mixer_elem_info(snd_mixer_elem_t *elem)
503d5ac70f0Sopenharmony_ci{
504d5ac70f0Sopenharmony_ci	return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
505d5ac70f0Sopenharmony_ci}
506d5ac70f0Sopenharmony_ci
507d5ac70f0Sopenharmony_ci/**
508d5ac70f0Sopenharmony_ci * \brief Mixer element values is changed
509d5ac70f0Sopenharmony_ci * \param elem Mixer element
510d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
511d5ac70f0Sopenharmony_ci *
512d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
513d5ac70f0Sopenharmony_ci */
514d5ac70f0Sopenharmony_ciint snd_mixer_elem_value(snd_mixer_elem_t *elem)
515d5ac70f0Sopenharmony_ci{
516d5ac70f0Sopenharmony_ci	return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
517d5ac70f0Sopenharmony_ci}
518d5ac70f0Sopenharmony_ci
519d5ac70f0Sopenharmony_ci/**
520d5ac70f0Sopenharmony_ci * \brief Register mixer element class
521d5ac70f0Sopenharmony_ci * \param class Mixer element class
522d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
523d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
524d5ac70f0Sopenharmony_ci *
525d5ac70f0Sopenharmony_ci * For use by mixer element class specific code.
526d5ac70f0Sopenharmony_ci */
527d5ac70f0Sopenharmony_ciint snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer)
528d5ac70f0Sopenharmony_ci{
529d5ac70f0Sopenharmony_ci	struct list_head *pos;
530d5ac70f0Sopenharmony_ci	class->mixer = mixer;
531d5ac70f0Sopenharmony_ci	list_add_tail(&class->list, &mixer->classes);
532d5ac70f0Sopenharmony_ci	if (!class->event)
533d5ac70f0Sopenharmony_ci		return 0;
534d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
535d5ac70f0Sopenharmony_ci		int err;
536d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *slave;
537d5ac70f0Sopenharmony_ci		snd_hctl_elem_t *elem;
538d5ac70f0Sopenharmony_ci		slave = list_entry(pos, snd_mixer_slave_t, list);
539d5ac70f0Sopenharmony_ci		elem = snd_hctl_first_elem(slave->hctl);
540d5ac70f0Sopenharmony_ci		while (elem) {
541d5ac70f0Sopenharmony_ci			err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL);
542d5ac70f0Sopenharmony_ci			if (err < 0)
543d5ac70f0Sopenharmony_ci				return err;
544d5ac70f0Sopenharmony_ci			elem = snd_hctl_elem_next(elem);
545d5ac70f0Sopenharmony_ci		}
546d5ac70f0Sopenharmony_ci	}
547d5ac70f0Sopenharmony_ci	return 0;
548d5ac70f0Sopenharmony_ci}
549d5ac70f0Sopenharmony_ci
550d5ac70f0Sopenharmony_ci/**
551d5ac70f0Sopenharmony_ci * \brief Unregister mixer element class and remove all its elements
552d5ac70f0Sopenharmony_ci * \param class Mixer element class
553d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
554d5ac70f0Sopenharmony_ci *
555d5ac70f0Sopenharmony_ci * Note that the class structure is also deallocated!
556d5ac70f0Sopenharmony_ci */
557d5ac70f0Sopenharmony_ciint snd_mixer_class_unregister(snd_mixer_class_t *class)
558d5ac70f0Sopenharmony_ci{
559d5ac70f0Sopenharmony_ci	unsigned int k;
560d5ac70f0Sopenharmony_ci	snd_mixer_elem_t *e;
561d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer = class->mixer;
562d5ac70f0Sopenharmony_ci	for (k = mixer->count; k > 0; k--) {
563d5ac70f0Sopenharmony_ci		e = mixer->pelems[k-1];
564d5ac70f0Sopenharmony_ci		if (e->class == class)
565d5ac70f0Sopenharmony_ci			snd_mixer_elem_remove(e);
566d5ac70f0Sopenharmony_ci	}
567d5ac70f0Sopenharmony_ci	if (class->private_free)
568d5ac70f0Sopenharmony_ci		class->private_free(class);
569d5ac70f0Sopenharmony_ci	list_del(&class->list);
570d5ac70f0Sopenharmony_ci	free(class);
571d5ac70f0Sopenharmony_ci	return 0;
572d5ac70f0Sopenharmony_ci}
573d5ac70f0Sopenharmony_ci
574d5ac70f0Sopenharmony_ci/**
575d5ac70f0Sopenharmony_ci * \brief Load a mixer elements
576d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
577d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
578d5ac70f0Sopenharmony_ci */
579d5ac70f0Sopenharmony_ciint snd_mixer_load(snd_mixer_t *mixer)
580d5ac70f0Sopenharmony_ci{
581d5ac70f0Sopenharmony_ci	struct list_head *pos;
582d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
583d5ac70f0Sopenharmony_ci		int err;
584d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
585d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
586d5ac70f0Sopenharmony_ci		err = snd_hctl_load(s->hctl);
587d5ac70f0Sopenharmony_ci		if (err < 0)
588d5ac70f0Sopenharmony_ci			return err;
589d5ac70f0Sopenharmony_ci	}
590d5ac70f0Sopenharmony_ci	return 0;
591d5ac70f0Sopenharmony_ci}
592d5ac70f0Sopenharmony_ci
593d5ac70f0Sopenharmony_ci/**
594d5ac70f0Sopenharmony_ci * \brief Unload all mixer elements and free all related resources
595d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
596d5ac70f0Sopenharmony_ci */
597d5ac70f0Sopenharmony_civoid snd_mixer_free(snd_mixer_t *mixer)
598d5ac70f0Sopenharmony_ci{
599d5ac70f0Sopenharmony_ci	struct list_head *pos;
600d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
601d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
602d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
603d5ac70f0Sopenharmony_ci		snd_hctl_free(s->hctl);
604d5ac70f0Sopenharmony_ci	}
605d5ac70f0Sopenharmony_ci}
606d5ac70f0Sopenharmony_ci
607d5ac70f0Sopenharmony_ci/**
608d5ac70f0Sopenharmony_ci * \brief Close a mixer and free all related resources
609d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
610d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
611d5ac70f0Sopenharmony_ci */
612d5ac70f0Sopenharmony_ciint snd_mixer_close(snd_mixer_t *mixer)
613d5ac70f0Sopenharmony_ci{
614d5ac70f0Sopenharmony_ci	int res = 0;
615d5ac70f0Sopenharmony_ci	assert(mixer);
616d5ac70f0Sopenharmony_ci	while (!list_empty(&mixer->classes)) {
617d5ac70f0Sopenharmony_ci		snd_mixer_class_t *c;
618d5ac70f0Sopenharmony_ci		c = list_entry(mixer->classes.next, snd_mixer_class_t, list);
619d5ac70f0Sopenharmony_ci		snd_mixer_class_unregister(c);
620d5ac70f0Sopenharmony_ci	}
621d5ac70f0Sopenharmony_ci	assert(list_empty(&mixer->elems));
622d5ac70f0Sopenharmony_ci	assert(mixer->count == 0);
623d5ac70f0Sopenharmony_ci	free(mixer->pelems);
624d5ac70f0Sopenharmony_ci	mixer->pelems = NULL;
625d5ac70f0Sopenharmony_ci	while (!list_empty(&mixer->slaves)) {
626d5ac70f0Sopenharmony_ci		int err;
627d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
628d5ac70f0Sopenharmony_ci		s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list);
629d5ac70f0Sopenharmony_ci		err = snd_hctl_close(s->hctl);
630d5ac70f0Sopenharmony_ci		if (err < 0)
631d5ac70f0Sopenharmony_ci			res = err;
632d5ac70f0Sopenharmony_ci		list_del(&s->list);
633d5ac70f0Sopenharmony_ci		free(s);
634d5ac70f0Sopenharmony_ci	}
635d5ac70f0Sopenharmony_ci	free(mixer);
636d5ac70f0Sopenharmony_ci	return res;
637d5ac70f0Sopenharmony_ci}
638d5ac70f0Sopenharmony_ci
639d5ac70f0Sopenharmony_cistatic int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
640d5ac70f0Sopenharmony_ci				     const snd_mixer_elem_t *c2)
641d5ac70f0Sopenharmony_ci{
642d5ac70f0Sopenharmony_ci	int d = c1->compare_weight - c2->compare_weight;
643d5ac70f0Sopenharmony_ci	if (d)
644d5ac70f0Sopenharmony_ci		return d;
645d5ac70f0Sopenharmony_ci	assert(c1->class && c1->class->compare);
646d5ac70f0Sopenharmony_ci	assert(c2->class && c2->class->compare);
647d5ac70f0Sopenharmony_ci	assert(c1->class == c2->class);
648d5ac70f0Sopenharmony_ci	return c1->class->compare(c1, c2);
649d5ac70f0Sopenharmony_ci}
650d5ac70f0Sopenharmony_ci
651d5ac70f0Sopenharmony_cistatic int mixer_compare(const void *a, const void *b)
652d5ac70f0Sopenharmony_ci{
653d5ac70f0Sopenharmony_ci	snd_mixer_t *mixer;
654d5ac70f0Sopenharmony_ci
655d5ac70f0Sopenharmony_ci	mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer;
656d5ac70f0Sopenharmony_ci	return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b);
657d5ac70f0Sopenharmony_ci}
658d5ac70f0Sopenharmony_ci
659d5ac70f0Sopenharmony_cistatic int snd_mixer_sort(snd_mixer_t *mixer)
660d5ac70f0Sopenharmony_ci{
661d5ac70f0Sopenharmony_ci	unsigned int k;
662d5ac70f0Sopenharmony_ci	assert(mixer);
663d5ac70f0Sopenharmony_ci	assert(mixer->compare);
664d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&mixer->elems);
665d5ac70f0Sopenharmony_ci	qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare);
666d5ac70f0Sopenharmony_ci	for (k = 0; k < mixer->count; k++)
667d5ac70f0Sopenharmony_ci		list_add_tail(&mixer->pelems[k]->list, &mixer->elems);
668d5ac70f0Sopenharmony_ci	return 0;
669d5ac70f0Sopenharmony_ci}
670d5ac70f0Sopenharmony_ci
671d5ac70f0Sopenharmony_ci/**
672d5ac70f0Sopenharmony_ci * \brief Change mixer compare function and reorder elements
673d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
674d5ac70f0Sopenharmony_ci * \param compare Element compare function
675d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code
676d5ac70f0Sopenharmony_ci */
677d5ac70f0Sopenharmony_ciint snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare)
678d5ac70f0Sopenharmony_ci{
679d5ac70f0Sopenharmony_ci	snd_mixer_compare_t compare_old;
680d5ac70f0Sopenharmony_ci	int err;
681d5ac70f0Sopenharmony_ci
682d5ac70f0Sopenharmony_ci	assert(mixer);
683d5ac70f0Sopenharmony_ci	compare_old = mixer->compare;
684d5ac70f0Sopenharmony_ci	mixer->compare = compare == NULL ? snd_mixer_compare_default : compare;
685d5ac70f0Sopenharmony_ci	if ((err = snd_mixer_sort(mixer)) < 0) {
686d5ac70f0Sopenharmony_ci		mixer->compare = compare_old;
687d5ac70f0Sopenharmony_ci		return err;
688d5ac70f0Sopenharmony_ci	}
689d5ac70f0Sopenharmony_ci	return 0;
690d5ac70f0Sopenharmony_ci}
691d5ac70f0Sopenharmony_ci
692d5ac70f0Sopenharmony_ci/**
693d5ac70f0Sopenharmony_ci * \brief get count of poll descriptors for mixer handle
694d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
695d5ac70f0Sopenharmony_ci * \return count of poll descriptors
696d5ac70f0Sopenharmony_ci */
697d5ac70f0Sopenharmony_ciint snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
698d5ac70f0Sopenharmony_ci{
699d5ac70f0Sopenharmony_ci	struct list_head *pos;
700d5ac70f0Sopenharmony_ci	unsigned int c = 0;
701d5ac70f0Sopenharmony_ci	assert(mixer);
702d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
703d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
704d5ac70f0Sopenharmony_ci		int n;
705d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
706d5ac70f0Sopenharmony_ci		n = snd_hctl_poll_descriptors_count(s->hctl);
707d5ac70f0Sopenharmony_ci		if (n < 0)
708d5ac70f0Sopenharmony_ci			return n;
709d5ac70f0Sopenharmony_ci		c += n;
710d5ac70f0Sopenharmony_ci	}
711d5ac70f0Sopenharmony_ci	return c;
712d5ac70f0Sopenharmony_ci}
713d5ac70f0Sopenharmony_ci
714d5ac70f0Sopenharmony_ci/**
715d5ac70f0Sopenharmony_ci * \brief get poll descriptors
716d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
717d5ac70f0Sopenharmony_ci * \param pfds array of poll descriptors
718d5ac70f0Sopenharmony_ci * \param space space in the poll descriptor array
719d5ac70f0Sopenharmony_ci * \return count of filled descriptors
720d5ac70f0Sopenharmony_ci */
721d5ac70f0Sopenharmony_ciint snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
722d5ac70f0Sopenharmony_ci{
723d5ac70f0Sopenharmony_ci	struct list_head *pos;
724d5ac70f0Sopenharmony_ci	unsigned int count = 0;
725d5ac70f0Sopenharmony_ci	assert(mixer);
726d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
727d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
728d5ac70f0Sopenharmony_ci		int n;
729d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
730d5ac70f0Sopenharmony_ci		n = snd_hctl_poll_descriptors(s->hctl, pfds, space);
731d5ac70f0Sopenharmony_ci		if (n < 0)
732d5ac70f0Sopenharmony_ci			return n;
733d5ac70f0Sopenharmony_ci		if (space >= (unsigned int) n) {
734d5ac70f0Sopenharmony_ci			count += n;
735d5ac70f0Sopenharmony_ci			space -= n;
736d5ac70f0Sopenharmony_ci			pfds += n;
737d5ac70f0Sopenharmony_ci		} else
738d5ac70f0Sopenharmony_ci			space = 0;
739d5ac70f0Sopenharmony_ci	}
740d5ac70f0Sopenharmony_ci	return count;
741d5ac70f0Sopenharmony_ci}
742d5ac70f0Sopenharmony_ci
743d5ac70f0Sopenharmony_ci/**
744d5ac70f0Sopenharmony_ci * \brief get returned events from poll descriptors
745d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
746d5ac70f0Sopenharmony_ci * \param pfds array of poll descriptors
747d5ac70f0Sopenharmony_ci * \param nfds count of poll descriptors
748d5ac70f0Sopenharmony_ci * \param revents returned events
749d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code
750d5ac70f0Sopenharmony_ci */
751d5ac70f0Sopenharmony_ciint snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
752d5ac70f0Sopenharmony_ci{
753d5ac70f0Sopenharmony_ci	unsigned int idx;
754d5ac70f0Sopenharmony_ci	unsigned short res;
755d5ac70f0Sopenharmony_ci        assert(mixer && pfds && revents);
756d5ac70f0Sopenharmony_ci	if (nfds == 0)
757d5ac70f0Sopenharmony_ci		return -EINVAL;
758d5ac70f0Sopenharmony_ci	res = 0;
759d5ac70f0Sopenharmony_ci	for (idx = 0; idx < nfds; idx++, pfds++)
760d5ac70f0Sopenharmony_ci		res |= pfds->revents & (POLLIN|POLLERR|POLLNVAL);
761d5ac70f0Sopenharmony_ci	*revents = res;
762d5ac70f0Sopenharmony_ci	return 0;
763d5ac70f0Sopenharmony_ci}
764d5ac70f0Sopenharmony_ci
765d5ac70f0Sopenharmony_ci/**
766d5ac70f0Sopenharmony_ci * \brief Wait for a mixer to become ready (i.e. at least one event pending)
767d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
768d5ac70f0Sopenharmony_ci * \param timeout maximum time in milliseconds to wait
769d5ac70f0Sopenharmony_ci * \return 0 otherwise a negative error code on failure
770d5ac70f0Sopenharmony_ci */
771d5ac70f0Sopenharmony_ciint snd_mixer_wait(snd_mixer_t *mixer, int timeout)
772d5ac70f0Sopenharmony_ci{
773d5ac70f0Sopenharmony_ci	struct pollfd spfds[16];
774d5ac70f0Sopenharmony_ci	struct pollfd *pfds = spfds;
775d5ac70f0Sopenharmony_ci	int err;
776d5ac70f0Sopenharmony_ci	int count;
777d5ac70f0Sopenharmony_ci	count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
778d5ac70f0Sopenharmony_ci	if (count < 0)
779d5ac70f0Sopenharmony_ci		return count;
780d5ac70f0Sopenharmony_ci	if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) {
781d5ac70f0Sopenharmony_ci		pfds = alloca(count * sizeof(*pfds));
782d5ac70f0Sopenharmony_ci		if (!pfds)
783d5ac70f0Sopenharmony_ci			return -ENOMEM;
784d5ac70f0Sopenharmony_ci		err = snd_mixer_poll_descriptors(mixer, pfds,
785d5ac70f0Sopenharmony_ci						 (unsigned int) count);
786d5ac70f0Sopenharmony_ci		assert(err == count);
787d5ac70f0Sopenharmony_ci	}
788d5ac70f0Sopenharmony_ci	err = poll(pfds, (unsigned int) count, timeout);
789d5ac70f0Sopenharmony_ci	if (err < 0)
790d5ac70f0Sopenharmony_ci		return -errno;
791d5ac70f0Sopenharmony_ci	return 0;
792d5ac70f0Sopenharmony_ci}
793d5ac70f0Sopenharmony_ci
794d5ac70f0Sopenharmony_ci/**
795d5ac70f0Sopenharmony_ci * \brief get first element for a mixer
796d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
797d5ac70f0Sopenharmony_ci * \return pointer to first element
798d5ac70f0Sopenharmony_ci */
799d5ac70f0Sopenharmony_cisnd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer)
800d5ac70f0Sopenharmony_ci{
801d5ac70f0Sopenharmony_ci	assert(mixer);
802d5ac70f0Sopenharmony_ci	if (list_empty(&mixer->elems))
803d5ac70f0Sopenharmony_ci		return NULL;
804d5ac70f0Sopenharmony_ci	return list_entry(mixer->elems.next, snd_mixer_elem_t, list);
805d5ac70f0Sopenharmony_ci}
806d5ac70f0Sopenharmony_ci
807d5ac70f0Sopenharmony_ci/**
808d5ac70f0Sopenharmony_ci * \brief get last element for a mixer
809d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
810d5ac70f0Sopenharmony_ci * \return pointer to last element
811d5ac70f0Sopenharmony_ci */
812d5ac70f0Sopenharmony_cisnd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer)
813d5ac70f0Sopenharmony_ci{
814d5ac70f0Sopenharmony_ci	assert(mixer);
815d5ac70f0Sopenharmony_ci	if (list_empty(&mixer->elems))
816d5ac70f0Sopenharmony_ci		return NULL;
817d5ac70f0Sopenharmony_ci	return list_entry(mixer->elems.prev, snd_mixer_elem_t, list);
818d5ac70f0Sopenharmony_ci}
819d5ac70f0Sopenharmony_ci
820d5ac70f0Sopenharmony_ci/**
821d5ac70f0Sopenharmony_ci * \brief get next mixer element
822d5ac70f0Sopenharmony_ci * \param elem mixer element
823d5ac70f0Sopenharmony_ci * \return pointer to next element
824d5ac70f0Sopenharmony_ci */
825d5ac70f0Sopenharmony_cisnd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem)
826d5ac70f0Sopenharmony_ci{
827d5ac70f0Sopenharmony_ci	assert(elem);
828d5ac70f0Sopenharmony_ci	if (elem->list.next == &elem->class->mixer->elems)
829d5ac70f0Sopenharmony_ci		return NULL;
830d5ac70f0Sopenharmony_ci	return list_entry(elem->list.next, snd_mixer_elem_t, list);
831d5ac70f0Sopenharmony_ci}
832d5ac70f0Sopenharmony_ci
833d5ac70f0Sopenharmony_ci/**
834d5ac70f0Sopenharmony_ci * \brief get previous mixer element
835d5ac70f0Sopenharmony_ci * \param elem mixer element
836d5ac70f0Sopenharmony_ci * \return pointer to previous element
837d5ac70f0Sopenharmony_ci */
838d5ac70f0Sopenharmony_cisnd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem)
839d5ac70f0Sopenharmony_ci{
840d5ac70f0Sopenharmony_ci	assert(elem);
841d5ac70f0Sopenharmony_ci	if (elem->list.prev == &elem->class->mixer->elems)
842d5ac70f0Sopenharmony_ci		return NULL;
843d5ac70f0Sopenharmony_ci	return list_entry(elem->list.prev, snd_mixer_elem_t, list);
844d5ac70f0Sopenharmony_ci}
845d5ac70f0Sopenharmony_ci
846d5ac70f0Sopenharmony_ci/**
847d5ac70f0Sopenharmony_ci * \brief Handle pending mixer events invoking callbacks
848d5ac70f0Sopenharmony_ci * \param mixer Mixer handle
849d5ac70f0Sopenharmony_ci * \return Number of events that occured on success, otherwise a negative error code on failure
850d5ac70f0Sopenharmony_ci */
851d5ac70f0Sopenharmony_ciint snd_mixer_handle_events(snd_mixer_t *mixer)
852d5ac70f0Sopenharmony_ci{
853d5ac70f0Sopenharmony_ci	struct list_head *pos;
854d5ac70f0Sopenharmony_ci	assert(mixer);
855d5ac70f0Sopenharmony_ci	mixer->events = 0;
856d5ac70f0Sopenharmony_ci	list_for_each(pos, &mixer->slaves) {
857d5ac70f0Sopenharmony_ci		int err;
858d5ac70f0Sopenharmony_ci		snd_mixer_slave_t *s;
859d5ac70f0Sopenharmony_ci		s = list_entry(pos, snd_mixer_slave_t, list);
860d5ac70f0Sopenharmony_ci		err = snd_hctl_handle_events(s->hctl);
861d5ac70f0Sopenharmony_ci		if (err < 0)
862d5ac70f0Sopenharmony_ci			return err;
863d5ac70f0Sopenharmony_ci	}
864d5ac70f0Sopenharmony_ci	return mixer->events;
865d5ac70f0Sopenharmony_ci}
866d5ac70f0Sopenharmony_ci
867d5ac70f0Sopenharmony_ci/**
868d5ac70f0Sopenharmony_ci * \brief Set callback function for a mixer
869d5ac70f0Sopenharmony_ci * \param obj mixer handle
870d5ac70f0Sopenharmony_ci * \param val callback function
871d5ac70f0Sopenharmony_ci */
872d5ac70f0Sopenharmony_civoid snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val)
873d5ac70f0Sopenharmony_ci{
874d5ac70f0Sopenharmony_ci	assert(obj);
875d5ac70f0Sopenharmony_ci	obj->callback = val;
876d5ac70f0Sopenharmony_ci}
877d5ac70f0Sopenharmony_ci
878d5ac70f0Sopenharmony_ci/**
879d5ac70f0Sopenharmony_ci * \brief Set callback private value for a mixer
880d5ac70f0Sopenharmony_ci * \param mixer mixer handle
881d5ac70f0Sopenharmony_ci * \param val callback private value
882d5ac70f0Sopenharmony_ci */
883d5ac70f0Sopenharmony_civoid snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val)
884d5ac70f0Sopenharmony_ci{
885d5ac70f0Sopenharmony_ci	assert(mixer);
886d5ac70f0Sopenharmony_ci	mixer->callback_private = val;
887d5ac70f0Sopenharmony_ci}
888d5ac70f0Sopenharmony_ci
889d5ac70f0Sopenharmony_ci/**
890d5ac70f0Sopenharmony_ci * \brief Get callback private value for a mixer
891d5ac70f0Sopenharmony_ci * \param mixer mixer handle
892d5ac70f0Sopenharmony_ci * \return callback private value
893d5ac70f0Sopenharmony_ci */
894d5ac70f0Sopenharmony_civoid * snd_mixer_get_callback_private(const snd_mixer_t *mixer)
895d5ac70f0Sopenharmony_ci{
896d5ac70f0Sopenharmony_ci	assert(mixer);
897d5ac70f0Sopenharmony_ci	return mixer->callback_private;
898d5ac70f0Sopenharmony_ci}
899d5ac70f0Sopenharmony_ci
900d5ac70f0Sopenharmony_ci/**
901d5ac70f0Sopenharmony_ci * \brief Get elements count for a mixer
902d5ac70f0Sopenharmony_ci * \param mixer mixer handle
903d5ac70f0Sopenharmony_ci * \return elements count
904d5ac70f0Sopenharmony_ci */
905d5ac70f0Sopenharmony_ciunsigned int snd_mixer_get_count(const snd_mixer_t *mixer)
906d5ac70f0Sopenharmony_ci{
907d5ac70f0Sopenharmony_ci	assert(mixer);
908d5ac70f0Sopenharmony_ci	return mixer->count;
909d5ac70f0Sopenharmony_ci}
910d5ac70f0Sopenharmony_ci
911d5ac70f0Sopenharmony_ci/**
912d5ac70f0Sopenharmony_ci * \brief Set callback function for a mixer element
913d5ac70f0Sopenharmony_ci * \param mixer mixer element
914d5ac70f0Sopenharmony_ci * \param val callback function
915d5ac70f0Sopenharmony_ci */
916d5ac70f0Sopenharmony_civoid snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val)
917d5ac70f0Sopenharmony_ci{
918d5ac70f0Sopenharmony_ci	assert(mixer);
919d5ac70f0Sopenharmony_ci	mixer->callback = val;
920d5ac70f0Sopenharmony_ci}
921d5ac70f0Sopenharmony_ci
922d5ac70f0Sopenharmony_ci/**
923d5ac70f0Sopenharmony_ci * \brief Set callback private value for a mixer element
924d5ac70f0Sopenharmony_ci * \param mixer mixer element
925d5ac70f0Sopenharmony_ci * \param val callback private value
926d5ac70f0Sopenharmony_ci */
927d5ac70f0Sopenharmony_civoid snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val)
928d5ac70f0Sopenharmony_ci{
929d5ac70f0Sopenharmony_ci	assert(mixer);
930d5ac70f0Sopenharmony_ci	mixer->callback_private = val;
931d5ac70f0Sopenharmony_ci}
932d5ac70f0Sopenharmony_ci
933d5ac70f0Sopenharmony_ci/**
934d5ac70f0Sopenharmony_ci * \brief Get callback private value for a mixer element
935d5ac70f0Sopenharmony_ci * \param mixer mixer element
936d5ac70f0Sopenharmony_ci * \return callback private value
937d5ac70f0Sopenharmony_ci */
938d5ac70f0Sopenharmony_civoid * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer)
939d5ac70f0Sopenharmony_ci{
940d5ac70f0Sopenharmony_ci	assert(mixer);
941d5ac70f0Sopenharmony_ci	return mixer->callback_private;
942d5ac70f0Sopenharmony_ci}
943d5ac70f0Sopenharmony_ci
944d5ac70f0Sopenharmony_ci/**
945d5ac70f0Sopenharmony_ci * \brief Get type for a mixer element
946d5ac70f0Sopenharmony_ci * \param mixer mixer element
947d5ac70f0Sopenharmony_ci * \return mixer element type
948d5ac70f0Sopenharmony_ci */
949d5ac70f0Sopenharmony_cisnd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer)
950d5ac70f0Sopenharmony_ci{
951d5ac70f0Sopenharmony_ci	assert(mixer);
952d5ac70f0Sopenharmony_ci	return mixer->type;
953d5ac70f0Sopenharmony_ci}
954d5ac70f0Sopenharmony_ci
955d5ac70f0Sopenharmony_ci
956d5ac70f0Sopenharmony_ci/**
957d5ac70f0Sopenharmony_ci * \brief get size of #snd_mixer_class_t
958d5ac70f0Sopenharmony_ci * \return size in bytes
959d5ac70f0Sopenharmony_ci */
960d5ac70f0Sopenharmony_cisize_t snd_mixer_class_sizeof()
961d5ac70f0Sopenharmony_ci{
962d5ac70f0Sopenharmony_ci	return sizeof(snd_mixer_class_t);
963d5ac70f0Sopenharmony_ci}
964d5ac70f0Sopenharmony_ci
965d5ac70f0Sopenharmony_ci/**
966d5ac70f0Sopenharmony_ci * \brief allocate an invalid #snd_mixer_class_t using standard malloc
967d5ac70f0Sopenharmony_ci * \param ptr returned pointer
968d5ac70f0Sopenharmony_ci * \return 0 on success otherwise negative error code
969d5ac70f0Sopenharmony_ci */
970d5ac70f0Sopenharmony_ciint snd_mixer_class_malloc(snd_mixer_class_t **ptr)
971d5ac70f0Sopenharmony_ci{
972d5ac70f0Sopenharmony_ci	assert(ptr);
973d5ac70f0Sopenharmony_ci	*ptr = calloc(1, sizeof(snd_mixer_class_t));
974d5ac70f0Sopenharmony_ci	if (!*ptr)
975d5ac70f0Sopenharmony_ci		return -ENOMEM;
976d5ac70f0Sopenharmony_ci	return 0;
977d5ac70f0Sopenharmony_ci}
978d5ac70f0Sopenharmony_ci
979d5ac70f0Sopenharmony_ci/**
980d5ac70f0Sopenharmony_ci * \brief frees a previously allocated #snd_mixer_class_t
981d5ac70f0Sopenharmony_ci * \param obj pointer to object to free
982d5ac70f0Sopenharmony_ci */
983d5ac70f0Sopenharmony_civoid snd_mixer_class_free(snd_mixer_class_t *obj)
984d5ac70f0Sopenharmony_ci{
985d5ac70f0Sopenharmony_ci	if (obj->private_free)
986d5ac70f0Sopenharmony_ci		obj->private_free(obj);
987d5ac70f0Sopenharmony_ci	free(obj);
988d5ac70f0Sopenharmony_ci}
989d5ac70f0Sopenharmony_ci
990d5ac70f0Sopenharmony_ci/**
991d5ac70f0Sopenharmony_ci * \brief copy one #snd_mixer_class_t to another
992d5ac70f0Sopenharmony_ci * \param dst pointer to destination
993d5ac70f0Sopenharmony_ci * \param src pointer to source
994d5ac70f0Sopenharmony_ci */
995d5ac70f0Sopenharmony_civoid snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src)
996d5ac70f0Sopenharmony_ci{
997d5ac70f0Sopenharmony_ci	assert(dst && src);
998d5ac70f0Sopenharmony_ci	*dst = *src;
999d5ac70f0Sopenharmony_ci}
1000d5ac70f0Sopenharmony_ci
1001d5ac70f0Sopenharmony_ci/**
1002d5ac70f0Sopenharmony_ci * \brief Get a mixer associated to given mixer class
1003d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1004d5ac70f0Sopenharmony_ci * \return mixer pointer
1005d5ac70f0Sopenharmony_ci */
1006d5ac70f0Sopenharmony_cisnd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj)
1007d5ac70f0Sopenharmony_ci{
1008d5ac70f0Sopenharmony_ci	assert(obj);
1009d5ac70f0Sopenharmony_ci	return obj->mixer;
1010d5ac70f0Sopenharmony_ci}
1011d5ac70f0Sopenharmony_ci
1012d5ac70f0Sopenharmony_ci/**
1013d5ac70f0Sopenharmony_ci * \brief Get mixer event callback associated to given mixer class
1014d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1015d5ac70f0Sopenharmony_ci * \return event callback pointer
1016d5ac70f0Sopenharmony_ci */
1017d5ac70f0Sopenharmony_cisnd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj)
1018d5ac70f0Sopenharmony_ci{
1019d5ac70f0Sopenharmony_ci	assert(obj);
1020d5ac70f0Sopenharmony_ci	return obj->event;
1021d5ac70f0Sopenharmony_ci}
1022d5ac70f0Sopenharmony_ci
1023d5ac70f0Sopenharmony_ci/**
1024d5ac70f0Sopenharmony_ci * \brief Get mixer private data associated to given mixer class
1025d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1026d5ac70f0Sopenharmony_ci * \return event callback pointer
1027d5ac70f0Sopenharmony_ci */
1028d5ac70f0Sopenharmony_civoid *snd_mixer_class_get_private(const snd_mixer_class_t *obj)
1029d5ac70f0Sopenharmony_ci{
1030d5ac70f0Sopenharmony_ci	assert(obj);
1031d5ac70f0Sopenharmony_ci	return obj->private_data;
1032d5ac70f0Sopenharmony_ci}
1033d5ac70f0Sopenharmony_ci
1034d5ac70f0Sopenharmony_ci
1035d5ac70f0Sopenharmony_ci/**
1036d5ac70f0Sopenharmony_ci * \brief Get mixer compare callback associated to given mixer class
1037d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1038d5ac70f0Sopenharmony_ci * \return event callback pointer
1039d5ac70f0Sopenharmony_ci */
1040d5ac70f0Sopenharmony_cisnd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj)
1041d5ac70f0Sopenharmony_ci{
1042d5ac70f0Sopenharmony_ci	assert(obj);
1043d5ac70f0Sopenharmony_ci	return obj->compare;
1044d5ac70f0Sopenharmony_ci}
1045d5ac70f0Sopenharmony_ci
1046d5ac70f0Sopenharmony_ci/**
1047d5ac70f0Sopenharmony_ci * \brief Set mixer event callback to given mixer class
1048d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1049d5ac70f0Sopenharmony_ci * \param event Event callback
1050d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code
1051d5ac70f0Sopenharmony_ci */
1052d5ac70f0Sopenharmony_ciint snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event)
1053d5ac70f0Sopenharmony_ci{
1054d5ac70f0Sopenharmony_ci	assert(obj);
1055d5ac70f0Sopenharmony_ci	obj->event = event;
1056d5ac70f0Sopenharmony_ci	return 0;
1057d5ac70f0Sopenharmony_ci}
1058d5ac70f0Sopenharmony_ci
1059d5ac70f0Sopenharmony_ci/**
1060d5ac70f0Sopenharmony_ci * \brief Set mixer private data to given mixer class
1061d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1062d5ac70f0Sopenharmony_ci * \param private_data class private data
1063d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code
1064d5ac70f0Sopenharmony_ci */
1065d5ac70f0Sopenharmony_ciint snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data)
1066d5ac70f0Sopenharmony_ci{
1067d5ac70f0Sopenharmony_ci	assert(obj);
1068d5ac70f0Sopenharmony_ci	obj->private_data = private_data;
1069d5ac70f0Sopenharmony_ci	return 0;
1070d5ac70f0Sopenharmony_ci}
1071d5ac70f0Sopenharmony_ci
1072d5ac70f0Sopenharmony_ci/**
1073d5ac70f0Sopenharmony_ci * \brief Set mixer private data free callback to given mixer class
1074d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1075d5ac70f0Sopenharmony_ci * \param private_free Mixer class private data free callback
1076d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code
1077d5ac70f0Sopenharmony_ci */
1078d5ac70f0Sopenharmony_ciint snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *))
1079d5ac70f0Sopenharmony_ci{
1080d5ac70f0Sopenharmony_ci	assert(obj);
1081d5ac70f0Sopenharmony_ci	obj->private_free = private_free;
1082d5ac70f0Sopenharmony_ci	return 0;
1083d5ac70f0Sopenharmony_ci}
1084d5ac70f0Sopenharmony_ci
1085d5ac70f0Sopenharmony_ci/**
1086d5ac70f0Sopenharmony_ci * \brief Set mixer compare callback to given mixer class
1087d5ac70f0Sopenharmony_ci * \param obj Mixer simple class identifier
1088d5ac70f0Sopenharmony_ci * \param compare the compare callback to be used
1089d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code
1090d5ac70f0Sopenharmony_ci */
1091d5ac70f0Sopenharmony_ciint snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare)
1092d5ac70f0Sopenharmony_ci{
1093d5ac70f0Sopenharmony_ci	assert(obj);
1094d5ac70f0Sopenharmony_ci	obj->compare = compare;
1095d5ac70f0Sopenharmony_ci	return 0;
1096d5ac70f0Sopenharmony_ci}
1097