Blame modules/mixer/simple/sbase.c

Packit 4a16fb
/*
Packit 4a16fb
 *  Mixer Interface - simple abstact module - base library
Packit 4a16fb
 *  Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
Packit 4a16fb
 *
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
#include <stdio.h>
Packit 4a16fb
#include <stdlib.h>
Packit 4a16fb
#include <unistd.h>
Packit 4a16fb
#include <string.h>
Packit 4a16fb
#include <fcntl.h>
Packit 4a16fb
#include <sys/ioctl.h>
Packit 4a16fb
#include <math.h>
Packit 4a16fb
#include "asoundlib.h"
Packit 4a16fb
#include "mixer_abst.h"
Packit 4a16fb
#include "sbase.h"
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Prototypes
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
static int selem_read(snd_mixer_elem_t *elem);
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Helpers
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
static unsigned int chanmap_to_channels(unsigned int chanmap)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int i, res;
Packit 4a16fb
	
Packit 4a16fb
	for (i = 0, res = 0; i < MAX_CHANNEL; i++)
Packit 4a16fb
		if (chanmap & (1 << i))
Packit 4a16fb
			res++;
Packit 4a16fb
	return res;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
#if 0
Packit 4a16fb
static long to_user(struct selem_base *s, int dir, struct helem_base *c, long value)
Packit 4a16fb
{
Packit 4a16fb
	int64_t n;
Packit 4a16fb
	if (c->max == c->min)
Packit 4a16fb
		return s->dir[dir].min;
Packit 4a16fb
	n = (int64_t) (value - c->min) * (s->dir[dir].max - s->dir[dir].min);
Packit 4a16fb
	return s->dir[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static long from_user(struct selem_base *s, int dir, struct helem_base *c, long value)
Packit 4a16fb
{ 
Packit 4a16fb
        int64_t n;
Packit 4a16fb
	if (s->dir[dir].max == s->dir[dir].min)
Packit 4a16fb
		return c->min;
Packit 4a16fb
        n = (int64_t) (value - s->dir[dir].min) * (c->max - c->min);
Packit 4a16fb
	return c->min + (n + (s->dir[dir].max - s->dir[dir].min) / 2) / (s->dir[dir].max - s->dir[dir].min);
Packit 4a16fb
}
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
static void update_ranges(struct selem_base *s)
Packit 4a16fb
{
Packit 4a16fb
	static unsigned int mask[2] = { SM_CAP_PVOLUME, SM_CAP_CVOLUME };
Packit 4a16fb
	static unsigned int gmask[2] = { SM_CAP_GVOLUME, SM_CAP_GVOLUME };
Packit 4a16fb
	unsigned int dir, ok_flag;
Packit 4a16fb
	struct list_head *pos;
Packit 4a16fb
	struct helem_base *helem;
Packit 4a16fb
	
Packit 4a16fb
	for (dir = 0; dir < 2; dir++) {
Packit 4a16fb
		s->dir[dir].min = 0;
Packit 4a16fb
		s->dir[dir].max = 0;
Packit 4a16fb
		ok_flag = 0;
Packit 4a16fb
		list_for_each(pos, &s->helems) {
Packit 4a16fb
			helem = list_entry(pos, struct helem_base, list);
Packit 4a16fb
			printf("min = %li, max = %li\n", helem->min, helem->max);
Packit 4a16fb
			if (helem->caps & mask[dir]) {
Packit 4a16fb
				s->dir[dir].min = helem->min;
Packit 4a16fb
				s->dir[dir].max = helem->max;
Packit 4a16fb
				ok_flag = 1;
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
		if (ok_flag)
Packit 4a16fb
			continue;
Packit 4a16fb
		list_for_each(pos, &s->helems) {
Packit 4a16fb
			helem = list_entry(pos, struct helem_base, list);
Packit 4a16fb
			if (helem->caps & gmask[dir]) {
Packit 4a16fb
				s->dir[dir].min = helem->min;
Packit 4a16fb
				s->dir[dir].max = helem->max;
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Simple Mixer Operations
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
Packit 4a16fb
{
Packit 4a16fb
	struct selem_base *s = snd_mixer_elem_get_private(elem);
Packit 4a16fb
Packit 4a16fb
	switch (cmd) {
Packit 4a16fb
Packit 4a16fb
	case SM_OPS_IS_ACTIVE: {
Packit 4a16fb
		struct list_head *pos;
Packit 4a16fb
		struct helem_base *helem;
Packit 4a16fb
		list_for_each(pos, &s->helems) {
Packit 4a16fb
			helem = list_entry(pos, struct helem_base, list);
Packit 4a16fb
			if (helem->inactive)
Packit 4a16fb
				return 0;
Packit 4a16fb
		}
Packit 4a16fb
		return 1;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	case SM_OPS_IS_MONO:
Packit 4a16fb
		return chanmap_to_channels(s->dir[dir].chanmap) == 1;
Packit 4a16fb
Packit 4a16fb
	case SM_OPS_IS_CHANNEL:
Packit 4a16fb
		if (val > MAX_CHANNEL)
Packit 4a16fb
			return 0;
Packit 4a16fb
		return !!((1 << val) & s->dir[dir].chanmap);
Packit 4a16fb
Packit 4a16fb
	case SM_OPS_IS_ENUMERATED: {
Packit 4a16fb
		struct helem_base *helem;
Packit 4a16fb
		helem = list_entry(s->helems.next, struct helem_base, list);
Packit 4a16fb
		return !!(helem->purpose == PURPOSE_ENUMLIST);
Packit 4a16fb
	}
Packit 4a16fb
	
Packit 4a16fb
	case SM_OPS_IS_ENUMCNT: {
Packit 4a16fb
		struct helem_base *helem;
Packit 4a16fb
		helem = list_entry(s->helems.next, struct helem_base, list);
Packit 4a16fb
		return helem->max;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	}
Packit 4a16fb
	
Packit 4a16fb
	return 1;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_range_ops(snd_mixer_elem_t *elem, int dir,
Packit 4a16fb
			 long *min, long *max)
Packit 4a16fb
{
Packit 4a16fb
	struct selem_base *s = snd_mixer_elem_get_private(elem);
Packit 4a16fb
	
Packit 4a16fb
	*min = s->dir[dir].min;
Packit 4a16fb
	*max = s->dir[dir].max;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_dB_range_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			    int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
			    long *min ATTRIBUTE_UNUSED,
Packit 4a16fb
			    long *max ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENXIO;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int set_range_ops(snd_mixer_elem_t *elem, int dir,
Packit 4a16fb
			 long min, long max)
Packit 4a16fb
{
Packit 4a16fb
	struct selem_base *s = snd_mixer_elem_get_private(elem);
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	s->dir[dir].forced_range = 1;
Packit 4a16fb
	s->dir[dir].min = min;
Packit 4a16fb
	s->dir[dir].max = max;
Packit 4a16fb
	
Packit 4a16fb
	if ((err = selem_read(elem)) < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
Packit 4a16fb
			  snd_mixer_selem_channel_id_t channel, long *value)
Packit 4a16fb
{
Packit 4a16fb
	struct selem_base *s = snd_mixer_elem_get_private(elem);
Packit 4a16fb
	
Packit 4a16fb
	*value = s->dir[dir].vol[channel];
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
		      int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
		      snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
		      long *value ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENXIO;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_switch_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			  int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
			  snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
			  int *value)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem); */
Packit 4a16fb
	*value = 0;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int set_volume_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			  int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
			  snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
			  long value ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem); */
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int set_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
		      int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
		      snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
		      long value ATTRIBUTE_UNUSED,
Packit 4a16fb
		      int xdir ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENXIO;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int set_switch_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			  int dir ATTRIBUTE_UNUSED,
Packit 4a16fb
			  snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
			  int value ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem); */
Packit 4a16fb
	/* int changed; */
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int enum_item_name_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			      unsigned int item ATTRIBUTE_UNUSED,
Packit 4a16fb
			      size_t maxlen ATTRIBUTE_UNUSED,
Packit 4a16fb
			      char *buf ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem);*/
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_enum_item_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			     snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
			     unsigned int *itemp ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem); */
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int set_enum_item_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
Packit 4a16fb
			     snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
Packit 4a16fb
			     unsigned int item ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	/* struct selem_base *s = snd_mixer_elem_get_private(elem); */
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static struct sm_elem_ops simple_ac97_ops = {
Packit 4a16fb
	.is		= is_ops,
Packit 4a16fb
	.get_range	= get_range_ops,
Packit 4a16fb
	.get_dB_range	= get_dB_range_ops,
Packit 4a16fb
	.set_range	= set_range_ops,
Packit 4a16fb
	.get_volume	= get_volume_ops,
Packit 4a16fb
	.get_dB		= get_dB_ops,
Packit 4a16fb
	.set_volume	= set_volume_ops,
Packit 4a16fb
	.set_dB		= set_dB_ops,
Packit 4a16fb
	.get_switch	= get_switch_ops,
Packit 4a16fb
	.set_switch	= set_switch_ops,
Packit 4a16fb
	.enum_item_name	= enum_item_name_ops,
Packit 4a16fb
	.get_enum_item	= get_enum_item_ops,
Packit 4a16fb
	.set_enum_item	= set_enum_item_ops
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * event handling
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
static int selem_read(snd_mixer_elem_t *elem)
Packit 4a16fb
{
Packit 4a16fb
	printf("elem read: %p\n", elem);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int simple_event_remove(snd_hctl_elem_t *helem,
Packit 4a16fb
			       snd_mixer_elem_t *melem ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	printf("event remove: %p\n", helem);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void selem_free(snd_mixer_elem_t *elem)
Packit 4a16fb
{
Packit 4a16fb
	struct selem_base *simple = snd_mixer_elem_get_private(elem);
Packit 4a16fb
	struct helem_base *hsimple;
Packit 4a16fb
	struct list_head *pos, *npos;
Packit 4a16fb
Packit 4a16fb
	if (simple->selem.id)
Packit 4a16fb
		snd_mixer_selem_id_free(simple->selem.id);
Packit 4a16fb
	list_for_each_safe(pos, npos, &simple->helems) {
Packit 4a16fb
		hsimple = list_entry(pos, struct helem_base, list);
Packit 4a16fb
		free(hsimple);
Packit 4a16fb
	}
Packit 4a16fb
	free(simple);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int simple_event_add1(snd_mixer_class_t *class,
Packit 4a16fb
			     snd_hctl_elem_t *helem,
Packit 4a16fb
			     struct helem_selector *sel)
Packit 4a16fb
{
Packit 4a16fb
	struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
Packit 4a16fb
	snd_mixer_elem_t *melem;
Packit 4a16fb
	snd_mixer_selem_id_t *id;
Packit 4a16fb
	snd_ctl_elem_info_t *info;
Packit 4a16fb
	struct selem_base *simple;
Packit 4a16fb
	struct helem_base *hsimple;
Packit 4a16fb
	snd_ctl_elem_type_t ctype;
Packit 4a16fb
	long min, max;
Packit 4a16fb
	int err, new = 0;
Packit 4a16fb
	struct list_head *pos;
Packit 4a16fb
	struct bclass_sid *bsid;
Packit 4a16fb
	struct melem_sids *sid;
Packit 4a16fb
	unsigned int ui;
Packit 4a16fb
	
Packit 4a16fb
	list_for_each(pos, &priv->sids) {
Packit 4a16fb
		bsid = list_entry(pos, struct bclass_sid, list);
Packit 4a16fb
		for (ui = 0; ui < bsid->count; ui++) {
Packit 4a16fb
			if (bsid->sids[ui].sid == sel->sid) {
Packit 4a16fb
				sid = &bsid->sids[ui];
Packit 4a16fb
				goto __sid_ok;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
Packit 4a16fb
      __sid_ok:
Packit 4a16fb
	snd_ctl_elem_info_alloca(&info;;
Packit 4a16fb
	err = snd_hctl_elem_info(helem, info);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	ctype = snd_ctl_elem_info_get_type(info);
Packit 4a16fb
	switch (ctype) {
Packit 4a16fb
	case SND_CTL_ELEM_TYPE_ENUMERATED:
Packit 4a16fb
		min = 0;
Packit 4a16fb
		max = snd_ctl_elem_info_get_items(info);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_CTL_ELEM_TYPE_INTEGER:
Packit 4a16fb
		min = snd_ctl_elem_info_get_min(info);
Packit 4a16fb
		max = snd_ctl_elem_info_get_max(info);
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		min = max = 0;
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	
Packit 4a16fb
	printf("event add: %p, %p (%s)\n", helem, sel, snd_hctl_elem_get_name(helem));
Packit 4a16fb
	if (snd_mixer_selem_id_malloc(&id))
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	hsimple = calloc(1, sizeof(*hsimple));
Packit 4a16fb
	if (hsimple == NULL) {
Packit 4a16fb
		snd_mixer_selem_id_free(id);
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
	switch (sel->purpose) {
Packit 4a16fb
	case PURPOSE_SWITCH:
Packit 4a16fb
		if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) {
Packit 4a16fb
		      __invalid_type:
Packit 4a16fb
		      	snd_mixer_selem_id_free(id);
Packit 4a16fb
			free(hsimple);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		break;
Packit 4a16fb
	case PURPOSE_VOLUME:
Packit 4a16fb
		if (ctype != SND_CTL_ELEM_TYPE_INTEGER)
Packit 4a16fb
			goto __invalid_type;
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	hsimple->purpose = sel->purpose;
Packit 4a16fb
	hsimple->caps = sel->caps;
Packit 4a16fb
	hsimple->min = min;
Packit 4a16fb
	hsimple->max = max;
Packit 4a16fb
	snd_mixer_selem_id_set_name(id, sid->sname);
Packit 4a16fb
	snd_mixer_selem_id_set_index(id, sid->sindex);
Packit 4a16fb
	melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id);
Packit 4a16fb
	if (!melem) {
Packit 4a16fb
		simple = calloc(1, sizeof(*simple));
Packit 4a16fb
		if (!simple) {
Packit 4a16fb
			snd_mixer_selem_id_free(id);
Packit 4a16fb
			free(hsimple);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
		simple->selem.id = id;
Packit 4a16fb
		simple->selem.ops = &simple_ac97_ops;
Packit 4a16fb
		INIT_LIST_HEAD(&simple->helems);
Packit 4a16fb
		simple->sid = sel->sid;
Packit 4a16fb
		err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE,
Packit 4a16fb
					 sid->weight,
Packit 4a16fb
					 simple, selem_free);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			snd_mixer_selem_id_free(id);
Packit 4a16fb
			free(hsimple);
Packit 4a16fb
			free(simple);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		new = 1;
Packit 4a16fb
	} else {
Packit 4a16fb
		simple = snd_mixer_elem_get_private(melem);
Packit 4a16fb
		snd_mixer_selem_id_free(id);
Packit 4a16fb
	}
Packit 4a16fb
	list_add_tail(&hsimple->list, &simple->helems);
Packit 4a16fb
	hsimple->inactive = snd_ctl_elem_info_is_inactive(info);
Packit 4a16fb
	err = snd_mixer_elem_attach(melem, helem);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		goto __error;
Packit 4a16fb
	simple->dir[0].chanmap |= sid->chanmap[0];
Packit 4a16fb
	simple->dir[1].chanmap |= sid->chanmap[1];
Packit 4a16fb
	simple->selem.caps |= hsimple->caps;
Packit 4a16fb
	update_ranges(simple);
Packit 4a16fb
#if 0
Packit 4a16fb
	err = simple_update(melem);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		if (new)
Packit 4a16fb
			goto __error;
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
#endif
Packit 4a16fb
	if (new)
Packit 4a16fb
		err = snd_mixer_elem_add(melem, class);
Packit 4a16fb
	else
Packit 4a16fb
		err = snd_mixer_elem_info(melem);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = selem_read(melem);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	if (err)
Packit 4a16fb
		err = snd_mixer_elem_value(melem);
Packit 4a16fb
	return err;
Packit 4a16fb
      __error:
Packit 4a16fb
      	if (new)
Packit 4a16fb
      		snd_mixer_elem_free(melem);
Packit 4a16fb
      	return -EINVAL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
Packit 4a16fb
{
Packit 4a16fb
	struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
Packit 4a16fb
	struct bclass_selector *sel;
Packit 4a16fb
	struct helem_selector *hsel;
Packit 4a16fb
	struct list_head *pos;
Packit 4a16fb
	snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
Packit 4a16fb
	const char *name = snd_hctl_elem_get_name(helem);
Packit 4a16fb
	unsigned int index = snd_hctl_elem_get_index(helem);
Packit 4a16fb
	unsigned int ui;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, &priv->selectors) {
Packit 4a16fb
		sel = list_entry(pos, struct bclass_selector, list);
Packit 4a16fb
		for (ui = 0; ui < sel->count; ui++) {
Packit 4a16fb
			hsel = &sel->selectors[ui];
Packit 4a16fb
			if (hsel->iface == iface && !strcmp(hsel->name, name) && hsel->index == index) {
Packit 4a16fb
				err = simple_event_add1(class, helem, hsel);
Packit 4a16fb
				if (err < 0)
Packit 4a16fb
					return err;	/* early exit? */
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask,
Packit 4a16fb
			    snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
	if (mask == SND_CTL_EVENT_MASK_REMOVE)
Packit 4a16fb
		return simple_event_remove(helem, melem);
Packit 4a16fb
	if (mask & SND_CTL_EVENT_MASK_ADD) {
Packit 4a16fb
		err = simple_event_add(class, helem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	if (mask & SND_CTL_EVENT_MASK_INFO) {
Packit 4a16fb
		err = simple_event_remove(helem, melem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		err = simple_event_add(class, helem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		return 0;
Packit 4a16fb
	}
Packit 4a16fb
	if (mask & SND_CTL_EVENT_MASK_VALUE) {
Packit 4a16fb
		err = selem_read(melem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (err) {
Packit 4a16fb
			err = snd_mixer_elem_value(melem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void sbasic_cpriv_free(snd_mixer_class_t *class)
Packit 4a16fb
{
Packit 4a16fb
	struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
Packit 4a16fb
	struct bclass_selector *sel;
Packit 4a16fb
	struct bclass_sid *sid;
Packit 4a16fb
	struct list_head *pos, *pos1;
Packit 4a16fb
Packit 4a16fb
	list_for_each_safe(pos, pos1, &priv->selectors) {
Packit 4a16fb
		sel = list_entry(pos, struct bclass_selector, list);
Packit 4a16fb
		free(sel);
Packit 4a16fb
	}
Packit 4a16fb
	list_for_each_safe(pos, pos1, &priv->sids) {
Packit 4a16fb
		sid = list_entry(pos, struct bclass_sid, list);
Packit 4a16fb
		free(sid);
Packit 4a16fb
	}
Packit 4a16fb
	free(priv);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void alsa_mixer_sbasic_initpriv(snd_mixer_class_t *class,
Packit 4a16fb
				struct bclass_private *priv)
Packit 4a16fb
{
Packit 4a16fb
	INIT_LIST_HEAD(&priv->selectors);
Packit 4a16fb
	INIT_LIST_HEAD(&priv->sids);
Packit 4a16fb
	snd_mixer_sbasic_set_private(class, priv);
Packit 4a16fb
	snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class,
Packit 4a16fb
			     struct helem_selector *selectors,
Packit 4a16fb
			     unsigned int count)
Packit 4a16fb
{
Packit 4a16fb
	struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
Packit 4a16fb
	struct bclass_selector *sel = calloc(1, sizeof(*sel));
Packit 4a16fb
Packit 4a16fb
	if (sel == NULL)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	if (priv == NULL) {
Packit 4a16fb
		priv = calloc(1, sizeof(*priv));
Packit 4a16fb
		if (priv == NULL) {
Packit 4a16fb
			free(sel);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	sel->selectors = selectors;
Packit 4a16fb
	sel->count = count;
Packit 4a16fb
	list_add_tail(&sel->list, &priv->selectors);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class,
Packit 4a16fb
			     struct melem_sids *sids,
Packit 4a16fb
			     unsigned int count)
Packit 4a16fb
{
Packit 4a16fb
	struct bclass_private *priv = snd_mixer_sbasic_get_private(class);
Packit 4a16fb
	struct bclass_sid *sid = calloc(1, sizeof(*sid));
Packit 4a16fb
Packit 4a16fb
	if (sid == NULL)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	if (priv == NULL) {
Packit 4a16fb
		priv = calloc(1, sizeof(*priv));
Packit 4a16fb
		if (priv == NULL) {
Packit 4a16fb
			free(sid);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
		INIT_LIST_HEAD(&priv->selectors);
Packit 4a16fb
		INIT_LIST_HEAD(&priv->sids);
Packit 4a16fb
		snd_mixer_sbasic_set_private(class, priv);
Packit 4a16fb
		snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free);
Packit 4a16fb
	}
Packit 4a16fb
	sid->sids = sids;
Packit 4a16fb
	sid->count = count;
Packit 4a16fb
	list_add(&sid->list, &priv->sids);
Packit 4a16fb
	return 0;
Packit 4a16fb
}