]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Initial amixer implementation + ctl & hctl API merging amixer
authorJaroslav Kysela <perex@perex.cz>
Tue, 12 May 2009 06:05:50 +0000 (08:05 +0200)
committerJaroslav Kysela <perex@perex.cz>
Fri, 15 May 2009 12:18:15 +0000 (14:18 +0200)
This patch adds new mixer API which simplifies the previous mixer
API (removed mixer class).

The control and hcontrol APIs were merged into one.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
29 files changed:
Makefile.am
include/control.h
include/mixer.h
include/mixer_abst.h
include/mixer_old.h [new file with mode: 0644]
modules/mixer/Makefile.am
modules/mixer/simple/sbase.c
modules/mixer/simple/sbase.h
modules/mixer/simple/sbasedl.c
src/Makefile.am
src/conf/alsa.conf
src/control/Makefile.am
src/control/control.c
src/control/control_ext.c
src/control/control_hw.c
src/control/control_local.h
src/control/control_shm.c
src/control/hcontrol.c
src/control/hcontrol_old.c [new file with mode: 0644]
src/mixer/Makefile.am
src/mixer/mixer.c
src/mixer/mixer_local.h
src/mixer/mixer_old.c [new file with mode: 0644]
src/mixer/mixer_old_local.h [moved from src/mixer/mixer_simple.h with 57% similarity]
src/mixer/mixer_symbols.c [new file with mode: 0644]
src/mixer/simple.c
src/mixer/simple_abst.c [deleted file]
src/mixer/simple_none.c
src/mixer/simple_old.c [new file with mode: 0644]

index f0c39c1de48eb20bffbec9dc059a722aa3bde8ad..924ae5e66c95052cf7d4c24ae46503afad07dc68 100644 (file)
@@ -9,7 +9,7 @@ SUBDIRS += aserver
 endif
 if BUILD_MIXER
 if BUILD_ALISP
-SUBDIRS += alsalisp
+#SUBDIRS += alsalisp
 endif
 endif
 SUBDIRS += test utils
index 2361dc3a01399b646e15f33cd8e971ca6fdf5ea7..d2076f04f6f7619ae4e0dc05f4a12ff286f9f55d 100644 (file)
@@ -4,7 +4,7 @@
  * \author Jaroslav Kysela <perex@perex.cz>
  * \author Abramo Bagnara <abramo@alsa-project.org>
  * \author Takashi Iwai <tiwai@suse.de>
- * \date 1998-2001
+ * \date 1998-2008
  *
  * Application interface library for the ALSA driver
  */
@@ -199,14 +199,13 @@ typedef enum _snd_ctl_type {
 /** Read only (flag for open mode) \hideinitializer */
 #define SND_CTL_READONLY               0x0004
 
+/** Cache (extended) mode (flag for open mode) \hideinitializer */
+#define SND_CTL_CACHE                  0x0008
+
 /** CTL handle */
 typedef struct _snd_ctl snd_ctl_t;
-
-/** Don't destroy the ctl handle when close */
-#define SND_SCTL_NOFREE                        0x0001
-
-/** SCTL type */
-typedef struct _snd_sctl snd_sctl_t;
+/** CTL element handle */
+typedef struct _snd_ctl_elem snd_ctl_elem_t;
 
 int snd_card_load(int card);
 int snd_card_next(int *card);
@@ -466,89 +465,72 @@ int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
 /**
  *  \defgroup HControl High level Control Interface
  *  \ingroup Control
- *  The high level control interface.
+ *  The high level control interface. The #SND_CTL_CACHE flag must be
+ *  set to enable this interface.
  *  See \ref hcontrol page for more details.
  *  \{
  */
 
-/** HCTL element handle */
-typedef struct _snd_hctl_elem snd_hctl_elem_t;
-
-/** HCTL handle */
-typedef struct _snd_hctl snd_hctl_t;
-
 /**
- * \brief Compare function for sorting HCTL elements
+ * \brief Compare function for sorting CTL elements
  * \param e1 First element
  * \param e2 Second element
  * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2
  */
-typedef int (*snd_hctl_compare_t)(const snd_hctl_elem_t *e1,
-                                 const snd_hctl_elem_t *e2);
-int snd_hctl_compare_fast(const snd_hctl_elem_t *c1,
-                         const snd_hctl_elem_t *c2);
+typedef int (*snd_ctl_compare_t)(const snd_ctl_elem_t *e1,
+                                const snd_ctl_elem_t *e2);
+int snd_ctl_compare_fast(const snd_ctl_elem_t *c1,
+                        const snd_ctl_elem_t *c2);
 /** 
- * \brief HCTL callback function
- * \param hctl HCTL handle
+ * \brief CTL callback function
+ * \param ctl CTL handle
  * \param mask event mask
- * \param elem related HCTL element (if any)
+ * \param elem related CTL element (if any)
  * \return 0 on success otherwise a negative error code
  */
-typedef int (*snd_hctl_callback_t)(snd_hctl_t *hctl,
-                                  unsigned int mask,
-                                  snd_hctl_elem_t *elem);
+typedef int (*snd_ctl_callback_t)(snd_ctl_t *ctl,
+                                 unsigned int mask,
+                                 snd_ctl_elem_t *elem);
 /** 
- * \brief HCTL element callback function
- * \param elem HCTL element
+ * \brief CTL element callback function
+ * \param elem CTL element
  * \param mask event mask
  * \return 0 on success otherwise a negative error code
  */
-typedef int (*snd_hctl_elem_callback_t)(snd_hctl_elem_t *elem,
-                                       unsigned int mask);
-
-int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode);
-int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl);
-int snd_hctl_close(snd_hctl_t *hctl);
-int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock);
-int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl);
-int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space);
-int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
-unsigned int snd_hctl_get_count(snd_hctl_t *hctl);
-int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort);
-snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl);
-snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl);
-snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id);
-void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback);
-void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data);
-void *snd_hctl_get_callback_private(snd_hctl_t *hctl);
-int snd_hctl_load(snd_hctl_t *hctl);
-int snd_hctl_free(snd_hctl_t *hctl);
-int snd_hctl_handle_events(snd_hctl_t *hctl);
-const char *snd_hctl_name(snd_hctl_t *hctl);
-int snd_hctl_wait(snd_hctl_t *hctl, int timeout);
-snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl);
-
-snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem);
-snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem);
-int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info);
-int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
-int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
-int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size);
-int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv);
-int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv);
-
-snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem);
-
-void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr);
-unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj);
-snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj);
-unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj);
-unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj);
-const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj);
-unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj);
-void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val);
-void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj);
-void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val);
+typedef int (*snd_ctl_elem_callback_t)(snd_ctl_elem_t *elem,
+                                      unsigned int mask);
+
+unsigned int snd_ctl_get_count(snd_ctl_t *ctl);
+int snd_ctl_set_compare(snd_ctl_t *ctl, snd_ctl_compare_t hsort);
+snd_ctl_elem_t *snd_ctl_first_elem(snd_ctl_t *ctl);
+snd_ctl_elem_t *snd_ctl_last_elem(snd_ctl_t *ctl);
+snd_ctl_elem_t *snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id);
+void snd_ctl_set_callback(snd_ctl_t *ctl, snd_ctl_callback_t callback);
+void snd_ctl_set_callback_private(snd_ctl_t *ctl, void *data);
+void *snd_ctl_get_callback_private(snd_ctl_t *ctl);
+int snd_ctl_handle_events(snd_ctl_t *ctl);
+
+snd_ctl_elem_t *snd_ctl_elem_next(snd_ctl_elem_t *elem);
+snd_ctl_elem_t *snd_ctl_elem_prev(snd_ctl_elem_t *elem);
+int snd_ctl_celem_info(snd_ctl_elem_t *elem, snd_ctl_elem_info_t * info);
+int snd_ctl_celem_read(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value);
+int snd_ctl_celem_write(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value);
+int snd_ctl_celem_tlv_read(snd_ctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size);
+int snd_ctl_celem_tlv_write(snd_ctl_elem_t *elem, const unsigned int *tlv);
+int snd_ctl_celem_tlv_command(snd_ctl_elem_t *elem, const unsigned int *tlv);
+
+snd_ctl_t *snd_ctl_elem_get_ctl(snd_ctl_elem_t *elem);
+
+void snd_ctl_elem_get_id(const snd_ctl_elem_t *obj, snd_ctl_elem_id_t *ptr);
+unsigned int snd_ctl_elem_get_numid(const snd_ctl_elem_t *obj);
+snd_ctl_elem_iface_t snd_ctl_elem_get_interface(const snd_ctl_elem_t *obj);
+unsigned int snd_ctl_elem_get_device(const snd_ctl_elem_t *obj);
+unsigned int snd_ctl_elem_get_subdevice(const snd_ctl_elem_t *obj);
+const char *snd_ctl_elem_get_name(const snd_ctl_elem_t *obj);
+unsigned int snd_ctl_elem_get_index(const snd_ctl_elem_t *obj);
+void snd_ctl_elem_set_callback(snd_ctl_elem_t *obj, snd_ctl_elem_callback_t val);
+void * snd_ctl_elem_get_callback_private(const snd_ctl_elem_t *obj);
+void snd_ctl_elem_set_callback_private(snd_ctl_elem_t *obj, void * val);
 
 /** \} */
 
@@ -561,6 +543,12 @@ void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val);
  *  \{
  */
 
+/** Don't destroy the ctl handle when close */
+#define SND_SCTL_NOFREE                        0x0001
+
+/** SCTL type */
+typedef struct _snd_sctl snd_sctl_t;
+
 int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config,
                   snd_config_t *private_data, int mode);
 int snd_sctl_free(snd_sctl_t *handle);
index df921642705e0249557392b53a17d2e91de3cdfe..dd79fef8108e1aa71921fa450db8e275969a0260 100644 (file)
@@ -1,10 +1,10 @@
-/**
+/*
  * \file include/mixer.h
  * \brief Application interface library for the ALSA driver
  * \author Jaroslav Kysela <perex@perex.cz>
  * \author Abramo Bagnara <abramo@alsa-project.org>
  * \author Takashi Iwai <tiwai@suse.de>
- * \date 1998-2001
+ * \date 1998-2009
  *
  * Application interface library for the ALSA driver
  */
@@ -34,142 +34,27 @@ extern "C" {
 
 /**
  *  \defgroup Mixer Mixer Interface
- *  The mixer interface.
+ *  The amixer interface.
  *  \{
  */
 
-/** Mixer handle */
-typedef struct _snd_mixer snd_mixer_t;
-/** Mixer elements class handle */
-typedef struct _snd_mixer_class snd_mixer_class_t;
-/** Mixer element handle */
-typedef struct _snd_mixer_elem snd_mixer_elem_t;
-
-/** 
- * \brief Mixer callback function
- * \param mixer Mixer handle
- * \param mask event mask
- * \param elem related mixer element (if any)
- * \return 0 on success otherwise a negative error code
- */
-typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl,
-                                   unsigned int mask,
-                                   snd_mixer_elem_t *elem);
-
-/** 
- * \brief Mixer element callback function
- * \param elem Mixer element
- * \param mask event mask
- * \return 0 on success otherwise a negative error code
- */
-typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem,
-                                        unsigned int mask);
-
-/**
- * \brief Compare function for sorting mixer elements
- * \param e1 First element
- * \param e2 Second element
- * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2
- */
-typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1,
-                                  const snd_mixer_elem_t *e2);
-
-/**
- * \brief Event callback for the mixer class
- * \param class_ Mixer class
- * \param mask Event mask (SND_CTL_EVENT_*)
- * \param helem HCTL element which invoked the event
- * \param melem Mixer element associated to HCTL element
- * \return zero if success, otherwise a negative error value
- */
-typedef int (*snd_mixer_event_t)(snd_mixer_class_t *class_, unsigned int mask,
-                                snd_hctl_elem_t *helem, snd_mixer_elem_t *melem);
-
-
-/** Mixer element type */
-typedef enum _snd_mixer_elem_type {
-       /* Simple mixer elements */
-       SND_MIXER_ELEM_SIMPLE,
-       SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE
-} snd_mixer_elem_type_t;
-
-int snd_mixer_open(snd_mixer_t **mixer, int mode);
-int snd_mixer_close(snd_mixer_t *mixer);
-snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer);
-snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer);
-int snd_mixer_handle_events(snd_mixer_t *mixer);
-int snd_mixer_attach(snd_mixer_t *mixer, const char *name);
-int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl);
-int snd_mixer_detach(snd_mixer_t *mixer, const char *name);
-int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl);
-int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl);
-int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer);
-int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space);
-int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
-int snd_mixer_load(snd_mixer_t *mixer);
-void snd_mixer_free(snd_mixer_t *mixer);
-int snd_mixer_wait(snd_mixer_t *mixer, int timeout);
-int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort);
-void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val);
-void * snd_mixer_get_callback_private(const snd_mixer_t *obj);
-void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val);
-unsigned int snd_mixer_get_count(const snd_mixer_t *obj);
-int snd_mixer_class_unregister(snd_mixer_class_t *clss);
-
-snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem);
-snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem);
-void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val);
-void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj);
-void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val);
-snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj);
-
-int snd_mixer_class_register(snd_mixer_class_t *class_, snd_mixer_t *mixer);
-int snd_mixer_add_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem);
-int snd_mixer_remove_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem);
-int snd_mixer_elem_new(snd_mixer_elem_t **elem,
-                      snd_mixer_elem_type_t type,
-                      int compare_weight,
-                      void *private_data,
-                      void (*private_free)(snd_mixer_elem_t *elem));
-int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class_);
-int snd_mixer_elem_remove(snd_mixer_elem_t *elem);
-void snd_mixer_elem_free(snd_mixer_elem_t *elem);
-int snd_mixer_elem_info(snd_mixer_elem_t *elem);
-int snd_mixer_elem_value(snd_mixer_elem_t *elem);
-int snd_mixer_elem_attach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem);
-int snd_mixer_elem_detach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem);
-int snd_mixer_elem_empty(snd_mixer_elem_t *melem);
-void *snd_mixer_elem_get_private(const snd_mixer_elem_t *melem);
-
-size_t snd_mixer_class_sizeof(void);
-/** \hideinitializer
- * \brief allocate an invalid #snd_mixer_class_t using standard alloca
- * \param ptr returned pointer
- */
-#define snd_mixer_class_alloca(ptr) __snd_alloca(ptr, snd_mixer_class)
-int snd_mixer_class_malloc(snd_mixer_class_t **ptr);
-void snd_mixer_class_free(snd_mixer_class_t *obj);
-void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src);
-snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *class_);
-snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *class_);
-void *snd_mixer_class_get_private(const snd_mixer_class_t *class_);
-snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *class_);
-int snd_mixer_class_set_event(snd_mixer_class_t *class_, snd_mixer_event_t event);
-int snd_mixer_class_set_private(snd_mixer_class_t *class_, void *private_data);
-int snd_mixer_class_set_private_free(snd_mixer_class_t *class_, void (*private_free)(snd_mixer_class_t *class_));
-int snd_mixer_class_set_compare(snd_mixer_class_t *class_, snd_mixer_compare_t compare);
+/* AMixer elements API */
 
-/**
- *  \defgroup SimpleMixer Simple Mixer Interface
- *  \ingroup Mixer
- *  The simple mixer interface.
- *  \{
- */
+/** dlsym version for interface entry callback */
+#define SND_AMIXER_DLSYM_VERSION       _dlsym_amixer_001
 
-/* Simple mixer elements API */
+/** AMixer element operation identifier */
+typedef enum _snd_amixer_elem_type {
+       /** Playback */
+       SND_MIXER_DIR_PLAYBACK = 0,
+       /** Capture */
+       SND_MIXER_DIR_CAPTURE = 1,
+       /** Common - playback and capture directions are identical */
+       SND_MIXER_DIR_COMMON = 2,
+} snd_amixer_dir_t;
 
-/** Mixer simple element channel identifier */
-typedef enum _snd_mixer_selem_channel_id {
+/** AMixer element channel identifier */
+typedef enum _snd_amixer_elem_channel_id {
        /** Unknown */
        SND_MIXER_SCHN_UNKNOWN = -1,
        /** Front left */
@@ -193,121 +78,168 @@ typedef enum _snd_mixer_selem_channel_id {
        SND_MIXER_SCHN_LAST = 31,
        /** Mono (Front left alias) */
        SND_MIXER_SCHN_MONO = SND_MIXER_SCHN_FRONT_LEFT
-} snd_mixer_selem_channel_id_t;
-
-/** Mixer simple element - register options - abstraction level */
-enum snd_mixer_selem_regopt_abstract {
-       /** no abstraction - try use all universal controls from driver */
-       SND_MIXER_SABSTRACT_NONE = 0,
-       /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */
-       SND_MIXER_SABSTRACT_BASIC,
-};
-
-/** Mixer simple element - register options */
-struct snd_mixer_selem_regopt {
-       /** structure version */
-       int ver;
-       /** v1: abstract layer selection */
-       enum snd_mixer_selem_regopt_abstract abstract;
-       /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */
-       const char *device;
-       /** v1: playback PCM connected to mixer device (NULL == none) */
-       snd_pcm_t *playback_pcm;
-       /** v1: capture PCM connected to mixer device (NULL == none) */
-       snd_pcm_t *capture_pcm;
-};
+} snd_amixer_elem_channel_id_t;
 
+/** Mixer handle */
+typedef struct _snd_amixer snd_amixer_t;
+/** Mixer element handle */
+typedef struct _snd_amixer_elem snd_amixer_elem_t;
 /** Mixer simple element identifier */
-typedef struct _snd_mixer_selem_id snd_mixer_selem_id_t;
-
-const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel);
-
-int snd_mixer_selem_register(snd_mixer_t *mixer,
-                            struct snd_mixer_selem_regopt *options,
-                            snd_mixer_class_t **classp);
-void snd_mixer_selem_get_id(snd_mixer_elem_t *element,
-                           snd_mixer_selem_id_t *id);
-const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem);
-unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem);
-snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
-                                      const snd_mixer_selem_id_t *id);
+typedef struct _snd_amixer_elem_id {
+       char name[60];
+       unsigned int index;
+} snd_amixer_elem_id_t;
 
-int snd_mixer_selem_is_active(snd_mixer_elem_t *elem);
-int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel);
-int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel);
-int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem);
-int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem);
+/** 
+ * \brief Mixer callback function
+ * \param amixer Mixer handle
+ * \param mask event mask
+ * \param elem related amixer element (if any)
+ * \return 0 on success otherwise a negative error code
+ */
+typedef int (*snd_amixer_callback_t)(snd_amixer_t *ctl,
+                                   unsigned int mask,
+                                   snd_amixer_elem_t *elem);
 
-int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue);
-int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue);
-int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value);
-int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value);
-int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
-int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
-int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
-int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
-int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value);
-int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value);
-int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value);
-int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value);
-int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir);
-int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir);
-int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value);
-int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value);
-int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir);
-int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir);
-int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value);
-int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value);
-int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value);
-int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value);
-int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, 
-                                             long *min, long *max);
-int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, 
-                                         long *min, long *max);
-int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, 
-                                             long min, long max);
-int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, 
-                                            long *min, long *max);
-int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, 
-                                        long *min, long *max);
-int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, 
-                                            long min, long max);
+/** 
+ * \brief Mixer element callback function
+ * \param elem Mixer element
+ * \param mask event mask
+ * \return 0 on success otherwise a negative error code
+ */
+typedef int (*snd_amixer_elem_callback_t)(snd_amixer_elem_t *elem,
+                                        unsigned int mask);
 
-int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem);
-int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem);
-int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem);
-int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem);
-int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str);
-int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp);
-int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx);
+/**
+ * \brief Compare function for sorting amixer elements
+ * \param e1 First element
+ * \param e2 Second element
+ * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2
+ */
+typedef int (*snd_amixer_compare_t)(const snd_amixer_elem_t *e1,
+                                   const snd_amixer_elem_t *e2);
 
-size_t snd_mixer_selem_id_sizeof(void);
+/**
+ * \brief Event callback for the amixer class
+ * \param amixer mixer handle
+ * \param mask Event mask (SND_CTL_EVENT_*)
+ * \param celem CTL element which invoked the event
+ * \param melem Mixer element associated to CTL element
+ * \return zero if success, otherwise a negative error value
+ */
+typedef int (*snd_amixer_event_t)(snd_amixer_t *amixer,
+                                 unsigned int mask,
+                                 snd_ctl_elem_t *celem,
+                                 snd_amixer_elem_t *melem);
+
+/** Expose all mixer controls (flag for open mode) \hideinitializer */
+#define SND_AMIXER_ALL         0x00000002
+/** Compatibility mode for older selem API (flag for open mode) \hideinitializer */
+#define SND_AMIXER_COMPAT1     0x40000000
+
+int snd_amixer_open(snd_amixer_t **amixer, const char *name,
+                   snd_pcm_t *playback_pcm, snd_pcm_t *capture_pcm,
+                   int mode);
+int snd_amixer_close(snd_amixer_t *amixer);
+int snd_amixer_handle_events(snd_amixer_t *amixer);
+int snd_amixer_poll_descriptors_count(snd_amixer_t *amixer);
+int snd_amixer_poll_descriptors(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int space);
+int snd_amixer_poll_descriptors_revents(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+int snd_amixer_wait(snd_amixer_t *amixer, int timeout);
+int snd_amixer_set_compare(snd_amixer_t *amixer, snd_amixer_compare_t msort);
+void snd_amixer_set_callback(snd_amixer_t *obj, snd_amixer_callback_t val);
+void *snd_amixer_get_callback_private(const snd_amixer_t *obj);
+void snd_amixer_set_callback_private(snd_amixer_t *obj, void *val);
+void snd_amixer_set_event(snd_amixer_t *amixer, snd_amixer_event_t event);
+snd_amixer_event_t snd_amixer_get_event(const snd_amixer_t *amixer);
+unsigned int snd_amixer_get_count(const snd_amixer_t *obj);
+void snd_amixer_set_private(const snd_amixer_t *amixer, void *private_data);
+void snd_amixer_set_private_free(const snd_amixer_t *amixer, void (*private_free)(snd_amixer_t *amixer));
+void *snd_amixer_get_private(const snd_amixer_t *amixer);
+int snd_amixer_conf_generic_id(const char *id);
+
+int snd_amixer_compare_default(const snd_amixer_elem_t *c1, const snd_amixer_elem_t *c2);
+
+snd_amixer_elem_t *snd_amixer_first_elem(snd_amixer_t *amixer);
+snd_amixer_elem_t *snd_amixer_last_elem(snd_amixer_t *amixer);
+snd_amixer_elem_t *snd_amixer_elem_next(snd_amixer_elem_t *elem);
+snd_amixer_elem_t *snd_amixer_elem_prev(snd_amixer_elem_t *elem);
+void snd_amixer_elem_set_callback(snd_amixer_elem_t *obj, snd_amixer_elem_callback_t val);
+void * snd_amixer_elem_get_callback_private(const snd_amixer_elem_t *obj);
+void snd_amixer_elem_set_callback_private(snd_amixer_elem_t *obj, void * val);
+
+int snd_amixer_add_elem(snd_amixer_t *amixer, snd_amixer_elem_t *elem);
+int snd_amixer_remove_elem(snd_amixer_t *amixer, snd_amixer_elem_t *elem);
+int snd_amixer_elem_new(snd_amixer_t *amixer,
+                       snd_amixer_elem_t **elem,
+                       snd_amixer_elem_id_t *id,
+                       int compare_weight,
+                       void *private_data,
+                       void (*private_free)(snd_amixer_elem_t *elem));
+int snd_amixer_elem_add(snd_amixer_t *amixer, snd_amixer_elem_t *elem);
+int snd_amixer_elem_remove(snd_amixer_elem_t *elem);
+void snd_amixer_elem_free(snd_amixer_elem_t *elem);
+int snd_amixer_elem_info(snd_amixer_elem_t *elem);
+int snd_amixer_elem_value(snd_amixer_elem_t *elem);
+int snd_amixer_elem_attach(snd_amixer_elem_t *melem, snd_ctl_elem_t *helem);
+int snd_amixer_elem_detach(snd_amixer_elem_t *melem, snd_ctl_elem_t *helem);
+int snd_amixer_elem_is_empty(snd_amixer_elem_t *melem);
+void *snd_amixer_elem_get_private(const snd_amixer_elem_t *melem);
+
+const char *snd_amixer_elem_channel_name(snd_amixer_elem_channel_id_t channel);
+
+void snd_amixer_elem_get_id(snd_amixer_elem_t *element,
+                           snd_amixer_elem_id_t *id);
+const char *snd_amixer_elem_get_name(snd_amixer_elem_t *elem);
+unsigned int snd_amixer_elem_get_index(snd_amixer_elem_t *elem);
+snd_amixer_elem_t *snd_amixer_find_elem(snd_amixer_t *amixer,
+                                       const snd_amixer_elem_id_t *id);
+
+int snd_amixer_elem_is_active(snd_amixer_elem_t *elem);
+int snd_amixer_elem_has_channel(snd_amixer_elem_t *obj, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel);
+int snd_amixer_elem_has_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_has_volume_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_has_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_has_switch_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+
+int snd_amixer_elem_get_group(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_has_switch_exclusive(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+
+int snd_amixer_elem_ask_vol_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, long *dBvalue);
+int snd_amixer_elem_ask_dB_vol(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long dBvalue, int xdir, long *value);
+int snd_amixer_elem_get_channels(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_get_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value);
+int snd_amixer_elem_get_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value);
+int snd_amixer_elem_get_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int *value);
+int snd_amixer_elem_get_volume_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max);
+int snd_amixer_elem_get_dB_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max);
+int snd_amixer_elem_set_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value);
+int snd_amixer_elem_set_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value, int xdir);
+int snd_amixer_elem_set_volume_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value);
+int snd_amixer_elem_set_dB_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, int xdir);
+int snd_amixer_elem_set_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value);
+int snd_amixer_elem_set_switch_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int value);
+int snd_amixer_elem_set_volume_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long min, long max);
+
+int snd_amixer_elem_is_enum(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+int snd_amixer_elem_get_enum_items(snd_amixer_elem_t *elem);
+int snd_amixer_elem_get_enum_item_name(snd_amixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str);
+int snd_amixer_elem_get_enum_item(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int *idxp);
+int snd_amixer_elem_set_enum_item(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int idx);
+
+size_t snd_amixer_elem_id_sizeof(void);
 /** \hideinitializer
- * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca
+ * \brief allocate an invalid #snd_amixer_elem_id_t using standard alloca
  * \param ptr returned pointer
  */
-#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id)
-int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr);
-void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj);
-void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src);
-const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj);
-unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj);
-void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val);
-void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val);
-
-/** \} */
+#define snd_amixer_elem_id_alloca(ptr) __snd_alloca(ptr, snd_amixer_elem_id)
+int snd_amixer_elem_id_malloc(snd_amixer_elem_id_t **ptr);
+void snd_amixer_elem_id_free(snd_amixer_elem_id_t *obj);
+void snd_amixer_elem_id_copy(snd_amixer_elem_id_t *dst, const snd_amixer_elem_id_t *src);
+const char *snd_amixer_elem_id_get_name(const snd_amixer_elem_id_t *obj);
+unsigned int snd_amixer_elem_id_get_index(const snd_amixer_elem_id_t *obj);
+void snd_amixer_elem_id_set_name(snd_amixer_elem_id_t *obj, const char *val);
+void snd_amixer_elem_id_set_index(snd_amixer_elem_id_t *obj, unsigned int val);
 
 /** \} */
 
index 7844b191014ec24be6ceb728354a3157aeb5e16b..781e9e309dec82e0e8b2cfe66522ddc13edd964f 100644 (file)
@@ -2,7 +2,7 @@
  * \file include/mixer_abst.h
  * \brief Mixer abstract implementation interface library for the ALSA library
  * \author Jaroslav Kysela <perex@perex.cz>
- * \date 2005
+ * \date 2005-2008
  *
  * Mixer abstact implementation interface library for the ALSA library
  */
@@ -36,8 +36,11 @@ extern "C" {
  *  \{
  */
 
-#define        SM_PLAY                 0
-#define SM_CAPT                        1
+#define SM_CTL_COUNT           8
+
+#define        SM_PLAY                 SND_MIXER_DIR_PLAYBACK
+#define SM_CAPT                        SND_MIXER_DIR_CAPTURE
+#define SM_COMM                        SND_MIXER_DIR_COMMON
 
 #define SM_CAP_GVOLUME         (1<<1)
 #define SM_CAP_GSWITCH         (1<<2)
@@ -55,52 +58,45 @@ extern "C" {
 /* SM_CAP_* 24-31 => private for module use */
 
 #define SM_OPS_IS_ACTIVE       0
-#define SM_OPS_IS_MONO         1
-#define SM_OPS_IS_CHANNEL      2
-#define SM_OPS_IS_ENUMERATED   3
-#define SM_OPS_IS_ENUMCNT      4
-
-#define sm_selem(x)            ((sm_selem_t *)((x)->private_data))
-#define sm_selem_ops(x)                ((sm_selem_t *)((x)->private_data))->ops
+#define SM_OPS_IS_CHANNEL      1
+#define SM_OPS_IS_ENUMERATED   2
+#define SM_OPS_IS_ENUMCNT      3
 
-typedef struct _sm_selem {
-       snd_mixer_selem_id_t *id;
+typedef struct _sm_elem {
+       snd_amixer_elem_id_t id;
        struct sm_elem_ops *ops;
        unsigned int caps;
        unsigned int capture_group;
-} sm_selem_t;
-
-typedef struct _sm_class_basic {
-       char *device;
-       snd_ctl_t *ctl;
-       snd_hctl_t *hctl;
-       snd_ctl_card_info_t *info;
-} sm_class_basic_t;
+} sm_elem_t;
 
 struct sm_elem_ops {   
-       int (*is)(snd_mixer_elem_t *elem, int dir, int cmd, int val);
-       int (*get_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max);
-       int (*set_range)(snd_mixer_elem_t *elem, int dir, long min, long max);
-       int (*get_dB_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max);
-       int (*ask_vol_dB)(snd_mixer_elem_t *elem, int dir, long value, long *dbValue);
-       int (*ask_dB_vol)(snd_mixer_elem_t *elem, int dir, long dbValue, long *value, int xdir);
-       int (*get_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value);
-       int (*get_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value);
-       int (*set_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value);
-       int (*set_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value, int xdir);
-       int (*get_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int *value);
-       int (*set_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value);
-       int (*enum_item_name)(snd_mixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf);
-       int (*get_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *itemp);
-       int (*set_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int item);
+       int (*is)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int cmd, int val);
+       int (*get_channels)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir);
+       int (*get_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max);
+       int (*set_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long min, long max);
+       int (*get_dB_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max);
+       int (*ask_vol_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, long *dbValue);
+       int (*ask_dB_vol)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long dbValue, long *value, int xdir);
+       int (*get_volume)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value);
+       int (*get_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value);
+       int (*set_volume)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value);
+       int (*set_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value, int xdir);
+       int (*get_switch)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int *value);
+       int (*set_switch)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value);
+       int (*enum_item_name)(snd_amixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf);
+       int (*get_enum_item)(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int *itemp);
+       int (*set_enum_item)(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int item);
 };
 
-int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2);
+struct sm_open {
+       const char *name;
+       snd_pcm_t *pcm_playback;
+       snd_pcm_t *pcm_capture;
+       int mode;
+       snd_ctl_t *ctl[SM_CTL_COUNT];
+};
 
-int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info);
-void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class);
-void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data);
-void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class));
+sm_elem_t *snd_amixer_elem_get_sm(snd_amixer_elem_t *elem);
 
 /** \} */
 
@@ -109,4 +105,3 @@ void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*pr
 #endif
 
 #endif /* __ALSA_MIXER_ABST_H */
