sound/pci/ac97/ac97_pcm.c
Source file repositories/reference/linux-study-clean/sound/pci/ac97/ac97_pcm.c
File Facts
- System
- Linux kernel
- Corpus path
sound/pci/ac97/ac97_pcm.c- Extension
.c- Size
- 20708 bytes
- Lines
- 734
- Domain
- Driver Families
- Bucket
- sound/pci
- 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.
- 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.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- 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
linux/delay.hlinux/init.hlinux/slab.hlinux/mutex.hlinux/export.hsound/core.hsound/pcm.hsound/control.hsound/ac97_codec.hsound/asoundef.hac97_id.hac97_local.h
Detected Declarations
function get_slot_regfunction set_spdif_ratefunction snd_ac97_set_ratefunction get_pslotsfunction get_cslotsfunction get_ratesfunction snd_ac97_pcm_assignfunction snd_ac97_pcm_openfunction snd_ac97_pcm_closefunction double_rate_hw_constraint_ratefunction double_rate_hw_constraint_channelsfunction snd_ac97_pcm_double_rate_rulesexport snd_ac97_set_rateexport snd_ac97_pcm_assignexport snd_ac97_pcm_openexport snd_ac97_pcm_closeexport snd_ac97_pcm_double_rate_rules
Annotated Snippet
switch (rate) {
case 48000: bits = 0; break;
case 44100: bits = 1 << AC97_SC_SPSR_SHIFT; break;
default: /* invalid - disable output */
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
return -EINVAL;
}
reg = AC97_CSR_SPDIF;
mask = 1 << AC97_SC_SPSR_SHIFT;
} else {
if (ac97->id == AC97_ID_CM9739 && rate != 48000) {
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
return -EINVAL;
}
switch (rate) {
case 44100: bits = AC97_SC_SPSR_44K; break;
case 48000: bits = AC97_SC_SPSR_48K; break;
case 32000: bits = AC97_SC_SPSR_32K; break;
default: /* invalid - disable output */
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
return -EINVAL;
}
reg = AC97_SPDIF;
mask = AC97_SC_SPSR_MASK;
}
guard(mutex)(&ac97->reg_mutex);
old = snd_ac97_read(ac97, reg) & mask;
if (old != bits) {
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
snd_ac97_update_bits_nolock(ac97, reg, mask, bits);
/* update the internal spdif bits */
sbits = ac97->spdif_status;
if (sbits & IEC958_AES0_PROFESSIONAL) {
sbits &= ~IEC958_AES0_PRO_FS;
switch (rate) {
case 44100: sbits |= IEC958_AES0_PRO_FS_44100; break;
case 48000: sbits |= IEC958_AES0_PRO_FS_48000; break;
case 32000: sbits |= IEC958_AES0_PRO_FS_32000; break;
}
} else {
sbits &= ~(IEC958_AES3_CON_FS << 24);
switch (rate) {
case 44100: sbits |= IEC958_AES3_CON_FS_44100<<24; break;
case 48000: sbits |= IEC958_AES3_CON_FS_48000<<24; break;
case 32000: sbits |= IEC958_AES3_CON_FS_32000<<24; break;
}
}
ac97->spdif_status = sbits;
}
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
return 0;
}
/**
* snd_ac97_set_rate - change the rate of the given input/output.
* @ac97: the ac97 instance
* @reg: the register to change
* @rate: the sample rate to set
*
* Changes the rate of the given input/output on the codec.
* If the codec doesn't support VAR, the rate must be 48000 (except
* for SPDIF).
*
* The valid registers are AC97_PCM_MIC_ADC_RATE,
* AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE.
* AC97_PCM_SURR_DAC_RATE and AC97_PCM_LFE_DAC_RATE are accepted
* if the codec supports them.
* AC97_SPDIF is accepted as a pseudo register to modify the SPDIF
* status bits.
*
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
{
int dbl;
unsigned int tmp;
dbl = rate > 48000;
if (dbl) {
if (!(ac97->flags & AC97_DOUBLE_RATE))
return -EINVAL;
if (reg != AC97_PCM_FRONT_DAC_RATE)
return -EINVAL;
}
snd_ac97_update_power(ac97, reg, 1);
switch (reg) {
case AC97_PCM_MIC_ADC_RATE:
if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */
Annotation
- Immediate include surface: `linux/delay.h`, `linux/init.h`, `linux/slab.h`, `linux/mutex.h`, `linux/export.h`, `sound/core.h`, `sound/pcm.h`, `sound/control.h`.
- Detected declarations: `function get_slot_reg`, `function set_spdif_rate`, `function snd_ac97_set_rate`, `function get_pslots`, `function get_cslots`, `function get_rates`, `function snd_ac97_pcm_assign`, `function snd_ac97_pcm_open`, `function snd_ac97_pcm_close`, `function double_rate_hw_constraint_rate`.
- Atlas domain: Driver Families / sound/pci.
- Implementation status: integration implementation candidate.
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.