static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { static char *outputs[32] = { /* 00 */ "PCM Left", /* 01 */ "PCM Right", /* 02 */ "PCM Surround Left", /* 03 */ "PCM Surround Right", /* 04 */ "MIDI Left", /* 05 */ "MIDI Right", /* 06 */ "PCM Center", /* 07 */ "PCM LFE", /* 08 */ "???", /* 09 */ "???", /* 10 */ "???", /* 11 */ "???", /* 12 */ "MIDI Reverb", /* 13 */ "MIDI Chorus", /* 14 */ "???", /* 15 */ "???", /* 16 */ "???", /* 17 */ "???", /* 18 */ "ADC Left / CDROM S/PDIF Left", /* 19 */ "ADC Right / CDROM S/PDIF Right", /* 20 */ "MIC / Zoom Video Left", /* 21 */ "Zoom Video Right", /* 22 */ "S/PDIF Left", /* 23 */ "S/PDIF Right", /* 24 */ "???", /* 25 */ "???", /* 26 */ "???", /* 27 */ "???", /* 28 */ "???", /* 29 */ "???", /* 30 */ "???", /* 31 */ "???" }; emu10k1_t *emu = snd_magic_cast(emu10k1_t, entry->private_data, return); unsigned int val; int nefx = emu->audigy ? 64 : 32; int idx; snd_iprintf(buffer, "EMU10K1\n\n"); val = emu->audigy ? snd_emu10k1_ptr_read(emu, A_FXRT1, 0) : snd_emu10k1_ptr_read(emu, FXRT, 0); snd_iprintf(buffer, "Card : %s\n", emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", emu->fx8010.etram_pages.bytes); snd_iprintf(buffer, "\n"); if (emu->audigy) { snd_iprintf(buffer, "Effect Send Routing : A=%i, B=%i, C=%i, D=%i\n", val & 0x3f, (val >> 8) & 0x3f, (val >> 16) & 0x3f, (val >> 24) & 0x3f); } else {
/* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; u32 tmp; #if 0 /* debug */ dev_dbg(emu->card->dev, "prepare:channel_number=%d, rate=%d, " "format=0x%x, channels=%d, buffer_size=%ld, " "period_size=%ld, periods=%u, frames_to_bytes=%d\n", channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); dev_dbg(emu->card->dev, "dma_addr=%x, dma_area=%p, table_base=%p\n", runtime->dma_addr, runtime->dma_area, table_base); dev_dbg(emu->card->dev, "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes); #endif /* debug */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); break; case 96000: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); break; case 192000: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); break; case 48000: default: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ for(i = 0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel)); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); return 0; }
/* prepare capture callback */ static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; u32 tmp; //printk("prepare capture:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); break; case 96000: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); break; case 192000: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); break; case 48000: default: snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); return 0; }
static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int tmp; unsigned long flags; spin_lock_irqsave(&emu->reg_lock, flags); tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); switch (tmp & A_SPDIF_RATE_MASK) { case A_SPDIF_44100: ucontrol->value.enumerated.item[0] = 0; break; case A_SPDIF_48000: ucontrol->value.enumerated.item[0] = 1; break; case A_SPDIF_96000: ucontrol->value.enumerated.item[0] = 2; break; default: ucontrol->value.enumerated.item[0] = 1; } spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int change; unsigned int reg, val, tmp; unsigned long flags; switch(ucontrol->value.enumerated.item[0]) { case 0: val = A_SPDIF_44100; break; case 1: val = A_SPDIF_48000; break; case 2: val = A_SPDIF_96000; break; default: val = A_SPDIF_48000; break; } spin_lock_irqsave(&emu->reg_lock, flags); reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp = reg & ~A_SPDIF_RATE_MASK; tmp |= val; if ((change = (tmp != reg))) snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); spin_unlock_irqrestore(&emu->reg_lock, flags); return change; }
static inline unsigned char mpu401_read(emu10k1_t *emu, emu10k1_midi_t *mpu, int idx) { if (emu->audigy) return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0); else return inb(emu->port + mpu->port + idx); }
static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu, struct snd_info_buffer *buffer, char *title, int status_reg, int rate_reg) { static char *clkaccy[4] = { "1000ppm", "50ppm", "variable", "unknown" }; static int samplerate[16] = { 44100, 1, 48000, 32000, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; static char *channel[16] = { "unspec", "left", "right", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; static char *emphasis[8] = { "none", "50/15 usec 2 channel", "2", "3", "4", "5", "6", "7" }; unsigned int status, rate = 0; status = snd_emu10k1_ptr_read(emu, status_reg, 0); snd_iprintf(buffer, "\n%s\n", title); if (status != 0xffffffff) { snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); if (rate_reg > 0) { rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off"); snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); /* From ((Rate * 48000 ) / 262144); */ snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11); }
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) { struct snd_emu10k1 *emu = dev_id; unsigned int status, status2, orig_status, orig_status2; int handled = 0; int timeout = 0; while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) { timeout++; orig_status = status; handled = 1; if ((status & 0xffffffff) == 0xffffffff) { ; break; } if (status & IPR_PCIERROR) { ; snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { if (emu->hwvol_interrupt) emu->hwvol_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { int voice; int voice_max = status & IPR_CHANNELNUMBERMASK; u32 val; struct snd_emu10k1_voice *pvoice = emu->voices; val = snd_emu10k1_ptr_read(emu, CLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, CLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_intr_ack(emu, voice); } else { snd_emu10k1_voice_intr_disable(emu, voice); } } val >>= 1; pvoice++; } val = snd_emu10k1_ptr_read(emu, HLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, HLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_half_loop_intr_ack(emu, voice); } else { snd_emu10k1_voice_half_loop_intr_disable(emu, voice); } } val >>= 1; pvoice++; } status &= ~IPR_CHANNELLOOP; } status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); } if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { if (emu->capture_mic_interrupt) emu->capture_mic_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); } if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { if (emu->capture_efx_interrupt) emu->capture_efx_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); } if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (emu->midi.interrupt) emu->midi.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); } if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { if (emu->midi2.interrupt) emu->midi2.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); } if (status & IPR_INTERVALTIMER) { if (emu->timer) snd_timer_interrupt(emu->timer, emu->timer->sticks); else snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); status &= ~IPR_INTERVALTIMER; } if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { if (emu->spdif_interrupt) emu->spdif_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); } if (status & IPR_FXDSP) { if (emu->dsp_interrupt) emu->dsp_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } if (status & IPR_P16V) { while ((status2 = inl(emu->port + IPR2)) != 0) { u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]); struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice); ; orig_status2 = status2; if(status2 & mask) { if(pvoice->use) { snd_pcm_period_elapsed(pvoice->epcm->substream); } else { ; } } if(status2 & 0x110000) { ; if(cvoice->use) { ; snd_pcm_period_elapsed(cvoice->epcm->substream); } } outl(orig_status2, emu->port + IPR2); /* ack all */ } status &= ~IPR_P16V; } if (status) { unsigned int bits; ; //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_MICBUFENABLE | INTE_ADCBUFENABLE | INTE_EFXBUFENABLE | INTE_GPSPDIFENABLE | INTE_CDSPDIFENABLE | INTE_INTERVALTIMERENB | INTE_MIDITXENABLE | INTE_MIDIRXENABLE; if (emu->audigy) bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; snd_emu10k1_intr_disable(emu, bits); } outl(orig_status, emu->port + IPR); /* ack all */ }
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; int ch; /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); /* reset recording buffers */ snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); snd_emu10k1_ptr_write(emu, MICBA, 0, 0); snd_emu10k1_ptr_write(emu, FXBS, 0, ADCBS_BUFSIZE_NONE); snd_emu10k1_ptr_write(emu, FXBA, 0, 0); snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); /* disable channel interrupt */ outl(0, emu->port + INTE); snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); if (emu->audigy){ /* set SPDIF bypass mode */ snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); /* enable rear left + rear right AC97 slots */ snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT | AC97SLOT_REAR_LEFT); } /* init envelope engine */ for (ch = 0; ch < NUM_G; ch++) snd_emu10k1_voice_init(emu, ch); snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]); snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]); snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]); if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ u32 tmp; //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); /* Setup SRCMulti Input Audio Enable */ /* Use 0xFFFFFFFF to enable P16V sounds. */ snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF); /* Enabled Phased (8-channel) P16V playback */ outl(0x0201, emu->port + HCFG2); /* Set playback routing. */ snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4); } if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ u32 tmp; snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ outl(0x600000, emu->port + 0x20); outl(0x14, emu->port + 0x24); /* Setup SRCMulti Input Audio Enable */ outl(0x7b0000, emu->port + 0x20); outl(0xFF000000, emu->port + 0x24); /* Setup SPDIF Out Audio Enable */ /* The Audigy 2 Value has a separate SPDIF out, * so no need for a mixer switch */ outl(0x7a0000, emu->port + 0x20); outl(0xFF000000, emu->port + 0x24); tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */ outl(tmp, emu->port + A_IOCFG); } if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */ int size, n; size = ARRAY_SIZE(spi_dac_init); for (n=0; n < size; n++) snd_emu10k1_spi_write(emu, spi_dac_init[n]); snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); /* Enable GPIOs * GPIO0: Unknown * GPIO1: Speakers-enabled. * GPIO2: Unknown * GPIO3: Unknown * GPIO4: IEC958 Output on. * GPIO5: Unknown * GPIO6: Unknown * GPIO7: Unknown */ outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ } snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; for (ch = 0; ch < NUM_G; ch++) { snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); } /* * Hokay, setup HCFG * Mute Disable Audio = 0 * Lock Tank Memory = 1 * Lock Sound Memory = 0 * Auto Mute = 1 */ if (emu->audigy) { if (emu->revision == 4) /* audigy2 */ outl(HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | HCFG_AC3ENABLE_GPSPDIF | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); else outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); /* FIXME: Remove all these emu->model and replace it with a card recognition parameter, * e.g. card_capabilities->joystick */ } else if (emu->model == 0x20 || emu->model == 0xc400 || (emu->model == 0x21 && emu->revision < 6)) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG); else // With on-chip joystick outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ if ( emu->card_capabilities->emu1212m) { ; /* Disable all access to A_IOCFG for the emu1212m */ } else if (emu->audigy) { unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); udelay(500); outl(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG); udelay(100); outl(reg, emu->port + A_IOCFG); } else { unsigned int reg = inl(emu->port + HCFG); outl(reg | HCFG_GPOUT2, emu->port + HCFG); udelay(500); outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG); udelay(100); outl(reg, emu->port + HCFG); } } if ( emu->card_capabilities->emu1212m) { ; /* Disable all access to A_IOCFG for the emu1212m */ } else if (emu->audigy) { /* enable analog output */ unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); } return 0; }
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { emu10k1_t *emu = dev_id; unsigned int status, status2, orig_status, orig_status2; int handled = 0; while ((status = inl(emu->port + IPR)) != 0) { // printk("irq - status = 0x%x\n", status); orig_status = status; handled = 1; if (status & IPR_PCIERROR) { snd_printk("interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { if (emu->hwvol_interrupt) emu->hwvol_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { int voice; int voice_max = status & IPR_CHANNELNUMBERMASK; u32 val; emu10k1_voice_t *pvoice = emu->voices; val = snd_emu10k1_ptr_read(emu, CLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, CLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_intr_ack(emu, voice); } else { snd_emu10k1_voice_intr_disable(emu, voice); } } val >>= 1; pvoice++; } val = snd_emu10k1_ptr_read(emu, HLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, HLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_half_loop_intr_ack(emu, voice); } else { snd_emu10k1_voice_half_loop_intr_disable(emu, voice); } } val >>= 1; pvoice++; } status &= ~IPR_CHANNELLOOP; } status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); } if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { if (emu->capture_mic_interrupt) emu->capture_mic_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); } if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { if (emu->capture_efx_interrupt) emu->capture_efx_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); } if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (emu->midi.interrupt) emu->midi.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); } if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { if (emu->midi2.interrupt) emu->midi2.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); } if (status & IPR_INTERVALTIMER) { if (emu->timer) snd_timer_interrupt(emu->timer, emu->timer->sticks); else snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); status &= ~IPR_INTERVALTIMER; } if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { if (emu->spdif_interrupt) emu->spdif_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); } if (status & IPR_FXDSP) { if (emu->dsp_interrupt) emu->dsp_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } if (status) { unsigned int bits; //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_MICBUFENABLE | INTE_ADCBUFENABLE | INTE_EFXBUFENABLE | INTE_GPSPDIFENABLE | INTE_CDSPDIFENABLE | INTE_INTERVALTIMERENB | INTE_MIDITXENABLE | INTE_MIDIRXENABLE; if (emu->audigy) bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; snd_emu10k1_intr_disable(emu, bits); } outl(orig_status, emu->port + IPR); /* ack all */ }