-
diff --git a/include/mixer_old.h b/include/mixer_old.h
new file mode 100644 (file)
index 0000000..fc38d34
--- /dev/null
@@ -0,0 +1,331 @@
+/**
+ * \file include/mixer_old.h
+ * \brief Application interface library for the ALSA driver
+ * \author Jaroslav Kysela <perex@perex.cz>
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \author Takashi Iwai <tiwai@suse.de>
+ * \date 1998-2009
+ *
+ * Application interface library for the ALSA driver
+ */
+/*
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __ALSA_MIXER_OLD_H
+#define __ALSA_MIXER_OLD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *  \defgroup HControl High level Control Interface
+ *  \ingroup Control
+ *  The high level control interface.
+ *  See \ref hcontrol page for more details.
+ *  \{
+ */
+
+/** HCTL element handle */
+#define snd_hctl_elem_t snd_ctl_elem_t
+
+/** HCTL handle */
+#define snd_hctl_t snd_ctl_t
+
+/**
+ * \brief Compare function for sorting HCTL elements
+ * \param e1 First element
+ * \param e2 Second element
+ * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2
+ */
+#define snd_hctl_compare_t snd_ctl_compare_t
+#define snd_hctl_compare_fast snd_ctl_compare_fast
+
+/** 
+ * \brief HCTL callback function
+ * \param hctl HCTL handle
+ * \param mask event mask
+ * \param elem related HCTL element (if any)
+ * \return 0 on success otherwise a negative error code
+ */
+#define snd_hctl_callback_t snd_ctl_callback_t
+
+/** 
+ * \brief HCTL element callback function
+ * \param elem HCTL element
+ * \param mask event mask
+ * \return 0 on success otherwise a negative error code
+ */
+#define snd_hctl_elem_callback_t snd_ctl_elem_callback_t
+
+int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode);
+int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl);
+int snd_hctl_close(snd_hctl_t *hctl);
+int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock);
+int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl);
+int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space);
+int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+unsigned int snd_hctl_get_count(snd_hctl_t *hctl);
+int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort);
+snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl);
+snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl);
+snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id);
+void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback);
+void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data);
+void *snd_hctl_get_callback_private(snd_hctl_t *hctl);
+int snd_hctl_load(snd_hctl_t *hctl);
+int snd_hctl_free(snd_hctl_t *hctl);
+int snd_hctl_handle_events(snd_hctl_t *hctl);
+const char *snd_hctl_name(snd_hctl_t *hctl);
+int snd_hctl_wait(snd_hctl_t *hctl, int timeout);
+snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl);
+
+snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem);
+snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem);
+int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info);
+int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
+int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
+int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size);
+int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv);
+int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv);
+
+snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem);
+
+void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr);
+unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj);
+snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj);
+unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj);
+unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj);
+const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj);
+unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj);
+void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val);
+void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj);
+void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val);
+
+/** \} */
+
+/** \} */
+
+/**
+ *  \defgroup MixerOld Mixer Interface
+ *  The mixer interface.
+ *  \{
+ */
+
+/** Mixer handle */
+typedef struct _snd_mixer snd_mixer_t;
+/** Mixer element handle */
+#define snd_mixer_elem_t snd_amixer_elem_t
+
+/** 
+ * \brief Mixer callback function
+ * \param mixer Mixer handle
+ * \param mask event mask
+ * \param elem related mixer element (if any)
+ * \return 0 on success otherwise a negative error code
+ */
+typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl,
+                                   unsigned int mask,
+                                   snd_mixer_elem_t *elem);
+
+/** 
+ * \brief Mixer element callback function
+ * \param elem Mixer element
+ * \param mask event mask
+ * \return 0 on success otherwise a negative error code
+ */
+typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem,
+                                        unsigned int mask);
+
+/**
+ * \brief Compare function for sorting mixer elements
+ * \param e1 First element
+ * \param e2 Second element
+ * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2
+ */
+typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1,
+                                  const snd_mixer_elem_t *e2);
+
+/** Mixer element type */
+typedef enum _snd_mixer_elem_type {
+       /* Simple mixer elements */
+       SND_MIXER_ELEM_SIMPLE,
+       SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE
+} snd_mixer_elem_type_t;
+
+int snd_mixer_open(snd_mixer_t **mixer, int mode);
+int snd_mixer_close(snd_mixer_t *mixer);
+snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer);
+snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer);
+int snd_mixer_handle_events(snd_mixer_t *mixer);
+int snd_mixer_attach(snd_mixer_t *mixer, const char *name);
+int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl);
+int snd_mixer_detach(snd_mixer_t *mixer, const char *name);
+int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl);
+int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl);
+int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer);
+int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space);
+int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+int snd_mixer_load(snd_mixer_t *mixer);
+void snd_mixer_free(snd_mixer_t *mixer);
+int snd_mixer_wait(snd_mixer_t *mixer, int timeout);
+int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort);
+void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val);
+void * snd_mixer_get_callback_private(const snd_mixer_t *obj);
+void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val);
+unsigned int snd_mixer_get_count(const snd_mixer_t *obj);
+
+snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem);
+snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem);
+void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val);
+void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj);
+void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val);
+snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj);
+
+/**
+ *  \defgroup SimpleMixer Simple Mixer Interface
+ *  \ingroup Mixer
+ *  The simple mixer interface.
+ *  \{
+ */
+
+/* Simple mixer elements API */
+
+/** Mixer simple element channel identifier */
+#define snd_mixer_selem_channel_id_t snd_amixer_elem_channel_id_t
+
+/** Mixer simple element - register options - abstraction level */
+enum snd_mixer_selem_regopt_abstract {
+       /** no abstraction - try use all universal controls from driver */
+       SND_MIXER_SABSTRACT_NONE = 0,
+       /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */
+       SND_MIXER_SABSTRACT_BASIC,
+};
+
+/** Mixer simple element - register options */
+struct snd_mixer_selem_regopt {
+       /** structure version */
+       int ver;
+       /** v1: abstract layer selection */
+       enum snd_mixer_selem_regopt_abstract abstract;
+       /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */
+       const char *device;
+       /** v1: playback PCM connected to mixer device (NULL == none) */
+       snd_pcm_t *playback_pcm;
+       /** v1: capture PCM connected to mixer device (NULL == none) */
+       snd_pcm_t *capture_pcm;
+};
+
+/** Mixer simple element identifier */
+#define snd_mixer_selem_id_t snd_amixer_elem_id_t
+
+const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel);
+
+int snd_mixer_selem_register(snd_mixer_t *mixer,
+                            struct snd_mixer_selem_regopt *options,
+                            void **nothing);
+void snd_mixer_selem_get_id(snd_mixer_elem_t *element,
+                           snd_mixer_selem_id_t *id);
+const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem);
+unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem);
+snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
+                                      const snd_mixer_selem_id_t *id);
+
+int snd_mixer_selem_is_active(snd_mixer_elem_t *elem);
+int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel);
+int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel);
+int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem);
+int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem);
+
+int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue);
+int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue);
+int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value);
+int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value);
+int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
+int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
+int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
+int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
+int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value);
+int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value);
+int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value);
+int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value);
+int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir);
+int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir);
+int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value);
+int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value);
+int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir);
+int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir);
+int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value);
+int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value);
+int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value);
+int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value);
+int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, 
+                                             long *min, long *max);
+int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, 
+                                         long *min, long *max);
+int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, 
+                                             long min, long max);
+int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, 
+                                            long *min, long *max);
+int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, 
+                                        long *min, long *max);
+int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, 
+                                            long min, long max);
+
+int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem);
+int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem);
+int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem);
+int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem);
+int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str);
+int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp);
+int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx);
+
+size_t snd_mixer_selem_id_sizeof(void);
+/** \hideinitializer
+ * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca
+ * \param ptr returned pointer
+ */
+#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id)
+int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr);
+void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj);
+void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src);
+const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj);
+unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj);
+void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val);
+void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val);
+
+/** \} */
+
+/** \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ALSA_MIXER_OLD_H */
index 9f5917fee751bb5d278a09ea206d87ddba7d624d..61272edfcaa4527a77422fb339f74172a897b734 100644 (file)
@@ -1 +1 @@
-SUBDIRS=simple
+#SUBDIRS=simple
index 97feee8905a622120ae31e898d04b56fc4f91229..1aab535aee39f449ceaebd272f241a2d0d738517 100644 (file)
@@ -34,7 +34,7 @@
  * Prototypes
  */
 
-static int selem_read(snd_mixer_elem_t *elem);
+static int selem_read(snd_amixer_elem_t *elem);
 
 /*
  * Helpers
@@ -313,11 +313,11 @@ static void selem_free(snd_mixer_elem_t *elem)
        free(simple);
 }
 
-static int simple_event_add1(snd_mixer_class_t *class,
+static int simple_event_add1(snd_amixer_t *amixer,
                             snd_hctl_elem_t *helem,
                             struct helem_selector *sel)
 {
-       struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+       struct bmixer_private *priv = snd_amixer_sbasic_get_private(class);
        snd_mixer_elem_t *melem;
        snd_mixer_selem_id_t *id;
        snd_ctl_elem_info_t *info;
@@ -328,12 +328,12 @@ static int simple_event_add1(snd_mixer_class_t *class,
        long min, max;
        int err, new = 0;
        struct list_head *pos;
-       struct bclass_sid *bsid;
+       struct bmixer_sid *bsid;
        struct melem_sids *sid;
        unsigned int ui;
        
        list_for_each(pos, &priv->sids) {
-               bsid = list_entry(pos, struct bclass_sid, list);
+               bsid = list_entry(pos, struct bmixer_sid, list);
                for (ui = 0; ui < bsid->count; ui++) {
                        if (bsid->sids[ui].sid == sel->sid) {
                                sid = &bsid->sids[ui];
@@ -391,7 +391,7 @@ static int simple_event_add1(snd_mixer_class_t *class,
        hsimple->max = max;
        snd_mixer_selem_id_set_name(id, sid->sname);
        snd_mixer_selem_id_set_index(id, sid->sindex);
-       melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id);
+       melem = snd_mixer_find_selem(amixer, id);
        if (!melem) {
                simple = calloc(1, sizeof(*simple));
                if (!simple) {
@@ -435,7 +435,7 @@ static int simple_event_add1(snd_mixer_class_t *class,
        }
 #endif
        if (new)
-               err = snd_mixer_elem_add(melem, class);
+               err = snd_mixer_elem_add(melem, amixer);
        else
                err = snd_mixer_elem_info(melem);
        if (err < 0)
@@ -452,10 +452,10 @@ static int simple_event_add1(snd_mixer_class_t *class,
        return -EINVAL;
 }
 
-static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
+static int simple_event_add(snd__amixer_t *amixer, snd_hctl_elem_t *helem)
 {
-       struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
-       struct bclass_selector *sel;
+       struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer);
+       struct bmixer_selector *sel;
        struct helem_selector *hsel;
        struct list_head *pos;
        snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
@@ -465,11 +465,11 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
        int err;
 
        list_for_each(pos, &priv->selectors) {
-               sel = list_entry(pos, struct bclass_selector, list);
+               sel = list_entry(pos, struct bmixer_selector, list);
                for (ui = 0; ui < sel->count; ui++) {
                        hsel = &sel->selectors[ui];
                        if (hsel->iface == iface && !strcmp(hsel->name, name) && hsel->index == index) {
-                               err = simple_event_add1(class, helem, hsel);
+                               err = simple_event_add1(amixer, helem, hsel);
                                if (err < 0)
                                        return err;     /* early exit? */
                        }
@@ -478,14 +478,14 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
        return 0;
 }
 
-int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask,
+int alsa_mixer_sbasic_event(snd_amixer_t *amixer, unsigned int mask,
                            snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
 {
        int err;
        if (mask == SND_CTL_EVENT_MASK_REMOVE)
                return simple_event_remove(helem, melem);
        if (mask & SND_CTL_EVENT_MASK_ADD) {
-               err = simple_event_add(class, helem);
+               err = simple_event_add(amixer, helem);
                if (err < 0)
                        return err;
        }
@@ -493,7 +493,7 @@ int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask,
                err = simple_event_remove(helem, melem);
                if (err < 0)
                        return err;
-               err = simple_event_add(class, helem);
+               err = simple_event_add(amixer, helem);
                if (err < 0)
                        return err;
                return 0;
@@ -511,39 +511,39 @@ int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask,
        return 0;
 }
 
-static void sbasic_cpriv_free(snd_mixer_class_t *class)
+static void sbasic_cpriv_free(snd_amixer_t *amixer)
 {
-       struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
-       struct bclass_selector *sel;
-       struct bclass_sid *sid;
+       struct bmixer_private *priv = snd_amixer_sbasic_get_private(amixer);
+       struct bmixer_selector *sel;
+       struct bmixer_sid *sid;
        struct list_head *pos, *pos1;
 
        list_for_each_safe(pos, pos1, &priv->selectors) {
-               sel = list_entry(pos, struct bclass_selector, list);
+               sel = list_entry(pos, struct bmixer_selector, list);
                free(sel);
        }
        list_for_each_safe(pos, pos1, &priv->sids) {
-               sid = list_entry(pos, struct bclass_sid, list);
+               sid = list_entry(pos, struct bmixer_sid, list);
                free(sid);
        }
        free(priv);
 }
 
-void alsa_mixer_sbasic_initpriv(snd_mixer_class_t *class,
-                               struct bclass_private *priv)
+void alsa_mixer_sbasic_initpriv(snd_amixer_t *amixer,
+                               struct bmixer_private *priv)
 {
        INIT_LIST_HEAD(&priv->selectors);
        INIT_LIST_HEAD(&priv->sids);
-       snd_mixer_sbasic_set_private(class, priv);
-       snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free);
+       snd_mixer_sbasic_set_private(amixer, priv);
+       snd_mixer_sbasic_set_private_free(amixer, sbasic_cpriv_free);
 }
 
-int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class,
+int alsa_mixer_sbasic_selreg(snd_amixer_t *amixer,
                             struct helem_selector *selectors,
                             unsigned int count)
 {
-       struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
-       struct bclass_selector *sel = calloc(1, sizeof(*sel));
+       struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer);
+       struct bmixer_selector *sel = calloc(1, sizeof(*sel));
 
        if (sel == NULL)
                return -ENOMEM;
@@ -560,12 +560,12 @@ int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class,
        return 0;
 }
 
-int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class,
+int alsa_mixer_sbasic_sidreg(snd_amixer_t *amixer,
                             struct melem_sids *sids,
                             unsigned int count)
 {
-       struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
-       struct bclass_sid *sid = calloc(1, sizeof(*sid));
+       struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer);
+       struct bmixer_sid *sid = calloc(1, sizeof(*sid));
 
        if (sid == NULL)
                return -ENOMEM;
@@ -577,8 +577,8 @@ int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class,
                }
                INIT_LIST_HEAD(&priv->selectors);
                INIT_LIST_HEAD(&priv->sids);
-               snd_mixer_sbasic_set_private(class, priv);
-               snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free);
+               snd_mixer_sbasic_set_private(amixer, priv);
+               snd_mixer_sbasic_set_private_free(amixer, sbasic_cpriv_free);
        }
        sid->sids = sids;
        sid->count = count;
index ee5fe03c5daf735339e1977bbfcc2c16ec0a04c8..7feedc585bfebc53e649d31bb9fc24bd19ca2bde 100644 (file)
@@ -55,7 +55,7 @@ struct helem_selector {
 
 struct helem_base {
        struct list_head list;
-       snd_hctl_elem_t *helem;
+       snd_ctl_elem_t *helem;
        unsigned short purpose;
        unsigned int caps;
        unsigned int inactive: 1;
@@ -64,7 +64,6 @@ struct helem_base {
 };
 
 struct selem_base {
-       sm_selem_t selem;
        struct list_head helems;
        unsigned short sid;
        struct {
@@ -75,37 +74,37 @@ struct selem_base {
        } dir[2];
 };
 
-struct bclass_selector {
+struct bmixer_selector {
        struct list_head list;
        struct helem_selector *selectors;
        unsigned int count;
 };
 
-struct bclass_sid {
+struct bmixer_sid {
        struct list_head list;
        struct melem_sids *sids;
        unsigned int count;
 };
 
-typedef struct bclass_base_ops {
-       int (*event)(snd_mixer_class_t *class, unsigned int mask,
-                    snd_hctl_elem_t *helem, snd_mixer_elem_t *melem);
-       int (*selreg)(snd_mixer_class_t *class,
+typedef struct bmixer_base_ops {
+       int (*event)(snd_amixer_t *amixer, unsigned int mask,
+                    snd_ctl_elem_t *helem, snd_amixer_elem_t *melem);
+       int (*selreg)(snd_amixer_t *amixer,
                      struct helem_selector *selectors,
                      unsigned int count);
-       int (*sidreg)(snd_mixer_class_t *class,
+       int (*sidreg)(snd_amixer_t *amixer,
                      struct melem_sids *sids,
                      unsigned int count);
-} bclass_base_ops_t;
+} bmixer_base_ops_t;
 
-struct bclass_private {
+struct bmixer_private {
        struct list_head selectors;
        struct list_head sids;
        void *dl_sbase;
-       bclass_base_ops_t ops;
+       bmixer_base_ops_t ops;
 };
 
-int mixer_simple_basic_dlopen(snd_mixer_class_t *class,
-                             bclass_base_ops_t **ops);
+int mixer_simple_basic_dlopen(snd_amixer_t *amixer,
+                             bmixer_base_ops_t **ops);
 
 #endif /* __SMIXER_BASE_H */
index 0137586a520e542a8b2596553c53ade9b51adc54..d03ca3ef7b8ab3c32330a03157fbeb50dc4b4c08 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Mixer Interface - simple abstact module - base library (dlopen function)
- *  Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2005-2008 by Jaroslav Kysela <perex@perex.cz>
  *
  *
  *   This library is free software; you can redistribute it and/or modify
index 3204fe46b88892504401c23954dd5f658e1db317..d3e3a7145a09e6fd6fe484a85f4ace1176d9815c 100644 (file)
@@ -39,8 +39,8 @@ SUBDIRS += seq
 libasound_la_LIBADD += seq/libseq.la
 endif
 if BUILD_ALISP
-SUBDIRS += alisp
-libasound_la_LIBADD += alisp/libalisp.la
+#SUBDIRS += alisp
+#libasound_la_LIBADD += alisp/libalisp.la
 endif
 SUBDIRS += compat conf
 libasound_la_LIBADD += compat/libcompat.la @ALSA_DEPLIBS@
index db6425976e79fdae354acdfe89441904d6deaff9..8d0d4a2957b400a0d2658a81c553772e4b4afb33 100644 (file)
@@ -98,6 +98,7 @@ defaults.pcm.modem.device defaults.pcm.device
 # truncate files via file or tee PCM
 defaults.pcm.file_format       "raw"
 defaults.pcm.file_truncate     true
+defaults.amixer.card 0
 defaults.rawmidi.card 0
 defaults.rawmidi.device 0
 defaults.rawmidi.subdevice -1
@@ -367,6 +368,30 @@ ctl.shm {
        ctl $CTL
 }
 
+#
+#  Mixer interface
+#
+
+amixer.default {
+       type none
+       @args [ CARD ]
+       @args.CARD {
+               type string
+               default {
+                       @func getenv
+                       vars [
+                               ALSA_AMIXER_CARD
+                               ALSA_CARD
+                       ]
+                       default {
+                               @func refer
+                               name defaults.amixer.card
+                       }
+               }
+       }
+       card $CARD
+}
+
 #
 #  RawMidi interface
 #
index d4c50c016d317d6197c8cf08bc94bd454b46eda6..eaf6f9175fac85edaba6b22972c5bc450e07b891 100644 (file)
@@ -1,7 +1,8 @@
 EXTRA_LTLIBRARIES = libcontrol.la
 
 libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c \
-                        control.c control_hw.c setup.c control_symbols.c
+                        control.c control_hw.c hcontrol_old.c \
+                        setup.c control_symbols.c
 if BUILD_CTL_PLUGIN_SHM
 libcontrol_la_SOURCES += control_shm.c
 endif
index c09079736c5ed1e41a1f98036f91deff7aeb1832..0537ad2a652c6b8a5c792bd6d501c8d3879d3344 100644 (file)
@@ -88,6 +88,8 @@ snd_ctl_type_t snd_ctl_type(snd_ctl_t *ctl)
 int snd_ctl_close(snd_ctl_t *ctl)
 {
        int err;
+
+       snd_ctl_cache_free(ctl);
        while (!list_empty(&ctl->async_handlers)) {
                snd_async_handler_t *h = list_entry(&ctl->async_handlers.next, snd_async_handler_t, hlist);
                snd_async_del_handler(h);
@@ -118,16 +120,18 @@ int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock)
 }
 
 #ifndef DOC_HIDDEN
-int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name)
+int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name, int mode)
 {
        snd_ctl_t *ctl;
        ctl = calloc(1, sizeof(*ctl));
        if (!ctl)
                return -ENOMEM;
        ctl->type = type;
+       ctl->mode = mode;
        if (name)
                ctl->name = strdup(name);
        INIT_LIST_HEAD(&ctl->async_handlers);
+       INIT_LIST_HEAD(&ctl->elems);
        *ctlp = ctl;
        return 0;
 }
@@ -218,7 +222,14 @@ int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsign
  */
 int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe)
 {
+       int err;
+
        assert(ctl);
+       if (ctl->mode & SND_CTL_CACHE) {
+               err = snd_ctl_cache_load(ctl);
+               if (err < 0)
+                       return err;
+       }
        return ctl->ops->subscribe_events(ctl, subscribe);
 }
 
index d1fe8eaadec55671d9fcdfcc456d9d13e97a0d84..1f46f6ee2f7cd3737a5814b7c962993d04d1f77e 100644 (file)
@@ -665,7 +665,7 @@ int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode)
                return -ENXIO;
        }
 
-       err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name);
+       err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name, mode);
        if (err < 0)
                return err;
 
index e9a6be274e03c07d0c65686fd86aa799c1813123..c33d8ca903c36d13cfbda78e0915096d99d0b7f6 100644 (file)
@@ -421,7 +421,7 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode)
        hw->fd = fd;
        hw->protocol = ver;
 
-       err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name);
+       err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name, mode);
        if (err < 0) {
                close(fd);
                free(hw);
index fd9f941804b4dae9501c2233131c5447d25b457a..b75183979d32390bd7ceab77d6567ee0a55733d1 100644 (file)
@@ -59,42 +59,44 @@ struct _snd_ctl {
        void *dl_handle;
        char *name;
        snd_ctl_type_t type;
+       int mode;
        const snd_ctl_ops_t *ops;
        void *private_data;
        int nonblock;
        int poll_fd;
        struct list_head async_handlers;
+       struct list_head elems;         /* list of all controls */
+       unsigned int alloc;     
+       unsigned int count;
+       snd_ctl_elem_t **pelems;
+       snd_ctl_compare_t compare;
+       snd_ctl_callback_t callback;
+       void *callback_private;
 };
 
-struct _snd_hctl_elem {
+struct _snd_ctl_elem {
        snd_ctl_elem_id_t id;           /* must be always on top */
        struct list_head list;          /* links for list of all helems */
        int compare_weight;             /* compare weight (reversed) */
        /* event callback */
-       snd_hctl_elem_callback_t callback;
+       snd_ctl_elem_callback_t callback;
        void *callback_private;
        /* links */
-       snd_hctl_t *hctl;               /* associated handle */
-};
-
-struct _snd_hctl {
-       snd_ctl_t *ctl;
-       struct list_head elems;         /* list of all controls */
-       unsigned int alloc;     
-       unsigned int count;
-       snd_hctl_elem_t **pelems;
-       snd_hctl_compare_t compare;
-       snd_hctl_callback_t callback;
-       void *callback_private;
+       snd_ctl_t *ctl;                 /* associated handle */
 };
 
 
 /* make local functions really local */
-#define snd_ctl_new    snd1_ctl_new
+#define snd_ctl_new            snd1_ctl_new
+#define snd_ctl_cache_load     snd1_ctl_cache_load
+#define snd_ctl_cache_free     snd1_ctl_cache_free
 
-int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name);
+int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name, int mode);
 int _snd_ctl_poll_descriptor(snd_ctl_t *ctl);
 #define _snd_ctl_async_descriptor _snd_ctl_poll_descriptor
 int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode);
 int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode);
 int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid);
+
+int snd_ctl_cache_load(snd_ctl_t *ctl);
+int snd_ctl_cache_free(snd_ctl_t *ctl);
index abab39831f61dd15df403c163b13dc9fe6e9caed..721ee69e914291138483569650eadd3cd2d07fb3 100644 (file)
@@ -535,7 +535,7 @@ int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname
        shm->socket = sock;
        shm->ctrl = ctrl;
 
-       err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name);
+       err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name, mode);
        if (err < 0) {
                result = err;
                goto _err;
@@ -548,6 +548,13 @@ int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname
                return err;
        }
        ctl->poll_fd = err;
+       if (mode & SND_CTL_CACHE) {
+               err = snd_ctl_cache_load(ctl);
+               if (err < 0) {
+                       snd_ctl_close(ctl);
+                       return err;
+               }
+       }
        *handlep = ctl;
        return 0;
 
index 181e7672ee428d8c670b56886b8aa6914edb12d9..7128616dc16dda8711cbd635e54e19a031722314 100644 (file)
@@ -1,11 +1,11 @@
 /**
  * \file control/hcontrol.c
- * \brief HCTL Interface - High Level CTL
+ * \brief CTL Interface - High Level Cached Control Elements
  * \author Jaroslav Kysela <perex@perex.cz>
  * \author Abramo Bagnara <abramo@alsa-project.org>
  * \date 2000
  *
- * HCTL interface is designed to access preloaded and sorted primitive controls.
+ * CTL interface is designed to access preloaded and sorted primitive controls.
  * Callbacks may be used for event handling.
  * See \ref hcontrol page for more details.
  */
@@ -31,7 +31,7 @@
  *
  */
 
-/*! \page hcontrol High level control interface
+/*! \page hcontrol High level cached control interface
 
 <P> High level control interface is designed to access preloaded and sorted primitive controls.
 
@@ -60,164 +60,26 @@ to reduce overhead accessing the real controls in kernel drivers.
 #define NOT_FOUND 1000000000
 #endif
 
-static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
-                                   const snd_hctl_elem_t *c2);
+static int snd_ctl_compare_default(const snd_ctl_elem_t *c1,
+                                  const snd_ctl_elem_t *c2);
 
-/**
- * \brief Opens an HCTL
- * \param hctlp Returned HCTL handle
- * \param name ASCII identifier of the underlying CTL handle
- * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
- * \return 0 on success otherwise a negative error code
- */
-int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode)
-{
-       snd_ctl_t *ctl;
-       int err;
-       
-       if ((err = snd_ctl_open(&ctl, name, mode)) < 0)
-               return err;
-       err = snd_hctl_open_ctl(hctlp, ctl);
-       if (err < 0)
-               snd_ctl_close(ctl);
-       return err;
-}
-
-/**
- * \brief Opens an HCTL
- * \param hctlp Returned HCTL handle
- * \param ctl underlying CTL handle
- * \return 0 on success otherwise a negative error code
- */
-int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl)
-{
-       snd_hctl_t *hctl;
-
-       assert(hctlp);
-       *hctlp = NULL;
-       if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&hctl->elems);
-       hctl->ctl = ctl;
-       *hctlp = hctl;
-       return 0;
-}
-
-/**
- * \brief close HCTL handle
- * \param hctl HCTL handle
- * \return 0 on success otherwise a negative error code
- *
- * Closes the specified HCTL handle and frees all associated
- * resources.
- */
-int snd_hctl_close(snd_hctl_t *hctl)
-{
-       int err;
-
-       assert(hctl);
-       err = snd_ctl_close(hctl->ctl);
-       snd_hctl_free(hctl);
-       free(hctl);
-       return err;
-}
-
-/**
- * \brief get identifier of HCTL handle
- * \param hctl HCTL handle
- * \return ascii identifier of HCTL handle
- *
- * Returns the ASCII identifier of given HCTL handle. It's the same
- * identifier specified in snd_hctl_open().
- */
-const char *snd_hctl_name(snd_hctl_t *hctl)
-{
-       assert(hctl);
-       return snd_ctl_name(hctl->ctl);
-}
-
-/**
- * \brief set nonblock mode
- * \param hctl HCTL handle
- * \param nonblock 0 = block, 1 = nonblock mode
- * \return 0 on success otherwise a negative error code
- */
-int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock)
-{
-       assert(hctl);
-       return snd_ctl_nonblock(hctl->ctl, nonblock);
-}
-
-/**
- * \brief set async mode
- * \param hctl HCTL handle
- * \param sig Signal to raise: < 0 disable, 0 default (SIGIO)
- * \param pid Process ID to signal: 0 current
- * \return 0 on success otherwise a negative error code
- *
- * A signal is raised when a change happens.
- */
-int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid)
-{
-       assert(hctl);
-       return snd_ctl_async(hctl->ctl, sig, pid);
-}
-
-/**
- * \brief get count of poll descriptors for HCTL handle
- * \param hctl HCTL handle
- * \return count of poll descriptors
- */
-int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl)
-{
-       assert(hctl);
-       return snd_ctl_poll_descriptors_count(hctl->ctl);
-}
-
-/**
- * \brief get poll descriptors
- * \param hctl HCTL handle
- * \param pfds array of poll descriptors
- * \param space space in the poll descriptor array
- * \return count of filled descriptors
- */
-int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space)
-{
-       assert(hctl);
-       return snd_ctl_poll_descriptors(hctl->ctl, pfds, space);
-}
-
-/**
- * \brief get returned events from poll descriptors
- * \param hctl HCTL handle
- * \param pfds array of poll descriptors
- * \param nfds count of poll descriptors
- * \param revents returned events
- * \return zero if success, otherwise a negative error code
- */
-int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+static int snd_ctl_throw_event(snd_ctl_t *ctl, unsigned int mask,
+                              snd_ctl_elem_t *elem)
 {
-       assert(hctl);
-       return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents);
-}
-
-static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask,
-                        snd_hctl_elem_t *elem)
-{
-       if (hctl->callback)
-               return hctl->callback(hctl, mask, elem);
+       if (ctl->callback)
+               return ctl->callback(ctl, mask, elem);
        return 0;
 }
 
-static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem,
-                             unsigned int mask)
+static int snd_ctl_elem_throw_event(snd_ctl_elem_t *elem,
+                                   unsigned int mask)
 {
        if (elem->callback)
                return elem->callback(elem, mask);
        return 0;
 }
 
-static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef)
+static int snd_ctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef)
 {
        int res;
 
@@ -298,7 +160,7 @@ static int get_compare_weight(const snd_ctl_elem_id_t *id)
        const char *name = (char *)id->name, *name1;
        int res, res1;
        
-       if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND)
+       if ((res = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND)
                return NOT_FOUND;
        if (*name == '\0')
                return res;
@@ -309,32 +171,32 @@ static int get_compare_weight(const snd_ctl_elem_id_t *id)
        if (name1 != name) {
                for (; name1 != name && *name1 != ' '; name1--);
                name = name1;
-               if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND)
+               if ((res1 = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND)
                        return res;
                res += res1;
        } else {
                name = name1;
        }
-       if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND)
+       if ((res1 = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND)
                return res;
        return res + res1;
 }
 
-static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir)
+static int _snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, int *dir)
 {
        unsigned int l, u;
-       snd_hctl_elem_t el;
+       snd_ctl_elem_t el;
        int c = 0;
        int idx = -1;
-       assert(hctl && id);
-       assert(hctl->compare);
+       assert(ctl && id);
+       assert(ctl->compare);
        el.id = *id;
        el.compare_weight = get_compare_weight(id);
        l = 0;
-       u = hctl->count;
+       u = ctl->count;
        while (l < u) {
                idx = (l + u) / 2;
-               c = hctl->compare(&el, hctl->pelems[idx]);
+               c = ctl->compare(&el, ctl->pelems[idx]);
                if (c < 0)
                        u = idx;
                else if (c > 0)
@@ -346,130 +208,133 @@ static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, in
        return idx;
 }
 
-static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem)
+static int snd_ctl_elem_add(snd_ctl_t *ctl, snd_ctl_elem_t *elem)
 {
        int dir;
        int idx; 
        elem->compare_weight = get_compare_weight(&elem->id);
-       if (hctl->count == hctl->alloc) {
-               snd_hctl_elem_t **h;
-               hctl->alloc += 32;
-               h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc);
+       if (ctl->count == ctl->alloc) {
+               snd_ctl_elem_t **h;
+               ctl->alloc += 32;
+               h = realloc(ctl->pelems, sizeof(*h) * ctl->alloc);
                if (!h) {
-                       hctl->alloc -= 32;
+                       ctl->alloc -= 32;
                        return -ENOMEM;
                }
-               hctl->pelems = h;
+               ctl->pelems = h;
        }
-       if (hctl->count == 0) {
-               list_add_tail(&elem->list, &hctl->elems);
-               hctl->pelems[0] = elem;
+       if (ctl->count == 0) {
+               list_add_tail(&elem->list, &ctl->elems);
+               ctl->pelems[0] = elem;
        } else {
-               idx = _snd_hctl_find_elem(hctl, &elem->id, &dir);
+               idx = _snd_ctl_find_elem(ctl, &elem->id, &dir);
                assert(dir != 0);
                if (dir > 0) {
-                       list_add(&elem->list, &hctl->pelems[idx]->list);
+                       list_add(&elem->list, &ctl->pelems[idx]->list);
                        idx++;
                } else {
-                       list_add_tail(&elem->list, &hctl->pelems[idx]->list);
+                       list_add_tail(&elem->list, &ctl->pelems[idx]->list);
                }
-               memmove(hctl->pelems + idx + 1,
-                       hctl->pelems + idx,
-                       (hctl->count - idx) * sizeof(snd_hctl_elem_t *));
-               hctl->pelems[idx] = elem;
+               memmove(ctl->pelems + idx + 1,
+                       ctl->pelems + idx,
+                       (ctl->count - idx) * sizeof(snd_ctl_elem_t *));
+               ctl->pelems[idx] = elem;
        }
-       hctl->count++;
-       return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem);
+       ctl->count++;
+       return snd_ctl_throw_event(ctl, SNDRV_CTL_EVENT_MASK_ADD, elem);
 }
 
