static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus, struct snd_gus_voice *pvoice) { struct gus_pcm_private * pcmp; struct snd_pcm_runtime *runtime; unsigned char voice_ctrl, ramp_ctrl; unsigned int idx; unsigned int end, step; if (!pvoice->private_data) { snd_printd("snd_gf1_pcm: unknown wave irq?\n"); snd_gf1_smart_stop_voice(gus, pvoice->number); return; } pcmp = pvoice->private_data; if (pcmp == NULL) { snd_printd("snd_gf1_pcm: unknown wave irq?\n"); snd_gf1_smart_stop_voice(gus, pvoice->number); return; } gus = pcmp->gus; runtime = pcmp->substream->runtime; spin_lock(&gus->reg_lock); snd_gf1_select_voice(gus, pvoice->number); voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b; ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03; #if 0 snd_gf1_select_voice(gus, pvoice->number); printk(KERN_DEBUG "position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); snd_gf1_select_voice(gus, pcmp->pvoices[1]->number); printk(KERN_DEBUG "position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4)); snd_gf1_select_voice(gus, pvoice->number); #endif pcmp->bpos++; pcmp->bpos %= pcmp->blocks; if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */ voice_ctrl |= 0x08; /* enable loop */ } else { ramp_ctrl |= 0x04; /* enable rollover */ } end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels); end -= voice_ctrl & 4 ? 2 : 1; step = pcmp->dma_size / runtime->channels; voice_ctrl |= 0x20; if (!pcmp->final_volume) { ramp_ctrl |= 0x20; ramp_ctrl &= ~0x03; } for (idx = 0; idx < pcmp->voices; idx++, end += step) { snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number); snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4); snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); voice_ctrl &= ~0x20; } if (!gus->gf1.enh_mode) { snd_gf1_delay(gus); voice_ctrl |= 0x20; for (idx = 0; idx < pcmp->voices; idx++) { snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number); snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); voice_ctrl &= ~0x20; } } spin_unlock(&gus->reg_lock); snd_pcm_period_elapsed(pcmp->substream); #if 0 if ((runtime->flags & SNDRV_PCM_FLG_MMAP) && *runtime->state == SNDRV_PCM_STATE_RUNNING) { end = pcmp->bpos * pcmp->block_size; if (runtime->channels > 1) { snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + (end / 2), pcmp->block_size / 2); snd_gf1_pcm_block_change(pcmp->substream, end + (pcmp->block_size / 2), pcmp->memory + (pcmp->dma_size / 2) + (end / 2), pcmp->block_size / 2); } else { snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + end, pcmp->block_size); } } #endif }
static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) { struct snd_card *card; unsigned long flags; int irq, dma1, dma2; static unsigned char irqs[16] = {0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; static unsigned char dmas[8] = {6, 1, 0, 2, 0, 3, 4, 5}; if (snd_BUG_ON(!gus)) return -EINVAL; card = gus->card; if (snd_BUG_ON(!card)) return -EINVAL; gus->mix_cntrl_reg &= 0xf8; gus->mix_cntrl_reg |= 0x01; /* disable MIC, LINE IN, enable LINE OUT */ if (gus->codec_flag || gus->ess_flag) { gus->mix_cntrl_reg &= ~1; /* enable LINE IN */ gus->mix_cntrl_reg |= 4; /* enable MIC */ } dma1 = gus->gf1.dma1; dma1 = abs(dma1); dma1 = dmas[dma1 & 7]; dma2 = gus->gf1.dma2; dma2 = abs(dma2); dma2 = dmas[dma2 & 7]; dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); if ((dma1 & 7) == 0 || (dma2 & 7) == 0) { snd_printk(KERN_ERR "Error! DMA isn't defined.\n"); return -EINVAL; } irq = gus->gf1.irq; irq = abs(irq); irq = irqs[irq & 0x0f]; if (irq == 0) { snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); return -EINVAL; } irq |= 0x40; #if 0 card->mixer.mix_ctrl_reg |= 0x10; #endif spin_lock_irqsave(&gus->reg_lock, flags); outb(5, GUSP(gus, REGCNTRLS)); outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(0x00, GUSP(gus, IRQDMACNTRLREG)); outb(0, GUSP(gus, REGCNTRLS)); spin_unlock_irqrestore(&gus->reg_lock, flags); udelay(100); spin_lock_irqsave(&gus->reg_lock, flags); outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(dma1, GUSP(gus, IRQDMACNTRLREG)); if (latches) { outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(irq, GUSP(gus, IRQDMACNTRLREG)); } spin_unlock_irqrestore(&gus->reg_lock, flags); udelay(100); spin_lock_irqsave(&gus->reg_lock, flags); outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(dma1, GUSP(gus, IRQDMACNTRLREG)); if (latches) { outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(irq, GUSP(gus, IRQDMACNTRLREG)); } spin_unlock_irqrestore(&gus->reg_lock, flags); snd_gf1_delay(gus); if (latches) gus->mix_cntrl_reg |= 0x08; /* enable latches */ else gus->mix_cntrl_reg &= ~0x08; /* disable latches */ spin_lock_irqsave(&gus->reg_lock, flags); outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG)); outb(0, GUSP(gus, GF1PAGE)); spin_unlock_irqrestore(&gus->reg_lock, flags); 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 long flags; unsigned char voice_ctrl, ramp_ctrl; unsigned short rate; unsigned int curr, begin, end; unsigned short vol; unsigned char pan; unsigned int voice; spin_lock_irqsave(&pcmp->lock, flags); if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) { spin_unlock_irqrestore(&pcmp->lock, flags); return; } pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE; pcmp->final_volume = 0; spin_unlock_irqrestore(&pcmp->lock, flags); 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; /* snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, " "ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate); */ pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8; vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right; spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number); snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, pan); snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, rate); snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, begin << 4, voice_ctrl & 4); snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4); snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, curr << 4, voice_ctrl & 4); snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME << 4); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 0x2f); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, SNDRV_GF1_MIN_OFFSET); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, vol >> 8); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); if (!gus->gf1.enh_mode) { snd_gf1_delay(gus); snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl); } spin_unlock_irqrestore(&gus->reg_lock, flags); } spin_lock_irqsave(&gus->reg_lock, flags); for (voice = 0; voice < pcmp->voices; voice++) { snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number); if (gus->gf1.enh_mode) snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, 0x00); /* deactivate voice */ snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); voice_ctrl &= ~0x20; } voice_ctrl |= 0x20; if (!gus->gf1.enh_mode) { snd_gf1_delay(gus); for (voice = 0; voice < pcmp->voices; voice++) { snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number); snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl); voice_ctrl &= ~0x20; /* disable IRQ for next voice */ } } spin_unlock_irqrestore(&gus->reg_lock, flags); }