URL
https://opencores.org/ocsvn/test_project/test_project/trunk
Subversion Repositories test_project
[/] [test_project/] [trunk/] [linux_sd_driver/] [sound/] [pci/] [es1968.c] - Rev 66
Go to most recent revision | Compare with Previous | Blame | View Log
/* * 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 #endif static 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_JOYSTICK static int joystick[SNDRV_CARDS]; #endif module_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_JOYSTICK module_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]; /* playback/capture pcm buffer */ struct esm_memory *memory; /* capture mixer buffer */ struct esm_memory *mixbuf; unsigned int hwptr; /* current hw pointer in bytes */ unsigned int count; /* sample counter in bytes */ unsigned int dma_size; /* total buffer size in bytes */ unsigned int frag_size; /* period size in bytes */ unsigned int wav_shift; u16 base[4]; /* offset for ptr */ /* stereo/16bit flag */ unsigned char fmt; int mode; /* playback / capture */ int bob_freq; /* required timer frequency */ struct snd_pcm_substream *substream; /* linked list */ struct list_head list; #ifdef CONFIG_PM u16 wc_map[4]; #endif }; struct es1968 { /* Module Config */ int total_bufsize; /* in bytes */ int playback_streams, capture_streams; unsigned int clock; /* clock */ /* for clock measurement */ unsigned int in_measurement: 1; unsigned int measure_apu; unsigned int measure_lastpos; unsigned int measure_count; /* buffer */ struct snd_dma_buffer dma; /* Resources... */ int irq; unsigned long io_port; int type; struct pci_dev *pci; struct snd_card *card; struct snd_pcm *pcm; int do_pm; /* power-management enabled */ /* DMA memory block */ struct list_head buf_list; /* ALSA Stuff */ struct snd_ac97 *ac97; struct snd_kcontrol *master_switch; /* for h/w volume control */ struct snd_kcontrol *master_volume; struct snd_rawmidi *rmidi; spinlock_t reg_lock; spinlock_t ac97_lock; struct tasklet_struct hwvol_tq; unsigned int in_suspend; /* Maestro Stuff */ u16 maestro_map[32]; int bobclient; /* active timer instancs */ int bob_freq; /* timer frequency */ struct mutex memory_mutex; /* memory lock */ /* APU states */ unsigned char apu[NR_APUS]; /* active substreams */ struct list_head substream_list; spinlock_t substream_lock; #ifdef CONFIG_PM u16 apu_map[NR_APUS][NR_APU_REGS]; #endif #ifdef SUPPORT_JOYSTICK struct gameport *gameport; #endif }; static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); static struct pci_device_id snd_es1968_ids[] = { /* Maestro 1 */ { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, /* Maestro 2 */ { 0x125d, 0x1968, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2 }, /* Maestro 2E */ { 0x125d, 0x1978, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2E }, { 0, } }; MODULE_DEVICE_TABLE(pci, snd_es1968_ids); /* ********************* * Low Level Funcs! * *********************/ /* no spinlock */ static void __maestro_write(struct es1968 *chip, u16 reg, u16 data) { outw(reg, chip->io_port + ESM_INDEX); outw(data, chip->io_port + ESM_DATA); chip->maestro_map[reg] = data; } static inline void maestro_write(struct es1968 *chip, u16 reg, u16 data) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); __maestro_write(chip, reg, data); spin_unlock_irqrestore(&chip->reg_lock, flags); } /* no spinlock */ static u16 __maestro_read(struct es1968 *chip, u16 reg) { if (READABLE_MAP & (1 << reg)) { outw(reg, chip->io_port + ESM_INDEX); chip->maestro_map[reg] = inw(chip->io_port + ESM_DATA); } return chip->maestro_map[reg]; } static inline u16 maestro_read(struct es1968 *chip, u16 reg) { unsigned long flags; u16 result; spin_lock_irqsave(&chip->reg_lock, flags); result = __maestro_read(chip, reg); spin_unlock_irqrestore(&chip->reg_lock, flags); return result; } /* Wait for the codec bus to be free */ static int snd_es1968_ac97_wait(struct es1968 *chip) { int timeout = 100000; while (timeout-- > 0) { if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1)) return 0; cond_resched(); } snd_printd("es1968: ac97 timeout\n"); return 1; /* timeout */ } static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct es1968 *chip = ac97->private_data; unsigned long flags; snd_es1968_ac97_wait(chip); /* Write the bus */ spin_lock_irqsave(&chip->ac97_lock, flags); outw(val, chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ outb(reg, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ spin_unlock_irqrestore(&chip->ac97_lock, flags); } static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { u16 data = 0; struct es1968 *chip = ac97->private_data; unsigned long flags; snd_es1968_ac97_wait(chip); spin_lock_irqsave(&chip->ac97_lock, flags); outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); /*msleep(1);*/ if (! snd_es1968_ac97_wait(chip)) { data = inw(chip->io_port + ESM_AC97_DATA); /*msleep(1);*/ } spin_unlock_irqrestore(&chip->ac97_lock, flags); return data; } /* no spinlock */ static void apu_index_set(struct es1968 *chip, u16 index) { int i; __maestro_write(chip, IDR1_CRAM_POINTER, index); for (i = 0; i < 1000; i++) if (__maestro_read(chip, IDR1_CRAM_POINTER) == index) return; snd_printd("es1968: APU register select failed. (Timeout)\n"); } /* no spinlock */ static void apu_data_set(struct es1968 *chip, u16 data) { int i; for (i = 0; i < 1000; i++) { if (__maestro_read(chip, IDR0_DATA_PORT) == data) return; __maestro_write(chip, IDR0_DATA_PORT, data); } snd_printd("es1968: APU register set probably failed (Timeout)!\n"); } /* no spinlock */ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data) { snd_assert(channel < NR_APUS, return); #ifdef CONFIG_PM chip->apu_map[channel][reg] = data; #endif reg |= (channel << 4); apu_index_set(chip, reg); apu_data_set(chip, data); } static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); __apu_set_register(chip, channel, reg, data); spin_unlock_irqrestore(&chip->reg_lock, flags); } static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg) { snd_assert(channel < NR_APUS, return 0); reg |= (channel << 4); apu_index_set(chip, reg); return __maestro_read(chip, IDR0_DATA_PORT); } static u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg) { unsigned long flags; u16 v; spin_lock_irqsave(&chip->reg_lock, flags); v = __apu_get_register(chip, channel, reg); spin_unlock_irqrestore(&chip->reg_lock, flags); return v; } #if 0 /* ASSP is not supported */ static void assp_set_register(struct es1968 *chip, u32 reg, u32 value) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); outl(reg, chip->io_port + ASSP_INDEX); outl(value, chip->io_port + ASSP_DATA); spin_unlock_irqrestore(&chip->reg_lock, flags); } static u32 assp_get_register(struct es1968 *chip, u32 reg) { unsigned long flags; u32 value; spin_lock_irqsave(&chip->reg_lock, flags); outl(reg, chip->io_port + ASSP_INDEX); value = inl(chip->io_port + ASSP_DATA); spin_unlock_irqrestore(&chip->reg_lock, flags); return value; } #endif static void wave_set_register(struct es1968 *chip, u16 reg, u16 value) { unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); outw(reg, chip->io_port + WC_INDEX); outw(value, chip->io_port + WC_DATA); spin_unlock_irqrestore(&chip->reg_lock, flags); } static u16 wave_get_register(struct es1968 *chip, u16 reg) { unsigned long flags; u16 value; spin_lock_irqsave(&chip->reg_lock, flags); outw(reg, chip->io_port + WC_INDEX); value = inw(chip->io_port + WC_DATA); spin_unlock_irqrestore(&chip->reg_lock, flags); return value; } /* ******************* * Bob the Timer! * *******************/ static void snd_es1968_bob_stop(struct es1968 *chip) { u16 reg; reg = __maestro_read(chip, 0x11); reg &= ~ESM_BOB_ENABLE; __maestro_write(chip, 0x11, reg); reg = __maestro_read(chip, 0x17); reg &= ~ESM_BOB_START; __maestro_write(chip, 0x17, reg); } static void snd_es1968_bob_start(struct es1968 *chip) { int prescale; int divide; /* compute ideal interrupt frequency for buffer size & play rate */ /* first, find best prescaler value to match freq */ for (prescale = 5; prescale < 12; prescale++) if (chip->bob_freq > (ESS_SYSCLK >> (prescale + 9))) break; /* next, back off prescaler whilst getting divider into optimum range */ divide = 1; while ((prescale > 5) && (divide < 32)) { prescale--; divide <<= 1; } divide >>= 1; /* now fine-tune the divider for best match */ for (; divide < 31; divide++) if (chip->bob_freq > ((ESS_SYSCLK >> (prescale + 9)) / (divide + 1))) break; /* divide = 0 is illegal, but don't let prescale = 4! */ if (divide == 0) { divide++; if (prescale > 5) prescale--; } else if (divide > 1) divide--; __maestro_write(chip, 6, 0x9000 | (prescale << 5) | divide); /* set reg */ /* Now set IDR 11/17 */ __maestro_write(chip, 0x11, __maestro_read(chip, 0x11) | 1); __maestro_write(chip, 0x17, __maestro_read(chip, 0x17) | 1); } /* call with substream spinlock */ static void snd_es1968_bob_inc(struct es1968 *chip, int freq) { chip->bobclient++; if (chip->bobclient == 1) { chip->bob_freq = freq; snd_es1968_bob_start(chip); } else if (chip->bob_freq < freq) { snd_es1968_bob_stop(chip); chip->bob_freq = freq; snd_es1968_bob_start(chip); } } /* call with substream spinlock */ static void snd_es1968_bob_dec(struct es1968 *chip) { chip->bobclient--; if (chip->bobclient <= 0) snd_es1968_bob_stop(chip); else if (chip->bob_freq > ESM_BOB_FREQ) { /* check reduction of timer frequency */ int max_freq = ESM_BOB_FREQ; struct esschan *es; list_for_each_entry(es, &chip->substream_list, list) { if (max_freq < es->bob_freq) max_freq = es->bob_freq; } if (max_freq != chip->bob_freq) { snd_es1968_bob_stop(chip); chip->bob_freq = max_freq; snd_es1968_bob_start(chip); } } } static int snd_es1968_calc_bob_rate(struct es1968 *chip, struct esschan *es, struct snd_pcm_runtime *runtime) { /* we acquire 4 interrupts per period for precise control.. */ int freq = runtime->rate * 4; if (es->fmt & ESS_FMT_STEREO) freq <<= 1; if (es->fmt & ESS_FMT_16BIT) freq <<= 1; freq /= es->frag_size; if (freq < ESM_BOB_FREQ) freq = ESM_BOB_FREQ; else if (freq > ESM_BOB_FREQ_MAX) freq = ESM_BOB_FREQ_MAX; return freq; } /************* * PCM Part * *************/ static u32 snd_es1968_compute_rate(struct es1968 *chip, u32 freq) { u32 rate = (freq << 16) / chip->clock; #if 0 /* XXX: do we need this? */ if (rate > 0x10000) rate = 0x10000; #endif return rate; } /* get current pointer */ static inline unsigned int snd_es1968_get_dma_ptr(struct es1968 *chip, struct esschan *es) { unsigned int offset; offset = apu_get_register(chip, es->apu[0], 5); offset -= es->base[0]; return (offset & 0xFFFE); /* hardware is in words */ } static void snd_es1968_apu_set_freq(struct es1968 *chip, int apu, int freq) { apu_set_register(chip, apu, 2, (apu_get_register(chip, apu, 2) & 0x00FF) | ((freq & 0xff) << 8) | 0x10); apu_set_register(chip, apu, 3, freq >> 8); } /* spin lock held */ static inline void snd_es1968_trigger_apu(struct es1968 *esm, int apu, int mode) { /* set the APU mode */ __apu_set_register(esm, apu, 0, (__apu_get_register(esm, apu, 0) & 0xff0f) | (mode << 4)); } static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es) { spin_lock(&chip->reg_lock); __apu_set_register(chip, es->apu[0], 5, es->base[0]); snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]); if (es->mode == ESM_MODE_CAPTURE) { __apu_set_register(chip, es->apu[2], 5, es->base[2]); snd_es1968_trigger_apu(chip, es->apu[2], es->apu_mode[2]); } if (es->fmt & ESS_FMT_STEREO) { __apu_set_register(chip, es->apu[1], 5, es->base[1]); snd_es1968_trigger_apu(chip, es->apu[1], es->apu_mode[1]); if (es->mode == ESM_MODE_CAPTURE) { __apu_set_register(chip, es->apu[3], 5, es->base[3]); snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]); } } spin_unlock(&chip->reg_lock); } static void snd_es1968_pcm_stop(struct es1968 *chip, struct esschan *es) { spin_lock(&chip->reg_lock); snd_es1968_trigger_apu(chip, es->apu[0], 0); snd_es1968_trigger_apu(chip, es->apu[1], 0); if (es->mode == ESM_MODE_CAPTURE) { snd_es1968_trigger_apu(chip, es->apu[2], 0); snd_es1968_trigger_apu(chip, es->apu[3], 0); } spin_unlock(&chip->reg_lock); } /* set the wavecache control reg */ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es, int channel, u32 addr, int capture) { u32 tmpval = (addr - 0x10) & 0xFFF8; if (! capture) { if (!(es->fmt & ESS_FMT_16BIT)) tmpval |= 4; /* 8bit */ if (es->fmt & ESS_FMT_STEREO) tmpval |= 2; /* stereo */ } /* set the wavecache control reg */ wave_set_register(chip, es->apu[channel] << 3, tmpval); #ifdef CONFIG_PM es->wc_map[channel] = tmpval; #endif } static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es, struct snd_pcm_runtime *runtime) { u32 pa; int high_apu = 0; int channel, apu; int i, size; unsigned long flags; u32 freq; size = es->dma_size >> es->wav_shift; if (es->fmt & ESS_FMT_STEREO) high_apu++; for (channel = 0; channel <= high_apu; channel++) { apu = es->apu[channel]; snd_es1968_program_wavecache(chip, es, channel, es->memory->buf.addr, 0); /* Offset to PCMBAR */ pa = es->memory->buf.addr; pa -= chip->dma.addr; pa >>= 1; /* words */ pa |= 0x00400000; /* System RAM (Bit 22) */ if (es->fmt & ESS_FMT_STEREO) { /* Enable stereo */ if (channel) pa |= 0x00800000; /* (Bit 23) */ if (es->fmt & ESS_FMT_16BIT) pa >>= 1; } /* base offset of dma calcs when reading the pointer on this left one */ es->base[channel] = pa & 0xFFFF; for (i = 0; i < 16; i++) apu_set_register(chip, apu, i, 0x0000); /* Load the buffer into the wave engine */ apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8); apu_set_register(chip, apu, 5, pa & 0xFFFF); apu_set_register(chip, apu, 6, (pa + size) & 0xFFFF); /* setting loop == sample len */ apu_set_register(chip, apu, 7, size); /* clear effects/env.. */ apu_set_register(chip, apu, 8, 0x0000); /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */ apu_set_register(chip, apu, 9, 0xD000); /* clear routing stuff */ apu_set_register(chip, apu, 11, 0x0000); /* dma on, no envelopes, filter to all 1s) */ apu_set_register(chip, apu, 0, 0x400F); if (es->fmt & ESS_FMT_16BIT) es->apu_mode[channel] = ESM_APU_16BITLINEAR; else es->apu_mode[channel] = ESM_APU_8BITLINEAR; if (es->fmt & ESS_FMT_STEREO) { /* set panning: left or right */ /* Check: different panning. On my Canyon 3D Chipset the Channels are swapped. I don't know, about the output to the SPDif Link. Perhaps you have to change this and not the APU Regs 4-5. */ apu_set_register(chip, apu, 10, 0x8F00 | (channel ? 0 : 0x10)); es->apu_mode[channel] += 1; /* stereo */ } else apu_set_register(chip, apu, 10, 0x8F08); } spin_lock_irqsave(&chip->reg_lock, flags); /* clear WP interrupts */ outw(1, chip->io_port + 0x04); /* enable WP ints */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); spin_unlock_irqrestore(&chip->reg_lock, flags); freq = runtime->rate; /* set frequency */ if (freq > 48000) freq = 48000; if (freq < 4000) freq = 4000; /* hmmm.. */ if (!(es->fmt & ESS_FMT_16BIT) && !(es->fmt & ESS_FMT_STEREO)) freq >>= 1; freq = snd_es1968_compute_rate(chip, freq); /* Load the frequency, turn on 6dB */ snd_es1968_apu_set_freq(chip, es->apu[0], freq); snd_es1968_apu_set_freq(chip, es->apu[1], freq); } static void init_capture_apu(struct es1968 *chip, struct esschan *es, int channel, unsigned int pa, unsigned int bsize, int mode, int route) { int i, apu = es->apu[channel]; es->apu_mode[channel] = mode; /* set the wavecache control reg */ snd_es1968_program_wavecache(chip, es, channel, pa, 1); /* Offset to PCMBAR */ pa -= chip->dma.addr; pa >>= 1; /* words */ /* base offset of dma calcs when reading the pointer on this left one */ es->base[channel] = pa & 0xFFFF; pa |= 0x00400000; /* bit 22 -> System RAM */ /* Begin loading the APU */ for (i = 0; i < 16; i++) apu_set_register(chip, apu, i, 0x0000); /* need to enable subgroups.. and we should probably have different groups for different /dev/dsps.. */ apu_set_register(chip, apu, 2, 0x8); /* Load the buffer into the wave engine */ apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8); apu_set_register(chip, apu, 5, pa & 0xFFFF); apu_set_register(chip, apu, 6, (pa + bsize) & 0xFFFF); apu_set_register(chip, apu, 7, bsize); /* clear effects/env.. */ apu_set_register(chip, apu, 8, 0x00F0); /* amplitude now? sure. why not. */ apu_set_register(chip, apu, 9, 0x0000); /* set filter tune, radius, polar pan */ apu_set_register(chip, apu, 10, 0x8F08); /* route input */ apu_set_register(chip, apu, 11, route); /* dma on, no envelopes, filter to all 1s) */ apu_set_register(chip, apu, 0, 0x400F); } static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es, struct snd_pcm_runtime *runtime) { int size; u32 freq; unsigned long flags; size = es->dma_size >> es->wav_shift; /* APU assignments: 0 = mono/left SRC 1 = right SRC 2 = mono/left Input Mixer 3 = right Input Mixer */ /* data seems to flow from the codec, through an apu into the 'mixbuf' bit of page, then through the SRC apu and out to the real 'buffer'. ok. sure. */ /* input mixer (left/mono) */ /* parallel in crap, see maestro reg 0xC [8-11] */ init_capture_apu(chip, es, 2, es->mixbuf->buf.addr, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x14); /* SRC (left/mono); get input from inputing apu */ init_capture_apu(chip, es, 0, es->memory->buf.addr, size, ESM_APU_SRCONVERTOR, es->apu[2]); if (es->fmt & ESS_FMT_STEREO) { /* input mixer (right) */ init_capture_apu(chip, es, 3, es->mixbuf->buf.addr + ESM_MIXBUF_SIZE/2, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x15); /* SRC (right) */ init_capture_apu(chip, es, 1, es->memory->buf.addr + size*2, size, ESM_APU_SRCONVERTOR, es->apu[3]); } freq = runtime->rate; /* Sample Rate conversion APUs don't like 0x10000 for their rate */ if (freq > 47999) freq = 47999; if (freq < 4000) freq = 4000; freq = snd_es1968_compute_rate(chip, freq); /* Load the frequency, turn on 6dB */ snd_es1968_apu_set_freq(chip, es->apu[0], freq); snd_es1968_apu_set_freq(chip, es->apu[1], freq); /* fix mixer rate at 48khz. and its _must_ be 0x10000. */ freq = 0x10000; snd_es1968_apu_set_freq(chip, es->apu[2], freq); snd_es1968_apu_set_freq(chip, es->apu[3], freq); spin_lock_irqsave(&chip->reg_lock, flags); /* clear WP interrupts */ outw(1, chip->io_port + 0x04); /* enable WP ints */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); spin_unlock_irqrestore(&chip->reg_lock, flags); } /******************* * ALSA Interface * *******************/ static int snd_es1968_pcm_prepare(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct esschan *es = runtime->private_data; es->dma_size = snd_pcm_lib_buffer_bytes(substream); es->frag_size = snd_pcm_lib_period_bytes(substream); es->wav_shift = 1; /* maestro handles always 16bit */ es->fmt = 0; if (snd_pcm_format_width(runtime->format) == 16) es->fmt |= ESS_FMT_16BIT; if (runtime->channels > 1) { es->fmt |= ESS_FMT_STEREO; if (es->fmt & ESS_FMT_16BIT) /* 8bit is already word shifted */ es->wav_shift++; } es->bob_freq = snd_es1968_calc_bob_rate(chip, es, runtime); switch (es->mode) { case ESM_MODE_PLAY: snd_es1968_playback_setup(chip, es, runtime); break; case ESM_MODE_CAPTURE: snd_es1968_capture_setup(chip, es, runtime); break; } return 0; } static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es = substream->runtime->private_data; spin_lock(&chip->substream_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (es->running) break; snd_es1968_bob_inc(chip, es->bob_freq); es->count = 0; es->hwptr = 0; snd_es1968_pcm_start(chip, es); es->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (! es->running) break; snd_es1968_pcm_stop(chip, es); es->running = 0; snd_es1968_bob_dec(chip); break; } spin_unlock(&chip->substream_lock); return 0; } static snd_pcm_uframes_t snd_es1968_pcm_pointer(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es = substream->runtime->private_data; unsigned int ptr; ptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift; return bytes_to_frames(substream->runtime, ptr % es->dma_size); } static struct snd_pcm_hardware snd_es1968_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 256, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0, }; static struct snd_pcm_hardware snd_es1968_capture = { .info = (SNDRV_PCM_INFO_NONINTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 256, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0, }; /* ************************* * DMA memory management * *************************/ /* Because the Maestro can only take addresses relative to the PCM base address register :( */ static int calc_available_memory_size(struct es1968 *chip) { int max_size = 0; struct esm_memory *buf; mutex_lock(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } mutex_unlock(&chip->memory_mutex); if (max_size >= 128*1024) max_size = 127*1024; return max_size; } /* allocate a new memory chunk with the specified size */ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) { struct esm_memory *buf; size = ALIGN(size, ESM_MEM_ALIGN); mutex_lock(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes >= size) goto __found; } mutex_unlock(&chip->memory_mutex); return NULL; __found: if (buf->buf.bytes > size) { struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); if (chunk == NULL) { mutex_unlock(&chip->memory_mutex); return NULL; } chunk->buf = buf->buf; chunk->buf.bytes -= size; chunk->buf.area += size; chunk->buf.addr += size; chunk->empty = 1; buf->buf.bytes = size; list_add(&chunk->list, &buf->list); } buf->empty = 0; mutex_unlock(&chip->memory_mutex); return buf; } /* free a memory chunk */ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf) { struct esm_memory *chunk; mutex_lock(&chip->memory_mutex); buf->empty = 1; if (buf->list.prev != &chip->buf_list) { chunk = list_entry(buf->list.prev, struct esm_memory, list); if (chunk->empty) { chunk->buf.bytes += buf->buf.bytes; list_del(&buf->list); kfree(buf); buf = chunk; } } if (buf->list.next != &chip->buf_list) { chunk = list_entry(buf->list.next, struct esm_memory, list); if (chunk->empty) { buf->buf.bytes += chunk->buf.bytes; list_del(&chunk->list); kfree(chunk); } } mutex_unlock(&chip->memory_mutex); } static void snd_es1968_free_dmabuf(struct es1968 *chip) { struct list_head *p; if (! chip->dma.area) return; snd_dma_reserve_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci)); while ((p = chip->buf_list.next) != &chip->buf_list) { struct esm_memory *chunk = list_entry(p, struct esm_memory, list); list_del(p); kfree(chunk); } } static int __devinit snd_es1968_init_dmabuf(struct es1968 *chip) { int err; struct esm_memory *chunk; chip->dma.dev.type = SNDRV_DMA_TYPE_DEV; chip->dma.dev.dev = snd_dma_pci_data(chip->pci); if (! snd_dma_get_reserved_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci))) { err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), chip->total_bufsize, &chip->dma); if (err < 0 || ! chip->dma.area) { snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n", chip->total_bufsize); return -ENOMEM; } if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { snd_dma_free_pages(&chip->dma); snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n"); return -ENOMEM; } } INIT_LIST_HEAD(&chip->buf_list); /* allocate an empty chunk */ chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); if (chunk == NULL) { snd_es1968_free_dmabuf(chip); return -ENOMEM; } memset(chip->dma.area, 0, ESM_MEM_ALIGN); chunk->buf = chip->dma; chunk->buf.area += ESM_MEM_ALIGN; chunk->buf.addr += ESM_MEM_ALIGN; chunk->buf.bytes -= ESM_MEM_ALIGN; chunk->empty = 1; list_add(&chunk->list, &chip->buf_list); return 0; } /* setup the dma_areas */ /* buffer is extracted from the pre-allocated memory chunk */ static int snd_es1968_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct esschan *chan = runtime->private_data; int size = params_buffer_bytes(hw_params); if (chan->memory) { if (chan->memory->buf.bytes >= size) { runtime->dma_bytes = size; return 0; } snd_es1968_free_memory(chip, chan->memory); } chan->memory = snd_es1968_new_memory(chip, size); if (chan->memory == NULL) { // snd_printd("cannot allocate dma buffer: size = %d\n", size); return -ENOMEM; } snd_pcm_set_runtime_buffer(substream, &chan->memory->buf); return 1; /* area was changed */ } /* remove dma areas if allocated */ static int snd_es1968_hw_free(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct esschan *chan; if (runtime->private_data == NULL) return 0; chan = runtime->private_data; if (chan->memory) { snd_es1968_free_memory(chip, chan->memory); chan->memory = NULL; } return 0; } /* * allocate APU pair */ static int snd_es1968_alloc_apu_pair(struct es1968 *chip, int type) { int apu; for (apu = 0; apu < NR_APUS; apu += 2) { if (chip->apu[apu] == ESM_APU_FREE && chip->apu[apu + 1] == ESM_APU_FREE) { chip->apu[apu] = chip->apu[apu + 1] = type; return apu; } } return -EBUSY; } /* * release APU pair */ static void snd_es1968_free_apu_pair(struct es1968 *chip, int apu) { chip->apu[apu] = chip->apu[apu + 1] = ESM_APU_FREE; } /****************** * PCM open/close * ******************/ static int snd_es1968_playback_open(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct esschan *es; int apu1; /* search 2 APUs */ apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY); if (apu1 < 0) return apu1; es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); return -ENOMEM; } es->apu[0] = apu1; es->apu[1] = apu1 + 1; es->apu_mode[0] = 0; es->apu_mode[1] = 0; es->running = 0; es->substream = substream; es->mode = ESM_MODE_PLAY; runtime->private_data = es; runtime->hw = snd_es1968_playback; runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = calc_available_memory_size(chip); spin_lock_irq(&chip->substream_lock); list_add(&es->list, &chip->substream_list); spin_unlock_irq(&chip->substream_lock); return 0; } static int snd_es1968_capture_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es; int apu1, apu2; apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE); if (apu1 < 0) return apu1; apu2 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_RATECONV); if (apu2 < 0) { snd_es1968_free_apu_pair(chip, apu1); return apu2; } es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); return -ENOMEM; } es->apu[0] = apu1; es->apu[1] = apu1 + 1; es->apu[2] = apu2; es->apu[3] = apu2 + 1; es->apu_mode[0] = 0; es->apu_mode[1] = 0; es->apu_mode[2] = 0; es->apu_mode[3] = 0; es->running = 0; es->substream = substream; es->mode = ESM_MODE_CAPTURE; /* get mixbuffer */ if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); kfree(es); return -ENOMEM; } memset(es->mixbuf->buf.area, 0, ESM_MIXBUF_SIZE); runtime->private_data = es; runtime->hw = snd_es1968_capture; runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */ snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); spin_lock_irq(&chip->substream_lock); list_add(&es->list, &chip->substream_list); spin_unlock_irq(&chip->substream_lock); return 0; } static int snd_es1968_playback_close(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es; if (substream->runtime->private_data == NULL) return 0; es = substream->runtime->private_data; spin_lock_irq(&chip->substream_lock); list_del(&es->list); spin_unlock_irq(&chip->substream_lock); snd_es1968_free_apu_pair(chip, es->apu[0]); kfree(es); return 0; } static int snd_es1968_capture_close(struct snd_pcm_substream *substream) { struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es; if (substream->runtime->private_data == NULL) return 0; es = substream->runtime->private_data; spin_lock_irq(&chip->substream_lock); list_del(&es->list); spin_unlock_irq(&chip->substream_lock); snd_es1968_free_memory(chip, es->mixbuf); snd_es1968_free_apu_pair(chip, es->apu[0]); snd_es1968_free_apu_pair(chip, es->apu[2]); kfree(es); return 0; } static struct snd_pcm_ops snd_es1968_playback_ops = { .open = snd_es1968_playback_open, .close = snd_es1968_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_es1968_hw_params, .hw_free = snd_es1968_hw_free, .prepare = snd_es1968_pcm_prepare, .trigger = snd_es1968_pcm_trigger, .pointer = snd_es1968_pcm_pointer, }; static struct snd_pcm_ops snd_es1968_capture_ops = { .open = snd_es1968_capture_open, .close = snd_es1968_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_es1968_hw_params, .hw_free = snd_es1968_hw_free, .prepare = snd_es1968_pcm_prepare, .trigger = snd_es1968_pcm_trigger, .pointer = snd_es1968_pcm_pointer, }; /* * measure clock */ #define CLOCK_MEASURE_BUFSIZE 16768 /* enough large for a single shot */ static void __devinit es1968_measure_clock(struct es1968 *chip) { int i, apu; unsigned int pa, offset, t; struct esm_memory *memory; struct timeval start_time, stop_time; if (chip->clock == 0) chip->clock = 48000; /* default clock value */ /* search 2 APUs (although one apu is enough) */ if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) { snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n"); return; } if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) { snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock); snd_es1968_free_apu_pair(chip, apu); return; } memset(memory->buf.area, 0, CLOCK_MEASURE_BUFSIZE); wave_set_register(chip, apu << 3, (memory->buf.addr - 0x10) & 0xfff8); pa = (unsigned int)((memory->buf.addr - chip->dma.addr) >> 1); pa |= 0x00400000; /* System RAM (Bit 22) */ /* initialize apu */ for (i = 0; i < 16; i++) apu_set_register(chip, apu, i, 0x0000); apu_set_register(chip, apu, 0, 0x400f); apu_set_register(chip, apu, 4, ((pa >> 16) & 0xff) << 8); apu_set_register(chip, apu, 5, pa & 0xffff); apu_set_register(chip, apu, 6, (pa + CLOCK_MEASURE_BUFSIZE/2) & 0xffff); apu_set_register(chip, apu, 7, CLOCK_MEASURE_BUFSIZE/2); apu_set_register(chip, apu, 8, 0x0000); apu_set_register(chip, apu, 9, 0xD000); apu_set_register(chip, apu, 10, 0x8F08); apu_set_register(chip, apu, 11, 0x0000); spin_lock_irq(&chip->reg_lock); outw(1, chip->io_port + 0x04); /* clear WP interrupts */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */ spin_unlock_irq(&chip->reg_lock); snd_es1968_apu_set_freq(chip, apu, ((unsigned int)48000 << 16) / chip->clock); /* 48000 Hz */ chip->in_measurement = 1; chip->measure_apu = apu; spin_lock_irq(&chip->reg_lock); snd_es1968_bob_inc(chip, ESM_BOB_FREQ); __apu_set_register(chip, apu, 5, pa & 0xffff); snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR); do_gettimeofday(&start_time); spin_unlock_irq(&chip->reg_lock); msleep(50); spin_lock_irq(&chip->reg_lock); offset = __apu_get_register(chip, apu, 5); do_gettimeofday(&stop_time); snd_es1968_trigger_apu(chip, apu, 0); /* stop */ snd_es1968_bob_dec(chip); chip->in_measurement = 0; spin_unlock_irq(&chip->reg_lock); /* check the current position */ offset -= (pa & 0xffff); offset &= 0xfffe; offset += chip->measure_count * (CLOCK_MEASURE_BUFSIZE/2); t = stop_time.tv_sec - start_time.tv_sec; t *= 1000000; if (stop_time.tv_usec < start_time.tv_usec) t -= start_time.tv_usec - stop_time.tv_usec; else t += stop_time.tv_usec - start_time.tv_usec; if (t == 0) { snd_printk(KERN_ERR "?? calculation error..\n"); } else { offset *= 1000; offset = (offset / t) * 1000 + ((offset % t) * 1000) / t; if (offset < 47500 || offset > 48500) { if (offset >= 40000 && offset <= 50000) chip->clock = (chip->clock * offset) / 48000; } printk(KERN_INFO "es1968: clocking to %d\n", chip->clock); } snd_es1968_free_memory(chip, memory); snd_es1968_free_apu_pair(chip, apu); } /* */ static void snd_es1968_pcm_free(struct snd_pcm *pcm) { struct es1968 *esm = pcm->private_data; snd_es1968_free_dmabuf(esm); esm->pcm = NULL; } static int __devinit snd_es1968_pcm(struct es1968 *chip, int device) { struct snd_pcm *pcm; int err; /* get DMA buffer */ if ((err = snd_es1968_init_dmabuf(chip)) < 0) return err; /* set PCMBAR */ wave_set_register(chip, 0x01FC, chip->dma.addr >> 12); wave_set_register(chip, 0x01FD, chip->dma.addr >> 12); wave_set_register(chip, 0x01FE, chip->dma.addr >> 12); wave_set_register(chip, 0x01FF, chip->dma.addr >> 12); if ((err = snd_pcm_new(chip->card, "ESS Maestro", device, chip->playback_streams, chip->capture_streams, &pcm)) < 0) return err; pcm->private_data = chip; pcm->private_free = snd_es1968_pcm_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1968_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1968_capture_ops); pcm->info_flags = 0; strcpy(pcm->name, "ESS Maestro"); chip->pcm = pcm; return 0; } /* * update pointer */ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es) { unsigned int hwptr; unsigned int diff; struct snd_pcm_substream *subs = es->substream; if (subs == NULL || !es->running) return; hwptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift; hwptr %= es->dma_size; diff = (es->dma_size + hwptr - es->hwptr) % es->dma_size; es->hwptr = hwptr; es->count += diff; if (es->count > es->frag_size) { spin_unlock(&chip->substream_lock); snd_pcm_period_elapsed(subs); spin_lock(&chip->substream_lock); es->count %= es->frag_size; } } /* */ static void es1968_update_hw_volume(unsigned long private_data) { struct es1968 *chip = (struct es1968 *) private_data; int x, val; unsigned long flags; /* Figure out which volume control button was pushed, based on differences from the default register values. */ x = inb(chip->io_port + 0x1c) & 0xee; /* Reset the volume control registers. */ outb(0x88, chip->io_port + 0x1c); outb(0x88, chip->io_port + 0x1d); outb(0x88, chip->io_port + 0x1e); outb(0x88, chip->io_port + 0x1f); if (chip->in_suspend) return; if (! chip->master_switch || ! chip->master_volume) return; /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ spin_lock_irqsave(&chip->ac97_lock, flags); val = chip->ac97->regs[AC97_MASTER]; switch (x) { case 0x88: /* mute */ val ^= 0x8000; chip->ac97->regs[AC97_MASTER] = val; outw(val, chip->io_port + ESM_AC97_DATA); outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); break; case 0xaa: /* volume up */ if ((val & 0x7f) > 0) val--; if ((val & 0x7f00) > 0) val -= 0x0100; chip->ac97->regs[AC97_MASTER] = val; outw(val, chip->io_port + ESM_AC97_DATA); outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; case 0x66: /* volume down */ if ((val & 0x7f) < 0x1f) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; chip->ac97->regs[AC97_MASTER] = val; outw(val, chip->io_port + ESM_AC97_DATA); outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; } spin_unlock_irqrestore(&chip->ac97_lock, flags); } /* * interrupt handler */ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) { struct es1968 *chip = dev_id; u32 event; if (!(event = inb(chip->io_port + 0x1A))) return IRQ_NONE; outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); if (event & ESM_HWVOL_IRQ) tasklet_hi_schedule(&chip->hwvol_tq); /* we'll do this later */ /* else ack 'em all, i imagine */ outb(0xFF, chip->io_port + 0x1A); if ((event & ESM_MPU401_IRQ) && chip->rmidi) { snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); } if (event & ESM_SOUND_IRQ) { struct esschan *es; spin_lock(&chip->substream_lock); list_for_each_entry(es, &chip->substream_list, list) { if (es->running) snd_es1968_update_pcm(chip, es); } spin_unlock(&chip->substream_lock); if (chip->in_measurement) { unsigned int curp = __apu_get_register(chip, chip->measure_apu, 5); if (curp < chip->measure_lastpos) chip->measure_count++; chip->measure_lastpos = curp; } } return IRQ_HANDLED; } /* * Mixer stuff */ static int __devinit snd_es1968_mixer(struct es1968 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; struct snd_ctl_elem_id id; int err; static struct snd_ac97_bus_ops ops = { .write = snd_es1968_ac97_write, .read = snd_es1968_ac97_read, }; if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) return err; pbus->no_vra = 1; /* ES1968 doesn't need VRA */ memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) return err; /* attach master switch / volumes for h/w volume control */ memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Switch"); chip->master_switch = snd_ctl_find_id(chip->card, &id); memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Volume"); chip->master_volume = snd_ctl_find_id(chip->card, &id); return 0; } /* * reset ac97 codec */ static void snd_es1968_ac97_reset(struct es1968 *chip) { unsigned long ioaddr = chip->io_port; unsigned short save_ringbus_a; unsigned short save_68; unsigned short w; unsigned int vend; /* save configuration */ save_ringbus_a = inw(ioaddr + 0x36); //outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); /* clear second codec id? */ /* set command/status address i/o to 1st codec */ outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); /* disable ac link */ outw(0x0000, ioaddr + 0x36); save_68 = inw(ioaddr + 0x68); pci_read_config_word(chip->pci, 0x58, &w); /* something magical with gpio and bus arb. */ pci_read_config_dword(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend); if (w & 1) save_68 |= 0x10; outw(0xfffe, ioaddr + 0x64); /* unmask gpio 0 */ outw(0x0001, ioaddr + 0x68); /* gpio write */ outw(0x0000, ioaddr + 0x60); /* write 0 to gpio 0 */ udelay(20); outw(0x0001, ioaddr + 0x60); /* write 1 to gpio 1 */ msleep(20); outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */ outw((inw(ioaddr + 0x38) & 0xfffc) | 0x1, ioaddr + 0x38); outw((inw(ioaddr + 0x3a) & 0xfffc) | 0x1, ioaddr + 0x3a); outw((inw(ioaddr + 0x3c) & 0xfffc) | 0x1, ioaddr + 0x3c); /* now the second codec */ /* disable ac link */ outw(0x0000, ioaddr + 0x36); outw(0xfff7, ioaddr + 0x64); /* unmask gpio 3 */ save_68 = inw(ioaddr + 0x68); outw(0x0009, ioaddr + 0x68); /* gpio write 0 & 3 ?? */ outw(0x0001, ioaddr + 0x60); /* write 1 to gpio */ udelay(20); outw(0x0009, ioaddr + 0x60); /* write 9 to gpio */ msleep(500); //outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); #if 0 /* the loop here needs to be much better if we want it.. */ snd_printk(KERN_INFO "trying software reset\n"); /* try and do a software reset */ outb(0x80 | 0x7c, ioaddr + 0x30); for (w = 0;; w++) { if ((inw(ioaddr + 0x30) & 1) == 0) { if (inb(ioaddr + 0x32) != 0) break; outb(0x80 | 0x7d, ioaddr + 0x30); if (((inw(ioaddr + 0x30) & 1) == 0) && (inb(ioaddr + 0x32) != 0)) break; outb(0x80 | 0x7f, ioaddr + 0x30); if (((inw(ioaddr + 0x30) & 1) == 0) && (inb(ioaddr + 0x32) != 0)) break; } if (w > 10000) { outb(inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */ msleep(500); /* oh my.. */ outb(inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37); udelay(1); outw(0x80, ioaddr + 0x30); for (w = 0; w < 10000; w++) { if ((inw(ioaddr + 0x30) & 1) == 0) break; } } } #endif if (vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) { /* turn on external amp? */ outw(0xf9ff, ioaddr + 0x64); outw(inw(ioaddr + 0x68) | 0x600, ioaddr + 0x68); outw(0x0209, ioaddr + 0x60); } /* restore.. */ outw(save_ringbus_a, ioaddr + 0x36); /* Turn on the 978 docking chip. First frob the "master output enable" bit, then set most of the playback volume control registers to max. */ outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0); outb(0xff, ioaddr+0xc3); outb(0xff, ioaddr+0xc4); outb(0xff, ioaddr+0xc6); outb(0xff, ioaddr+0xc8); outb(0x3f, ioaddr+0xcf); outb(0x3f, ioaddr+0xd0); } static void snd_es1968_reset(struct es1968 *chip) { /* Reset */ outw(ESM_RESET_MAESTRO | ESM_RESET_DIRECTSOUND, chip->io_port + ESM_PORT_HOST_IRQ); udelay(10); outw(0x0000, chip->io_port + ESM_PORT_HOST_IRQ); udelay(10); } /* * initialize maestro chip */ static void snd_es1968_chip_init(struct es1968 *chip) { struct pci_dev *pci = chip->pci; int i; unsigned long iobase = chip->io_port; u16 w; u32 n; /* We used to muck around with pci config space that * we had no business messing with. We don't know enough * about the machine to know which DMA mode is appropriate, * etc. We were guessing wrong on some machines and making * them unhappy. We now trust in the BIOS to do things right, * which almost certainly means a new host of problems will * arise with broken BIOS implementations. screw 'em. * We're already intolerant of machines that don't assign * IRQs. */ /* Config Reg A */ pci_read_config_word(pci, ESM_CONFIG_A, &w); w &= ~DMA_CLEAR; /* Clear DMA bits */ w &= ~(PIC_SNOOP1 | PIC_SNOOP2); /* Clear Pic Snoop Mode Bits */ w &= ~SAFEGUARD; /* Safeguard off */ w |= POST_WRITE; /* Posted write */ w |= PCI_TIMING; /* PCI timing on */ /* XXX huh? claims to be reserved.. */ w &= ~SWAP_LR; /* swap left/right seems to only have effect on SB Emulation */ w &= ~SUBTR_DECODE; /* Subtractive decode off */ pci_write_config_word(pci, ESM_CONFIG_A, w); /* Config Reg B */ pci_read_config_word(pci, ESM_CONFIG_B, &w); w &= ~(1 << 15); /* Turn off internal clock multiplier */ /* XXX how do we know which to use? */ w &= ~(1 << 14); /* External clock */ w &= ~SPDIF_CONFB; /* disable S/PDIF output */ w |= HWV_CONFB; /* HWV on */ w |= DEBOUNCE; /* Debounce off: easier to push the HW buttons */ w &= ~GPIO_CONFB; /* GPIO 4:5 */ w |= CHI_CONFB; /* Disconnect from the CHI. Enabling this made a dell 7500 work. */ w &= ~IDMA_CONFB; /* IDMA off (undocumented) */ w &= ~MIDI_FIX; /* MIDI fix off (undoc) */ w &= ~(1 << 1); /* reserved, always write 0 */ w &= ~IRQ_TO_ISA; /* IRQ to ISA off (undoc) */ pci_write_config_word(pci, ESM_CONFIG_B, w); /* DDMA off */ pci_read_config_word(pci, ESM_DDMA, &w); w &= ~(1 << 0); pci_write_config_word(pci, ESM_DDMA, w); /* * Legacy mode */ pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &w); w |= ESS_DISABLE_AUDIO; /* Disable Legacy Audio */ w &= ~ESS_ENABLE_SERIAL_IRQ; /* Disable SIRQ */ w &= ~(0x1f); /* disable mpu irq/io, game port, fm, SB */ pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, w); /* Set up 978 docking control chip. */ pci_read_config_word(pci, 0x58, &w); w|=1<<2; /* Enable 978. */ w|=1<<3; /* Turn on 978 hardware volume control. */ w&=~(1<<11); /* Turn on 978 mixer volume control. */ pci_write_config_word(pci, 0x58, w); /* Sound Reset */ snd_es1968_reset(chip); /* * Ring Bus Setup */ /* setup usual 0x34 stuff.. 0x36 may be chip specific */ outw(0xC090, iobase + ESM_RING_BUS_DEST); /* direct sound, stereo */ udelay(20); outw(0x3000, iobase + ESM_RING_BUS_CONTR_A); /* enable ringbus/serial */ udelay(20); /* * Reset the CODEC */ snd_es1968_ac97_reset(chip); /* Ring Bus Control B */ n = inl(iobase + ESM_RING_BUS_CONTR_B); n &= ~RINGB_EN_SPDIF; /* SPDIF off */ //w |= RINGB_EN_2CODEC; /* enable 2nd codec */ outl(n, iobase + ESM_RING_BUS_CONTR_B); /* Set hardware volume control registers to midpoints. We can tell which button was pushed based on how they change. */ outb(0x88, iobase+0x1c); outb(0x88, iobase+0x1d); outb(0x88, iobase+0x1e); outb(0x88, iobase+0x1f); /* it appears some maestros (dell 7500) only work if these are set, regardless of wether we use the assp or not. */ outb(0, iobase + ASSP_CONTROL_B); outb(3, iobase + ASSP_CONTROL_A); /* M: Reserved bits... */ outb(0, iobase + ASSP_CONTROL_C); /* M: Disable ASSP, ASSP IRQ's and FM Port */ /* * set up wavecache */ for (i = 0; i < 16; i++) { /* Write 0 into the buffer area 0x1E0->1EF */ outw(0x01E0 + i, iobase + WC_INDEX); outw(0x0000, iobase + WC_DATA); /* The 1.10 test program seem to write 0 into the buffer area * 0x1D0-0x1DF too.*/ outw(0x01D0 + i, iobase + WC_INDEX); outw(0x0000, iobase + WC_DATA); } wave_set_register(chip, IDR7_WAVE_ROMRAM, (wave_get_register(chip, IDR7_WAVE_ROMRAM) & 0xFF00)); wave_set_register(chip, IDR7_WAVE_ROMRAM, wave_get_register(chip, IDR7_WAVE_ROMRAM) | 0x100); wave_set_register(chip, IDR7_WAVE_ROMRAM, wave_get_register(chip, IDR7_WAVE_ROMRAM) & ~0x200); wave_set_register(chip, IDR7_WAVE_ROMRAM, wave_get_register(chip, IDR7_WAVE_ROMRAM) | ~0x400); maestro_write(chip, IDR2_CRAM_DATA, 0x0000); /* Now back to the DirectSound stuff */ /* audio serial configuration.. ? */ maestro_write(chip, 0x08, 0xB004); maestro_write(chip, 0x09, 0x001B); maestro_write(chip, 0x0A, 0x8000); maestro_write(chip, 0x0B, 0x3F37); maestro_write(chip, 0x0C, 0x0098); /* parallel in, has something to do with recording :) */ maestro_write(chip, 0x0C, (maestro_read(chip, 0x0C) & ~0xF000) | 0x8000); /* parallel out */ maestro_write(chip, 0x0C, (maestro_read(chip, 0x0C) & ~0x0F00) | 0x0500); maestro_write(chip, 0x0D, 0x7632); /* Wave cache control on - test off, sg off, enable, enable extra chans 1Mb */ w = inw(iobase + WC_CONTROL); w &= ~0xFA00; /* Seems to be reserved? I don't know */ w |= 0xA000; /* reserved... I don't know */ w &= ~0x0200; /* Channels 56,57,58,59 as Extra Play,Rec Channel enable Seems to crash the Computer if enabled... */ w |= 0x0100; /* Wave Cache Operation Enabled */ w |= 0x0080; /* Channels 60/61 as Placback/Record enabled */ w &= ~0x0060; /* Clear Wavtable Size */ w |= 0x0020; /* Wavetable Size : 1MB */ /* Bit 4 is reserved */ w &= ~0x000C; /* DMA Stuff? I don't understand what the datasheet means */ /* Bit 1 is reserved */ w &= ~0x0001; /* Test Mode off */ outw(w, iobase + WC_CONTROL); /* Now clear the APU control ram */ for (i = 0; i < NR_APUS; i++) { for (w = 0; w < NR_APU_REGS; w++) apu_set_register(chip, i, w, 0); } } /* Enable IRQ's */ static void snd_es1968_start_irq(struct es1968 *chip) { unsigned short w; w = ESM_HIRQ_DSIE | ESM_HIRQ_HW_VOLUME; if (chip->rmidi) w |= ESM_HIRQ_MPU401; outw(w, chip->io_port + ESM_PORT_HOST_IRQ); } #ifdef CONFIG_PM /* * PM support */ static int es1968_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct es1968 *chip = card->private_data; if (! chip->do_pm) return 0; chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_es1968_bob_stop(chip); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } static int es1968_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct es1968 *chip = card->private_data; struct esschan *es; if (! chip->do_pm) return 0; /* restore all our config */ pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "es1968: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); snd_es1968_chip_init(chip); /* need to restore the base pointers.. */ if (chip->dma.addr) { /* set PCMBAR */ wave_set_register(chip, 0x01FC, chip->dma.addr >> 12); } snd_es1968_start_irq(chip); /* restore ac97 state */ snd_ac97_resume(chip->ac97); list_for_each_entry(es, &chip->substream_list, list) { switch (es->mode) { case ESM_MODE_PLAY: snd_es1968_playback_setup(chip, es, es->substream->runtime); break; case ESM_MODE_CAPTURE: snd_es1968_capture_setup(chip, es, es->substream->runtime); break; } } /* start timer again */ if (chip->bobclient) snd_es1968_bob_start(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); chip->in_suspend = 0; return 0; } #endif /* CONFIG_PM */ #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 static int __devinit snd_es1968_create_gameport(struct es1968 *chip, int dev) { struct gameport *gp; struct resource *r; u16 val; if (!joystick[dev]) return -ENODEV; r = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport"); if (!r) return -EBUSY; chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "es1968: cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &val); pci_write_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04); gameport_set_name(gp, "ES1968 Gameport"); gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); gameport_set_dev_parent(gp, &chip->pci->dev); gp->io = JOYSTICK_ADDR; gameport_set_port_data(gp, r); gameport_register_port(gp); return 0; } static void snd_es1968_free_gameport(struct es1968 *chip) { if (chip->gameport) { struct resource *r = gameport_get_port_data(chip->gameport); gameport_unregister_port(chip->gameport); chip->gameport = NULL; release_and_free_resource(r); } } #else static inline int snd_es1968_create_gameport(struct es1968 *chip, int dev) { return -ENOSYS; } static inline void snd_es1968_free_gameport(struct es1968 *chip) { } #endif static int snd_es1968_free(struct es1968 *chip) { if (chip->io_port) { synchronize_irq(chip->irq); outw(1, chip->io_port + 0x04); /* clear WP interrupts */ outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */ } if (chip->irq >= 0) free_irq(chip->irq, chip); snd_es1968_free_gameport(chip); chip->master_switch = NULL; chip->master_volume = NULL; pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0; } static int snd_es1968_dev_free(struct snd_device *device) { struct es1968 *chip = device->device_data; return snd_es1968_free(chip); } struct ess_device_list { unsigned short type; /* chip type */ unsigned short vendor; /* subsystem vendor id */ }; static struct ess_device_list pm_whitelist[] __devinitdata = { { TYPE_MAESTRO2E, 0x0e11 }, /* Compaq Armada */ { TYPE_MAESTRO2E, 0x1028 }, { TYPE_MAESTRO2E, 0x103c }, { TYPE_MAESTRO2E, 0x1179 }, { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ { TYPE_MAESTRO2E, 0x1558 }, }; static struct ess_device_list mpu_blacklist[] __devinitdata = { { TYPE_MAESTRO2, 0x125d }, }; static int __devinit snd_es1968_create(struct snd_card *card, struct pci_dev *pci, int total_bufsize, int play_streams, int capt_streams, int chip_type, int do_pm, struct es1968 **chip_ret) { static struct snd_device_ops ops = { .dev_free = snd_es1968_dev_free, }; struct es1968 *chip; int i, err; *chip_ret = NULL; /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { pci_disable_device(pci); return -ENOMEM; } /* Set Vars */ chip->type = chip_type; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->substream_lock); INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->substream_list); spin_lock_init(&chip->ac97_lock); mutex_init(&chip->memory_mutex); tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); chip->card = card; chip->pci = pci; chip->irq = -1; chip->total_bufsize = total_bufsize; /* in bytes */ chip->playback_streams = play_streams; chip->capture_streams = capt_streams; if ((err = pci_request_regions(pci, "ESS Maestro")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->io_port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED, "ESS Maestro", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1968_free(chip); return -EBUSY; } chip->irq = pci->irq; /* Clear Maestro_map */ for (i = 0; i < 32; i++) chip->maestro_map[i] = 0; /* Clear Apu Map */ for (i = 0; i < NR_APUS; i++) chip->apu[i] = ESM_APU_FREE; /* just to be sure */ pci_set_master(pci); if (do_pm > 1) { /* disable power-management if not on the whitelist */ unsigned short vend; pci_read_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend); for (i = 0; i < (int)ARRAY_SIZE(pm_whitelist); i++) { if (chip->type == pm_whitelist[i].type && vend == pm_whitelist[i].vendor) { do_pm = 1; break; } } if (do_pm > 1) { /* not matched; disabling pm */ printk(KERN_INFO "es1968: not attempting power management.\n"); do_pm = 0; } } chip->do_pm = do_pm; snd_es1968_chip_init(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_es1968_free(chip); return err; } snd_card_set_dev(card, &pci->dev); *chip_ret = chip; return 0; } /* */ static int __devinit snd_es1968_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; struct es1968 *chip; unsigned int i; int err; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (!card) return -ENOMEM; if (total_bufsize[dev] < 128) total_bufsize[dev] = 128; if (total_bufsize[dev] > 4096) total_bufsize[dev] = 4096; if ((err = snd_es1968_create(card, pci, total_bufsize[dev] * 1024, /* in bytes */ pcm_substreams_p[dev], pcm_substreams_c[dev], pci_id->driver_data, use_pm[dev], &chip)) < 0) { snd_card_free(card); return err; } card->private_data = chip; switch (chip->type) { case TYPE_MAESTRO2E: strcpy(card->driver, "ES1978"); strcpy(card->shortname, "ESS ES1978 (Maestro 2E)"); break; case TYPE_MAESTRO2: strcpy(card->driver, "ES1968"); strcpy(card->shortname, "ESS ES1968 (Maestro 2)"); break; case TYPE_MAESTRO: strcpy(card->driver, "ESM1"); strcpy(card->shortname, "ESS Maestro 1"); break; } if ((err = snd_es1968_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } if ((err = snd_es1968_mixer(chip)) < 0) { snd_card_free(card); return err; } if (enable_mpu[dev] == 2) { /* check the black list */ unsigned short vend; pci_read_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend); for (i = 0; i < ARRAY_SIZE(mpu_blacklist); i++) { if (chip->type == mpu_blacklist[i].type && vend == mpu_blacklist[i].vendor) { enable_mpu[dev] = 0; break; } } } if (enable_mpu[dev]) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->io_port + ESM_MPU401_PORT, MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi)) < 0) { printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); } } snd_es1968_create_gameport(chip, dev); snd_es1968_start_irq(chip); chip->clock = clock[dev]; if (! chip->clock) es1968_measure_clock(chip); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->io_port, chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); dev++; return 0; } static void __devexit snd_es1968_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } static struct pci_driver driver = { .name = "ES1968 (ESS Maestro)", .id_table = snd_es1968_ids, .probe = snd_es1968_probe, .remove = __devexit_p(snd_es1968_remove), #ifdef CONFIG_PM .suspend = es1968_suspend, .resume = es1968_resume, #endif }; static int __init alsa_card_es1968_init(void) { return pci_register_driver(&driver); } static void __exit alsa_card_es1968_exit(void) { pci_unregister_driver(&driver); } module_init(alsa_card_es1968_init) module_exit(alsa_card_es1968_exit)
Go to most recent revision | Compare with Previous | Blame | View Log