-static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx)
+static void snd_ctl_celem_remove(snd_ctl_t *ctl, unsigned int idx)
 {
-       snd_hctl_elem_t *elem = hctl->pelems[idx];
+       snd_ctl_elem_t *elem = ctl->pelems[idx];
        unsigned int m;
-       snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE);
+       snd_ctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE);
        list_del(&elem->list);
        free(elem);
-       hctl->count--;
-       m = hctl->count - idx;
+       ctl->count--;
+       m = ctl->count - idx;
        if (m > 0)
-               memmove(hctl->pelems + idx,
-                       hctl->pelems + idx + 1,
-                       m * sizeof(snd_hctl_elem_t *));
+               memmove(ctl->pelems + idx,
+                       ctl->pelems + idx + 1,
+                       m * sizeof(snd_ctl_elem_t *));
 }
 
+#ifndef DOC_HIDDEN
 /**
- * \brief free HCTL loaded elements
- * \param hctl HCTL handle
+ * \brief free cached elements
+ * \param ctl CTL handle
  * \return 0 on success otherwise a negative error code
  */
-int snd_hctl_free(snd_hctl_t *hctl)
+int snd_ctl_cache_free(snd_ctl_t *ctl)
 {
-       while (hctl->count > 0)
-               snd_hctl_elem_remove(hctl, hctl->count - 1);
-       free(hctl->pelems);
-       hctl->pelems = 0;
-       hctl->alloc = 0;
-       INIT_LIST_HEAD(&hctl->elems);
+       while (ctl->count > 0)
+               snd_ctl_celem_remove(ctl, ctl->count - 1);
+       if (ctl->pelems)
+               free(ctl->pelems);
+       ctl->pelems = 0;
+       ctl->alloc = 0;
+       INIT_LIST_HEAD(&ctl->elems);
        return 0;
 }
+#endif
 
-static snd_hctl_t *compare_hctl;
-static int hctl_compare(const void *a, const void *b) {
-       return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a,
-                            *(const snd_hctl_elem_t * const *) b);
+static snd_ctl_t *compare_ctl;
+static int ctl_compare(const void *a, const void *b) {
+       return compare_ctl->compare(*(const snd_ctl_elem_t * const *) a,
+                                   *(const snd_ctl_elem_t * const *) b);
 }
 
-static void snd_hctl_sort(snd_hctl_t *hctl)
+static void snd_ctl_sort(snd_ctl_t *ctl)
 {
        unsigned int k;
 #ifdef HAVE_LIBPTHREAD
        static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
-       assert(hctl);
-       assert(hctl->compare);
-       INIT_LIST_HEAD(&hctl->elems);
+       assert(ctl);
+       assert(ctl->compare);
+       INIT_LIST_HEAD(&ctl->elems);
 
 #ifdef HAVE_LIBPTHREAD
        pthread_mutex_lock(&sync_lock);
 #endif
-       compare_hctl = hctl;
-       qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare);
+       compare_ctl = ctl;
+       qsort(ctl->pelems, ctl->count, sizeof(*ctl->pelems), ctl_compare);
 #ifdef HAVE_LIBPTHREAD
        pthread_mutex_unlock(&sync_lock);
 #endif
-       for (k = 0; k < hctl->count; k++)
-               list_add_tail(&hctl->pelems[k]->list, &hctl->elems);
+       for (k = 0; k < ctl->count; k++)
+               list_add_tail(&ctl->pelems[k]->list, &ctl->elems);
 }
 
 /**
- * \brief Change HCTL compare function and reorder elements
- * \param hctl HCTL handle
+ * \brief Change CTL compare function and reorder elements
+ * \param ctl CTL handle
  * \param compare Element compare function
  * \return 0 on success otherwise a negative error code
  */
-int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare)
+int snd_ctl_set_compare(snd_ctl_t *ctl, snd_ctl_compare_t compare)
 {
-       assert(hctl);
-       hctl->compare = compare == NULL ? snd_hctl_compare_default : compare;
-       snd_hctl_sort(hctl);
+       assert(ctl);
+       ctl->compare = compare == NULL ? snd_ctl_compare_default : compare;
+       snd_ctl_sort(ctl);
        return 0;
 }
 
 /**
- * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare
- * \param c1 First HCTL element
- * \param c2 Second HCTL element
+ * \brief A "don't care" fast compare functions that may be used with #snd_ctl_set_compare
+ * \param c1 First CTL element
+ * \param c2 Second CTL element
  * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
  */
-int snd_hctl_compare_fast(const snd_hctl_elem_t *c1,
-                         const snd_hctl_elem_t *c2)
+int snd_ctl_compare_fast(const snd_ctl_elem_t *c1,
+                        const snd_ctl_elem_t *c2)
 {
        return c1->id.numid - c2->id.numid;
 }
 
-static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
-                                   const snd_hctl_elem_t *c2)
+static int snd_ctl_compare_default(const snd_ctl_elem_t *c1,
+                                   const snd_ctl_elem_t *c2)
 {
        int res;
        int d = c1->id.iface - c2->id.iface;
@@ -488,248 +353,187 @@ static int snd_hctl_compare_default(const snd_hctl_elem_t *c1,
 }
 
 /**
- * \brief get first element for an HCTL
- * \param hctl HCTL handle
+ * \brief get first element for an CTL
+ * \param ctl CTL handle
  * \return pointer to first element
  */
-snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl)
+snd_ctl_elem_t *snd_ctl_first_elem(snd_ctl_t *ctl)
 {
-       assert(hctl);
-       if (list_empty(&hctl->elems))
+       assert(ctl);
+       if (list_empty(&ctl->elems))
                return NULL;
-       return list_entry(hctl->elems.next, snd_hctl_elem_t, list);
+       return list_entry(ctl->elems.next, snd_ctl_elem_t, list);
 }
 
 /**
- * \brief get last element for an HCTL
- * \param hctl HCTL handle
+ * \brief get last element for an CTL
+ * \param ctl CTL handle
  * \return pointer to last element
  */
-snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl)
+snd_ctl_elem_t *snd_ctl_last_elem(snd_ctl_t *ctl)
 {
-       assert(hctl);
-       if (list_empty(&hctl->elems))
+       assert(ctl);
+       if (list_empty(&ctl->elems))
                return NULL;
-       return list_entry(hctl->elems.prev, snd_hctl_elem_t, list);
+       return list_entry(ctl->elems.prev, snd_ctl_elem_t, list);
 }
 
 /**
- * \brief get next HCTL element
- * \param elem HCTL element
+ * \brief get next CTL element
+ * \param elem CTL element
  * \return pointer to next element
  */
-snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem)
+snd_ctl_elem_t *snd_ctl_elem_next(snd_ctl_elem_t *elem)
 {
        assert(elem);
-       if (elem->list.next == &elem->hctl->elems)
+       if (elem->list.next == &elem->ctl->elems)
                return NULL;
-       return list_entry(elem->list.next, snd_hctl_elem_t, list);
+       return list_entry(elem->list.next, snd_ctl_elem_t, list);
 }
 
 /**
- * \brief get previous HCTL element
- * \param elem HCTL element
+ * \brief get previous CTL element
+ * \param elem CTL element
  * \return pointer to previous element
  */
-snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem)
+snd_ctl_elem_t *snd_ctl_elem_prev(snd_ctl_elem_t *elem)
 {
        assert(elem);
-       if (elem->list.prev == &elem->hctl->elems)
+       if (elem->list.prev == &elem->ctl->elems)
                return NULL;
-       return list_entry(elem->list.prev, snd_hctl_elem_t, list);
+       return list_entry(elem->list.prev, snd_ctl_elem_t, list);
 }
 
 /**
- * \brief Search an HCTL element
- * \param hctl HCTL handle
+ * \brief Search an CTL element
+ * \param ctl CTL handle
  * \param id Element identifier
- * \return pointer to found HCTL element or NULL if it does not exists
+ * \return pointer to found CTL element or NULL if it does not exists
  */
-snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id)
+snd_ctl_elem_t *snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id)
 {
        int dir;
-       int res = _snd_hctl_find_elem(hctl, id, &dir);
+       int res = _snd_ctl_find_elem(ctl, id, &dir);
        if (res < 0 || dir != 0)
                return NULL;
-       return hctl->pelems[res];
+       return ctl->pelems[res];
 }
 
+#ifndef DOC_HIDDEN
 /**
- * \brief Load an HCTL with all elements and sort them
- * \param hctl HCTL handle
+ * \brief Load an CTL with all elements and sort them
+ * \param ctl CTL handle
  * \return 0 on success otherwise a negative error code
  */
-int snd_hctl_load(snd_hctl_t *hctl)
+int snd_ctl_cache_load(snd_ctl_t *ctl)
 {
        snd_ctl_elem_list_t list;
        int err = 0;
        unsigned int idx;
 
-       assert(hctl);
-       assert(hctl->ctl);
-       assert(hctl->count == 0);
-       assert(list_empty(&hctl->elems));
+       assert(ctl);
+       assert(ctl->count == 0);
+       assert(list_empty(&ctl->elems));
        memset(&list, 0, sizeof(list));
-       if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
+       if ((err = snd_ctl_elem_list(ctl, &list)) < 0)
                goto _end;
        while (list.count != list.used) {
+               if (list.space)
+                       snd_ctl_elem_list_free_space(&list);
                err = snd_ctl_elem_list_alloc_space(&list, list.count);
                if (err < 0)
                        goto _end;
-               if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0)
+               if ((err = snd_ctl_elem_list(ctl, &list)) < 0)
                        goto _end;
        }
-       if (hctl->alloc < list.count) {
-               hctl->alloc = list.count;
-               free(hctl->pelems);
-               hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems));
-               if (!hctl->pelems) {
+       if (ctl->alloc < list.count) {
+               ctl->alloc = list.count;
+               free(ctl->pelems);
+               ctl->pelems = malloc(ctl->alloc * sizeof(*ctl->pelems));
+               if (!ctl->pelems) {
                        err = -ENOMEM;
                        goto _end;
                }
        }
        for (idx = 0; idx < list.count; idx++) {
-               snd_hctl_elem_t *elem;
-               elem = calloc(1, sizeof(snd_hctl_elem_t));
+               snd_ctl_elem_t *elem;
+               elem = calloc(1, sizeof(snd_ctl_elem_t));
                if (elem == NULL) {
-                       snd_hctl_free(hctl);
+                       snd_ctl_cache_free(ctl);
                        err = -ENOMEM;
                        goto _end;
                }
                elem->id = list.pids[idx];
-               elem->hctl = hctl;
+               elem->ctl = ctl;
                elem->compare_weight = get_compare_weight(&elem->id);
-               hctl->pelems[idx] = elem;
-               list_add_tail(&elem->list, &hctl->elems);
-               hctl->count++;
+               ctl->pelems[idx] = elem;
+               list_add_tail(&elem->list, &ctl->elems);
+               ctl->count++;
        }
-       if (!hctl->compare)
-               hctl->compare = snd_hctl_compare_default;
-       snd_hctl_sort(hctl);
-       for (idx = 0; idx < hctl->count; idx++) {
-               int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD,
-                                              hctl->pelems[idx]);
+       if (!ctl->compare)
+               ctl->compare = snd_ctl_compare_default;
+       snd_ctl_sort(ctl);
+       for (idx = 0; idx < ctl->count; idx++) {
+               int res = snd_ctl_throw_event(ctl, SNDRV_CTL_EVENT_MASK_ADD,
+                                              ctl->pelems[idx]);
                if (res < 0)
                        return res;
        }
-       err = snd_ctl_subscribe_events(hctl->ctl, 1);
  _end:
-       free(list.pids);
+       snd_ctl_elem_list_free_space(&list);
        return err;
 }
+#endif
 
 /**
- * \brief Set callback function for an HCTL
- * \param hctl HCTL handle
+ * \brief Set callback function for an CTL
+ * \param ctl CTL handle
  * \param callback callback function
  */
-void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback)
+void snd_ctl_set_callback(snd_ctl_t *ctl, snd_ctl_callback_t callback)
 {
-       assert(hctl);
-       hctl->callback = callback;
+       assert(ctl);
+       ctl->callback = callback;
 }
 
 /**
- * \brief Set callback private value for an HCTL
- * \param hctl HCTL handle
+ * \brief Set callback private value for an CTL
+ * \param ctl CTL handle
  * \param callback_private callback private value
  */
-void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private)
+void snd_ctl_set_callback_private(snd_ctl_t *ctl, void *callback_private)
 {
-       assert(hctl);
-       hctl->callback_private = callback_private;
+       assert(ctl);
+       ctl->callback_private = callback_private;
 }
 
 /**
- * \brief Get callback private value for an HCTL
- * \param hctl HCTL handle
+ * \brief Get callback private value for an CTL
+ * \param ctl CTL handle
  * \return callback private value
  */
-void *snd_hctl_get_callback_private(snd_hctl_t *hctl)
+void *snd_ctl_get_callback_private(snd_ctl_t *ctl)
 {
-       assert(hctl);
-       return hctl->callback_private;
+       assert(ctl);
+       return ctl->callback_private;
 }
 
 /**
- * \brief Get number of loaded elements for an HCTL
- * \param hctl HCTL handle
+ * \brief Get number of loaded elements for an CTL
+ * \param ctl CTL handle
  * \return elements count
  */
-unsigned int snd_hctl_get_count(snd_hctl_t *hctl)
-{
-       return hctl->count;
-}
-
-/**
- * \brief Wait for a HCTL to become ready (i.e. at least one event pending)
- * \param hctl HCTL handle
- * \param timeout maximum time in milliseconds to wait
- * \return a positive value on success otherwise a negative error code
- * \retval 0 timeout occurred
- * \retval 1 an event is pending
- */
-int snd_hctl_wait(snd_hctl_t *hctl, int timeout)
-{
-       struct pollfd *pfd;
-       unsigned short *revents;
-       int i, npfds, pollio, err, err_poll;
-       
-       npfds = snd_hctl_poll_descriptors_count(hctl);
-       if (npfds <= 0 || npfds >= 16) {
-               SNDERR("Invalid poll_fds %d\n", npfds);
-               return -EIO;
-       }
-       pfd = alloca(sizeof(*pfd) * npfds);
-       revents = alloca(sizeof(*revents) * npfds);
-       err = snd_hctl_poll_descriptors(hctl, pfd, npfds);
-       if (err < 0)
-               return err;
-       if (err != npfds) {
-               SNDMSG("invalid poll descriptors %d\n", err);
-               return -EIO;
-       }
-       do {
-               pollio = 0;
-               err_poll = poll(pfd, npfds, timeout);
-               if (err_poll < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       return -errno;
-               }
-               if (! err_poll)
-                       break;
-               err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents);
-               if (err < 0)
-                       return err;
-               for (i = 0; i < npfds; i++) {
-                       if (revents[i] & (POLLERR | POLLNVAL))
-                               return -EIO;
-                       if ((revents[i] & (POLLIN | POLLOUT)) == 0)
-                               continue;
-                       pollio++;
-               }
-       } while (! pollio);
-       return err_poll > 0 ? 1 : 0;
-}
-
-/**
- * \brief Get a ctl handle associated to the given hctl handle
- * \param hctl HCTL handle
- * \return a ctl handle otherwise NULL
- */
-snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl)
+unsigned int snd_ctl_get_count(snd_ctl_t *ctl)
 {
-       return hctl->ctl;
+       return ctl->count;
 }
 
-static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event)
+static int snd_ctl_handle_event(snd_ctl_t *ctl, snd_ctl_event_t *event)
 {
-       snd_hctl_elem_t *elem;
+       snd_ctl_elem_t *elem;
        int res;
 
-       assert(hctl);
-       assert(hctl->ctl);
+       assert(ctl);
        switch (event->type) {
        case SND_CTL_EVENT_ELEM:
                break;
@@ -738,30 +542,30 @@ static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event)
        }
        if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
                int dir;
-               res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir);
+               res = _snd_ctl_find_elem(ctl, &event->data.elem.id, &dir);
                assert(res >= 0 && dir == 0);
                if (res < 0 || dir != 0)
                        return -ENOENT;
-               snd_hctl_elem_remove(hctl, (unsigned int) res);
+               snd_ctl_celem_remove(ctl, (unsigned int) res);
                return 0;
        }
        if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) {
-               elem = calloc(1, sizeof(snd_hctl_elem_t));
+               elem = calloc(1, sizeof(snd_ctl_elem_t));
                if (elem == NULL)
                        return -ENOMEM;
                elem->id = event->data.elem.id;
-               elem->hctl = hctl;
-               res = snd_hctl_elem_add(hctl, elem);
+               elem->ctl = ctl;
+               res = snd_ctl_elem_add(ctl, elem);
                if (res < 0)
                        return res;
        }
        if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE |
                                     SNDRV_CTL_EVENT_MASK_INFO)) {
-               elem = snd_hctl_find_elem(hctl, &event->data.elem.id);
+               elem = snd_ctl_find_elem(ctl, &event->data.elem.id);
                assert(elem);
                if (!elem)
                        return -ENOENT;
-               res = snd_hctl_elem_throw_event(elem, event->data.elem.mask &
+               res = snd_ctl_elem_throw_event(elem, event->data.elem.mask &
                                                (SNDRV_CTL_EVENT_MASK_VALUE |
                                                 SNDRV_CTL_EVENT_MASK_INFO));
                if (res < 0)
@@ -771,23 +575,22 @@ static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event)
 }
 
 /**
- * \brief Handle pending HCTL events invoking callbacks
- * \param hctl HCTL handle
+ * \brief Handle pending CTL events invoking callbacks
+ * \param ctl CTL handle
  * \return 0 otherwise a negative error code on failure
  */
-int snd_hctl_handle_events(snd_hctl_t *hctl)
+int snd_ctl_handle_events(snd_ctl_t *ctl)
 {
        snd_ctl_event_t event;
        int res;
        unsigned int count = 0;
        
-       assert(hctl);
-       assert(hctl->ctl);
-       while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 &&
+       assert(ctl);
+       while ((res = snd_ctl_read(ctl, &event)) != 0 &&
               res != -EAGAIN) {
                if (res < 0)
                        return res;
-               res = snd_hctl_handle_event(hctl, &event);
+               res = snd_ctl_handle_event(ctl, &event);
                if (res < 0)
                        return res;
                count++;
@@ -796,108 +599,108 @@ int snd_hctl_handle_events(snd_hctl_t *hctl)
 }
 
 /**
- * \brief Get information for an HCTL element
- * \param elem HCTL element
- * \param info HCTL element information
+ * \brief Get information for an CTL element
+ * \param elem CTL element
+ * \param info CTL element information
  * \return 0 otherwise a negative error code on failure
  */
-int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info)
+int snd_ctl_celem_info(snd_ctl_elem_t *elem, snd_ctl_elem_info_t *info)
 {
        assert(elem);
-       assert(elem->hctl);
+       assert(elem->ctl);
        assert(info);
        info->id = elem->id;
-       return snd_ctl_elem_info(elem->hctl->ctl, info);
+       return snd_ctl_elem_info(elem->ctl, info);
 }
 
 /**
- * \brief Get value for an HCTL element
- * \param elem HCTL element
- * \param value HCTL element value
+ * \brief Get value for an CTL element
+ * \param elem CTL element
+ * \param value CTL element value
  * \return 0 otherwise a negative error code on failure
  */
-int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
+int snd_ctl_celem_read(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value)
 {
        assert(elem);
-       assert(elem->hctl);
+       assert(elem->ctl);
        assert(value);
        value->id = elem->id;
-       return snd_ctl_elem_read(elem->hctl->ctl, value);
+       return snd_ctl_elem_read(elem->ctl, value);
 }
 
 /**
- * \brief Set value for an HCTL element
- * \param elem HCTL element
- * \param value HCTL element value
+ * \brief Set value for an CTL element
+ * \param elem CTL element
+ * \param value CTL element value
  * \retval 0 on success
  * \retval >1 on success when value was changed
  * \retval <0 a negative error code on failure
  */
-int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
+int snd_ctl_celem_write(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value)
 {
        assert(elem);
-       assert(elem->hctl);
+       assert(elem->ctl);
        assert(value);
        value->id = elem->id;
-       return snd_ctl_elem_write(elem->hctl->ctl, value);
+       return snd_ctl_elem_write(elem->ctl, value);
 }
 
 /**
- * \brief Get TLV value for an HCTL element
- * \param elem HCTL element
+ * \brief Get TLV value for an CTL element
+ * \param elem CTL element
  * \param tlv TLV array for value
  * \param tlv_size size of TLV array in bytes
  * \return 0 otherwise a negative error code on failure
  */
-int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
+int snd_ctl_celem_tlv_read(snd_ctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
 {
        assert(elem);
        assert(tlv);
        assert(tlv_size >= 12);
-       return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size);
+       return snd_ctl_elem_tlv_read(elem->ctl, &elem->id, tlv, tlv_size);
 }
 
 /**
- * \brief Set TLV value for an HCTL element
- * \param elem HCTL element
+ * \brief Set TLV value for an CTL element
+ * \param elem CTL element
  * \param tlv TLV array for value
  * \retval 0 on success
  * \retval >1 on success when value was changed
  * \retval <0 a negative error code on failure
  */
-int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv)
+int snd_ctl_celem_tlv_write(snd_ctl_elem_t *elem, const unsigned int *tlv)
 {
        assert(elem);
        assert(tlv);
        assert(tlv[1] >= 4);
-       return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv);
+       return snd_ctl_elem_tlv_write(elem->ctl, &elem->id, tlv);
 }
 
 /**
- * \brief Set TLV value for an HCTL element
- * \param elem HCTL element
+ * \brief Set TLV value for an CTL element
+ * \param elem CTL element
  * \param tlv TLV array for value
  * \retval 0 on success
  * \retval >1 on success when value was changed
  * \retval <0 a negative error code on failure
  */
-int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv)
+int snd_ctl_celem_tlv_command(snd_ctl_elem_t *elem, const unsigned int *tlv)
 {
        assert(elem);
        assert(tlv);
        assert(tlv[1] >= 4);
-       return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv);
+       return snd_ctl_elem_tlv_command(elem->ctl, &elem->id, tlv);
 }
 
 /**
- * \brief Get HCTL handle for an HCTL element
- * \param elem HCTL element
- * \return HCTL handle
+ * \brief Get CTL handle for an CTL element
+ * \param elem CTL element
+ * \return CTL handle
  */
-snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem)
+snd_ctl_t *snd_ctl_elem_get_ctl(snd_ctl_elem_t *elem)
 {
        assert(elem);
-       return elem->hctl;
+       return elem->ctl;
 }
 
 /**
@@ -905,7 +708,7 @@ snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem)
  * \param obj CTL element id/value
  * \param ptr Pointer to returned CTL element identifier
  */
-void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
+void snd_ctl_elem_get_id(const snd_ctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
 {
        assert(obj && ptr);
        *ptr = obj->id;
@@ -916,7 +719,7 @@ void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
  * \param obj CTL element id/value
  * \return element numeric identifier
  */
-unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj)
+unsigned int snd_ctl_elem_get_numid(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->id.numid;
@@ -927,7 +730,7 @@ unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj)
  * \param obj CTL element id/value
  * \return interface part of element identifier
  */
-snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj)
+snd_ctl_elem_iface_t snd_ctl_elem_get_interface(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->id.iface;
@@ -938,7 +741,7 @@ snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj)
  * \param obj CTL element id/value
  * \return device part of element identifier
  */
-unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj)
+unsigned int snd_ctl_elem_get_device(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->id.device;
@@ -949,7 +752,7 @@ unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj)
  * \param obj CTL element id/value
  * \return subdevice part of element identifier
  */
-unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj)
+unsigned int snd_ctl_elem_get_subdevice(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->id.subdevice;
@@ -960,7 +763,7 @@ unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj)
  * \param obj CTL element id/value
  * \return name part of element identifier
  */
-const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj)
+const char *snd_ctl_elem_get_name(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return (const char *)obj->id.name;
@@ -971,40 +774,40 @@ const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj)
  * \param obj CTL element id/value
  * \return index part of element identifier
  */
-unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj)
+unsigned int snd_ctl_elem_get_index(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->id.index;
 }
 
 /**
- * \brief Set callback function for an HCTL element
- * \param obj HCTL element
+ * \brief Set callback function for an CTL element
+ * \param obj CTL element
  * \param val callback function
  */
-void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val)
+void snd_ctl_elem_set_callback(snd_ctl_elem_t *obj, snd_ctl_elem_callback_t val)
 {
        assert(obj);
        obj->callback = val;
 }
 
 /**
- * \brief Set callback private value for an HCTL element
- * \param obj HCTL element
+ * \brief Set callback private value for an CTL element
+ * \param obj CTL element
  * \param val callback private value
  */
-void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val)
+void snd_ctl_elem_set_callback_private(snd_ctl_elem_t *obj, void * val)
 {
        assert(obj);
        obj->callback_private = val;
 }
 
 /**
- * \brief Get callback private value for an HCTL element
- * \param obj HCTL element
+ * \brief Get callback private value for an CTL element
+ * \param obj CTL element
  * \return callback private value
  */
-void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj)
+void * snd_ctl_elem_get_callback_private(const snd_ctl_elem_t *obj)
 {
        assert(obj);
        return obj->callback_private;
diff --git a/src/control/hcontrol_old.c b/src/control/hcontrol_old.c
new file mode 100644 (file)
index 0000000..a084f1a
--- /dev/null
@@ -0,0 +1,512 @@
+/**
+ * \file control/hcontrol_old.c
+ * \brief HCTL Interface - High Level CTL
+ * \author Jaroslav Kysela <perex@perex.cz>
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \date 2000
+ *
+ * HCTL interface is designed to access preloaded and sorted primitive controls.
+ * Callbacks may be used for event handling.
+ * See \ref hcontrol page for more details.
+ */
+/*
+ *  Control Interface - high level API
+ *  Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/*! \page hcontrol High level control interface
+
+<P> High level control interface is designed to access preloaded and sorted primitive controls.
+
+\section hcontrol_general_overview General overview
+
+<P> High level control interface caches the accesses to primitive controls
+to reduce overhead accessing the real controls in kernel drivers.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include "control_local.h"
+#include "mixer_old.h"
+
+/**
+ * \brief Opens an HCTL
+ * \param hctlp Returned HCTL handle
+ * \param name ASCII identifier of the underlying CTL handle
+ * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode ATTRIBUTE_UNUSED)
+{
+       return snd_ctl_open(hctlp, name, SND_CTL_CACHE);
+}
+
+/**
+ * \brief Opens an HCTL
+ * \param hctlp Returned HCTL handle
+ * \param ctl underlying CTL handle
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl)
+{
+       assert(hctlp);
+       assert(ctl);
+       *hctlp = ctl;
+       ctl->mode = SND_CTL_CACHE;
+       return 0;
+}
+
+/**
+ * \brief close HCTL handle
+ * \param hctl HCTL handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified HCTL handle and frees all associated
+ * resources.
+ */
+int snd_hctl_close(snd_hctl_t *hctl)
+{
+       return snd_ctl_close(hctl);
+}
+
+/**
+ * \brief get identifier of HCTL handle
+ * \param hctl HCTL handle
+ * \return ascii identifier of HCTL handle
+ *
+ * Returns the ASCII identifier of given HCTL handle. It's the same
+ * identifier specified in snd_hctl_open().
+ */
+const char *snd_hctl_name(snd_hctl_t *hctl)
+{
+       assert(hctl);
+       return snd_ctl_name(hctl);
+}
+
+/**
+ * \brief set nonblock mode
+ * \param hctl HCTL handle
+ * \param nonblock 0 = block, 1 = nonblock mode
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock)
+{
+       assert(hctl);
+       return snd_ctl_nonblock(hctl, nonblock);
+}
+
+/**
+ * \brief set async mode
+ * \param hctl HCTL handle
+ * \param sig Signal to raise: < 0 disable, 0 default (SIGIO)
+ * \param pid Process ID to signal: 0 current
+ * \return 0 on success otherwise a negative error code
+ *
+ * A signal is raised when a change happens.
+ */
+int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid)
+{
+       assert(hctl);
+       return snd_ctl_async(hctl, sig, pid);
+}
+
+/**
+ * \brief get count of poll descriptors for HCTL handle
+ * \param hctl HCTL handle
+ * \return count of poll descriptors
+ */
+int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl)
+{
+       assert(hctl);
+       return snd_ctl_poll_descriptors_count(hctl);
+}
+
+/**
+ * \brief get poll descriptors
+ * \param hctl HCTL handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \return count of filled descriptors
+ */
+int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space)
+{
+       assert(hctl);
+       return snd_ctl_poll_descriptors(hctl, pfds, space);
+}
+
+/**
+ * \brief get returned events from poll descriptors
+ * \param hctl HCTL handle
+ * \param pfds array of poll descriptors
+ * \param nfds count of poll descriptors
+ * \param revents returned events
+ * \return zero if success, otherwise a negative error code
+ */
+int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+{
+       assert(hctl);
+       return snd_ctl_poll_descriptors_revents(hctl, pfds, nfds, revents);
+}
+
+/**
+ * \brief free HCTL loaded elements
+ * \param hctl HCTL handle
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_free(snd_hctl_t *hctl)
+{
+       return snd_ctl_cache_free(hctl);
+}
+
+/**
+ * \brief Change HCTL compare function and reorder elements
+ * \param hctl HCTL handle
+ * \param compare Element compare function
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare)
+{
+       return snd_ctl_set_compare(hctl, compare);
+}
+
+/**
+ * \brief get first element for an HCTL
+ * \param hctl HCTL handle
+ * \return pointer to first element
+ */
+snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl)
+{
+       return snd_ctl_first_elem(hctl);
+}
+
+/**
+ * \brief get last element for an HCTL
+ * \param hctl HCTL handle
+ * \return pointer to last element
+ */
+snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl)
+{
+       return snd_ctl_last_elem(hctl);
+}
+
+/**
+ * \brief get next HCTL element
+ * \param elem HCTL element
+ * \return pointer to next element
+ */
+snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem)
+{
+       return snd_ctl_elem_next(elem);
+}
+
+/**
+ * \brief get previous HCTL element
+ * \param elem HCTL element
+ * \return pointer to previous element
+ */
+snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem)
+{
+       return snd_ctl_elem_prev(elem);
+}
+
+/**
+ * \brief Search an HCTL element
+ * \param hctl HCTL handle
+ * \param id Element identifier
+ * \return pointer to found HCTL element or NULL if it does not exists
+ */
+snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id)
+{
+       return snd_ctl_find_elem(hctl, id);
+}
+
+/**
+ * \brief Load an HCTL with all elements and sort them
+ * \param hctl HCTL handle
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hctl_load(snd_hctl_t *hctl)
+{
+       return snd_ctl_subscribe_events(hctl, 1);
+}
+
+/**
+ * \brief Set callback function for an HCTL
+ * \param hctl HCTL handle
+ * \param callback callback function
+ */
+void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback)
+{
+       snd_ctl_set_callback(hctl, callback);
+}
+
+/**
+ * \brief Set callback private value for an HCTL
+ * \param hctl HCTL handle
+ * \param callback_private callback private value
+ */
+void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private)
+{
+       snd_ctl_set_callback_private(hctl, callback_private);
+}
+
+/**
+ * \brief Get callback private value for an HCTL
+ * \param hctl HCTL handle
+ * \return callback private value
+ */
+void *snd_hctl_get_callback_private(snd_hctl_t *hctl)
+{
+       return snd_ctl_get_callback_private(hctl);
+}
+
+/**
+ * \brief Get number of loaded elements for an HCTL
+ * \param hctl HCTL handle
+ * \return elements count
+ */
+unsigned int snd_hctl_get_count(snd_hctl_t *hctl)
+{
+       return snd_ctl_get_count(hctl);
+}
+
+/**
+ * \brief Wait for a HCTL to become ready (i.e. at least one event pending)
+ * \param hctl HCTL handle
+ * \param timeout maximum time in milliseconds to wait
+ * \return a positive value on success otherwise a negative error code
+ * \retval 0 timeout occurred
+ * \retval 1 an event is pending
+ */
+int snd_hctl_wait(snd_hctl_t *hctl, int timeout)
+{
+       return snd_ctl_wait(hctl, timeout);
+}
+
+/**
+ * \brief Get a ctl handle associated to the given hctl handle
+ * \param hctl HCTL handle
+ * \return a ctl handle otherwise NULL
+ */
+snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl)
+{
+       return hctl;
+}
+
+/**
+ * \brief Handle pending HCTL events invoking callbacks
+ * \param hctl HCTL handle
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_handle_events(snd_hctl_t *hctl)
+{
+       return snd_ctl_handle_events(hctl);
+}
+
+/**
+ * \brief Get information for an HCTL element
+ * \param elem HCTL element
+ * \param info HCTL element information
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info)
+{
+       return snd_ctl_celem_info(elem, info);
+}
+
+/**
+ * \brief Get value for an HCTL element
+ * \param elem HCTL element
+ * \param value HCTL element value
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
+{
+       return snd_ctl_celem_read(elem, value);
+}
+
+/**
+ * \brief Set value for an HCTL element
+ * \param elem HCTL element
+ * \param value HCTL element value
+ * \retval 0 on success
+ * \retval >1 on success when value was changed
+ * \retval <0 a negative error code on failure
+ */
+int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
+{
+       return snd_ctl_celem_write(elem, value);
+}
+
+/**
+ * \brief Get TLV value for an HCTL element
+ * \param elem HCTL element
+ * \param tlv TLV array for value
+ * \param tlv_size size of TLV array in bytes
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
+{
+       return snd_ctl_celem_tlv_read(elem, tlv, tlv_size);
+}
+
+/**
+ * \brief Set TLV value for an HCTL element
+ * \param elem HCTL element
+ * \param tlv TLV array for value
+ * \retval 0 on success
+ * \retval >1 on success when value was changed
+ * \retval <0 a negative error code on failure
+ */
+int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv)
+{
+       return snd_ctl_celem_tlv_write(elem, tlv);
+}
+
+/**
+ * \brief Set TLV value for an HCTL element
+ * \param elem HCTL element
+ * \param tlv TLV array for value
+ * \retval 0 on success
+ * \retval >1 on success when value was changed
+ * \retval <0 a negative error code on failure
+ */
+int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv)
+{
+       return snd_ctl_celem_tlv_command(elem, tlv);
+}
+
+/**
+ * \brief Get HCTL handle for an HCTL element
+ * \param elem HCTL element
+ * \return HCTL handle
+ */
+snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem)
+{
+       return snd_ctl_elem_get_ctl(elem);
+}
+
+/**
+ * \brief Get CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \param ptr Pointer to returned CTL element identifier
+ */
+void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr)
+{
+       snd_ctl_elem_get_id(obj, ptr);
+}
+
+/**
+ * \brief Get element numeric identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return element numeric identifier
+ */
+unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_numid(obj);
+}
+
+/**
+ * \brief Get interface part of CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return interface part of element identifier
+ */
+snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj)
+{
+return snd_ctl_elem_get_interface(obj);
+}
+
+/**
+ * \brief Get device part of CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return device part of element identifier
+ */
+unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_device(obj);
+}
+
+/**
+ * \brief Get subdevice part of CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return subdevice part of element identifier
+ */
+unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_subdevice(obj);
+}
+
+/**
+ * \brief Get name part of CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return name part of element identifier
+ */
+const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_name(obj);
+}
+
+/**
+ * \brief Get index part of CTL element identifier of a CTL element id/value
+ * \param obj CTL element id/value
+ * \return index part of element identifier
+ */
+unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_index(obj);
+}
+
+/**
+ * \brief Set callback function for an HCTL element
+ * \param obj HCTL element
+ * \param val callback function
+ */
+void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val)
+{
+       return snd_ctl_elem_set_callback(obj, val);
+}
+
+/**
+ * \brief Set callback private value for an HCTL element
+ * \param obj HCTL element
+ * \param val callback private value
+ */
+void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val)
+{
+       return snd_ctl_elem_set_callback_private(obj, val);
+}
+
+/**
+ * \brief Get callback private value for an HCTL element
+ * \param obj HCTL element
+ * \return callback private value
+ */
+void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj)
+{
+       return snd_ctl_elem_get_callback_private(obj);
+}
+
index bb466ed773858512a7d33238757c019ad52a3cf5..84272ada76e8c7c6b81be2591e994d1c0d224e2b 100644 (file)
@@ -1,8 +1,9 @@
 EXTRA_LTLIBRARIES=libmixer.la
 
-libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c simple_abst.c
+libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c mixer_symbols.c \
+                     mixer_old.c simple_old.c
 
-noinst_HEADERS = mixer_local.h mixer_simple.h
+noinst_HEADERS = mixer_local.h mixer_old_local.h
 
 all: libmixer.la
 
index 85d843fc9a35f1b36e86c24471af1d1d7625f28c..cece6541636413906018b8067371df632c501cf6 100644 (file)
@@ -3,7 +3,7 @@
  * \brief Mixer Interface
  * \author Jaroslav Kysela <perex@perex.cz>
  * \author Abramo Bagnara <abramo@alsa-project.org>
- * \date 2001
+ * \date 2001-2009
  *
  * Mixer interface is designed to access mixer elements.
  * Callbacks may be used for event handling.
  *
  */
 
-/*! \page mixer Mixer interface
+/*! \page amixer Mixer interface
 
-<P>Mixer interface is designed to access the abstracted mixer controls.
-This is an abstraction layer over the hcontrol layer.
+<P>Mixer interface is designed to access the abstracted amixer controls.
 
-\section mixer_general_overview General overview
+\section amixer_general_overview General overview
+
+\section amixer_global Global mixer
+
+The global mixer exposes basic or all (#SND_AMIXER_ALL) mixer related
+controls to application.
+
+\par Master
+This control element defines playback master volume control for
+whole card.
+
+\section amixer_pcm PCM related mixer
+
+This mixer works with PCM related controls with predefined abstractions.
+
+\subsection amixer_pcm_playback Playback direction
+
+Bellow mixer controls are available for playback PCM.
+
+\par Master
+Playback master volume control.
+
+\par PCM
+Playback PCM stream related volume control.
+
+\subsection amixer_pcm_capture Capture direction
+
+Note that none or any combination of controls might be present, but
+at least Capture control should be implemented in alsa-lib.
+
+\par Capture
+Capture PCM stream related volume control.
+
+\par Source
+Capture Source (enum like Mic,CD,Line etc.).
+
+\par [other] - like CD, Aux, Front Line etc.
+These sources are mixed to PCM input. Both volume and switch might be
+available.
 
 */
 
@@ -46,103 +83,342 @@ This is an abstraction layer over the hcontrol layer.
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "mixer_local.h"
-
-#ifndef DOC_HIDDEN
-typedef struct _snd_mixer_slave {
-       snd_hctl_t *hctl;
-       struct list_head list;
-} snd_mixer_slave_t;
-
+#include "mixer_abst.h"
+
+static int ctl_event_handler(snd_ctl_t *ctl,
+                            unsigned int mask,
+                            snd_ctl_elem_t *elem);
+
+static const char *const build_in_mixers[] = {
+       "none", NULL
+};
+
+static int snd_amixer_open_conf(snd_amixer_t **amixerp,
+                               const char *name,
+                               snd_config_t *mixer_root,
+                               snd_config_t *mixer_conf,
+                               snd_pcm_t *pcm_playback,
+                               snd_pcm_t *pcm_capture,
+                               int mode)
+{
+       const char *str;
+       char *buf = NULL, *buf1 = NULL;
+       int err, idx;
+       snd_config_t *conf, *type_conf = NULL;
+       snd_config_iterator_t i, next;
+       const char *id;
+       const char *lib = NULL, *open_name = NULL;
+       int (*open_func)(snd_amixer_t *amixer,
+                        snd_config_t *root,
+                        snd_config_t *conf,
+                        struct sm_open *sm_open) = NULL;
+#ifndef PIC
+       extern void *snd_amixer_open_symbols(void);
+#endif
+       void *h = NULL;
+       snd_amixer_t *amixer;
+       if (snd_config_get_type(mixer_conf) != SND_CONFIG_TYPE_COMPOUND) {
+               char *val;
+               id = NULL;
+               snd_config_get_id(mixer_conf, &id);
+               val = NULL;
+               snd_config_get_ascii(mixer_conf, &val);
+               SNDERR("Invalid type for mixer %s%sdefinition (id: %s, value: %s)", name ? name : "", name ? " " : "", id, val);
+               free(val);
+               return -EINVAL;
+       }
+       err = snd_config_search(mixer_conf, "type", &conf);
+       if (err < 0) {
+               SNDERR("type is not defined");
+               return err;
+       }
+       err = snd_config_get_id(conf, &id);
+       if (err < 0) {
+               SNDERR("unable to get id");
+               return err;
+       }
+       err = snd_config_get_string(conf, &str);
+       if (err < 0) {
+               SNDERR("Invalid type for %s", id);
+               return err;
+       }
+       err = snd_config_search_definition(mixer_root, "amixer_type", str, &type_conf);
+       if (err >= 0) {
+               if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
+                       SNDERR("Invalid type for amixer type %s definition", str);
+                       goto _err;
+               }
+               snd_config_for_each(i, next, type_conf) {
+                       snd_config_t *n = snd_config_iterator_entry(i);
+                       const char *id;
+                       if (snd_config_get_id(n, &id) < 0)
+                               continue;
+                       if (strcmp(id, "comment") == 0)
+                               continue;
+                       if (strcmp(id, "lib") == 0) {
+                               err = snd_config_get_string(n, &lib);
+                               if (err < 0) {
+                                       SNDERR("Invalid type for %s", id);
+                                       goto _err;
+                               }
+                               continue;
+                       }
+                       if (strcmp(id, "open") == 0) {
+                               err = snd_config_get_string(n, &open_name);
+                               if (err < 0) {
+                                       SNDERR("Invalid type for %s", id);
+                                       goto _err;
+                               }
+                               continue;
+                       }
+                       SNDERR("Unknown field %s", id);
+                       err = -EINVAL;
+                       goto _err;
+               }
+       }
+       if (!open_name) {
+               buf = malloc(strlen(str) + 32);
+               if (buf == NULL) {
+                       err = -ENOMEM;
+                       goto _err;
+               }
+               open_name = buf;
+               sprintf(buf, "_snd_amixer_%s_open", str);
+       }
+       if (!lib) {
+               const char *const *build_in = build_in_mixers;
+               while (*build_in) {
+                       if (!strcmp(*build_in, str))
+                               break;
+                       build_in++;
+               }
+               if (*build_in == NULL) {
+                       buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
+                       if (buf1 == NULL) {
+                               err = -ENOMEM;
+                               goto _err;
+                       }
+                       lib = buf1;
+                       sprintf(buf1, "%s/libasound_module_mixer_%s.so", ALSA_PLUGIN_DIR, str);
+               }
+       }
+#ifndef PIC
+       snd_mixer_open_symbols();       /* this call is for static linking only */
 #endif
+       open_func = snd_dlobj_cache_lookup(open_name);
+       if (open_func) {
+               err = 0;
+               goto _err;
+       }
+       h = snd_dlopen(lib, RTLD_NOW);
+       if (h)
+               open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_AMIXER_DLSYM_VERSION));
+       err = 0;
+       if (!h) {
+               SNDERR("Cannot open shared library %s",
+                      lib ? lib : "[builtin]");
+               err = -ENOENT;
+       } else if (!open_func) {
+               SNDERR("symbol %s is not defined inside %s", open_name,
+                      lib ? lib : "[builtin]");
+               snd_dlclose(h);
+               err = -ENXIO;
+       }
+       _err:
+       if (err >= 0) {
+               amixer = calloc(1, sizeof(*amixer));
+               if (amixer == NULL) {
+                       err = -ENOMEM;
+                       goto _err1;
+               }
+               INIT_LIST_HEAD(&amixer->elems);
+               amixer->compare = snd_amixer_compare_default;
+               amixer->sm_open.name = name;
+               amixer->sm_open.pcm_playback = pcm_playback;
+               amixer->sm_open.pcm_capture = pcm_capture;
+               amixer->sm_open.mode = mode;
+               err = open_func(amixer, mixer_root, mixer_conf, &amixer->sm_open);
+               if (err < 0) {
+                       snd_amixer_close(amixer);
+                       goto _err1;
+               }
+               for (idx = 0; idx < SM_CTL_COUNT; idx++) {
+                       snd_ctl_t *ctl = amixer->sm_open.ctl[idx];
+                       if (ctl == NULL)
+                               continue;
+                       snd_ctl_set_callback(ctl, ctl_event_handler);
+                       snd_ctl_set_callback_private(ctl, amixer);
+                       err = snd_hctl_nonblock(ctl, 1);
+                       if (err >= 0)
+                               err = snd_ctl_subscribe_events(ctl, 1);
+                       if (err < 0) {
+                               snd_amixer_close(amixer);
+                               goto _err1;
+                        }
+               }
+               *amixerp = amixer;
+              _err1:
+               if (err >= 0) {
+                       if (h /*&& (mode & SND_PCM_KEEP_ALIVE)*/) {
+                               snd_dlobj_cache_add(open_name, h, open_func);
+                               h = NULL;
+                       }
+                       amixer->dl_handle = h;
+                       err = 0;
+               } else {
+                       if (h)
+                               snd_dlclose(h);
+               }
+       }
+       if (type_conf)
+               snd_config_delete(type_conf);
+       free(buf);
+       free(buf1);
+       return err;
+}
+
+static int snd_amixer_open_noupdate(snd_amixer_t **amixerp,
+                                   snd_config_t *root,
+                                   const char *name,
+                                   snd_pcm_t *pcm_playback,
+                                   snd_pcm_t *pcm_capture,
+                                   int mode,
+                                   int hop)
+{
+       int err, pcm = pcm_playback || pcm_capture;
+       snd_config_t *mixer_conf;
+       const char *str;
 
-static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
-                                    const snd_mixer_elem_t *c2);
+       err = snd_config_search_definition(root, pcm ? "amixer_pcm" : "amixer", name, &mixer_conf);
+       if (err < 0) {
+               SNDERR("Uknown amixer %s", name);
+               return err;
+       }
+       if (snd_config_get_string(mixer_conf, &str) >= 0) {
+               err = snd_amixer_open_noupdate(amixerp, root, name, pcm_playback, pcm_capture, mode, hop);
+       } else {
+               snd_config_set_hop(mixer_conf, hop);
+               err = snd_amixer_open_conf(amixerp, name, root, mixer_conf, pcm_playback, pcm_capture, mode);
+       }
+       snd_config_delete(mixer_conf);
+       return err;
+}
 
+/**
+ * \brief Opens the global or PCM related mixer
+ * \param amixerp Returned amixer handle
+ * \param name ASCII identifier of the mixer handle
+ * \param pcm_playback Playback PCM
+ * \param pcm_capture Capture PCM
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ *
+ * If both pcm_playback and pcm_capture parameters are NULL, the global
+ * mixer is opened.
+ */
+int snd_amixer_open(snd_amixer_t **amixerp,
+                   const char *name,
+                   snd_pcm_t *pcm_playback,
+                   snd_pcm_t *pcm_capture,
+                   int mode)
+{
+       int err;
+       assert(amixerp);
+       assert(name);
+       err = snd_config_update();
+       if (err < 0)
+               return err;
+       return snd_amixer_open_noupdate(amixerp, snd_config, name, pcm_playback, pcm_capture, mode, 0);
+}
 
 /**
- * \brief Opens an empty mixer
- * \param mixerp Returned mixer handle
+ * \brief Opens the global or PCM related mixer using local configuration
+ * \param amixerp Returned amixer handle
+ * \param name ASCII identifier of the mixer handle
+ * \param pcm_playback Playback PCM
+ * \param pcm_capture Capture PCM
  * \param mode Open mode
+ * \param lconf Local configuration
  * \return 0 on success otherwise a negative error code
+ *
+ * If both pcm_playback and pcm_capture parameters are NULL, the global
+ * mixer is opened.
  */
-int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED)
+int snd_amixer_open_lconf(snd_amixer_t **amixerp,
+                         const char *name,
+                         snd_pcm_t *pcm_playback,
+                         snd_pcm_t *pcm_capture,
+                         int mode,
+                         snd_config_t *lconf)
 {
-       snd_mixer_t *mixer;
-       assert(mixerp);
-       mixer = calloc(1, sizeof(*mixer));
-       if (mixer == NULL)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&mixer->slaves);
-       INIT_LIST_HEAD(&mixer->classes);
-       INIT_LIST_HEAD(&mixer->elems);
-       mixer->compare = snd_mixer_compare_default;
-       *mixerp = mixer;
-       return 0;
+       assert(amixerp);
+       assert(name);
+       assert(lconf);
+       return snd_amixer_open_noupdate(amixerp, lconf, name, pcm_playback, pcm_capture, mode, 0);
 }
 
 /**
- * \brief Attach an HCTL element to a mixer element
+ * \brief Attach an CTL element to a amixer element
  * \param melem Mixer element
- * \param helem HCTL element
+ * \param elem CTL element
  * \return 0 on success otherwise a negative error code
  *
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
  */
-int snd_mixer_elem_attach(snd_mixer_elem_t *melem,
-                         snd_hctl_elem_t *helem)
+int snd_amixer_elem_attach(snd_amixer_elem_t *melem,
+                          snd_ctl_elem_t *elem)
 {
-       bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+       bag_t *bag = snd_ctl_elem_get_callback_private(elem);
        int err;
        err = bag_add(bag, melem);
        if (err < 0)
                return err;
-       return bag_add(&melem->helems, helem);
+       return bag_add(&melem->helems, elem);
 }
 
 /**
- * \brief Detach an HCTL element from a mixer element
+ * \brief Detach an CTL element from a amixer element
  * \param melem Mixer element
- * \param helem HCTL element
+ * \param elem CTL element
  * \return 0 on success otherwise a negative error code
  *
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
  */
-int snd_mixer_elem_detach(snd_mixer_elem_t *melem,
-                         snd_hctl_elem_t *helem)
+int snd_amixer_elem_detach(snd_amixer_elem_t *melem,
+                          snd_ctl_elem_t *elem)
 {
-       bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+       bag_t *bag = snd_ctl_elem_get_callback_private(elem);
        int err;
        err = bag_del(bag, melem);
        assert(err >= 0);
-       err = bag_del(&melem->helems, helem);
+       err = bag_del(&melem->helems, elem);
        assert(err >= 0);
        return 0;
 }
 
 /**
- * \brief Return true if a mixer element does not contain any HCTL elements
+ * \brief Return true if a amixer element does not contain any CTL elements
  * \param melem Mixer element
  * \return 0 if not empty, 1 if empty
  *
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
  */
-int snd_mixer_elem_empty(snd_mixer_elem_t *melem)
+int snd_amixer_elem_is_empty(snd_amixer_elem_t *melem)
 {
        return bag_empty(&melem->helems);
 }
 
-static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
-                                  unsigned int mask)
+static int ctl_elem_event_handler(snd_ctl_elem_t *elem,
+                                 unsigned int mask)
 {
-       bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+       bag_t *bag = snd_ctl_elem_get_callback_private(elem);
        if (mask == SND_CTL_EVENT_MASK_REMOVE) {
                int res = 0;
                int err;
                bag_iterator_t i, n;
                bag_for_each_safe(i, n, bag) {
-                       snd_mixer_elem_t *melem = bag_iterator_entry(i);
-                       snd_mixer_class_t *class = melem->class;
-                       err = class->event(class, mask, helem, melem);
+                       snd_amixer_elem_t *melem = bag_iterator_entry(i);
+                       err = melem->amixer->event(melem->amixer, mask, elem, melem);
                        if (err < 0)
                                res = err;
                }
@@ -154,9 +430,8 @@ static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
                int err = 0;
                bag_iterator_t i, n;
                bag_for_each_safe(i, n, bag) {
-                       snd_mixer_elem_t *melem = bag_iterator_entry(i);
-                       snd_mixer_class_t *class = melem->class;
-                       err = class->event(class, mask, helem, melem);
+                       snd_amixer_elem_t *melem = bag_iterator_entry(i);
+                       err = melem->amixer->event(melem->amixer, mask, elem, melem);
                        if (err < 0)
                                return err;
                }
@@ -164,176 +439,57 @@ static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
        return 0;
 }
 
-static int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask,
-                             snd_hctl_elem_t *elem)
+static int ctl_event_handler(snd_ctl_t *ctl,
+                            unsigned int mask,
+                            snd_ctl_elem_t *elem)
 {
-       snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl);
+       snd_amixer_t *amixer = snd_ctl_get_callback_private(ctl);
        int res = 0;
        if (mask & SND_CTL_EVENT_MASK_ADD) {
-               struct list_head *pos;
                bag_t *bag;
                int err = bag_new(&bag);
                if (err < 0)
                        return err;
-               snd_hctl_elem_set_callback(elem, hctl_elem_event_handler);
-               snd_hctl_elem_set_callback_private(elem, bag);
-               list_for_each(pos, &mixer->classes) {
-                       snd_mixer_class_t *c;
-                       c = list_entry(pos, snd_mixer_class_t, list);
-                       err = c->event(c, mask, elem, NULL);
-                       if (err < 0)
-                               res = err;
-               }
+               snd_ctl_elem_set_callback(elem, ctl_elem_event_handler);
+               snd_ctl_elem_set_callback_private(elem, bag);
+               err = amixer->event(amixer, mask, elem, NULL);
+               if (err < 0)
+                       return err;
        }
        return res;
 }
 
-
-/**
- * \brief Attach an HCTL specified with the CTL device name to an opened mixer
- * \param mixer Mixer handle
- * \param name HCTL name (see #snd_hctl_open)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_attach(snd_mixer_t *mixer, const char *name)
-{
-       snd_hctl_t *hctl;
-       int err;
-
-       err = snd_hctl_open(&hctl, name, 0);
-       if (err < 0)
-               return err;
-       err = snd_mixer_attach_hctl(mixer, hctl);
-       if (err < 0) {
-               snd_hctl_close(hctl);
-               return err;
-       }
-       return 0;
-}
-
-/**
- * \brief Attach an HCTL to an opened mixer
- * \param mixer Mixer handle
- * \param hctl the HCTL to be attached
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
-{
-       snd_mixer_slave_t *slave;
-       int err;
-
-       assert(hctl);
-       slave = calloc(1, sizeof(*slave));
-       if (slave == NULL)
-               return -ENOMEM;
-       err = snd_hctl_nonblock(hctl, 1);
-       if (err < 0) {
-               snd_hctl_close(hctl);
-               free(slave);
-               return err;
-       }
-       snd_hctl_set_callback(hctl, hctl_event_handler);
-       snd_hctl_set_callback_private(hctl, mixer);
-       slave->hctl = hctl;
-       list_add_tail(&slave->list, &mixer->slaves);
-       return 0;
-}
-
-/**
- * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
- * \param mixer Mixer handle
- * \param name HCTL previously attached
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_detach(snd_mixer_t *mixer, const char *name)
-{
-       struct list_head *pos;
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
-                       snd_hctl_close(s->hctl);
-                       list_del(pos);
-                       free(s);
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-/**
- * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
- * \param mixer Mixer handle
- * \param hctl HCTL previously attached
- * \return 0 on success otherwise a negative error code
- *
- * Note: The hctl handle is not closed!
- */
-int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
-{
-       struct list_head *pos;
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               if (hctl == s->hctl) {
-                       list_del(pos);
-                       free(s);
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-/**
- * \brief Obtain a HCTL pointer associated to given name
- * \param mixer Mixer handle
- * \param name HCTL previously attached
- * \param hctl HCTL pointer
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl)
-{
-       struct list_head *pos;
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
-                       *hctl = s->hctl;
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-static int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask,
-                         snd_mixer_elem_t *elem)
+static int snd_amixer_throw_event(snd_amixer_t *amixer,
+                                 unsigned int mask,
+                                 snd_amixer_elem_t *elem)
 {
-       mixer->events++;
-       if (mixer->callback)
-               return mixer->callback(mixer, mask, elem);
+       amixer->events++;
+       if (amixer->callback)
+               return amixer->callback(amixer, mask, elem);
        return 0;
 }
 
-static int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask)
+static int snd_amixer_elem_throw_event(snd_amixer_elem_t *elem,
+                                      unsigned int mask)
 {
-       elem->class->mixer->events++;
+       elem->amixer->events++;
        if (elem->callback)
                return elem->callback(elem, mask);
        return 0;
 }
 
-static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir)
+static int _snd_amixer_find_elem(snd_amixer_t *amixer, snd_amixer_elem_t *elem, int *dir)
 {
        unsigned int l, u;
        int c = 0;
        int idx = -1;
-       assert(mixer && elem);
-       assert(mixer->compare);
+       assert(amixer && elem);
+       assert(amixer->compare);
        l = 0;
-       u = mixer->count;
+       u = amixer->count;
        while (l < u) {
                idx = (l + u) / 2;
-               c = mixer->compare(elem, mixer->pelems[idx]);
+               c = amixer->compare(elem, amixer->pelems[idx]);
                if (c < 0)
                        u = idx;
                else if (c > 0)
@@ -346,38 +502,37 @@ static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int
 }
 
 /**
- * \brief Get private data associated to give mixer element
+ * \brief Get private data associated to give amixer element
  * \param elem Mixer element
  * \return private data
- *
- * For use by mixer element class specific code.
  */
-void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem)
+void *snd_amixer_elem_get_private(const snd_amixer_elem_t *elem)
 {
        return elem->private_data;
 }
 
 /**
- * \brief Allocate a new mixer element
- * \param elem Returned mixer element
- * \param type Mixer element type
+ * \brief Allocate a new amixer element
+ * \param amixer Mixer handle
+ * \param elem Returned amixer element
+ * \param id Element identificator
  * \param compare_weight Mixer element compare weight
  * \param private_data Private data
  * \param private_free Private data free callback
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
  */
-int snd_mixer_elem_new(snd_mixer_elem_t **elem,
-                      snd_mixer_elem_type_t type,
-                      int compare_weight,
-                      void *private_data,
-                      void (*private_free)(snd_mixer_elem_t *elem))
+int snd_amixer_elem_new(snd_amixer_t *amixer,
+                       snd_amixer_elem_t **elem,
+                       snd_amixer_elem_id_t *id,
+                       int compare_weight,
+                       void *private_data,
+                       void (*private_free)(snd_amixer_elem_t *elem))
 {
-       snd_mixer_elem_t *melem = calloc(1, sizeof(*melem));
+       snd_amixer_elem_t *melem = calloc(1, sizeof(*melem));
        if (melem == NULL)
                return -ENOMEM;
-       melem->type = type;
+       melem->amixer = amixer;
+       melem->sm.id = *id;
        melem->compare_weight = compare_weight;
        melem->private_data = private_data;
        melem->private_free = private_free;
@@ -387,92 +542,84 @@ int snd_mixer_elem_new(snd_mixer_elem_t **elem,
 }
 
 /**
- * \brief Add an element for a registered mixer element class
+ * \brief Add an element for an amixer handle
+ * \param amixer Mixer handle
  * \param elem Mixer element
- * \param class Mixer element class
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
  */
-int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
+int snd_amixer_elem_add(snd_amixer_t *amixer, snd_amixer_elem_t *elem)
 {
        int dir, idx;
-       snd_mixer_t *mixer = class->mixer;
-       elem->class = class;
 
-       if (mixer->count == mixer->alloc) {
-               snd_mixer_elem_t **m;
-               mixer->alloc += 32;
-               m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc);
+       if (amixer->count == amixer->alloc) {
+               snd_amixer_elem_t **m;
+               amixer->alloc += 32;
+               m = realloc(amixer->pelems, sizeof(*m) * amixer->alloc);
                if (!m) {
-                       mixer->alloc -= 32;
+                       amixer->alloc -= 32;
                        return -ENOMEM;
                }
-               mixer->pelems = m;
+               amixer->pelems = m;
        }
-       if (mixer->count == 0) {
-               list_add_tail(&elem->list, &mixer->elems);
-               mixer->pelems[0] = elem;
+       if (amixer->count == 0) {
+               list_add_tail(&elem->list, &amixer->elems);
+               amixer->pelems[0] = elem;
        } else {
-               idx = _snd_mixer_find_elem(mixer, elem, &dir);
+               idx = _snd_amixer_find_elem(amixer, elem, &dir);
                assert(dir != 0);
                if (dir > 0) {
-                       list_add(&elem->list, &mixer->pelems[idx]->list);
+                       list_add(&elem->list, &amixer->pelems[idx]->list);
                        idx++;
                } else {
-                       list_add_tail(&elem->list, &mixer->pelems[idx]->list);
+                       list_add_tail(&elem->list, &amixer->pelems[idx]->list);
                }
-               memmove(mixer->pelems + idx + 1,
-                       mixer->pelems + idx,
-                       (mixer->count - idx) * sizeof(snd_mixer_elem_t *));
-               mixer->pelems[idx] = elem;
+               memmove(amixer->pelems + idx + 1,
+                       amixer->pelems + idx,
+                       (amixer->count - idx) * sizeof(snd_amixer_elem_t *));
+               amixer->pelems[idx] = elem;
        }
-       mixer->count++;
-       return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem);
+       amixer->count++;
+       return snd_amixer_throw_event(amixer, SND_CTL_EVENT_MASK_ADD, elem);
 }
 
 /**
- * \brief Remove a mixer element
+ * \brief Remove a amixer element
  * \param elem Mixer element
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
  */
-int snd_mixer_elem_remove(snd_mixer_elem_t *elem)
+int snd_amixer_elem_remove(snd_amixer_elem_t *elem)
 {
-       snd_mixer_t *mixer = elem->class->mixer;
+       snd_amixer_t *amixer = elem->amixer;
        bag_iterator_t i, n;
        int err, idx, dir;
        unsigned int m;
        assert(elem);
-       assert(mixer->count);
-       idx = _snd_mixer_find_elem(mixer, elem, &dir);
+       assert(amixer->count);
+       idx = _snd_amixer_find_elem(amixer, elem, &dir);
        if (dir != 0)
                return -EINVAL;
        bag_for_each_safe(i, n, &elem->helems) {
-               snd_hctl_elem_t *helem = bag_iterator_entry(i);
-               snd_mixer_elem_detach(elem, helem);
+               snd_ctl_elem_t *helem = bag_iterator_entry(i);
+               snd_amixer_elem_detach(elem, helem);
        }
-       err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
+       err = snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
        list_del(&elem->list);
-       snd_mixer_elem_free(elem);
-       mixer->count--;
-       m = mixer->count - idx;
+       snd_amixer_elem_free(elem);
+       amixer->count--;
+       m = amixer->count - idx;
        if (m > 0)
-               memmove(mixer->pelems + idx,
-                       mixer->pelems + idx + 1,
-                       m * sizeof(snd_mixer_elem_t *));
+               memmove(amixer->pelems + idx,
+                       amixer->pelems + idx + 1,
+                       m * sizeof(snd_amixer_elem_t *));
        return err;
 }
 
 /**
- * \brief Free a mixer element
+ * \brief Free a amixer element
  * \param elem Mixer element
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
  */
-void snd_mixer_elem_free(snd_mixer_elem_t *elem)
+void snd_amixer_elem_free(snd_amixer_elem_t *elem)
 {
        if (elem->private_free)
                elem->private_free(elem);
@@ -483,214 +630,100 @@ void snd_mixer_elem_free(snd_mixer_elem_t *elem)
  * \brief Mixer element informations are changed
  * \param elem Mixer element
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
  */
-int snd_mixer_elem_info(snd_mixer_elem_t *elem)
+int snd_amixer_elem_info(snd_amixer_elem_t *elem)
 {
-       return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
+       return snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
 }
 
 /**
  * \brief Mixer element values is changed
  * \param elem Mixer element
  * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
- */
-int snd_mixer_elem_value(snd_mixer_elem_t *elem)
-{
-       return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
-}
-
-/**
- * \brief Register mixer element class
- * \param class Mixer element class
- * \param mixer Mixer handle
- * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
- */
-int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer)
-{
-       struct list_head *pos;
-       class->mixer = mixer;
-       list_add_tail(&class->list, &mixer->classes);
-       if (!class->event)
-               return 0;
-       list_for_each(pos, &mixer->slaves) {
-               int err;
-               snd_mixer_slave_t *slave;
-               snd_hctl_elem_t *elem;
-               slave = list_entry(pos, snd_mixer_slave_t, list);
-               elem = snd_hctl_first_elem(slave->hctl);
-               while (elem) {
-                       err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL);
-                       if (err < 0)
-                               return err;
-                       elem = snd_hctl_elem_next(elem);
-               }
-       }
-       return 0;
-}
-
-/**
- * \brief Unregister mixer element class and remove all its elements
- * \param class Mixer element class
- * \return 0 on success otherwise a negative error code
- *
- * Note that the class structure is also deallocated!
  */
-int snd_mixer_class_unregister(snd_mixer_class_t *class)
+int snd_amixer_elem_value(snd_amixer_elem_t *elem)
 {
-       unsigned int k;
-       snd_mixer_elem_t *e;
-       snd_mixer_t *mixer = class->mixer;
-       for (k = mixer->count; k > 0; k--) {
-               e = mixer->pelems[k-1];
-               if (e->class == class)
-                       snd_mixer_elem_remove(e);
-       }
-       if (class->private_free)
-               class->private_free(class);
-       list_del(&class->list);
-       free(class);
-       return 0;
+       return snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
 }
 
 /**
- * \brief Load a mixer elements
- * \param mixer Mixer handle
+ * \brief Close a amixer and free all related resources
+ * \param amixer Mixer handle
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_load(snd_mixer_t *mixer)
+int snd_amixer_close(snd_amixer_t *amixer)
 {
-       struct list_head *pos;
-       list_for_each(pos, &mixer->slaves) {
-               int err;
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               err = snd_hctl_load(s->hctl);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
+       int res = 0, i;
 
-/**
- * \brief Unload all mixer elements and free all related resources
- * \param mixer Mixer handle
- */
-void snd_mixer_free(snd_mixer_t *mixer)
-{
-       struct list_head *pos;
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               snd_hctl_free(s->hctl);
-       }
-}
-
-/**
- * \brief Close a mixer and free all related resources
- * \param mixer Mixer handle
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_close(snd_mixer_t *mixer)
-{
-       int res = 0;
-       assert(mixer);
-       while (!list_empty(&mixer->classes)) {
-               snd_mixer_class_t *c;
-               c = list_entry(mixer->classes.next, snd_mixer_class_t, list);
-               snd_mixer_class_unregister(c);
+       assert(amixer);
+       for (i = 0; i < SM_CTL_COUNT; i++) {
+               if (amixer->sm_open.ctl[i])
+                       res = snd_ctl_close(amixer->sm_open.ctl[i]);
+               amixer->sm_open.ctl[i] = NULL;
        }
-       assert(list_empty(&mixer->elems));
-       assert(mixer->count == 0);
-       free(mixer->pelems);
-       mixer->pelems = NULL;
-       while (!list_empty(&mixer->slaves)) {
-               int err;
-               snd_mixer_slave_t *s;
-               s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list);
-               err = snd_hctl_close(s->hctl);
-               if (err < 0)
-                       res = err;
-               list_del(&s->list);
-               free(s);
-       }
-       free(mixer);
+       assert(list_empty(&amixer->elems));
+       if (amixer->pelems)
+               free(amixer->pelems);
+       if (amixer->dl_handle)
+               snd_dlclose(amixer->dl_handle);
+       free(amixer);
        return res;
 }
 
-static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
-                                    const snd_mixer_elem_t *c2)
-{
-       int d = c1->compare_weight - c2->compare_weight;
-       if (d)
-               return d;
-       assert(c1->class && c1->class->compare);
-       assert(c2->class && c2->class->compare);
-       assert(c1->class == c2->class);
-       return c1->class->compare(c1, c2);
-}
-
-static int mixer_compare(const void *a, const void *b)
+static int amixer_compare(const void *a, const void *b)
 {
-       snd_mixer_t *mixer;
+       snd_amixer_t *amixer;
 
-       mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer;
-       return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b);
+       amixer = (*((const snd_amixer_elem_t * const *)a))->amixer;
+       return amixer->compare(*(const snd_amixer_elem_t * const *)a, *(const snd_amixer_elem_t * const *)b);
 }
 
-static int snd_mixer_sort(snd_mixer_t *mixer)
+static int snd_amixer_sort(snd_amixer_t *amixer)
 {
        unsigned int k;
-       assert(mixer);
-       assert(mixer->compare);
-       INIT_LIST_HEAD(&mixer->elems);
-       qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare);
-       for (k = 0; k < mixer->count; k++)
-               list_add_tail(&mixer->pelems[k]->list, &mixer->elems);
+       assert(amixer);
+       assert(amixer->compare);
+       INIT_LIST_HEAD(&amixer->elems);
+       qsort(amixer->pelems, amixer->count, sizeof(snd_amixer_elem_t *), amixer_compare);
+       for (k = 0; k < amixer->count; k++)
+               list_add_tail(&amixer->pelems[k]->list, &amixer->elems);
        return 0;
 }
 
 /**
- * \brief Change mixer compare function and reorder elements
- * \param mixer Mixer handle
+ * \brief Change amixer compare function and reorder elements
+ * \param amixer Mixer handle
  * \param compare Element compare function
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare)
+int snd_amixer_set_compare(snd_amixer_t *amixer, snd_amixer_compare_t compare)
 {
-       snd_mixer_compare_t compare_old;
+       snd_amixer_compare_t compare_old;
        int err;
 
-       assert(mixer);
-       compare_old = mixer->compare;
-       mixer->compare = compare == NULL ? snd_mixer_compare_default : compare;
-       if ((err = snd_mixer_sort(mixer)) < 0) {
-               mixer->compare = compare_old;
+       assert(amixer);
+       compare_old = amixer->compare;
+       amixer->compare = compare == NULL ? snd_amixer_compare_default : compare;
+       if ((err = snd_amixer_sort(amixer)) < 0) {
+               amixer->compare = compare_old;
                return err;
        }
        return 0;
 }
 
 /**
- * \brief get count of poll descriptors for mixer handle
- * \param mixer Mixer handle
+ * \brief get count of poll descriptors for amixer handle
+ * \param amixer Mixer handle
  * \return count of poll descriptors
  */
