Imported Upstream version 1.0.28
[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                 snd_hctl_close(hctl);
209                 return err;
210         }
211         return 0;
212 }
213
214 /**
215  * \brief Attach an HCTL to an opened mixer
216  * \param mixer Mixer handle
217  * \param hctl the HCTL to be attached
218  * \return 0 on success otherwise a negative error code
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                 return -ENOMEM;
229         err = snd_hctl_nonblock(hctl, 1);
230         if (err < 0) {
231                 snd_hctl_close(hctl);
232                 free(slave);
233                 return err;
234         }
235         snd_hctl_set_callback(hctl, hctl_event_handler);
236         snd_hctl_set_callback_private(hctl, mixer);
237         slave->hctl = hctl;
238         list_add_tail(&slave->list, &mixer->slaves);
239         return 0;
240 }
241
242 /**
243  * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
244  * \param mixer Mixer handle
245  * \param name HCTL previously attached
246  * \return 0 on success otherwise a negative error code
247  */
248 int snd_mixer_detach(snd_mixer_t *mixer, const char *name)
249 {
250         struct list_head *pos;
251         list_for_each(pos, &mixer->slaves) {
252                 snd_mixer_slave_t *s;
253                 s = list_entry(pos, snd_mixer_slave_t, list);
254                 if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
255                         snd_hctl_close(s->hctl);
256                         list_del(pos);
257                         free(s);
258                         return 0;
259                 }
260         }
261         return -ENOENT;
262 }
263
264 /**
265  * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
266  * \param mixer Mixer handle
267  * \param hctl HCTL previously attached
268  * \return 0 on success otherwise a negative error code
269  *
270  * Note: The hctl handle is not closed!
271  */
272 int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
273 {
274         struct list_head *pos;
275         list_for_each(pos, &mixer->slaves) {
276                 snd_mixer_slave_t *s;
277                 s = list_entry(pos, snd_mixer_slave_t, list);
278                 if (hctl == s->hctl) {
279                         list_del(pos);
280                         free(s);
281                         return 0;
282                 }
283         }
284         return -ENOENT;
285 }
286
287 /**
288  * \brief Obtain a HCTL pointer associated to given name
289  * \param mixer Mixer handle
290  * \param name HCTL previously attached
291  * \param hctl HCTL pointer
292  * \return 0 on success otherwise a negative error code
293  */
294 int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl)
295 {
296         struct list_head *pos;
297         list_for_each(pos, &mixer->slaves) {
298                 snd_mixer_slave_t *s;
299                 s = list_entry(pos, snd_mixer_slave_t, list);
300                 if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
301                         *hctl = s->hctl;
302                         return 0;
303                 }
304         }
305         return -ENOENT;
306 }
307
308 static int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask,
309                           snd_mixer_elem_t *elem)
310 {
311         mixer->events++;
312         if (mixer->callback)
313                 return mixer->callback(mixer, mask, elem);
314         return 0;
315 }
316
317 static int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask)
318 {
319         elem->class->mixer->events++;
320         if (elem->callback)
321                 return elem->callback(elem, mask);
322         return 0;
323 }
324
325 static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir)
326 {
327         unsigned int l, u;
328         int c = 0;
329         int idx = -1;
330         assert(mixer && elem);
331         assert(mixer->compare);
332         l = 0;
333         u = mixer->count;
334         while (l < u) {
335                 idx = (l + u) / 2;
336                 c = mixer->compare(elem, mixer->pelems[idx]);
337                 if (c < 0)
338                         u = idx;
339                 else if (c > 0)
340                         l = idx + 1;
341                 else
342                         break;
343         }
344         *dir = c;
345         return idx;
346 }
347
348 /**
349  * \brief Get private data associated to give mixer element
350  * \param elem Mixer element
351  * \return private data
352  *
353  * For use by mixer element class specific code.
354  */
355 void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem)
356 {
357         return elem->private_data;
358 }
359
360 /**
361  * \brief Allocate a new mixer element
362  * \param elem Returned mixer element
363  * \param type Mixer element type
364  * \param compare_weight Mixer element compare weight
365  * \param private_data Private data
366  * \param private_free Private data free callback
367  * \return 0 on success otherwise a negative error code
368  *
369  * For use by mixer element class specific code.
370  */
371 int snd_mixer_elem_new(snd_mixer_elem_t **elem,
372                        snd_mixer_elem_type_t type,
373                        int compare_weight,
374                        void *private_data,
375                        void (*private_free)(snd_mixer_elem_t *elem))
376 {
377         snd_mixer_elem_t *melem = calloc(1, sizeof(*melem));
378         if (melem == NULL)
379                 return -ENOMEM;
380         melem->type = type;
381         melem->compare_weight = compare_weight;
382         melem->private_data = private_data;
383         melem->private_free = private_free;
384         INIT_LIST_HEAD(&melem->helems);
385         *elem = melem;
386         return 0;
387 }
388
389 /**
390  * \brief Add an element for a registered mixer element class
391  * \param elem Mixer element
392  * \param class Mixer element class
393  * \return 0 on success otherwise a negative error code
394  *
395  * For use by mixer element class specific code.
396  */
397 int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
398 {
399         int dir, idx;
400         snd_mixer_t *mixer = class->mixer;
401         elem->class = class;
402
403         if (mixer->count == mixer->alloc) {
404                 snd_mixer_elem_t **m;
405                 mixer->alloc += 32;
406                 m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc);
407                 if (!m) {
408                         mixer->alloc -= 32;
409                         return -ENOMEM;
410                 }
411                 mixer->pelems = m;
412         }
413         if (mixer->count == 0) {
414                 list_add_tail(&elem->list, &mixer->elems);
415                 mixer->pelems[0] = elem;
416         } else {
417                 idx = _snd_mixer_find_elem(mixer, elem, &dir);
418                 assert(dir != 0);
419                 if (dir > 0) {
420                         list_add(&elem->list, &mixer->pelems[idx]->list);
421                         idx++;
422                 } else {
423                         list_add_tail(&elem->list, &mixer->pelems[idx]->list);
424                 }
425                 memmove(mixer->pelems + idx + 1,
426                         mixer->pelems + idx,
427                         (mixer->count - idx) * sizeof(snd_mixer_elem_t *));
428                 mixer->pelems[idx] = elem;
429         }
430         mixer->count++;
431         return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem);
432 }
433
434 /**
435  * \brief Remove a mixer element
436  * \param elem Mixer element
437  * \return 0 on success otherwise a negative error code
438  *
439  * For use by mixer element class specific code.
440  */
441 int snd_mixer_elem_remove(snd_mixer_elem_t *elem)
442 {
443         snd_mixer_t *mixer = elem->class->mixer;
444         bag_iterator_t i, n;
445         int err, idx, dir;
446         unsigned int m;
447         assert(elem);
448         assert(mixer->count);
449         idx = _snd_mixer_find_elem(mixer, elem, &dir);
450         if (dir != 0)
451                 return -EINVAL;
452         bag_for_each_safe(i, n, &elem->helems) {
453                 snd_hctl_elem_t *helem = bag_iterator_entry(i);
454                 snd_mixer_elem_detach(elem, helem);
455         }
456         err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
457         list_del(&elem->list);
458         snd_mixer_elem_free(elem);
459         mixer->count--;
460         m = mixer->count - idx;
461         if (m > 0)
462                 memmove(mixer->pelems + idx,
463                         mixer->pelems + idx + 1,
464                         m * sizeof(snd_mixer_elem_t *));
465         return err;
466 }
467
468 /**
469  * \brief Free a mixer element
470  * \param elem Mixer element
471  * \return 0 on success otherwise a negative error code
472  *
473  * For use by mixer element class specific code.
474  */
475 void snd_mixer_elem_free(snd_mixer_elem_t *elem)
476 {
477         if (elem->private_free)
478                 elem->private_free(elem);
479         free(elem);
480 }
481
482 /**
483  * \brief Mixer element informations are changed
484  * \param elem Mixer element
485  * \return 0 on success otherwise a negative error code
486  *
487  * For use by mixer element class specific code.
488  */
489 int snd_mixer_elem_info(snd_mixer_elem_t *elem)
490 {
491         return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
492 }
493
494 /**
495  * \brief Mixer element values is changed
496  * \param elem Mixer element
497  * \return 0 on success otherwise a negative error code
498  *
499  * For use by mixer element class specific code.
500  */
501 int snd_mixer_elem_value(snd_mixer_elem_t *elem)
502 {
503         return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
504 }
505
506 /**
507  * \brief Register mixer element class
508  * \param class Mixer element class
509  * \param mixer Mixer handle
510  * \return 0 on success otherwise a negative error code
511  *
512  * For use by mixer element class specific code.
513  */
514 int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer)
515 {
516         struct list_head *pos;
517         class->mixer = mixer;
518         list_add_tail(&class->list, &mixer->classes);
519         if (!class->event)
520                 return 0;
521         list_for_each(pos, &mixer->slaves) {
522                 int err;
523                 snd_mixer_slave_t *slave;
524                 snd_hctl_elem_t *elem;
525                 slave = list_entry(pos, snd_mixer_slave_t, list);
526                 elem = snd_hctl_first_elem(slave->hctl);
527                 while (elem) {
528                         err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL);
529                         if (err < 0)
530                                 return err;
531                         elem = snd_hctl_elem_next(elem);
532                 }
533         }
534         return 0;
535 }
536
537 /**
538  * \brief Unregister mixer element class and remove all its elements
539  * \param class Mixer element class
540  * \return 0 on success otherwise a negative error code
541  *
542  * Note that the class structure is also deallocated!
543  */
544 int snd_mixer_class_unregister(snd_mixer_class_t *class)
545 {
546         unsigned int k;
547         snd_mixer_elem_t *e;
548         snd_mixer_t *mixer = class->mixer;
549         for (k = mixer->count; k > 0; k--) {
550                 e = mixer->pelems[k-1];
551                 if (e->class == class)
552                         snd_mixer_elem_remove(e);
553         }
554         if (class->private_free)
555                 class->private_free(class);
556         list_del(&class->list);
557         free(class);
558         return 0;
559 }
560
561 /**
562  * \brief Load a mixer elements
563  * \param mixer Mixer handle
564  * \return 0 on success otherwise a negative error code
565  */
566 int snd_mixer_load(snd_mixer_t *mixer)
567 {
568         struct list_head *pos;
569         list_for_each(pos, &mixer->slaves) {
570                 int err;
571                 snd_mixer_slave_t *s;
572                 s = list_entry(pos, snd_mixer_slave_t, list);
573                 err = snd_hctl_load(s->hctl);
574                 if (err < 0)
575                         return err;
576         }
577         return 0;
578 }
579
580 /**
581  * \brief Unload all mixer elements and free all related resources
582  * \param mixer Mixer handle
583  */
584 void snd_mixer_free(snd_mixer_t *mixer)
585 {
586         struct list_head *pos;
587         list_for_each(pos, &mixer->slaves) {
588                 snd_mixer_slave_t *s;
589                 s = list_entry(pos, snd_mixer_slave_t, list);
590                 snd_hctl_free(s->hctl);
591         }
592 }
593
594 /**
595  * \brief Close a mixer and free all related resources
596  * \param mixer Mixer handle
597  * \return 0 on success otherwise a negative error code
598  */
599 int snd_mixer_close(snd_mixer_t *mixer)
600 {
601         int res = 0;
602         assert(mixer);
603         while (!list_empty(&mixer->classes)) {
604                 snd_mixer_class_t *c;
605                 c = list_entry(mixer->classes.next, snd_mixer_class_t, list);
606                 snd_mixer_class_unregister(c);
607         }
608         assert(list_empty(&mixer->elems));
609         assert(mixer->count == 0);
610         free(mixer->pelems);
611         mixer->pelems = NULL;
612         while (!list_empty(&mixer->slaves)) {
613                 int err;
614                 snd_mixer_slave_t *s;
615                 s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list);
616                 err = snd_hctl_close(s->hctl);
617                 if (err < 0)
618                         res = err;
619                 list_del(&s->list);
620                 free(s);
621         }
622         free(mixer);
623         return res;
624 }
625
626 static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
627                                      const snd_mixer_elem_t *c2)
628 {
629         int d = c1->compare_weight - c2->compare_weight;
630         if (d)
631                 return d;
632         assert(c1->class && c1->class->compare);
633         assert(c2->class && c2->class->compare);
634         assert(c1->class == c2->class);
635         return c1->class->compare(c1, c2);
636 }
637
638 static int mixer_compare(const void *a, const void *b)
639 {
640         snd_mixer_t *mixer;
641
642         mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer;
643         return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b);
644 }
645
646 static int snd_mixer_sort(snd_mixer_t *mixer)
647 {
648         unsigned int k;
649         assert(mixer);
650         assert(mixer->compare);
651         INIT_LIST_HEAD(&mixer->elems);
652         qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare);
653         for (k = 0; k < mixer->count; k++)
654                 list_add_tail(&mixer->pelems[k]->list, &mixer->elems);
655         return 0;
656 }
657
658 /**
659  * \brief Change mixer compare function and reorder elements
660  * \param mixer Mixer handle
661  * \param compare Element compare function
662  * \return 0 on success otherwise a negative error code
663  */
664 int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare)
665 {
666         snd_mixer_compare_t compare_old;
667         int err;
668
669         assert(mixer);
670         compare_old = mixer->compare;
671         mixer->compare = compare == NULL ? snd_mixer_compare_default : compare;
672         if ((err = snd_mixer_sort(mixer)) < 0) {
673                 mixer->compare = compare_old;
674                 return err;
675         }
676         return 0;
677 }
678
679 /**
680  * \brief get count of poll descriptors for mixer handle
681  * \param mixer Mixer handle
682  * \return count of poll descriptors
683  */
684 int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
685 {
686         struct list_head *pos;
687         unsigned int c = 0;
688         assert(mixer);
689         list_for_each(pos, &mixer->slaves) {
690                 snd_mixer_slave_t *s;
691                 int n;
692                 s = list_entry(pos, snd_mixer_slave_t, list);
693                 n = snd_hctl_poll_descriptors_count(s->hctl);
694                 if (n < 0)
695                         return n;
696                 c += n;
697         }
698         return c;
699 }
700
701 /**
702  * \brief get poll descriptors
703  * \param mixer Mixer handle
704  * \param pfds array of poll descriptors
705  * \param space space in the poll descriptor array
706  * \return count of filled descriptors
707  */
708 int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
709 {
710         struct list_head *pos;
711         unsigned int count = 0;
712         assert(mixer);
713         list_for_each(pos, &mixer->slaves) {
714                 snd_mixer_slave_t *s;
715                 int n;
716                 s = list_entry(pos, snd_mixer_slave_t, list);
717                 n = snd_hctl_poll_descriptors(s->hctl, pfds, space);
718                 if (n < 0)
719                         return n;
720                 if (space >= (unsigned int) n) {
721                         count += n;
722                         space -= n;
723                         pfds += n;
724                 } else
725                         space = 0;
726         }
727         return count;
728 }
729
730 /**
731  * \brief get returned events from poll descriptors
732  * \param mixer Mixer handle
733  * \param pfds array of poll descriptors
734  * \param nfds count of poll descriptors
735  * \param revents returned events
736  * \return zero if success, otherwise a negative error code
737  */
738 int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
739 {
740         unsigned int idx;
741         unsigned short res;
742         assert(mixer && pfds && revents);
743         if (nfds == 0)
744                 return -EINVAL;
745         res = 0;
746         for (idx = 0; idx < nfds; idx++, pfds++)
747                 res |= pfds->revents & (POLLIN|POLLERR|POLLNVAL);
748         *revents = res;
749         return 0;
750 }
751
752 /**
753  * \brief Wait for a mixer to become ready (i.e. at least one event pending)
754  * \param mixer Mixer handle
755  * \param timeout maximum time in milliseconds to wait
756  * \return 0 otherwise a negative error code on failure
757  */
758 int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
759 {
760         struct pollfd spfds[16];
761         struct pollfd *pfds = spfds;
762         int err;
763         int count;
764         count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
765         if (count < 0)
766                 return count;
767         if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) {
768                 pfds = malloc(count * sizeof(*pfds));
769                 if (!pfds)
770                         return -ENOMEM;
771                 err = snd_mixer_poll_descriptors(mixer, pfds, 
772                                                  (unsigned int) count);
773                 assert(err == count);
774         }
775         err = poll(pfds, (unsigned int) count, timeout);
776         if (err < 0)
777                 return -errno;
778         return 0;
779 }
780
781 /**
782  * \brief get first element for a mixer
783  * \param mixer Mixer handle
784  * \return pointer to first element
785  */
786 snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer)
787 {
788         assert(mixer);
789         if (list_empty(&mixer->elems))
790                 return NULL;
791         return list_entry(mixer->elems.next, snd_mixer_elem_t, list);
792 }
793
794 /**
795  * \brief get last element for a mixer
796  * \param mixer Mixer handle
797  * \return pointer to last element
798  */
799 snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer)
800 {
801         assert(mixer);
802         if (list_empty(&mixer->elems))
803                 return NULL;
804         return list_entry(mixer->elems.prev, snd_mixer_elem_t, list);
805 }
806
807 /**
808  * \brief get next mixer element
809  * \param elem mixer element
810  * \return pointer to next element
811  */
812 snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem)
813 {
814         assert(elem);
815         if (elem->list.next == &elem->class->mixer->elems)
816                 return NULL;
817         return list_entry(elem->list.next, snd_mixer_elem_t, list);
818 }
819
820 /**
821  * \brief get previous mixer element
822  * \param elem mixer element
823  * \return pointer to previous element
824  */
825 snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem)
826 {
827         assert(elem);
828         if (elem->list.prev == &elem->class->mixer->elems)
829                 return NULL;
830         return list_entry(elem->list.prev, snd_mixer_elem_t, list);
831 }
832
833 /**
834  * \brief Handle pending mixer events invoking callbacks
835  * \param mixer Mixer handle
836  * \return Number of events that occured on success, otherwise a negative error code on failure
837  */
838 int snd_mixer_handle_events(snd_mixer_t *mixer)
839 {
840         struct list_head *pos;
841         assert(mixer);
842         mixer->events = 0;
843         list_for_each(pos, &mixer->slaves) {
844                 int err;
845                 snd_mixer_slave_t *s;
846                 s = list_entry(pos, snd_mixer_slave_t, list);
847                 err = snd_hctl_handle_events(s->hctl);
848                 if (err < 0)
849                         return err;
850         }
851         return mixer->events;
852 }
853
854 /**
855  * \brief Set callback function for a mixer
856  * \param obj mixer handle
857  * \param val callback function
858  */
859 void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val)
860 {
861         assert(obj);
862         obj->callback = val;
863 }
864
865 /**
866  * \brief Set callback private value for a mixer
867  * \param mixer mixer handle
868  * \param val callback private value
869  */
870 void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val)
871 {
872         assert(mixer);
873         mixer->callback_private = val;
874 }
875
876 /**
877  * \brief Get callback private value for a mixer
878  * \param mixer mixer handle
879  * \return callback private value
880  */
881 void * snd_mixer_get_callback_private(const snd_mixer_t *mixer)
882 {
883         assert(mixer);
884         return mixer->callback_private;
885 }
886
887 /**
888  * \brief Get elements count for a mixer
889  * \param mixer mixer handle
890  * \return elements count
891  */
892 unsigned int snd_mixer_get_count(const snd_mixer_t *mixer)
893 {
894         assert(mixer);
895         return mixer->count;
896 }
897
898 /**
899  * \brief Set callback function for a mixer element
900  * \param mixer mixer element
901  * \param val callback function
902  */
903 void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val)
904 {
905         assert(mixer);
906         mixer->callback = val;
907 }
908
909 /**
910  * \brief Set callback private value for a mixer element
911  * \param mixer mixer element
912  * \param val callback private value
913  */
914 void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val)
915 {
916         assert(mixer);
917         mixer->callback_private = val;
918 }
919
920 /**
921  * \brief Get callback private value for a mixer element
922  * \param mixer mixer element
923  * \return callback private value
924  */
925 void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer)
926 {
927         assert(mixer);
928         return mixer->callback_private;
929 }
930
931 /**
932  * \brief Get type for a mixer element
933  * \param mixer mixer element
934  * \return mixer element type
935  */
936 snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer)
937 {
938         assert(mixer);
939         return mixer->type;
940 }
941
942
943 /**
944  * \brief get size of #snd_mixer_class_t
945  * \return size in bytes
946  */
947 size_t snd_mixer_class_sizeof()
948 {
949         return sizeof(snd_mixer_class_t);
950 }
951
952 /**
953  * \brief allocate an invalid #snd_mixer_class_t using standard malloc
954  * \param ptr returned pointer
955  * \return 0 on success otherwise negative error code
956  */
957 int snd_mixer_class_malloc(snd_mixer_class_t **ptr)
958 {
959         assert(ptr);
960         *ptr = calloc(1, sizeof(snd_mixer_class_t));
961         if (!*ptr)
962                 return -ENOMEM;
963         return 0;
964 }
965
966 /**
967  * \brief frees a previously allocated #snd_mixer_class_t
968  * \param obj pointer to object to free
969  */
970 void snd_mixer_class_free(snd_mixer_class_t *obj)
971 {
972         if (obj->private_free)
973                 obj->private_free(obj);
974         free(obj);
975 }
976
977 /**
978  * \brief copy one #snd_mixer_class_t to another
979  * \param dst pointer to destination
980  * \param src pointer to source
981  */
982 void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src)
983 {
984         assert(dst && src);
985         *dst = *src;
986 }
987
988 /**
989  * \brief Get a mixer associated to given mixer class
990  * \param obj Mixer simple class identifier
991  * \return mixer pointer
992  */
993 snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj)
994 {
995         assert(obj);
996         return obj->mixer;
997 }
998
999 /**
1000  * \brief Get mixer event callback associated to given mixer class
1001  * \param obj Mixer simple class identifier
1002  * \return event callback pointer
1003  */
1004 snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj)
1005 {
1006         assert(obj);
1007         return obj->event;
1008 }
1009
1010 /**
1011  * \brief Get mixer private data associated to given mixer class
1012  * \param obj Mixer simple class identifier
1013  * \return event callback pointer
1014  */
1015 void *snd_mixer_class_get_private(const snd_mixer_class_t *obj)
1016 {
1017         assert(obj);
1018         return obj->private_data;
1019 }
1020
1021
1022 /**
1023  * \brief Get mixer compare callback associated to given mixer class
1024  * \param obj Mixer simple class identifier
1025  * \return event callback pointer
1026  */
1027 snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj)
1028 {
1029         assert(obj);
1030         return obj->compare;
1031 }
1032
1033 /**
1034  * \brief Set mixer event callback to given mixer class
1035  * \param obj Mixer simple class identifier
1036  * \param event Event callback
1037  * \return zero if success, otherwise a negative error code
1038  */
1039 int snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event)
1040 {
1041         assert(obj);
1042         obj->event = event;
1043         return 0;
1044 }
1045
1046 /**
1047  * \brief Set mixer private data to given mixer class
1048  * \param obj Mixer simple class identifier
1049  * \param private_data class private data
1050  * \return zero if success, otherwise a negative error code
1051  */
1052 int snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data)
1053 {
1054         assert(obj);
1055         obj->private_data = private_data;
1056         return 0;
1057 }
1058
1059 /**
1060  * \brief Set mixer private data free callback to given mixer class
1061  * \param obj Mixer simple class identifier
1062  * \param private_free Mixer class private data free callback
1063  * \return zero if success, otherwise a negative error code
1064  */
1065 int snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *))
1066 {
1067         assert(obj);
1068         obj->private_free = private_free;
1069         return 0;
1070 }
1071
1072 /**
1073  * \brief Set mixer compare callback to given mixer class
1074  * \param obj Mixer simple class identifier
1075  * \param compare the compare callback to be used
1076  * \return zero if success, otherwise a negative error code
1077  */
1078 int snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare)
1079 {
1080         assert(obj);
1081         obj->compare = compare;
1082         return 0;
1083 }