static int snd_gus_dram_peek(snd_gus_card_t *gus, char __user *_buffer, unsigned int address, unsigned int size, int rom) { unsigned long flags; unsigned int size1, size2; char buffer[512], *pbuffer; while (size > 0) { size1 = size > 512 ? 512 : size; if (gus->interwave) { spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01); snd_gf1_dram_addr(gus, address); insb(GUSP(gus, DRAM), buffer, size1); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); spin_unlock_irqrestore(&gus->reg_lock, flags); address += size1; } else { pbuffer = buffer; size2 = size1; while (size2--) *pbuffer++ = snd_gf1_peek(gus, address++); } if (copy_to_user(_buffer, buffer, size1)) return -EFAULT; size -= size1; _buffer += size1; } return 0; }
static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf, unsigned int pos, unsigned int count, int w16, int invert) { unsigned int len; unsigned long flags; /* printk(KERN_DEBUG "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port); */ while (count > 0) { len = count; if (len > 512) /* limit, to allow IRQ */ len = 512; count -= len; if (gus->interwave) { spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01 | (invert ? 0x08 : 0x00)); snd_gf1_dram_addr(gus, pos); if (w16) { outb(SNDRV_GF1_GW_DRAM_IO16, GUSP(gus, GF1REGSEL)); outsw(GUSP(gus, GF1DATALOW), buf, len >> 1); } else { outsb(GUSP(gus, DRAM), buf, len); } spin_unlock_irqrestore(&gus->reg_lock, flags); buf += 512; pos += 512; } else {
static int snd_gf1_timer2_start(snd_timer_t * timer) { unsigned long flags; unsigned char tmp; unsigned int ticks; snd_gus_card_t *gus; gus = snd_timer_chip(timer); spin_lock_irqsave(&gus->reg_lock, flags); ticks = timer->sticks; tmp = (gus->gf1.timer_enabled |= 8); snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks); /* timer 2 count */ snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 2 IRQ */ snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */ spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; }
static void snd_gf1_dma_ack(struct snd_gus_card * gus) { unsigned long flags; spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00); snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL); spin_unlock_irqrestore(&gus->reg_lock, flags); }
static int snd_gf1_timer2_stop(snd_timer_t * timer) { unsigned long flags; unsigned char tmp; snd_gus_card_t *gus; gus = snd_timer_chip(timer); spin_lock_irqsave(&gus->reg_lock, flags); tmp = (gus->gf1.timer_enabled &= ~8); snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */ spin_unlock_irqrestore(&gus->reg_lock, flags); return 0; }
static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned char nval; nval = ucontrol->value.integer.value[0] & 31; spin_lock_irqsave(&gus->reg_lock, flags); change = gus->joystick_dac != nval; gus->joystick_dac = nval; snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac); spin_unlock_irqrestore(&gus->reg_lock, flags); return change; }
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 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); }