sound/isa/gus/gus_pcm.c
Source file repositories/reference/linux-study-clean/sound/isa/gus/gus_pcm.c
File Facts
- System
- Linux kernel
- Corpus path
sound/isa/gus/gus_pcm.c- Extension
.c- Size
- 27500 bytes
- Lines
- 863
- Domain
- Driver Families
- Bucket
- sound/isa
- 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.
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
asm/dma.hlinux/slab.hlinux/sched/signal.hsound/core.hsound/control.hsound/gus.hsound/pcm_params.hgus_tables.h
Detected Declarations
struct gus_pcm_privatefunction snd_gf1_pcm_block_change_ackfunction snd_gf1_pcm_block_changefunction snd_gf1_pcm_trigger_upfunction scoped_guardfunction snd_gf1_pcm_interrupt_wavefunction scoped_guardfunction snd_gf1_pcm_interrupt_volumefunction snd_gf1_pcm_volume_changefunction get_bposfunction playback_copy_ackfunction snd_gf1_pcm_playback_copyfunction snd_gf1_pcm_playback_silencefunction snd_gf1_pcm_playback_hw_paramsfunction snd_gf1_pcm_playback_hw_freefunction snd_gf1_pcm_playback_preparefunction snd_gf1_pcm_playback_triggerfunction scoped_guardfunction snd_gf1_pcm_playback_pointerfunction snd_gf1_pcm_capture_hw_paramsfunction snd_gf1_pcm_capture_preparefunction snd_gf1_pcm_capture_triggerfunction snd_gf1_pcm_capture_pointerfunction snd_gf1_pcm_interrupt_dma_readfunction snd_gf1_pcm_playback_freefunction snd_gf1_pcm_playback_openfunction snd_gf1_pcm_playback_closefunction snd_gf1_pcm_capture_openfunction snd_gf1_pcm_capture_closefunction snd_gf1_pcm_volume_infofunction snd_gf1_pcm_volume_getfunction snd_gf1_pcm_volume_putfunction snd_gf1_pcm_new
Annotated Snippet
struct gus_pcm_private {
struct snd_gus_card * gus;
struct snd_pcm_substream *substream;
spinlock_t lock;
unsigned int voices;
struct snd_gus_voice *pvoices[2];
unsigned int memory;
unsigned short flags;
unsigned char voice_ctrl, ramp_ctrl;
unsigned int bpos;
unsigned int blocks;
unsigned int block_size;
unsigned int dma_size;
wait_queue_head_t sleep;
atomic_t dma_count;
int final_volume;
};
static void snd_gf1_pcm_block_change_ack(struct snd_gus_card * gus, void *private_data)
{
struct gus_pcm_private *pcmp = private_data;
if (pcmp) {
atomic_dec(&pcmp->dma_count);
wake_up(&pcmp->sleep);
}
}
static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
unsigned int offset,
unsigned int addr,
unsigned int count)
{
struct snd_gf1_dma_block block;
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
count += offset & 31;
offset &= ~31;
memset(&block, 0, sizeof(block));
block.cmd = SNDRV_GF1_DMA_IRQ;
if (snd_pcm_format_unsigned(runtime->format))
block.cmd |= SNDRV_GF1_DMA_UNSIGNED;
if (snd_pcm_format_width(runtime->format) == 16)
block.cmd |= SNDRV_GF1_DMA_16BIT;
block.addr = addr & ~31;
block.buffer = runtime->dma_area + offset;
block.buf_addr = runtime->dma_addr + offset;
block.count = count;
block.private_data = pcmp;
block.ack = snd_gf1_pcm_block_change_ack;
if (!snd_gf1_dma_transfer_block(pcmp->gus, &block, 0, 0))
atomic_inc(&pcmp->dma_count);
return 0;
}
static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
struct snd_gus_card * gus = pcmp->gus;
unsigned char voice_ctrl, ramp_ctrl;
unsigned short rate;
unsigned int curr, begin, end;
unsigned short vol;
unsigned char pan;
unsigned int voice;
scoped_guard(spinlock_irqsave, &pcmp->lock) {
if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE)
return;
pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE;
pcmp->final_volume = 0;
}
rate = snd_gf1_translate_freq(gus, runtime->rate << 4);
/* enable WAVE IRQ */
voice_ctrl = snd_pcm_format_width(runtime->format) == 16 ? 0x24 : 0x20;
/* enable RAMP IRQ + rollover */
ramp_ctrl = 0x24;
if (pcmp->blocks == 1) {
voice_ctrl |= 0x08; /* loop enable */
ramp_ctrl &= ~0x04; /* disable rollover */
}
for (voice = 0; voice < pcmp->voices; voice++) {
begin = pcmp->memory + voice * (pcmp->dma_size / runtime->channels);
curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
end = curr + (pcmp->block_size / runtime->channels);
end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
Annotation
- Immediate include surface: `asm/dma.h`, `linux/slab.h`, `linux/sched/signal.h`, `sound/core.h`, `sound/control.h`, `sound/gus.h`, `sound/pcm_params.h`, `gus_tables.h`.
- Detected declarations: `struct gus_pcm_private`, `function snd_gf1_pcm_block_change_ack`, `function snd_gf1_pcm_block_change`, `function snd_gf1_pcm_trigger_up`, `function scoped_guard`, `function snd_gf1_pcm_interrupt_wave`, `function scoped_guard`, `function snd_gf1_pcm_interrupt_volume`, `function snd_gf1_pcm_volume_change`, `function get_bpos`.
- Atlas domain: Driver Families / sound/isa.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.