Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 768b3526 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ALSA: PCM: User contol API implementation"

parents 13593eee cda3673c
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -453,6 +453,7 @@ struct snd_pcm_str {
#endif
	struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
	struct snd_kcontrol *vol_kctl; /* volume controls */
	struct snd_kcontrol *usr_kctl; /* user controls */
};

struct snd_pcm {
@@ -1173,4 +1174,28 @@ int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
			   unsigned long private_value,
			   struct snd_pcm_volume **info_ret);

/*
 * PCM User control API
 */
/* array element of usr elem */
struct snd_pcm_usr_elem {
	int val[128];
};

/* pp information; retrieved via snd_kcontrol_chip() */
struct snd_pcm_usr {
	struct snd_pcm *pcm;	/* assigned PCM instance */
	int stream;		/* PLAYBACK or CAPTURE */
	struct snd_kcontrol *kctl;
	const struct snd_pcm_usr_elem *usr;
	int max_length;
	void *private_data;	/* optional: private data pointer */
};

int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
			 const struct snd_pcm_usr_elem *usr,
			 int max_length, int max_control_str_len,
			 unsigned long private_value,
			 struct snd_pcm_usr **info_ret);

#endif /* __SOUND_PCM_H */
+4 −0
Original line number Diff line number Diff line
@@ -1126,6 +1126,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
			snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl);
			pcm->streams[cidx].vol_kctl = NULL;
		}
		if (pcm->streams[cidx].usr_kctl) {
			snd_ctl_remove(pcm->card, pcm->streams[cidx].usr_kctl);
			pcm->streams[cidx].usr_kctl = NULL;
		}
	}
	mutex_unlock(&pcm->open_mutex);
 unlock:
+93 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <sound/timer.h>

#define STRING_LENGTH_OF_INT 12
#define MAX_USR_CTRL_CNT 128

/*
 * fill ring buffer with silence
@@ -2699,3 +2700,95 @@ int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
	return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);

static int pcm_usr_ctl_info(struct snd_kcontrol *kcontrol,
			    struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = MAX_USR_CTRL_CNT;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = INT_MAX;
	return 0;
}

static void pcm_usr_ctl_private_free(struct snd_kcontrol *kcontrol)
{
	struct snd_pcm_usr *info = snd_kcontrol_chip(kcontrol);
	info->pcm->streams[info->stream].usr_kctl = NULL;
	kfree(info);
}

/**
 * snd_pcm_add_usr_ctls - create user control elements
 * @pcm: the assigned PCM instance
 * @stream: stream direction
 * @max_length: the max length of the user parameter of stream
 * @private_value: the value passed to each kcontrol's private_value field
 * @info_ret: store struct snd_pcm_usr instance if non-NULL
 *
 * Create usr control elements assigned to the given PCM stream(s).
 * Returns zero if succeed, or a negative error value.
 */
int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
			 const struct snd_pcm_usr_elem *usr,
			 int max_length, int max_kctrl_str_len,
			 unsigned long private_value,
			 struct snd_pcm_usr **info_ret)
{
	struct snd_pcm_usr *info;
	struct snd_kcontrol_new knew = {
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = pcm_usr_ctl_info,
	};
	int err;
	char *buf;

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
		pr_err("%s: snd_pcm_usr alloc failed\n", __func__);
		return -ENOMEM;
	}
	info->pcm = pcm;
	info->stream = stream;
	info->usr = usr;
	info->max_length = max_length;
	buf = kzalloc(max_kctrl_str_len, GFP_KERNEL);
	if (!buf) {
		pr_err("%s: buffer allocation failed\n", __func__);
		kfree(info);
		return -ENOMEM;
	}
	knew.name = buf;
	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
		snprintf(buf, max_kctrl_str_len, "%s %d %s",
			"Playback", pcm->device, "User kcontrol");
	else
		snprintf(buf, max_kctrl_str_len, "%s %d %s",
			"Capture", pcm->device, "User kcontrol");
	knew.device = pcm->device;
	knew.count = pcm->streams[stream].substream_count;
	knew.private_value = private_value;
	info->kctl = snd_ctl_new1(&knew, info);
	if (!info->kctl) {
		kfree(info);
		kfree(knew.name);
		pr_err("%s: snd_ctl_new failed\n", __func__);
		return -ENOMEM;
	}
	info->kctl->private_free = pcm_usr_ctl_private_free;
	err = snd_ctl_add(pcm->card, info->kctl);
	if (err < 0) {
		kfree(info);
		kfree(knew.name);
		pr_err("%s: snd_ctl_add failed:%d\n", __func__,
			err);
		return -ENOMEM;
	}
	pcm->streams[stream].usr_kctl = info->kctl;
	if (info_ret)
		*info_ret = info;
	kfree(knew.name);
	return 0;
}
EXPORT_SYMBOL(snd_pcm_add_usr_ctls);