sound/virtio/virtio_pcm.c

Source file repositories/reference/linux-study-clean/sound/virtio/virtio_pcm.c

File Facts

System
Linux kernel
Corpus path
sound/virtio/virtio_pcm.c
Extension
.c
Size
15044 bytes
Lines
526
Domain
Driver Families
Bucket
sound/virtio
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

struct virtsnd_v2a_rate {
	unsigned int alsa_bit;
	unsigned int rate;
};

static const struct virtsnd_v2a_rate g_v2a_rate_map[] = {
	[VIRTIO_SND_PCM_RATE_5512] = { SNDRV_PCM_RATE_5512, 5512 },
	[VIRTIO_SND_PCM_RATE_8000] = { SNDRV_PCM_RATE_8000, 8000 },
	[VIRTIO_SND_PCM_RATE_11025] = { SNDRV_PCM_RATE_11025, 11025 },
	[VIRTIO_SND_PCM_RATE_16000] = { SNDRV_PCM_RATE_16000, 16000 },
	[VIRTIO_SND_PCM_RATE_22050] = { SNDRV_PCM_RATE_22050, 22050 },
	[VIRTIO_SND_PCM_RATE_32000] = { SNDRV_PCM_RATE_32000, 32000 },
	[VIRTIO_SND_PCM_RATE_44100] = { SNDRV_PCM_RATE_44100, 44100 },
	[VIRTIO_SND_PCM_RATE_48000] = { SNDRV_PCM_RATE_48000, 48000 },
	[VIRTIO_SND_PCM_RATE_64000] = { SNDRV_PCM_RATE_64000, 64000 },
	[VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 },
	[VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 },
	[VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 },
	[VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 },
	[VIRTIO_SND_PCM_RATE_384000] = { SNDRV_PCM_RATE_384000, 384000 }
};

/**
 * virtsnd_pcm_build_hw() - Parse substream config and build HW descriptor.
 * @vss: VirtIO substream.
 * @info: VirtIO substream information entry.
 *
 * Context: Any context.
 * Return: 0 on success, -EINVAL if configuration is invalid.
 */
static int virtsnd_pcm_build_hw(struct virtio_pcm_substream *vss,
				struct virtio_snd_pcm_info *info)
{
	struct virtio_device *vdev = vss->snd->vdev;
	unsigned int i;
	u64 values;
	size_t sample_max = 0;
	size_t sample_min = 0;

	vss->features = le32_to_cpu(info->features);

	/*
	 * TODO: set SNDRV_PCM_INFO_{BATCH,BLOCK_TRANSFER} if device supports
	 * only message-based transport.
	 */
	vss->hw.info =
		SNDRV_PCM_INFO_MMAP |
		SNDRV_PCM_INFO_MMAP_VALID |
		SNDRV_PCM_INFO_BATCH |
		SNDRV_PCM_INFO_BLOCK_TRANSFER |
		SNDRV_PCM_INFO_INTERLEAVED |
		SNDRV_PCM_INFO_PAUSE |
		SNDRV_PCM_INFO_NO_REWINDS |
		SNDRV_PCM_INFO_SYNC_APPLPTR;

	if (!info->channels_min || info->channels_min > info->channels_max) {
		dev_err(&vdev->dev,
			"SID %u: invalid channel range [%u %u]\n",
			vss->sid, info->channels_min, info->channels_max);
		return -EINVAL;
	}

	vss->hw.channels_min = info->channels_min;
	vss->hw.channels_max = info->channels_max;

	values = le64_to_cpu(info->formats);

	vss->hw.formats = 0;

	for (i = 0; i < ARRAY_SIZE(g_v2a_format_map); ++i)
		if (values & (1ULL << i)) {
			snd_pcm_format_t alsa_fmt = g_v2a_format_map[i];
			int bytes = snd_pcm_format_physical_width(alsa_fmt) / 8;

			if (!sample_min || sample_min > bytes)
				sample_min = bytes;

			if (sample_max < bytes)
				sample_max = bytes;

			vss->hw.formats |= pcm_format_to_bits(alsa_fmt);
		}

	if (!vss->hw.formats) {
		dev_err(&vdev->dev,
			"SID %u: no supported PCM sample formats found\n",
			vss->sid);
		return -EINVAL;
	}

Annotation

Implementation Notes