📄 es1968.c
字号:
/* * Driver for ESS Maestro 1/2/2E Sound Card (started 21.8.99) * Copyright (c) by Matze Braun <MatzeBraun@gmx.de>. * Takashi Iwai <tiwai@suse.de> * * Most of the driver code comes from Zach Brown(zab@redhat.com) * Alan Cox OSS Driver * Rewritted from card-es1938.c source. * * TODO: * Perhaps Synth * * 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 * * * Notes from Zach Brown about the driver code * * Hardware Description * * A working Maestro setup contains the Maestro chip wired to a * codec or 2. In the Maestro we have the APUs, the ASSP, and the * Wavecache. The APUs can be though of as virtual audio routing * channels. They can take data from a number of sources and perform * basic encodings of the data. The wavecache is a storehouse for * PCM data. Typically it deals with PCI and interracts with the * APUs. The ASSP is a wacky DSP like device that ESS is loth * to release docs on. Thankfully it isn't required on the Maestro * until you start doing insane things like FM emulation and surround * encoding. The codecs are almost always AC-97 compliant codecs, * but it appears that early Maestros may have had PT101 (an ESS * part?) wired to them. The only real difference in the Maestro * families is external goop like docking capability, memory for * the ASSP, and initialization differences. * * Driver Operation * * We only drive the APU/Wavecache as typical DACs and drive the * mixers in the codecs. There are 64 APUs. We assign 6 to each * /dev/dsp? device. 2 channels for output, and 4 channels for * input. * * Each APU can do a number of things, but we only really use * 3 basic functions. For playback we use them to convert PCM * data fetched over PCI by the wavecahche into analog data that * is handed to the codec. One APU for mono, and a pair for stereo. * When in stereo, the combination of smarts in the APU and Wavecache * decide which wavecache gets the left or right channel. * * For record we still use the old overly mono system. For each in * coming channel the data comes in from the codec, through a 'input' * APU, through another rate converter APU, and then into memory via * the wavecache and PCI. If its stereo, we mash it back into LRLR in * software. The pass between the 2 APUs is supposedly what requires us * to have a 512 byte buffer sitting around in wavecache/memory. * * The wavecache makes our life even more fun. First off, it can * only address the first 28 bits of PCI address space, making it * useless on quite a few architectures. Secondly, its insane. * It claims to fetch from 4 regions of PCI space, each 4 meg in length. * But that doesn't really work. You can only use 1 region. So all our * allocations have to be in 4meg of each other. Booo. Hiss. * So we have a module parameter, dsps_order, that is the order of * the number of dsps to provide. All their buffer space is allocated * on open time. The sonicvibes OSS routines we inherited really want * power of 2 buffers, so we have all those next to each other, then * 512 byte regions for the recording wavecaches. This ends up * wasting quite a bit of memory. The only fixes I can see would be * getting a kernel allocator that could work in zones, or figuring out * just how to coerce the WP into doing what we want. * * The indirection of the various registers means we have to spinlock * nearly all register accesses. We have the main register indirection * like the wave cache, maestro registers, etc. Then we have beasts * like the APU interface that is indirect registers gotten at through * the main maestro indirection. Ouch. We spinlock around the actual * ports on a per card basis. This means spinlock activity at each IO * operation, but the only IO operation clusters are in non critical * paths and it makes the code far easier to follow. Interrupts are * blocked while holding the locks because the int handler has to * get at some of them :(. The mixer interface doesn't, however. * We also have an OSS state lock that is thrown around in a few * places. */#include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/slab.h>#include <linux/gameport.h>#include <linux/moduleparam.h>#include <linux/mutex.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/mpu401.h>#include <sound/ac97_codec.h>#include <sound/initval.h>#define CARD_NAME "ESS Maestro1/2"#define DRIVER_NAME "ES1968"MODULE_DESCRIPTION("ESS Maestro");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e}," "{ESS,Maestro 2}," "{ESS,Maestro 1}," "{TerraTec,DMX}}");#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))#define SUPPORT_JOYSTICK 1#endifstatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 1-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 };static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 };static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 };static int clock[SNDRV_CARDS];static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};#ifdef SUPPORT_JOYSTICKstatic int joystick[SNDRV_CARDS];#endifmodule_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");module_param_array(total_bufsize, int, NULL, 0444);MODULE_PARM_DESC(total_bufsize, "Total buffer size in kB.");module_param_array(pcm_substreams_p, int, NULL, 0444);MODULE_PARM_DESC(pcm_substreams_p, "PCM Playback substreams for " CARD_NAME " soundcard.");module_param_array(pcm_substreams_c, int, NULL, 0444);MODULE_PARM_DESC(pcm_substreams_c, "PCM Capture substreams for " CARD_NAME " soundcard.");module_param_array(clock, int, NULL, 0444);MODULE_PARM_DESC(clock, "Clock on " CARD_NAME " soundcard. (0 = auto-detect)");module_param_array(use_pm, int, NULL, 0444);MODULE_PARM_DESC(use_pm, "Toggle power-management. (0 = off, 1 = on, 2 = auto)");module_param_array(enable_mpu, int, NULL, 0444);MODULE_PARM_DESC(enable_mpu, "Enable MPU401. (0 = off, 1 = on, 2 = auto)");#ifdef SUPPORT_JOYSTICKmodule_param_array(joystick, bool, NULL, 0444);MODULE_PARM_DESC(joystick, "Enable joystick.");#endif#define NR_APUS 64#define NR_APU_REGS 16/* NEC Versas ? */#define NEC_VERSA_SUBID1 0x80581033#define NEC_VERSA_SUBID2 0x803c1033/* Mode Flags */#define ESS_FMT_STEREO 0x01#define ESS_FMT_16BIT 0x02#define DAC_RUNNING 1#define ADC_RUNNING 2/* Values for the ESM_LEGACY_AUDIO_CONTROL */#define ESS_DISABLE_AUDIO 0x8000#define ESS_ENABLE_SERIAL_IRQ 0x4000#define IO_ADRESS_ALIAS 0x0020#define MPU401_IRQ_ENABLE 0x0010#define MPU401_IO_ENABLE 0x0008#define GAME_IO_ENABLE 0x0004#define FM_IO_ENABLE 0x0002#define SB_IO_ENABLE 0x0001/* Values for the ESM_CONFIG_A */#define PIC_SNOOP1 0x4000#define PIC_SNOOP2 0x2000#define SAFEGUARD 0x0800#define DMA_CLEAR 0x0700#define DMA_DDMA 0x0000#define DMA_TDMA 0x0100#define DMA_PCPCI 0x0200#define POST_WRITE 0x0080#define PCI_TIMING 0x0040#define SWAP_LR 0x0020#define SUBTR_DECODE 0x0002/* Values for the ESM_CONFIG_B */#define SPDIF_CONFB 0x0100#define HWV_CONFB 0x0080#define DEBOUNCE 0x0040#define GPIO_CONFB 0x0020#define CHI_CONFB 0x0010#define IDMA_CONFB 0x0008 /*undoc */#define MIDI_FIX 0x0004 /*undoc */#define IRQ_TO_ISA 0x0001 /*undoc *//* Values for Ring Bus Control B */#define RINGB_2CODEC_ID_MASK 0x0003#define RINGB_DIS_VALIDATION 0x0008#define RINGB_EN_SPDIF 0x0010#define RINGB_EN_2CODEC 0x0020#define RINGB_SING_BIT_DUAL 0x0040/* ****Port Adresses**** *//* Write & Read */#define ESM_INDEX 0x02#define ESM_DATA 0x00/* AC97 + RingBus */#define ESM_AC97_INDEX 0x30#define ESM_AC97_DATA 0x32#define ESM_RING_BUS_DEST 0x34#define ESM_RING_BUS_CONTR_A 0x36#define ESM_RING_BUS_CONTR_B 0x38#define ESM_RING_BUS_SDO 0x3A/* WaveCache*/#define WC_INDEX 0x10#define WC_DATA 0x12#define WC_CONTROL 0x14/* ASSP*/#define ASSP_INDEX 0x80#define ASSP_MEMORY 0x82#define ASSP_DATA 0x84#define ASSP_CONTROL_A 0xA2#define ASSP_CONTROL_B 0xA4#define ASSP_CONTROL_C 0xA6#define ASSP_HOSTW_INDEX 0xA8#define ASSP_HOSTW_DATA 0xAA#define ASSP_HOSTW_IRQ 0xAC/* Midi */#define ESM_MPU401_PORT 0x98/* Others */#define ESM_PORT_HOST_IRQ 0x18#define IDR0_DATA_PORT 0x00#define IDR1_CRAM_POINTER 0x01#define IDR2_CRAM_DATA 0x02#define IDR3_WAVE_DATA 0x03#define IDR4_WAVE_PTR_LOW 0x04#define IDR5_WAVE_PTR_HI 0x05#define IDR6_TIMER_CTRL 0x06#define IDR7_WAVE_ROMRAM 0x07#define WRITEABLE_MAP 0xEFFFFF#define READABLE_MAP 0x64003F/* PCI Register */#define ESM_LEGACY_AUDIO_CONTROL 0x40#define ESM_ACPI_COMMAND 0x54#define ESM_CONFIG_A 0x50#define ESM_CONFIG_B 0x52#define ESM_DDMA 0x60/* Bob Bits */#define ESM_BOB_ENABLE 0x0001#define ESM_BOB_START 0x0001/* Host IRQ Control Bits */#define ESM_RESET_MAESTRO 0x8000#define ESM_RESET_DIRECTSOUND 0x4000#define ESM_HIRQ_ClkRun 0x0100#define ESM_HIRQ_HW_VOLUME 0x0040#define ESM_HIRQ_HARPO 0x0030 /* What's that? */#define ESM_HIRQ_ASSP 0x0010#define ESM_HIRQ_DSIE 0x0004#define ESM_HIRQ_MPU401 0x0002#define ESM_HIRQ_SB 0x0001/* Host IRQ Status Bits */#define ESM_MPU401_IRQ 0x02#define ESM_SB_IRQ 0x01#define ESM_SOUND_IRQ 0x04#define ESM_ASSP_IRQ 0x10#define ESM_HWVOL_IRQ 0x40#define ESS_SYSCLK 50000000#define ESM_BOB_FREQ 200#define ESM_BOB_FREQ_MAX 800#define ESM_FREQ_ESM1 (49152000L / 1024L) /* default rate 48000 */#define ESM_FREQ_ESM2 (50000000L / 1024L)/* APU Modes: reg 0x00, bit 4-7 */#define ESM_APU_MODE_SHIFT 4#define ESM_APU_MODE_MASK (0xf << 4)#define ESM_APU_OFF 0x00#define ESM_APU_16BITLINEAR 0x01 /* 16-Bit Linear Sample Player */#define ESM_APU_16BITSTEREO 0x02 /* 16-Bit Stereo Sample Player */#define ESM_APU_8BITLINEAR 0x03 /* 8-Bit Linear Sample Player */#define ESM_APU_8BITSTEREO 0x04 /* 8-Bit Stereo Sample Player */#define ESM_APU_8BITDIFF 0x05 /* 8-Bit Differential Sample Playrer */#define ESM_APU_DIGITALDELAY 0x06 /* Digital Delay Line */#define ESM_APU_DUALTAP 0x07 /* Dual Tap Reader */#define ESM_APU_CORRELATOR 0x08 /* Correlator */#define ESM_APU_INPUTMIXER 0x09 /* Input Mixer */#define ESM_APU_WAVETABLE 0x0A /* Wave Table Mode */#define ESM_APU_SRCONVERTOR 0x0B /* Sample Rate Convertor */#define ESM_APU_16BITPINGPONG 0x0C /* 16-Bit Ping-Pong Sample Player */#define ESM_APU_RESERVED1 0x0D /* Reserved 1 */#define ESM_APU_RESERVED2 0x0E /* Reserved 2 */#define ESM_APU_RESERVED3 0x0F /* Reserved 3 *//* reg 0x00 */#define ESM_APU_FILTER_Q_SHIFT 0#define ESM_APU_FILTER_Q_MASK (3 << 0)/* APU Filtey Q Control */#define ESM_APU_FILTER_LESSQ 0x00#define ESM_APU_FILTER_MOREQ 0x03#define ESM_APU_FILTER_TYPE_SHIFT 2#define ESM_APU_FILTER_TYPE_MASK (3 << 2)#define ESM_APU_ENV_TYPE_SHIFT 8#define ESM_APU_ENV_TYPE_MASK (3 << 8)#define ESM_APU_ENV_STATE_SHIFT 10#define ESM_APU_ENV_STATE_MASK (3 << 10)#define ESM_APU_END_CURVE (1 << 12)#define ESM_APU_INT_ON_LOOP (1 << 13)#define ESM_APU_DMA_ENABLE (1 << 14)/* reg 0x02 */#define ESM_APU_SUBMIX_GROUP_SHIRT 0#define ESM_APU_SUBMIX_GROUP_MASK (7 << 0)#define ESM_APU_SUBMIX_MODE (1 << 3)#define ESM_APU_6dB (1 << 4)#define ESM_APU_DUAL_EFFECT (1 << 5)#define ESM_APU_EFFECT_CHANNELS_SHIFT 6#define ESM_APU_EFFECT_CHANNELS_MASK (3 << 6)/* reg 0x03 */#define ESM_APU_STEP_SIZE_MASK 0x0fff/* reg 0x04 */#define ESM_APU_PHASE_SHIFT 0#define ESM_APU_PHASE_MASK (0xff << 0)#define ESM_APU_WAVE64K_PAGE_SHIFT 8 /* most 8bit of wave start offset */#define ESM_APU_WAVE64K_PAGE_MASK (0xff << 8)/* reg 0x05 - wave start offset *//* reg 0x06 - wave end offset *//* reg 0x07 - wave loop length *//* reg 0x08 */#define ESM_APU_EFFECT_GAIN_SHIFT 0#define ESM_APU_EFFECT_GAIN_MASK (0xff << 0)#define ESM_APU_TREMOLO_DEPTH_SHIFT 8#define ESM_APU_TREMOLO_DEPTH_MASK (0xf << 8)#define ESM_APU_TREMOLO_RATE_SHIFT 12#define ESM_APU_TREMOLO_RATE_MASK (0xf << 12)/* reg 0x09 *//* bit 0-7 amplitude dest? */#define ESM_APU_AMPLITUDE_NOW_SHIFT 8#define ESM_APU_AMPLITUDE_NOW_MASK (0xff << 8)/* reg 0x0a */#define ESM_APU_POLAR_PAN_SHIFT 0#define ESM_APU_POLAR_PAN_MASK (0x3f << 0)/* Polar Pan Control */#define ESM_APU_PAN_CENTER_CIRCLE 0x00#define ESM_APU_PAN_MIDDLE_RADIUS 0x01#define ESM_APU_PAN_OUTSIDE_RADIUS 0x02#define ESM_APU_FILTER_TUNING_SHIFT 8#define ESM_APU_FILTER_TUNING_MASK (0xff << 8)/* reg 0x0b */#define ESM_APU_DATA_SRC_A_SHIFT 0#define ESM_APU_DATA_SRC_A_MASK (0x7f << 0)#define ESM_APU_INV_POL_A (1 << 7)#define ESM_APU_DATA_SRC_B_SHIFT 8#define ESM_APU_DATA_SRC_B_MASK (0x7f << 8)#define ESM_APU_INV_POL_B (1 << 15)#define ESM_APU_VIBRATO_RATE_SHIFT 0#define ESM_APU_VIBRATO_RATE_MASK (0xf << 0)#define ESM_APU_VIBRATO_DEPTH_SHIFT 4#define ESM_APU_VIBRATO_DEPTH_MASK (0xf << 4)#define ESM_APU_VIBRATO_PHASE_SHIFT 8#define ESM_APU_VIBRATO_PHASE_MASK (0xff << 8)/* reg 0x0c */#define ESM_APU_RADIUS_SELECT (1 << 6)/* APU Filter Control */#define ESM_APU_FILTER_2POLE_LOPASS 0x00#define ESM_APU_FILTER_2POLE_BANDPASS 0x01#define ESM_APU_FILTER_2POLE_HIPASS 0x02#define ESM_APU_FILTER_1POLE_LOPASS 0x03#define ESM_APU_FILTER_1POLE_HIPASS 0x04#define ESM_APU_FILTER_OFF 0x05/* APU ATFP Type */#define ESM_APU_ATFP_AMPLITUDE 0x00#define ESM_APU_ATFP_TREMELO 0x01#define ESM_APU_ATFP_FILTER 0x02#define ESM_APU_ATFP_PAN 0x03/* APU ATFP Flags */#define ESM_APU_ATFP_FLG_OFF 0x00#define ESM_APU_ATFP_FLG_WAIT 0x01#define ESM_APU_ATFP_FLG_DONE 0x02#define ESM_APU_ATFP_FLG_INPROCESS 0x03/* capture mixing buffer size */#define ESM_MEM_ALIGN 0x1000#define ESM_MIXBUF_SIZE 0x400#define ESM_MODE_PLAY 0#define ESM_MODE_CAPTURE 1/* APU use in the driver */enum snd_enum_apu_type { ESM_APU_PCM_PLAY, ESM_APU_PCM_CAPTURE, ESM_APU_PCM_RATECONV, ESM_APU_FREE};/* chip type */enum { TYPE_MAESTRO, TYPE_MAESTRO2, TYPE_MAESTRO2E};/* DMA Hack! */struct esm_memory { struct snd_dma_buffer buf; int empty; /* status */ struct list_head list;};/* Playback Channel */struct esschan { int running; u8 apu[4]; u8 apu_mode[4];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -