cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

audio_helper.c (4878B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Greybus Audio Sound SoC helper APIs
      4 */
      5
      6#include <linux/debugfs.h>
      7#include <sound/core.h>
      8#include <sound/soc.h>
      9#include <sound/soc-dapm.h>
     10#include "audio_helper.h"
     11
     12#define gbaudio_dapm_for_each_direction(dir) \
     13	for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
     14		(dir)++)
     15
     16static void gbaudio_dapm_link_dai_widget(struct snd_soc_dapm_widget *dai_w,
     17					 struct snd_soc_card *card)
     18{
     19	struct snd_soc_dapm_widget *w;
     20	struct snd_soc_dapm_widget *src, *sink;
     21	struct snd_soc_dai *dai = dai_w->priv;
     22
     23	/* ...find all widgets with the same stream and link them */
     24	list_for_each_entry(w, &card->widgets, list) {
     25		if (w->dapm != dai_w->dapm)
     26			continue;
     27
     28		switch (w->id) {
     29		case snd_soc_dapm_dai_in:
     30		case snd_soc_dapm_dai_out:
     31			continue;
     32		default:
     33			break;
     34		}
     35
     36		if (!w->sname || !strstr(w->sname, dai_w->sname))
     37			continue;
     38
     39		/*
     40		 * check if widget is already linked,
     41		 * if (w->linked)
     42		 *	return;
     43		 */
     44
     45		if (dai_w->id == snd_soc_dapm_dai_in) {
     46			src = dai_w;
     47			sink = w;
     48		} else {
     49			src = w;
     50			sink = dai_w;
     51		}
     52		dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
     53		/* Add the DAPM path and set widget's linked status
     54		 * snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
     55		 * w->linked = 1;
     56		 */
     57	}
     58}
     59
     60int gbaudio_dapm_link_component_dai_widgets(struct snd_soc_card *card,
     61					    struct snd_soc_dapm_context *dapm)
     62{
     63	struct snd_soc_dapm_widget *dai_w;
     64
     65	/* For each DAI widget... */
     66	list_for_each_entry(dai_w, &card->widgets, list) {
     67		if (dai_w->dapm != dapm)
     68			continue;
     69		switch (dai_w->id) {
     70		case snd_soc_dapm_dai_in:
     71		case snd_soc_dapm_dai_out:
     72			break;
     73		default:
     74			continue;
     75		}
     76		gbaudio_dapm_link_dai_widget(dai_w, card);
     77	}
     78
     79	return 0;
     80}
     81
     82static void gbaudio_dapm_free_path(struct snd_soc_dapm_path *path)
     83{
     84	list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
     85	list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
     86	list_del(&path->list_kcontrol);
     87	list_del(&path->list);
     88	kfree(path);
     89}
     90
     91static void gbaudio_dapm_free_widget(struct snd_soc_dapm_widget *w)
     92{
     93	struct snd_soc_dapm_path *p, *next_p;
     94	enum snd_soc_dapm_direction dir;
     95
     96	list_del(&w->list);
     97	/*
     98	 * remove source and sink paths associated to this widget.
     99	 * While removing the path, remove reference to it from both
    100	 * source and sink widgets so that path is removed only once.
    101	 */
    102	gbaudio_dapm_for_each_direction(dir) {
    103		snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
    104			gbaudio_dapm_free_path(p);
    105	}
    106
    107	kfree(w->kcontrols);
    108	kfree_const(w->name);
    109	kfree_const(w->sname);
    110	kfree(w);
    111}
    112
    113int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
    114			       const struct snd_soc_dapm_widget *widget,
    115			       int num)
    116{
    117	int i;
    118	struct snd_soc_dapm_widget *w, *next_w;
    119#ifdef CONFIG_DEBUG_FS
    120	struct dentry *parent = dapm->debugfs_dapm;
    121	struct dentry *debugfs_w = NULL;
    122#endif
    123
    124	mutex_lock(&dapm->card->dapm_mutex);
    125	for (i = 0; i < num; i++) {
    126		/* below logic can be optimized to identify widget pointer */
    127		list_for_each_entry_safe(w, next_w, &dapm->card->widgets,
    128					 list) {
    129			if (w->dapm != dapm)
    130				continue;
    131			if (!strcmp(w->name, widget->name))
    132				break;
    133			w = NULL;
    134		}
    135		if (!w) {
    136			dev_err(dapm->dev, "%s: widget not found\n",
    137				widget->name);
    138			widget++;
    139			continue;
    140		}
    141		widget++;
    142#ifdef CONFIG_DEBUG_FS
    143		if (!parent)
    144			debugfs_w = debugfs_lookup(w->name, parent);
    145		debugfs_remove(debugfs_w);
    146		debugfs_w = NULL;
    147#endif
    148		gbaudio_dapm_free_widget(w);
    149	}
    150	mutex_unlock(&dapm->card->dapm_mutex);
    151	return 0;
    152}
    153
    154static int gbaudio_remove_controls(struct snd_card *card, struct device *dev,
    155				   const struct snd_kcontrol_new *controls,
    156				   int num_controls, const char *prefix)
    157{
    158	int i, err;
    159
    160	for (i = 0; i < num_controls; i++) {
    161		const struct snd_kcontrol_new *control = &controls[i];
    162		struct snd_ctl_elem_id id;
    163		struct snd_kcontrol *kctl;
    164
    165		if (prefix)
    166			snprintf(id.name, sizeof(id.name), "%s %s", prefix,
    167				 control->name);
    168		else
    169			strscpy(id.name, control->name, sizeof(id.name));
    170		id.numid = 0;
    171		id.iface = control->iface;
    172		id.device = control->device;
    173		id.subdevice = control->subdevice;
    174		id.index = control->index;
    175		kctl = snd_ctl_find_id(card, &id);
    176		if (!kctl) {
    177			dev_err(dev, "Failed to find %s\n", control->name);
    178			continue;
    179		}
    180		err = snd_ctl_remove(card, kctl);
    181		if (err < 0) {
    182			dev_err(dev, "%d: Failed to remove %s\n", err,
    183				control->name);
    184			continue;
    185		}
    186	}
    187	return 0;
    188}
    189
    190int gbaudio_remove_component_controls(struct snd_soc_component *component,
    191				      const struct snd_kcontrol_new *controls,
    192				      unsigned int num_controls)
    193{
    194	struct snd_card *card = component->card->snd_card;
    195	int err;
    196
    197	down_write(&card->controls_rwsem);
    198	err = gbaudio_remove_controls(card, component->dev, controls,
    199				      num_controls, component->name_prefix);
    200	up_write(&card->controls_rwsem);
    201	return err;
    202}