-int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
+int snd_amixer_poll_descriptors_count(snd_amixer_t *amixer)
 {
-       struct list_head *pos;
-       unsigned int c = 0;
-       assert(mixer);
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               int n;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               n = snd_hctl_poll_descriptors_count(s->hctl);
+       assert(amixer);
+       int i, c = 0, n;
+       for (i = 0; i < SM_CTL_COUNT; i++) {
+               if (amixer->sm_open.ctl[i] == NULL)
+                       continue;
+               n = snd_ctl_poll_descriptors_count(amixer->sm_open.ctl[i]);
                if (n < 0)
                        return n;
                c += n;
@@ -700,46 +733,46 @@ int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
 
 /**
  * \brief get poll descriptors
- * \param mixer Mixer handle
+ * \param amixer Mixer handle
  * \param pfds array of poll descriptors
  * \param space space in the poll descriptor array
  * \return count of filled descriptors
  */
-int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
+int snd_amixer_poll_descriptors(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int space)
 {
-       struct list_head *pos;
-       unsigned int count = 0;
-       assert(mixer);
-       list_for_each(pos, &mixer->slaves) {
-               snd_mixer_slave_t *s;
-               int n;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               n = snd_hctl_poll_descriptors(s->hctl, pfds, space);
+       int i, count = 0, n;
+
+       assert(amixer);
+       for (i = 0; i < SM_CTL_COUNT; i++) {
+               if (amixer->sm_open.ctl[i] == NULL)
+                       continue;
+               n = snd_ctl_poll_descriptors(amixer->sm_open.ctl[i], pfds, space);
                if (n < 0)
                        return n;
-               if (space >= (unsigned int) n) {
+               if (space >= (unsigned int)n) {
                        count += n;
                        space -= n;
                        pfds += n;
-               } else
+               } else {
                        space = 0;
+               }
        }
        return count;
 }
 
 /**
  * \brief get returned events from poll descriptors
- * \param mixer Mixer handle
+ * \param amixer Mixer handle
  * \param pfds array of poll descriptors
  * \param nfds count of poll descriptors
  * \param revents returned events
  * \return zero if success, otherwise a negative error code
  */
-int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+int snd_amixer_poll_descriptors_revents(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
 {
        unsigned int idx;
        unsigned short res;
-        assert(mixer && pfds && revents);
+        assert(amixer && pfds && revents);
        if (nfds == 0)
                return -EINVAL;
        res = 0;
@@ -750,25 +783,25 @@ int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds,
 }
 
 /**
- * \brief Wait for a mixer to become ready (i.e. at least one event pending)
- * \param mixer Mixer handle
+ * \brief Wait for a amixer to become ready (i.e. at least one event pending)
+ * \param amixer Mixer handle
  * \param timeout maximum time in milliseconds to wait
  * \return 0 otherwise a negative error code on failure
  */
-int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
+int snd_amixer_wait(snd_amixer_t *amixer, int timeout)
 {
        struct pollfd spfds[16];
        struct pollfd *pfds = spfds;
        int err;
        int count;
-       count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
+       count = snd_amixer_poll_descriptors(amixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
        if (count < 0)
                return count;
        if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) {
                pfds = malloc(count * sizeof(*pfds));
                if (!pfds)
                        return -ENOMEM;
-               err = snd_mixer_poll_descriptors(mixer, pfds, 
+               err = snd_amixer_poll_descriptors(amixer, pfds, 
                                                 (unsigned int) count);
                assert(err == count);
        }
@@ -779,305 +812,181 @@ int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
 }
 
 /**
- * \brief get first element for a mixer
- * \param mixer Mixer handle
+ * \brief get first element for a amixer
+ * \param amixer Mixer handle
  * \return pointer to first element
  */
-snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer)
+snd_amixer_elem_t *snd_amixer_first_elem(snd_amixer_t *amixer)
 {
-       assert(mixer);
-       if (list_empty(&mixer->elems))
+       assert(amixer);
+       if (list_empty(&amixer->elems))
                return NULL;
-       return list_entry(mixer->elems.next, snd_mixer_elem_t, list);
+       return list_entry(amixer->elems.next, snd_amixer_elem_t, list);
 }
 
 /**
- * \brief get last element for a mixer
- * \param mixer Mixer handle
+ * \brief get last element for a amixer
+ * \param amixer Mixer handle
  * \return pointer to last element
  */
-snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer)
+snd_amixer_elem_t *snd_amixer_last_elem(snd_amixer_t *amixer)
 {
-       assert(mixer);
-       if (list_empty(&mixer->elems))
+       assert(amixer);
+       if (list_empty(&amixer->elems))
                return NULL;
-       return list_entry(mixer->elems.prev, snd_mixer_elem_t, list);
+       return list_entry(amixer->elems.prev, snd_amixer_elem_t, list);
 }
 
 /**
- * \brief get next mixer element
- * \param elem mixer element
+ * \brief get next amixer element
+ * \param elem amixer element
  * \return pointer to next element
  */
-snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem)
+snd_amixer_elem_t *snd_amixer_elem_next(snd_amixer_elem_t *elem)
 {
        assert(elem);
-       if (elem->list.next == &elem->class->mixer->elems)
+       if (elem->list.next == &elem->amixer->elems)
                return NULL;
-       return list_entry(elem->list.next, snd_mixer_elem_t, list);
+       return list_entry(elem->list.next, snd_amixer_elem_t, list);
 }
 
 /**
- * \brief get previous mixer element
- * \param elem mixer element
+ * \brief get previous amixer element
+ * \param elem amixer element
  * \return pointer to previous element
  */
-snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem)
+snd_amixer_elem_t *snd_amixer_elem_prev(snd_amixer_elem_t *elem)
 {
        assert(elem);
-       if (elem->list.prev == &elem->class->mixer->elems)
+       if (elem->list.prev == &elem->amixer->elems)
                return NULL;
-       return list_entry(elem->list.prev, snd_mixer_elem_t, list);
+       return list_entry(elem->list.prev, snd_amixer_elem_t, list);
 }
 
 /**
- * \brief Handle pending mixer events invoking callbacks
- * \param mixer Mixer handle
+ * \brief Handle pending amixer events invoking callbacks
+ * \param amixer Mixer handle
  * \return Number of events that occured on success, otherwise a negative error code on failure
  */
-int snd_mixer_handle_events(snd_mixer_t *mixer)
+int snd_amixer_handle_events(snd_amixer_t *amixer)
 {
-       struct list_head *pos;
-       assert(mixer);
-       mixer->events = 0;
-       list_for_each(pos, &mixer->slaves) {
-               int err;
-               snd_mixer_slave_t *s;
-               s = list_entry(pos, snd_mixer_slave_t, list);
-               err = snd_hctl_handle_events(s->hctl);
+       int err, i;
+
+       assert(amixer);
+       amixer->events = 0;
+       for (i = 0; i < SM_CTL_COUNT; i++) {
+               if (amixer->sm_open.ctl[i] == NULL)
+                       continue;
+               err = snd_ctl_handle_events(amixer->sm_open.ctl[i]);
                if (err < 0)
                        return err;
        }
-       return mixer->events;
+       return amixer->events;
 }
 
 /**
- * \brief Set callback function for a mixer
- * \param obj mixer handle
+ * \brief Set event callback function for a amixer
+ * \param obj amixer handle
  * \param val callback function
+ *
+ * This function is used in the mixer implementation. Use callback
+ * functions to watch events.
  */
-void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val)
+void snd_amixer_set_event(snd_amixer_t *obj, snd_amixer_event_t val)
 {
        assert(obj);
-       obj->callback = val;
-}
-
-/**
- * \brief Set callback private value for a mixer
- * \param mixer mixer handle
- * \param val callback private value
- */
-void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val)
-{
-       assert(mixer);
-       mixer->callback_private = val;
-}
-
-/**
- * \brief Get callback private value for a mixer
- * \param mixer mixer handle
- * \return callback private value
- */
-void * snd_mixer_get_callback_private(const snd_mixer_t *mixer)
-{
-       assert(mixer);
-       return mixer->callback_private;
-}
-
-/**
- * \brief Get elements count for a mixer
- * \param mixer mixer handle
- * \return elements count
- */
-unsigned int snd_mixer_get_count(const snd_mixer_t *mixer)
-{
-       assert(mixer);
-       return mixer->count;
+       obj->event = val;
 }
 
 /**
- * \brief Set callback function for a mixer element
- * \param mixer mixer element
+ * \brief Set callback function for a amixer
+ * \param obj amixer handle
  * \param val callback function
  */
-void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val)
-{
-       assert(mixer);
-       mixer->callback = val;
-}
-
-/**
- * \brief Set callback private value for a mixer element
- * \param mixer mixer element
- * \param val callback private value
- */
-void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val)
-{
-       assert(mixer);
-       mixer->callback_private = val;
-}
-
-/**
- * \brief Get callback private value for a mixer element
- * \param mixer mixer element
- * \return callback private value
- */
-void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer)
-{
-       assert(mixer);
-       return mixer->callback_private;
-}
-
-/**
- * \brief Get type for a mixer element
- * \param mixer mixer element
- * \return mixer element type
- */
-snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer)
-{
-       assert(mixer);
-       return mixer->type;
-}
-
-
-/**
- * \brief get size of #snd_mixer_class_t
- * \return size in bytes
- */
-size_t snd_mixer_class_sizeof()
-{
-       return sizeof(snd_mixer_class_t);
-}
-
-/**
- * \brief allocate an invalid #snd_mixer_class_t using standard malloc
- * \param ptr returned pointer
- * \return 0 on success otherwise negative error code
- */
-int snd_mixer_class_malloc(snd_mixer_class_t **ptr)
-{
-       assert(ptr);
-       *ptr = calloc(1, sizeof(snd_mixer_class_t));
-       if (!*ptr)
-               return -ENOMEM;
-       return 0;
-}
-
-/**
- * \brief frees a previously allocated #snd_mixer_class_t
- * \param obj pointer to object to free
- */
-void snd_mixer_class_free(snd_mixer_class_t *obj)
-{
-       if (obj->private_free)
-               obj->private_free(obj);
-       free(obj);
-}
-
-/**
- * \brief copy one #snd_mixer_class_t to another
- * \param dst pointer to destination
- * \param src pointer to source
- */
-void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src)
-{
-       assert(dst && src);
-       *dst = *src;
-}
-
-/**
- * \brief Get a mixer associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return mixer pointer
- */
-snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj)
+void snd_amixer_set_callback(snd_amixer_t *obj, snd_amixer_callback_t val)
 {
        assert(obj);
-       return obj->mixer;
+       obj->callback = val;
 }
 
 /**
- * \brief Get mixer event callback associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Set callback private value for a amixer
+ * \param obj amixer handle
+ * \param val callback private value
  */
-snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj)
+void snd_amixer_set_callback_private(snd_amixer_t *obj, void * val)
 {
        assert(obj);
-       return obj->event;
+       obj->callback_private = val;
 }
 
 /**
- * \brief Get mixer private data associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Get callback private value for a amixer
+ * \param amixer amixer handle
+ * \return callback private value
  */
-void *snd_mixer_class_get_private(const snd_mixer_class_t *obj)
+void * snd_amixer_get_callback_private(const snd_amixer_t *amixer)
 {
-       assert(obj);
-       return obj->private_data;
+       assert(amixer);
+       return amixer->callback_private;
 }
 
-
 /**
- * \brief Get mixer compare callback associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Get elements count for a amixer
+ * \param amixer amixer handle
+ * \return elements count
  */
-snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj)
+unsigned int snd_amixer_get_count(const snd_amixer_t *amixer)
 {
-       assert(obj);
-       return obj->compare;
+       assert(amixer);
+       return amixer->count;
 }
 
 /**
- * \brief Set mixer event callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param event Event callback
- * \return zero if success, otherwise a negative error code
+ * \brief Set callback function for a amixer element
+ * \param amixer amixer element
+ * \param val callback function
  */
-int snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event)
+void snd_amixer_elem_set_callback(snd_amixer_elem_t *amixer, snd_amixer_elem_callback_t val)
 {
-       assert(obj);
-       obj->event = event;
-       return 0;
+       assert(amixer);
+       amixer->callback = val;
 }
 
 /**
- * \brief Set mixer private data to given mixer class
- * \param obj Mixer simple class identifier
- * \param private_data class private data
- * \return zero if success, otherwise a negative error code
+ * \brief Set callback private value for a amixer element
+ * \param amixer amixer element
+ * \param val callback private value
  */
-int snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data)
+void snd_amixer_elem_set_callback_private(snd_amixer_elem_t *amixer, void * val)
 {
-       assert(obj);
-       obj->private_data = private_data;
-       return 0;
+       assert(amixer);
+       amixer->callback_private = val;
 }
 
 /**
- * \brief Set mixer private data free callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param private_free Mixer class private data free callback
- * \return zero if success, otherwise a negative error code
+ * \brief Get callback private value for a amixer element
+ * \param amixer amixer element
+ * \return callback private value
  */
-int snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *class))
+void * snd_amixer_elem_get_callback_private(const snd_amixer_elem_t *amixer)
 {
-       assert(obj);
-       obj->private_free = private_free;
-       return 0;
+       assert(amixer);
+       return amixer->callback_private;
 }
 
 /**
- * \brief Set mixer compare callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param compare the compare callback to be used
- * \return zero if success, otherwise a negative error code
+ * \brief Check if ID is generic
+ * \param id string
+ * \return 1 if success, otherwise 0
  */
-int snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare)
+int snd_amixer_conf_generic_id(const char *id)
 {
-       assert(obj);
-       obj->compare = compare;
+       static const char ids[3][8] = { "comment", "type", "hint" };
+       unsigned int k;
+       for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) {
+               if (strcmp(id, ids[k]) == 0)
+                       return 1;
+       }
        return 0;
 }
index 27b4a3b1a0e09b17c226622c4c2e7bb12bf05d67..cf68ffe38d2e399a1c84e70faf31a9df5a543479 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "local.h"
+#include "mixer_abst.h"
 
 typedef struct _bag1 {
        void *ptr;
@@ -42,41 +43,40 @@ typedef struct list_head *bag_iterator_t;
 #define bag_for_each(pos, bag) list_for_each(pos, bag)
 #define bag_for_each_safe(pos, next, bag) list_for_each_safe(pos, next, bag)
 
-struct _snd_mixer_class {
-       struct list_head list;
-       snd_mixer_t *mixer;
-       snd_mixer_event_t event;
-       void *private_data;             
-       void (*private_free)(snd_mixer_class_t *class);
-       snd_mixer_compare_t compare;
-};
-
-struct _snd_mixer_elem {
-       snd_mixer_elem_type_t type;
+struct _snd_amixer_elem {
        struct list_head list;          /* links for list of all elems */
-       snd_mixer_class_t *class;
+       snd_amixer_t *amixer;
+       snd_ctl_t *ctl;
        void *private_data;
-       void (*private_free)(snd_mixer_elem_t *elem);
-       snd_mixer_elem_callback_t callback;
+       void (*private_free)(snd_amixer_elem_t *elem);
+       snd_amixer_elem_callback_t callback;
        void *callback_private;
        bag_t helems;
        int compare_weight;             /* compare weight (reversed) */
+       sm_elem_t sm;
 };
 
-struct _snd_mixer {
-       struct list_head slaves;        /* list of all slaves */
-       struct list_head classes;       /* list of all elem classes */
-       struct list_head elems;         /* list of all elems */
-       snd_mixer_elem_t **pelems;      /* array of all elems */
+struct _snd_amixer {
+       struct sm_open sm_open;
+       struct list_head elems;           /* list of all elems */
+       snd_amixer_elem_t **pelems;       /* array of all elems */
        unsigned int count;
        unsigned int alloc;
        unsigned int events;
-       snd_mixer_callback_t callback;
+       snd_amixer_callback_t callback;
        void *callback_private;
-       snd_mixer_compare_t compare;
+       snd_amixer_compare_t compare;
+       snd_amixer_event_t event;
+       void *dl_handle;
 };
 
-struct _snd_mixer_selem_id {
-       char name[60];
-       unsigned int index;
-};
+/* make local functions really local */
+#define snd_amixer_simple_none_open \
+       snd1_amixer_simple_none_open
+#define snd_amixer_simple_basic_open \
+       snd1_amixer_simple_basic_open
+
+int snd_amixer_simple_none_open(snd_amixer_t *amixer,
+                               struct sm_open *sm_open);
+int snd_amixer_simple_basic_open(snd_amixer_t *amixer,
+                                struct sm_open *sm_open);
diff --git a/src/mixer/mixer_old.c b/src/mixer/mixer_old.c
new file mode 100644 (file)
index 0000000..37da864
--- /dev/null
@@ -0,0 +1,375 @@
+/**
+ * \file mixer/mixer.c
+ * \brief Mixer Interface
+ * \author Jaroslav Kysela <perex@perex.cz>
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \date 2001
+ *
+ * Old (v1) mixer interface is designed to access mixer elements.
+ * Callbacks may be used for event handling.
+ */
+/*
+ *  Mixer Interface - main file
+ *  Copyright (c) 1998/1999/2000 by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/*! \page mixer Mixer interface
+
+<P>Mixer interface is designed to access the abstracted mixer controls.
+This is an abstraction layer over the hcontrol layer.
+
+\section mixer_general_overview General overview
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "mixer_old_local.h"
+
+/**
+ * \brief Opens an empty mixer
+ * \param mixerp Returned mixer handle
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED)
+{
+       snd_mixer_t *mixer;
+       assert(mixerp);
+       mixer = calloc(1, sizeof(*mixer));
+       if (mixer == NULL)
+               return -ENOMEM;
+       *mixerp = mixer;
+       return 0;
+}
+
+/**
+ * \brief Attach a HCTL to midxer
+ * \param mixer Mixer handle
+ * \param name the HCTL device name
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_attach(snd_mixer_t *mixer, const char *name)
+{
+       assert(mixer);
+       assert(name);
+       if (mixer->amixer)
+               return -EBUSY;
+       return snd_amixer_open(&mixer->amixer, name, NULL, NULL, SND_AMIXER_COMPAT1);
+}
+
+/**
+ * \brief Attach an HCTL to an opened mixer
+ * \param mixer Mixer handle
+ * \param hctl the HCTL to be attached
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
+{
+       return -ENXIO;
+}
+
+/**
+ * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
+ * \param mixer Mixer handle
+ * \param name HCTL previously attached
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_detach(snd_mixer_t *mixer, const char *name)
+{
+       return -ENXIO;
+}
+
+/**
+ * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
+ * \param mixer Mixer handle
+ * \param hctl HCTL previously attached
+ * \return 0 on success otherwise a negative error code
+ *
+ * Note: The hctl handle is not closed!
+ */
+int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
+{
+       return -ENXIO;
+}
+
+/**
+ * \brief Obtain a HCTL pointer associated to given name
+ * \param mixer Mixer handle
+ * \param name HCTL previously attached
+ * \param hctl HCTL pointer
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl)
+{
+       return -ENXIO;
+}
+
+/**
+ * \brief Get private data associated to give mixer element
+ * \param elem Mixer element
+ * \return private data
+ *
+ * For use by mixer element class specific code.
+ */
+void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_private(elem);
+}
+
+/**
+ * \brief Load a mixer elements
+ * \param mixer Mixer handle
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_load(snd_mixer_t *mixer)
+{
+       return 0;
+}
+
+/**
+ * \brief Unload all mixer elements and free all related resources
+ * \param mixer Mixer handle
+ */
+void snd_mixer_free(snd_mixer_t *mixer)
+{
+}
+
+/**
+ * \brief Close a mixer and free all related resources
+ * \param mixer Mixer handle
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_close(snd_mixer_t *mixer)
+{
+       int res;
+       
+       if (mixer->amixer)
+               res = snd_amixer_close(mixer->amixer);
+       free(mixer);
+       return 0;
+}
+
+/**
+ * \brief Change mixer compare function and reorder elements
+ * \param mixer Mixer handle
+ * \param compare Element compare function
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare)
+{
+       return snd_amixer_set_compare(mixer->amixer, compare);
+}
+
+/**
+ * \brief get count of poll descriptors for mixer handle
+ * \param mixer Mixer handle
+ * \return count of poll descriptors
+ */
+int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
+{
+       return snd_amixer_poll_descriptors_count(mixer->amixer);
+}
+
+/**
+ * \brief get poll descriptors
+ * \param mixer Mixer handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \return count of filled descriptors
+ */
+int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
+{
+       return snd_amixer_poll_descriptors(mixer->amixer, pfds, space);
+}
+
+/**
+ * \brief get returned events from poll descriptors
+ * \param mixer Mixer handle
+ * \param pfds array of poll descriptors
+ * \param nfds count of poll descriptors
+ * \param revents returned events
+ * \return zero if success, otherwise a negative error code
+ */
+int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+{
+       return snd_amixer_poll_descriptors_revents(mixer->amixer, pfds, nfds, revents);
+}
+
+/**
+ * \brief Wait for a mixer to become ready (i.e. at least one event pending)
+ * \param mixer Mixer handle
+ * \param timeout maximum time in milliseconds to wait
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
+{
+       return snd_amixer_wait(mixer->amixer, timeout);
+}
+
+/**
+ * \brief get first element for a mixer
+ * \param mixer Mixer handle
+ * \return pointer to first element
+ */
+snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer)
+{
+       return snd_amixer_first_elem(mixer->amixer);
+}
+
+/**
+ * \brief get last element for a mixer
+ * \param mixer Mixer handle
+ * \return pointer to last element
+ */
+snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer)
+{
+       return snd_amixer_last_elem(mixer->amixer);
+}
+
+/**
+ * \brief get next mixer element
+ * \param elem mixer element
+ * \return pointer to next element
+ */
+snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_next(elem);
+}
+
+/**
+ * \brief get previous mixer element
+ * \param elem mixer element
+ * \return pointer to previous element
+ */
+snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_prev(elem);
+}
+
+/**
+ * \brief Handle pending mixer events invoking callbacks
+ * \param mixer Mixer handle
+ * \return Number of events that occured on success, otherwise a negative error code on failure
+ */
+int snd_mixer_handle_events(snd_mixer_t *mixer)
+{
+       return snd_amixer_handle_events(mixer->amixer);
+}
+
+static int snd_mixer_default_callback(snd_amixer_t *mixer,
+                                     unsigned int mask,
+                                     snd_mixer_elem_t *elem)
+{
+       snd_mixer_t *old = snd_amixer_get_callback_private(mixer);
+       return old->callback(old, mask, elem);
+}
+
+/**
+ * \brief Set callback function for a mixer
+ * \param obj mixer handle
+ * \param val callback function
+ */
+void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val)
+{
+       assert(obj);
+       obj->callback = val;
+       snd_amixer_set_callback(obj->amixer, snd_mixer_default_callback);
+       snd_amixer_set_callback_private(obj->amixer, obj);
+}
+
+/**
+ * \brief Set callback private value for a mixer
+ * \param mixer mixer handle
+ * \param val callback private value
+ */
+void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val)
+{
+       assert(mixer);
+       mixer->callback_private = val;
+}
+
+/**
+ * \brief Get callback private value for a mixer
+ * \param mixer mixer handle
+ * \return callback private value
+ */
+void * snd_mixer_get_callback_private(const snd_mixer_t *mixer)
+{
+       assert(mixer);
+       return mixer->callback_private;
+}
+
+/**
+ * \brief Get elements count for a mixer
+ * \param mixer mixer handle
+ * \return elements count
+ */
+unsigned int snd_mixer_get_count(const snd_mixer_t *mixer)
+{
+       return snd_amixer_get_count(mixer->amixer);
+}
+
+/**
+ * \brief Set callback function for a mixer element
+ * \param mixer mixer element
+ * \param val callback function
+ */
+void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val)
+{
+       return snd_amixer_elem_set_callback(mixer, val);
+}
+
+/**
+ * \brief Set callback private value for a mixer element
+ * \param elem mixer element
+ * \param val callback private value
+ */
+void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *elem, void * val)
+{
+       return snd_amixer_elem_set_callback_private(elem, val);
+}
+
+/**
+ * \brief Get callback private value for a mixer element
+ * \param elem mixer element
+ * \return callback private value
+ */
+void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_callback_private(elem);
+}
+
+/**
+ * \brief Get type for a mixer element
+ * \param mixer mixer element
+ * \return mixer element type
+ */
+snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer)
+{
+       assert(mixer);
+       return SND_MIXER_ELEM_SIMPLE;
+}
+
+
similarity index 57%
rename from src/mixer/mixer_simple.h
rename to src/mixer/mixer_old_local.h
index e88b00710cd2e2f065c8099e73acb9252b289307..16d10c059aa8467c86087b46626bd55f7777ceab 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *  Mixer Simple Interface - local header file
- *  Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
+ *  Mixer Interface - local header file
+ *  Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
  *
  *
  *   This library is free software; you can redistribute it and/or modify
  *
  */
 
-#include "mixer_abst.h"
+#include "local.h"
+#include "mixer_old.h"
 
-/* make local functions really local */
-#define snd_mixer_simple_none_register \
-       snd1_mixer_simple_none_register
-#define snd_mixer_simple_basic_register \
-       snd1_mixer_simple_basic_register
-
-int snd_mixer_simple_none_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp);
-int snd_mixer_simple_basic_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp);
+struct _snd_mixer {
+        snd_amixer_t *amixer;
+        snd_mixer_callback_t callback;
+        void *callback_private;
+};
diff --git a/src/mixer/mixer_symbols.c b/src/mixer/mixer_symbols.c
new file mode 100644 (file)
index 0000000..29af4c0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Mixer Symbols
+ *  Copyright (c) 2009 by Jaroslav Kysela <perex@perex.cz>
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef PIC
+
+#include "config.h"
+
+extern const char *_snd_module_mixer_none;
+
+static const char **snd_pcm_open_objects[] = {
+       &_snd_module_mixer_none,
+};
+       
+void *snd_mixer_open_symbols(void)
+{
+       return snd_mixer_open_objects;
+}
+
+#endif /* !PIC */
index 39790b2e05cbbbebaa8558816ec20b98f2fa70db..8cbe484d99059318433d0dfe1ffbf8e8bb1873a2 100644 (file)
@@ -3,7 +3,7 @@
  * \brief Mixer Simple Element Class Interface
  * \author Jaroslav Kysela <perex@perex.cz>
  * \author Abramo Bagnara <abramo@alsa-project.org>
- * \date 2001-2004
+ * \date 2001-2008
  *
  * Mixer simple element class interface.
  */
 #include <sys/ioctl.h>
 #include <math.h>
 #include "mixer_local.h"
