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