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