📄 emu10k1_main.c
字号:
/* * Copyright (c) by Jaroslav Kysela <perex@suse.cz> * Creative Labs, Inc. * Routines for control of EMU10K1 chips * * BUGS: * -- * * TODO: * -- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#define __NO_VERSION__#include <sound/driver.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <sound/core.h>#include <sound/emu10k1.h>#if 0MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc.");MODULE_DESCRIPTION("Routines for control of EMU10K1 chips");MODULE_LICENSE("GPL");#endif/************************************************************************* * EMU10K1 init / done *************************************************************************/void snd_emu10k1_voice_init(emu10k1_t * emu, int ch){ snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); snd_emu10k1_ptr_write(emu, IP, ch, 0); snd_emu10k1_ptr_write(emu, VTFT, ch, 0xffff); snd_emu10k1_ptr_write(emu, CVCF, ch, 0xffff); snd_emu10k1_ptr_write(emu, PTRX, ch, 0); snd_emu10k1_ptr_write(emu, CPF, ch, 0); snd_emu10k1_ptr_write(emu, CCR, ch, 0); snd_emu10k1_ptr_write(emu, PSST, ch, 0); snd_emu10k1_ptr_write(emu, DSL, ch, 0x10); snd_emu10k1_ptr_write(emu, CCCA, ch, 0); snd_emu10k1_ptr_write(emu, Z1, ch, 0); snd_emu10k1_ptr_write(emu, Z2, ch, 0); snd_emu10k1_ptr_write(emu, FXRT, ch, 0x32100000); snd_emu10k1_ptr_write(emu, ATKHLDM, ch, 0); snd_emu10k1_ptr_write(emu, DCYSUSM, ch, 0); snd_emu10k1_ptr_write(emu, IFATN, ch, 0xffff); snd_emu10k1_ptr_write(emu, PEFE, ch, 0); snd_emu10k1_ptr_write(emu, FMMOD, ch, 0); snd_emu10k1_ptr_write(emu, TREMFRQ, ch, 24); /* 1 Hz */ snd_emu10k1_ptr_write(emu, FM2FRQ2, ch, 24); /* 1 Hz */ snd_emu10k1_ptr_write(emu, TEMPENV, ch, 0); /*** these are last so OFF prevents writing ***/ snd_emu10k1_ptr_write(emu, LFOVAL2, ch, 0); snd_emu10k1_ptr_write(emu, LFOVAL1, ch, 0); snd_emu10k1_ptr_write(emu, ATKHLDV, ch, 0); snd_emu10k1_ptr_write(emu, ENVVOL, ch, 0); snd_emu10k1_ptr_write(emu, ENVVAL, ch, 0); /* Audigy extra stuffs */ if (emu->audigy) { snd_emu10k1_ptr_write(emu, 0x4c, ch, 0); /* ?? */ snd_emu10k1_ptr_write(emu, 0x4d, ch, 0); /* ?? */ snd_emu10k1_ptr_write(emu, 0x4e, ch, 0); /* ?? */ snd_emu10k1_ptr_write(emu, 0x4f, ch, 0); /* ?? */ snd_emu10k1_ptr_write(emu, A_FXRT1, ch, 0x03020100); snd_emu10k1_ptr_write(emu, A_FXRT2, ch, 0x3f3f3f3f); snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, ch, 0); }}static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir){ int ch, idx, err; unsigned int silent_page; emu->fx8010.itram_size = (16 * 1024)/2; emu->fx8010.etram_size = 0; /* 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){ snd_emu10k1_ptr_write(emu, 0x5e, 0, 0xf00); /* ?? */ snd_emu10k1_ptr_write(emu, 0x5f, 0, 0x3); /* ?? */ } /* init envelope engine */ for (ch = 0; ch < NUM_G; ch++) { emu->voices[ch].emu = emu; emu->voices[ch].number = ch; snd_emu10k1_voice_init(emu, ch); } /* * Init to 0x02109204 : * Clock accuracy = 0 (1000ppm) * Sample Rate = 2 (48kHz) * Audio Channel = 1 (Left of 2) * Source Number = 0 (Unspecified) * Generation Status = 1 (Original for Cat Code 12) * Cat Code = 12 (Digital Signal Mixer) * Mode = 0 (Mode 0) * Emphasis = 0 (None) * CP = 1 (Copyright unasserted) * AN = 0 (Audio data) * P = 0 (Consumer) */ snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); /* * Clear page with silence & setup all pointers to this page */ memset(emu->silent_page, 0, PAGE_SIZE); silent_page = emu->silent_page_dmaaddr << 1; for (idx = 0; idx < MAXPAGES; idx++) emu->ptb_pages[idx] = silent_page | idx; snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages_dmaaddr); 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_dmaaddr << 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) outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); 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 */ 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->APS) { /* enable analog output */ unsigned int reg = inl(emu->port + HCFG); outl(reg | HCFG_GPOUT0, emu->port + HCFG); } /* * Initialize the effect engine */ if ((err = snd_emu10k1_init_efx(emu)) < 0) return err; /* * Enable the audio bit */ outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); /* Enable analog/digital outs on audigy */ if (emu->audigy) outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);#if 0 { unsigned int tmp; /* FIXME: the following routine disables LiveDrive-II !! */ // TOSLink detection emu->tos_link = 0; tmp = inl(emu->port + HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { outl(tmp|0x800, emu->port + HCFG); udelay(50); if (tmp != (inl(emu->port + HCFG) & ~0x800)) { emu->tos_link = 1; outl(tmp, emu->port + HCFG); } } }#endif snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); emu->reserved_page = (emu10k1_memblk_t *)snd_emu10k1_synth_alloc(emu, 4096); if (emu->reserved_page) emu->reserved_page->map_locked = 1; return 0;}static int snd_emu10k1_done(emu10k1_t * emu){ int ch; outl(0, emu->port + INTE); /* * Shutdown the chip */ for (ch = 0; ch < NUM_G; ch++) snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); for (ch = 0; ch < NUM_G; ch++) { snd_emu10k1_ptr_write(emu, VTFT, ch, 0); snd_emu10k1_ptr_write(emu, CVCF, ch, 0); snd_emu10k1_ptr_write(emu, PTRX, ch, 0); snd_emu10k1_ptr_write(emu, CPF, ch, 0); } /* reset recording buffers */ snd_emu10k1_ptr_write(emu, MICBS, 0, 0); snd_emu10k1_ptr_write(emu, MICBA, 0, 0); snd_emu10k1_ptr_write(emu, FXBS, 0, 0); snd_emu10k1_ptr_write(emu, FXBA, 0, 0); snd_emu10k1_ptr_write(emu, FXWC, 0, 0); snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); snd_emu10k1_ptr_write(emu, TCB, 0, 0); if (emu->audigy) snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, 0x8000); /* disable channel interrupt */ 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); /* remove reserved page */ if (emu->reserved_page != NULL) { snd_emu10k1_synth_free(emu, (snd_util_memblk_t *)emu->reserved_page); emu->reserved_page = NULL; } /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); snd_emu10k1_ptr_write(emu, PTB, 0, 0); snd_emu10k1_free_efx(emu); return 0;}/************************************************************************* * ECARD functional implementation *************************************************************************//* In A1 Silicon, these bits are in the HC register */#define HOOKN_BIT (1L << 12)#define HANDN_BIT (1L << 11)#define PULSEN_BIT (1L << 10)#define EC_GDI1 (1 << 13)#define EC_GDI0 (1 << 14)#define EC_NUM_CONTROL_BITS 20#define EC_AC3_DATA_SELN 0x0001L#define EC_EE_DATA_SEL 0x0002L#define EC_EE_CNTRL_SELN 0x0004L#define EC_EECLK 0x0008L#define EC_EECS 0x0010L#define EC_EESDO 0x0020L#define EC_TRIM_CSN 0x0040L#define EC_TRIM_SCLK 0x0080L#define EC_TRIM_SDATA 0x0100L#define EC_TRIM_MUTEN 0x0200L#define EC_ADCCAL 0x0400L#define EC_ADCRSTN 0x0800L#define EC_DACCAL 0x1000L#define EC_DACMUTEN 0x2000L#define EC_LEDN 0x4000L#define EC_SPDIF0_SEL_SHIFT 15#define EC_SPDIF1_SEL_SHIFT 17#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT)#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -