snd_mixer_selem_set_capture_dB_all;
snd_mixer_selem_compare;
snd_mixer_sbasic_info;
+ snd_mixer_sbasic_get_private;
+ snd_mixer_sbasic_set_private;
+ snd_mixer_sbasic_set_private_free;
snd_ctl_ext_create;
snd_ctl_ext_delete;
searchl "AC97a:"
lib smixer-ac97.so
}
+hda {
+ searchl "HDA:"
+ lib smixer-hda.so
+}
AM_CFLAGS = -g -O2 -W -Wall
-pkglib_LTLIBRARIES = smixer-ac97.la
+pkglib_LTLIBRARIES = smixer-sbase.la \
+ smixer-ac97.la \
+ smixer-hda.la
-smixer_ac97_la_SOURCES = ac97.c
+smixer_sbase_la_SOURCES = sbase.c
+smixer_sbase_la_LDFLAGS = -module
+
+smixer_ac97_la_SOURCES = ac97.c sbasedl.c
smixer_ac97_la_LDFLAGS = -module
+
+smixer_hda_la_SOURCES = hda.c sbasedl.c
+smixer_hda_la_LDFLAGS = -module
#include <math.h>
#include "asoundlib.h"
#include "mixer_abst.h"
-#include "list.h"
+#include "sbase.h"
-#define MAX_CHANNEL 6
-
-#define SID_MASTER 0
-
-struct melem_sids {
- const char *sname;
- unsigned short sindex;
- unsigned short weight;
- unsigned int chanmap[2];
-};
+static struct sm_elem_ops simple_ac97_ops;
struct melem_sids sids[] = {
{
+ .sid = SID_MASTER,
.sname = "Master",
.sindex = 0,
.weight = 1,
.chanmap = { 3, 0 },
+ .sops = &simple_ac97_ops,
}
};
-#define PURPOSE_VOLUME 0
-#define PURPOSE_SWITCH 1
-#define PURPOSE_ENUMLIST 2
-
-struct helem_selector {
- snd_ctl_elem_iface_t iface;
- const char *name;
- unsigned short index;
- unsigned short sid;
- unsigned short purpose;
- unsigned short caps;
-};
-
#define SELECTORS (sizeof(selectors)/sizeof(selectors[0]))
struct helem_selector selectors[] = {
}
};
-struct helem_ac97 {
- struct list_head list;
- snd_hctl_elem_t *helem;
- unsigned short purpose;
- unsigned int caps;
- unsigned int inactive: 1;
- long min, max;
- unsigned int count;
-};
-
-struct selem_ac97 {
- sm_selem_t selem;
- struct list_head helems;
- unsigned short sid;
- struct {
- unsigned int chanmap;
- unsigned int forced_range: 1;
- long min, max;
- long vol[MAX_CHANNEL];
- } dir[2];
-};
-
-/*
- * Prototypes
- */
-
-static int selem_read(snd_mixer_elem_t *elem);
-
-/*
- * Helpers
- */
-
-static unsigned int chanmap_to_channels(unsigned int chanmap)
-{
- unsigned int i, res;
-
- for (i = 0, res = 0; i < MAX_CHANNEL; i++)
- if (chanmap & (1 << i))
- res++;
- return res;
-}
-
-static long to_user(struct selem_ac97 *s, int dir, struct helem_ac97 *c, long value)
-{
- int64_t n;
- if (c->max == c->min)
- return s->dir[dir].min;
- n = (int64_t) (value - c->min) * (s->dir[dir].max - s->dir[dir].min);
- return s->dir[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min);
-}
-
-static long from_user(struct selem_ac97 *s, int dir, struct helem_ac97 *c, long value)
-{
- int64_t n;
- if (s->dir[dir].max == s->dir[dir].min)
- return c->min;
- n = (int64_t) (value - s->dir[dir].min) * (c->max - c->min);
- return c->min + (n + (s->dir[dir].max - s->dir[dir].min) / 2) / (s->dir[dir].max - s->dir[dir].min);
-}
-
-static void update_ranges(struct selem_ac97 *s)
-{
- static unsigned int mask[2] = { SM_CAP_PVOLUME, SM_CAP_CVOLUME };
- static unsigned int gmask[2] = { SM_CAP_GVOLUME, SM_CAP_GVOLUME };
- unsigned int dir, ok_flag;
- struct list_head *pos;
- struct helem_ac97 *helem;
-
- for (dir = 0; dir < 2; dir++) {
- s->dir[dir].min = 0;
- s->dir[dir].max = 0;
- ok_flag = 0;
- list_for_each(pos, &s->helems) {
- helem = list_entry(pos, struct helem_ac97, list);
- printf("min = %li, max = %li\n", helem->min, helem->max);
- if (helem->caps & mask[dir]) {
- s->dir[dir].min = helem->min;
- s->dir[dir].max = helem->max;
- ok_flag = 1;
- break;
- }
- }
- if (ok_flag)
- continue;
- list_for_each(pos, &s->helems) {
- helem = list_entry(pos, struct helem_ac97, list);
- if (helem->caps & gmask[dir]) {
- s->dir[dir].min = helem->min;
- s->dir[dir].max = helem->max;
- break;
- }
- }
- }
-}
-
-/*
- * Simple Mixer Operations
- */
-
-static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
-
- switch (cmd) {
-
- case SM_OPS_IS_ACTIVE: {
- struct list_head *pos;
- struct helem_ac97 *helem;
- list_for_each(pos, &s->helems) {
- helem = list_entry(pos, struct helem_ac97, list);
- if (helem->inactive)
- return 0;
- }
- return 1;
- }
-
- case SM_OPS_IS_MONO:
- return chanmap_to_channels(s->dir[dir].chanmap) == 1;
-
- case SM_OPS_IS_CHANNEL:
- if (val > MAX_CHANNEL)
- return 0;
- return !!((1 << val) & s->dir[dir].chanmap);
-
- case SM_OPS_IS_ENUMERATED: {
- struct helem_ac97 *helem;
- helem = list_entry(s->helems.next, struct helem_ac97, list);
- return !!(helem->purpose == PURPOSE_ENUMLIST);
- }
-
- case SM_OPS_IS_ENUMCNT: {
- struct helem_ac97 *helem;
- helem = list_entry(s->helems.next, struct helem_ac97, list);
- return helem->max;
- }
-
- }
-
- return 1;
-}
-
-static int get_range_ops(snd_mixer_elem_t *elem, int dir,
- long *min, long *max)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
-
- *min = s->dir[dir].min;
- *max = s->dir[dir].max;
-
- return 0;
-}
-
-static int get_dB_range_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
- int dir ATTRIBUTE_UNUSED,
- long *min ATTRIBUTE_UNUSED,
- long *max ATTRIBUTE_UNUSED)
+int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask,
+ snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
{
- return -ENXIO;
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ return priv->ops.event(class, mask, helem, melem);
}
-static int set_range_ops(snd_mixer_elem_t *elem, int dir,
- long min, long max)
+int alsa_mixer_simple_init(snd_mixer_class_t *class)
{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
+ struct bclass_base_ops *ops;
int err;
-
- s->dir[dir].forced_range = 1;
- s->dir[dir].min = min;
- s->dir[dir].max = max;
- if ((err = selem_read(elem)) < 0)
- return err;
- return 0;
-}
-
-static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
- snd_mixer_selem_channel_id_t channel, long *value)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
-
- *value = s->dir[dir].vol[channel];
- return 0;
-}
-
-static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
- int dir ATTRIBUTE_UNUSED,
- snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
- long *value ATTRIBUTE_UNUSED)
-{
- return -ENXIO;
-}
-
-static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
- snd_mixer_selem_channel_id_t channel, int *value)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- *value = 0;
- return 0;
-}
-
-static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
- snd_mixer_selem_channel_id_t channel, long value)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- return 0;
-}
-
-static int set_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
- int dir ATTRIBUTE_UNUSED,
- snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
- long value ATTRIBUTE_UNUSED,
- int xdir ATTRIBUTE_UNUSED)
-{
- return -ENXIO;
-}
-
-static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
- snd_mixer_selem_channel_id_t channel, int value)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- int changed;
- return 0;
-}
-
-static int enum_item_name_ops(snd_mixer_elem_t *elem,
- unsigned int item,
- size_t maxlen, char *buf)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- return 0;
-}
-
-static int get_enum_item_ops(snd_mixer_elem_t *elem,
- snd_mixer_selem_channel_id_t channel,
- unsigned int *itemp)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- return 0;
-}
-
-static int set_enum_item_ops(snd_mixer_elem_t *elem,
- snd_mixer_selem_channel_id_t channel,
- unsigned int item)
-{
- struct selem_ac97 *s = snd_mixer_elem_get_private(elem);
- return 0;
-}
-
-static struct sm_elem_ops simple_ac97_ops = {
- .is = is_ops,
- .get_range = get_range_ops,
- .get_dB_range = get_dB_range_ops,
- .set_range = set_range_ops,
- .get_volume = get_volume_ops,
- .get_dB = get_dB_ops,
- .set_volume = set_volume_ops,
- .set_dB = set_dB_ops,
- .get_switch = get_switch_ops,
- .set_switch = set_switch_ops,
- .enum_item_name = enum_item_name_ops,
- .get_enum_item = get_enum_item_ops,
- .set_enum_item = set_enum_item_ops
-};
-
-/*
- * event handling
- */
-
-static int selem_read(snd_mixer_elem_t *elem)
-{
- printf("elem read: %p\n", elem);
- return 0;
-}
-
-static int simple_event_remove(snd_hctl_elem_t *helem,
- snd_mixer_elem_t *melem)
-{
- printf("event remove: %p\n", helem);
- return 0;
-}
-
-static void selem_free(snd_mixer_elem_t *elem)
-{
- struct selem_ac97 *simple = snd_mixer_elem_get_private(elem);
- struct helem_ac97 *hsimple;
- struct list_head *pos, *npos;
-
- if (simple->selem.id)
- snd_mixer_selem_id_free(simple->selem.id);
- list_for_each_safe(pos, npos, &simple->helems) {
- hsimple = list_entry(pos, struct helem_ac97, list);
- free(hsimple);
- }
- free(simple);
-}
-
-static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
-{
- int count;
- struct helem_selector *sel;
- snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
- const char *name = snd_hctl_elem_get_name(helem);
- unsigned int index = snd_hctl_elem_get_index(helem);
- snd_mixer_elem_t *melem;
- snd_mixer_selem_id_t *id;
- struct selem_ac97 *simple;
- struct helem_ac97 *hsimple;
- snd_ctl_elem_info_t *info;
- snd_ctl_elem_type_t ctype;
- unsigned long values;
- long min, max;
- int err, new = 0;
-
- snd_ctl_elem_info_alloca(&info);
- for (count = SELECTORS, sel = selectors; count > 0; count--, sel++) {
- if (sel->iface == iface && !strcmp(sel->name, name) && sel->index == index)
- break;
- }
- if (count == 0)
- return 0; /* ignore this helem */
- err = snd_hctl_elem_info(helem, info);
- if (err < 0)
- return err;
- ctype = snd_ctl_elem_info_get_type(info);
- values = snd_ctl_elem_info_get_count(info);
- switch (ctype) {
- case SND_CTL_ELEM_TYPE_ENUMERATED:
- min = 0;
- max = snd_ctl_elem_info_get_items(info);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER:
- min = snd_ctl_elem_info_get_min(info);
- max = snd_ctl_elem_info_get_max(info);
- break;
- default:
- min = max = 0;
- break;
- }
-
- printf("event add: %p, %p (%s)\n", helem, sel, name);
- if (snd_mixer_selem_id_malloc(&id))
- return -ENOMEM;
- hsimple = calloc(1, sizeof(*hsimple));
- if (hsimple == NULL) {
- snd_mixer_selem_id_free(id);
- return -ENOMEM;
- }
- switch (sel->purpose) {
- case PURPOSE_SWITCH:
- if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) {
- __invalid_type:
- snd_mixer_selem_id_free(id);
- return -EINVAL;
- }
- break;
- case PURPOSE_VOLUME:
- if (ctype != SND_CTL_ELEM_TYPE_INTEGER)
- goto __invalid_type;
- break;
- }
- hsimple->purpose = sel->purpose;
- hsimple->caps = sel->caps;
- hsimple->min = min;
- hsimple->max = max;
- snd_mixer_selem_id_set_name(id, sids[sel->sid].sname);
- snd_mixer_selem_id_set_index(id, sids[sel->sid].sindex);
- melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id);
- if (!melem) {
- simple = calloc(1, sizeof(*simple));
- if (!simple) {
- snd_mixer_selem_id_free(id);
- free(hsimple);
- return -ENOMEM;
- }
- simple->selem.id = id;
- simple->selem.ops = &simple_ac97_ops;
- INIT_LIST_HEAD(&simple->helems);
- simple->sid = sel->sid;
- err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE,
- sids[sel->sid].weight,
- simple, selem_free);
- if (err < 0) {
- snd_mixer_selem_id_free(id);
- free(hsimple);
- free(simple);
- return err;
- }
- new = 1;
- } else {
- simple = snd_mixer_elem_get_private(melem);
- snd_mixer_selem_id_free(id);
- }
- list_add_tail(&hsimple->list, &simple->helems);
- hsimple->inactive = snd_ctl_elem_info_is_inactive(info);
- err = snd_mixer_elem_attach(melem, helem);
+ err = mixer_simple_basic_dlopen(class, &ops);
if (err < 0)
- goto __error;
- simple->dir[0].chanmap |= sids[sel->sid].chanmap[0];
- simple->dir[1].chanmap |= sids[sel->sid].chanmap[1];
- simple->selem.caps |= hsimple->caps;
- update_ranges(simple);
-#if 0
- err = simple_update(melem);
- if (err < 0) {
- if (new)
- goto __error;
- return err;
- }
-#endif
- if (new)
- err = snd_mixer_elem_add(melem, class);
- else
- err = snd_mixer_elem_info(melem);
+ return 0;
+ err = ops->selreg(class, selectors, SELECTORS);
if (err < 0)
return err;
- err = selem_read(melem);
+ err = ops->sidreg(class, sids, SELECTORS);
if (err < 0)
return err;
- if (err)
- err = snd_mixer_elem_value(melem);
- return err;
- __error:
- if (new)
- snd_mixer_elem_free(melem);
- return -EINVAL;
- return 0;
-}
-
-int alsa_mixer_simple_event(snd_mixer_class_t *class, 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);
- if (err < 0)
- return err;
- }
- if (mask & SND_CTL_EVENT_MASK_INFO) {
- err = simple_event_remove(helem, melem);
- if (err < 0)
- return err;
- err = simple_event_add(class, helem);
- if (err < 0)
- return err;
- return 0;
- }
- if (mask & SND_CTL_EVENT_MASK_VALUE) {
- err = selem_read(melem);
- if (err < 0)
- return err;
- if (err) {
- err = snd_mixer_elem_value(melem);
- if (err < 0)
- return err;
- }
- }
return 0;
}
--- /dev/null
+/*
+ * Mixer Interface - HDA simple abstact module
+ * Copyright (c) 2005 by Jaroslav Kysela <perex@suse.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 "asoundlib.h"
+#include "mixer_abst.h"
+#include "sbase.h"
+
+static struct sm_elem_ops simple_hda_ops;
+
+struct melem_sids sids[] = {
+ {
+ .sid = SID_FRONT,
+ .sname = "Front",
+ .sindex = 0,
+ .weight = 1,
+ .chanmap = { 3, 0 },
+ .sops = &simple_hda_ops,
+ }
+};
+
+#define SELECTORS (sizeof(selectors)/sizeof(selectors[0]))
+
+struct helem_selector selectors[] = {
+ {
+ .iface = SND_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Playback Volume",
+ .index = 0,
+ .sid = SID_FRONT,
+ .purpose = PURPOSE_VOLUME,
+ .caps = SM_CAP_PVOLUME,
+ },
+ {
+ .iface = SND_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Playback Switch",
+ .index = 0,
+ .sid = SID_FRONT,
+ .purpose = PURPOSE_SWITCH,
+ .caps = SM_CAP_PSWITCH,
+ }
+};
+
+int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask,
+ snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
+{
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ return priv->ops.event(class, mask, helem, melem);
+}
+
+int alsa_mixer_simple_init(snd_mixer_class_t *class)
+{
+ struct bclass_base_ops *ops;
+ int err;
+
+ err = mixer_simple_basic_dlopen(class, &ops);
+ if (err < 0)
+ return 0;
+ err = ops->selreg(class, selectors, SELECTORS);
+ if (err < 0)
+ return err;
+ err = ops->sidreg(class, sids, SELECTORS);
+ if (err < 0)
+ return err;
+ return 0;
+}
--- /dev/null
+/*
+ * Mixer Interface - simple abstact module - base library
+ * Copyright (c) 2005 by Jaroslav Kysela <perex@suse.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 "asoundlib.h"
+#include "mixer_abst.h"
+#include "sbase.h"
+
+/*
+ * Prototypes
+ */
+
+static int selem_read(snd_mixer_elem_t *elem);
+
+/*
+ * Helpers
+ */
+
+static unsigned int chanmap_to_channels(unsigned int chanmap)
+{
+ unsigned int i, res;
+
+ for (i = 0, res = 0; i < MAX_CHANNEL; i++)
+ if (chanmap & (1 << i))
+ res++;
+ return res;
+}
+
+static long to_user(struct selem_base *s, int dir, struct helem_base *c, long value)
+{
+ int64_t n;
+ if (c->max == c->min)
+ return s->dir[dir].min;
+ n = (int64_t) (value - c->min) * (s->dir[dir].max - s->dir[dir].min);
+ return s->dir[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min);
+}
+
+static long from_user(struct selem_base *s, int dir, struct helem_base *c, long value)
+{
+ int64_t n;
+ if (s->dir[dir].max == s->dir[dir].min)
+ return c->min;
+ n = (int64_t) (value - s->dir[dir].min) * (c->max - c->min);
+ return c->min + (n + (s->dir[dir].max - s->dir[dir].min) / 2) / (s->dir[dir].max - s->dir[dir].min);
+}
+
+static void update_ranges(struct selem_base *s)
+{
+ static unsigned int mask[2] = { SM_CAP_PVOLUME, SM_CAP_CVOLUME };
+ static unsigned int gmask[2] = { SM_CAP_GVOLUME, SM_CAP_GVOLUME };
+ unsigned int dir, ok_flag;
+ struct list_head *pos;
+ struct helem_base *helem;
+
+ for (dir = 0; dir < 2; dir++) {
+ s->dir[dir].min = 0;
+ s->dir[dir].max = 0;
+ ok_flag = 0;
+ list_for_each(pos, &s->helems) {
+ helem = list_entry(pos, struct helem_base, list);
+ printf("min = %li, max = %li\n", helem->min, helem->max);
+ if (helem->caps & mask[dir]) {
+ s->dir[dir].min = helem->min;
+ s->dir[dir].max = helem->max;
+ ok_flag = 1;
+ break;
+ }
+ }
+ if (ok_flag)
+ continue;
+ list_for_each(pos, &s->helems) {
+ helem = list_entry(pos, struct helem_base, list);
+ if (helem->caps & gmask[dir]) {
+ s->dir[dir].min = helem->min;
+ s->dir[dir].max = helem->max;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Simple Mixer Operations
+ */
+
+static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+
+ switch (cmd) {
+
+ case SM_OPS_IS_ACTIVE: {
+ struct list_head *pos;
+ struct helem_base *helem;
+ list_for_each(pos, &s->helems) {
+ helem = list_entry(pos, struct helem_base, list);
+ if (helem->inactive)
+ return 0;
+ }
+ return 1;
+ }
+
+ case SM_OPS_IS_MONO:
+ return chanmap_to_channels(s->dir[dir].chanmap) == 1;
+
+ case SM_OPS_IS_CHANNEL:
+ if (val > MAX_CHANNEL)
+ return 0;
+ return !!((1 << val) & s->dir[dir].chanmap);
+
+ case SM_OPS_IS_ENUMERATED: {
+ struct helem_base *helem;
+ helem = list_entry(s->helems.next, struct helem_base, list);
+ return !!(helem->purpose == PURPOSE_ENUMLIST);
+ }
+
+ case SM_OPS_IS_ENUMCNT: {
+ struct helem_base *helem;
+ helem = list_entry(s->helems.next, struct helem_base, list);
+ return helem->max;
+ }
+
+ }
+
+ return 1;
+}
+
+static int get_range_ops(snd_mixer_elem_t *elem, int dir,
+ long *min, long *max)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+
+ *min = s->dir[dir].min;
+ *max = s->dir[dir].max;
+
+ return 0;
+}
+
+static int get_dB_range_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
+ int dir ATTRIBUTE_UNUSED,
+ long *min ATTRIBUTE_UNUSED,
+ long *max ATTRIBUTE_UNUSED)
+{
+ return -ENXIO;
+}
+
+static int set_range_ops(snd_mixer_elem_t *elem, int dir,
+ long min, long max)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ int err;
+
+ s->dir[dir].forced_range = 1;
+ s->dir[dir].min = min;
+ s->dir[dir].max = max;
+
+ if ((err = selem_read(elem)) < 0)
+ return err;
+ return 0;
+}
+
+static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
+ snd_mixer_selem_channel_id_t channel, long *value)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+
+ *value = s->dir[dir].vol[channel];
+ return 0;
+}
+
+static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
+ int dir ATTRIBUTE_UNUSED,
+ snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
+ long *value ATTRIBUTE_UNUSED)
+{
+ return -ENXIO;
+}
+
+static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
+ snd_mixer_selem_channel_id_t channel, int *value)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ *value = 0;
+ return 0;
+}
+
+static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
+ snd_mixer_selem_channel_id_t channel, long value)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ return 0;
+}
+
+static int set_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
+ int dir ATTRIBUTE_UNUSED,
+ snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
+ long value ATTRIBUTE_UNUSED,
+ int xdir ATTRIBUTE_UNUSED)
+{
+ return -ENXIO;
+}
+
+static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
+ snd_mixer_selem_channel_id_t channel, int value)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ int changed;
+ return 0;
+}
+
+static int enum_item_name_ops(snd_mixer_elem_t *elem,
+ unsigned int item,
+ size_t maxlen, char *buf)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ return 0;
+}
+
+static int get_enum_item_ops(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ unsigned int *itemp)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ return 0;
+}
+
+static int set_enum_item_ops(snd_mixer_elem_t *elem,
+ snd_mixer_selem_channel_id_t channel,
+ unsigned int item)
+{
+ struct selem_base *s = snd_mixer_elem_get_private(elem);
+ return 0;
+}
+
+static struct sm_elem_ops simple_ac97_ops = {
+ .is = is_ops,
+ .get_range = get_range_ops,
+ .get_dB_range = get_dB_range_ops,
+ .set_range = set_range_ops,
+ .get_volume = get_volume_ops,
+ .get_dB = get_dB_ops,
+ .set_volume = set_volume_ops,
+ .set_dB = set_dB_ops,
+ .get_switch = get_switch_ops,
+ .set_switch = set_switch_ops,
+ .enum_item_name = enum_item_name_ops,
+ .get_enum_item = get_enum_item_ops,
+ .set_enum_item = set_enum_item_ops
+};
+
+/*
+ * event handling
+ */
+
+static int selem_read(snd_mixer_elem_t *elem)
+{
+ printf("elem read: %p\n", elem);
+ return 0;
+}
+
+static int simple_event_remove(snd_hctl_elem_t *helem,
+ snd_mixer_elem_t *melem)
+{
+ printf("event remove: %p\n", helem);
+ return 0;
+}
+
+static void selem_free(snd_mixer_elem_t *elem)
+{
+ struct selem_base *simple = snd_mixer_elem_get_private(elem);
+ struct helem_base *hsimple;
+ struct list_head *pos, *npos;
+
+ if (simple->selem.id)
+ snd_mixer_selem_id_free(simple->selem.id);
+ list_for_each_safe(pos, npos, &simple->helems) {
+ hsimple = list_entry(pos, struct helem_base, list);
+ free(hsimple);
+ }
+ free(simple);
+}
+
+static int simple_event_add1(snd_mixer_class_t *class,
+ snd_hctl_elem_t *helem,
+ struct helem_selector *sel)
+{
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ int count;
+ snd_mixer_elem_t *melem;
+ snd_mixer_selem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ struct selem_base *simple;
+ struct helem_base *hsimple;
+ snd_ctl_elem_type_t ctype;
+ unsigned long values;
+ long min, max;
+ int err, new = 0;
+ struct list_head *pos;
+ struct bclass_sid *bsid;
+ struct melem_sids *sid;
+ unsigned int ui;
+
+ list_for_each(pos, &priv->sids) {
+ bsid = list_entry(pos, struct bclass_sid, list);
+ for (ui = 0; ui < bsid->count; ui++) {
+ if (bsid->sids[ui].sid == sel->sid) {
+ sid = &bsid->sids[ui];
+ goto __sid_ok;
+ }
+ }
+ }
+ return 0;
+
+ __sid_ok:
+ snd_ctl_elem_info_alloca(&info);
+ err = snd_hctl_elem_info(helem, info);
+ if (err < 0)
+ return err;
+ ctype = snd_ctl_elem_info_get_type(info);
+ values = snd_ctl_elem_info_get_count(info);
+ switch (ctype) {
+ case SND_CTL_ELEM_TYPE_ENUMERATED:
+ min = 0;
+ max = snd_ctl_elem_info_get_items(info);
+ break;
+ case SND_CTL_ELEM_TYPE_INTEGER:
+ min = snd_ctl_elem_info_get_min(info);
+ max = snd_ctl_elem_info_get_max(info);
+ break;
+ default:
+ min = max = 0;
+ break;
+ }
+
+ printf("event add: %p, %p (%s)\n", helem, sel, snd_hctl_elem_get_name(helem));
+ if (snd_mixer_selem_id_malloc(&id))
+ return -ENOMEM;
+ hsimple = calloc(1, sizeof(*hsimple));
+ if (hsimple == NULL) {
+ snd_mixer_selem_id_free(id);
+ return -ENOMEM;
+ }
+ switch (sel->purpose) {
+ case PURPOSE_SWITCH:
+ if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) {
+ __invalid_type:
+ snd_mixer_selem_id_free(id);
+ return -EINVAL;
+ }
+ break;
+ case PURPOSE_VOLUME:
+ if (ctype != SND_CTL_ELEM_TYPE_INTEGER)
+ goto __invalid_type;
+ break;
+ }
+ hsimple->purpose = sel->purpose;
+ hsimple->caps = sel->caps;
+ hsimple->min = min;
+ 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);
+ if (!melem) {
+ simple = calloc(1, sizeof(*simple));
+ if (!simple) {
+ snd_mixer_selem_id_free(id);
+ free(hsimple);
+ return -ENOMEM;
+ }
+ simple->selem.id = id;
+ simple->selem.ops = &simple_ac97_ops;
+ INIT_LIST_HEAD(&simple->helems);
+ simple->sid = sel->sid;
+ err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE,
+ sid->weight,
+ simple, selem_free);
+ if (err < 0) {
+ snd_mixer_selem_id_free(id);
+ free(hsimple);
+ free(simple);
+ return err;
+ }
+ new = 1;
+ } else {
+ simple = snd_mixer_elem_get_private(melem);
+ snd_mixer_selem_id_free(id);
+ }
+ list_add_tail(&hsimple->list, &simple->helems);
+ hsimple->inactive = snd_ctl_elem_info_is_inactive(info);
+ err = snd_mixer_elem_attach(melem, helem);
+ if (err < 0)
+ goto __error;
+ simple->dir[0].chanmap |= sid->chanmap[0];
+ simple->dir[1].chanmap |= sid->chanmap[1];
+ simple->selem.caps |= hsimple->caps;
+ update_ranges(simple);
+#if 0
+ err = simple_update(melem);
+ if (err < 0) {
+ if (new)
+ goto __error;
+ return err;
+ }
+#endif
+ if (new)
+ err = snd_mixer_elem_add(melem, class);
+ else
+ err = snd_mixer_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);
+ return err;
+ __error:
+ if (new)
+ snd_mixer_elem_free(melem);
+ return -EINVAL;
+}
+
+static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
+{
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ struct bclass_selector *sel;
+ struct helem_selector *hsel;
+ struct list_head *pos;
+ snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
+ const char *name = snd_hctl_elem_get_name(helem);
+ unsigned int index = snd_hctl_elem_get_index(helem);
+ unsigned int ui;
+ int err;
+
+ list_for_each(pos, &priv->selectors) {
+ sel = list_entry(pos, struct bclass_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);
+ if (err < 0)
+ return err; /* early exit? */
+ }
+ }
+ }
+ return 0;
+}
+
+int alsa_mixer_sbasic_event(snd_mixer_class_t *class, 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);
+ if (err < 0)
+ return err;
+ }
+ if (mask & SND_CTL_EVENT_MASK_INFO) {
+ err = simple_event_remove(helem, melem);
+ if (err < 0)
+ return err;
+ err = simple_event_add(class, helem);
+ if (err < 0)
+ return err;
+ return 0;
+ }
+ if (mask & SND_CTL_EVENT_MASK_VALUE) {
+ err = selem_read(melem);
+ if (err < 0)
+ return err;
+ if (err) {
+ err = snd_mixer_elem_value(melem);
+ if (err < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
+static void sbasic_cpriv_free(snd_mixer_class_t *class)
+{
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ struct bclass_selector *sel;
+ struct bclass_sid *sid;
+ struct list_head *pos, *pos1;
+
+ list_for_each_safe(pos, pos1, &priv->selectors) {
+ sel = list_entry(pos, struct bclass_selector, list);
+ free(sel);
+ }
+ list_for_each_safe(pos, pos1, &priv->sids) {
+ sid = list_entry(pos, struct bclass_sid, list);
+ free(sid);
+ }
+ free(priv);
+}
+
+void alsa_mixer_sbasic_initpriv(snd_mixer_class_t *class,
+ struct bclass_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);
+}
+
+int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class,
+ 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));
+
+ if (sel == NULL)
+ return -ENOMEM;
+ if (priv == NULL) {
+ priv = calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ free(sel);
+ return -ENOMEM;
+ }
+ }
+ sel->selectors = selectors;
+ sel->count = count;
+ list_add_tail(&sel->list, &priv->selectors);
+ return 0;
+}
+
+int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class,
+ 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));
+
+ if (sid == NULL)
+ return -ENOMEM;
+ if (priv == NULL) {
+ priv = calloc(1, sizeof(*priv));
+ if (priv == NULL) {
+ free(sid);
+ return -ENOMEM;
+ }
+ 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);
+ }
+ sid->sids = sids;
+ sid->count = count;
+ list_add(&sid->list, &priv->sids);
+ return 0;
+}
--- /dev/null
+/*
+ * Mixer Interface - simple abstact module - base library
+ * Copyright (c) 2005 by Jaroslav Kysela <perex@suse.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 __SMIXER_BASE_H
+
+#include "list.h"
+
+#define MAX_CHANNEL 6
+
+#define SID_MASTER 0
+#define SID_HEADPHONE 1
+#define SID_FRONT 2
+#define SID_PCM 3
+#define SID_CD 4
+
+struct melem_sids {
+ unsigned short sid;
+ const char *sname;
+ unsigned short sindex;
+ unsigned short weight;
+ unsigned int chanmap[2];
+ struct sm_elem_ops *sops;
+};
+
+#define PURPOSE_VOLUME 0
+#define PURPOSE_SWITCH 1
+#define PURPOSE_ENUMLIST 2
+
+struct helem_selector {
+ snd_ctl_elem_iface_t iface;
+ const char *name;
+ unsigned short index;
+ unsigned short sid;
+ unsigned short purpose;
+ unsigned short caps;
+};
+
+struct helem_base {
+ struct list_head list;
+ snd_hctl_elem_t *helem;
+ unsigned short purpose;
+ unsigned int caps;
+ unsigned int inactive: 1;
+ long min, max;
+ unsigned int count;
+};
+
+struct selem_base {
+ sm_selem_t selem;
+ struct list_head helems;
+ unsigned short sid;
+ struct {
+ unsigned int chanmap;
+ unsigned int forced_range: 1;
+ long min, max;
+ long vol[MAX_CHANNEL];
+ } dir[2];
+};
+
+struct bclass_selector {
+ struct list_head list;
+ struct helem_selector *selectors;
+ unsigned int count;
+};
+
+struct bclass_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,
+ struct helem_selector *selectors,
+ unsigned int count);
+ int (*sidreg)(snd_mixer_class_t *class,
+ struct melem_sids *sids,
+ unsigned int count);
+} bclass_base_ops_t;
+
+struct bclass_private {
+ struct list_head selectors;
+ struct list_head sids;
+ void *dl_sbase;
+ bclass_base_ops_t ops;
+};
+
+int mixer_simple_basic_dlopen(snd_mixer_class_t *class,
+ bclass_base_ops_t **ops);
+
+#endif /* __SMIXER_BASE_H */
--- /dev/null
+/*
+ * Mixer Interface - simple abstact module - base library (dlopen function)
+ * Copyright (c) 2005 by Jaroslav Kysela <perex@suse.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_abst.h"
+#include "sbase.h"
+
+#define SO_PATH PKGLIBDIR "/smixer"
+
+int mixer_simple_basic_dlopen(snd_mixer_class_t *class,
+ bclass_base_ops_t **ops)
+{
+ struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
+ const char *lib = "smixer-sbase.so";
+ void (*initpriv)(snd_mixer_class_t *class, struct bclass_private *priv);
+ char *xlib, *path;
+ void *h;
+ int initflag = 0;
+
+ if (priv == NULL) {
+ priv = calloc(1, sizeof(*priv));
+ if (priv == NULL)
+ return -ENOMEM;
+ initflag = 1;
+ }
+ path = getenv("ALSA_MIXER_SIMPLE_MODULES");
+ if (!path)
+ path = SO_PATH;
+ xlib = malloc(strlen(lib) + strlen(path) + 1 + 1);
+ if (xlib == NULL) {
+ if (initflag)
+ free(priv);
+ 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);
+ goto __error;
+ }
+ initpriv = dlsym(h, "alsa_mixer_sbasic_initpriv");
+ if (initpriv == NULL) {
+ SNDERR("Symbol 'alsa_mixer_sbasic_initpriv' was not found in '%s'", xlib);
+ goto __error;
+ }
+ priv->ops.event = dlsym(h, "alsa_mixer_sbasic_event");
+ if (priv->ops.event == NULL) {
+ SNDERR("Symbol 'alsa_mixer_sbasic_event' was not found in '%s'", xlib);
+ goto __error;
+ }
+ priv->ops.selreg = dlsym(h, "alsa_mixer_sbasic_selreg");
+ if (priv->ops.selreg == NULL) {
+ SNDERR("Symbol 'alsa_mixer_sbasic_selreg' was not found in '%s'", xlib);
+ goto __error;
+ }
+ priv->ops.sidreg = dlsym(h, "alsa_mixer_sbasic_sidreg");
+ if (priv->ops.sidreg == NULL) {
+ SNDERR("Symbol 'alsa_mixer_sbasic_sidreg' was not found in '%s'", xlib);
+ goto __error;
+ }
+ free(xlib);
+ if (initflag)
+ initpriv(class, priv);
+ priv->dl_sbase = h;
+ if (ops)
+ *ops = &priv->ops;
+ return 1;
+
+ __error:
+ if (initflag)
+ free(priv);
+ if (h == NULL)
+ snd_dlclose(h);
+ free(xlib);
+ return -ENXIO;
+}
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);
+
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;
char *xlib, *path;
void *h;
+ int err;
path = getenv("ALSA_MIXER_SIMPLE_MODULES");
if (!path)
free(xlib);
return -ENXIO;
}
+ init_func = dlsym(h, "alsa_mixer_simple_init");
+ if (init_func == NULL) {
+ SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib);
+ snd_dlclose(h);
+ free(xlib);
+ return -ENXIO;
+ }
free(xlib);
+ err = init_func(class);
+ if (err < 0) {
+ snd_dlclose(h);
+ return err;
+ }
snd_mixer_class_set_event(class, event_func);
priv->dlhandle = h;
return 1;
{
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)
}
/**
- * \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
+ * \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)
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 for basic abstraction
+ * \param class Mixer class
+ * \param private_data 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;
+}