sound/core/pcm_lib.c

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

File Facts

System
Linux kernel
Corpus path
sound/core/pcm_lib.c
Extension
.c
Size
74641 bytes
Lines
2636
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

if (new_hw_ptr == ULONG_MAX) {
			/*
			 * Initialization, fill the whole unused buffer with silence.
			 *
			 * Usually, this is entered while stopped, before data is queued,
			 * so both pointers are expected to be zero.
			 */
			snd_pcm_sframes_t avail = runtime->control->appl_ptr - hw_ptr;
			if (avail < 0)
				avail += runtime->boundary;
			/*
			 * In free-running mode, appl_ptr will be zero even while running,
			 * so we end up with a huge number. There is no useful way to
			 * handle this, so we just clear the whole buffer.
			 */
			runtime->silence_filled = avail > runtime->buffer_size ? 0 : avail;
			runtime->silence_start = hw_ptr;
		} else {
			/* Silence the just played area immediately */
			update_silence_vars(runtime, hw_ptr, new_hw_ptr);
		}
		/*
		 * In this mode, silence_filled actually includes the valid
		 * sample data from the user.
		 */
		frames = runtime->buffer_size - runtime->silence_filled;
	}
	if (snd_BUG_ON(frames > runtime->buffer_size))
		return;
	if (frames == 0)
		return;
	ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
	do {
		transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
		err = fill_silence_frames(substream, ofs, transfer);
		snd_BUG_ON(err < 0);
		runtime->silence_filled += transfer;
		frames -= transfer;
		ofs = 0;
	} while (frames > 0);
	snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
}

#ifdef CONFIG_SND_DEBUG
void snd_pcm_debug_name(struct snd_pcm_substream *substream,
			   char *name, size_t len)
{
	snprintf(name, len, "pcmC%dD%d%c:%d",
		 substream->pcm->card->number,
		 substream->pcm->device,
		 substream->stream ? 'c' : 'p',
		 substream->number);
}
EXPORT_SYMBOL(snd_pcm_debug_name);
#endif

#define XRUN_DEBUG_BASIC	(1<<0)
#define XRUN_DEBUG_STACK	(1<<1)	/* dump also stack */
#define XRUN_DEBUG_JIFFIESCHECK	(1<<2)	/* do jiffies check */

#ifdef CONFIG_SND_PCM_XRUN_DEBUG

#define xrun_debug(substream, mask) \
			((substream)->pstr->xrun_debug & (mask))
#else
#define xrun_debug(substream, mask)	0
#endif

#define dump_stack_on_xrun(substream) do {			\
		if (xrun_debug(substream, XRUN_DEBUG_STACK))	\
			dump_stack();				\
	} while (0)

/* call with stream lock held */
void __snd_pcm_xrun(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;

	trace_xrun(substream);
	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
		struct timespec64 tstamp;

		snd_pcm_gettime(runtime, &tstamp);
		runtime->status->tstamp.tv_sec = tstamp.tv_sec;
		runtime->status->tstamp.tv_nsec = tstamp.tv_nsec;
	}
	snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
	if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
		char name[16];
		snd_pcm_debug_name(substream, name, sizeof(name));

Annotation

Implementation Notes