drivers/media/usb/go7007/snd-go7007.c

Source file repositories/reference/linux-study-clean/drivers/media/usb/go7007/snd-go7007.c

File Facts

System
Linux kernel
Corpus path
drivers/media/usb/go7007/snd-go7007.c
Extension
.c
Size
6890 bytes
Lines
272
Domain
Driver Families
Bucket
drivers/media
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

struct go7007_snd {
	struct snd_card *card;
	struct snd_pcm *pcm;
	struct snd_pcm_substream *substream;
	spinlock_t lock;
	int w_idx;
	int hw_ptr;
	int avail;
	int capturing;
};

static const struct snd_pcm_hardware go7007_snd_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_48000,
	.rate_min		= 48000,
	.rate_max		= 48000,
	.channels_min		= 2,
	.channels_max		= 2,
	.buffer_bytes_max	= (128*1024),
	.period_bytes_min	= 4096,
	.period_bytes_max	= (128*1024),
	.periods_min		= 1,
	.periods_max		= 32,
};

static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length)
{
	struct go7007_snd *gosnd = go->snd_context;
	struct snd_pcm_runtime *runtime = gosnd->substream->runtime;
	int frames = bytes_to_frames(runtime, length);
	unsigned long flags;

	spin_lock_irqsave(&gosnd->lock, flags);
	gosnd->hw_ptr += frames;
	if (gosnd->hw_ptr >= runtime->buffer_size)
		gosnd->hw_ptr -= runtime->buffer_size;
	gosnd->avail += frames;
	spin_unlock_irqrestore(&gosnd->lock, flags);
	if (gosnd->w_idx + length > runtime->dma_bytes) {
		int cpy = runtime->dma_bytes - gosnd->w_idx;

		memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy);
		length -= cpy;
		buf += cpy;
		gosnd->w_idx = 0;
	}
	memcpy(runtime->dma_area + gosnd->w_idx, buf, length);
	gosnd->w_idx += length;
	spin_lock_irqsave(&gosnd->lock, flags);
	if (gosnd->avail < runtime->period_size) {
		spin_unlock_irqrestore(&gosnd->lock, flags);
		return;
	}
	gosnd->avail -= runtime->period_size;
	spin_unlock_irqrestore(&gosnd->lock, flags);
	if (gosnd->capturing)
		snd_pcm_period_elapsed(gosnd->substream);
}

static int go7007_snd_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *hw_params)
{
	struct go7007 *go = snd_pcm_substream_chip(substream);

	go->audio_deliver = parse_audio_stream_data;
	return 0;
}

static int go7007_snd_hw_free(struct snd_pcm_substream *substream)
{
	struct go7007 *go = snd_pcm_substream_chip(substream);

	go->audio_deliver = NULL;
	return 0;
}

static int go7007_snd_capture_open(struct snd_pcm_substream *substream)
{
	struct go7007 *go = snd_pcm_substream_chip(substream);
	struct go7007_snd *gosnd = go->snd_context;
	unsigned long flags;
	int r;

	spin_lock_irqsave(&gosnd->lock, flags);
	if (gosnd->substream == NULL) {
		gosnd->substream = substream;

Annotation

Implementation Notes