/* * prepare playback/capture stream */ static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { int i; volatile struct dbdma_cmd __iomem *cp; struct snd_pcm_runtime *runtime = subs->runtime; int rate_index; long offset; struct pmac_stream *astr; rec->dma_size = snd_pcm_lib_buffer_bytes(subs); rec->period_size = snd_pcm_lib_period_bytes(subs); rec->nperiods = rec->dma_size / rec->period_size; rec->cur_period = 0; rate_index = snd_pmac_rate_index(chip, rec, runtime->rate); /* set up constraints */ astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); if (! astr) return -EINVAL; astr->cur_freqs = 1 << rate_index; astr->cur_formats = 1 << runtime->format; chip->rate_index = rate_index; chip->format = runtime->format; /* We really want to execute a DMA stop command, after the AWACS * is initialized. * For reasons I don't understand, it stops the hissing noise * common to many PowerBook G3 systems and random noise otherwise * captured on iBook2's about every third time. -ReneR */ spin_lock_irq(&chip->reg_lock); snd_pmac_dma_stop(rec); chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP); snd_pmac_dma_set_command(rec, &chip->extra_dma); snd_pmac_dma_run(rec, RUN); spin_unlock_irq(&chip->reg_lock); mdelay(5); spin_lock_irq(&chip->reg_lock); /* continuous DMA memory type doesn't provide the physical address, * so we need to resolve the address here... */ offset = runtime->dma_addr; for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) { cp->phy_addr = cpu_to_le32(offset); cp->req_count = cpu_to_le16(rec->period_size); /*cp->res_count = cpu_to_le16(0);*/ cp->xfer_status = cpu_to_le16(0); offset += rec->period_size; } /* make loop */ cp->command = cpu_to_le16(DBDMA_NOP + BR_ALWAYS); cp->cmd_dep = cpu_to_le32(rec->cmd.addr); snd_pmac_dma_stop(rec); snd_pmac_dma_set_command(rec, &rec->cmd); spin_unlock_irq(&chip->reg_lock); return 0; }
/* * handling beep */ void snd_pmac_beep_dma_start(struct snd_pmac *chip, int bytes, unsigned long addr, int speed) { struct pmac_stream *rec = &chip->playback; snd_pmac_dma_stop(rec); st_le16(&chip->extra_dma.cmds->req_count, bytes); st_le16(&chip->extra_dma.cmds->xfer_status, 0); st_le32(&chip->extra_dma.cmds->cmd_dep, chip->extra_dma.addr); st_le32(&chip->extra_dma.cmds->phy_addr, addr); st_le16(&chip->extra_dma.cmds->command, OUTPUT_MORE + BR_ALWAYS); out_le32(&chip->awacs->control, (in_le32(&chip->awacs->control) & ~0x1f00) | (speed << 8)); out_le32(&chip->awacs->byteswap, 0); snd_pmac_dma_set_command(rec, &chip->extra_dma); snd_pmac_dma_run(rec, RUN); }
static int snd_pmac_pcm_close(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { struct pmac_stream *astr; snd_pmac_dma_stop(rec); astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); if (! astr) return -EINVAL; /* reset constraints */ astr->cur_freqs = chip->freqs_ok; astr->cur_formats = chip->formats_ok; return 0; }
/* * PCM trigger/stop */ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs, int cmd) { volatile struct dbdma_cmd __iomem *cp; int i, command; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (rec->running) return -EBUSY; command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ? OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS; spin_lock(&chip->reg_lock); snd_pmac_beep_stop(chip); snd_pmac_pcm_set_format(chip); for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) out_le16(&cp->command, command); snd_pmac_dma_set_command(rec, &rec->cmd); (void)in_le32(&rec->dma->status); snd_pmac_dma_run(rec, RUN|WAKE); rec->running = 1; spin_unlock(&chip->reg_lock); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&chip->reg_lock); rec->running = 0; /*printk(KERN_DEBUG "stopped!!\n");*/ snd_pmac_dma_stop(rec); for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) out_le16(&cp->command, DBDMA_STOP); spin_unlock(&chip->reg_lock); break; default: return -EINVAL; } return 0; }
void snd_pmac_beep_dma_stop(struct snd_pmac *chip) { snd_pmac_dma_stop(&chip->playback); st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP); snd_pmac_pcm_set_format(chip); /* reset format */ }