1/**
2 * \file control/hcontrol.c
3 * \brief HCTL Interface - High Level CTL
4 * \author Jaroslav Kysela <perex@perex.cz>
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000
7 *
8 * HCTL interface is designed to access preloaded and sorted primitive controls.
9 * Callbacks may be used for event handling.
10 * See \ref hcontrol page for more details.
11 */
12/*
13 *  Control Interface - high level API
14 *  Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
15 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
16 *
17 *
18 *   This library is free software; you can redistribute it and/or modify
19 *   it under the terms of the GNU Lesser General Public License as
20 *   published by the Free Software Foundation; either version 2.1 of
21 *   the License, or (at your option) any later version.
22 *
23 *   This program is distributed in the hope that it will be useful,
24 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
25 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26 *   GNU Lesser General Public License for more details.
27 *
28 *   You should have received a copy of the GNU Lesser General Public
29 *   License along with this library; if not, write to the Free Software
30 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
31 *
32 */
33
34/*! \page hcontrol High level control interface
35
36<P> High level control interface is designed to access preloaded and sorted primitive controls.
37
38\section hcontrol_general_overview General overview
39
40<P> High level control interface caches the accesses to primitive controls
41to reduce overhead accessing the real controls in kernel drivers.
42
43*/
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <unistd.h>
48#include <string.h>
49#include <fcntl.h>
50#include <sys/ioctl.h>
51#include "control_local.h"
52#ifdef HAVE_LIBPTHREAD
53#include <pthread.h>
54#endif
55
56#ifndef DOC_HIDDEN
57#define NOT_FOUND 1000000000
58#endif
59
60static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
61				    const snd_hctl_elem_t *c2);
62
63/**
64 * \brief Opens an HCTL
65 * \param hctlp Returned HCTL handle
66 * \param name ASCII identifier of the underlying CTL handle
67 * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
68 * \return 0 on success otherwise a negative error code
69 */
70int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode)
71{
72	snd_ctl_t *ctl;
73	int err;
74
75	if ((err = snd_ctl_open(&ctl, name, mode)) < 0)
76		return err;
77	err = snd_hctl_open_ctl(hctlp, ctl);
78	if (err < 0)
79		snd_ctl_close(ctl);
80	return err;
81}
82
83/**
84 * \brief Opens an HCTL
85 * \param hctlp Returned HCTL handle
86 * \param ctl underlying CTL handle
87 * \return 0 on success otherwise a negative error code
88 */
89int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl)
90{
91	snd_hctl_t *hctl;
92
93	assert(hctlp);
94	*hctlp = NULL;
95	if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL)
96		return -ENOMEM;
97	INIT_LIST_HEAD(&hctl->elems);
98	hctl->ctl = ctl;
99	*hctlp = hctl;
100	return 0;
101}
102
103/**
104 * \brief close HCTL handle
105 * \param hctl HCTL handle
106 * \return 0 on success otherwise a negative error code
107 *
108 * Closes the specified HCTL handle and frees all associated
109 * resources.
110 */
111int snd_hctl_close(snd_hctl_t *hctl)
112{
113	int err;
114
115	assert(hctl);
116	err = snd_ctl_close(hctl->ctl);
117	snd_hctl_free(hctl);
118	free(hctl);
119	return err;
120}
121
122/**
123 * \brief get identifier of HCTL handle
124 * \param hctl HCTL handle
125 * \return ascii identifier of HCTL handle
126 *
127 * Returns the ASCII identifier of given HCTL handle. It's the same
128 * identifier specified in snd_hctl_open().
129 */
130const char *snd_hctl_name(snd_hctl_t *hctl)
131{
132	assert(hctl);
133	return snd_ctl_name(hctl->ctl);
134}
135
136/**
137 * \brief set nonblock mode
138 * \param hctl HCTL handle
139 * \param nonblock 0 = block, 1 = nonblock mode
140 * \return 0 on success otherwise a negative error code
141 */
142int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock)
143{
144	assert(hctl);
145	return snd_ctl_nonblock(hctl->ctl, nonblock);
146}
147
148/**
149 * \brief set async mode
150 * \param hctl HCTL handle
151 * \param sig Signal to raise: < 0 disable, 0 default (SIGIO)
152 * \param pid Process ID to signal: 0 current
153 * \return 0 on success otherwise a negative error code
154 *
155 * A signal is raised when a change happens.
156 */
157int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid)
158{
159	assert(hctl);
160	return snd_ctl_async(hctl->ctl, sig, pid);
161}
162
163/**
164 * \brief get count of poll descriptors for HCTL handle
165 * \param hctl HCTL handle
166 * \return count of poll descriptors
167 */
168int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl)
169{
170	assert(hctl);
171	return snd_ctl_poll_descriptors_count(hctl->ctl);
172}
173
174/**
175 * \brief get poll descriptors
176 * \param hctl HCTL handle
177 * \param pfds array of poll descriptors
178 * \param space space in the poll descriptor array
179 * \return count of filled descriptors
180 */
181int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space)
182{
183	assert(hctl);
184	return snd_ctl_poll_descriptors(hctl->ctl, pfds, space);
185}
186
187/**
188 * \brief get returned events from poll descriptors
189 * \param hctl HCTL handle
190 * \param pfds array of poll descriptors
191 * \param nfds count of poll descriptors
192 * \param revents returned events
193 * \return zero if success, otherwise a negative error code
194 */
195int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
196{
197	assert(hctl);
198	return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents);
199}
200
201static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask,
202			 snd_hctl_elem_t *elem)
203{
204	if (hctl->callback)
205		return hctl->callback(hctl, mask, elem);
206	return 0;
207}
208
209static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem,
210			      unsigned int mask)
211{
212	if (elem->callback)
213		return elem->callback(elem, mask);
214	return 0;
215}
216
217static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef)
218{
219	int res;
220
221	for (res = 0; *names; names++, res += coef) {
222		if (!strncmp(*name, *names, strlen(*names))) {
223			*name += strlen(*names);
224			if (**name == ' ')
225				(*name)++;
226			return res+1;
227		}
228	}
229	return NOT_FOUND;
230}
231
232static int get_compare_weight(const snd_ctl_elem_id_t *id)
233{
234	static const char *const names[] = {
235		"Master",
236		"Hardware Master",
237		"Headphone",
238		"Tone Control",
239		"3D Control",
240		"PCM",
241		"Front",
242		"Surround",
243		"Center",
244		"LFE",
245		"Synth",
246		"FM",
247		"Wave",
248		"Music",
249		"DSP",
250		"Line",
251		"CD",
252		"Mic",
253		"Phone",
254		"Video",
255		"Zoom Video",
256		"PC Speaker",
257		"Aux",
258		"Mono",
259		"ADC",
260		"Capture Source",
261		"Capture",
262		"Playback",
263		"Loopback",
264		"Analog Loopback",
265		"Digital Loopback",
266		"I2S",
267		"IEC958",
268		NULL
269	};
270	static const char *const names1[] = {
271		"Switch",
272		"Volume",
273		"Playback",
274		"Capture",
275		"Bypass",
276		"Mono",
277		"Front",
278		"Rear",
279		"Pan",
280		"Output",
281		"-",
282		NULL
283	};
284	static const char *const names2[] = {
285		"Switch",
286		"Volume",
287		"Bypass",
288		"Depth",
289		"Wide",
290		"Space",
291		"Level",
292		"Center",
293		NULL
294	};
295	const char *name = (char *)id->name, *name1;
296	int res, res1;
297
298	if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND)
299		return NOT_FOUND;
300	if (*name == '\0')
301		return res;
302	for (name1 = name; *name1 != '\0'; name1++);
303	for (name1--; name1 != name && *name1 != ' '; name1--);
304	while (name1 != name && *name1 == ' ')
305		name1--;
306	if (name1 != name) {
307		for (; name1 != name && *name1 != ' '; name1--);
308		name = name1;
309		if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND)
310			return res;
311		res += res1;
312	} else {
313		name = name1;
314	}
315	if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND)
316		return res;
317	return res + res1;
318}
319
320static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir)
321{
322	unsigned int l, u;
323	snd_hctl_elem_t el;
324	int c = 0;
325	int idx = -1;
326	assert(hctl && id);
327	assert(hctl->compare);
328	el.id = *id;
329	el.compare_weight = get_compare_weight(id);
330	l = 0;
331	u = hctl->count;
332	while (l < u) {
333		idx = (l + u) / 2;
334		c = hctl->compare(&el, hctl->pelems[idx]);
335		if (c < 0)
336			u = idx;
337		else if (c > 0)
338			l = idx + 1;
339		else
340			break;
341	}
342	*dir = c;
343	return idx;
344}
345
346static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem)
347{
348	int dir;
349	int idx;
350	elem->compare_weight = get_compare_weight(&elem->id);
351	if (hctl->count == hctl->alloc) {
352		snd_hctl_elem_t **h;
353		hctl->alloc += 32;
354		h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc);
355		if (!h) {
356			hctl->alloc -= 32;
357			return -ENOMEM;
358		}
359		hctl->pelems = h;
360	}
361	if (hctl->count == 0) {
362		list_add_tail(&elem->list, &hctl->elems);
363		hctl->pelems[0] = elem;
364	} else {
365		idx = _snd_hctl_find_elem(hctl, &elem->id, &dir);
366		assert(dir != 0);
367		if (dir > 0) {
368			list_add(&elem->list, &hctl->pelems[idx]->list);
369			idx++;
370		} else {
371			list_add_tail(&elem->list, &hctl->pelems[idx]->list);
372		}
373		memmove(hctl->pelems + idx + 1,
374			hctl->pelems + idx,
375			(hctl->count - idx) * sizeof(snd_hctl_elem_t *));
376		hctl->pelems[idx] = elem;
377	}
378	hctl->count++;
379	return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem);
380}
381
382static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx)
383{
384	snd_hctl_elem_t *elem = hctl->pelems[idx];
385	unsigned int m;
386	snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE);
387	list_del(&elem->list);
388	free(elem);
389	hctl->count--;
390	m = hctl->count - idx;
391	if (m > 0)
392		memmove(hctl->pelems + idx,
393			hctl->pelems + idx + 1,
394			m * sizeof(snd_hctl_elem_t *));
395}
396
397/**
398 * \brief free HCTL loaded elements
399 * \param hctl HCTL handle
400 * \return 0 on success otherwise a negative error code
401 */
402int snd_hctl_free(snd_hctl_t *hctl)
403{
404	while (hctl->count > 0)
405		snd_hctl_elem_remove(hctl, hctl->count - 1);
406	free(hctl->pelems);
407	hctl->pelems = 0;
408	hctl->alloc = 0;
409	INIT_LIST_HEAD(&hctl->elems);
410	return 0;
411}
412
413static snd_hctl_t *compare_hctl;
414static int hctl_compare(const void *a, const void *b) {
415	return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a,
416			     *(const snd_hctl_elem_t * const *) b);
417}
418
419static void snd_hctl_sort(snd_hctl_t *hctl)
420{
421	unsigned int k;
422#ifdef HAVE_LIBPTHREAD
423	static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
424#endif
425
426	assert(hctl);
427	assert(hctl->compare);
428	INIT_LIST_HEAD(&hctl->elems);
429
430#ifdef HAVE_LIBPTHREAD
431	pthread_mutex_lock(&sync_lock);
432#endif
433	compare_hctl = hctl;
434	qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare);
435#ifdef HAVE_LIBPTHREAD
436	pthread_mutex_unlock(&sync_lock);
437#endif
438	for (k = 0; k < hctl->count; k++)
439		list_add_tail(&hctl->pelems[k]->list, &hctl->elems);
440}
441
442/**
443 * \brief Change HCTL compare function and reorder elements
444 * \param hctl HCTL handle
445 * \param compare Element compare function
446 * \return 0 on success otherwise a negative error code
447 */
448int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare)
449{
450	assert(hctl);
451	hctl->compare = compare == NULL ? snd_hctl_compare_default : compare;
452	snd_hctl_sort(hctl);
453	return 0;
454}
455
456/**
457 * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare
458 * \param c1 First HCTL element
459 * \param c2 Second HCTL element
460 * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
461 */
462int snd_hctl_compare_fast(const snd_hctl_elem_t *c1,
463			  const snd_hctl_elem_t *c2)
464{
465	return c1->id.numid - c2->id.numid;
466}
467
468static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
469				    const snd_hctl_elem_t *c2)
470{
471	int res, d;
472
473	d = c1->id.iface - c2->id.iface;
474	if (d != 0)
475		return d;
476	if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) {
477		d = c1->compare_weight - c2->compare_weight;
478		if (d != 0)
479			return d;
480	}
481	d = c1->id.device - c2->id.device;
482	if (d != 0)
483		return d;
484	d = c1->id.subdevice - c2->id.subdevice;
485	if (d != 0)
486		return d;
487	res = strcmp((const char *)c1->id.name, (const char *)c2->id.name);
488	if (res != 0)
489		return res;
490	return c1->id.index - c2->id.index;
491}
492
493/**
494 * \brief get first element for an HCTL
495 * \param hctl HCTL handle
496 * \return pointer to first element
497 */
498snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl)
499{
500	assert(hctl);
501	if (list_empty(&hctl->elems))
502		return NULL;
503	return list_entry(hctl->elems.next, snd_hctl_elem_t, list);
504}
505
506/**
507 * \brief get last element for an HCTL
508 * \param hctl HCTL handle
509 * \return pointer to last element
510 */
511snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl)
512{
513	assert(hctl);
514	if (list_empty(&hctl->elems))
515		return NULL;
516	return list_entry(hctl->elems.prev, snd_hctl_elem_t, list);
517}
518
519/**
520 * \brief get next HCTL element
521 * \param elem HCTL element
522 * \return pointer to next element
523 */
524snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem)
525{
526	assert(elem);
527	if (elem->list.next == &elem->hctl->elems)
528		return NULL;
529	return list_entry(elem->list.next, snd_hctl_elem_t, list);
530}
531
532/**
533 * \brief get previous HCTL element
534 * \param elem HCTL element
535 * \return pointer to previous element
536 */
537snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem)
538{
539	assert(elem);
540	if (elem->list.prev == &elem->hctl->elems)
541		return NULL;
542	return list_entry(elem->list.prev, snd_hctl_elem_t, list);
543}
544
545/**
546 * \brief Search an HCTL element
547 * \param hctl HCTL handle
548 * \param id Element identifier
549 * \return pointer to found HCTL element or NULL if it does not exists
550 */
551snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id)
552{
553	int dir;
554	int res = _snd_hctl_find_elem(hctl, id, &dir);
555	if (res < 0 || dir != 0)
556		return NULL;
557	return hctl->pelems[res];
558}
559
560/**
561 * \brief Load an HCTL with all elements and sort them
562 * \param hctl HCTL handle
563 * \return 0 on success otherwise a negative error code
564 */
565int snd_hctl_load(snd_hctl_t *hctl)
566{
567	snd_ctl_elem_list_t list;
568	int err = 0;
569	unsigned int idx;
570
571	assert(hctl);
572	assert(hctl->ctl);
573	assert(hctl->count == 0);
574	assert(list_empty(&hctl->elems));
575	memset(&list, 0, sizeof(list));
576	if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
577		goto _end;
578	while (list.count != list.used) {
579		err = snd_ctl_elem_list_alloc_space(&list, list.count);
580		if (err < 0)
581			goto _end;
582		if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
583			goto _end;
584	}
585	if (hctl->alloc < list.count) {
586		hctl->alloc = list.count;
587		free(hctl->pelems);
588		hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems));
589		if (!hctl->pelems) {
590			err = -ENOMEM;
591			goto _end;
592		}
593	}
594	for (idx = 0; idx < list.count; idx++) {
595		snd_hctl_elem_t *elem;
596		elem = calloc(1, sizeof(snd_hctl_elem_t));
597		if (elem == NULL) {
598			snd_hctl_free(hctl);
599			err = -ENOMEM;
600			goto _end;
601		}
602		elem->id = list.pids[idx];
603		elem->hctl = hctl;
604		elem->compare_weight = get_compare_weight(&elem->id);
605		hctl->pelems[idx] = elem;
606		list_add_tail(&elem->list, &hctl->elems);
607		hctl->count++;
608	}
609	if (!hctl->compare)
610		hctl->compare = snd_hctl_compare_default;
611	snd_hctl_sort(hctl);
612	for (idx = 0; idx < hctl->count; idx++) {
613		int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD,
614					       hctl->pelems[idx]);
615		if (res < 0)
616			return res;
617	}
618	err = snd_ctl_subscribe_events(hctl->ctl, 1);
619 _end:
620	free(list.pids);
621	return err;
622}
623
624/**
625 * \brief Set callback function for an HCTL
626 * \param hctl HCTL handle
627 * \param callback callback function
628 */
629void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback)
630{
631	assert(hctl);
632	hctl->callback = callback;
633}
634
635/**
636 * \brief Set callback private value for an HCTL
637 * \param hctl HCTL handle
638 * \param callback_private callback private value
639 */
640void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private)
641{
642	assert(hctl);
643	hctl->callback_private = callback_private;
644}
645
646/**
647 * \brief Get callback private value for an HCTL
648 * \param hctl HCTL handle
649 * \return callback private value
650 */
651void *snd_hctl_get_callback_private(snd_hctl_t *hctl)
652{
653	assert(hctl);
654	return hctl->callback_private;
655}
656
657/**
658 * \brief Get number of loaded elements for an HCTL
659 * \param hctl HCTL handle
660 * \return elements count
661 */
662unsigned int snd_hctl_get_count(snd_hctl_t *hctl)
663{
664	return hctl->count;
665}
666
667/**
668 * \brief Wait for a HCTL to become ready (i.e. at least one event pending)
669 * \param hctl HCTL handle
670 * \param timeout maximum time in milliseconds to wait
671 * \return a positive value on success otherwise a negative error code
672 * \retval 0 timeout occurred
673 * \retval 1 an event is pending
674 */
675int snd_hctl_wait(snd_hctl_t *hctl, int timeout)
676{
677	struct pollfd *pfd;
678	unsigned short *revents;
679	int i, npfds, pollio, err, err_poll;
680
681	npfds = snd_hctl_poll_descriptors_count(hctl);
682	if (npfds <= 0 || npfds >= 16) {
683		SNDERR("Invalid poll_fds %d\n", npfds);
684		return -EIO;
685	}
686	pfd = alloca(sizeof(*pfd) * npfds);
687	revents = alloca(sizeof(*revents) * npfds);
688	err = snd_hctl_poll_descriptors(hctl, pfd, npfds);
689	if (err < 0)
690		return err;
691	if (err != npfds) {
692		SNDMSG("invalid poll descriptors %d\n", err);
693		return -EIO;
694	}
695	do {
696		pollio = 0;
697		err_poll = poll(pfd, npfds, timeout);
698		if (err_poll < 0) {
699			if (errno == EINTR)
700				continue;
701			return -errno;
702		}
703		if (! err_poll)
704			break;
705		err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents);
706		if (err < 0)
707			return err;
708		for (i = 0; i < npfds; i++) {
709			if (revents[i] & (POLLERR | POLLNVAL))
710				return -EIO;
711			if ((revents[i] & (POLLIN | POLLOUT)) == 0)
712				continue;
713			pollio++;
714		}
715	} while (! pollio);
716	return err_poll > 0 ? 1 : 0;
717}
718
719/**
720 * \brief Get a ctl handle associated to the given hctl handle
721 * \param hctl HCTL handle
722 * \return a ctl handle otherwise NULL
723 */
724snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl)
725{
726	return hctl->ctl;
727}
728
729static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event)
730{
731	snd_hctl_elem_t *elem;
732	int res;
733
734	assert(hctl);
735	assert(hctl->ctl);
736	switch (event->type) {
737	case SND_CTL_EVENT_ELEM:
738		break;
739	default:
740		return 0;
741	}
742	if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
743		int dir;
744		res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir);
745		assert(res >= 0 && dir == 0);
746		if (res < 0 || dir != 0)
747			return -ENOENT;
748		snd_hctl_elem_remove(hctl, (unsigned int) res);
749		return 0;
750	}
751	if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) {
752		elem = calloc(1, sizeof(snd_hctl_elem_t));
753		if (elem == NULL)
754			return -ENOMEM;
755		elem->id = event->data.elem.id;
756		elem->hctl = hctl;
757		res = snd_hctl_elem_add(hctl, elem);
758		if (res < 0)
759			return res;
760	}
761	if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE |
762				     SNDRV_CTL_EVENT_MASK_INFO)) {
763		elem = snd_hctl_find_elem(hctl, &event->data.elem.id);
764		if (!elem)
765			return -ENOENT;
766		res = snd_hctl_elem_throw_event(elem, event->data.elem.mask &
767						(SNDRV_CTL_EVENT_MASK_VALUE |
768						 SNDRV_CTL_EVENT_MASK_INFO));
769		if (res < 0)
770			return res;
771	}
772	return 0;
773}
774
775/**
776 * \brief Handle pending HCTL events invoking callbacks
777 * \param hctl HCTL handle
778 * \return 0 otherwise a negative error code on failure
779 */
780int snd_hctl_handle_events(snd_hctl_t *hctl)
781{
782	snd_ctl_event_t event;
783	int res;
784	unsigned int count = 0;
785
786	assert(hctl);
787	assert(hctl->ctl);
788	while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 &&
789	       res != -EAGAIN) {
790		if (res < 0)
791			return res;
792		res = snd_hctl_handle_event(hctl, &event);
793		if (res < 0)
794			return res;
795		count++;
796	}
797	return count;
798}
799
800/**
801 * \brief Get information for an HCTL element
802 * \param elem HCTL element
803 * \param info HCTL element information
804 * \return 0 otherwise a negative error code on failure
805 */
806int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info)
807{
808	assert(elem);
809	assert(elem->hctl);
810	assert(info);
811	info->id = elem->id;
812	return snd_ctl_elem_info(elem->hctl->ctl, info);
813}
814
815/**
816 * \brief Get value for an HCTL element
817 * \param elem HCTL element
818 * \param value HCTL element value
819 * \return 0 otherwise a negative error code on failure
820 */
821int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
822{
823	assert(elem);
824	assert(elem->hctl);
825	assert(value);
826	value->id = elem->id;
827	return snd_ctl_elem_read(elem->hctl->ctl, value);
828}
829
830/**
831 * \brief Set value for an HCTL element
832 * \param elem HCTL element
833 * \param value HCTL element value
834 * \retval 0 on success
835 * \retval >1 on success when value was changed
836 * \retval <0 a negative error code on failure
837 */
838int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
839{
840	assert(elem);
841	assert(elem->hctl);
842	assert(value);
843	value->id = elem->id;
844	return snd_ctl_elem_write(elem->hctl->ctl, value);
845}
846
847/**
848 * \brief Get TLV value for an HCTL element
849 * \param elem HCTL element
850 * \param tlv TLV array for value
851 * \param tlv_size size of TLV array in bytes
852 * \return 0 otherwise a negative error code on failure
853 */
854int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
855{
856	assert(elem);
857	assert(tlv);
858	assert(tlv_size >= 12);
859	return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size);
860}
861
862/**
863 * \brief Set TLV value for an HCTL element
864 * \param elem HCTL element
865 * \param tlv TLV array for value
866 * \retval 0 on success
867 * \retval >1 on success when value was changed
868 * \retval <0 a negative error code on failure
869 */
870int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv)
871{
872	assert(elem);
873	assert(tlv);
874	assert(tlv[1] >= 4);
875	return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv);
876}
877
878/**
879 * \brief Set TLV value for an HCTL element
880 * \param elem HCTL element
881 * \param tlv TLV array for value
882 * \retval 0 on success
883 * \retval >1 on success when value was changed
884 * \retval <0 a negative error code on failure
885 */
886int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv)
887{
888	assert(elem);
889	assert(tlv);
890	assert(tlv[1] >= 4);
891	return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv);
892}
893
894/**
895 * \brief Get HCTL handle for an HCTL element
896 * \param elem HCTL element
897 * \return HCTL handle
898 */
899snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem)
900{
901	assert(elem);
902	return elem->hctl;
903}
904
905/**
906 * \brief Get CTL element identifier of a CTL element id/value
907 * \param obj CTL element id/value
908 * \param ptr Pointer to returned CTL element identifier
909 */
910void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
911{
912	assert(obj && ptr);
913	*ptr = obj->id;
914}
915
916/**
917 * \brief Get element numeric identifier of a CTL element id/value
918 * \param obj CTL element id/value
919 * \return element numeric identifier
920 */
921unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj)
922{
923	assert(obj);
924	return obj->id.numid;
925}
926
927/**
928 * \brief Get interface part of CTL element identifier of a CTL element id/value
929 * \param obj CTL element id/value
930 * \return interface part of element identifier
931 */
932snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj)
933{
934	assert(obj);
935	return obj->id.iface;
936}
937
938/**
939 * \brief Get device part of CTL element identifier of a CTL element id/value
940 * \param obj CTL element id/value
941 * \return device part of element identifier
942 */
943unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj)
944{
945	assert(obj);
946	return obj->id.device;
947}
948
949/**
950 * \brief Get subdevice part of CTL element identifier of a CTL element id/value
951 * \param obj CTL element id/value
952 * \return subdevice part of element identifier
953 */
954unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj)
955{
956	assert(obj);
957	return obj->id.subdevice;
958}
959
960/**
961 * \brief Get name part of CTL element identifier of a CTL element id/value
962 * \param obj CTL element id/value
963 * \return name part of element identifier
964 */
965const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj)
966{
967	assert(obj);
968	return (const char *)obj->id.name;
969}
970
971/**
972 * \brief Get index part of CTL element identifier of a CTL element id/value
973 * \param obj CTL element id/value
974 * \return index part of element identifier
975 */
976unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj)
977{
978	assert(obj);
979	return obj->id.index;
980}
981
982/**
983 * \brief Set callback function for an HCTL element
984 * \param obj HCTL element
985 * \param val callback function
986 */
987void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val)
988{
989	assert(obj);
990	obj->callback = val;
991}
992
993/**
994 * \brief Set callback private value for an HCTL element
995 * \param obj HCTL element
996 * \param val callback private value
997 */
998void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val)
999{
1000	assert(obj);
1001	obj->callback_private = val;
1002}
1003
1004/**
1005 * \brief Get callback private value for an HCTL element
1006 * \param obj HCTL element
1007 * \return callback private value
1008 */
1009void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj)
1010{
1011	assert(obj);
1012	return obj->callback_private;
1013}
1014
1015