sound/soc/au1x/dma.c

Source file repositories/reference/linux-study-clean/sound/soc/au1x/dma.c

File Facts

System
Linux kernel
Corpus path
sound/soc/au1x/dma.c
Extension
.c
Size
8779 bytes
Lines
328
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

struct pcm_period {
	u32 start;
	u32 relative_end;	/* relative to start of buffer */
	struct pcm_period *next;
};

struct audio_stream {
	struct snd_pcm_substream *substream;
	int dma;
	struct pcm_period *buffer;
	unsigned int period_size;
	unsigned int periods;
};

struct alchemy_pcm_ctx {
	struct audio_stream stream[2];	/* playback & capture */
};

static void au1000_release_dma_link(struct audio_stream *stream)
{
	struct pcm_period *pointer;
	struct pcm_period *pointer_next;

	stream->period_size = 0;
	stream->periods = 0;
	pointer = stream->buffer;
	if (!pointer)
		return;
	do {
		pointer_next = pointer->next;
		kfree(pointer);
		pointer = pointer_next;
	} while (pointer != stream->buffer);
	stream->buffer = NULL;
}

static int au1000_setup_dma_link(struct audio_stream *stream,
				 unsigned int period_bytes,
				 unsigned int periods)
{
	struct snd_pcm_substream *substream = stream->substream;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct pcm_period *pointer;
	unsigned long dma_start;
	int i;

	dma_start = virt_to_phys(runtime->dma_area);

	if (stream->period_size == period_bytes &&
	    stream->periods == periods)
		return 0; /* not changed */

	au1000_release_dma_link(stream);

	stream->period_size = period_bytes;
	stream->periods = periods;

	stream->buffer = kmalloc_obj(struct pcm_period);
	if (!stream->buffer)
		return -ENOMEM;
	pointer = stream->buffer;
	for (i = 0; i < periods; i++) {
		pointer->start = (u32)(dma_start + (i * period_bytes));
		pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
		if (i < periods - 1) {
			pointer->next = kmalloc_obj(struct pcm_period);
			if (!pointer->next) {
				au1000_release_dma_link(stream);
				return -ENOMEM;
			}
			pointer = pointer->next;
		}
	}
	pointer->next = stream->buffer;
	return 0;
}

static void au1000_dma_stop(struct audio_stream *stream)
{
	if (stream->buffer)
		disable_dma(stream->dma);
}

static void au1000_dma_start(struct audio_stream *stream)
{
	if (!stream->buffer)
		return;

	init_dma(stream->dma);
	if (get_dma_active_buffer(stream->dma) == 0) {

Annotation

Implementation Notes