sound/core/vmaster.c

Source file repositories/reference/linux-study-clean/sound/core/vmaster.c

File Facts

System
Linux kernel
Corpus path
sound/core/vmaster.c
Extension
.c
Size
15204 bytes
Lines
551
Domain
Driver Families
Bucket
sound/core
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct link_ctl_info {
	snd_ctl_elem_type_t type; /* value type */
	int count;		/* item count */
	int min_val, max_val;	/* min, max values */
};

/*
 * link master - this contains a list of follower controls that are
 * identical types, i.e. info returns the same value type and value
 * ranges, but may have different number of counts.
 *
 * The master control is so far only mono volume/switch for simplicity.
 * The same value will be applied to all followers.
 */
struct link_master {
	struct list_head followers;
	struct link_ctl_info info;
	int val;		/* the master value */
	unsigned int tlv[4];
	void (*hook)(void *private_data, int);
	void *hook_private_data;
};

/*
 * link follower - this contains a follower control element
 *
 * It fakes the control callbacks with additional attenuation by the
 * master control.  A follower may have either one or two channels.
 */

struct link_follower {
	struct list_head list;
	struct link_master *master;
	struct link_ctl_info info;
	int vals[2];		/* current values */
	unsigned int flags;
	struct snd_kcontrol *kctl; /* original kcontrol pointer */
	struct snd_kcontrol follower; /* the copy of original control entry */
};

static int follower_update(struct link_follower *follower)
{
	int err, ch;
	struct snd_ctl_elem_value *uctl __free(kfree) =
		kzalloc_obj(*uctl);

	if (!uctl)
		return -ENOMEM;
	uctl->id = follower->follower.id;
	err = follower->follower.get(&follower->follower, uctl);
	if (err < 0)
		return err;
	for (ch = 0; ch < follower->info.count; ch++)
		follower->vals[ch] = uctl->value.integer.value[ch];
	return 0;
}

/* get the follower ctl info and save the initial values */
static int follower_init(struct link_follower *follower)
{
	int err;

	if (follower->info.count) {
		/* already initialized */
		if (follower->flags & SND_CTL_FOLLOWER_NEED_UPDATE)
			return follower_update(follower);
		return 0;
	}

	struct snd_ctl_elem_info *uinfo __free(kfree) =
		kmalloc_obj(*uinfo);
	if (!uinfo)
		return -ENOMEM;
	uinfo->id = follower->follower.id;
	err = follower->follower.info(&follower->follower, uinfo);
	if (err < 0)
		return err;
	follower->info.type = uinfo->type;
	follower->info.count = uinfo->count;
	if (follower->info.count > 2  ||
	    (follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
	     follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
		pr_err("ALSA: vmaster: invalid follower element\n");
		return -EINVAL;
	}
	follower->info.min_val = uinfo->value.integer.min;
	follower->info.max_val = uinfo->value.integer.max;

	return follower_update(follower);
}

Annotation

Implementation Notes