-#include "mixer_simple.h"
-
-/**
- * \brief Register mixer simple element class
- * \param mixer Mixer handle
- * \param options Options container
- * \param classp Pointer to returned mixer simple element class handle (or NULL)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_register(snd_mixer_t *mixer,
-                            struct snd_mixer_selem_regopt *options,
-                            snd_mixer_class_t **classp)
-{
-       if (options && options->ver == 1) {
-               if (options->device != NULL &&
-                   (options->playback_pcm != NULL ||
-                    options->capture_pcm != NULL))
-                       return -EINVAL;
-               if (options->device == NULL &&
-                   options->playback_pcm == NULL &&
-                   options->capture_pcm == NULL)
-                       return -EINVAL;
-       }
-       if (options == NULL ||
-           (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) {
-               int err = snd_mixer_simple_none_register(mixer, options, classp);
-               if (err < 0)
-                       return err;
-               if (options != NULL) {
-                       err = snd_mixer_attach(mixer, options->device);
-                       if (err < 0)
-                               return err;
-               }
-               return 0;
-       } else if (options->ver == 1) {
-               if (options->abstract == SND_MIXER_SABSTRACT_BASIC)
-                       return snd_mixer_simple_basic_register(mixer, options, classp);
-       }
-       return -ENXIO;
-}
 
 #ifndef DOC_HIDDEN
 
-#define CHECK_BASIC(xelem) \
-{ \
-       assert(xelem); \
-       assert((xelem)->type == SND_MIXER_ELEM_SIMPLE); \
-}
-
-#define CHECK_DIR(xelem, xwhat) \
-{ \
-       unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \
-       if (! (xcaps & (xwhat))) \
-               return -EINVAL; \
-}
-
-#define CHECK_DIR_CHN(xelem, xwhat, xjoin, xchannel) \
-{ \
-       unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \
-       if (! (xcaps & (xwhat))) \
-               return -EINVAL; \
-       if (xcaps & (xjoin)) \
-               xchannel = 0; \
-}
-
 #define CHECK_ENUM(xelem) \
-       if (!((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM)) \
+       if (!(elem->sm.caps & (SM_CAP_PENUM|SM_CAP_CENUM))) \
                return -EINVAL;
 
 #define COND_CAPS(xelem, what) \
-       !!(((sm_selem_t *)(elem)->private_data)->caps & (what))
+       !!(elem->sm.caps & (what))
+
+#define sm_elem(x)              (&(x)->sm)
+#define sm_elem_ops(x)          ((x)->sm.ops)
 
 #endif /* !DOC_HIDDEN */
 
 #ifndef DOC_HIDDEN
-int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
+int snd_amixer_compare_default(const snd_amixer_elem_t *c1, const snd_amixer_elem_t *c2)
 {
-       sm_selem_t *s1 = c1->private_data;
-       sm_selem_t *s2 = c2->private_data;
-       int res = strcmp(s1->id->name, s2->id->name);
-       if (res)
-               return res;
-       return s1->id->index - s2->id->index;
+       int d;
+       
+       d = c1->compare_weight - c2->compare_weight;
+       if (d)
+               return d;
+       d = strcmp(c1->sm.id.name, c2->sm.id.name);
+       if (d)
+               return d;
+       return c1->sm.id.index - c2->sm.id.index;
 }
 #endif
        
@@ -129,19 +73,15 @@ int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *
  * \param id Mixer simple element identifier
  * \return mixer simple element handle or NULL if not found
  */
-snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
-                                      const snd_mixer_selem_id_t *id)
+snd_amixer_elem_t *snd_amixer_find_elem(snd_amixer_t *mixer,
+                                      const snd_amixer_elem_id_t *id)
 {
        struct list_head *list;
-       snd_mixer_elem_t *e;
-       sm_selem_t *s;
+       snd_amixer_elem_t *e;
 
        list_for_each(list, &mixer->elems) {
-               e = list_entry(list, snd_mixer_elem_t, list);
-               if (e->type != SND_MIXER_ELEM_SIMPLE)
-                       continue;
-               s = e->private_data;
-               if (!strcmp(s->id->name, id->name) && s->id->index == id->index)
+               e = list_entry(list, snd_amixer_elem_t, list);
+               if (!strcmp(e->sm.id.name, id->name) && e->sm.id.index == id->index)
                        return e;
        }
        return NULL;
@@ -152,14 +92,11 @@ snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
  * \param elem Mixer simple element handle
  * \param id returned mixer simple element identifier
  */
-void snd_mixer_selem_get_id(snd_mixer_elem_t *elem,
-                           snd_mixer_selem_id_t *id)
+void snd_amixer_elem_get_id(snd_amixer_elem_t *elem,
+                           snd_amixer_elem_id_t *id)
 {
-       sm_selem_t *s;
        assert(id);
-       CHECK_BASIC(elem);
-       s = elem->private_data;
-       *id = *s->id;
+       *id = elem->sm.id;
 }
 
 /**
@@ -167,12 +104,9 @@ void snd_mixer_selem_get_id(snd_mixer_elem_t *elem,
  * \param elem Mixer simple element handle
  * \return name part of simple element identifier
  */
-const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
+const char *snd_amixer_elem_get_name(snd_amixer_elem_t *elem)
 {
-       sm_selem_t *s;
-       CHECK_BASIC(elem);
-       s = elem->private_data;
-       return s->id->name;
+       return elem->sm.id.name;
 }
 
 /**
@@ -180,34 +114,73 @@ const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
  * \param elem Mixer simple element handle
  * \return index part of simple element identifier
  */
-unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem)
+unsigned int snd_amixer_elem_get_index(snd_amixer_elem_t *elem)
 {
-       sm_selem_t *s;
-       CHECK_BASIC(elem);
-       s = elem->private_data;
-       return s->id->index;
+       return elem->sm.id.index;
 }
 
 /**
- * \brief Return true if mixer simple element has only one volume control for both playback and capture
+ * \brief Return true if mixer simple element has control for specified direction
  * \param elem Mixer simple element handle
- * \return 0 separated control, 1 common control
+ * \param dir Mixer direction
+ * \return 0 false, 1 true
  */
-int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem)
+int snd_amixer_elem_has_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_GVOLUME);
+       if (dir == SM_COMM)
+               return COND_CAPS(elem, SM_CAP_GVOLUME);
+       if (dir == SM_PLAY)
+               return COND_CAPS(elem, SM_CAP_PVOLUME);
+       if (dir == SM_CAPT)
+               return COND_CAPS(elem, SM_CAP_CVOLUME);
+       return 0;
 }
 
 /**
- * \brief Return true if mixer simple element has only one switch control for both playback and capture
+ * \brief Return info about volume control of a mixer simple element
  * \param elem Mixer simple element handle
- * \return 0 separated control, 1 common control
+ * \param dir Mixer direction
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
  */
-int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem)
+int snd_amixer_elem_has_volume_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_GSWITCH);
+       if (dir == SM_PLAY)
+               return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN);
+       if (dir == SM_CAPT)
+               return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN);
+       return 0;
+}
+
+/**
+ * \brief Return true if mixer simple element has control for specified direction
+ * \param elem Mixer simple element handle
+ * \param dir Mixer direction
+ * \return 0 false, 1 true
+ */
+int snd_amixer_elem_has_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
+{
+       if (dir == SM_COMM)
+               return COND_CAPS(elem, SM_CAP_GSWITCH);
+       if (dir == SM_PLAY)
+               return COND_CAPS(elem, SM_CAP_PSWITCH);
+       if (dir == SM_CAPT)
+               return COND_CAPS(elem, SM_CAP_CSWITCH);
+       return 0;
+}
+
+/**
+ * \brief Return info about switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param dir Mixer direction
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int snd_amixer_elem_has_switch_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
+{
+       if (dir == SM_PLAY)
+               return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN);
+       if (dir == SM_CAPT)
+               return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN);
+       return 0;
 }
 
 /**
@@ -215,7 +188,7 @@ int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem)
  * \param channel mixer simple element channel identifier
  * \return channel name
  */
-const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel)
+const char *snd_amixer_elem_channel_name(snd_amixer_elem_channel_id_t channel)
 {
        static const char *const array[SND_MIXER_SCHN_LAST + 1] = {
                [SND_MIXER_SCHN_FRONT_LEFT] = "Front Left",
@@ -241,270 +214,262 @@ const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel)
  * \param elem Mixer simple element handle
  * \return 0 if not active, 1 if active
  */
-int snd_mixer_selem_is_active(snd_mixer_elem_t *elem)
+int snd_amixer_elem_is_active(snd_amixer_elem_t *elem)
 {
-       CHECK_BASIC(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0);
+       return sm_elem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0);
 }
 
 /**
- * \brief Get info about channels of playback stream of a mixer simple element
+ * \brief Get info about channels of a mixer simple element
  * \param elem Mixer simple element handle
- * \return 0 if not mono, 1 if mono
+ * \param dir Mixer direction
+ * \param channel Mixer simple element channel identifier
+ * \return 0 if channel is not present, 1 if present
  */
-int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem)
+int snd_amixer_elem_has_channel(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel)
 {
-       CHECK_BASIC(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_MONO, 0);
+       return sm_elem_ops(elem)->is(elem, dir, SM_OPS_IS_CHANNEL, (int)channel);
 }
 
 /**
- * \brief Get info about channels of playback stream of a mixer simple element
+ * \brief Get count of valid channels
  * \param elem Mixer simple element handle
- * \param channel Mixer simple element channel identifier
- * \return 0 if channel is not present, 1 if present
+ * \param dir Mixer direction
+ * \return 1 or more
  */
-int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
+int snd_amixer_elem_get_channels(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       CHECK_BASIC(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel);
+       return sm_elem_ops(elem)->get_channels(elem, dir);
 }
 
 /**
- * \brief Get range for playback volume of a mixer simple element
+ * \brief Get range for volume of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param min Pointer to returned minimum
  * \param max Pointer to returned maximum
  */
-int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem,
-                                              long *min, long *max)
+int snd_amixer_elem_get_volume_range(snd_amixer_elem_t *elem,
+                                    snd_amixer_dir_t dir,
+                                    long *min, long *max)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_PVOLUME);
-       return sm_selem_ops(elem)->get_range(elem, SM_PLAY, min, max);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       return sm_elem_ops(elem)->get_range(elem, dir, min, max);
 }
 
 /**
- * \brief Get range in dB for playback volume of a mixer simple element
+ * \brief Get range in dB for volume of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param min Pointer to returned minimum (dB * 100)
  * \param max Pointer to returned maximum (dB * 100)
  */
-int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem,
-                                         long *min, long *max)
+int snd_amixer_elem_get_dB_range(snd_amixer_elem_t *elem,
+                                snd_amixer_dir_t dir,
+                                long *min, long *max)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_PVOLUME);
-       return sm_selem_ops(elem)->get_dB_range(elem, SM_PLAY, min, max);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       return sm_elem_ops(elem)->get_dB_range(elem, dir, min, max);
 }
 
 /**
- * \brief Set range for playback volume of a mixer simple element
+ * \brief Set range for volume of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param min minimum volume value
  * \param max maximum volume value
  */
-int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, 
-                                             long min, long max)
+int snd_amixer_elem_set_volume_range(snd_amixer_elem_t *elem,
+                                    snd_amixer_dir_t dir,
+                                    long min, long max)
 {
-       CHECK_BASIC(elem);
        assert(min < max);
-       CHECK_DIR(elem, SM_CAP_PVOLUME);
-       return sm_selem_ops(elem)->set_range(elem, SM_PLAY, min, max);
-}
-
-/**
- * \brief Return info about playback volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if no control is present, 1 if it's present
- */
-int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_PVOLUME);
-}
-
-/**
- * \brief Return info about playback volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if control is separated per channel, 1 if control acts on all channels together
- */
-int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN);
-}
-
-/**
- * \brief Return info about playback switch control existence of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if no control is present, 1 if it's present
- */
-int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_PSWITCH);
-}
-
-/**
- * \brief Return info about playback switch control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if control is separated per channel, 1 if control acts on all channels together
- */
-int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       return sm_elem_ops(elem)->set_range(elem, dir, min, max);
 }
 
 /**
- * \brief Return corresponding dB value to an integer playback volume for a mixer simple element
+ * \brief Return corresponding dB value to an integer volume for a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param value value to be converted to dB range
  * \param dBvalue pointer to returned dB value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
+int snd_amixer_elem_ask_vol_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                              long value, long *dBvalue)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_PVOLUME);
-       return sm_selem_ops(elem)->ask_vol_dB(elem, SM_PLAY, value, dBvalue);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       return sm_elem_ops(elem)->ask_vol_dB(elem, dir, value, dBvalue);
 }
 
 /**
- * \brief Return corresponding integer playback volume for given dB value for a mixer simple element
+ * \brief Return corresponding integer volume for given dB value for a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param value value to be converted to dB range
- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \param xdir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
  * \param dBvalue pointer to returned dB value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
+int snd_amixer_elem_ask_dB_vol(snd_amixer_elem_t *elem,
+                              snd_amixer_dir_t dir,
+                              long dBvalue, int xdir, long *value)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_PVOLUME);
-       return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       return sm_elem_ops(elem)->ask_dB_vol(elem, dir, dBvalue, value, xdir);
 }
 
 /**
  * \brief Return value of playback volume control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value pointer to returned value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+int snd_amixer_elem_get_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                              snd_amixer_elem_channel_id_t channel,
+                              long *value)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       if (snd_amixer_elem_has_volume_joined(elem, dir))
+               channel = 0;
+       return sm_elem_ops(elem)->get_volume(elem, dir, channel, value);
 }
 
 /**
- * \brief Return value of playback volume in dB control of a mixer simple element
+ * \brief Return value of volume in dB control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value pointer to returned value (dB * 100)
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+int snd_amixer_elem_get_dB(snd_amixer_elem_t *elem,
+                          snd_amixer_dir_t dir,
+                          snd_amixer_elem_channel_id_t channel, long *value)
 {
-       unsigned int caps;
-
-       CHECK_BASIC(elem);
-       caps = ((sm_selem_t *)elem->private_data)->caps;
-       if (!(caps & SM_CAP_PVOLUME))
+       if (!snd_amixer_elem_has_volume(elem, dir))
                return -EINVAL;
-       if (caps & SM_CAP_PVOLUME_JOIN)
+       if (snd_amixer_elem_has_volume_joined(elem, dir))
                channel = 0;
-       return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value);
+       return sm_elem_ops(elem)->get_dB(elem, dir, channel, value);
 }
 
 /**
  * \brief Return value of playback switch control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value pointer to returned value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
+int snd_amixer_elem_get_switch(snd_amixer_elem_t *elem, 
+                              snd_amixer_dir_t dir,
+                              snd_amixer_elem_channel_id_t channel,
+                              int *value)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
-       return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       if (snd_amixer_elem_has_volume_joined(elem, dir))
+               channel = 0;
+       return sm_elem_ops(elem)->get_switch(elem, dir, channel, value);
 }
 
 /**
- * \brief Set value of playback volume control of a mixer simple element
+ * \brief Set value of volume control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value control value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
+int snd_amixer_elem_set_volume(snd_amixer_elem_t *elem,
+                              snd_amixer_dir_t dir,
+                              snd_amixer_elem_channel_id_t channel,
+                              long value)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       if (snd_amixer_elem_has_volume_joined(elem, dir))
+               channel = 0;
+       return sm_elem_ops(elem)->set_volume(elem, dir, channel, value);
 }
 
 /**
  * \brief Set value in dB of playback volume control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value control value in dB * 100
  * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
+int snd_amixer_elem_set_dB(snd_amixer_elem_t *elem,
+                          snd_amixer_dir_t dir,
+                          snd_amixer_elem_channel_id_t channel,
+                          long value, int xdir)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir);
+       if (!snd_amixer_elem_has_volume(elem, dir))
+               return -EINVAL;
+       if (snd_amixer_elem_has_volume_joined(elem, dir))
+               channel = 0;
+       return sm_elem_ops(elem)->set_dB(elem, dir, channel, value, xdir);
 }
 
 /**
- * \brief Set value of playback volume control for all channels of a mixer simple element
+ * \brief Set value of volume control for all channels of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param value control value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value)
+int snd_amixer_elem_set_volume_all(snd_amixer_elem_t *elem,
+                                  snd_amixer_dir_t dir, long value)
 {
-       snd_mixer_selem_channel_id_t chn;
+       snd_amixer_elem_channel_id_t chn;
        int err;
 
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_playback_channel(elem, chn))
+       for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
+               if (!snd_amixer_elem_has_channel(elem, dir, chn))
                        continue;
-               err = snd_mixer_selem_set_playback_volume(elem, chn, value);
+               err = snd_amixer_elem_set_volume(elem, dir, chn, value);
                if (err < 0)
                        return err;
-               if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
+               if (chn == 0 && snd_amixer_elem_has_volume_joined(elem, dir))
                        return 0;
        }
        return 0;
 }
 
 /**
- * \brief Set value in dB of playback volume control for all channels of a mixer simple element
+ * \brief Set value in dB of volume control for all channels of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param value control value in dB * 100
  * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir)
+int snd_amixer_elem_set_dB_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                              long value, int xdir)
 {
-       snd_mixer_selem_channel_id_t chn;
+       snd_amixer_elem_channel_id_t chn;
        int err;
 
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_playback_channel(elem, chn))
+       for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
+               if (!snd_amixer_elem_has_channel(elem, dir, chn))
                        continue;
-               err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir);
+               err = snd_amixer_elem_set_dB(elem, dir, chn, value, xdir);
                if (err < 0)
                        return err;
-               if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
+               if (chn == 0 && snd_amixer_elem_has_volume_joined(elem, dir))
                        return 0;
        }
        return 0;
@@ -513,397 +478,91 @@ int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int
 /**
  * \brief Set value of playback switch control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param channel mixer simple element channel identifier
  * \param value control value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
+int snd_amixer_elem_set_switch(snd_amixer_elem_t *elem,
+                              snd_amixer_dir_t dir,
+                              snd_amixer_elem_channel_id_t channel,
+                              int value)
 {
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
-       return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value);
+       if (!snd_amixer_elem_has_switch(elem, dir))
+               return -EINVAL;
+       if (snd_amixer_elem_has_switch_joined(elem, dir))
+               channel = 0;
+       return sm_elem_ops(elem)->set_switch(elem, dir, channel, value);
 }
 
 /**
- * \brief Set value of playback switch control for all channels of a mixer simple element
+ * \brief Set value of switch control for all channels of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \param value control value
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value)
+int snd_amixer_elem_set_switch_all(snd_amixer_elem_t *elem,
+                                  snd_amixer_dir_t dir, int value)
 {
-       snd_mixer_selem_channel_id_t chn;
+       snd_amixer_elem_channel_id_t chn;
        int err;
 
-       CHECK_BASIC(elem);
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_playback_channel(elem, chn))
+       for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
+               if (!snd_amixer_elem_has_channel(elem, dir, chn))
                        continue;
-               err = snd_mixer_selem_set_playback_switch(elem, chn, value);
+               err = snd_amixer_elem_set_switch(elem, dir, chn, value);
                if (err < 0)
                        return err;
-               if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem))
+               if (chn == 0 && snd_amixer_elem_has_switch_joined(elem, dir))
                        return 0;
        }
        return 0;
 }
 
 /**
- * \brief Get info about channels of capture stream of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if not mono, 1 if mono
- */
-int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
-       return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0);
-}
-
-/**
- * \brief Get info about channels of capture stream of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel Mixer simple element channel identifier
- * \return 0 if channel is not present, 1 if present
- */
-int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
-       return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel);
-}
-
-/**
- * \brief Get range for capture volume of a mixer simple element
- * \param elem Mixer simple element handle
- * \param min Pointer to returned minimum
- * \param max Pointer to returned maximum
- */
-int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem,
-                                            long *min, long *max)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME);
-       return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max);
-}
-
-/**
- * \brief Get range in dB for capture volume of a mixer simple element
- * \param elem Mixer simple element handle
- * \param min Pointer to returned minimum (dB * 100)
- * \param max Pointer to returned maximum (dB * 100)
- */
-int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem,
-                                        long *min, long *max)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME);
-       return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max);
-}
-
-/**
- * \brief Set range for capture volume of a mixer simple element
- * \param elem Mixer simple element handle
- * \param min minimum volume value
- * \param max maximum volume value
- */
-int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, 
-                                            long min, long max)
-{
-       CHECK_BASIC(elem);
-       assert(min < max);
-       CHECK_DIR(elem, SM_CAP_CVOLUME);
-       return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max);
-}
-
-/**
- * \brief Return info about capture volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if no control is present, 1 if it's present
- */
-int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_CVOLUME);
-}
-
-/**
- * \brief Return info about capture volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if control is separated per channel, 1 if control acts on all channels together
- */
-int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN);
-}
-
-/**
- * \brief Return info about capture switch control existence of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if no control is present, 1 if it's present
- */
-int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_CSWITCH);
-}
-
-/**
- * \brief Return info about capture switch control of a mixer simple element
- * \param elem Mixer simple element handle
- * \return 0 if control is separated per channel, 1 if control acts on all channels together
- */
-int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN);
-}
-
-/**
- * \brief Return info about capture switch control of a mixer simple element
+ * \brief Return info about switch control of a mixer simple element
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction (should be capture for now)
  * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group)
  */
-int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem)
+int snd_amixer_elem_has_switch_exclusive(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       CHECK_BASIC(elem);
-       return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL);
+       if (dir == SM_CAPT)
+               return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL);
+       return 0;
 }
 
 /**
- * \brief Return info about capture switch control of a mixer simple element
+ * \brief Return info about switch control of a mixer simple element
  * \param elem Mixer simple element handle
- * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive)
+ * \param dir Mixer direction
+ * \return group for switch exclusivity (see #snd_amixer_elem_has_switch_exclusive)
  */
-int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem)
+int snd_amixer_elem_get_group(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       sm_selem_t *s;
-       CHECK_BASIC(elem);
-       s = elem->private_data;
+       sm_elem_t *s;
+       if (dir != SM_CAPT)
+               return -EINVAL;
+       s = sm_elem(elem);
        if (! (s->caps & SM_CAP_CSWITCH_EXCL))
                return -EINVAL;
        return s->capture_group;
 }
 
 /**
- * \brief Return corresponding dB value to an integer capture volume for a mixer simple element
- * \param elem Mixer simple element handle
- * \param value value to be converted to dB range
- * \param dBvalue pointer to returned dB value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME);
-       return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue);
-}
-
-/**
- * \brief Return corresponding integer capture volume for given dB value for a mixer simple element
- * \param elem Mixer simple element handle
- * \param dBvalue dB value to be converted to integer range
- * \param value pointer to returned integer value
- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR(elem, SM_CAP_CVOLUME);
-       return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir);
-}
-
-/**
- * \brief Return value of capture volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value pointer to returned value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value);
-}
-
-/**
- * \brief Return value of capture volume in dB control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value pointer to returned value (dB * 100)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value);
-}
-
-/**
- * \brief Return value of capture switch control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value pointer to returned value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
-       return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value);
-}
-
-/**
- * \brief Set value of capture volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value control value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value);
-}
-
-/**
- * \brief Set value in dB of capture volume control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value control value in dB * 100
- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
-       return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir);
-}
-
-/**
- * \brief Set value of capture volume control for all channels of a mixer simple element
- * \param elem Mixer simple element handle
- * \param value control value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value)
-{
-       snd_mixer_selem_channel_id_t chn;
-       int err;
-
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_capture_channel(elem, chn))
-                       continue;
-               err = snd_mixer_selem_set_capture_volume(elem, chn, value);
-               if (err < 0)
-                       return err;
-               if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
-                       return 0;
-       }
-       return 0;
-}
-
-/**
- * \brief Set value in dB of capture volume control for all channels of a mixer simple element
- * \param elem Mixer simple element handle
- * \param value control value in dB * 100
- * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir)
-{
-       snd_mixer_selem_channel_id_t chn;
-       int err;
-
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_capture_channel(elem, chn))
-                       continue;
-               err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir);
-               if (err < 0)
-                       return err;
-               if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
-                       return 0;
-       }
-       return 0;
-}
-
-/**
- * \brief Set value of capture switch control of a mixer simple element
- * \param elem Mixer simple element handle
- * \param channel mixer simple element channel identifier
- * \param value control value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
-{
-       CHECK_BASIC(elem);
-       CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
-       return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value);
-}
-
-/**
- * \brief Set value of capture switch control for all channels of a mixer simple element
- * \param elem Mixer simple element handle
- * \param value control value
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value)
-{
-       snd_mixer_selem_channel_id_t chn;
-       int err;
-
-       for (chn = 0; chn < 32; chn++) {
-               if (!snd_mixer_selem_has_capture_channel(elem, chn))
-                       continue;
-               err = snd_mixer_selem_set_capture_switch(elem, chn, value);
-               if (err < 0)
-                       return err;
-               if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem))
-                       return 0;
-       }
-       return 0;
-}
-
-/**
- * \brief Return true if mixer simple element is an enumerated control
- * \param elem Mixer simple element handle
- * \return 0 normal volume/switch control, 1 enumerated control
- */
-int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0);
-}
-
-/**
- * \brief Return true if mixer simple enumerated element belongs to the playback direction
+ * \brief Return true if mixer simple enumerated element belongs to the direction
  * \param elem Mixer simple element handle
+ * \param dir Mixer direction
  * \return 0 no playback direction, 1 playback direction
  */
-int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem)
+int snd_amixer_elem_is_enum(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
 {
-       CHECK_BASIC(elem);
-       CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1);
-}
+       int res;
 
-/**
- * \brief Return true if mixer simple enumerated element belongs to the capture direction
- * \param elem Mixer simple element handle
- * \return 0 no capture direction, 1 capture direction
- */
-int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem)
-{
-       CHECK_BASIC(elem);
-       CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1);
+       if (!(elem->sm.caps & (SM_CAP_PENUM|SM_CAP_CENUM)))
+               return 0;
+       return sm_elem_ops(elem)->is(elem, dir, SM_OPS_IS_ENUMERATED, 0);
 }
 
 /**
@@ -911,11 +570,10 @@ int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem)
  * \param elem Mixer simple element handle
  * \return the number of enumerated items, otherwise a negative error code
  */
-int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem)
+int snd_amixer_elem_get_enum_items(snd_amixer_elem_t *elem)
 {
-       CHECK_BASIC(elem);
        CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0);
+       return sm_elem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0);
 }
 
 /**
@@ -926,13 +584,12 @@ int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem)
  * \param buf the buffer to store the name string
  * \return 0 if successful, otherwise a negative error code
  */
-int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem,
+int snd_amixer_elem_get_enum_item_name(snd_amixer_elem_t *elem,
                                       unsigned int item,
                                       size_t maxlen, char *buf)
 {
-       CHECK_BASIC(elem);
        CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf);
+       return sm_elem_ops(elem)->enum_item_name(elem, item, maxlen, buf);
 }
 
 /**
@@ -942,13 +599,12 @@ int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem,
  * \param itemp the pointer to store the index of the enumerated item
  * \return 0 if successful, otherwise a negative error code
  */
-int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem,
-                                 snd_mixer_selem_channel_id_t channel,
+int snd_amixer_elem_get_enum_item(snd_amixer_elem_t *elem,
+                                 snd_amixer_elem_channel_id_t channel,
                                  unsigned int *itemp)
 {
-       CHECK_BASIC(elem);
        CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp);
+       return sm_elem_ops(elem)->get_enum_item(elem, channel, itemp);
 }
 
 /**
@@ -958,53 +614,52 @@ int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem,
  * \param item the enumerated item index
  * \return 0 if successful, otherwise a negative error code
  */
-int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem,
-                                 snd_mixer_selem_channel_id_t channel,
+int snd_amixer_elem_set_enum_item(snd_amixer_elem_t *elem,
+                                 snd_amixer_elem_channel_id_t channel,
                                  unsigned int item)
 {
-       CHECK_BASIC(elem);
        CHECK_ENUM(elem);
-       return sm_selem_ops(elem)->set_enum_item(elem, channel, item);
+       return sm_elem_ops(elem)->set_enum_item(elem, channel, item);
 }
 
 /**
- * \brief get size of #snd_mixer_selem_id_t
+ * \brief get size of #snd_amixer_elem_id_t
  * \return size in bytes
  */
-size_t snd_mixer_selem_id_sizeof()
+size_t snd_amixer_elem_id_sizeof()
 {
-       return sizeof(snd_mixer_selem_id_t);
+       return sizeof(snd_amixer_elem_id_t);
 }
 
 /**
- * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc
+ * \brief allocate an invalid #snd_amixer_elem_id_t using standard malloc
  * \param ptr returned pointer
  * \return 0 on success otherwise negative error code
  */
-int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
+int snd_amixer_elem_id_malloc(snd_amixer_elem_id_t **ptr)
 {
        assert(ptr);
-       *ptr = calloc(1, sizeof(snd_mixer_selem_id_t));
+       *ptr = calloc(1, sizeof(snd_amixer_elem_id_t));
        if (!*ptr)
                return -ENOMEM;
        return 0;
 }
 
 /**
- * \brief frees a previously allocated #snd_mixer_selem_id_t
+ * \brief frees a previously allocated #snd_amixer_elem_id_t
  * \param obj pointer to object to free
  */
-void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
+void snd_amixer_elem_id_free(snd_amixer_elem_id_t *obj)
 {
        free(obj);
 }
 
 /**
- * \brief copy one #snd_mixer_selem_id_t to another
+ * \brief copy one #snd_amixer_elem_id_t to another
  * \param dst pointer to destination
  * \param src pointer to source
  */
-void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src)
+void snd_amixer_elem_id_copy(snd_amixer_elem_id_t *dst, const snd_amixer_elem_id_t *src)
 {
        assert(dst && src);
        *dst = *src;
@@ -1015,7 +670,7 @@ void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id
  * \param obj Mixer simple element identifier
  * \return name part
  */
-const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj)
+const char *snd_amixer_elem_id_get_name(const snd_amixer_elem_id_t *obj)
 {
        assert(obj);
        return obj->name;
@@ -1026,7 +681,7 @@ const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj)
  * \param obj Mixer simple element identifier
  * \return index part
  */
-unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj)
+unsigned int snd_amixer_elem_id_get_index(const snd_amixer_elem_id_t *obj)
 {
        assert(obj);
        return obj->index;
@@ -1037,7 +692,7 @@ unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj)
  * \param obj Mixer simple element identifier
  * \param val name part
  */
-void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val)
+void snd_amixer_elem_id_set_name(snd_amixer_elem_id_t *obj, const char *val)
 {
        assert(obj);
        strncpy(obj->name, val, sizeof(obj->name));
@@ -1049,8 +704,20 @@ void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val)
  * \param obj Mixer simple element identifier
  * \param val index part
  */
-void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val)
+void snd_amixer_elem_id_set_index(snd_amixer_elem_id_t *obj, unsigned int val)
 {
        assert(obj);
        obj->index = val;
 }
