diff options
Diffstat (limited to 'sound/pci/emu10k1')
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 616 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1x.c | 6 | ||||
-rw-r--r-- | sound/pci/emu10k1/emufx.c | 204 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumixer.c | 745 | ||||
-rw-r--r-- | sound/pci/emu10k1/emupcm.c | 147 | ||||
-rw-r--r-- | sound/pci/emu10k1/emuproc.c | 34 | ||||
-rw-r--r-- | sound/pci/emu10k1/io.c | 104 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.c | 14 | ||||
-rw-r--r-- | sound/pci/emu10k1/p17v.h | 47 | ||||
-rw-r--r-- | sound/pci/emu10k1/voice.c | 2 |
10 files changed, 1709 insertions, 210 deletions
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 972ec40d816..80aa585eade 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -3,8 +3,10 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips * - * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> * Added support for Audigy 2 Value. + * Added EMU 1010 support. + * General bug fixes and enhancements. * * * BUGS: @@ -41,8 +43,10 @@ #include <sound/core.h> #include <sound/emu10k1.h> +#include <linux/firmware.h> #include "p16v.h" #include "tina2.h" +#include "p17v.h" /************************************************************************* @@ -117,11 +121,28 @@ static unsigned int spi_dac_init[] = { 0x0622, 0x1400, }; + +static unsigned int i2c_adc_init[][2] = { + { 0x17, 0x00 }, /* Reset */ + { 0x07, 0x00 }, /* Timeout */ + { 0x0b, 0x22 }, /* Interface control */ + { 0x0c, 0x22 }, /* Master mode control */ + { 0x0d, 0x08 }, /* Powerdown control */ + { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ + { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ + { 0x10, 0x7b }, /* ALC Control 1 */ + { 0x11, 0x00 }, /* ALC Control 2 */ + { 0x12, 0x32 }, /* ALC Control 3 */ + { 0x13, 0x00 }, /* Noise gate control */ + { 0x14, 0xa6 }, /* Limiter control */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ +}; static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; int ch; + u32 tmp; /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, @@ -160,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; @@ -181,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ - u32 tmp; - snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); @@ -211,7 +228,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) int size, n; size = ARRAY_SIZE(spi_dac_init); - for (n=0; n < size; n++) + for (n = 0; n < size; n++) snd_emu10k1_spi_write(emu, spi_dac_init[n]); snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10); @@ -228,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ } + if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ + int size, n; + + snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); + tmp = inl(emu->port + A_IOCFG); + outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ + tmp = inl(emu->port + A_IOCFG); + size = ARRAY_SIZE(i2c_adc_init); + for (n = 0; n < size; n++) + snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); + for (n=0; n < 4; n++) { + emu->i2c_capture_volume[n][0]= 0xcf; + emu->i2c_capture_volume[n][1]= 0xcf; + } + + } + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ @@ -239,6 +273,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); } + if (emu->card_capabilities->emu1010) { + outl(HCFG_AUTOMUTE_ASYNC | + HCFG_EMU32_SLAVE | + HCFG_AUDIOENABLE, emu->port + HCFG); /* * Hokay, setup HCFG * Mute Disable Audio = 0 @@ -246,7 +284,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) * Lock Sound Memory = 0 * Auto Mute = 1 */ - if (emu->audigy) { + } else if (emu->audigy) { if (emu->revision == 4) /* audigy2 */ outl(HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | @@ -265,8 +303,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); @@ -284,8 +324,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } } - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { /* enable analog output */ unsigned int reg = inl(emu->port + A_IOCFG); outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); @@ -302,8 +344,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); /* Enable analog/digital outs on audigy */ - if ( emu->card_capabilities->emu1212m) { - ; /* Disable all access to A_IOCFG for the emu1212m */ + if (emu->card_capabilities->emu1010) { + ; /* Disable all access to A_IOCFG for the emu1010 */ + } else if (emu->card_capabilities->i2c_adc) { + ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); @@ -596,133 +640,423 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) { - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - if (value<0 || value>0x3f) /* 0 to 0x3f are values */ - return 1; - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - outl(value, emu->port + A_IOCFG); - outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - - return 0; -} - -static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) -{ - if (reg<0 || reg>0x3f) - return 1; - reg+=0x40; /* 0x40 upwards are registers. */ - outl(reg, emu->port + A_IOCFG); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - *value = inl(emu->port + A_IOCFG); - - return 0; -} + int err; + int n, i; + int reg; + int value; + const struct firmware *fw_entry; + + if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { + snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); + return err; + } + snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); + if (fw_entry->size != 0x133a4) { + snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); + return -EINVAL; + } -static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value) -{ - snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) ); - snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) ); + /* The FPGA is a Xilinx Spartan IIE XC2S50E */ + /* GPIO7 -> FPGA PGMN + * GPIO6 -> FPGA CCLK + * GPIO5 -> FPGA DIN + * FPGA CONFIG OFF -> FPGA PGMN + */ + outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ + udelay(1); + outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ + udelay(100); /* Allow FPGA memory to clean */ + for(n = 0; n < fw_entry->size; n++) { + value=fw_entry->data[n]; + for(i = 0; i < 8; i++) { + reg = 0x80; + if (value & 0x1) + reg = reg | 0x20; + value = value >> 1; + outl(reg, emu->port + A_IOCFG); + outl(reg | 0x40, emu->port + A_IOCFG); + } + } + /* After programming, set GPIO bit 4 high again. */ + outl(0x10, emu->port + A_IOCFG); + + release_firmware(fw_entry); return 0; } -static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) { unsigned int i; - int tmp; - - snd_printk(KERN_ERR "emu1212m: Special config.\n"); + int tmp,tmp2; + int reg; + int err; + const char *hana_filename = "emu/hana.fw"; + const char *dock_filename = "emu/audio_dock.fw"; + + snd_printk(KERN_INFO "emu1010: Special config.\n"); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ outl(0x0005a00c, emu->port + HCFG); - outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0005a004, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); + /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, + * Mute all codecs. + */ outl(0x0005a000, emu->port + HCFG); - snd_emu1212m_fpga_read(emu, 0x22, &tmp ); - snd_emu1212m_fpga_read(emu, 0x23, &tmp ); - snd_emu1212m_fpga_read(emu, 0x24, &tmp ); - snd_emu1212m_fpga_write(emu, 0x04, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x0b, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0b, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x10, &tmp ); - snd_emu1212m_fpga_write(emu, 0x10, 0x00 ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x13, &tmp ); - snd_emu1212m_fpga_write(emu, 0x13, 0x0f ); - snd_emu1212m_fpga_read(emu, 0x11, &tmp ); - snd_emu1212m_fpga_write(emu, 0x11, 0x30 ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x09, 0x0f ); - snd_emu1212m_fpga_write(emu, 0x06, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x05, 0x00 ); - snd_emu1212m_fpga_write(emu, 0x0e, 0x12 ); - snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201); - snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500); - snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501); - snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400); - snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401); - snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402); - snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403); - snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404); - snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405); - snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406); - snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407); - snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100); - snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104); - snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200); - snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201); - for (i=0;i < 0x20;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000); + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + + /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg1=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA netlist already present so clear it */ + /* Return to programming mode */ + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); } - for (i=0;i < 4;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg2=0x%x\n",reg); + if (reg == 0x55) { + /* FPGA failed to return to programming mode */ + return -ENODEV; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000); + snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); + if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) { + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename); + return err; } - for (i=0;i < 7;i++) { - snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000); + + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); + return -ENODEV; } - snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108); - snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c); - snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110); - snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114); - snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118); - snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c); - snd_emu1212m_fpga_write(emu, 0x07, 0x01 ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); + snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); + snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); + /* Enable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); + /* ADAT input. */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); + /* Set no attenuation on Audio Dock pads. */ + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); + emu->emu1010.adc_pads = 0x00; + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + /* Unmute Audio dock DACs, Headphone source DAC-4. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); + /* DAC PADs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); + emu->emu1010.dac_pads = 0x0f; + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); + /* MIDI routing */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); + /* Unknown. */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ + /* IRQ Enable: All off */ + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); + /* Default WCLK set to 48kHz. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + /* Audio Dock LEDs. */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - outl(0x0000a000, emu->port + HCFG); +#if 0 + /* For 96kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2); +#endif +#if 0 + /* For 192kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4); +#endif +#if 1 + /* For 48kHz */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1); +#endif +#if 0 + /* Original */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); +#endif + for (i = 0;i < 0x20; i++ ) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 4; i++) { + /* Hana SPDIF Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hamoa DAC <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); + } + for (i = 0;i < 7; i++) { + /* Hana ADAT Out <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); + } + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Mute all codecs. + */ + outl(0x0000a000, emu->port + HCFG); + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, + * Lock Sound Memory Cache, Lock Tank Memory Cache, + * Un-Mute all codecs. + */ outl(0x0000a001, emu->port + HCFG); + /* Initial boot complete. Now patches */ - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_write(emu, 0x0c, 0x19 ); - snd_emu1212m_fpga_write(emu, 0x12, 0x0c ); - snd_emu1212m_fpga_read(emu, 0x0a, &tmp ); - snd_emu1212m_fpga_write(emu, 0x0a, 0x10 ); - - snd_emu1212m_fpga_read(emu, 0x20, &tmp ); - snd_emu1212m_fpga_read(emu, 0x21, &tmp ); - - snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312); - snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313); - snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302); - snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + + /* Delay to allow Audio Dock to settle */ + msleep(100); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + /* FIXME: The loading of this should be able to happen any time, + * as the user can plug/unplug it at any time + */ + if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) { + return err; + } + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + if (reg != 0x55) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + return 0; + return -ENODEV; + } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + } +#if 0 + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ +#endif + /* Default outputs */ + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[0] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[1] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[2] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[3] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[4] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[5] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[6] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[7] = 28; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[8] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[9] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[10] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[11] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[12] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[13] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[14] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[15] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ + emu->emu1010.output_source[16] = 21; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); + emu->emu1010.output_source[17] = 22; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); + emu->emu1010.output_source[18] = 23; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); + emu->emu1010.output_source[19] = 24; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); + emu->emu1010.output_source[20] = 25; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); + emu->emu1010.output_source[21] = 26; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); + emu->emu1010.output_source[22] = 27; + snd_emu1010_fpga_link_dst_src_write(emu, + EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); + emu->emu1010.output_source[23] = 28; + + /* TEMP: Select SPDIF in/out */ + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + + /* TEMP: Select 48kHz SPDIF out */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + emu->emu1010.internal_clock = 1; /* 48000 */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ return 0; } @@ -747,6 +1081,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } snd_emu10k1_free_efx(emu); } + if (emu->card_capabilities->emu1010) { + /* Disable 48Volt power to Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); if (emu->silent_page.area) @@ -838,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ - /* Tested by James@superbug.co.uk 22th December 2005 */ + /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) - * Audio inputs not tested. + * Audio Mic/Line inputs working. + * Digital input not tested. */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 @@ -849,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = { * AC97: None * CA0151: None */ + /* Tested by James@superbug.co.uk 4th April 2006 */ + /* A_IOCFG bits + * Output + * 0: Not Used + * 1: 0 = Mute all the 7.1 channel out. 1 = unmute. + * 2: Analog input 0 = line in, 1 = mic in + * 3: Not Used + * 4: Digital output 0 = off, 1 = on. + * 5: Not Used + * 6: Not Used + * 7: Not Used + * Input + * All bits 1 (0x3fxx) means nothing plugged in. + * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing. + * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing. + * C-D: 2 = Front/Rear/etc, 3 = nothing. + * E-F: Always 0 + * + */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", @@ -856,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .ca_cardbus_chip = 1, .spi_dac = 1, + .i2c_adc = 1, .spk71 = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", @@ -865,11 +1224,12 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ac97_chip = 1} , /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1212m [4001]", - .id = "EMU1212m", + .driver = "Audigy2", .name = "E-mu 1010 [4001]", + .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, - .emu1212m = 1} , + .spk71 = 1, + .emu1010 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", @@ -1297,8 +1657,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } else if (emu->card_capabilities->ca_cardbus_chip) { if ((err = snd_emu10k1_cardbus_init(emu)) < 0) goto error; - } else if (emu->card_capabilities->emu1212m) { - if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) { + } else if (emu->card_capabilities->emu1010) { + if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { snd_emu10k1_free(emu); return err; } @@ -1446,8 +1806,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->ca_cardbus_chip) snd_emu10k1_cardbus_init(emu); - else if (emu->card_capabilities->emu1212m) - snd_emu10k1_emu1212m_init(emu); + else if (emu->card_capabilities->emu1010) + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 2199b42a601..bb0fec7f7e1 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; - for(i=0; i < runtime->periods; i++) { + for(i = 0; i < runtime->periods; i++) { *table_base++=runtime->dma_addr+(i*period_size_bytes); *table_base++=period_size_bytes<<16; } @@ -1042,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) - && (channel_id >=0) && (channel_id <= 2) ) + if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) + && (channel_id >= 0) && (channel_id <= 2) ) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 13cd6ce8981..c02012cccd8 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -3,6 +3,9 @@ * Creative Labs, Inc. * Routines for effect processor FX8010 * + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> + * Added EMU 1010 support. + * * BUGS: * -- * @@ -293,7 +296,7 @@ static const u32 db_table[101] = { }; /* EMU10k1/EMU10k2 DSP control db gain */ -static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); +static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); static const u32 onoff_table[2] = { 0x00000000, 0x00000001 @@ -652,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) return NULL; } +#define MAX_TLV_SIZE 256 + +static unsigned int *copy_tlv(const unsigned int __user *_tlv) +{ + unsigned int data[2]; + unsigned int *tlv; + + if (!_tlv) + return NULL; + if (copy_from_user(data, _tlv, sizeof(data))) + return NULL; + if (data[1] >= MAX_TLV_SIZE) + return NULL; + tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); + if (!tlv) + return NULL; + memcpy(tlv, data, sizeof(data)); + if (copy_from_user(tlv + 2, _tlv + 2, data[1])) { + kfree(tlv); + return NULL; + } + return tlv; +} + +static int copy_gctl(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr *gctl, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)); + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + if (copy_from_user(gctl, &octl[idx], sizeof(*octl))) + return -EFAULT; + gctl->tlv = NULL; + return 0; +} + +static int copy_gctl_to_user(struct snd_emu10k1 *emu, + struct snd_emu10k1_fx8010_control_gpr __user *_gctl, + struct snd_emu10k1_fx8010_control_gpr *gctl, + int idx) +{ + struct snd_emu10k1_fx8010_control_old_gpr __user *octl; + + if (emu->support_tlv) + return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl)); + + octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl; + return copy_to_user(&octl[idx], gctl, sizeof(*octl)); +} + static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i; struct snd_ctl_elem_id __user *_id; struct snd_ctl_elem_id id; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; int err; @@ -673,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; err = 0; - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -694,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, goto __error; } } - for (i = 0, _gctl = icode->gpr_list_controls; - i < icode->gpr_list_control_count; i++, _gctl++) { + for (i = 0; i < icode->gpr_list_control_count; i++) { /* FIXME: we need to check the WRITE access */ - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) { err = -EFAULT; goto __error; } @@ -715,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) kctl->private_value = 0; list_del(&ctl->list); kfree(ctl); + if (kctl->tlv.p) + kfree(kctl->tlv.p); } static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_code *icode) { unsigned int i, j; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_control_gpr *gctl; struct snd_emu10k1_fx8010_ctl *ctl, *nctl; struct snd_kcontrol_new knew; @@ -737,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, goto __error; } - for (i = 0, _gctl = icode->gpr_add_controls; - i < icode->gpr_add_control_count; i++, _gctl++) { - if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { + for (i = 0; i < icode->gpr_add_control_count; i++) { + if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) { err = -EFAULT; goto __error; } @@ -760,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, knew.device = gctl->id.device; knew.subdevice = gctl->id.subdevice; knew.info = snd_emu10k1_gpr_ctl_info; - if (gctl->tlv.p) { - knew.tlv.p = gctl->tlv.p; + knew.tlv.p = copy_tlv(gctl->tlv); + if (knew.tlv.p) knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ; - } knew.get = snd_emu10k1_gpr_ctl_get; knew.put = snd_emu10k1_gpr_ctl_put; memset(nctl, 0, sizeof(*nctl)); @@ -782,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) { err = -ENOMEM; + kfree(knew.tlv.p); goto __error; } knew.private_value = (unsigned long)ctl; *ctl = *nctl; if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { kfree(ctl); + kfree(knew.tlv.p); goto __error; } kctl->private_free = snd_emu10k1_ctl_private_free; @@ -838,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, unsigned int i = 0, j; unsigned int total = 0; struct snd_emu10k1_fx8010_control_gpr *gctl; - struct snd_emu10k1_fx8010_control_gpr __user *_gctl; struct snd_emu10k1_fx8010_ctl *ctl; struct snd_ctl_elem_id *id; struct list_head *list; @@ -847,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, if (! gctl) return -ENOMEM; - _gctl = icode->gpr_list_controls; list_for_each(list, &emu->fx8010.gpr_ctl) { ctl = emu10k1_gpr_ctl(list); total++; - if (_gctl && i < icode->gpr_list_control_count) { + if (icode->gpr_list_controls && + i < icode->gpr_list_control_count) { memset(gctl, 0, sizeof(*gctl)); id = &ctl->kcontrol->id; gctl->id.iface = id->iface; @@ -868,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, gctl->min = ctl->min; gctl->max = ctl->max; gctl->translation = ctl->translation; - if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { + if (copy_gctl_to_user(emu, icode->gpr_list_controls, + gctl, i)) { kfree(gctl); return -EFAULT; } - _gctl++; i++; } } @@ -1023,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1038,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; ctl->min = 0; ctl->max = 100; - ctl->tlv.p = snd_emu10k1_db_scale1; + ctl->tlv = snd_emu10k1_db_scale1; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; } @@ -1069,6 +1123,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; } +static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( + struct snd_emu10k1_fx8010_code *icode, + u32 *ptr, int tmp, int bit_shifter16, + int reg_in, int reg_out) +{ + A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000); + A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2)); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000); + A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000); + A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000); + A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2)); + A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000); + return 1; +} /* * initial DSP configuration for Audigy @@ -1077,6 +1146,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, nctl; + int bit_shifter16; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ const int stereo_mix = capture + 2; @@ -1114,17 +1184,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) ptr = 0; nctl = 0; gpr = stereo_mix + 10; + gpr_map[gpr++] = 0x00007fff; + gpr_map[gpr++] = 0x00008000; + gpr_map[gpr++] = 0x0000ffff; + bit_shifter16 = gpr; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); -#if 0 - /* FIX: jcd test */ - for (z = 0; z < 80; z=z+2) { - A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */ - A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */ - } -#endif /* jcd test */ #if 1 /* PCM front Playback Volume (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); @@ -1182,13 +1249,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); gpr += 2; - + /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) + /* emu1212 DSP 0 and DSP 1 Capture */ + if (emu->card_capabilities->emu1010) { + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); + gpr += 2; + } /* AC'97 Playback Volume - used only for mic (renamed later) */ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); @@ -1429,6 +1503,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* digital outputs */ /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ + if (emu->card_capabilities->emu1010) { + /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ + snd_printk("EMU outputs on\n"); + for (z = 0; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } + } /* IEC958 Optical Raw Playback Switch */ gpr_map[gpr++] = 0; @@ -1466,9 +1547,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); #endif - /* EFX capture - capture the 16 EXTINs */ - for (z = 0; z < 16; z++) { - A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + if (emu->card_capabilities->emu1010) { + snd_printk("EMU inputs on\n"); + /* Capture 8 channels of S32_LE sound */ + + /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ + /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ + /* A_P16VIN(0) is delayed by one sample, + * so all other A_P16VIN channels will need to also be delayed + */ + /* Left ADC in. 1 of 2 */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); + /* Right ADC in 1 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); + /* For 96kHz mode */ + /* Left ADC in. 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); + /* Right ADC in 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); + +#if 0 + for (z = 4; z < 8; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } + for (z = 0xc; z < 0x10; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000); + } +#endif + } else { + /* EFX capture - capture the 16 EXTINs */ + /* Capture 16 channels of S16_LE sound */ + for (z = 0; z < 16; z++) { + A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); + } } #endif /* JCD test */ @@ -1488,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) seg = snd_enter_user(); icode->gpr_add_control_count = nctl; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); __err: @@ -2105,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) seg = snd_enter_user(); icode->gpr_add_control_count = i; icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; + emu->support_tlv = 1; /* support TLV */ err = snd_emu10k1_icode_poke(emu, icode); + emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); if (err >= 0) err = snd_emu10k1_ipcm_poke(emu, ipcm); @@ -2138,7 +2271,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu) snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); } -#if 0 // FIXME: who use them? +#if 0 /* FIXME: who use them? */ int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output) { if (output < 0 || output >= 6) @@ -2249,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un int res; switch (cmd) { + case SNDRV_EMU10K1_IOCTL_PVERSION: + emu->support_tlv = 1; + return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp); case SNDRV_EMU10K1_IOCTL_INFO: info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c31f3d0877f..4db6e1ca166 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -5,6 +5,9 @@ * Routines for control of EMU10K1 chips / mixer routines * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> * + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> + * Added EMU 1010 support. + * * BUGS: * -- * @@ -32,9 +35,15 @@ #include <linux/init.h> #include <sound/core.h> #include <sound/emu10k1.h> +#include <linux/delay.h> +#include <sound/tlv.h> + +#include "p17v.h" #define AC97_ID_STAC9758 0x83847658 +static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ + static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -68,6 +77,669 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } +static char *emu1010_src_texts[] = { + "Silence", + "Dock Mic A", + "Dock Mic B", + "Dock ADC1 Left", + "Dock ADC1 Right", + "Dock ADC2 Left", + "Dock ADC2 Right", + "Dock ADC3 Left", + "Dock ADC3 Right", + "0202 ADC Left", + "0202 ADC Right", + "0202 SPDIF Left", + "0202 SPDIF Right", + "ADAT 0", + "ADAT 1", + "ADAT 2", + "ADAT 3", + "ADAT 4", + "ADAT 5", + "ADAT 6", + "ADAT 7", + "DSP 0", + "DSP 1", + "DSP 2", + "DSP 3", + "DSP 4", + "DSP 5", + "DSP 6", + "DSP 7", + "DSP 8", + "DSP 9", + "DSP 10", + "DSP 11", + "DSP 12", + "DSP 13", + "DSP 14", + "DSP 15", + "DSP 16", + "DSP 17", + "DSP 18", + "DSP 19", + "DSP 20", + "DSP 21", + "DSP 22", + "DSP 23", + "DSP 24", + "DSP 25", + "DSP 26", + "DSP 27", + "DSP 28", + "DSP 29", + "DSP 30", + "DSP 31", +}; + +static unsigned int emu1010_src_regs[] = { + EMU_SRC_SILENCE,/* 0 */ + EMU_SRC_DOCK_MIC_A1, /* 1 */ + EMU_SRC_DOCK_MIC_B1, /* 2 */ + EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ + EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ + EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ + EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ + EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ + EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ + EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ + EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ + EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ + EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ + EMU_SRC_HANA_ADAT, /* 13 */ + EMU_SRC_HANA_ADAT+1, /* 14 */ + EMU_SRC_HANA_ADAT+2, /* 15 */ + EMU_SRC_HANA_ADAT+3, /* 16 */ + EMU_SRC_HANA_ADAT+4, /* 17 */ + EMU_SRC_HANA_ADAT+5, /* 18 */ + EMU_SRC_HANA_ADAT+6, /* 19 */ + EMU_SRC_HANA_ADAT+7, /* 20 */ + EMU_SRC_ALICE_EMU32A, /* 21 */ + EMU_SRC_ALICE_EMU32A+1, /* 22 */ + EMU_SRC_ALICE_EMU32A+2, /* 23 */ + EMU_SRC_ALICE_EMU32A+3, /* 24 */ + EMU_SRC_ALICE_EMU32A+4, /* 25 */ + EMU_SRC_ALICE_EMU32A+5, /* 26 */ + EMU_SRC_ALICE_EMU32A+6, /* 27 */ + EMU_SRC_ALICE_EMU32A+7, /* 28 */ + EMU_SRC_ALICE_EMU32A+8, /* 29 */ + EMU_SRC_ALICE_EMU32A+9, /* 30 */ + EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ + EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ + EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ + EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ + EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ + EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ + EMU_SRC_ALICE_EMU32B, /* 37 */ + EMU_SRC_ALICE_EMU32B+1, /* 38 */ + EMU_SRC_ALICE_EMU32B+2, /* 39 */ + EMU_SRC_ALICE_EMU32B+3, /* 40 */ + EMU_SRC_ALICE_EMU32B+4, /* 41 */ + EMU_SRC_ALICE_EMU32B+5, /* 42 */ + EMU_SRC_ALICE_EMU32B+6, /* 43 */ + EMU_SRC_ALICE_EMU32B+7, /* 44 */ + EMU_SRC_ALICE_EMU32B+8, /* 45 */ + EMU_SRC_ALICE_EMU32B+9, /* 46 */ + EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ + EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ + EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ + EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ + EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ + EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ +}; + +static unsigned int emu1010_output_dst[] = { + EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ + EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ + EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ + EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ + EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ + EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ + EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ + EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ + EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ + EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ + EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ + EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ + EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ + EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ + EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ + EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ + EMU_DST_HANA_ADAT, /* 16 */ + EMU_DST_HANA_ADAT+1, /* 17 */ + EMU_DST_HANA_ADAT+2, /* 18 */ + EMU_DST_HANA_ADAT+3, /* 19 */ + EMU_DST_HANA_ADAT+4, /* 20 */ + EMU_DST_HANA_ADAT+5, /* 21 */ + EMU_DST_HANA_ADAT+6, /* 22 */ + EMU_DST_HANA_ADAT+7, /* 23 */ +}; + +static unsigned int emu1010_input_dst[] = { + EMU_DST_ALICE2_EMU32_0, + EMU_DST_ALICE2_EMU32_1, + EMU_DST_ALICE2_EMU32_2, + EMU_DST_ALICE2_EMU32_3, + EMU_DST_ALICE2_EMU32_4, + EMU_DST_ALICE2_EMU32_5, + EMU_DST_ALICE2_EMU32_6, + EMU_DST_ALICE2_EMU32_7, + EMU_DST_ALICE2_EMU32_8, + EMU_DST_ALICE2_EMU32_9, + EMU_DST_ALICE2_EMU32_A, + EMU_DST_ALICE2_EMU32_B, + EMU_DST_ALICE2_EMU32_C, + EMU_DST_ALICE2_EMU32_D, + EMU_DST_ALICE2_EMU32_E, + EMU_DST_ALICE2_EMU32_F, + EMU_DST_ALICE_I2S0_LEFT, + EMU_DST_ALICE_I2S0_RIGHT, + EMU_DST_ALICE_I2S1_LEFT, + EMU_DST_ALICE_I2S1_RIGHT, + EMU_DST_ALICE_I2S2_LEFT, + EMU_DST_ALICE_I2S2_RIGHT, +}; + +static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 53; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; + return 0; +} + +static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_output_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int channel; + + channel = (kcontrol->private_value) & 0xff; + ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; + return 0; +} + +static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int change = 0; + unsigned int val; + int channel; + + channel = (kcontrol->private_value) & 0xff; + if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { + val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; + change = 1; + snd_emu1010_fpga_link_dst_src_write(emu, + emu1010_input_dst[channel], emu1010_src_regs[val]); + } + return change; +} + +#define EMU1010_SOURCE_OUTPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_output_source_get, \ + .put = snd_emu1010_output_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), + EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), + EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), + EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), + EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), + EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), + EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), + EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), + EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), + EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), + EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), + EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), + EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), + EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), + EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), + EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), + EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), + EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), + EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), +}; + +#define EMU1010_SOURCE_INPUT(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_input_output_source_info, \ + .get = snd_emu1010_input_source_get, \ + .put = snd_emu1010_input_source_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { + EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), + EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), + EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), + EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), + EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), + EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), + EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), + EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), + EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), + EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), + EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), + EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), + EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), + EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), + EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), + EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), + EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), + EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), + EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), + EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), + EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), + EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), +}; + + + + +static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.adc_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.adc_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); + emu->emu1010.adc_pads = cache; + } + + return 0; +} + + + +#define EMU1010_ADC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_adc_pads_info, \ + .get = snd_emu1010_adc_pads_get, \ + .put = snd_emu1010_adc_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { + EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), + EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), + EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), + EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), +}; + +static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; + return 0; +} + +static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int mask = kcontrol->private_value & 0xff; + unsigned int val, cache; + val = ucontrol->value.integer.value[0]; + cache = emu->emu1010.dac_pads; + if (val == 1) + cache = cache | mask; + else + cache = cache & ~mask; + if (cache != emu->emu1010.dac_pads) { + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); + emu->emu1010.dac_pads = cache; + } + + return 0; +} + + + +#define EMU1010_DAC_PADS(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = snd_emu1010_dac_pads_info, \ + .get = snd_emu1010_dac_pads_get, \ + .put = snd_emu1010_dac_pads_put, \ + .private_value = chid \ +} + +static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { + EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), + EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), + EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), + EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), + EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), +}; + + +static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2] = { + "44100", "48000" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; + return 0; +} + +static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->emu1010.internal_clock != val); + if (change) { + emu->emu1010.internal_clock = val; + switch (val) { + case 0: + /* 44100 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); + /* Word Clock source, Internal 44.1kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + case 1: + /* 48000 */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, Internal 48kHz x1 */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + } + } + return change; +} + +static struct snd_kcontrol_new snd_emu1010_internal_clock = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Internal Rate", + .count = 1, + .info = snd_emu1010_internal_clock_info, + .get = snd_emu1010_internal_clock_get, + .put = snd_emu1010_internal_clock_put +}; + +static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ +#if 0 + static char *texts[4] = { + "Unknown1", "Unknown2", "Mic", "Line" + }; +#endif + static char *texts[2] = { + "Mic", "Line" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; + return 0; +} + +static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int source_id; + unsigned int ngain, ogain; + u32 gpio; + int change = 0; + unsigned long flags; + u32 source; + /* If the capture source has changed, + * update the capture volume from the cached value + * for the particular source. + */ + source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ + change = (emu->i2c_capture_source != source_id); + if (change) { + snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + spin_lock_irqsave(&emu->emu_lock, flags); + gpio = inl(emu->port + A_IOCFG); + if (source_id==0) + outl(gpio | 0x4, emu->port + A_IOCFG); + else + outl(gpio & ~0x4, emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->emu_lock, flags); + + ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); + ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ + if (ngain != ogain) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + + source = 1 << (source_id + 2); + snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = source_id; + } + return change; +} + +static struct snd_kcontrol_new snd_audigy_i2c_capture_source = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_audigy_i2c_capture_source_info, + .get = snd_audigy_i2c_capture_source_get, + .put = snd_audigy_i2c_capture_source_put +}; + +static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; +} + +static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + int source_id; + + source_id = kcontrol->private_value; + + ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; + ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; + return 0; +} + +static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int ogain; + unsigned int ngain; + int source_id; + int change = 0; + + source_id = kcontrol->private_value; + ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ngain = ucontrol->value.integer.value[0]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); + emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; + change = 1; + } + ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ + ngain = ucontrol->value.integer.value[1]; + if (ngain > 0xff) + return 0; + if (ogain != ngain) { + if (emu->i2c_capture_source == source_id) + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; + change = 1; + } + + return change; +} + +#define I2C_VOLUME(xname,chid) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_audigy_i2c_volume_info, \ + .get = snd_audigy_i2c_volume_get, \ + .put = snd_audigy_i2c_volume_put, \ + .tlv = { .p = snd_audigy_db_scale2 }, \ + .private_value = chid \ +} + + +static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { + I2C_VOLUME("Mic Capture Volume", 0), + I2C_VOLUME("Line Capture Volume", 0) +}; + #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -668,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, int change = 0; spin_lock_irqsave(&emu->reg_lock, flags); - if (emu->audigy) { + if ( emu->card_capabilities->i2c_adc) { + /* Do nothing for Audigy 2 ZS Notebook */ + } else if (emu->audigy) { reg = inl(emu->port + A_IOCFG); val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; @@ -806,6 +1480,24 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "AMic Playback Volume", "Mic Playback Volume", NULL }; + static char *audigy_rename_ctls_i2c_adc[] = { + //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", + "Line Capture Volume", "Analog Mix Capture Volume", + "Wave Playback Volume", "OLD PCM Playback Volume", + "Wave Master Playback Volume", "Master Playback Volume", + "AMic Playback Volume", "Old Mic Playback Volume", + "CD Capture Volume", "IEC958 Optical Capture Volume", + NULL + }; + static char *audigy_remove_ctls_i2c_adc[] = { + /* On the Audigy2 ZS Notebook + * Capture via WM8775 */ + "Mic Capture Volume", + "Analog Mix Capture Volume", + "Aux Capture Volume", + "IEC958 Optical Capture Volume", + NULL + }; static char *audigy_remove_ctls_1361t_adc[] = { /* On the Audigy2 the AC97 playback is piped into * the Philips ADC for 24bit capture */ @@ -890,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->ac97->id == AC97_ID_STAC9758) { emu->rear_ac97 = 1; snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); + snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); } /* remove unused AC97 controls */ snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); @@ -898,6 +1591,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } for (; *c; c++) remove_ctl(card, *c); + } else if (emu->card_capabilities->i2c_adc) { + c = audigy_remove_ctls_i2c_adc; + for (; *c; c++) + remove_ctl(card, *c); } else { no_ac97: if (emu->card_capabilities->ecard) @@ -911,6 +1608,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (emu->audigy) if (emu->card_capabilities->adc_1361t) c = audigy_rename_ctls_1361t_adc; + else if (emu->card_capabilities->i2c_adc) + c = audigy_rename_ctls_i2c_adc; else c = audigy_rename_ctls; else @@ -1021,7 +1720,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, return err; } - if ( emu->card_capabilities->emu1212m) { + if ( emu->card_capabilities->emu1010) { ; /* Disable the snd_audigy_spdif_shared_spdif */ } else if (emu->audigy) { if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) @@ -1045,6 +1744,48 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if ((err = snd_p16v_mixer(emu))) return err; } + + if ( emu->card_capabilities->emu1010) { + int i; + + for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); + if (err < 0) + return err; + } + for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); + if (err < 0) + return err; + } + err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); + if (err < 0) + return err; + } + + if ( emu->card_capabilities->i2c_adc) { + int i; + + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); + if (err < 0) + return err; + } + } return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 717e92ec9e0..ab4f5df5241 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic 1, &epcm->extra); if (err < 0) { - // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); + /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */ for (i = 0; i < voices; i++) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } } - // setup routing + /* setup routing */ if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXRT1, voice, snd_emu10k1_compose_audigy_fxrt1(send_routing)); @@ -353,12 +353,15 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } else snd_emu10k1_ptr_write(emu, FXRT, voice, snd_emu10k1_compose_send_routing(send_routing)); - // Stop CA - // Assumption that PT is already 0 so no harm overwriting + /* Stop CA */ + /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); if (extra) snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | emu10k1_select_interprom(pitch_target) | @@ -367,14 +370,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | emu10k1_select_interprom(pitch_target) | (w_16 ? 0 : CCCA_8BITSELECT)); - // Clear filter delay memory + /* Clear filter delay memory */ snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); - // invalidate maps + /* invalidate maps */ silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); - // modulation envelope + /* modulation envelope */ snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); @@ -385,12 +388,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); - // volume envelope + /* volume envelope */ snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); - // filter envelope + /* filter envelope */ snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); - // pitch envelope + /* pitch envelope */ snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); spin_unlock_irqrestore(&emu->reg_lock, flags); @@ -468,7 +471,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream) snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; } - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { if (epcm->voices[i]) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; @@ -637,7 +640,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e stereo = (!extra && runtime->channels == 2); sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; ccis = emu10k1_ccis(stereo, sample == 0); - // set cs to 2 * number of cache registers beside the invalidated + /* set cs to 2 * number of cache registers beside the invalidated */ cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; if (cs > 16) cs = 16; for (i = 0; i < cs; i++) { @@ -646,14 +649,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); } } - // reset cache + /* reset cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); } - // fill cache + /* fill cache */ snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); if (stereo) { snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); @@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s voice = evoice->number; pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; - pitch_target = emu10k1_calc_pitch_target(runtime->rate); + if (emu->card_capabilities->emu1010) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); if (master || evoice->epcm->type == PLAYBACK_EFX) snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); @@ -732,7 +738,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1_pcm_mixer *mix; int result = 0; - // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); + /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */ spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -778,10 +784,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - // hmm this should cause full and half full interrupt to be raised? + /* hmm this should cause full and half full interrupt to be raised? */ outl(epcm->capture_ipr, emu->port + IPR); snd_emu10k1_intr_enable(emu, epcm->capture_inte); - // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); + /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ switch (epcm->type) { case CAPTURE_AC97ADC: snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); @@ -790,6 +796,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); + snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); } else snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); break; @@ -851,7 +858,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * ptr -= runtime->buffer_size; } #endif - // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); + /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */ return ptr; } @@ -868,7 +875,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - // prepare voices + /* prepare voices */ for (i = 0; i < NUM_EFX_PLAYBACK; i++) { snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); } @@ -917,7 +924,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s if (!epcm->running) return 0; if (epcm->first_ptr) { - udelay(50); // hack, it takes awhile until capture is started + udelay(50); /* hack, it takes awhile until capture is started */ epcm->first_ptr = 0; } ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; @@ -972,6 +979,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture = .fifo_size = 0, }; +static struct snd_pcm_hardware snd_emu10k1_capture_efx = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, + .rate_max = 192000, + .channels_min = 8, + .channels_max = 8, + .buffer_bytes_max = (64*1024), + .period_bytes_min = 384, + .period_bytes_max = (64*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, +}; + /* * */ @@ -1016,7 +1045,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm_mixer *mix; int i; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->epcm = NULL; snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); @@ -1045,7 +1074,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; - for (i=0; i < NUM_EFX_PLAYBACK; i++) { + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; mix->send_routing[0][0] = i; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); @@ -1199,15 +1228,69 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) epcm->capture_idx_reg = FXIDX; substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; - runtime->hw = snd_emu10k1_capture; + runtime->hw = snd_emu10k1_capture_efx; runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; spin_lock_irq(&emu->reg_lock); - runtime->hw.channels_min = runtime->hw.channels_max = 0; - for (idx = 0; idx < nefx; idx++) { - if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { - runtime->hw.channels_min++; - runtime->hw.channels_max++; + if (emu->card_capabilities->emu1010) { + /* TODO + * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE + * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 + * rate_min = 44100, + * rate_max = 192000, + * channels_min = 8, + * channels_max = 8, + * Need to add mixer control to fix sample rate + * + * There are 16 mono channels of 16bits each. + * 24bit Audio uses 2x channels over 16bit + * 96kHz uses 2x channels over 48kHz + * 192kHz uses 4x channels over 48kHz + * So, for 48kHz 24bit, one has 8 channels + * for 96kHz 24bit, one has 4 channels + * for 192kHz 24bit, one has 2 channels + */ +#if 1 + switch (emu->emu1010.internal_clock) { + case 0: + /* For 44.1kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_44100; + runtime->hw.rate_min = runtime->hw.rate_max = 44100; + runtime->hw.channels_min = runtime->hw.channels_max = 8; + break; + case 1: + /* For 48kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = runtime->hw.rate_max = 48000; + runtime->hw.channels_min = runtime->hw.channels_max = 8; + break; + }; +#endif +#if 0 + /* For 96kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_96000; + runtime->hw.rate_min = runtime->hw.rate_max = 96000; + runtime->hw.channels_min = runtime->hw.channels_max = 4; +#endif +#if 0 + /* For 192kHz */ + runtime->hw.rates = SNDRV_PCM_RATE_192000; + runtime->hw.rate_min = runtime->hw.rate_max = 192000; + runtime->hw.channels_min = runtime->hw.channels_max = 2; +#endif + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; + /* efx_voices_mask[0] is expected to be zero + * efx_voices_mask[1] is expected to have 16bits set + */ + } else { + runtime->hw.channels_min = runtime->hw.channels_max = 0; + for (idx = 0; idx < nefx; idx++) { + if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { + runtime->hw.channels_min++; + runtime->hw.channels_max++; + } } } epcm->capture_cr_val = emu->efx_voices_mask[0]; @@ -1460,7 +1543,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, unsigned int count, unsigned int tram_shift) { - // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); + /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */ if ((tram_shift & 1) == 0) { while (count--) { *dst_left-- = *src++; @@ -1537,7 +1620,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number]; unsigned int i; - // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); + /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */ memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index b939e03aaed..2c1585991bc 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -3,6 +3,9 @@ * Creative Labs, Inc. * Routines for control of EMU10K1 chips / proc interface routines * + * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> + * Added EMU 1010 support. + * * BUGS: * -- * @@ -255,7 +258,7 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, unsigned int val, tmp, n; val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); tmp = (val >> 16) & 0x8; - for (n=0;n<4;n++) { + for (n = 0; n < 4; n++) { tmp = val >> (16 + (n*4)); if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); else snd_iprintf(buffer, "Channel %d: No input\n", n); @@ -372,6 +375,27 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, } #ifdef CONFIG_SND_DEBUG +static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_emu10k1 *emu = entry->private_data; + unsigned long value; + unsigned long flags; + unsigned long regs; + int i; + snd_iprintf(buffer, "EMU1010 Registers:\n\n"); + + for(i = 0; i < 0x30; i+=1) { + spin_lock_irqsave(&emu->emu_lock, flags); + regs=i+0x40; /* 0x40 upwards are registers. */ + outl(regs, emu->port + A_IOCFG); + outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + value = inl(emu->port + A_IOCFG); + spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f); + } +} + static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -398,7 +422,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { + if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -474,7 +498,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) + if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) snd_ptr_write(emu, iobase, reg, channel_id, val); } } @@ -531,6 +555,10 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG + if ((emu->card_capabilities->emu1010) && + snd_card_proc_new(emu->card, "emu1010_regs", &entry)) { + snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); + } if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); entry->c.text.write = snd_emu_proc_io_reg_write; diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 029e7856c43..116e1c8d936 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -30,6 +30,7 @@ #include <sound/core.h> #include <sound/emu10k1.h> #include <linux/delay.h> +#include "p17v.h" unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { @@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, return 0; } +/* The ADC does not support i2c read, so only write is implemented */ +int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, + u32 reg, + u32 value) +{ + u32 tmp; + int timeout = 0; + int status; + int retry; + if ((reg > 0x7f) || (value > 0x1ff)) { + snd_printk(KERN_ERR "i2c_write: invalid values.\n"); + return -EINVAL; + } + + tmp = reg << 25 | value << 16; + // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); + /* Not sure what this I2C channel controls. */ + /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ + + /* This controls the I2C connected to the WM8775 ADC Codec */ + snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); + tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ + + for (retry = 0; retry < 10; retry++) { + /* Send the data to i2c */ + //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); + //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); + tmp = 0; + tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); + snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); + + /* Wait till the transaction ends */ + while (1) { + udelay(10); + status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); + // snd_printk("I2C:status=0x%x\n", status); + timeout++; + if ((status & I2C_A_ADC_START) == 0) + break; + + if (timeout > 1000) { + snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); + break; + } + } + //Read back and see if the transaction is successful + if ((status & I2C_A_ADC_ABORT) == 0) + break; + } + + if (retry == 10) { + snd_printk(KERN_ERR "Writing to ADC failed!\n"); + return -EINVAL; + } + + return 0; +} + +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +{ + if (reg < 0 || reg > 0x3f) + return 1; + reg += 0x40; /* 0x40 upwards are registers. */ + if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + return 1; + outl(reg, emu->port + A_IOCFG); + udelay(10); + outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + udelay(10); + outl(value, emu->port + A_IOCFG); + udelay(10); + outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + + return 0; +} + +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) +{ + if (reg < 0 || reg > 0x3f) + return 1; + reg += 0x40; /* 0x40 upwards are registers. */ + outl(reg, emu->port + A_IOCFG); + udelay(10); + outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + udelay(10); + *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); + + return 0; +} + +/* Each Destination has one and only one Source, + * but one Source can feed any number of Destinations simultaneously. + */ +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) +{ + snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); + snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); + + return 0; +} + void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { unsigned long flags; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 4e0f95438f4..465f8d50532 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -253,7 +253,7 @@ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); //struct snd_pcm_runtime *runtime = substream->runtime; //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; + emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0; /* FIXME: maybe zero others */ return 0; } @@ -264,7 +264,7 @@ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); //struct snd_pcm_runtime *runtime = substream->runtime; //struct snd_emu10k1_pcm *epcm = runtime->private_data; - emu->p16v_capture_voice.use=0; + emu->p16v_capture_voice.use = 0; /* FIXME: maybe zero others */ return 0; } @@ -349,7 +349,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - for(i=0; i < runtime->periods; i++) { + for(i = 0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } @@ -394,7 +394,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) /* FIXME: Check emu->buffer.size before actually writing to it. */ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); - snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); @@ -437,7 +437,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 inte = 0; - int running=0; + int running = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -445,7 +445,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: default: - running=0; + running = 0; break; } snd_pcm_group_for_each(pos, substream) { @@ -785,7 +785,7 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, } return change; } -static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); +static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); #define P16V_VOL(xname,xreg,xhl) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 7ddb5be632c..4ef5f68a9cd 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h @@ -43,6 +43,53 @@ #define P17V_I2C_ADDR 0x3d /* I2C Address */ #define P17V_I2C_0 0x3e /* I2C Data */ #define P17V_I2C_1 0x3f /* I2C Data */ +/* I2C values */ +#define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */ +#define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */ +#define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */ +#define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */ +#define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */ +#define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */ + +#define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */ +#define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */ +#define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */ +#define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */ +#define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */ +#define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */ + +#define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */ +#define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */ + +#define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */ +#define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */ +#define ADC_MASTER 0x0000000c /*ADC Master Mode Control */ +#define ADC_POWER 0x0000000d /*ADC PowerDown Control */ +#define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */ +#define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */ +#define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */ +#define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */ +#define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */ +#define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */ +#define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */ +#define ADC_MUX 0x00000015 /*ADC Mux offset */ +#if 0 +/* FIXME: Not tested yet. */ +#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain +#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB +#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute +#define ADC_MUTE 0x000000c0 //Value to mute ADC +#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select +#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock +#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter +#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window +#endif + +#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux +#define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used) +#define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used) +#define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux +#define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux #define P17V_START_AUDIO 0x40 /* Start Audio bit */ /* 41 - 47: Reserved */ diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 94eca82dd4f..1db50fe6147 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -83,7 +83,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, if (first_voice == last_voice) return -ENOMEM; - for (i=0; i < number; i++) { + for (i = 0; i < number; i++) { voice = &emu->voices[(first_voice + i) % NUM_G]; // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); voice->use = 1; |