static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); unsigned long flags; int addr = kcontrol->private_value & 0xff; int change; unsigned char val1, val2, oval1, oval2, tmp; val1 = ucontrol->value.integer.value[0] & 127; val2 = ucontrol->value.integer.value[1] & 127; spin_lock_irqsave(&gus->reg_lock, flags); oval1 = gus->gf1.ics_regs[addr][0]; oval2 = gus->gf1.ics_regs[addr][1]; change = val1 != oval1 || val2 != oval2; gus->gf1.ics_regs[addr][0] = val1; gus->gf1.ics_regs[addr][1] = val2; if (gus->ics_flag && gus->ics_flipped && (addr == SNDRV_ICS_GF1_DEV || addr == SNDRV_ICS_MASTER_DEV)) { tmp = val1; val1 = val2; val2 = tmp; } addr <<= 3; outb(addr | 0, GUSP(gus, MIXCNTRLPORT)); outb(1, GUSP(gus, MIXDATAPORT)); outb(addr | 2, GUSP(gus, MIXCNTRLPORT)); outb((unsigned char) val1, GUSP(gus, MIXDATAPORT)); outb(addr | 1, GUSP(gus, MIXCNTRLPORT)); outb(2, GUSP(gus, MIXDATAPORT)); outb(addr | 3, GUSP(gus, MIXCNTRLPORT)); outb((unsigned char) val2, GUSP(gus, MIXDATAPORT)); spin_unlock_irqrestore(&gus->reg_lock, flags); return change; }
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_gus_check_version(struct snd_gus_card * gus) { unsigned long flags; unsigned char val, rev; struct snd_card *card; card = gus->card; spin_lock_irqsave(&gus->reg_lock, flags); outb(0x20, GUSP(gus, REGCNTRLS)); val = inb(GUSP(gus, REGCNTRLS)); rev = inb(GUSP(gus, BOARDVERSION)); spin_unlock_irqrestore(&gus->reg_lock, flags); snd_printdd("GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev); strcpy(card->driver, "GUS"); strcpy(card->longname, "Gravis UltraSound Classic (2.4)"); if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) { if (rev >= 5 && rev <= 9) { gus->ics_flag = 1; if (rev == 5) gus->ics_flipped = 1; card->longname[27] = '3'; card->longname[29] = rev == 5 ? '5' : '7'; } if (rev >= 10 && rev != 255) { if (rev >= 10 && rev <= 11) { strcpy(card->driver, "GUS MAX"); strcpy(card->longname, "Gravis UltraSound MAX"); gus->max_flag = 1; } else if (rev == 0x30) { strcpy(card->driver, "GUS ACE"); strcpy(card->longname, "Gravis UltraSound Ace"); gus->ace_flag = 1; } else if (rev == 0x50) { strcpy(card->driver, "GUS Extreme"); strcpy(card->longname, "Gravis UltraSound Extreme"); gus->ess_flag = 1; } else { snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val); snd_printk(KERN_ERR " please - report to <*****@*****.**>\n"); } } } strcpy(card->shortname, card->longname); gus->uart_enable = 1; /* standard GUSes doesn't have midi uart trouble */ snd_gus_init_control(gus); return 0; }
void snd_gf1_delay(snd_gus_card_t * gus) { int i; for (i = 0; i < 6; i++) { mb(); inb(GUSP(gus, DRAM)); } }
static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol); unsigned long flags; int shift = kcontrol->private_value & 0xff; int invert = (kcontrol->private_value >> 8) & 1; int change; unsigned char oval, nval; nval = ucontrol->value.integer.value[0] & 1; if (invert) nval ^= 1; nval <<= shift; spin_lock_irqsave(&gus->reg_lock, flags); oval = gus->mix_cntrl_reg; nval = (oval & ~(1 << shift)) | nval; change = nval != oval; outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG)); outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE)); spin_unlock_irqrestore(&gus->reg_lock, flags); return change; }
static void __init snd_gusmax_init(int dev, snd_card_t * card, snd_gus_card_t * gus) { gus->equal_irq = 1; gus->codec_flag = 1; gus->joystick_dac = joystick_dac[dev]; /* init control register */ gus->max_cntrl_val = (gus->gf1.port >> 4) & 0x0f; if (gus->gf1.dma1 > 3) gus->max_cntrl_val |= 0x10; if (gus->gf1.dma2 > 3) gus->max_cntrl_val |= 0x20; gus->max_cntrl_val |= 0x40; outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT)); }
irqreturn_t snd_gus_interrupt(int irq, void *dev_id) { struct snd_gus_card * gus = dev_id; unsigned char status; int loop = 100; int handled = 0; __again: status = inb(gus->gf1.reg_irqstat); if (status == 0) return IRQ_RETVAL(handled); handled = 1; // snd_printk("IRQ: status = 0x%x\n", status); if (status & 0x02) { STAT_ADD(gus->gf1.interrupt_stat_midi_in); if (gus->gf1.interrupt_handler_midi_in) gus->gf1.interrupt_handler_midi_in(gus); } if (status & 0x01) { STAT_ADD(gus->gf1.interrupt_stat_midi_out); if (gus->gf1.interrupt_handler_midi_out) gus->gf1.interrupt_handler_midi_out(gus); } if (status & (0x20 | 0x40)) { unsigned int already, _current_; unsigned char voice_status, voice; struct snd_gus_voice *pvoice; already = 0; while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) { voice = voice_status & 0x1f; _current_ = 1 << voice; if (already & _current_) continue; /* multi request */ already |= _current_; /* mark request */ #if 0 printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE))); #endif pvoice = &gus->gf1.voices[voice]; if (pvoice->use) { if (!(voice_status & 0x80)) { /* voice position IRQ */ STAT_ADD(pvoice->interrupt_stat_wave); pvoice->handler_wave(gus, pvoice); } if (!(voice_status & 0x40)) { /* volume ramp IRQ */ STAT_ADD(pvoice->interrupt_stat_volume); pvoice->handler_volume(gus, pvoice); } } else { STAT_ADD(gus->gf1.interrupt_stat_voice_lost); snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); } } } if (status & 0x04) { STAT_ADD(gus->gf1.interrupt_stat_timer1); if (gus->gf1.interrupt_handler_timer1) gus->gf1.interrupt_handler_timer1(gus); } if (status & 0x08) { STAT_ADD(gus->gf1.interrupt_stat_timer2); if (gus->gf1.interrupt_handler_timer2) gus->gf1.interrupt_handler_timer2(gus); } if (status & 0x80) { if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) { STAT_ADD(gus->gf1.interrupt_stat_dma_write); if (gus->gf1.interrupt_handler_dma_write) gus->gf1.interrupt_handler_dma_write(gus); } if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) { STAT_ADD(gus->gf1.interrupt_stat_dma_read); if (gus->gf1.interrupt_handler_dma_read) gus->gf1.interrupt_handler_dma_read(gus); } } if (--loop > 0) goto __again; return IRQ_NONE; }
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; }
int snd_gus_create(struct snd_card *card, unsigned long port, int irq, int dma1, int dma2, int timer_dev, int voices, int pcm_channels, int effect, struct snd_gus_card **rgus) { struct snd_gus_card *gus; int err; static struct snd_device_ops ops = { .dev_free = snd_gus_dev_free, }; *rgus = NULL; gus = kzalloc(sizeof(*gus), GFP_KERNEL); if (gus == NULL) return -ENOMEM; spin_lock_init(&gus->reg_lock); spin_lock_init(&gus->voice_alloc); spin_lock_init(&gus->active_voice_lock); spin_lock_init(&gus->event_lock); spin_lock_init(&gus->dma_lock); spin_lock_init(&gus->pcm_volume_level_lock); spin_lock_init(&gus->uart_cmd_lock); mutex_init(&gus->dma_mutex); gus->gf1.irq = -1; gus->gf1.dma1 = -1; gus->gf1.dma2 = -1; gus->card = card; gus->gf1.port = port; /* fill register variables for speedup */ gus->gf1.reg_page = GUSP(gus, GF1PAGE); gus->gf1.reg_regsel = GUSP(gus, GF1REGSEL); gus->gf1.reg_data8 = GUSP(gus, GF1DATAHIGH); gus->gf1.reg_data16 = GUSP(gus, GF1DATALOW); gus->gf1.reg_irqstat = GUSP(gus, IRQSTAT); gus->gf1.reg_dram = GUSP(gus, DRAM); gus->gf1.reg_timerctrl = GUSP(gus, TIMERCNTRL); gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA); /* allocate resources */ if ((gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)")) == NULL) { snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port); snd_gus_free(gus); return -EBUSY; } if ((gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)")) == NULL) { snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100); snd_gus_free(gus); return -EBUSY; } if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) { snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq); snd_gus_free(gus); return -EBUSY; } gus->gf1.irq = irq; if (request_dma(dma1, "GUS - 1")) { snd_printk(KERN_ERR "gus: can't grab DMA1 %d\n", dma1); snd_gus_free(gus); return -EBUSY; } gus->gf1.dma1 = dma1; if (dma2 >= 0 && dma1 != dma2) { if (request_dma(dma2, "GUS - 2")) { snd_printk(KERN_ERR "gus: can't grab DMA2 %d\n", dma2); snd_gus_free(gus); return -EBUSY; } gus->gf1.dma2 = dma2; } else { gus->gf1.dma2 = gus->gf1.dma1; gus->equal_dma = 1; } gus->timer_dev = timer_dev; if (voices < 14) voices = 14; if (voices > 32) voices = 32; if (pcm_channels < 0) pcm_channels = 0; if (pcm_channels > 8) pcm_channels = 8; pcm_channels++; pcm_channels &= ~1; gus->gf1.effect = effect ? 1 : 0; gus->gf1.active_voices = voices; gus->gf1.pcm_channels = pcm_channels; gus->gf1.volume_ramp = 25; gus->gf1.smooth_pan = 1; if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) { snd_gus_free(gus); return err; } *rgus = gus; return 0; }
irqreturn_t snd_gus_interrupt(int irq, void *dev_id) { struct snd_gus_card * gus = dev_id; unsigned char status; int loop = 100; int handled = 0; __again: status = inb(gus->gf1.reg_irqstat); if (status == 0) return IRQ_RETVAL(handled); handled = 1; #ifdef CONFIG_DEBUG_PRINTK /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */ #else /* ; #endif if (status & 0x02) { STAT_ADD(gus->gf1.interrupt_stat_midi_in); if (gus->gf1.interrupt_handler_midi_in) gus->gf1.interrupt_handler_midi_in(gus); } if (status & 0x01) { STAT_ADD(gus->gf1.interrupt_stat_midi_out); if (gus->gf1.interrupt_handler_midi_out) gus->gf1.interrupt_handler_midi_out(gus); } if (status & (0x20 | 0x40)) { unsigned int already, _current_; unsigned char voice_status, voice; struct snd_gus_voice *pvoice; already = 0; while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) { voice = voice_status & 0x1f; _current_ = 1 << voice; if (already & _current_) continue; /* multi request */ already |= _current_; /* mark request */ #if 0 #ifdef CONFIG_DEBUG_PRINTK printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, " "voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE))); #else ; #endif #endif pvoice = &gus->gf1.voices[voice]; if (pvoice->use) { if (!(voice_status & 0x80)) { /* voice position IRQ */ STAT_ADD(pvoice->interrupt_stat_wave); pvoice->handler_wave(gus, pvoice); } if (!(voice_status & 0x40)) { /* volume ramp IRQ */ STAT_ADD(pvoice->interrupt_stat_volume); pvoice->handler_volume(gus, pvoice); } } else { STAT_ADD(gus->gf1.interrupt_stat_voice_lost); snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); } }