+
+/**
+ * \brief Get simple mixer element abstraction structure
+ * \param obj Mixer simple element identifier
+ * \return sm_elem_t pointer
+ */
+sm_elem_t *snd_amixer_elem_get_sm(snd_amixer_elem_t *obj)
+{
+       assert(obj);
+       return &obj->sm;
+}
+
diff --git a/src/mixer/simple_abst.c b/src/mixer/simple_abst.c
deleted file mode 100644 (file)
index 9e9aaf5..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/**
- * \file mixer/simple_abst.c
- * \brief Mixer Simple Element Class Interface - Module Abstraction
- * \author Jaroslav Kysela <perex@perex.cz>
- * \date 2005
- *
- * Mixer simple element class interface.
- */
-/*
- *  Mixer Interface - simple controls - abstraction module
- *  Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This library is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as
- *   published by the Free Software Foundation; either version 2.1 of
- *   the License, or (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public
- *   License along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <math.h>
-#include <dlfcn.h>
-#include "config.h"
-#include "asoundlib.h"
-#include "mixer_simple.h"
-
-#ifndef DOC_HIDDEN
-
-#define SO_PATH ALSA_PLUGIN_DIR "/smixer"
-
-typedef struct _class_priv {
-       char *device;
-       snd_ctl_t *ctl;
-       snd_hctl_t *hctl;
-       int attach_flag;
-       snd_ctl_card_info_t *info;
-       void *dlhandle;
-       void *private_data;
-       void (*private_free)(snd_mixer_class_t *class);
-} class_priv_t;
-
-typedef int (*snd_mixer_sbasic_init_t)(snd_mixer_class_t *class);
-typedef int (*snd_mixer_sfbasic_init_t)(snd_mixer_class_t *class,
-                                       snd_mixer_t *mixer,
-                                       const char *device);
-
-#endif /* !DOC_HIDDEN */
-
-static int try_open(snd_mixer_class_t *class, const char *lib)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-       snd_mixer_event_t event_func;
-       snd_mixer_sbasic_init_t init_func = NULL;
-       char *xlib, *path;
-       void *h;
-       int err = 0;
-
-       path = getenv("ALSA_MIXER_SIMPLE_MODULES");
-       if (!path)
-               path = SO_PATH;
-       xlib = malloc(strlen(lib) + strlen(path) + 1 + 1);
-       if (xlib == NULL)
-               return -ENOMEM;
-       strcpy(xlib, path);
-       strcat(xlib, "/");
-       strcat(xlib, lib);
-       h = snd_dlopen(xlib, RTLD_NOW);
-       if (h == NULL) {
-               SNDERR("Unable to open library '%s'", xlib);
-               free(xlib);
-               return -ENXIO;
-       }
-       priv->dlhandle = h;
-       event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL);
-       if (event_func == NULL) {
-               SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib);
-               err = -ENXIO;
-       }
-       if (err == 0) {
-               init_func = snd_dlsym(h, "alsa_mixer_simple_init", NULL);
-               if (init_func == NULL) {
-                       SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib);
-                       err = -ENXIO;
-               }
-       }
-       free(xlib);
-       err = err == 0 ? init_func(class) : err;
-       if (err < 0)
-               return err;
-       snd_mixer_class_set_event(class, event_func);
-       return 1;
-}
-
-static int try_open_full(snd_mixer_class_t *class, snd_mixer_t *mixer,
-                        const char *lib, const char *device)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-       snd_mixer_event_t event_func;
-       snd_mixer_sfbasic_init_t init_func = NULL;
-       char *xlib, *path;
-       void *h;
-       int err = 0;
-
-       path = getenv("ALSA_MIXER_SIMPLE_MODULES");
-       if (!path)
-               path = SO_PATH;
-       xlib = malloc(strlen(lib) + strlen(path) + 1 + 1);
-       if (xlib == NULL)
-               return -ENOMEM;
-       strcpy(xlib, path);
-       strcat(xlib, "/");
-       strcat(xlib, lib);
-       /* note python modules requires RTLD_GLOBAL */
-       h = snd_dlopen(xlib, RTLD_NOW|RTLD_GLOBAL);
-       if (h == NULL) {
-               SNDERR("Unable to open library '%s'", xlib);
-               free(xlib);
-               return -ENXIO;
-       }
-       priv->dlhandle = h;
-       event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL);
-       if (event_func == NULL) {
-               SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib);
-               err = -ENXIO;
-       }
-       if (err == 0) {
-               init_func = snd_dlsym(h, "alsa_mixer_simple_finit", NULL);
-               if (init_func == NULL) {
-                       SNDERR("Symbol 'alsa_mixer_simple_finit' was not found in '%s'", xlib);
-                       err = -ENXIO;
-               }
-       }
-       free(xlib);
-       err = err == 0 ? init_func(class, mixer, device) : err;
-       if (err < 0)
-               return err;
-       snd_mixer_class_set_event(class, event_func);
-       return 1;
-}
-
-static int match(snd_mixer_class_t *class, const char *lib, const char *searchl)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-       const char *components;
-
-       if (searchl == NULL)
-               return try_open(class, lib);
-       components = snd_ctl_card_info_get_components(priv->info);
-       while (*components != '\0') {
-               if (!strncmp(components, searchl, strlen(searchl)))
-                       return try_open(class, lib);
-               while (*components != ' ' && *components != '\0')
-                       components++;
-               while (*components == ' ' && *components != '\0')
-                       components++;
-       }
-       return 0;
-}
-
-static int find_full(snd_mixer_class_t *class, snd_mixer_t *mixer,
-                    snd_config_t *top, const char *device)
-{
-       snd_config_iterator_t i, next;
-       char *lib;
-       const char *id;
-       int err;
-
-       snd_config_for_each(i, next, top) {
-               snd_config_t *n = snd_config_iterator_entry(i);
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-               if (strcmp(id, "_full"))
-                       continue;
-               err = snd_config_get_string(n, (const char **)&lib);
-               if (err < 0)
-                       return err;
-               err = try_open_full(class, mixer, lib, device);
-               if (err < 0)
-                       return err;
-               return 0;
-       }
-       return -ENOENT;
-}
-
-static int find_module(snd_mixer_class_t *class, snd_config_t *top)
-{
-       snd_config_iterator_t i, next;
-       snd_config_iterator_t j, jnext;
-       char *lib, *searchl;
-       const char *id;
-       int err;
-
-       snd_config_for_each(i, next, top) {
-               snd_config_t *n = snd_config_iterator_entry(i);
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-               if (*id == '_')
-                       continue;
-               searchl = NULL;
-               lib = NULL;
-               snd_config_for_each(j, jnext, n) {
-                       snd_config_t *m = snd_config_iterator_entry(j);
-                       if (snd_config_get_id(m, &id) < 0)
-                               continue;
-                       if (!strcmp(id, "searchl")) {
-                               err = snd_config_get_string(m, (const char **)&searchl);
-                               if (err < 0)
-                                       return err;
-                               continue;
-                       }
-                       if (!strcmp(id, "lib")) {
-                               err = snd_config_get_string(m, (const char **)&lib);
-                               if (err < 0)
-                                       return err;
-                               continue;
-                       }
-               }
-               err = match(class, lib, searchl);
-               if (err == 1)
-                       return 0;
-               if (err < 0)
-                       return err;
-       }
-       return -ENOENT;
-}
-
-static void private_free(snd_mixer_class_t *class)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-       
-       if (priv->private_free)
-               priv->private_free(class);
-       if (priv->dlhandle)
-               snd_dlclose(priv->dlhandle);
-       if (priv->info)
-               snd_ctl_card_info_free(priv->info);
-       if (priv->hctl) {
-               if (priv->attach_flag)
-                       snd_mixer_detach_hctl(snd_mixer_class_get_mixer(class), priv->hctl);
-               snd_hctl_close(priv->hctl);
-       } else if (priv->ctl)
-               snd_ctl_close(priv->ctl);
-       free(priv->device);
-       free(priv);
-}
-
-/**
- * \brief Register mixer simple element class - basic abstraction
- * \param mixer Mixer handle
- * \param options Options container
- * \param classp Pointer to returned mixer simple element class handle (or NULL
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_simple_basic_register(snd_mixer_t *mixer,
-                                   struct snd_mixer_selem_regopt *options,
-                                   snd_mixer_class_t **classp)
-{
-       snd_mixer_class_t *class;
-       class_priv_t *priv = calloc(1, sizeof(*priv));
-       const char *file;
-       snd_input_t *input;
-       snd_config_t *top = NULL;
-       int err;
-
-       if (priv == NULL)
-               return -ENOMEM;
-       if (options->device == NULL) {
-               free(priv);
-               return -EINVAL;
-       }
-       if (snd_mixer_class_malloc(&class)) {
-               free(priv);
-               return -ENOMEM;
-       }
-       priv->device = strdup(options->device);
-       if (priv->device == NULL) {
-               free(priv);
-               snd_mixer_class_free(class);
-               return -ENOMEM;
-       }
-       snd_mixer_class_set_compare(class, snd_mixer_selem_compare);
-       snd_mixer_class_set_private(class, priv);
-       snd_mixer_class_set_private_free(class, private_free);
-       file = getenv("ALSA_MIXER_SIMPLE");
-       if (!file)
-               file = ALSA_CONFIG_DIR "/smixer.conf";
-       err = snd_config_top(&top);
-       if (err >= 0) {
-               err = snd_input_stdio_open(&input, file, "r");
-               if (err < 0) {
-                       SNDERR("unable to open simple mixer configuration file '%s'", file);
-                       goto __error;
-               }
-               err = snd_config_load(top, input);
-               snd_input_close(input);
-               if (err < 0) {
-                       SNDERR("%s may be old or corrupted: consider to remove or fix it", file);
-                       goto __error;
-               }
-               err = find_full(class, mixer, top, priv->device);
-               if (err >= 0)
-                       goto __full;
-       }
-       if (err >= 0) {
-               err = snd_ctl_open(&priv->ctl, priv->device, 0);
-               if (err < 0) {
-                       SNDERR("unable to open control device '%s': %s", priv->device, snd_strerror(err));
-                       goto __error;
-               }
-               err = snd_hctl_open_ctl(&priv->hctl, priv->ctl);
-               if (err < 0)
-                       goto __error;
-               err = snd_ctl_card_info_malloc(&priv->info);
-               if (err < 0)
-                       goto __error;
-               err = snd_ctl_card_info(priv->ctl, priv->info);
-               if (err < 0)
-                       goto __error;
-       }
-       if (err >= 0)
-               err = find_module(class, top);
-       if (err >= 0)
-               err = snd_mixer_attach_hctl(mixer, priv->hctl);
-       if (err >= 0) {
-               priv->attach_flag = 1;
-               err = snd_mixer_class_register(class, mixer);
-       }
-      __full:
-       if (err < 0) {
-             __error:
-               if (top)
-                       snd_config_delete(top);
-               if (class)
-                       snd_mixer_class_free(class);
-               return err;
-       }
-       if (top)
-               snd_config_delete(top);
-       if (classp)
-               *classp = class;
-       return 0;
-}
-
-/**
- * \brief Basic Mixer Abstraction - Get information about device
- * \param class Mixer class
- * \param info Info structure
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-
-       if (class == NULL || info == NULL)
-               return -EINVAL;
-       info->device = priv->device;
-       info->ctl = priv->ctl;
-       info->hctl = priv->hctl;
-       info->info = priv->info;
-       return 0;
-}
-
-/**
- * \brief Get private data for basic abstraction
- * \param class Mixer class
- * \return private data
- */
-void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class)
-{
-       class_priv_t *priv = snd_mixer_class_get_private(class);
-
-       if (class == NULL)
-               return NULL;
-       return priv->private_data;
-}
-
-/**
- * \brief Set private data for basic abstraction
- * \param class Mixer class
- * \param private_data Private data
- */
-void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data)
-{
-       class_priv_t *priv;
-
-       if (class == NULL)
-               return;
-       priv = snd_mixer_class_get_private(class);
-       priv->private_data = private_data;
-}
-
-/**
- * \brief Set private data free callback for basic abstraction
- * \param class Mixer class
- * \param private_free free callback for private data
- */
-void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class))
-{
-       class_priv_t *priv;
-
-       if (class == NULL)
-               return;
-       priv = snd_mixer_class_get_private(class);
-       priv->private_free = private_free;
-}
index 480220041a4324fa277f913bca8dcfd1f87eff06..63442111c23970216b228554ac79f39616e17464 100644 (file)
@@ -5,7 +5,7 @@
  * \author Abramo Bagnara <abramo@alsa-project.org>
  * \date 2001-2004
  *
- * Mixer simple element class interface.
+ * Mixer simple element interface.
  */
 /*
  *  Mixer Interface - simple controls
 #include <math.h>
 #include <limits.h>
 #include <alsa/asoundlib.h>
-#include "mixer_simple.h"
+#include "mixer_abst.h"
+
+#ifndef PIC
+/* entry for static linking */
+const char *_snd_module_mixer_none = "";
+#endif
 
 #ifndef DOC_HIDDEN
 
@@ -66,7 +71,7 @@ typedef enum _selem_ctl_type {
 } selem_ctl_type_t;
 
 typedef struct _selem_ctl {
-       snd_hctl_elem_t *elem;
+       snd_ctl_elem_t *elem;
        snd_ctl_elem_type_t type;
        unsigned int inactive: 1;
        unsigned int values;
@@ -74,7 +79,6 @@ typedef struct _selem_ctl {
 } selem_ctl_t;
 
 typedef struct _selem_none {
-       sm_selem_t selem;
        selem_ctl_t ctls[CTL_LAST + 1];
        unsigned int capture_item;
        struct selem_str {
@@ -211,7 +215,7 @@ static int get_compare_weight(const char *name, unsigned int idx)
        return MIXER_COMPARE_WEIGHT_SIMPLE_BASE + res + idx;
 }
 
-static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
+static long to_user(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_t *c, long value)
 {
        int64_t n;
        if (c->max == c->min)
@@ -220,7 +224,7 @@ static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
        return s->str[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min);
 }
 
-static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
+static long from_user(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_t *c, long value)
 {
        int64_t n;
        if (s->str[dir].max == s->str[dir].min)
@@ -229,14 +233,15 @@ static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
        return c->min + (n + (s->str[dir].max - s->str[dir].min) / 2) / (s->str[dir].max - s->str[dir].min);
 }
 
-static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_read_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < s->str[dir].channels; idx++) {
                unsigned int idx1 = idx;
@@ -247,14 +252,15 @@ static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type)
        return 0;
 }
 
-static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_read_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < s->str[dir].channels; idx++) {
                unsigned int idx1 = idx;
@@ -266,14 +272,15 @@ static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type)
        return 0;
 }
 
-static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_read_route(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < s->str[dir].channels; idx++) {
                unsigned int idx1 = idx;
@@ -285,23 +292,25 @@ static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type)
        return 0;
 }
 
-static int elem_read_enum(selem_none_t *s)
+static int elem_read_enum(snd_amixer_elem_t *elem)
 {
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        int type;
        selem_ctl_t *c;
        type = CTL_GLOBAL_ENUM;
-       if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) )
+       if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) )
                type = CTL_GLOBAL_ENUM;
-       else if (s->selem.caps & SM_CAP_PENUM)
+       else if (sm->caps & SM_CAP_PENUM)
                type = CTL_PLAYBACK_ENUM;
-       else if (s->selem.caps & SM_CAP_CENUM)
+       else if (sm->caps & SM_CAP_CENUM)
                type = CTL_CAPTURE_ENUM;
        c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < s->str[0].channels; idx++) {
                unsigned int idx1 = idx;
@@ -312,17 +321,15 @@ static int elem_read_enum(selem_none_t *s)
        return 0;
 }
 
-static int selem_read(snd_mixer_elem_t *elem)
+static int selem_read(snd_amixer_elem_t *elem)
 {
-       selem_none_t *s;
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        unsigned int idx;
        int err = 0;
        long pvol[32], cvol[32];
        unsigned int psw, csw;
 
-       assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
-       s = snd_mixer_elem_get_private(elem);
-
        memcpy(pvol, s->str[SM_PLAY].vol, sizeof(pvol));
        memset(&s->str[SM_PLAY].vol, 0, sizeof(s->str[SM_PLAY].vol));
        psw = s->str[SM_PLAY].sw;
@@ -333,21 +340,21 @@ static int selem_read(snd_mixer_elem_t *elem)
        s->str[SM_CAPT].sw = ~0U;
 
        if (s->ctls[CTL_GLOBAL_ENUM].elem) {
-               err = elem_read_enum(s);
+               err = elem_read_enum(elem);
                if (err < 0)
                        return err;
                goto __skip_cswitch;
        }
 
        if (s->ctls[CTL_CAPTURE_ENUM].elem) {
-               err = elem_read_enum(s);
+               err = elem_read_enum(elem);
                if (err < 0)
                        return err;
                goto __skip_cswitch;
        }
 
        if (s->ctls[CTL_PLAYBACK_ENUM].elem) {
-               err = elem_read_enum(s);
+               err = elem_read_enum(elem);
                if (err < 0)
                        return err;
                goto __skip_cswitch;
@@ -355,84 +362,84 @@ static int selem_read(snd_mixer_elem_t *elem)
 
 
        if (s->ctls[CTL_PLAYBACK_VOLUME].elem)
-               err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME);
+               err = elem_read_volume(elem, SM_PLAY, CTL_PLAYBACK_VOLUME);
        else if (s->ctls[CTL_GLOBAL_VOLUME].elem)
-               err = elem_read_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME);
+               err = elem_read_volume(elem, SM_PLAY, CTL_GLOBAL_VOLUME);
        else if (s->ctls[CTL_SINGLE].elem &&
                 s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
-               err = elem_read_volume(s, SM_PLAY, CTL_SINGLE);
+               err = elem_read_volume(elem, SM_PLAY, CTL_SINGLE);
        if (err < 0)
                return err;
 
-       if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) {
+       if ((sm->caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) {
                s->str[SM_PLAY].sw = 0;
                goto __skip_pswitch;
        }
        if (s->ctls[CTL_PLAYBACK_SWITCH].elem) {
-               err = elem_read_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH);
+               err = elem_read_switch(elem, SM_PLAY, CTL_PLAYBACK_SWITCH);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_GLOBAL_SWITCH].elem) {
-               err = elem_read_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH);
+               err = elem_read_switch(elem, SM_PLAY, CTL_GLOBAL_SWITCH);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_SINGLE].elem &&
            s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) {
-               err = elem_read_switch(s, SM_PLAY, CTL_SINGLE);
+               err = elem_read_switch(elem, SM_PLAY, CTL_SINGLE);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_PLAYBACK_ROUTE].elem) {
-               err = elem_read_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE);
+               err = elem_read_route(elem, SM_PLAY, CTL_PLAYBACK_ROUTE);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_GLOBAL_ROUTE].elem) {
-               err = elem_read_route(s, SM_PLAY, CTL_GLOBAL_ROUTE);
+               err = elem_read_route(elem, SM_PLAY, CTL_GLOBAL_ROUTE);
                if (err < 0)
                        return err;
        }
       __skip_pswitch:
 
        if (s->ctls[CTL_CAPTURE_VOLUME].elem)
-               err = elem_read_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME);
+               err = elem_read_volume(elem, SM_CAPT, CTL_CAPTURE_VOLUME);
        else if (s->ctls[CTL_GLOBAL_VOLUME].elem)
-               err = elem_read_volume(s, SM_CAPT, CTL_GLOBAL_VOLUME);
+               err = elem_read_volume(elem, SM_CAPT, CTL_GLOBAL_VOLUME);
        else if (s->ctls[CTL_SINGLE].elem &&
                 s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
-               err = elem_read_volume(s, SM_CAPT, CTL_SINGLE);
+               err = elem_read_volume(elem, SM_CAPT, CTL_SINGLE);
        if (err < 0)
                return err;
 
-       if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) {
+       if ((sm->caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) {
                s->str[SM_CAPT].sw = 0;
                goto __skip_cswitch;
        }
        if (s->ctls[CTL_CAPTURE_SWITCH].elem) {
-               err = elem_read_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH);
+               err = elem_read_switch(elem, SM_CAPT, CTL_CAPTURE_SWITCH);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_GLOBAL_SWITCH].elem) {
-               err = elem_read_switch(s, SM_CAPT, CTL_GLOBAL_SWITCH);
+               err = elem_read_switch(elem, SM_CAPT, CTL_GLOBAL_SWITCH);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_SINGLE].elem &&
            s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) {
-               err = elem_read_switch(s, SM_CAPT, CTL_SINGLE);
+               err = elem_read_switch(elem, SM_CAPT, CTL_SINGLE);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_CAPTURE_ROUTE].elem) {
-               err = elem_read_route(s, SM_CAPT, CTL_CAPTURE_ROUTE);
+               err = elem_read_route(elem, SM_CAPT, CTL_CAPTURE_ROUTE);
                if (err < 0)
                        return err;
        }
        if (s->ctls[CTL_GLOBAL_ROUTE].elem) {
-               err = elem_read_route(s, SM_CAPT, CTL_GLOBAL_ROUTE);
+               err = elem_read_route(elem, SM_CAPT, CTL_GLOBAL_ROUTE);
                if (err < 0)
                        return err;
        }
@@ -440,7 +447,7 @@ static int selem_read(snd_mixer_elem_t *elem)
                snd_ctl_elem_value_t *ctl;
                selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE];
                snd_ctl_elem_value_alloca(&ctl);
-               err = snd_hctl_elem_read(c->elem, ctl);
+               err = snd_ctl_celem_read(c->elem, ctl);
                if (err < 0)
                        return err;
                for (idx = 0; idx < s->str[SM_CAPT].channels; idx++) {
@@ -461,34 +468,34 @@ static int selem_read(snd_mixer_elem_t *elem)
        return 0;
 }
 
-static int elem_write_volume(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_write_volume(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < c->values; idx++)
                snd_ctl_elem_value_set_integer(ctl, idx, from_user(s, dir, c, s->str[dir].vol[idx]));
-       if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                return err;
        return 0;
 }
 
-static int elem_write_switch(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_write_switch(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < c->values; idx++)
                snd_ctl_elem_value_set_integer(ctl, idx, !!(s->str[dir].sw & (1 << idx)));
-       if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                return err;
        return 0;
 }
@@ -500,75 +507,75 @@ static int elem_write_switch_constant(selem_none_t *s, selem_ctl_type_t type, in
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < c->values; idx++)
                snd_ctl_elem_value_set_integer(ctl, idx, !!val);
-       if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                return err;
        return 0;
 }
 
-static int elem_write_route(selem_none_t *s, int dir, selem_ctl_type_t type)
+static int elem_write_route(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type)
 {
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
        selem_ctl_t *c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < c->values * c->values; idx++)
                snd_ctl_elem_value_set_integer(ctl, idx, 0);
        for (idx = 0; idx < c->values; idx++)
                snd_ctl_elem_value_set_integer(ctl, idx * c->values + idx, !!(s->str[dir].sw & (1 << idx)));
-       if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                return err;
        return 0;
 }
 
-static int elem_write_enum(selem_none_t *s)
+static int elem_write_enum(snd_amixer_elem_t *elem)
 {
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        snd_ctl_elem_value_t *ctl;
+
        unsigned int idx;
        int err;
        int type;
        selem_ctl_t *c;
        type = CTL_GLOBAL_ENUM;
-       if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) )
+       if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) )
                type = CTL_GLOBAL_ENUM;
-       else if (s->selem.caps & SM_CAP_PENUM)
+       else if (sm->caps & SM_CAP_PENUM)
                type = CTL_PLAYBACK_ENUM;
-       else if (s->selem.caps & SM_CAP_CENUM)
+       else if (sm->caps & SM_CAP_CENUM)
                type = CTL_CAPTURE_ENUM;
        c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
-       if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                return err;
        for (idx = 0; idx < c->values; idx++)
                snd_ctl_elem_value_set_enumerated(ctl, idx, (unsigned int)s->str[0].vol[idx]);
-       if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+       if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                return err;
        return 0;
 }
 
-static int selem_write_main(snd_mixer_elem_t *elem)
+static int selem_write_main(snd_amixer_elem_t *elem)
 {
-       selem_none_t *s;
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        unsigned int idx;
        int err;
 
-       assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
-       s = snd_mixer_elem_get_private(elem);
-
        if (s->ctls[CTL_GLOBAL_ENUM].elem)
-               return elem_write_enum(s);
+               return elem_write_enum(elem);
 
        if (s->ctls[CTL_PLAYBACK_ENUM].elem)
-               return elem_write_enum(s);
+               return elem_write_enum(elem);
 
        if (s->ctls[CTL_CAPTURE_ENUM].elem)
-               return elem_write_enum(s);
+               return elem_write_enum(elem);
 
        if (s->ctls[CTL_SINGLE].elem) {
                if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
@@ -625,13 +632,13 @@ static int selem_write_main(snd_mixer_elem_t *elem)
                snd_ctl_elem_value_t *ctl;
                selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE];
                snd_ctl_elem_value_alloca(&ctl);
-               if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
+               if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0)
                        return err;
                for (idx = 0; idx < c->values; idx++) {
                        if (s->str[SM_CAPT].sw & (1 << idx))
                                snd_ctl_elem_value_set_enumerated(ctl, idx, s->capture_item);
                }
-               if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0)
+               if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0)
                        return err;
                /* update the element, don't remove */
                err = selem_read(elem);
@@ -641,7 +648,7 @@ static int selem_write_main(snd_mixer_elem_t *elem)
        return 0;
 }
 
-static int selem_write(snd_mixer_elem_t *elem)
+static int selem_write(snd_amixer_elem_t *elem)
 {
        int err;
        
@@ -651,21 +658,19 @@ static int selem_write(snd_mixer_elem_t *elem)
        return err;
 }
 
-static void selem_free(snd_mixer_elem_t *elem)
+static void selem_free(snd_amixer_elem_t *elem)
 {
-       selem_none_t *simple = snd_mixer_elem_get_private(elem);
-       assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
-       if (simple->selem.id)
-               snd_mixer_selem_id_free(simple->selem.id);
+       selem_none_t *simple = snd_amixer_elem_get_private(elem);
        /* free db range information */
        free(simple->str[0].db_info);
        free(simple->str[1].db_info);
        free(simple);
 }
 
-static int simple_update(snd_mixer_elem_t *melem)
+static int simple_update(snd_amixer_elem_t *melem)
 {
        selem_none_t *simple;
+       sm_elem_t *sm;
        unsigned int caps, pchannels, cchannels;
        long pmin, pmax, cmin, cmax;
        selem_ctl_t *ctl;
@@ -678,9 +683,9 @@ static int simple_update(snd_mixer_elem_t *melem)
        cchannels = 0;
        cmin = LONG_MAX;
        cmax = LONG_MIN;
-       assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE);
-       simple = snd_mixer_elem_get_private(melem);
-       name = snd_mixer_selem_get_name(melem);
+       simple = snd_amixer_elem_get_private(melem);
+       sm = snd_amixer_elem_get_sm(melem);
+       name = snd_amixer_elem_get_name(melem);
        ctl = &simple->ctls[CTL_SINGLE];
        if (ctl->elem) {
                pchannels = cchannels = ctl->values;
@@ -868,7 +873,7 @@ static int simple_update(snd_mixer_elem_t *melem)
            (caps & (SM_CAP_PVOLUME|SM_CAP_CVOLUME)) == 0)
                caps |= SM_CAP_PVOLUME|SM_CAP_CVOLUME;
 
-       simple->selem.caps = caps;
+       sm->caps = caps;
        simple->str[SM_PLAY].channels = pchannels;
        if (!simple->str[SM_PLAY].range) {
                simple->str[SM_PLAY].min = pmin != LONG_MAX ? pmin : 0;
@@ -943,16 +948,17 @@ static int base_len(const char *name, selem_ctl_type_t *type)
  * Simple Mixer Operations
  */
        
-static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value)
+static int _snd_amixer_selem_set_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       selem_none_t *s = snd_amixer_elem_get_private(elem);   
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        if ((unsigned int) channel >= s->str[dir].channels)
                return 0;
        if (value < s->str[dir].min || value > s->str[dir].max)
                return 0;
-       if (s->selem.caps & 
+       if (sm->caps & 
            (dir == SM_PLAY ? SM_CAP_PVOLUME_JOIN : SM_CAP_CVOLUME_JOIN))
                channel = 0;
        if (value != s->str[dir].vol[channel]) {
@@ -962,12 +968,14 @@ static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixe
        return 0;
 }
 
-static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value)
+static int _snd_amixer_selem_set_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
+
        if ((unsigned int) channel >= s->str[dir].channels)
                return 0;
-       if (s->selem.caps & 
+       if (sm->caps & 
            (dir == SM_PLAY ? SM_CAP_PSWITCH_JOIN : SM_CAP_CSWITCH_JOIN))
                channel = 0;
        if (value) {
@@ -984,9 +992,10 @@ static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixe
        return 0;
 }
 
-static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
+static int is_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int cmd, int val)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        
        switch (cmd) {
 
@@ -998,37 +1007,31 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
                return 1;
        }
 
-       case SM_OPS_IS_MONO:
-               return s->str[dir].channels == 1;
-
        case SM_OPS_IS_CHANNEL:
                return (unsigned int) val < s->str[dir].channels;
 
        case SM_OPS_IS_ENUMERATED:
-               if (val == 1) {
-                       if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) )
-                               return 1;
-                       if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) )
-                               return 1;
-                       return 0;
-               }
-               if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) )
+               if (dir == SM_PLAY && (sm->caps & SM_CAP_PENUM) && !(sm->caps & SM_CAP_CENUM))
+                       return 1;
+               if (dir == SM_CAPT && (sm->caps & SM_CAP_CENUM) && !(sm->caps & SM_CAP_PENUM))
+                       return 1;
+               if (dir == SM_COMM && (sm->caps & (SM_CAP_CENUM|SM_CAP_PENUM)) == (SM_CAP_CENUM|SM_CAP_PENUM))
                        return 1;
                return 0;
        
        case SM_OPS_IS_ENUMCNT:
                /* Both */
-               if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) {
+               if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) {
                        if (! s->ctls[CTL_GLOBAL_ENUM].elem)
                                return -EINVAL;
                        return s->ctls[CTL_GLOBAL_ENUM].max;
                /* Only Playback */
-               } else if (s->selem.caps & SM_CAP_PENUM ) {
+               } else if (sm->caps & SM_CAP_PENUM ) {
                        if (! s->ctls[CTL_PLAYBACK_ENUM].elem)
                                return -EINVAL;
                        return s->ctls[CTL_PLAYBACK_ENUM].max;
                /* Only Capture */
-               } else if (s->selem.caps & SM_CAP_CENUM ) {
+               } else if (sm->caps & SM_CAP_CENUM ) {
                        if (! s->ctls[CTL_CAPTURE_ENUM].elem)
                                return -EINVAL;
                        return s->ctls[CTL_CAPTURE_ENUM].max;
@@ -1039,19 +1042,25 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
        return 1;
 }
 
-static int get_range_ops(snd_mixer_elem_t *elem, int dir,
+static int get_channels_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir)
+{
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       return s->str[dir].channels;
+}
+
+static int get_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
                         long *min, long *max)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        *min = s->str[dir].min;
        *max = s->str[dir].max;
        return 0;
 }
 
-static int set_range_ops(snd_mixer_elem_t *elem, int dir,
+static int set_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
                         long min, long max)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        int err;
 
        s->str[dir].range = 1;
@@ -1062,11 +1071,12 @@ static int set_range_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
-                         snd_mixer_selem_channel_id_t channel, long *value)
+static int get_volume_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                         snd_amixer_elem_channel_id_t channel, long *value)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        if ((unsigned int) channel >= s->str[dir].channels)
                return -EINVAL;
@@ -1074,9 +1084,9 @@ static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec);
+static int init_db_range(snd_ctl_elem_t *ctl, struct selem_str *rec);
 
-static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
+static int convert_to_dB(snd_ctl_elem_t *ctl, struct selem_str *rec,
                         long volume, long *db_gain)
 {
        if (init_db_range(ctl, rec) < 0)
@@ -1087,7 +1097,7 @@ static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
 
 /* initialize dB range information, reading TLV via hcontrol
  */
-static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec)
+static int init_db_range(snd_ctl_elem_t *ctl, struct selem_str *rec)
 {
        snd_ctl_elem_info_t *info;
        unsigned int *tlv = NULL;
@@ -1101,14 +1111,14 @@ static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec)
                return 0;
 
        snd_ctl_elem_info_alloca(&info);
-       if (snd_hctl_elem_info(ctl, info) < 0)
+       if (snd_ctl_celem_info(ctl, info) < 0)
                goto error;
        if (! snd_ctl_elem_info_is_tlv_readable(info))
                goto error;
        tlv = malloc(tlv_size);
        if (! tlv)
                return -ENOMEM;
-       if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0)
+       if (snd_ctl_celem_tlv_read(ctl, tlv, tlv_size) < 0)
                goto error;
        db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec);
        if (db_size < 0)
@@ -1128,7 +1138,7 @@ static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec)
 }
 
 /* get selem_ctl for TLV access */
-static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir)
+static selem_ctl_t *get_selem_ctl(selem_none_t *s, snd_amixer_dir_t dir)
 {
        selem_ctl_t *c;
        if (dir == SM_PLAY)
@@ -1147,7 +1157,7 @@ static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir)
        return c;
 }
 
-static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec,
+static int get_dB_range(snd_ctl_elem_t *ctl, struct selem_str *rec,
                        long *min, long *max)
 {
        if (init_db_range(ctl, rec) < 0)
@@ -1156,13 +1166,14 @@ static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec,
        return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max);
 }
        
-static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir,
+static int get_dB_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
                            long *min, long *max)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        selem_ctl_t *c;
 
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        c = get_selem_ctl(s, dir);
        if (! c)
@@ -1170,7 +1181,7 @@ static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir,
        return get_dB_range(c->elem, &s->str[dir], min, max);
 }
 
-static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
+static int convert_from_dB(snd_ctl_elem_t *ctl, struct selem_str *rec,
                           long db_gain, long *value, int xdir)
 {
        if (init_db_range(ctl, rec) < 0)
@@ -1180,12 +1191,12 @@ static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
                                       db_gain, value, xdir);
 }
 
-static int ask_vol_dB_ops(snd_mixer_elem_t *elem,
-                         int dir,
+static int ask_vol_dB_ops(snd_amixer_elem_t *elem,
+                         snd_amixer_dir_t dir,
                          long value,
                          long *dBvalue)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        selem_ctl_t *c;
 
        c = get_selem_ctl(s, dir);
@@ -1195,17 +1206,18 @@ static int ask_vol_dB_ops(snd_mixer_elem_t *elem,
        return res;
 }
 
-static int get_dB_ops(snd_mixer_elem_t *elem,
-                      int dir,
-                      snd_mixer_selem_channel_id_t channel,
+static int get_dB_ops(snd_amixer_elem_t *elem,
+                      snd_amixer_dir_t dir,
+                      snd_amixer_elem_channel_id_t channel,
                       long *value)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        selem_ctl_t *c;
        int err;
        long volume, db_gain;
 
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        c = get_selem_ctl(s, dir);
        if (! c)
@@ -1220,11 +1232,12 @@ static int get_dB_ops(snd_mixer_elem_t *elem,
        return err;
 }
 
-static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
-                         snd_mixer_selem_channel_id_t channel, int *value)
+static int get_switch_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                         snd_amixer_elem_channel_id_t channel, int *value)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
-       if (s->selem.caps & SM_CAP_GSWITCH)
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
+       if (sm->caps & SM_CAP_GSWITCH)
                dir = SM_PLAY;
        if ((unsigned int) channel >= s->str[dir].channels)
                return -EINVAL;
