Exemple #1
0
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;
}
Exemple #3
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);
}