/** * snd_ac97_pcm_close - closes the given AC97 pcm * @pcm: the ac97 pcm instance * * It frees the locked AC97 slots. * * Return: Zero. */ int snd_ac97_pcm_close(struct ac97_pcm *pcm) { struct snd_ac97_bus *bus; unsigned short slots = pcm->aslots; int i, cidx; #ifdef CONFIG_SND_AC97_POWER_SAVE int r = pcm->cur_dbl; for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; for (cidx = 0; cidx < 4; cidx++) { if (pcm->r[r].rslots[cidx] & (1 << i)) { int reg = get_slot_reg(pcm, cidx, i, r); snd_ac97_update_power(pcm->r[r].codec[cidx], reg, 0); } } } #endif bus = pcm->bus; spin_lock_irq(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; for (cidx = 0; cidx < 4; cidx++) bus->used_slots[pcm->stream][cidx] &= ~(1 << i); } pcm->aslots = 0; pcm->cur_dbl = 0; spin_unlock_irq(&pcm->bus->bus_lock); return 0; }
static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream) { struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); struct cs5535audio_dma *dma = substream->runtime->private_data; if (dma->pcm_open_flag) { if (substream == cs5535au->playback_substream) snd_ac97_update_power(cs5535au->ac97, AC97_PCM_FRONT_DAC_RATE, 0); else snd_ac97_update_power(cs5535au->ac97, AC97_PCM_LR_ADC_RATE, 0); dma->pcm_open_flag = 0; } cs5535audio_clear_dma_packets(cs5535au, dma, substream); return snd_pcm_lib_free_pages(substream); }
/** * 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_PMC_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 */ if (rate != 48000) return -EINVAL; break; case AC97_PCM_FRONT_DAC_RATE: case AC97_PCM_LR_ADC_RATE: if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ if (rate != 48000 && rate != 96000) return -EINVAL; break; case AC97_PCM_SURR_DAC_RATE: if (! (ac97->scaps & AC97_SCAP_SURROUND_DAC)) return -EINVAL; break; case AC97_PCM_LFE_DAC_RATE: if (! (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)) return -EINVAL; break; case AC97_SPDIF: /* special case */ return set_spdif_rate(ac97, rate); default: return -EINVAL; } if (dbl) rate /= 2; tmp = (rate * ac97->bus->clock) / 48000; if (tmp > 65535) return -EINVAL; if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE) snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_DRA, dbl ? AC97_EA_DRA : 0); snd_ac97_update(ac97, reg, tmp & 0xffff); snd_ac97_read(ac97, reg); if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE) { /* Intel controllers require double rate data to be put in * slots 7+8 */ snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, dbl ? AC97_GP_DRSS_78 : 0); snd_ac97_read(ac97, AC97_GENERAL_PURPOSE); } return 0; }