sound/soc/sof/ipc4-control.c

Source file repositories/reference/linux-study-clean/sound/soc/sof/ipc4-control.c

File Facts

System
Linux kernel
Corpus path
sound/soc/sof/ipc4-control.c
Extension
.c
Size
29112 bytes
Lines
1038
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source 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

if (swidget->comp_id == scontrol->comp_id) {
			widget_found = true;
			break;
		}
	}

	if (!widget_found) {
		dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
		return -ENOENT;
	}

	if (lock)
		mutex_lock(&swidget->setup_mutex);
	else
		lockdep_assert_held(&swidget->setup_mutex);

	/*
	 * Volatile controls should always be part of static pipelines and the
	 * widget use_count would always be > 0 in this case. For the others,
	 * just return the cached value if the widget is not set up.
	 */
	if (!swidget->use_count)
		goto unlock;

	msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
	msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);

	ret = iops->set_get_data(sdev, msg, msg->data_size, set);
	if (!set)
		goto unlock;

	/* It is a set-data operation, and we have a valid backup that we can restore */
	if (ret < 0) {
		if (!scontrol->old_ipc_control_data)
			goto unlock;
		/*
		 * Current ipc_control_data is not valid, we use the last known good
		 * configuration
		 */
		memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data,
		       scontrol->size);
		kfree(scontrol->old_ipc_control_data);
		scontrol->old_ipc_control_data = NULL;
		/* Send the last known good configuration to firmware */
		ret = iops->set_get_data(sdev, msg, msg->data_size, set);
		if (ret < 0)
			goto unlock;
	}

unlock:
	if (lock)
		mutex_unlock(&swidget->setup_mutex);

	return ret;
}

static int
sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
			 struct snd_sof_control *scontrol, bool lock)
{
	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
	struct sof_ipc4_gain *gain = swidget->private;
	struct sof_ipc4_gain_params params;
	bool all_channels_equal = true;
	struct sof_ipc4_msg msg;
	u32 value;
	int ret, i;

	/* check if all channel values are equal */
	value = cdata->chanv[0].value;
	for (i = 1; i < scontrol->num_channels; i++) {
		if (cdata->chanv[i].value != value) {
			all_channels_equal = false;
			break;
		}
	}

	/*
	 * notify DSP with a single IPC message if all channel values are equal. Otherwise send
	 * a separate IPC for each channel.
	 */
	memcpy(&msg, &cdata->msg, sizeof(msg));
	for (i = 0; i < scontrol->num_channels; i++) {
		if (all_channels_equal) {
			params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
			params.init_val = cdata->chanv[0].value;
		} else {
			params.channels = cdata->chanv[i].channel;
			params.init_val = cdata->chanv[i].value;
		}

Annotation

Implementation Notes