@@ -1232,11 +1245,11 @@ static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
-                         snd_mixer_selem_channel_id_t channel, long value)
+static int set_volume_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                         snd_amixer_elem_channel_id_t channel, long value)
 {
        int changed;
-       changed = _snd_mixer_selem_set_volume(elem, dir, channel, value);
+       changed = _snd_amixer_selem_set_volume(elem, dir, channel, value);
        if (changed < 0)
                return changed;
        if (changed)
@@ -1244,13 +1257,14 @@ static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir,
+static int ask_dB_vol_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
                          long dbValue, long *value, int xdir)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        selem_ctl_t *c;
 
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        c = get_selem_ctl(s, dir);
        if (! c)
@@ -1258,16 +1272,17 @@ static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir,
        return convert_from_dB(c->elem, &s->str[dir], dbValue, value, xdir);
 }
 
-static int set_dB_ops(snd_mixer_elem_t *elem, int dir,
-                     snd_mixer_selem_channel_id_t channel,
+static int set_dB_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                     snd_amixer_elem_channel_id_t channel,
                      long db_gain, int xdir)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
        selem_ctl_t *c;
        long value;
        int err;
 
-       if (s->selem.caps & SM_CAP_GVOLUME)
+       if (sm->caps & SM_CAP_GVOLUME)
                dir = SM_PLAY;
        c = get_selem_ctl(s, dir);
        if (! c)
@@ -1278,21 +1293,21 @@ static int set_dB_ops(snd_mixer_elem_t *elem, int dir,
        return set_volume_ops(elem, dir, channel, value);
 }
 
-static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
-                         snd_mixer_selem_channel_id_t channel, int value)
+static int set_switch_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir,
+                         snd_amixer_elem_channel_id_t channel, int value)
 {
        int changed;
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
-       if (s->selem.caps & SM_CAP_GSWITCH)
+       sm_elem_t *sm = snd_amixer_elem_get_sm(elem);
+       if (sm->caps & SM_CAP_GSWITCH)
                dir = SM_PLAY;
        if (dir == SM_PLAY) {
-               if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)))
+               if (! (sm->caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)))
                        return -EINVAL;
        } else {
-               if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)))
+               if (! (sm->caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)))
                        return -EINVAL;
        }
-       changed = _snd_mixer_selem_set_switch(elem, dir, channel, value);
+       changed = _snd_amixer_selem_set_switch(elem, dir, channel, value);
        if (changed < 0)
                return changed;
        if (changed)
@@ -1300,13 +1315,13 @@ static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int enum_item_name_ops(snd_mixer_elem_t *elem,
+static int enum_item_name_ops(snd_amixer_elem_t *elem,
                              unsigned int item,
                              size_t maxlen, char *buf)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_info_t *info;
-       snd_hctl_elem_t *helem;
+       snd_ctl_elem_t *helem;
        int type;
 
        type = CTL_GLOBAL_ENUM;
@@ -1323,20 +1338,20 @@ static int enum_item_name_ops(snd_mixer_elem_t *elem,
        if (item >= (unsigned int)s->ctls[type].max)
                return -EINVAL;
        snd_ctl_elem_info_alloca(&info);
-       snd_hctl_elem_info(helem, info);
+       snd_ctl_celem_info(helem, info);
        snd_ctl_elem_info_set_item(info, item);
-       snd_hctl_elem_info(helem, info);
+       snd_ctl_celem_info(helem, info);
        strncpy(buf, snd_ctl_elem_info_get_item_name(info), maxlen);
        return 0;
 }
 
-static int get_enum_item_ops(snd_mixer_elem_t *elem,
-                            snd_mixer_selem_channel_id_t channel,
+static int get_enum_item_ops(snd_amixer_elem_t *elem,
+                            snd_amixer_elem_channel_id_t channel,
                             unsigned int *itemp)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_value_t *ctl;
-       snd_hctl_elem_t *helem;
+       snd_ctl_elem_t *helem;
        int err;
 
        if ((unsigned int) channel >= s->str[0].channels)
@@ -1346,19 +1361,19 @@ static int get_enum_item_ops(snd_mixer_elem_t *elem,
        if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem;
        assert(helem);
        snd_ctl_elem_value_alloca(&ctl);
-       err = snd_hctl_elem_read(helem, ctl);
+       err = snd_ctl_celem_read(helem, ctl);
        if (! err)
                *itemp = snd_ctl_elem_value_get_enumerated(ctl, channel);
        return err;
 }
 
-static int set_enum_item_ops(snd_mixer_elem_t *elem,
-                            snd_mixer_selem_channel_id_t channel,
+static int set_enum_item_ops(snd_amixer_elem_t *elem,
+                            snd_amixer_elem_channel_id_t channel,
                             unsigned int item)
 {
-       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_none_t *s = snd_amixer_elem_get_private(elem);
        snd_ctl_elem_value_t *ctl;
-       snd_hctl_elem_t *helem;
+       snd_ctl_elem_t *helem;
        int err;
        int type;
 
@@ -1380,16 +1395,17 @@ static int set_enum_item_ops(snd_mixer_elem_t *elem,
                return -EINVAL;
        }
        snd_ctl_elem_value_alloca(&ctl);
-       err = snd_hctl_elem_read(helem, ctl);
+       err = snd_ctl_celem_read(helem, ctl);
        if (err < 0) {
                return err;
        }
        snd_ctl_elem_value_set_enumerated(ctl, channel, item);
-       return snd_hctl_elem_write(helem, ctl);
+       return snd_ctl_celem_write(helem, ctl);
 }
 
 static struct sm_elem_ops simple_none_ops = {
        .is             = is_ops,
+       .get_channels   = get_channels_ops,
        .get_range      = get_range_ops,
        .get_dB_range   = get_dB_range_ops,
        .set_range      = set_range_ops,
@@ -1406,12 +1422,13 @@ static struct sm_elem_ops simple_none_ops = {
        .set_enum_item  = set_enum_item_ops
 };
 
-static int simple_add1(snd_mixer_class_t *class, const char *name,
-                      snd_hctl_elem_t *helem, selem_ctl_type_t type,
+static int simple_add1(snd_amixer_t *amixer, const char *name,
+                      snd_ctl_elem_t *helem, selem_ctl_type_t type,
                       unsigned int value)
 {
-       snd_mixer_elem_t *melem;
-       snd_mixer_selem_id_t *id;
+       snd_amixer_elem_t *melem;
+       sm_elem_t *sm;
+       snd_amixer_elem_id_t *id;
        int new = 0;
        int err;
        snd_ctl_elem_info_t *info;
@@ -1421,7 +1438,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        unsigned long values;
 
        snd_ctl_elem_info_alloca(&info);
-       err = snd_hctl_elem_info(helem, info);
+       err = snd_ctl_celem_info(helem, info);
        if (err < 0)
                return err;
        ctype = snd_ctl_elem_info_get_type(info);
@@ -1508,39 +1525,42 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
                break;
        }
        name1 = get_short_name(name);
-       if (snd_mixer_selem_id_malloc(&id))
+       if (snd_amixer_elem_id_malloc(&id))
                return -ENOMEM;
-       snd_mixer_selem_id_set_name(id, name1);
-       snd_mixer_selem_id_set_index(id, snd_hctl_elem_get_index(helem));
-       melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id);
+       snd_amixer_elem_id_set_name(id, name1);
+       snd_amixer_elem_id_set_index(id, snd_ctl_elem_get_index(helem));
+       melem = snd_amixer_find_elem(amixer, id);
        if (!melem) {
                simple = calloc(1, sizeof(*simple));
                if (!simple) {
-                       snd_mixer_selem_id_free(id);
+                       snd_amixer_elem_id_free(id);
                        return -ENOMEM;
                }
-               simple->selem.id = id;
-               simple->selem.ops = &simple_none_ops;
-               err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE,
-                                        get_compare_weight(snd_mixer_selem_id_get_name(simple->selem.id), snd_mixer_selem_id_get_index(simple->selem.id)),
-                                        simple, selem_free);
+               err = snd_amixer_elem_new(amixer,
+                                         &melem,
+                                         id,
+                                         get_compare_weight(snd_amixer_elem_id_get_name(id), snd_amixer_elem_id_get_index(id)),
+                                         simple, selem_free);
+               snd_amixer_elem_id_free(id);
                if (err < 0) {
-                       snd_mixer_selem_id_free(id);
+                       snd_amixer_elem_id_free(id);
                        free(simple);
                        return err;
                }
+               sm = snd_amixer_elem_get_sm(melem);
+               sm->ops = &simple_none_ops;
                new = 1;
        } else {
-               simple = snd_mixer_elem_get_private(melem);
-               snd_mixer_selem_id_free(id);
+               simple = snd_amixer_elem_get_private(melem);
+               snd_amixer_elem_id_free(id);
        }
        if (simple->ctls[type].elem) {
                SNDERR("helem (%s,'%s',%u,%u,%u) appears twice or more",
-                               snd_ctl_elem_iface_name(snd_hctl_elem_get_interface(helem)),
-                               snd_hctl_elem_get_name(helem),
-                               snd_hctl_elem_get_index(helem),
-                               snd_hctl_elem_get_device(helem),
-                               snd_hctl_elem_get_subdevice(helem));
+                               snd_ctl_elem_iface_name(snd_ctl_elem_get_interface(helem)),
+                               snd_ctl_elem_get_name(helem),
+                               snd_ctl_elem_get_index(helem),
+                               snd_ctl_elem_get_device(helem),
+                               snd_ctl_elem_get_subdevice(helem));
                err = -EINVAL;
                goto __error;
        }
@@ -1566,7 +1586,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        default:
                break;
        }
-       err = snd_mixer_elem_attach(melem, helem);
+       err = snd_amixer_elem_attach(melem, helem);
        if (err < 0)
                goto __error;
        err = simple_update(melem);
@@ -1576,36 +1596,36 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
                return err;
        }
        if (new)
-               err = snd_mixer_elem_add(melem, class);
+               err = snd_amixer_elem_add(amixer, melem);
        else
-               err = snd_mixer_elem_info(melem);
+               err = snd_amixer_elem_info(melem);
        if (err < 0)
                return err;
        err = selem_read(melem);
        if (err < 0)
                return err;
        if (err)
-               err = snd_mixer_elem_value(melem);
+               err = snd_amixer_elem_value(melem);
        return err;
       __error:
        if (new)
-               snd_mixer_elem_free(melem);
+               snd_amixer_elem_free(melem);
        return -EINVAL;
 }
 
-static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
+static int simple_event_add(snd_amixer_t *amixer, snd_ctl_elem_t *helem)
 {
-       const char *name = snd_hctl_elem_get_name(helem);
+       const char *name = snd_ctl_elem_get_name(helem);
        size_t len;
        selem_ctl_type_t type = CTL_SINGLE; /* to shut up warning */
-       if (snd_hctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER)
+       if (snd_ctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER)
                return 0;
        if (strcmp(name, "Capture Source") == 0) {
                snd_ctl_elem_info_t *info;
                unsigned int k, items;
                int err;
                snd_ctl_elem_info_alloca(&info);
-               err = snd_hctl_elem_info(helem, info);
+               err = snd_ctl_celem_info(helem, info);
                assert(err >= 0);
                if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_ENUMERATED)
                        return 0;
@@ -1613,11 +1633,11 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
                for (k = 0; k < items; ++k) {
                        const char *n;
                        snd_ctl_elem_info_set_item(info, k);
-                       err = snd_hctl_elem_info(helem, info);
+                       err = snd_ctl_celem_info(helem, info);
                        if (err < 0)
                                return err;
                        n = snd_ctl_elem_info_get_item_name(info);
-                       err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE, k);
+                       err = simple_add1(amixer, n, helem, CTL_CAPTURE_SOURCE, k);
                        if (err < 0)
                                return err;
                }
@@ -1625,7 +1645,7 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
        }
        len = base_len(name, &type);
        if (len == 0) {
-               return simple_add1(class, name, helem, CTL_SINGLE, 0);
+               return simple_add1(amixer, name, helem, CTL_SINGLE, 0);
        } else {
                char ename[128];
                if (len >= sizeof(ename))
@@ -1637,14 +1657,14 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
                        type = CTL_CAPTURE_VOLUME;
                else if (type == CTL_GLOBAL_SWITCH && !strcmp(ename, "Capture"))
                        type = CTL_CAPTURE_SWITCH;
-               return simple_add1(class, ename, helem, type, 0);
+               return simple_add1(amixer, ename, helem, type, 0);
        }
 }
 
-static int simple_event_remove(snd_hctl_elem_t *helem,
-                              snd_mixer_elem_t *melem)
+static int simple_event_remove(snd_ctl_elem_t *helem,
+                              snd_amixer_elem_t *melem)
 {
-       selem_none_t *simple = snd_mixer_elem_get_private(melem);
+       selem_none_t *simple = snd_amixer_elem_get_private(melem);
        int err;
        int k;
        for (k = 0; k <= CTL_LAST; k++) {
@@ -1653,23 +1673,23 @@ static int simple_event_remove(snd_hctl_elem_t *helem,
        }
        assert(k <= CTL_LAST);
        simple->ctls[k].elem = NULL;
-       err = snd_mixer_elem_detach(melem, helem);
+       err = snd_amixer_elem_detach(melem, helem);
        if (err < 0)
                return err;
-       if (snd_mixer_elem_empty(melem))
-               return snd_mixer_elem_remove(melem);
+       if (snd_amixer_elem_is_empty(melem))
+               return snd_amixer_elem_remove(melem);
        err = simple_update(melem);
-       return snd_mixer_elem_info(melem);
+       return snd_amixer_elem_info(melem);
 }
 
-static int simple_event(snd_mixer_class_t *class, unsigned int mask,
-                       snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
+static int simple_event(snd_amixer_t *amixer, unsigned int mask,
+                       snd_ctl_elem_t *helem, snd_amixer_elem_t *melem)
 {
        int err;
        if (mask == SND_CTL_EVENT_MASK_REMOVE)
                return simple_event_remove(helem, melem);
        if (mask & SND_CTL_EVENT_MASK_ADD) {
-               err = simple_event_add(class, helem);
+               err = simple_event_add(amixer, helem);
                if (err < 0)
                        return err;
        }
@@ -1677,7 +1697,7 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask,
                err = simple_event_remove(helem, melem);
                if (err < 0)
                        return err;
-               err = simple_event_add(class, helem);
+               err = simple_event_add(amixer, helem);
                if (err < 0)
                        return err;
                return 0;
@@ -1687,7 +1707,7 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask,
                if (err < 0)
                        return err;
                if (err) {
-                       err = snd_mixer_elem_value(melem);
+                       err = snd_amixer_elem_value(melem);
                        if (err < 0)
                                return err;
                }
@@ -1695,30 +1715,75 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask,
        return 0;
 }
 
+#ifndef DOC_HIDDEN
 /**
- * \brief Register mixer simple element class - none abstraction
- * \param mixer Mixer handle
- * \param options Options container
- * \param classp Pointer to returned mixer simple element class handle (or NULL)
+ * \brief Open mixer - none abstraction
+ * \param amixer Mixer handle
+ * \param name Device name
+ * \param pcm_playback PCM handle for playback
+ * \param pcm_capture PCM handle for capture
+ * \param mode Open mode
  * \return 0 on success otherwise a negative error code
  */
-int snd_mixer_simple_none_register(snd_mixer_t *mixer,
-                                  struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED,
-                                  snd_mixer_class_t **classp)
+int _snd_amixer_none_open(snd_amixer_t *amixer,
+                         snd_config_t *root ATTRIBUTE_UNUSED,
+                         snd_config_t *conf,
+                         struct sm_open *sm_open)
 {
-       snd_mixer_class_t *class;
+       snd_config_iterator_t i, next;
+       const char *str;
        int err;
-
-       if (snd_mixer_class_malloc(&class))
-               return -ENOMEM;
-       snd_mixer_class_set_event(class, simple_event);
-       snd_mixer_class_set_compare(class, snd_mixer_selem_compare);
-       err = snd_mixer_class_register(class, mixer);
-       if (err < 0) {
-               free(class);
-               return err;
+       snd_config_t *n;
+       char ctlname[64];
+       
+       ctlname[0] = '\0';
+       if (sm_open->pcm_playback || sm_open->pcm_capture)
+               return -ENXIO;
+       snd_config_for_each(i, next, conf) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+               if (snd_amixer_conf_generic_id(id))
+                       continue;
+               if (strcmp(id, "card") == 0) {
+                       long card = -1;
+                       err = snd_config_get_integer(n, &card);
+                       if (err < 0) {
+                               err = snd_config_get_string(n, &str);
+                               if (err < 0) {
+                                       SNDERR("Invalid type for %s", id);
+                                       return -EINVAL;
+                               }
+                               card = snd_card_get_index(str);
+                               if (card < 0) {
+                                       SNDERR("Invalid value for %s", id);
+                                       return card;
+                               }
+                       }
+                       sprintf(ctlname, "hw:%li", card);
+                       continue;
+               }
+               if (strcmp(id, "ctlname") == 0) {
+                       err = snd_config_get_string(n, &str);
+                       if (err < 0) {
+                               SNDERR("ctlname must be a string");
+                               return -EINVAL;
+                       }
+                       strncpy(ctlname, str, sizeof(ctlname)-1);
+                       ctlname[sizeof(ctlname)-1] = '\0';
+                       continue;
+               }
+               SNDERR("Unknown field %s", id);
+               return -EINVAL;
        }
-       if (classp)
-               *classp = class;
-       return 0;
+       if (ctlname[0] == '\0') {
+               SNDERR("card or ctlname is not defined");
+               return -EINVAL;
+       }
+       snd_amixer_set_event(amixer, simple_event);
+       return snd_ctl_open(&sm_open->ctl[0], ctlname, SND_CTL_CACHE);
 }
+
+SND_DLSYM_BUILD_VERSION(_snd_amixer_none_open, SND_AMIXER_DLSYM_VERSION);
+#endif
diff --git a/src/mixer/simple_old.c b/src/mixer/simple_old.c
new file mode 100644 (file)
index 0000000..339b994
--- /dev/null
@@ -0,0 +1,805 @@
+/**
+ * \file mixer/simple.c
+ * \brief Mixer Simple Element Class Interface
+ * \author Jaroslav Kysela <perex@perex.cz>
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \date 2001-2004
+ *
+ * Mixer simple element class interface.
+ */
+/*
+ *  Mixer Interface - simple controls
+ *  Copyright (c) 2000,2004 by Jaroslav Kysela <perex@perex.cz>
+ *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <math.h>
+#include "mixer_old_local.h"
+
+#define SM_PLAY SND_MIXER_DIR_PLAYBACK
+#define SM_CAPT SND_MIXER_DIR_CAPTURE
+#define SM_COMM SND_MIXER_DIR_COMMON
+
+/**
+ * \brief Register mixer simple element class
+ * \param mixer Mixer handle
+ * \param options Options container
+ * \param nothing Pass NULL
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_mixer_selem_register(snd_mixer_t *mixer,
+                            struct snd_mixer_selem_regopt *options,
+                            void **nothing ATTRIBUTE_UNUSED)
+{
+       int err;
+
+       if (options && options->ver == 1) {
+               if (options->device != NULL &&
+                   (options->playback_pcm != NULL ||
+                    options->capture_pcm != NULL))
+                       return -EINVAL;
+               if (options->device == NULL &&
+                   options->playback_pcm == NULL &&
+                   options->capture_pcm == NULL)
+                       return -EINVAL;
+       }
+       if (options == NULL ||
+           (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) {
+               if (options != NULL) {
+                       err = snd_mixer_attach(mixer, options->device);
+                       if (err < 0)
+                               return err;
+               }
+               return 0;
+       } else if (options->ver == 1) {
+               if (options->abstract == SND_MIXER_SABSTRACT_BASIC)
+                       return snd_mixer_attach(mixer, options->device);
+       }
+       return -ENXIO;
+}
+
+/**
+ * \brief Find a mixer simple element
+ * \param mixer Mixer handle
+ * \param id Mixer simple element identifier
+ * \return mixer simple element handle or NULL if not found
+ */
+snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
+                                      const snd_mixer_selem_id_t *id)
+{
+       return snd_amixer_find_elem(mixer->amixer, id);
+}
+
+/**
+ * \brief Get mixer simple element identifier
+ * \param elem Mixer simple element handle
+ * \param id returned mixer simple element identifier
+ */
+void snd_mixer_selem_get_id(snd_mixer_elem_t *elem,
+                           snd_mixer_selem_id_t *id)
+{
+       return snd_amixer_elem_get_id(elem, id);
+}
+
+/**
+ * \brief Get name part of mixer simple element identifier
+ * \param elem Mixer simple element handle
+ * \return name part of simple element identifier
+ */
+const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_name(elem);
+}
+
+/**
+ * \brief Get index part of mixer simple element identifier
+ * \param elem Mixer simple element handle
+ * \return index part of simple element identifier
+ */
+unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_index(elem);
+}
+
+/**
+ * \brief Return true if mixer simple element has only one volume control for both playback and capture
+ * \param elem Mixer simple element handle
+ * \return 0 separated control, 1 common control
+ */
+int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_volume(elem, SM_COMM);
+}
+
+/**
+ * \brief Return true if mixer simple element has only one switch control for both playback and capture
+ * \param elem Mixer simple element handle
+ * \return 0 separated control, 1 common control
+ */
+int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch(elem, SM_COMM);
+}
+
+/**
+ * \brief Return name of mixer simple element channel
+ * \param channel mixer simple element channel identifier
+ * \return channel name
+ */
+const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel)
+{
+       return snd_amixer_elem_channel_name(channel);
+}
+
+/**
+ * \brief Get info about the active state of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not active, 1 if active
+ */
+int snd_mixer_selem_is_active(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_is_active(elem);
+}
+
+/**
+ * \brief Get info about channels of playback stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not mono, 1 if mono
+ */
+int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_channels(elem, SM_PLAY) == 1;
+}
+
+/**
+ * \brief Get info about channels of playback stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel Mixer simple element channel identifier
+ * \return 0 if channel is not present, 1 if present
+ */
+int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
+{
+       return snd_amixer_elem_has_channel(elem, SM_PLAY, channel);
+}
+
+/**
+ * \brief Get range for playback volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum
+ * \param max Pointer to returned maximum
+ */
+int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem,
+                                              long *min, long *max)
+{
+       return snd_amixer_elem_get_volume_range(elem, SM_PLAY, min, max);
+}
+
+/**
+ * \brief Get range in dB for playback volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum (dB * 100)
+ * \param max Pointer to returned maximum (dB * 100)
+ */
+int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem,
+                                         long *min, long *max)
+{
+       return snd_amixer_elem_get_dB_range(elem, SM_PLAY, min, max);
+}
+
+/**
+ * \brief Set range for playback volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min minimum volume value
+ * \param max maximum volume value
+ */
+int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, 
+                                             long min, long max)
+{
+       return snd_amixer_elem_set_volume_range(elem, SM_PLAY, min, max);
+}
+
+/**
+ * \brief Return info about playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_volume(elem, SM_PLAY);
+}
+
+/**
+ * \brief Return info about playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_volume_joined(elem, SM_PLAY);
+}
+
+/**
+ * \brief Return info about playback switch control existence of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch(elem, SM_PLAY);
+}
+
+/**
+ * \brief Return info about playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch_joined(elem, SM_PLAY);
+}
+
+/**
+ * \brief Return corresponding dB value to an integer playback volume for a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value value to be converted to dB range
+ * \param dBvalue pointer to returned dB value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
+{
+       return snd_amixer_elem_ask_vol_dB(elem, SM_PLAY, value, dBvalue);
+}
+
+/**
+ * \brief Return corresponding integer playback volume for given dB value for a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value value to be converted to dB range
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \param dBvalue pointer to returned dB value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
+{
+       return snd_amixer_elem_ask_dB_vol(elem, SM_PLAY, dBvalue, dir, value);
+}
+
+/**
+ * \brief Return value of playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+       return snd_amixer_elem_get_volume(elem, SM_PLAY, channel, value);
+}
+
+/**
+ * \brief Return value of playback volume in dB control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value (dB * 100)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+       return snd_amixer_elem_get_dB(elem, SM_PLAY, channel, value);
+}
+
+/**
+ * \brief Return value of playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
+{
+       return snd_amixer_elem_get_switch(elem, SM_PLAY, channel, value);
+}
+
+/**
+ * \brief Set value of playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
+{
+       return snd_amixer_elem_set_volume(elem, SM_PLAY, channel, value);
+}
+
+/**
+ * \brief Set value in dB of playback volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value in dB * 100
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
+{
+       return snd_amixer_elem_set_dB(elem, SM_PLAY, channel, value, dir);
+}
+
+/**
+ * \brief Set value of playback volume control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value)
+{
+       return snd_amixer_elem_set_volume_all(elem, SM_PLAY, value);
+}
+
+/**
+ * \brief Set value in dB of playback volume control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value in dB * 100
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir)
+{
+       return snd_amixer_elem_set_dB_all(elem, SM_PLAY, value, dir);
+}
+
+/**
+ * \brief Set value of playback switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
+{
+       return snd_amixer_elem_set_switch(elem, SM_PLAY, channel, value);
+}
+
+/**
+ * \brief Set value of playback switch control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value)
+{
+       return snd_amixer_elem_set_switch_all(elem, SM_PLAY, value);
+}
+
+/**
+ * \brief Get info about channels of capture stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if not mono, 1 if mono
+ */
+int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_channels(elem, SM_CAPT) == 1;
+}
+
+/**
+ * \brief Get info about channels of capture stream of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel Mixer simple element channel identifier
+ * \return 0 if channel is not present, 1 if present
+ */
+int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
+{
+       return snd_amixer_elem_has_channel(elem, SM_CAPT, channel);
+}
+
+/**
+ * \brief Get range for capture volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum
+ * \param max Pointer to returned maximum
+ */
+int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem,
+                                            long *min, long *max)
+{
+       return snd_amixer_elem_get_volume_range(elem, SM_CAPT, min, max);
+}
+
+/**
+ * \brief Get range in dB for capture volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min Pointer to returned minimum (dB * 100)
+ * \param max Pointer to returned maximum (dB * 100)
+ */
+int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem,
+                                        long *min, long *max)
+{
+       return snd_amixer_elem_get_dB_range(elem, SM_CAPT, min, max);
+}
+
+/**
+ * \brief Set range for capture volume of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param min minimum volume value
+ * \param max maximum volume value
+ */
+int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, 
+                                            long min, long max)
+{
+       return snd_amixer_elem_set_volume_range(elem, SM_CAPT, min, max);
+}
+
+/**
+ * \brief Return info about capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_volume(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return info about capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_volume_joined(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return info about capture switch control existence of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if no control is present, 1 if it's present
+ */
+int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return info about capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per channel, 1 if control acts on all channels together
+ */
+int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch_joined(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return info about capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group)
+ */
+int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_has_switch_exclusive(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return info about capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive)
+ */
+int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_group(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return corresponding dB value to an integer capture volume for a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value value to be converted to dB range
+ * \param dBvalue pointer to returned dB value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
+{
+       return snd_amixer_elem_ask_vol_dB(elem, SM_CAPT, value, dBvalue);
+}
+
+/**
+ * \brief Return corresponding integer capture volume for given dB value for a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param dBvalue dB value to be converted to integer range
+ * \param value pointer to returned integer value
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
+{
+       return snd_amixer_elem_ask_dB_vol(elem, SM_CAPT, dBvalue, dir, value);
+}
+
+/**
+ * \brief Return value of capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+       return snd_amixer_elem_get_volume(elem, SM_CAPT, channel, value);
+}
+
+/**
+ * \brief Return value of capture volume in dB control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value (dB * 100)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+       return snd_amixer_elem_get_dB(elem, SM_CAPT, channel, value);
+}
+
+/**
+ * \brief Return value of capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value pointer to returned value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
+{
+       return snd_amixer_elem_get_switch(elem, SM_CAPT, channel, value);
+}
+
+/**
+ * \brief Set value of capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
+{
+       return snd_amixer_elem_set_volume(elem, SM_CAPT, channel, value);
+}
+
+/**
+ * \brief Set value in dB of capture volume control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value in dB * 100
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
+{
+       return snd_amixer_elem_set_dB(elem, SM_CAPT, channel, value, dir);
+}
+
+/**
+ * \brief Set value of capture volume control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value)
+{
+       return snd_amixer_elem_set_volume_all(elem, SM_CAPT, value);
+}
+
+/**
+ * \brief Set value in dB of capture volume control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value in dB * 100
+ * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above)
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir)
+{
+       return snd_amixer_elem_set_dB_all(elem, SM_CAPT, value, dir);
+}
+
+/**
+ * \brief Set value of capture switch control of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
+{
+       return snd_amixer_elem_set_switch(elem, SM_CAPT, channel, value);
+}
+
+/**
+ * \brief Set value of capture switch control for all channels of a mixer simple element
+ * \param elem Mixer simple element handle
+ * \param value control value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value)
+{
+       return snd_amixer_elem_set_switch_all(elem, SM_CAPT, value);
+}
+
+/**
+ * \brief Return true if mixer simple element is an enumerated control
+ * \param elem Mixer simple element handle
+ * \return 0 normal volume/switch control, 1 enumerated control
+ */
+int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_is_enum(elem, SM_COMM) ||
+              snd_amixer_elem_is_enum(elem, SM_PLAY) ||
+              snd_amixer_elem_is_enum(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return true if mixer simple enumerated element belongs to the playback direction
+ * \param elem Mixer simple element handle
+ * \return 0 no playback direction, 1 playback direction
+ */
+int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_is_enum(elem, SM_PLAY);
+}
+
+/**
+ * \brief Return true if mixer simple enumerated element belongs to the capture direction
+ * \param elem Mixer simple element handle
+ * \return 0 no capture direction, 1 capture direction
+ */
+int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_is_enum(elem, SM_CAPT);
+}
+
+/**
+ * \brief Return the number of enumerated items of the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \return the number of enumerated items, otherwise a negative error code
+ */
+int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem)
+{
+       return snd_amixer_elem_get_enum_items(elem);
+}
+
+/**
+ * \brief get the enumerated item string for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param item the index of the enumerated item to query
+ * \param maxlen the maximal length to be stored
+ * \param buf the buffer to store the name string
+ * \return 0 if successful, otherwise a negative error code
+ */
+int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem,
+                                      unsigned int item,
+                                      size_t maxlen, char *buf)
+{
+       return snd_amixer_elem_get_enum_item_name(elem, item, maxlen, buf);
+}
+
+/**
+ * \brief get the current selected enumerated item for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param itemp the pointer to store the index of the enumerated item
+ * \return 0 if successful, otherwise a negative error code
+ */
+int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem,
+                                 snd_mixer_selem_channel_id_t channel,
+                                 unsigned int *itemp)
+{
+       return snd_amixer_elem_get_enum_item(elem, channel, itemp);
+}
+
+/**
+ * \brief set the current selected enumerated item for the given mixer simple element
+ * \param elem Mixer simple element handle
+ * \param channel mixer simple element channel identifier
+ * \param item the enumerated item index
+ * \return 0 if successful, otherwise a negative error code
+ */
+int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem,
+                                 snd_mixer_selem_channel_id_t channel,
+                                 unsigned int item)
+{
+       return snd_amixer_elem_set_enum_item(elem, channel, item);
+}
+
+/**
+ * \brief get size of #snd_mixer_selem_id_t
+ * \return size in bytes
+ */
+size_t snd_mixer_selem_id_sizeof(void)
+{
+       return snd_amixer_elem_id_sizeof();
+}
+
+/**
+ * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc
+ * \param ptr returned pointer
+ * \return 0 on success otherwise negative error code
+ */
+int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
+{
+       return snd_amixer_elem_id_malloc(ptr);
+}
+
+/**
+ * \brief frees a previously allocated #snd_mixer_selem_id_t
+ * \param obj pointer to object to free
+ */
+void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
+{
+       return snd_amixer_elem_id_free(obj);
+}
+
+/**
+ * \brief copy one #snd_mixer_selem_id_t to another
+ * \param dst pointer to destination
+ * \param src pointer to source
+ */
+void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src)
+{
+       return snd_amixer_elem_id_copy(dst, src);
+}
+
+/**
+ * \brief Get name part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \return name part
+ */
+const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj)
+{
+       return snd_amixer_elem_id_get_name(obj);
+}
+
+/**
+ * \brief Get index part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \return index part
+ */
+unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj)
+{
+       return snd_amixer_elem_id_get_index(obj);
+}
+
+/**
+ * \brief Set name part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \param val name part
+ */
+void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val)
+{
+       return snd_amixer_elem_id_set_name(obj, val);
+}
+
+/**
+ * \brief Set index part of a mixer simple element identifier
+ * \param obj Mixer simple element identifier
+ * \param val index part
+ */
+void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val)
+{
+       return snd_amixer_elem_id_set_index(obj, val);
+}