drivers/media/pci/tw686x/tw686x-audio.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/tw686x/tw686x-audio.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/tw686x/tw686x-audio.c
Extension
.c
Size
10842 bytes
Lines
414
Domain
Driver Families
Bucket
drivers/media
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 (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) {
			spin_unlock_irqrestore(&ac->lock, flags);
			continue;
		}

		if (!list_empty(&ac->buf_list)) {
			next = list_first_entry(&ac->buf_list,
					struct tw686x_audio_buf, list);
			list_move_tail(&next->list, &ac->buf_list);
			done = ac->curr_bufs[!pb];
			ac->curr_bufs[pb] = next;
		}
		spin_unlock_irqrestore(&ac->lock, flags);

		if (!done)
			continue;
		/*
		 * Checking for a non-nil dma_desc[pb]->virt buffer is
		 * the same as checking for memcpy DMA mode.
		 */
		desc = &ac->dma_descs[pb];
		if (desc->virt) {
			memcpy(done->virt, desc->virt,
			       dev->period_size);
		} else {
			u32 reg = pb ? ADMA_B_ADDR[ch] : ADMA_P_ADDR[ch];
			reg_write(dev, reg, next->dma);
		}
		ac->ptr = done->dma - ac->buf[0].dma;
		snd_pcm_period_elapsed(ac->ss);
	}
}

/*
 * Audio parameters are global and shared among all
 * capture channels. The driver prevents changes to
 * the parameters if any audio channel is capturing.
 */
static const struct snd_pcm_hardware tw686x_capture_hw = {
	.info			= (SNDRV_PCM_INFO_MMAP |
				   SNDRV_PCM_INFO_INTERLEAVED |
				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
				   SNDRV_PCM_INFO_MMAP_VALID),
	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
	.rates			= SNDRV_PCM_RATE_8000_48000,
	.rate_min		= 8000,
	.rate_max		= 48000,
	.channels_min		= 1,
	.channels_max		= 1,
	.buffer_bytes_max	= TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
	.period_bytes_min	= AUDIO_DMA_SIZE_MIN,
	.period_bytes_max	= AUDIO_DMA_SIZE_MAX,
	.periods_min		= TW686X_AUDIO_PERIODS_MIN,
	.periods_max		= TW686X_AUDIO_PERIODS_MAX,
};

static int tw686x_pcm_open(struct snd_pcm_substream *ss)
{
	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
	struct snd_pcm_runtime *rt = ss->runtime;
	int err;

	ac->ss = ss;
	rt->hw = tw686x_capture_hw;

	err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
	if (err < 0)
		return err;

	return 0;
}

static int tw686x_pcm_close(struct snd_pcm_substream *ss)
{
	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];

	ac->ss = NULL;
	return 0;
}

static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
{
	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
	struct snd_pcm_runtime *rt = ss->runtime;
	unsigned int period_size = snd_pcm_lib_period_bytes(ss);
	struct tw686x_audio_buf *p_buf, *b_buf;
	unsigned long flags;

Annotation

Implementation Notes