static int snd_atiixp_pcm_hw_free(snd_pcm_substream_t * substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; if (dma->pcm_open_flag) { struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type]; snd_ac97_pcm_close(pcm); dma->pcm_open_flag = 0; } atiixp_clear_dma_packets(chip, dma, substream); snd_pcm_lib_free_pages(substream); return 0; }
/* * hw_params - allocate the buffer and set up buffer descriptors */ static int snd_atiixp_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) { atiixp_t *chip = snd_pcm_substream_chip(substream); atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; dma->buf_addr = substream->runtime->dma_addr; dma->buf_bytes = params_buffer_bytes(hw_params); err = atiixp_build_dma_packets(chip, dma, substream, params_periods(hw_params), params_period_bytes(hw_params)); if (err < 0) return err; if (dma->ac97_pcm_type >= 0) { struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type]; /* PCM is bound to AC97 codec(s) * set up the AC97 codecs */ if (dma->pcm_open_flag) { snd_ac97_pcm_close(pcm); dma->pcm_open_flag = 0; } err = snd_ac97_pcm_open(pcm, params_rate(hw_params), params_channels(hw_params), pcm->r[0].slots); if (err >= 0) dma->pcm_open_flag = 1; } return err; }
/** * snd_ac97_pcm_open - opens the given AC97 pcm * @pcm: the ac97 pcm instance * @rate: rate in Hz, if codec does not support VRA, this value must be 48000Hz * @cfg: output stream characteristics * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm * * It locks the specified slots and sets the given rate to AC97 registers. * * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, enum ac97_pcm_cfg cfg, unsigned short slots) { struct snd_ac97_bus *bus; int i, cidx, r, ok_flag; unsigned int reg_ok[4] = {0,0,0,0}; unsigned char reg; int err = 0; r = rate > 48000; bus = pcm->bus; if (cfg == AC97_PCM_CFG_SPDIF) { for (cidx = 0; cidx < 4; cidx++) if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) { err = set_spdif_rate(bus->codec[cidx], rate); if (err < 0) return err; } } spin_lock_irq(&pcm->bus->bus_lock); for (i = 3; i < 12; i++) { if (!(slots & (1 << i))) continue; ok_flag = 0; for (cidx = 0; cidx < 4; cidx++) { if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { spin_unlock_irq(&pcm->bus->bus_lock); err = -EBUSY; goto error; } if (pcm->r[r].rslots[cidx] & (1 << i)) { bus->used_slots[pcm->stream][cidx] |= (1 << i); ok_flag++; } } if (!ok_flag) { spin_unlock_irq(&pcm->bus->bus_lock); snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i); err = -EAGAIN; goto error; } } pcm->cur_dbl = r; spin_unlock_irq(&pcm->bus->bus_lock); 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)) { reg = get_slot_reg(pcm, cidx, i, r); if (reg == 0xff) { snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i); continue; } if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE))) continue; //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate); err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate); if (err < 0) snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err); else reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE)); } } } pcm->aslots = slots; return 0; error: pcm->aslots = slots; snd_ac97_pcm_close(pcm); return err; }