Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (365 commits) ALSA: hda - Disable sticky PCM stream assignment for AD codecs ALSA: usb - Creative USB X-Fi volume knob support ALSA: ca0106: Use card specific dac id for mute controls. ALSA: ca0106: Allow different sound cards to use different SPI channel mappings. ALSA: ca0106: Create a nice spot for mapping channels to dacs. ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence. ALSA: ca0106: Pull out dac powering routine into separate function. ALSA: ca0106 - add Sound Blaster 5.1vx info. ASoC: tlv320dac33: Use usleep_range for delays ALSA: usb-audio: add Novation Launchpad support ALSA: hda - Add workarounds for CT-IBG controllers ALSA: hda - Fix wrong TLV mute bit for STAC/IDT codecs ASoC: tpa6130a2: Error handling for broken chip ASoC: max98088: Staticise m98088_eq_band ASoC: soc-core: Fix codec->name memory leak ALSA: hda - Apply ideapad quirk to Acer laptops with Cxt5066 ALSA: hda - Add some workarounds for Creative IBG ALSA: hda - Fix wrong SPDIF NID assignment for CA0110 ALSA: hda - Fix codec rename rules for ALC662-compatible codecs ALSA: hda - Add alc_init_jacks() call to other codecs ...
This commit is contained in:
commit
33081adf8b
|
@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
control correctly. If you have problems regarding this, try
|
||||
another ALSA compliant mixer (alsamixer works).
|
||||
|
||||
Module snd-azt1605
|
||||
------------------
|
||||
|
||||
Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
|
||||
chipset.
|
||||
|
||||
port - port # for BASE (0x220,0x240,0x260,0x280)
|
||||
wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
|
||||
irq - IRQ # for WSS (7,9,10,11)
|
||||
dma1 - DMA # for WSS playback (0,1,3)
|
||||
dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
|
||||
mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
|
||||
mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
|
||||
fm_port - port # for OPL3 (0x388), -1 = disabled (default)
|
||||
|
||||
This module supports multiple cards. It does not support autoprobe: port,
|
||||
wss_port, irq and dma1 have to be specified. The other values are
|
||||
optional.
|
||||
|
||||
"port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
|
||||
or the value stored in the card's EEPROM for cards that have an EEPROM and
|
||||
their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
|
||||
be choosen freely from the options enumerated above.
|
||||
|
||||
If dma2 is specified and different from dma1, the card will operate in
|
||||
full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
|
||||
enable capture since only channels 0 and 1 are available for capture.
|
||||
|
||||
Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
|
||||
mpu_port=0x330 mpu_irq=9 fm_port=0x388".
|
||||
|
||||
Whatever IRQ and DMA channels you pick, be sure to reserve them for
|
||||
legacy ISA in your BIOS.
|
||||
|
||||
Module snd-azt2316
|
||||
------------------
|
||||
|
||||
Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
|
||||
chipset.
|
||||
|
||||
port - port # for BASE (0x220,0x240,0x260,0x280)
|
||||
wss_port - port # for WSS (0x530,0x604,0xe80,0xf40)
|
||||
irq - IRQ # for WSS (7,9,10,11)
|
||||
dma1 - DMA # for WSS playback (0,1,3)
|
||||
dma2 - DMA # for WSS capture (0,1), -1 = disabled (default)
|
||||
mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
|
||||
mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
|
||||
fm_port - port # for OPL3 (0x388), -1 = disabled (default)
|
||||
|
||||
This module supports multiple cards. It does not support autoprobe: port,
|
||||
wss_port, irq and dma1 have to be specified. The other values are
|
||||
optional.
|
||||
|
||||
"port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
|
||||
or the value stored in the card's EEPROM for cards that have an EEPROM and
|
||||
their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
|
||||
be choosen freely from the options enumerated above.
|
||||
|
||||
If dma2 is specified and different from dma1, the card will operate in
|
||||
full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
|
||||
enable capture since only channels 0 and 1 are available for capture.
|
||||
|
||||
Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
|
||||
mpu_port=0x330 mpu_irq=9 fm_port=0x388".
|
||||
|
||||
Whatever IRQ and DMA channels you pick, be sure to reserve them for
|
||||
legacy ISA in your BIOS.
|
||||
|
||||
Module snd-aw2
|
||||
--------------
|
||||
|
||||
|
@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
|
||||
This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
|
||||
|
||||
Module snd-sgalaxy
|
||||
------------------
|
||||
|
||||
Module for Aztech Sound Galaxy sound card.
|
||||
|
||||
sbport - Port # for SB16 interface (0x220,0x240)
|
||||
wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604)
|
||||
irq - IRQ # (7,9,10,11)
|
||||
dma1 - DMA #
|
||||
|
||||
This module supports multiple cards.
|
||||
|
||||
The power-management is supported.
|
||||
|
||||
Module snd-sscape
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -57,9 +57,11 @@ dead. However, this detection isn't perfect on some devices. In such
|
|||
a case, you can change the default method via `position_fix` option.
|
||||
|
||||
`position_fix=1` means to use LPIB method explicitly.
|
||||
`position_fix=2` means to use the position-buffer. 0 is the default
|
||||
value, the automatic check and fallback to LPIB as described in the
|
||||
above. If you get a problem of repeated sounds, this option might
|
||||
`position_fix=2` means to use the position-buffer.
|
||||
`position_fix=3` means to use a combination of both methods, needed
|
||||
for some VIA and ATI controllers. 0 is the default value for all other
|
||||
controllers, the automatic check and fallback to LPIB as described in
|
||||
the above. If you get a problem of repeated sounds, this option might
|
||||
help.
|
||||
|
||||
In addition to that, every controller is known to be broken regarding
|
||||
|
|
|
@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct platform_device davinci_pcm_device = {
|
||||
.name = "davinci-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void davinci_init_pcm(void)
|
||||
{
|
||||
platform_device_register(&davinci_pcm_device);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct davinci_timer_instance davinci_timer_instance[2] = {
|
||||
{
|
||||
.base = DAVINCI_TIMER0_BASE,
|
||||
|
@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
|
|||
/* please keep these calls, and their implementations above,
|
||||
* in alphabetical order so they're easier to sort through.
|
||||
*/
|
||||
davinci_init_pcm();
|
||||
davinci_init_wdt();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
|
|||
.resource = ep93xx_i2s_resource,
|
||||
};
|
||||
|
||||
static struct platform_device ep93xx_pcm_device = {
|
||||
.name = "ep93xx-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
void __init ep93xx_register_i2s(void)
|
||||
{
|
||||
platform_device_register(&ep93xx_i2s_device);
|
||||
platform_device_register(&ep93xx_pcm_device);
|
||||
}
|
||||
|
||||
#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
|
||||
|
@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
|
|||
}
|
||||
EXPORT_SYMBOL(ep93xx_i2s_release);
|
||||
|
||||
/*************************************************************************
|
||||
* EP93xx AC97 audio peripheral handling
|
||||
*************************************************************************/
|
||||
static struct resource ep93xx_ac97_resources[] = {
|
||||
{
|
||||
.start = EP93XX_AAC_PHYS_BASE,
|
||||
.end = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = IRQ_EP93XX_AACINTR,
|
||||
.end = IRQ_EP93XX_AACINTR,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ep93xx_ac97_device = {
|
||||
.name = "ep93xx-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(ep93xx_ac97_resources),
|
||||
.resource = ep93xx_ac97_resources,
|
||||
};
|
||||
|
||||
void __init ep93xx_register_ac97(void)
|
||||
{
|
||||
/*
|
||||
* Make sure that the AC97 pins are not used by I2S.
|
||||
*/
|
||||
ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
|
||||
|
||||
platform_device_register(&ep93xx_ac97_device);
|
||||
platform_device_register(&ep93xx_pcm_device);
|
||||
}
|
||||
|
||||
extern void ep93xx_gpio_init(void);
|
||||
|
||||
void __init ep93xx_init_devices(void)
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
|
||||
#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)
|
||||
|
||||
#define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000)
|
||||
#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
|
||||
|
||||
#define EP93XX_SPI_PHYS_BASE EP93XX_APB_PHYS(0x000a0000)
|
||||
|
|
|
@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
|
|||
void ep93xx_register_i2s(void);
|
||||
int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
|
||||
void ep93xx_i2s_release(void);
|
||||
void ep93xx_register_ac97(void);
|
||||
|
||||
void ep93xx_init_devices(void);
|
||||
extern struct sys_timer ep93xx_timer;
|
||||
|
|
|
@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
|
|||
ep93xx_register_fb(&simone_fb_info);
|
||||
ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
|
||||
ARRAY_SIZE(simone_i2c_board_info));
|
||||
ep93xx_register_ac97();
|
||||
}
|
||||
|
||||
MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
|
||||
|
|
|
@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct platform_device kirkwood_pcm_device = {
|
||||
.name = "kirkwood-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
void __init kirkwood_audio_init(void)
|
||||
{
|
||||
kirkwood_clk_ctrl |= CGC_AUDIO;
|
||||
platform_device_register(&kirkwood_i2s_device);
|
||||
platform_device_register(&kirkwood_pcm_device);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <mach/gpio.h>
|
||||
#include <plat/mmc.h>
|
||||
#include <plat/omap7xx.h>
|
||||
#include <plat/mcbsp.h>
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -195,6 +196,30 @@ static inline void omap_init_spi100k(void)
|
|||
|
||||
static inline void omap_init_sti(void) {}
|
||||
|
||||
#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
|
||||
|
||||
static struct platform_device omap_pcm = {
|
||||
.name = "omap-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(1);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(2);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(3);
|
||||
|
||||
static void omap_init_audio(void)
|
||||
{
|
||||
platform_device_register(&omap_mcbsp1);
|
||||
platform_device_register(&omap_mcbsp2);
|
||||
if (!cpu_is_omap7xx())
|
||||
platform_device_register(&omap_mcbsp3);
|
||||
platform_device_register(&omap_pcm);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void omap_init_audio(void) {}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
@ -227,6 +252,7 @@ static int __init omap1_init_devices(void)
|
|||
omap_init_rtc();
|
||||
omap_init_spi100k();
|
||||
omap_init_sti();
|
||||
omap_init_audio();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <sound/tlv320aic3x.h>
|
||||
|
||||
#include <plat/mcspi.h>
|
||||
#include <plat/board.h>
|
||||
|
@ -689,7 +690,6 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
|
|||
};
|
||||
|
||||
|
||||
|
||||
static struct twl4030_platform_data rx51_twldata __initdata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
|
@ -710,10 +710,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
|
|||
.vio = &rx51_vio,
|
||||
};
|
||||
|
||||
static struct aic3x_pdata rx51_aic3x_data __initdata = {
|
||||
.gpio_reset = 60,
|
||||
};
|
||||
|
||||
static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
|
||||
.id = TPA6130A2,
|
||||
.power_gpio = 98,
|
||||
|
@ -728,6 +724,17 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* Audio setup data */
|
||||
static struct aic3x_setup_data rx51_aic34_setup = {
|
||||
.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
|
||||
.gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
|
||||
};
|
||||
|
||||
static struct aic3x_pdata rx51_aic3x_data = {
|
||||
.setup = &rx51_aic34_setup,
|
||||
.gpio_reset = 60,
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("tlv320aic3x", 0x18),
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <plat/common.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include <mach/board-zoom.h>
|
||||
|
||||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
|
||||
|
@ -238,6 +240,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* EXTMUTE callback function */
|
||||
void zoom2_set_hs_extmute(int mute)
|
||||
{
|
||||
gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
|
||||
}
|
||||
|
||||
static int zoom_batt_table[] = {
|
||||
/* 0 C*/
|
||||
|
@ -307,6 +314,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
|
|||
|
||||
static int __init omap_i2c_init(void)
|
||||
{
|
||||
if (machine_is_omap_zoom2()) {
|
||||
zoom_audio_data.ramp_delay_value = 3; /* 161 ms */
|
||||
zoom_audio_data.hs_extmute = 1;
|
||||
zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
|
||||
}
|
||||
omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
|
||||
ARRAY_SIZE(zoom_i2c_boardinfo));
|
||||
omap_register_i2c_bus(2, 400, NULL, 0);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -34,41 +35,6 @@ static void __init omap_zoom2_init_irq(void)
|
|||
omap_gpio_init();
|
||||
}
|
||||
|
||||
/* REVISIT: These audio entries can be removed once MFD code is merged */
|
||||
#if 0
|
||||
|
||||
static struct twl4030_madc_platform_data zoom2_madc_data = {
|
||||
.irq_line = 1,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data zoom2_audio_data = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data zoom2_codec_data = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &zoom2_audio_data,
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data zoom2_twldata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
|
||||
/* platform_data for children goes here */
|
||||
.bci = &zoom2_bci_data,
|
||||
.madc = &zoom2_madc_data,
|
||||
.usb = &zoom2_usb_data,
|
||||
.gpio = &zoom2_gpio_data,
|
||||
.keypad = &zoom2_kp_twl4030_data,
|
||||
.codec = &zoom2_codec_data,
|
||||
.vmmc1 = &zoom2_vmmc1,
|
||||
.vmmc2 = &zoom2_vmmc2,
|
||||
.vsim = &zoom2_vsim,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP_MUX
|
||||
static struct omap_board_mux board_mux[] __initdata = {
|
||||
/* WLAN IRQ - GPIO 162 */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <plat/control.h>
|
||||
#include <plat/tc.h>
|
||||
#include <plat/board.h>
|
||||
#include <plat/mcbsp.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/mmc.h>
|
||||
#include <plat/dma.h>
|
||||
|
@ -235,6 +236,43 @@ static inline void omap_init_mbox(void) { }
|
|||
|
||||
static inline void omap_init_sti(void) {}
|
||||
|
||||
#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
|
||||
|
||||
static struct platform_device omap_pcm = {
|
||||
.name = "omap-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
/*
|
||||
* OMAP2420 has 2 McBSP ports
|
||||
* OMAP2430 has 5 McBSP ports
|
||||
* OMAP3 has 5 McBSP ports
|
||||
* OMAP4 has 4 McBSP ports
|
||||
*/
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(1);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(2);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(3);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(4);
|
||||
OMAP_MCBSP_PLATFORM_DEVICE(5);
|
||||
|
||||
static void omap_init_audio(void)
|
||||
{
|
||||
platform_device_register(&omap_mcbsp1);
|
||||
platform_device_register(&omap_mcbsp2);
|
||||
if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
|
||||
platform_device_register(&omap_mcbsp3);
|
||||
platform_device_register(&omap_mcbsp4);
|
||||
}
|
||||
if (cpu_is_omap243x() || cpu_is_omap34xx())
|
||||
platform_device_register(&omap_mcbsp5);
|
||||
|
||||
platform_device_register(&omap_pcm);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void omap_init_audio(void) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
|
||||
|
||||
#include <plat/mcspi.h>
|
||||
|
@ -917,6 +955,7 @@ static int __init omap2_init_devices(void)
|
|||
* in alphabetical order so they're easier to sort through.
|
||||
*/
|
||||
omap_hsmmc_reset();
|
||||
omap_init_audio();
|
||||
omap_init_camera();
|
||||
omap_init_mbox();
|
||||
omap_init_mcspi();
|
||||
|
|
|
@ -9,3 +9,5 @@
|
|||
extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
|
||||
extern int __init zoom_debugboard_init(void);
|
||||
extern void __init zoom_peripherals_init(void);
|
||||
|
||||
#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
|
||||
|
|
|
@ -382,6 +382,31 @@ struct platform_device pxa_device_i2s = {
|
|||
.num_resources = ARRAY_SIZE(pxai2s_resources),
|
||||
};
|
||||
|
||||
struct platform_device pxa_device_asoc_ssp1 = {
|
||||
.name = "pxa-ssp-dai",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
struct platform_device pxa_device_asoc_ssp2= {
|
||||
.name = "pxa-ssp-dai",
|
||||
.id = 1,
|
||||
};
|
||||
|
||||
struct platform_device pxa_device_asoc_ssp3 = {
|
||||
.name = "pxa-ssp-dai",
|
||||
.id = 2,
|
||||
};
|
||||
|
||||
struct platform_device pxa_device_asoc_ssp4 = {
|
||||
.name = "pxa-ssp-dai",
|
||||
.id = 3,
|
||||
};
|
||||
|
||||
struct platform_device pxa_device_asoc_platform = {
|
||||
.name = "pxa-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static u64 pxaficp_dmamask = ~(u32)0;
|
||||
|
||||
struct platform_device pxa_device_ficp = {
|
||||
|
|
|
@ -39,4 +39,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
|
|||
|
||||
extern struct platform_device pxa3xx_device_gcu;
|
||||
|
||||
extern struct platform_device pxa_device_asoc_platform;
|
||||
extern struct platform_device pxa_device_asoc_ssp1;
|
||||
extern struct platform_device pxa_device_asoc_ssp2;
|
||||
extern struct platform_device pxa_device_asoc_ssp3;
|
||||
extern struct platform_device pxa_device_asoc_ssp4;
|
||||
|
||||
void __init pxa_register_device(struct platform_device *dev, void *data);
|
||||
|
|
|
@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
|
|||
&pxa27x_device_udc,
|
||||
&pxa_device_pmu,
|
||||
&pxa_device_i2s,
|
||||
&pxa_device_asoc_ssp1,
|
||||
&pxa_device_asoc_ssp2,
|
||||
&pxa_device_asoc_ssp3,
|
||||
&pxa_device_asoc_platform,
|
||||
&sa1100_device_rtc,
|
||||
&pxa_device_rtc,
|
||||
&pxa27x_device_ssp1,
|
||||
|
|
|
@ -593,6 +593,11 @@ static struct platform_device *devices[] __initdata = {
|
|||
&pxa27x_device_udc,
|
||||
&pxa_device_pmu,
|
||||
&pxa_device_i2s,
|
||||
&pxa_device_asoc_ssp1,
|
||||
&pxa_device_asoc_ssp2,
|
||||
&pxa_device_asoc_ssp3,
|
||||
&pxa_device_asoc_ssp4,
|
||||
&pxa_device_asoc_platform,
|
||||
&sa1100_device_rtc,
|
||||
&pxa_device_rtc,
|
||||
&pxa27x_device_ssp1,
|
||||
|
|
|
@ -45,6 +45,16 @@ int wm9713_irq;
|
|||
int lcd_id;
|
||||
int lcd_orientation;
|
||||
|
||||
struct platform_device pxa_device_wm9713_audio = {
|
||||
.name = "wm9713-codec",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void __init zylonite_init_wm9713_audio(void)
|
||||
{
|
||||
platform_device_register(&pxa_device_wm9713_audio);
|
||||
}
|
||||
|
||||
static struct resource smc91x_resources[] = {
|
||||
[0] = {
|
||||
.start = ZYLONITE_ETH_PHYS + 0x300,
|
||||
|
@ -408,6 +418,7 @@ static void __init zylonite_init(void)
|
|||
zylonite_init_nand();
|
||||
zylonite_init_leds();
|
||||
zylonite_init_ohci();
|
||||
zylonite_init_wm9713_audio();
|
||||
}
|
||||
|
||||
MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
|
||||
|
|
|
@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
|
|||
s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "Invalid I2S Controller number!");
|
||||
printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
|
||||
pdev->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
|
|||
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "Invalid PCM Controller number!");
|
||||
printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
|
||||
pdev->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -333,3 +336,16 @@ void __init s3c64xx_ac97_setup_gpio(int num)
|
|||
else
|
||||
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
|
||||
}
|
||||
|
||||
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_pcm = {
|
||||
.name = "s3c24xx-pcm-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL(s3c_device_pcm);
|
||||
|
||||
|
|
|
@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
|
|||
&s3c_device_fb,
|
||||
&s3c_device_ohci,
|
||||
&s3c_device_usb_hsotg,
|
||||
&s3c_device_pcm,
|
||||
&s3c64xx_device_iisv4,
|
||||
&samsung_device_keypad,
|
||||
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <plat/clock.h>
|
||||
|
||||
/* macro for building platform_device for McBSP ports */
|
||||
#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr) \
|
||||
static struct platform_device omap_mcbsp##port_nr = { \
|
||||
.name = "omap-mcbsp-dai", \
|
||||
.id = OMAP_MCBSP##port_nr, \
|
||||
}
|
||||
|
||||
#define OMAP7XX_MCBSP1_BASE 0xfffb1000
|
||||
#define OMAP7XX_MCBSP2_BASE 0xfffb1800
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
|
|||
static u64 s3c_device_iis_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_iis = {
|
||||
.name = "s3c2410-iis",
|
||||
.name = "s3c24xx-iis",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c_iis_resource),
|
||||
.resource = s3c_iis_resource,
|
||||
|
@ -259,6 +259,21 @@ struct platform_device s3c_device_iis = {
|
|||
|
||||
EXPORT_SYMBOL(s3c_device_iis);
|
||||
|
||||
/* ASoC PCM DMA */
|
||||
|
||||
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_pcm = {
|
||||
.name = "s3c24xx-pcm-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(s3c_device_pcm);
|
||||
|
||||
/* RTC */
|
||||
|
||||
static struct resource s3c_rtc_resource[] = {
|
||||
|
@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
|
||||
|
||||
struct platform_device s3c_device_ac97 = {
|
||||
.name = "s3c-ac97",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
|
||||
.resource = s3c_ac97_resource,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_ac97_dmamask,
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(s3c_device_ac97);
|
||||
|
||||
/* ASoC I2S */
|
||||
|
||||
struct platform_device s3c2412_device_iis = {
|
||||
.name = "s3c2412-iis",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &s3c_device_audio_dmamask,
|
||||
.coherent_dma_mask = 0xffffffffUL
|
||||
}
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(s3c2412_device_iis);
|
||||
|
||||
#endif // CONFIG_CPU_S32440
|
||||
|
|
|
@ -32,6 +32,8 @@ extern struct platform_device s3c64xx_device_iisv4;
|
|||
extern struct platform_device s3c64xx_device_spi0;
|
||||
extern struct platform_device s3c64xx_device_spi1;
|
||||
|
||||
extern struct platform_device s3c_device_pcm;
|
||||
|
||||
extern struct platform_device s3c64xx_device_pcm0;
|
||||
extern struct platform_device s3c64xx_device_pcm1;
|
||||
|
||||
|
|
|
@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
|
|||
.resource = au1200_psc1_res,
|
||||
};
|
||||
|
||||
static struct platform_device db1200_stac_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = 1, /* on PSC1 */
|
||||
};
|
||||
|
||||
static struct platform_device *db1200_devs[] __initdata = {
|
||||
NULL, /* PSC0, selected by S6.8 */
|
||||
&db1200_ide_dev,
|
||||
|
@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
|
|||
&db1200_rtc_dev,
|
||||
&db1200_nand_dev,
|
||||
&db1200_audio_dev,
|
||||
&db1200_stac_dev,
|
||||
};
|
||||
|
||||
static int __init db1200_dev_init(void)
|
||||
|
|
|
@ -286,6 +286,7 @@
|
|||
|
||||
ssi@16100 {
|
||||
compatible = "fsl,mpc8610-ssi";
|
||||
status = "disabled";
|
||||
cell-index = <1>;
|
||||
reg = <0x16100 0x100>;
|
||||
interrupt-parent = <&mpic>;
|
||||
|
|
|
@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
|
|||
CONFIG_I2C_MPC=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_VIDEO_OUTPUT_CONTROL=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_FSL_DIU=y
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
# CONFIG_SND_SUPPORT_OLD_API is not set
|
||||
|
|
|
@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
|
|||
CONFIG_I2C_MPC=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_VIDEO_OUTPUT_CONTROL=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_FSL_DIU=y
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
# CONFIG_SND_SUPPORT_OLD_API is not set
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* MPC86xx Internal Memory Map
|
||||
* Freecale 85xx and 86xx Global Utilties register set
|
||||
*
|
||||
* Authors: Jeff Brown
|
||||
* Timur Tabi <timur@freescale.com>
|
||||
|
@ -10,73 +10,112 @@
|
|||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This header file defines structures for various 86xx SOC devices that are
|
||||
* used by multiple source files.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_POWERPC_IMMAP_86XX_H__
|
||||
#define __ASM_POWERPC_IMMAP_86XX_H__
|
||||
#ifndef __ASM_POWERPC_FSL_GUTS_H__
|
||||
#define __ASM_POWERPC_FSL_GUTS_H__
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* Global Utility Registers */
|
||||
struct ccsr_guts {
|
||||
/*
|
||||
* These #ifdefs are safe because it's not possible to build a kernel that
|
||||
* runs on e500 and e600 cores.
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
|
||||
#error Only 85xx and 86xx SOCs are supported
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Global Utility Registers.
|
||||
*
|
||||
* Not all registers defined in this structure are available on all chips, so
|
||||
* you are expected to know whether a given register actually exists on your
|
||||
* chip before you access it.
|
||||
*
|
||||
* Also, some registers are similar on different chips but have slightly
|
||||
* different names. In these cases, one name is chosen to avoid extraneous
|
||||
* #ifdefs.
|
||||
*/
|
||||
#ifdef CONFIG_PPC_85xx
|
||||
struct ccsr_guts_85xx {
|
||||
#else
|
||||
struct ccsr_guts_86xx {
|
||||
#endif
|
||||
__be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
|
||||
__be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
|
||||
__be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
|
||||
__be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
|
||||
__be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
|
||||
u8 res1[0x20 - 0x14];
|
||||
__be32 pordevsr2; /* 0x.0014 - POR device status register 2 */
|
||||
u8 res018[0x20 - 0x18];
|
||||
__be32 porcir; /* 0x.0020 - POR Configuration Information Register */
|
||||
u8 res2[0x30 - 0x24];
|
||||
u8 res024[0x30 - 0x24];
|
||||
__be32 gpiocr; /* 0x.0030 - GPIO Control Register */
|
||||
u8 res3[0x40 - 0x34];
|
||||
u8 res034[0x40 - 0x34];
|
||||
__be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
|
||||
u8 res4[0x50 - 0x44];
|
||||
u8 res044[0x50 - 0x44];
|
||||
__be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */
|
||||
u8 res5[0x60 - 0x54];
|
||||
u8 res054[0x60 - 0x54];
|
||||
__be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
|
||||
u8 res6[0x70 - 0x64];
|
||||
__be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */
|
||||
__be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
|
||||
u8 res06c[0x70 - 0x6c];
|
||||
__be32 devdisr; /* 0x.0070 - Device Disable Control */
|
||||
__be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
|
||||
u8 res7[0x80 - 0x78];
|
||||
u8 res078[0x7c - 0x78];
|
||||
__be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
|
||||
__be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
|
||||
u8 res8[0x90 - 0x84];
|
||||
__be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */
|
||||
__be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */
|
||||
__be32 pmcdr; /* 0x.008c - 4Power management clock disable register */
|
||||
__be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
|
||||
__be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */
|
||||
u8 res9[0xA0 - 0x98];
|
||||
__be32 ectrstcr; /* 0x.0098 - Exception reset control register */
|
||||
__be32 autorstsr; /* 0x.009c - Automatic reset status register */
|
||||
__be32 pvr; /* 0x.00a0 - Processor Version Register */
|
||||
__be32 svr; /* 0x.00a4 - System Version Register */
|
||||
u8 res10[0xB0 - 0xA8];
|
||||
u8 res0a8[0xb0 - 0xa8];
|
||||
__be32 rstcr; /* 0x.00b0 - Reset Control Register */
|
||||
u8 res11[0xC0 - 0xB4];
|
||||
u8 res0b4[0xc0 - 0xb4];
|
||||
#ifdef CONFIG_PPC_85xx
|
||||
__be32 iovselsr; /* 0x.00c0 - I/O voltage select status register */
|
||||
#else
|
||||
__be32 elbcvselcr; /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
|
||||
u8 res12[0x800 - 0xC4];
|
||||
#endif
|
||||
u8 res0c4[0x224 - 0xc4];
|
||||
__be32 iodelay1; /* 0x.0224 - IO delay control register 1 */
|
||||
__be32 iodelay2; /* 0x.0228 - IO delay control register 2 */
|
||||
u8 res22c[0x800 - 0x22c];
|
||||
__be32 clkdvdr; /* 0x.0800 - Clock Divide Register */
|
||||
u8 res13[0x900 - 0x804];
|
||||
u8 res804[0x900 - 0x804];
|
||||
__be32 ircr; /* 0x.0900 - Infrared Control Register */
|
||||
u8 res14[0x908 - 0x904];
|
||||
u8 res904[0x908 - 0x904];
|
||||
__be32 dmacr; /* 0x.0908 - DMA Control Register */
|
||||
u8 res15[0x914 - 0x90C];
|
||||
u8 res90c[0x914 - 0x90c];
|
||||
__be32 elbccr; /* 0x.0914 - eLBC Control Register */
|
||||
u8 res16[0xB20 - 0x918];
|
||||
u8 res918[0xb20 - 0x918];
|
||||
__be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
|
||||
__be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
|
||||
__be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
|
||||
u8 res17[0xE00 - 0xB2C];
|
||||
u8 resb2c[0xe00 - 0xb2c];
|
||||
__be32 clkocr; /* 0x.0e00 - Clock Out Select Register */
|
||||
u8 res18[0xE10 - 0xE04];
|
||||
u8 rese04[0xe10 - 0xe04];
|
||||
__be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
|
||||
u8 res19[0xE20 - 0xE14];
|
||||
u8 rese14[0xe20 - 0xe14];
|
||||
__be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
|
||||
u8 res20[0xF04 - 0xE24];
|
||||
__be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */
|
||||
u8 rese28[0xf04 - 0xe28];
|
||||
__be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
|
||||
__be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
|
||||
u8 res21[0xF40 - 0xF0C];
|
||||
__be32 srds2cr0; /* 0x.0f40 - SerDes1 Control Register 0 */
|
||||
__be32 srds2cr1; /* 0x.0f44 - SerDes1 Control Register 0 */
|
||||
u8 resf0c[0xf2c - 0xf0c];
|
||||
__be32 itcr; /* 0x.0f2c - Internal transaction control register */
|
||||
u8 resf30[0xf40 - 0xf30];
|
||||
__be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
|
||||
__be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#ifdef CONFIG_PPC_86xx
|
||||
|
||||
#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
|
||||
#define CCSR_GUTS_DMACR_DEV_IR 1 /* DMA controller/channel set to IR */
|
||||
|
||||
|
@ -93,7 +132,7 @@ struct ccsr_guts {
|
|||
* ch: The channel on the DMA controller (0, 1, 2, or 3)
|
||||
* device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
|
||||
*/
|
||||
static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
|
||||
static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
|
||||
unsigned int co, unsigned int ch, unsigned int device)
|
||||
{
|
||||
unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
|
||||
|
@ -129,7 +168,7 @@ static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
|
|||
* ch: The channel on the DMA controller (0, 1, 2, or 3)
|
||||
* value: the new value for the bit (0 or 1)
|
||||
*/
|
||||
static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
|
||||
static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
|
||||
unsigned int co, unsigned int ch, unsigned int value)
|
||||
{
|
||||
if ((ch == 0) || (ch == 3)) {
|
||||
|
@ -152,5 +191,7 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
|
|||
#define CCSR_GUTS_CLKDVDR_SSICLK_MASK 0x000000FF
|
||||
#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
|
||||
|
||||
#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -8,7 +8,6 @@
|
|||
* Copyright 2010 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This file is taken from the Freescale P1022DS BSP, with modifications:
|
||||
* 1) No DIU support (pending rewrite of DIU code)
|
||||
* 2) No AMP support
|
||||
* 3) No PCI endpoint support
|
||||
*
|
||||
|
@ -20,12 +19,211 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/memblock.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include <asm/mpic.h>
|
||||
#include <asm/swiotlb.h>
|
||||
|
||||
#include <sysdev/fsl_soc.h>
|
||||
#include <sysdev/fsl_pci.h>
|
||||
#include <asm/fsl_guts.h>
|
||||
|
||||
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
|
||||
|
||||
/*
|
||||
* Board-specific initialization of the DIU. This code should probably be
|
||||
* executed when the DIU is opened, rather than in arch code, but the DIU
|
||||
* driver does not have a mechanism for this (yet).
|
||||
*
|
||||
* This is especially problematic on the P1022DS because the local bus (eLBC)
|
||||
* and the DIU video signals share the same pins, which means that enabling the
|
||||
* DIU will disable access to NOR flash.
|
||||
*/
|
||||
|
||||
/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
|
||||
#define CLKDVDR_PXCKEN 0x80000000
|
||||
#define CLKDVDR_PXCKINV 0x10000000
|
||||
#define CLKDVDR_PXCKDLY 0x06000000
|
||||
#define CLKDVDR_PXCLK_MASK 0x00FF0000
|
||||
|
||||
/* Some ngPIXIS register definitions */
|
||||
#define PX_BRDCFG1_DVIEN 0x80
|
||||
#define PX_BRDCFG1_DFPEN 0x40
|
||||
#define PX_BRDCFG1_BACKLIGHT 0x20
|
||||
#define PX_BRDCFG1_DDCEN 0x10
|
||||
|
||||
/*
|
||||
* DIU Area Descriptor
|
||||
*
|
||||
* Note that we need to byte-swap the value before it's written to the AD
|
||||
* register. So even though the registers don't look like they're in the same
|
||||
* bit positions as they are on the MPC8610, the same value is written to the
|
||||
* AD register on the MPC8610 and on the P1022.
|
||||
*/
|
||||
#define AD_BYTE_F 0x10000000
|
||||
#define AD_ALPHA_C_MASK 0x0E000000
|
||||
#define AD_ALPHA_C_SHIFT 25
|
||||
#define AD_BLUE_C_MASK 0x01800000
|
||||
#define AD_BLUE_C_SHIFT 23
|
||||
#define AD_GREEN_C_MASK 0x00600000
|
||||
#define AD_GREEN_C_SHIFT 21
|
||||
#define AD_RED_C_MASK 0x00180000
|
||||
#define AD_RED_C_SHIFT 19
|
||||
#define AD_PALETTE 0x00040000
|
||||
#define AD_PIXEL_S_MASK 0x00030000
|
||||
#define AD_PIXEL_S_SHIFT 16
|
||||
#define AD_COMP_3_MASK 0x0000F000
|
||||
#define AD_COMP_3_SHIFT 12
|
||||
#define AD_COMP_2_MASK 0x00000F00
|
||||
#define AD_COMP_2_SHIFT 8
|
||||
#define AD_COMP_1_MASK 0x000000F0
|
||||
#define AD_COMP_1_SHIFT 4
|
||||
#define AD_COMP_0_MASK 0x0000000F
|
||||
#define AD_COMP_0_SHIFT 0
|
||||
|
||||
#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
|
||||
cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
|
||||
(blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
|
||||
(red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
|
||||
(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
|
||||
(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
|
||||
|
||||
/**
|
||||
* p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
|
||||
*
|
||||
* The Area Descriptor is a 32-bit value that determine which bits in each
|
||||
* pixel are to be used for each color.
|
||||
*/
|
||||
static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
|
||||
int monitor_port)
|
||||
{
|
||||
switch (bits_per_pixel) {
|
||||
case 32:
|
||||
/* 0x88883316 */
|
||||
return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
|
||||
case 24:
|
||||
/* 0x88082219 */
|
||||
return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
|
||||
case 16:
|
||||
/* 0x65053118 */
|
||||
return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
|
||||
default:
|
||||
pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* p1022ds_set_gamma_table: update the gamma table, if necessary
|
||||
*
|
||||
* On some boards, the gamma table for some ports may need to be modified.
|
||||
* This is not the case on the P1022DS, so we do nothing.
|
||||
*/
|
||||
static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* p1022ds_set_monitor_port: switch the output to a different monitor port
|
||||
*
|
||||
*/
|
||||
static void p1022ds_set_monitor_port(int monitor_port)
|
||||
{
|
||||
struct device_node *pixis_node;
|
||||
u8 __iomem *brdcfg1;
|
||||
|
||||
pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
|
||||
if (!pixis_node) {
|
||||
pr_err("p1022ds: missing ngPIXIS node\n");
|
||||
return;
|
||||
}
|
||||
|
||||
brdcfg1 = of_iomap(pixis_node, 0);
|
||||
if (!brdcfg1) {
|
||||
pr_err("p1022ds: could not map ngPIXIS registers\n");
|
||||
return;
|
||||
}
|
||||
brdcfg1 += 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */
|
||||
|
||||
switch (monitor_port) {
|
||||
case 0: /* DVI */
|
||||
/* Enable the DVI port, disable the DFP and the backlight */
|
||||
clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
|
||||
PX_BRDCFG1_DVIEN);
|
||||
break;
|
||||
case 1: /* Single link LVDS */
|
||||
/* Enable the DFP port, disable the DVI and the backlight */
|
||||
clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
|
||||
PX_BRDCFG1_DFPEN);
|
||||
break;
|
||||
default:
|
||||
pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* p1022ds_set_pixel_clock: program the DIU's clock
|
||||
*
|
||||
* @pixclock: the wavelength, in picoseconds, of the clock
|
||||
*/
|
||||
void p1022ds_set_pixel_clock(unsigned int pixclock)
|
||||
{
|
||||
struct device_node *guts_np = NULL;
|
||||
struct ccsr_guts_85xx __iomem *guts;
|
||||
unsigned long freq;
|
||||
u64 temp;
|
||||
u32 pxclk;
|
||||
|
||||
/* Map the global utilities registers. */
|
||||
guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
|
||||
if (!guts_np) {
|
||||
pr_err("p1022ds: missing global utilties device node\n");
|
||||
return;
|
||||
}
|
||||
|
||||
guts = of_iomap(guts_np, 0);
|
||||
of_node_put(guts_np);
|
||||
if (!guts) {
|
||||
pr_err("p1022ds: could not map global utilties device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert pixclock from a wavelength to a frequency */
|
||||
temp = 1000000000000ULL;
|
||||
do_div(temp, pixclock);
|
||||
freq = temp;
|
||||
|
||||
/* pixclk is the ratio of the platform clock to the pixel clock */
|
||||
pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
|
||||
|
||||
/* Disable the pixel clock, and set it to non-inverted and no delay */
|
||||
clrbits32(&guts->clkdvdr,
|
||||
CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
|
||||
|
||||
/* Enable the clock and set the pxclk */
|
||||
setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* p1022ds_show_monitor_port: show the current monitor
|
||||
*
|
||||
* This function returns a string indicating whether the current monitor is
|
||||
* set to DVI or LVDS.
|
||||
*/
|
||||
ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
|
||||
monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
|
||||
*/
|
||||
int p1022ds_set_sysfs_monitor_port(int val)
|
||||
{
|
||||
return val < 2 ? val : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void __init p1022_ds_pic_init(void)
|
||||
{
|
||||
|
@ -92,6 +290,15 @@ static void __init p1022_ds_setup_arch(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
|
||||
diu_ops.get_pixel_format = p1022ds_get_pixel_format;
|
||||
diu_ops.set_gamma_table = p1022ds_set_gamma_table;
|
||||
diu_ops.set_monitor_port = p1022ds_set_monitor_port;
|
||||
diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;
|
||||
diu_ops.show_monitor_port = p1022ds_show_monitor_port;
|
||||
diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
mpc85xx_smp_init();
|
||||
#endif
|
||||
|
|
|
@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
|
|||
};
|
||||
|
||||
static struct platform_device siu_device = {
|
||||
.name = "sh_siu",
|
||||
.name = "siu-pcm-audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &siu_platform_data,
|
||||
|
|
|
@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
|
|||
.probe = twl4030_vibra_probe,
|
||||
.remove = __devexit_p(twl4030_vibra_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_codec_vibra",
|
||||
.name = "twl4030-vibra",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &twl4030_vibra_pm_ops,
|
||||
|
@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
|
|||
}
|
||||
module_exit(twl4030_vibra_exit);
|
||||
|
||||
MODULE_ALIAS("platform:twl4030_codec_vibra");
|
||||
MODULE_ALIAS("platform:twl4030-vibra");
|
||||
|
||||
MODULE_DESCRIPTION("TWL4030 Vibra driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
|||
|
||||
if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
|
||||
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
|
||||
child = add_child(sub_chip_id, "twl4030_codec",
|
||||
child = add_child(sub_chip_id, "twl4030-audio",
|
||||
pdata->codec, sizeof(*pdata->codec),
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
/* Phoenix*/
|
||||
/* Phoenix codec driver is probed directly atm */
|
||||
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
|
||||
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
|
||||
child = add_child(sub_chip_id, "twl6040_codec",
|
||||
child = add_child(sub_chip_id, "twl6040-codec",
|
||||
pdata->codec, sizeof(*pdata->codec),
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
|
|
|
@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
|||
|
||||
if (pdata->audio) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030_codec_audio";
|
||||
cell->name = "twl4030-codec";
|
||||
cell->platform_data = pdata->audio;
|
||||
cell->data_size = sizeof(*pdata->audio);
|
||||
childs++;
|
||||
}
|
||||
if (pdata->vibra) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030_codec_vibra";
|
||||
cell->name = "twl4030-vibra";
|
||||
cell->platform_data = pdata->vibra;
|
||||
cell->data_size = sizeof(*pdata->vibra);
|
||||
childs++;
|
||||
|
@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:twl4030_codec");
|
||||
MODULE_ALIAS("platform:twl4030-audio");
|
||||
|
||||
static struct platform_driver twl4030_codec_driver = {
|
||||
.probe = twl4030_codec_probe,
|
||||
.remove = __devexit_p(twl4030_codec_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "twl4030_codec",
|
||||
.name = "twl4030-audio",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@ TODO:
|
|||
- get rid of non-linux related stuff
|
||||
|
||||
Please send patches to:
|
||||
Arnaud Patard <apatard@mandriva.com>
|
||||
Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
|
|
|
@ -1919,6 +1919,9 @@ config FB_SH_MOBILE_HDMI
|
|||
tristate "SuperH Mobile HDMI controller support"
|
||||
depends on FB_SH_MOBILE_LCDC
|
||||
select FB_MODE_HELPERS
|
||||
select SOUND
|
||||
select SND
|
||||
select SND_SOC
|
||||
---help---
|
||||
Driver for the on-chip SH-Mobile HDMI controller.
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include <video/sh_mobile_hdmi.h>
|
||||
#include <video/sh_mobile_lcdc.h>
|
||||
|
@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
|
|||
return ioread8(hdmi->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* HDMI sound
|
||||
*/
|
||||
static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return hdmi_read(hdmi, reg);
|
||||
}
|
||||
|
||||
static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
hdmi_write(hdmi, value, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver sh_hdmi_dai = {
|
||||
.name = "sh_mobile_hdmi-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
};
|
||||
|
||||
static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
|
||||
.probe = sh_hdmi_snd_probe,
|
||||
.read = sh_hdmi_snd_read,
|
||||
.write = sh_hdmi_snd_write,
|
||||
};
|
||||
|
||||
/*
|
||||
* HDMI video
|
||||
*/
|
||||
|
||||
/* External video parameter settings */
|
||||
static void hdmi_external_video_param(struct sh_hdmi *hdmi)
|
||||
{
|
||||
|
@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
|
|||
*/
|
||||
static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
|
||||
{
|
||||
u8 data;
|
||||
struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
|
||||
|
||||
/*
|
||||
* [7:4] L/R data swap control
|
||||
* [3:0] appropriate N[19:16]
|
||||
|
@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
|
|||
* [6:5] set required down sampling rate if required
|
||||
* [4:3] set required audio source
|
||||
*/
|
||||
hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
|
||||
switch (pdata->flags & HDMI_SND_SRC_MASK) {
|
||||
default:
|
||||
/* fall through */
|
||||
case HDMI_SND_SRC_I2S:
|
||||
data = 0x0 << 3;
|
||||
break;
|
||||
case HDMI_SND_SRC_SPDIF:
|
||||
data = 0x1 << 3;
|
||||
break;
|
||||
case HDMI_SND_SRC_DSD:
|
||||
data = 0x2 << 3;
|
||||
break;
|
||||
case HDMI_SND_SRC_HBR:
|
||||
data = 0x3 << 3;
|
||||
break;
|
||||
}
|
||||
hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
|
||||
|
||||
/* [3:0] set sending channel number for channel status */
|
||||
hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
|
||||
|
@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
|
||||
if (ret < 0)
|
||||
goto esndreg;
|
||||
|
||||
hdmi->dev = &pdev->dev;
|
||||
|
||||
hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
|
||||
|
@ -976,6 +1054,8 @@ eclkenable:
|
|||
erate:
|
||||
clk_put(hdmi->hdmi_clk);
|
||||
egetclk:
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
esndreg:
|
||||
kfree(hdmi);
|
||||
|
||||
return ret;
|
||||
|
@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
|
|||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
pdata->lcd_chan->board_cfg.display_on = NULL;
|
||||
pdata->lcd_chan->board_cfg.display_off = NULL;
|
||||
pdata->lcd_chan->board_cfg.board_data = NULL;
|
||||
|
|
|
@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
|
|||
extern int twl4030_remove_script(u8 flags);
|
||||
|
||||
struct twl4030_codec_audio_data {
|
||||
unsigned int audio_mclk;
|
||||
unsigned int audio_mclk; /* not used, will be removed */
|
||||
unsigned int digimic_delay; /* in ms */
|
||||
unsigned int ramp_delay_value;
|
||||
unsigned int offset_cncl_path;
|
||||
unsigned int check_defaults:1;
|
||||
unsigned int reset_registers:1;
|
||||
unsigned int hs_extmute:1;
|
||||
void (*set_hs_extmute)(int mute);
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
|
|||
#define snd_power_lock(card) do { (void)(card); } while (0)
|
||||
#define snd_power_unlock(card) do { (void)(card); } while (0)
|
||||
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
|
||||
#define snd_power_get_state(card) SNDRV_CTL_POWER_D0
|
||||
#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
|
||||
#define snd_power_change_state(card, state) do { (void)(card); } while (0)
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
@ -438,6 +438,8 @@
|
|||
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
|
||||
#define CCCA_CURRADDR 0x18000008
|
||||
|
||||
/* undefine CCR to avoid conflict with the definition for SH */
|
||||
#undef CCR
|
||||
#define CCR 0x09 /* Cache control register */
|
||||
#define CCR_CACHEINVALIDSIZE 0x07190009
|
||||
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
|
||||
|
|
|
@ -47,6 +47,9 @@ enum snd_jack_types {
|
|||
SND_JACK_BTN_0 = 0x4000,
|
||||
SND_JACK_BTN_1 = 0x2000,
|
||||
SND_JACK_BTN_2 = 0x1000,
|
||||
SND_JACK_BTN_3 = 0x0800,
|
||||
SND_JACK_BTN_4 = 0x0400,
|
||||
SND_JACK_BTN_5 = 0x0200,
|
||||
};
|
||||
|
||||
struct snd_jack {
|
||||
|
@ -55,7 +58,7 @@ struct snd_jack {
|
|||
int type;
|
||||
const char *id;
|
||||
char name[100];
|
||||
unsigned int key[3]; /* Keep in sync with definitions above */
|
||||
unsigned int key[6]; /* Keep in sync with definitions above */
|
||||
void *private_data;
|
||||
void (*private_free)(struct snd_jack *);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Platform data for MAX98088
|
||||
*
|
||||
* Copyright 2010 Maxim Integrated Products
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_MAX98088_PDATA_H__
|
||||
#define __SOUND_MAX98088_PDATA_H__
|
||||
|
||||
/* Equalizer filter response configuration */
|
||||
struct max98088_eq_cfg {
|
||||
const char *name;
|
||||
unsigned int rate;
|
||||
u16 band1[5];
|
||||
u16 band2[5];
|
||||
u16 band3[5];
|
||||
u16 band4[5];
|
||||
u16 band5[5];
|
||||
};
|
||||
|
||||
/* codec platform data */
|
||||
struct max98088_pdata {
|
||||
|
||||
/* Equalizers for DAI1 and DAI2 */
|
||||
struct max98088_eq_cfg *eq_cfg;
|
||||
unsigned int eq_cfgcnt;
|
||||
|
||||
/* Receiver output can be configured as power amplifier or LINE out */
|
||||
/* Set receiver_mode to:
|
||||
* 0 = amplifier output, or
|
||||
* 1 = LINE level output
|
||||
*/
|
||||
unsigned int receiver_mode:1;
|
||||
|
||||
/* Analog/digital microphone configuration:
|
||||
* 0 = analog microphone input (normal setting)
|
||||
* 1 = digital microphone input
|
||||
*/
|
||||
unsigned int digmic_left_mode:1;
|
||||
unsigned int digmic_right_mode:1;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -278,6 +278,7 @@ struct snd_pcm_runtime {
|
|||
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
|
||||
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
|
||||
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
|
||||
unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
|
||||
snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
|
||||
|
||||
/* -- HW params -- */
|
||||
|
|
|
@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
|
|||
int (*set_rate)(int is_porta, int rate); /* for master mode */
|
||||
};
|
||||
|
||||
extern struct snd_soc_dai fsi_soc_dai[2];
|
||||
extern struct snd_soc_platform fsi_soc_platform;
|
||||
|
||||
#endif /* __SOUND_FSI_H */
|
||||
|
|
|
@ -91,15 +91,17 @@ struct snd_pcm_substream;
|
|||
SNDRV_PCM_FMTBIT_S32_LE |\
|
||||
SNDRV_PCM_FMTBIT_S32_BE)
|
||||
|
||||
struct snd_soc_dai_ops;
|
||||
struct snd_soc_dai_driver;
|
||||
struct snd_soc_dai;
|
||||
struct snd_ac97_bus_ops;
|
||||
|
||||
/* Digital Audio Interface registration */
|
||||
int snd_soc_register_dai(struct snd_soc_dai *dai);
|
||||
void snd_soc_unregister_dai(struct snd_soc_dai *dai);
|
||||
int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
|
||||
void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
|
||||
int snd_soc_register_dai(struct device *dev,
|
||||
struct snd_soc_dai_driver *dai_drv);
|
||||
void snd_soc_unregister_dai(struct device *dev);
|
||||
int snd_soc_register_dais(struct device *dev,
|
||||
struct snd_soc_dai_driver *dai_drv, size_t count);
|
||||
void snd_soc_unregister_dais(struct device *dev, size_t count);
|
||||
|
||||
/* Digital Audio Interface clocking API.*/
|
||||
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
|
@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
|
|||
/* Digital Audio Interface mute */
|
||||
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
|
||||
|
||||
/*
|
||||
* Digital Audio Interface.
|
||||
*
|
||||
* Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
|
||||
* operations and capabilities. Codec and platform drivers will register this
|
||||
* structure for every DAI they have.
|
||||
*
|
||||
* This structure covers the clocking, formating and ALSA operations for each
|
||||
* interface.
|
||||
*/
|
||||
struct snd_soc_dai_ops {
|
||||
/*
|
||||
* DAI clocking configuration, all optional.
|
||||
|
@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
|
|||
};
|
||||
|
||||
/*
|
||||
* Digital Audio Interface runtime data.
|
||||
* Digital Audio Interface Driver.
|
||||
*
|
||||
* Holds runtime data for a DAI.
|
||||
* Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
|
||||
* operations and capabilities. Codec and platform drivers will register this
|
||||
* structure for every DAI they have.
|
||||
*
|
||||
* This structure covers the clocking, formating and ALSA operations for each
|
||||
* interface.
|
||||
*/
|
||||
struct snd_soc_dai {
|
||||
struct snd_soc_dai_driver {
|
||||
/* DAI description */
|
||||
char *name;
|
||||
const char *name;
|
||||
unsigned int id;
|
||||
int ac97_control;
|
||||
|
||||
struct device *dev;
|
||||
void *ac97_pdata; /* platform_data for the ac97 codec */
|
||||
|
||||
/* DAI callbacks */
|
||||
int (*probe)(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai);
|
||||
void (*remove)(struct platform_device *pdev,
|
||||
struct snd_soc_dai *dai);
|
||||
/* DAI driver callbacks */
|
||||
int (*probe)(struct snd_soc_dai *dai);
|
||||
int (*remove)(struct snd_soc_dai *dai);
|
||||
int (*suspend)(struct snd_soc_dai *dai);
|
||||
int (*resume)(struct snd_soc_dai *dai);
|
||||
|
||||
|
@ -219,26 +211,51 @@ struct snd_soc_dai {
|
|||
struct snd_soc_pcm_stream capture;
|
||||
struct snd_soc_pcm_stream playback;
|
||||
unsigned int symmetric_rates:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Digital Audio Interface runtime data.
|
||||
*
|
||||
* Holds runtime data for a DAI.
|
||||
*/
|
||||
struct snd_soc_dai {
|
||||
const char *name;
|
||||
int id;
|
||||
struct device *dev;
|
||||
void *ac97_pdata; /* platform_data for the ac97 codec */
|
||||
|
||||
/* driver ops */
|
||||
struct snd_soc_dai_driver *driver;
|
||||
|
||||
/* DAI runtime info */
|
||||
struct snd_soc_codec *codec;
|
||||
unsigned int capture_active:1; /* stream is in use */
|
||||
unsigned int playback_active:1; /* stream is in use */
|
||||
unsigned int symmetric_rates:1;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
unsigned int active;
|
||||
unsigned char pop_wait:1;
|
||||
unsigned char probed:1;
|
||||
|
||||
/* DAI private data */
|
||||
void *private_data;
|
||||
/* DAI DMA data */
|
||||
void *playback_dma_data;
|
||||
void *capture_dma_data;
|
||||
|
||||
/* parent platform */
|
||||
struct snd_soc_platform *platform;
|
||||
/* parent platform/codec */
|
||||
union {
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_codec *codec;
|
||||
};
|
||||
struct snd_soc_card *card;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
};
|
||||
|
||||
static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
|
||||
const struct snd_pcm_substream *ss)
|
||||
{
|
||||
return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
dai->playback.dma_data : dai->capture.dma_data;
|
||||
dai->playback_dma_data : dai->capture_dma_data;
|
||||
}
|
||||
|
||||
static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
|
||||
|
@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
|
|||
void *data)
|
||||
{
|
||||
if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dai->playback.dma_data = data;
|
||||
dai->playback_dma_data = data;
|
||||
else
|
||||
dai->capture.dma_data = data;
|
||||
dai->capture_dma_data = data;
|
||||
}
|
||||
|
||||
static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
|
||||
void *data)
|
||||
{
|
||||
dev_set_drvdata(dai->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
|
||||
{
|
||||
return dev_get_drvdata(dai->dev);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -172,9 +172,19 @@
|
|||
#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert }
|
||||
#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert, \
|
||||
.event = wevent, .event_flags = wflags }
|
||||
#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert }
|
||||
#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert, \
|
||||
.event = wevent, .event_flags = wflags }
|
||||
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert}
|
||||
|
@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
|
|||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
|
||||
void snd_soc_dapm_free(struct snd_soc_device *socdev);
|
||||
void snd_soc_dapm_free(struct snd_soc_codec *codec);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
|
||||
/* dapm events */
|
||||
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
|
||||
int event);
|
||||
void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
|
||||
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
|
||||
const char *stream, int event);
|
||||
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
|
||||
|
||||
/* dapm sys fs - used by the core */
|
||||
int snd_soc_dapm_sys_add(struct device *dev);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* OF helpers for ALSA SoC
|
||||
*
|
||||
* Copyright (C) 2008, Secret Lab Technologies Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOC_OF_H_
|
||||
#define _INCLUDE_SOC_OF_H_
|
||||
|
||||
#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
|
||||
void *codec_data, struct snd_soc_dai *dai,
|
||||
struct device_node *node);
|
||||
|
||||
int of_snd_soc_register_platform(struct snd_soc_platform *platform,
|
||||
struct device_node *node,
|
||||
struct snd_soc_dai *cpu_dai);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_SOC_OF_H_ */
|
|
@ -214,10 +214,10 @@
|
|||
* @OFF: Power Off. No restrictions on transition times.
|
||||
*/
|
||||
enum snd_soc_bias_level {
|
||||
SND_SOC_BIAS_ON,
|
||||
SND_SOC_BIAS_PREPARE,
|
||||
SND_SOC_BIAS_STANDBY,
|
||||
SND_SOC_BIAS_OFF,
|
||||
SND_SOC_BIAS_STANDBY,
|
||||
SND_SOC_BIAS_PREPARE,
|
||||
SND_SOC_BIAS_ON,
|
||||
};
|
||||
|
||||
struct snd_jack;
|
||||
|
@ -228,13 +228,17 @@ struct snd_soc_ops;
|
|||
struct snd_soc_dai_mode;
|
||||
struct snd_soc_pcm_runtime;
|
||||
struct snd_soc_dai;
|
||||
struct snd_soc_dai_driver;
|
||||
struct snd_soc_platform;
|
||||
struct snd_soc_dai_link;
|
||||
struct snd_soc_platform_driver;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_codec_driver;
|
||||
struct soc_enum;
|
||||
struct snd_soc_ac97_ops;
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_jack_pin;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct snd_soc_jack_gpio;
|
||||
#endif
|
||||
|
@ -249,19 +253,18 @@ enum snd_soc_control_type {
|
|||
SND_SOC_SPI,
|
||||
};
|
||||
|
||||
int snd_soc_register_platform(struct snd_soc_platform *platform);
|
||||
void snd_soc_unregister_platform(struct snd_soc_platform *platform);
|
||||
int snd_soc_register_codec(struct snd_soc_codec *codec);
|
||||
void snd_soc_unregister_codec(struct snd_soc_codec *codec);
|
||||
int snd_soc_register_platform(struct device *dev,
|
||||
struct snd_soc_platform_driver *platform_drv);
|
||||
void snd_soc_unregister_platform(struct device *dev);
|
||||
int snd_soc_register_codec(struct device *dev,
|
||||
struct snd_soc_codec_driver *codec_drv,
|
||||
struct snd_soc_dai_driver *dai_drv, int num_dai);
|
||||
void snd_soc_unregister_codec(struct device *dev);
|
||||
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
|
||||
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
|
||||
int addr_bits, int data_bits,
|
||||
enum snd_soc_control_type control);
|
||||
|
||||
/* pcm <-> DAI connect */
|
||||
void snd_soc_free_pcms(struct snd_soc_device *socdev);
|
||||
int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
|
||||
|
||||
/* Utility functions to get clock rates from various things */
|
||||
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
|
||||
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
|
||||
|
@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
|||
const struct snd_pcm_hardware *hw);
|
||||
|
||||
/* Jack reporting */
|
||||
int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
|
||||
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
|
||||
struct snd_soc_jack *jack);
|
||||
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
|
||||
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
|
||||
|
@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
|
|||
int invert;
|
||||
int debounce_time;
|
||||
struct snd_soc_jack *jack;
|
||||
struct work_struct work;
|
||||
struct delayed_work work;
|
||||
|
||||
int (*jack_status_check)(void);
|
||||
};
|
||||
|
@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
|
|||
|
||||
struct snd_soc_jack {
|
||||
struct snd_jack *jack;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_codec *codec;
|
||||
struct list_head pins;
|
||||
int status;
|
||||
struct blocking_notifier_head notifier;
|
||||
|
@ -398,15 +401,13 @@ struct snd_soc_jack {
|
|||
|
||||
/* SoC PCM stream information */
|
||||
struct snd_soc_pcm_stream {
|
||||
char *stream_name;
|
||||
const char *stream_name;
|
||||
u64 formats; /* SNDRV_PCM_FMTBIT_* */
|
||||
unsigned int rates; /* SNDRV_PCM_RATE_* */
|
||||
unsigned int rate_min; /* min rate */
|
||||
unsigned int rate_max; /* max rate */
|
||||
unsigned int channels_min; /* min channels */
|
||||
unsigned int channels_max; /* max channels */
|
||||
unsigned int active; /* stream is in use */
|
||||
void *dma_data; /* used by platform code */
|
||||
};
|
||||
|
||||
/* SoC audio ops */
|
||||
|
@ -419,44 +420,36 @@ struct snd_soc_ops {
|
|||
int (*trigger)(struct snd_pcm_substream *, int);
|
||||
};
|
||||
|
||||
/* SoC Audio Codec */
|
||||
/* SoC Audio Codec device */
|
||||
struct snd_soc_codec {
|
||||
char *name;
|
||||
struct module *owner;
|
||||
struct mutex mutex;
|
||||
const char *name;
|
||||
int id;
|
||||
struct device *dev;
|
||||
struct snd_soc_device *socdev;
|
||||
struct snd_soc_codec_driver *driver;
|
||||
|
||||
struct mutex mutex;
|
||||
struct snd_soc_card *card;
|
||||
struct list_head list;
|
||||
|
||||
/* callbacks */
|
||||
int (*set_bias_level)(struct snd_soc_codec *,
|
||||
enum snd_soc_bias_level level);
|
||||
struct list_head card_list;
|
||||
int num_dai;
|
||||
|
||||
/* runtime */
|
||||
struct snd_card *card;
|
||||
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
|
||||
unsigned int active;
|
||||
unsigned int pcm_devs;
|
||||
void *drvdata;
|
||||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
int (*display_register)(struct snd_soc_codec *, char *,
|
||||
size_t, unsigned int);
|
||||
int (*volatile_register)(unsigned int);
|
||||
int (*readable_register)(unsigned int);
|
||||
hw_write_t hw_write;
|
||||
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
|
||||
void *reg_cache;
|
||||
short reg_cache_size;
|
||||
short reg_cache_step;
|
||||
|
||||
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
|
||||
unsigned int cache_only:1; /* Suppress writes to hardware */
|
||||
unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
|
||||
unsigned int suspended:1; /* Codec is in suspend PM state */
|
||||
unsigned int probed:1; /* Codec has been probed */
|
||||
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
|
||||
unsigned int ac97_created:1; /* Codec has been created by SoC */
|
||||
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
|
||||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
hw_write_t hw_write;
|
||||
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
|
||||
void *reg_cache;
|
||||
|
||||
/* dapm */
|
||||
u32 pop_time;
|
||||
|
@ -466,10 +459,6 @@ struct snd_soc_codec {
|
|||
enum snd_soc_bias_level suspend_bias_level;
|
||||
struct delayed_work delayed_work;
|
||||
|
||||
/* codec DAI's */
|
||||
struct snd_soc_dai *dai;
|
||||
unsigned int num_dai;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_codec_root;
|
||||
struct dentry *debugfs_reg;
|
||||
|
@ -478,23 +467,40 @@ struct snd_soc_codec {
|
|||
#endif
|
||||
};
|
||||
|
||||
/* codec device */
|
||||
struct snd_soc_codec_device {
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct platform_device *pdev, pm_message_t state);
|
||||
int (*resume)(struct platform_device *pdev);
|
||||
/* codec driver */
|
||||
struct snd_soc_codec_driver {
|
||||
|
||||
/* driver ops */
|
||||
int (*probe)(struct snd_soc_codec *);
|
||||
int (*remove)(struct snd_soc_codec *);
|
||||
int (*suspend)(struct snd_soc_codec *,
|
||||
pm_message_t state);
|
||||
int (*resume)(struct snd_soc_codec *);
|
||||
|
||||
/* codec IO */
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
int (*display_register)(struct snd_soc_codec *, char *,
|
||||
size_t, unsigned int);
|
||||
int (*volatile_register)(unsigned int);
|
||||
int (*readable_register)(unsigned int);
|
||||
short reg_cache_size;
|
||||
short reg_cache_step;
|
||||
short reg_word_size;
|
||||
const void *reg_cache_default;
|
||||
|
||||
/* codec bias level */
|
||||
int (*set_bias_level)(struct snd_soc_codec *,
|
||||
enum snd_soc_bias_level level);
|
||||
};
|
||||
|
||||
/* SoC platform interface */
|
||||
struct snd_soc_platform {
|
||||
char *name;
|
||||
struct list_head list;
|
||||
struct snd_soc_platform_driver {
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
int (*suspend)(struct snd_soc_dai_link *dai_link);
|
||||
int (*resume)(struct snd_soc_dai_link *dai_link);
|
||||
int (*probe)(struct snd_soc_platform *);
|
||||
int (*remove)(struct snd_soc_platform *);
|
||||
int (*suspend)(struct snd_soc_dai *dai);
|
||||
int (*resume)(struct snd_soc_dai *dai);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
|
||||
|
@ -509,23 +515,31 @@ struct snd_soc_platform {
|
|||
struct snd_soc_dai *);
|
||||
|
||||
/* platform stream ops */
|
||||
struct snd_pcm_ops *pcm_ops;
|
||||
struct snd_pcm_ops *ops;
|
||||
};
|
||||
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
struct snd_soc_dai_link {
|
||||
char *name; /* Codec name */
|
||||
char *stream_name; /* Stream name */
|
||||
struct snd_soc_platform {
|
||||
const char *name;
|
||||
int id;
|
||||
struct device *dev;
|
||||
struct snd_soc_platform_driver *driver;
|
||||
|
||||
/* DAI */
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
unsigned int suspended:1; /* platform is suspended */
|
||||
unsigned int probed:1;
|
||||
|
||||
/* machine stream operations */
|
||||
struct snd_soc_ops *ops;
|
||||
struct snd_soc_card *card;
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
};
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_codec *codec);
|
||||
struct snd_soc_dai_link {
|
||||
/* config - must be set by machine driver */
|
||||
const char *name; /* Codec name */
|
||||
const char *stream_name; /* Stream name */
|
||||
const char *codec_name; /* for multi-codec */
|
||||
const char *platform_name; /* for multi-platform */
|
||||
const char *cpu_dai_name;
|
||||
const char *codec_dai_name;
|
||||
|
||||
/* Keep DAI active over suspend */
|
||||
unsigned int ignore_suspend:1;
|
||||
|
@ -533,21 +547,24 @@ struct snd_soc_dai_link {
|
|||
/* Symmetry requirements */
|
||||
unsigned int symmetric_rates:1;
|
||||
|
||||
/* Symmetry data - only valid if symmetry is being enforced */
|
||||
unsigned int rate;
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_pcm_runtime *rtd);
|
||||
|
||||
/* DAI pcm */
|
||||
struct snd_pcm *pcm;
|
||||
/* machine stream operations */
|
||||
struct snd_soc_ops *ops;
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
struct snd_soc_card {
|
||||
char *name;
|
||||
const char *name;
|
||||
struct device *dev;
|
||||
struct snd_card *snd_card;
|
||||
struct module *owner;
|
||||
|
||||
struct list_head list;
|
||||
struct mutex mutex;
|
||||
|
||||
int instantiated;
|
||||
bool instantiated;
|
||||
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
int (*remove)(struct platform_device *pdev);
|
||||
|
@ -568,28 +585,38 @@ struct snd_soc_card {
|
|||
/* CPU <--> Codec DAI links */
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int num_links;
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
int num_rtd;
|
||||
|
||||
struct snd_soc_device *socdev;
|
||||
|
||||
struct snd_soc_codec *codec;
|
||||
|
||||
struct snd_soc_platform *platform;
|
||||
struct delayed_work delayed_work;
|
||||
struct work_struct deferred_resume_work;
|
||||
|
||||
/* lists of probed devices belonging to this card */
|
||||
struct list_head codec_dev_list;
|
||||
struct list_head platform_dev_list;
|
||||
struct list_head dai_dev_list;
|
||||
};
|
||||
|
||||
/* SoC Device - the audio subsystem */
|
||||
struct snd_soc_device {
|
||||
struct device *dev;
|
||||
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
|
||||
struct snd_soc_pcm_runtime {
|
||||
struct device dev;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_codec_device *codec_dev;
|
||||
void *codec_data;
|
||||
};
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
|
||||
/* runtime channel data */
|
||||
struct snd_soc_pcm_runtime {
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct snd_soc_device *socdev;
|
||||
unsigned int complete:1;
|
||||
unsigned int dev_registered:1;
|
||||
|
||||
/* Symmetry data - only valid if symmetry is being enforced */
|
||||
unsigned int rate;
|
||||
long pmdown_time;
|
||||
|
||||
/* runtime devices */
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
|
||||
struct delayed_work delayed_work;
|
||||
};
|
||||
|
||||
/* mixer control */
|
||||
|
@ -615,24 +642,48 @@ struct soc_enum {
|
|||
static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
return codec->read(codec, reg);
|
||||
return codec->driver->read(codec, reg);
|
||||
}
|
||||
|
||||
static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
return codec->write(codec, reg, val);
|
||||
return codec->driver->write(codec, reg, val);
|
||||
}
|
||||
|
||||
/* device driver data */
|
||||
|
||||
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
|
||||
void *data)
|
||||
void *data)
|
||||
{
|
||||
codec->drvdata = data;
|
||||
dev_set_drvdata(codec->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
|
||||
{
|
||||
return codec->drvdata;
|
||||
return dev_get_drvdata(codec->dev);
|
||||
}
|
||||
|
||||
static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
|
||||
void *data)
|
||||
{
|
||||
dev_set_drvdata(platform->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
|
||||
{
|
||||
return dev_get_drvdata(platform->dev);
|
||||
}
|
||||
|
||||
static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
|
||||
void *data)
|
||||
{
|
||||
dev_set_drvdata(&rtd->dev, data);
|
||||
}
|
||||
|
||||
static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
return dev_get_drvdata(&rtd->dev);
|
||||
}
|
||||
|
||||
#include <sound/soc-dai.h>
|
||||
|
|
|
@ -38,9 +38,11 @@
|
|||
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
|
||||
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
|
||||
|
||||
#define TLV_DB_SCALE_MASK 0xffff
|
||||
#define TLV_DB_SCALE_MUTE 0x10000
|
||||
#define TLV_DB_SCALE_ITEM(min, step, mute) \
|
||||
SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
|
||||
(min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
|
||||
(min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
|
||||
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
|
||||
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
|
||||
|
||||
|
|
|
@ -10,8 +10,49 @@
|
|||
#ifndef __TLV320AIC3x_H__
|
||||
#define __TLV320AIC3x_H__
|
||||
|
||||
struct aic3x_pdata {
|
||||
int gpio_reset; /* < 0 if not used */
|
||||
/* GPIO API */
|
||||
enum {
|
||||
AIC3X_GPIO1_FUNC_DISABLED = 0,
|
||||
AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX = 2,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4,
|
||||
AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5,
|
||||
AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6,
|
||||
AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7,
|
||||
AIC3X_GPIO1_FUNC_INPUT = 8,
|
||||
AIC3X_GPIO1_FUNC_OUTPUT = 9,
|
||||
AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10,
|
||||
AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11,
|
||||
AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12,
|
||||
AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13,
|
||||
AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14,
|
||||
AIC3X_GPIO1_FUNC_ALL_IRQ = 16
|
||||
};
|
||||
|
||||
#endif
|
||||
enum {
|
||||
AIC3X_GPIO2_FUNC_DISABLED = 0,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2,
|
||||
AIC3X_GPIO2_FUNC_INPUT = 3,
|
||||
AIC3X_GPIO2_FUNC_OUTPUT = 4,
|
||||
AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5,
|
||||
AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
|
||||
AIC3X_GPIO2_FUNC_ALL_IRQ = 10,
|
||||
AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
|
||||
AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
|
||||
AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13,
|
||||
AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14,
|
||||
AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
|
||||
};
|
||||
|
||||
struct aic3x_setup_data {
|
||||
unsigned int gpio_func[2];
|
||||
};
|
||||
|
||||
struct aic3x_pdata {
|
||||
int gpio_reset; /* < 0 if not used */
|
||||
struct aic3x_setup_data *setup;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* wm8962.h -- WM8962 Soc Audio driver platform data
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _WM8962_PDATA_H
|
||||
#define _WM8962_PDATA_H
|
||||
|
||||
#define WM8962_MAX_GPIO 6
|
||||
|
||||
/* Use to set GPIO default values to zero */
|
||||
#define WM8962_GPIO_SET 0x10000
|
||||
|
||||
struct wm8962_pdata {
|
||||
int gpio_base;
|
||||
u32 gpio_init[WM8962_MAX_GPIO];
|
||||
|
||||
/* Setup for microphone detection, raw value to be written to
|
||||
* R48(0x30) - only microphone related bits will be updated.
|
||||
* Detection may be enabled here for use with signals brought
|
||||
* out on the GPIOs. */
|
||||
u32 mic_cfg;
|
||||
|
||||
bool irq_active_low;
|
||||
|
||||
bool spk_mono; /* Speaker outputs tied together as mono */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -14,9 +14,25 @@
|
|||
struct sh_mobile_lcdc_chan_cfg;
|
||||
struct device;
|
||||
|
||||
/*
|
||||
* flags format
|
||||
*
|
||||
* 0x0000000A
|
||||
*
|
||||
* A: Audio source select
|
||||
*/
|
||||
|
||||
/* Audio source select */
|
||||
#define HDMI_SND_SRC_MASK (0xF << 0)
|
||||
#define HDMI_SND_SRC_I2S (0 << 0) /* default */
|
||||
#define HDMI_SND_SRC_SPDIF (1 << 0)
|
||||
#define HDMI_SND_SRC_DSD (2 << 0)
|
||||
#define HDMI_SND_SRC_HBR (3 << 0)
|
||||
|
||||
struct sh_mobile_hdmi_info {
|
||||
struct sh_mobile_lcdc_chan_cfg *lcd_chan;
|
||||
struct device *lcd_dev;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
|
|||
return -EEXIST;
|
||||
}
|
||||
for (idx = 0; idx < snd_ecards_limit; idx++) {
|
||||
if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
|
||||
goto __exist;
|
||||
if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
|
||||
if (card == snd_cards[idx])
|
||||
goto __ok;
|
||||
else
|
||||
goto __exist;
|
||||
}
|
||||
}
|
||||
strcpy(card->id, buf1);
|
||||
snd_info_card_id_change(card);
|
||||
__ok:
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
|
||||
return count;
|
||||
|
|
|
@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
|
|||
struct snd_mixer_oss_file *fmixer;
|
||||
|
||||
if (file->private_data) {
|
||||
fmixer = (struct snd_mixer_oss_file *) file->private_data;
|
||||
fmixer = file->private_data;
|
||||
module_put(fmixer->card->module);
|
||||
snd_card_file_remove(fmixer->card, file);
|
||||
kfree(fmixer);
|
||||
|
@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
|
|||
|
||||
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
|
||||
return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
|
||||
}
|
||||
|
||||
int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
|
||||
|
@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *left, int *right)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
*left = *right = 100;
|
||||
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
|
||||
|
@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
|||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
}
|
||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL)
|
||||
|
@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||
up_read(&fmixer->card->controls_rwsem);
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
}
|
||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||
|
@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int left, int right)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
|
||||
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
|
||||
|
@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
int left, right;
|
||||
|
||||
left = right = 1;
|
||||
|
@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int *active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
int left, right;
|
||||
|
||||
left = right = 1;
|
||||
|
@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
|
||||
return 0;
|
||||
|
@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
|
|||
struct snd_mixer_oss_slot *pslot,
|
||||
int active)
|
||||
{
|
||||
struct slot *slot = (struct slot *)pslot->private_data;
|
||||
struct slot *slot = pslot->private_data;
|
||||
|
||||
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
|
||||
return 0;
|
||||
|
@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto __unlock;
|
||||
goto __free_only;
|
||||
}
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||
|
@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||
continue;
|
||||
pslot = &mixer->slots[idx];
|
||||
slot = (struct slot *)pslot->private_data;
|
||||
slot = pslot->private_data;
|
||||
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
|
||||
continue;
|
||||
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
|
||||
|
@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
err = 0;
|
||||
__unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
__free_only:
|
||||
kfree(uctl);
|
||||
kfree(uinfo);
|
||||
return err;
|
||||
|
@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||
if (uinfo == NULL || uctl == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto __unlock;
|
||||
goto __free_only;
|
||||
}
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||
|
@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
if (!(mixer->mask_recsrc & (1 << idx)))
|
||||
continue;
|
||||
pslot = &mixer->slots[idx];
|
||||
slot = (struct slot *)pslot->private_data;
|
||||
slot = pslot->private_data;
|
||||
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
|
||||
continue;
|
||||
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
|
||||
|
@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
|||
err = 0;
|
||||
__unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
__free_only:
|
||||
kfree(uctl);
|
||||
kfree(uinfo);
|
||||
return err;
|
||||
|
@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
|
|||
|
||||
static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
|
||||
{
|
||||
struct slot *p = (struct slot *)chn->private_data;
|
||||
struct slot *p = chn->private_data;
|
||||
if (p) {
|
||||
if (p->allocated && p->assigned) {
|
||||
kfree(p->assigned->name);
|
||||
|
|
|
@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
|
|||
static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
|
||||
buffer);
|
||||
snd_pcm_proc_info_read(entry->private_data, buffer);
|
||||
}
|
||||
|
||||
static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
|
||||
|
|
|
@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
/* delta = "expected next hw_ptr" for in_interrupt != 0 */
|
||||
delta = runtime->hw_ptr_interrupt + runtime->period_size;
|
||||
if (delta > new_hw_ptr) {
|
||||
hw_base += runtime->buffer_size;
|
||||
if (hw_base >= runtime->boundary)
|
||||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
goto __delta;
|
||||
/* check for double acknowledged interrupts */
|
||||
hdelta = jiffies - runtime->hw_ptr_jiffies;
|
||||
if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
|
||||
hw_base += runtime->buffer_size;
|
||||
if (hw_base >= runtime->boundary)
|
||||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
goto __delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* new_hw_ptr might be lower than old_hw_ptr in case when */
|
||||
|
|
|
@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
|
|||
|
||||
#ifdef RULES_DEBUG
|
||||
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
|
||||
char *snd_pcm_hw_param_names[] = {
|
||||
static const char * const snd_pcm_hw_param_names[] = {
|
||||
HW_PARAM(ACCESS),
|
||||
HW_PARAM(FORMAT),
|
||||
HW_PARAM(SUBFORMAT),
|
||||
|
@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
|
|||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_trigger_tstamp(substream);
|
||||
runtime->hw_ptr_jiffies = jiffies;
|
||||
runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
|
||||
runtime->rate;
|
||||
runtime->status->state = state;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
runtime->silence_size > 0)
|
||||
|
|
|
@ -74,6 +74,25 @@ config SND_DUMMY
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-dummy.
|
||||
|
||||
config SND_ALOOP
|
||||
tristate "Generic loopback driver (PCM)"
|
||||
select SND_PCM
|
||||
help
|
||||
Say 'Y' or 'M' to include support for the PCM loopback device.
|
||||
This module returns played samples back to the user space using
|
||||
the standard ALSA PCM device. The devices are routed 0->1 and
|
||||
1->0, where first number is the playback PCM device and second
|
||||
number is the capture device. Module creates two PCM devices and
|
||||
configured number of substreams (see the pcm_substreams module
|
||||
parameter).
|
||||
|
||||
The looback device allow time sychronization with an external
|
||||
timing source using the time shift universal control (+-20%
|
||||
of system time).
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-aloop.
|
||||
|
||||
config SND_VIRMIDI
|
||||
tristate "Virtual MIDI soundcard"
|
||||
depends on SND_SEQUENCER
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
|
||||
snd-dummy-objs := dummy.o
|
||||
snd-aloop-objs := aloop.o
|
||||
snd-mtpav-objs := mtpav.o
|
||||
snd-mts64-objs := mts64.o
|
||||
snd-portman2x4-objs := portman2x4.o
|
||||
|
@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
|
|||
|
||||
# Toplevel Module Dependency
|
||||
obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
|
||||
obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
|
||||
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
|
||||
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
|
||||
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
|
|||
sizeof(struct snd_card_virmidi), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
vmidi = (struct snd_card_virmidi *)card->private_data;
|
||||
vmidi = card->private_data;
|
||||
vmidi->card = card;
|
||||
|
||||
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
|
||||
|
|
|
@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
|
|||
static void proc_regs_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
|
||||
struct snd_akm4xxx *ak = entry->private_data;
|
||||
int reg, val, chip;
|
||||
for (chip = 0; chip < ak->num_chips; chip++) {
|
||||
for (reg = 0; reg < ak->total_regs; reg++) {
|
||||
|
|
|
@ -77,6 +77,32 @@ config SND_ALS100
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-als100.
|
||||
|
||||
config SND_AZT1605
|
||||
tristate "Aztech AZT1605 Driver"
|
||||
depends on SND
|
||||
select SND_WSS_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_OPL3_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy cards
|
||||
based on the AZT1605 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-azt1605.
|
||||
|
||||
config SND_AZT2316
|
||||
tristate "Aztech AZT2316 Driver"
|
||||
depends on SND
|
||||
select SND_WSS_LIB
|
||||
select SND_MPU401_UART
|
||||
select SND_OPL3_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy cards
|
||||
based on the AZT2316 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-azt2316.
|
||||
|
||||
config SND_AZT2320
|
||||
tristate "Aztech Systems AZT2320"
|
||||
depends on PNP
|
||||
|
@ -351,16 +377,6 @@ config SND_SB16_CSP
|
|||
coprocessor can do variable tasks like various compression and
|
||||
decompression algorithms.
|
||||
|
||||
config SND_SGALAXY
|
||||
tristate "Aztech Sound Galaxy"
|
||||
select SND_WSS_LIB
|
||||
help
|
||||
Say Y here to include support for Aztech Sound Galaxy
|
||||
soundcards.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-sgalaxy.
|
||||
|
||||
config SND_SSCAPE
|
||||
tristate "Ensoniq SoundScape driver"
|
||||
select SND_MPU401_UART
|
||||
|
|
|
@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
|
|||
snd-es18xx-objs := es18xx.o
|
||||
snd-opl3sa2-objs := opl3sa2.o
|
||||
snd-sc6000-objs := sc6000.o
|
||||
snd-sgalaxy-objs := sgalaxy.o
|
||||
snd-sscape-objs := sscape.o
|
||||
|
||||
# Toplevel Module Dependency
|
||||
|
@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
|
|||
obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
|
||||
obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
|
||||
obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
|
||||
obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
|
||||
obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
|
||||
|
||||
obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
|
||||
obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
|
||||
sb/ wavefront/ wss/
|
||||
|
|
|
@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
|
|||
sizeof(struct snd_card_ad1816a), &card);
|
||||
if (error < 0)
|
||||
return error;
|
||||
acard = (struct snd_card_ad1816a *)card->private_data;
|
||||
acard = card->private_data;
|
||||
|
||||
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
|
||||
snd_card_free(card);
|
||||
|
|
|
@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
|
|||
sizeof(struct snd_card_azt2320), &card);
|
||||
if (error < 0)
|
||||
return error;
|
||||
acard = (struct snd_card_azt2320 *)card->private_data;
|
||||
acard = card->private_data;
|
||||
|
||||
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
|
||||
snd_card_free(card);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Makefile for ALSA
|
||||
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
|
||||
#
|
||||
|
||||
snd-azt1605-objs := azt1605.o
|
||||
snd-azt2316-objs := azt2316.o
|
||||
|
||||
obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
|
||||
obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Aztech AZT1605 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define AZT1605
|
||||
|
||||
#define CRD_NAME "Aztech AZT1605"
|
||||
#define DRV_NAME "AZT1605"
|
||||
#define DEV_NAME "azt1605"
|
||||
|
||||
#define GALAXY_DSP_MAJOR 2
|
||||
#define GALAXY_DSP_MINOR 1
|
||||
|
||||
#define GALAXY_CONFIG_SIZE 3
|
||||
|
||||
/*
|
||||
* 24-bit config register
|
||||
*/
|
||||
|
||||
#define GALAXY_CONFIG_SBA_220 (0 << 0)
|
||||
#define GALAXY_CONFIG_SBA_240 (1 << 0)
|
||||
#define GALAXY_CONFIG_SBA_260 (2 << 0)
|
||||
#define GALAXY_CONFIG_SBA_280 (3 << 0)
|
||||
#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
|
||||
|
||||
#define GALAXY_CONFIG_MPUA_300 (0 << 2)
|
||||
#define GALAXY_CONFIG_MPUA_330 (1 << 2)
|
||||
|
||||
#define GALAXY_CONFIG_MPU_ENABLE (1 << 3)
|
||||
|
||||
#define GALAXY_CONFIG_GAME_ENABLE (1 << 4)
|
||||
|
||||
#define GALAXY_CONFIG_CD_PANASONIC (1 << 5)
|
||||
#define GALAXY_CONFIG_CD_MITSUMI (1 << 6)
|
||||
#define GALAXY_CONFIG_CD_MASK (\
|
||||
GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
|
||||
|
||||
#define GALAXY_CONFIG_UNUSED (1 << 7)
|
||||
#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED
|
||||
|
||||
#define GALAXY_CONFIG_SBIRQ_2 (1 << 8)
|
||||
#define GALAXY_CONFIG_SBIRQ_3 (1 << 9)
|
||||
#define GALAXY_CONFIG_SBIRQ_5 (1 << 10)
|
||||
#define GALAXY_CONFIG_SBIRQ_7 (1 << 11)
|
||||
|
||||
#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12)
|
||||
#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13)
|
||||
#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14)
|
||||
#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15)
|
||||
|
||||
#define GALAXY_CONFIG_WSSA_530 (0 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_604 (1 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_E80 (2 << 16)
|
||||
#define GALAXY_CONFIG_WSSA_F40 (3 << 16)
|
||||
|
||||
#define GALAXY_CONFIG_WSS_ENABLE (1 << 18)
|
||||
|
||||
#define GALAXY_CONFIG_CDIRQ_11 (1 << 19)
|
||||
#define GALAXY_CONFIG_CDIRQ_12 (1 << 20)
|
||||
#define GALAXY_CONFIG_CDIRQ_15 (1 << 21)
|
||||
#define GALAXY_CONFIG_CDIRQ_MASK (\
|
||||
GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
|
||||
GALAXY_CONFIG_CDIRQ_15)
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_0 (1 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_1 (2 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_3 (3 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3
|
||||
|
||||
#define GALAXY_CONFIG_MASK (\
|
||||
GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
|
||||
GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
|
||||
GALAXY_CONFIG_CDDMA_MASK)
|
||||
|
||||
#include "galaxy.c"
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Aztech AZT2316 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define AZT2316
|
||||
|
||||
#define CRD_NAME "Aztech AZT2316"
|
||||
#define DRV_NAME "AZT2316"
|
||||
#define DEV_NAME "azt2316"
|
||||
|
||||
#define GALAXY_DSP_MAJOR 3
|
||||
#define GALAXY_DSP_MINOR 1
|
||||
|
||||
#define GALAXY_CONFIG_SIZE 4
|
||||
|
||||
/*
|
||||
* 32-bit config register
|
||||
*/
|
||||
|
||||
#define GALAXY_CONFIG_SBA_220 (0 << 0)
|
||||
#define GALAXY_CONFIG_SBA_240 (1 << 0)
|
||||
#define GALAXY_CONFIG_SBA_260 (2 << 0)
|
||||
#define GALAXY_CONFIG_SBA_280 (3 << 0)
|
||||
#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280
|
||||
|
||||
#define GALAXY_CONFIG_SBIRQ_2 (1 << 2)
|
||||
#define GALAXY_CONFIG_SBIRQ_5 (1 << 3)
|
||||
#define GALAXY_CONFIG_SBIRQ_7 (1 << 4)
|
||||
#define GALAXY_CONFIG_SBIRQ_10 (1 << 5)
|
||||
|
||||
#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_0 (1 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_1 (2 << 6)
|
||||
#define GALAXY_CONFIG_SBDMA_3 (3 << 6)
|
||||
|
||||
#define GALAXY_CONFIG_WSSA_530 (0 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_604 (1 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_E80 (2 << 8)
|
||||
#define GALAXY_CONFIG_WSSA_F40 (3 << 8)
|
||||
|
||||
#define GALAXY_CONFIG_WSS_ENABLE (1 << 10)
|
||||
|
||||
#define GALAXY_CONFIG_GAME_ENABLE (1 << 11)
|
||||
|
||||
#define GALAXY_CONFIG_MPUA_300 (0 << 12)
|
||||
#define GALAXY_CONFIG_MPUA_330 (1 << 12)
|
||||
|
||||
#define GALAXY_CONFIG_MPU_ENABLE (1 << 13)
|
||||
|
||||
#define GALAXY_CONFIG_CDA_310 (0 << 14)
|
||||
#define GALAXY_CONFIG_CDA_320 (1 << 14)
|
||||
#define GALAXY_CONFIG_CDA_340 (2 << 14)
|
||||
#define GALAXY_CONFIG_CDA_350 (3 << 14)
|
||||
#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350
|
||||
|
||||
#define GALAXY_CONFIG_CD_DISABLE (0 << 16)
|
||||
#define GALAXY_CONFIG_CD_PANASONIC (1 << 16)
|
||||
#define GALAXY_CONFIG_CD_SONY (2 << 16)
|
||||
#define GALAXY_CONFIG_CD_MITSUMI (3 << 16)
|
||||
#define GALAXY_CONFIG_CD_AZTECH (4 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16)
|
||||
#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16)
|
||||
#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_0 (1 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_1 (2 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_3 (3 << 20)
|
||||
#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3
|
||||
|
||||
#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_5 (1 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_6 (2 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_7 (3 << 22)
|
||||
#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7
|
||||
|
||||
#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24)
|
||||
#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25)
|
||||
#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26)
|
||||
#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27)
|
||||
|
||||
#define GALAXY_CONFIG_CDIRQ_5 (1 << 28)
|
||||
#define GALAXY_CONFIG_CDIRQ_11 (1 << 29)
|
||||
#define GALAXY_CONFIG_CDIRQ_12 (1 << 30)
|
||||
#define GALAXY_CONFIG_CDIRQ_15 (1 << 31)
|
||||
#define GALAXY_CONFIG_CDIRQ_MASK (\
|
||||
GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
|
||||
GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
|
||||
|
||||
#define GALAXY_CONFIG_MASK (\
|
||||
GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
|
||||
GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
|
||||
GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
|
||||
|
||||
#include "galaxy.c"
|
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
* Aztech AZT1605/AZT2316 Driver
|
||||
* Copyright (C) 2007,2010 Rene Herman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/mpu401.h>
|
||||
#include <sound/opl3.h>
|
||||
|
||||
MODULE_DESCRIPTION(CRD_NAME);
|
||||
MODULE_AUTHOR("Rene Herman");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
|
||||
|
||||
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
|
||||
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
|
||||
|
||||
module_param_array(port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
|
||||
module_param_array(wss_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
|
||||
module_param_array(mpu_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
|
||||
module_param_array(fm_port, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
|
||||
module_param_array(irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
|
||||
module_param_array(mpu_irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
|
||||
module_param_array(dma1, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
|
||||
module_param_array(dma2, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
|
||||
|
||||
/*
|
||||
* Generic SB DSP support routines
|
||||
*/
|
||||
|
||||
#define DSP_PORT_RESET 0x6
|
||||
#define DSP_PORT_READ 0xa
|
||||
#define DSP_PORT_COMMAND 0xc
|
||||
#define DSP_PORT_STATUS 0xc
|
||||
#define DSP_PORT_DATA_AVAIL 0xe
|
||||
|
||||
#define DSP_SIGNATURE 0xaa
|
||||
|
||||
#define DSP_COMMAND_GET_VERSION 0xe1
|
||||
|
||||
static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
|
||||
{
|
||||
int loops = 1000;
|
||||
|
||||
while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
|
||||
if (!loops--)
|
||||
return -EIO;
|
||||
cpu_relax();
|
||||
}
|
||||
*val = ioread8(port + DSP_PORT_READ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_reset(void __iomem *port)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
iowrite8(1, port + DSP_PORT_RESET);
|
||||
udelay(10);
|
||||
iowrite8(0, port + DSP_PORT_RESET);
|
||||
|
||||
if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_command(void __iomem *port, u8 cmd)
|
||||
{
|
||||
int loops = 1000;
|
||||
|
||||
while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
|
||||
if (!loops--)
|
||||
return -EIO;
|
||||
cpu_relax();
|
||||
}
|
||||
iowrite8(cmd, port + DSP_PORT_COMMAND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp_command(port, DSP_COMMAND_GET_VERSION);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(port, major);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(port, minor);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic WSS support routines
|
||||
*/
|
||||
|
||||
#define WSS_CONFIG_DMA_0 (1 << 0)
|
||||
#define WSS_CONFIG_DMA_1 (2 << 0)
|
||||
#define WSS_CONFIG_DMA_3 (3 << 0)
|
||||
#define WSS_CONFIG_DUPLEX (1 << 2)
|
||||
#define WSS_CONFIG_IRQ_7 (1 << 3)
|
||||
#define WSS_CONFIG_IRQ_9 (2 << 3)
|
||||
#define WSS_CONFIG_IRQ_10 (3 << 3)
|
||||
#define WSS_CONFIG_IRQ_11 (4 << 3)
|
||||
|
||||
#define WSS_PORT_CONFIG 0
|
||||
#define WSS_PORT_SIGNATURE 3
|
||||
|
||||
#define WSS_SIGNATURE 4
|
||||
|
||||
static int __devinit wss_detect(void __iomem *wss_port)
|
||||
{
|
||||
if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wss_set_config(void __iomem *wss_port, u8 wss_config)
|
||||
{
|
||||
iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Aztech Sound Galaxy specifics
|
||||
*/
|
||||
|
||||
#define GALAXY_PORT_CONFIG 1024
|
||||
#define CONFIG_PORT_SET 4
|
||||
|
||||
#define DSP_COMMAND_GALAXY_8 8
|
||||
#define GALAXY_COMMAND_GET_TYPE 5
|
||||
|
||||
#define DSP_COMMAND_GALAXY_9 9
|
||||
#define GALAXY_COMMAND_WSSMODE 0
|
||||
#define GALAXY_COMMAND_SB8MODE 1
|
||||
|
||||
#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
|
||||
#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
|
||||
|
||||
struct snd_galaxy {
|
||||
void __iomem *port;
|
||||
void __iomem *config_port;
|
||||
void __iomem *wss_port;
|
||||
u32 config;
|
||||
struct resource *res_port;
|
||||
struct resource *res_config_port;
|
||||
struct resource *res_wss_port;
|
||||
};
|
||||
|
||||
static u32 config[SNDRV_CARDS];
|
||||
static u8 wss_config[SNDRV_CARDS];
|
||||
|
||||
static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
|
||||
{
|
||||
if (!enable[n])
|
||||
return 0;
|
||||
|
||||
switch (port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_err(dev, "please specify port\n");
|
||||
return 0;
|
||||
case 0x220:
|
||||
config[n] |= GALAXY_CONFIG_SBA_220;
|
||||
break;
|
||||
case 0x240:
|
||||
config[n] |= GALAXY_CONFIG_SBA_240;
|
||||
break;
|
||||
case 0x260:
|
||||
config[n] |= GALAXY_CONFIG_SBA_260;
|
||||
break;
|
||||
case 0x280:
|
||||
config[n] |= GALAXY_CONFIG_SBA_280;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid port %#lx\n", port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (wss_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_err(dev, "please specify wss_port\n");
|
||||
return 0;
|
||||
case 0x530:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
|
||||
break;
|
||||
case 0x604:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
|
||||
break;
|
||||
case 0xe80:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
|
||||
break;
|
||||
case 0xf40:
|
||||
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (irq[n]) {
|
||||
case SNDRV_AUTO_IRQ:
|
||||
dev_err(dev, "please specify irq\n");
|
||||
return 0;
|
||||
case 7:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_7;
|
||||
break;
|
||||
case 2:
|
||||
irq[n] = 9;
|
||||
case 9:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_9;
|
||||
break;
|
||||
case 10:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_10;
|
||||
break;
|
||||
case 11:
|
||||
wss_config[n] |= WSS_CONFIG_IRQ_11;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid IRQ %d\n", irq[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dma1[n]) {
|
||||
case SNDRV_AUTO_DMA:
|
||||
dev_err(dev, "please specify dma1\n");
|
||||
return 0;
|
||||
case 0:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_0;
|
||||
break;
|
||||
case 1:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_1;
|
||||
break;
|
||||
case 3:
|
||||
wss_config[n] |= WSS_CONFIG_DMA_3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
|
||||
dma2[n] = -1;
|
||||
goto mpu;
|
||||
}
|
||||
|
||||
wss_config[n] |= WSS_CONFIG_DUPLEX;
|
||||
switch (dma2[n]) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
if (dma1[n] == 0)
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpu:
|
||||
switch (mpu_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
|
||||
mpu_port[n] = -1;
|
||||
goto fm;
|
||||
case 0x300:
|
||||
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
|
||||
break;
|
||||
case 0x330:
|
||||
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (mpu_irq[n]) {
|
||||
case SNDRV_AUTO_IRQ:
|
||||
dev_warn(dev, "mpu_irq not specified: using polling mode\n");
|
||||
mpu_irq[n] = -1;
|
||||
break;
|
||||
case 2:
|
||||
mpu_irq[n] = 9;
|
||||
case 9:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_2;
|
||||
break;
|
||||
#ifdef AZT1605
|
||||
case 3:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_3;
|
||||
break;
|
||||
#endif
|
||||
case 5:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_5;
|
||||
break;
|
||||
case 7:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_7;
|
||||
break;
|
||||
#ifdef AZT2316
|
||||
case 10:
|
||||
config[n] |= GALAXY_CONFIG_MPUIRQ_10;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mpu_irq[n] == irq[n]) {
|
||||
dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fm:
|
||||
switch (fm_port[n]) {
|
||||
case SNDRV_AUTO_PORT:
|
||||
dev_warn(dev, "fm_port not specified: not using OPL3\n");
|
||||
fm_port[n] = -1;
|
||||
break;
|
||||
case 0x388:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
config[n] |= GALAXY_CONFIG_GAME_ENABLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
|
||||
{
|
||||
u8 major;
|
||||
u8 minor;
|
||||
int err;
|
||||
|
||||
err = dsp_reset(galaxy->port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_version(galaxy->port, &major, &minor);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
|
||||
return -ENODEV;
|
||||
|
||||
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_get_byte(galaxy->port, type);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = dsp_command(galaxy->port, mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#ifdef AZT1605
|
||||
/*
|
||||
* Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
|
||||
*/
|
||||
err = dsp_reset(galaxy->port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
|
||||
{
|
||||
u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
|
||||
int i;
|
||||
|
||||
iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
|
||||
for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
|
||||
iowrite8(config, galaxy->config_port + i);
|
||||
config >>= 8;
|
||||
}
|
||||
iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = GALAXY_CONFIG_SIZE; i; i--) {
|
||||
u8 tmp = ioread8(galaxy->config_port + i - 1);
|
||||
galaxy->config = (galaxy->config << 8) | tmp;
|
||||
}
|
||||
config |= galaxy->config & GALAXY_CONFIG_MASK;
|
||||
galaxy_set_config(galaxy, config);
|
||||
}
|
||||
|
||||
static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = wss_detect(galaxy->wss_port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
wss_set_config(galaxy->wss_port, wss_config);
|
||||
|
||||
err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_galaxy_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_galaxy *galaxy = card->private_data;
|
||||
|
||||
if (galaxy->wss_port) {
|
||||
wss_set_config(galaxy->wss_port, 0);
|
||||
ioport_unmap(galaxy->wss_port);
|
||||
release_and_free_resource(galaxy->res_wss_port);
|
||||
}
|
||||
if (galaxy->config_port) {
|
||||
galaxy_set_config(galaxy, galaxy->config);
|
||||
ioport_unmap(galaxy->config_port);
|
||||
release_and_free_resource(galaxy->res_config_port);
|
||||
}
|
||||
if (galaxy->port) {
|
||||
ioport_unmap(galaxy->port);
|
||||
release_and_free_resource(galaxy->res_port);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
|
||||
{
|
||||
struct snd_galaxy *galaxy;
|
||||
struct snd_wss *chip;
|
||||
struct snd_card *card;
|
||||
u8 type;
|
||||
int err;
|
||||
|
||||
err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
|
||||
&card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
snd_card_set_dev(card, dev);
|
||||
|
||||
card->private_free = snd_galaxy_free;
|
||||
galaxy = card->private_data;
|
||||
|
||||
galaxy->res_port = request_region(port[n], 16, DRV_NAME);
|
||||
if (!galaxy->res_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
|
||||
port[n] + 15);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->port = ioport_map(port[n], 16);
|
||||
|
||||
err = galaxy_init(galaxy, &type);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
|
||||
goto error;
|
||||
}
|
||||
dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
|
||||
|
||||
galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
|
||||
16, DRV_NAME);
|
||||
if (!galaxy->res_config_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n",
|
||||
port[n] + GALAXY_PORT_CONFIG,
|
||||
port[n] + GALAXY_PORT_CONFIG + 15);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
|
||||
|
||||
galaxy_config(galaxy, config[n]);
|
||||
|
||||
galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
|
||||
if (!galaxy->res_wss_port) {
|
||||
dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
|
||||
wss_port[n] + 3);
|
||||
err = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
galaxy->wss_port = ioport_map(wss_port[n], 4);
|
||||
|
||||
err = galaxy_wss_config(galaxy, wss_config[n]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "could not configure WSS\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
strcpy(card->driver, DRV_NAME);
|
||||
strcpy(card->shortname, DRV_NAME);
|
||||
sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
|
||||
card->shortname, port[n], wss_port[n], irq[n], dma1[n],
|
||||
dma2[n]);
|
||||
|
||||
err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
|
||||
dma2[n], WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_pcm(chip, 0, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_mixer(chip);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_wss_timer(chip, 0, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (mpu_port[n] >= 0) {
|
||||
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
mpu_port[n], 0, mpu_irq[n],
|
||||
IRQF_DISABLED, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fm_port[n] >= 0) {
|
||||
struct snd_opl3 *opl3;
|
||||
|
||||
err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
|
||||
OPL3_HW_AUTO, 0, &opl3);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
|
||||
goto error;
|
||||
}
|
||||
err = snd_opl3_timer_new(opl3, 1, 2);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
dev_set_drvdata(dev, card);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
|
||||
{
|
||||
snd_card_free(dev_get_drvdata(dev));
|
||||
dev_set_drvdata(dev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct isa_driver snd_galaxy_driver = {
|
||||
.match = snd_galaxy_match,
|
||||
.probe = snd_galaxy_probe,
|
||||
.remove = __devexit_p(snd_galaxy_remove),
|
||||
|
||||
.driver = {
|
||||
.name = DEV_NAME
|
||||
}
|
||||
};
|
||||
|
||||
static int __init alsa_card_galaxy_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_galaxy_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_galaxy_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_galaxy_init);
|
||||
module_exit(alsa_card_galaxy_exit);
|
|
@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
|
|||
|
||||
static void snd_gusmax_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
|
||||
struct snd_gusmax *maxcard = card->private_data;
|
||||
|
||||
if (maxcard == NULL)
|
||||
return;
|
||||
|
@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
|
|||
if (err < 0)
|
||||
return err;
|
||||
card->private_free = snd_gusmax_free;
|
||||
maxcard = (struct snd_gusmax *)card->private_data;
|
||||
maxcard = card->private_data;
|
||||
maxcard->card = card;
|
||||
maxcard->irq = -1;
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
|
|||
|
||||
static void snd_sb8_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
|
||||
struct snd_sb8 *acard = card->private_data;
|
||||
|
||||
if (acard == NULL)
|
||||
return;
|
||||
|
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* Driver for Aztech Sound Galaxy cards
|
||||
* Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
|
||||
*
|
||||
* I don't have documentation for this card, I based this driver on the
|
||||
* driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/dma.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/sb.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/control.h>
|
||||
#define SNDRV_LEGACY_FIND_FREE_IRQ
|
||||
#define SNDRV_LEGACY_FIND_FREE_DMA
|
||||
#include <sound/initval.h>
|
||||
|
||||
MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
|
||||
MODULE_DESCRIPTION("Aztech Sound Galaxy");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
|
||||
static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
|
||||
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
|
||||
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
|
||||
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
|
||||
module_param_array(id, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
|
||||
module_param_array(sbport, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
|
||||
module_param_array(wssport, long, NULL, 0444);
|
||||
MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
|
||||
module_param_array(irq, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
|
||||
module_param_array(dma1, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
|
||||
|
||||
#define SGALAXY_AUXC_LEFT 18
|
||||
#define SGALAXY_AUXC_RIGHT 19
|
||||
|
||||
#define PFX "sgalaxy: "
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
|
||||
|
||||
/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
|
||||
/* short time we actually need it.. */
|
||||
|
||||
static int snd_sgalaxy_sbdsp_reset(unsigned long port)
|
||||
{
|
||||
int i;
|
||||
|
||||
outb(1, SBP1(port, RESET));
|
||||
udelay(10);
|
||||
outb(0, SBP1(port, RESET));
|
||||
udelay(30);
|
||||
for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
|
||||
if (inb(SBP1(port, READ)) != 0xaa) {
|
||||
snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
|
||||
unsigned char val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 10000; i; i--)
|
||||
if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
|
||||
outb(val, SBP1(port, COMMAND));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
|
||||
{
|
||||
static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1,
|
||||
0x10, 0x18, 0x20, -1, -1, -1, -1};
|
||||
static int dma_bits[] = {1, 2, 0, 3};
|
||||
int tmp, tmp1;
|
||||
|
||||
if ((tmp = inb(port + 3)) == 0xff)
|
||||
{
|
||||
snd_printdd("I/O address dead (0x%lx)\n", port);
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
snd_printdd("WSS signature = 0x%x\n", tmp);
|
||||
#endif
|
||||
|
||||
if ((tmp & 0x3f) != 0x04 &&
|
||||
(tmp & 0x3f) != 0x0f &&
|
||||
(tmp & 0x3f) != 0x00) {
|
||||
snd_printdd("No WSS signature detected on port 0x%lx\n",
|
||||
port + 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
|
||||
#endif
|
||||
|
||||
/* initialize IRQ for WSS codec */
|
||||
tmp = interrupt_bits[irq % 16];
|
||||
if (tmp < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
|
||||
snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
outb(tmp | 0x40, port);
|
||||
tmp1 = dma_bits[dma % 4];
|
||||
outb(tmp | tmp1, port);
|
||||
|
||||
free_irq(irq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
|
||||
{
|
||||
#if 0
|
||||
snd_printdd(PFX "switching to WSS mode\n");
|
||||
#endif
|
||||
|
||||
/* switch to WSS mode */
|
||||
snd_sgalaxy_sbdsp_reset(sbport[dev]);
|
||||
|
||||
snd_sgalaxy_sbdsp_command(sbport[dev], 9);
|
||||
snd_sgalaxy_sbdsp_command(sbport[dev], 0);
|
||||
|
||||
udelay(400);
|
||||
return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Playback Volume", 0,
|
||||
SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
|
||||
};
|
||||
|
||||
static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
struct snd_ctl_elem_id id1, id2;
|
||||
unsigned int idx;
|
||||
int err;
|
||||
|
||||
memset(&id1, 0, sizeof(id1));
|
||||
memset(&id2, 0, sizeof(id2));
|
||||
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
/* reassign AUX0 to LINE */
|
||||
strcpy(id1.name, "Aux Playback Switch");
|
||||
strcpy(id2.name, "Line Playback Switch");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
strcpy(id1.name, "Aux Playback Volume");
|
||||
strcpy(id2.name, "Line Playback Volume");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
/* reassign AUX1 to FM */
|
||||
strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
|
||||
strcpy(id2.name, "FM Playback Switch");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
strcpy(id1.name, "Aux Playback Volume");
|
||||
strcpy(id2.name, "FM Playback Volume");
|
||||
if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
|
||||
return err;
|
||||
/* build AUX2 input */
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
if (!enable[dev])
|
||||
return 0;
|
||||
if (sbport[dev] == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR PFX "specify SB port\n");
|
||||
return 0;
|
||||
}
|
||||
if (wssport[dev] == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR PFX "specify WSS port\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
static int possible_irqs[] = {7, 9, 10, 11, -1};
|
||||
static int possible_dmas[] = {1, 3, 0, -1};
|
||||
int err, xirq, xdma1;
|
||||
struct snd_card *card;
|
||||
struct snd_wss *chip;
|
||||
|
||||
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
xirq = irq[dev];
|
||||
if (xirq == SNDRV_AUTO_IRQ) {
|
||||
if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
|
||||
snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
|
||||
err = -EBUSY;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
xdma1 = dma1[dev];
|
||||
if (xdma1 == SNDRV_AUTO_DMA) {
|
||||
if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
|
||||
snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
|
||||
err = -EBUSY;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
|
||||
goto _err;
|
||||
|
||||
err = snd_wss_create(card, wssport[dev] + 4, -1,
|
||||
xirq, xdma1, -1,
|
||||
WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
goto _err;
|
||||
card->private_data = chip;
|
||||
|
||||
err = snd_wss_pcm(chip, 0, NULL);
|
||||
if (err < 0) {
|
||||
snd_printdd(PFX "error creating new WSS PCM device\n");
|
||||
goto _err;
|
||||
}
|
||||
err = snd_wss_mixer(chip);
|
||||
if (err < 0) {
|
||||
snd_printdd(PFX "error creating new WSS mixer\n");
|
||||
goto _err;
|
||||
}
|
||||
if ((err = snd_sgalaxy_mixer(chip)) < 0) {
|
||||
snd_printdd(PFX "the mixer rewrite failed\n");
|
||||
goto _err;
|
||||
}
|
||||
|
||||
strcpy(card->driver, "Sound Galaxy");
|
||||
strcpy(card->shortname, "Sound Galaxy");
|
||||
sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
|
||||
wssport[dev], xirq, xdma1);
|
||||
|
||||
snd_card_set_dev(card, devptr);
|
||||
|
||||
if ((err = snd_card_register(card)) < 0)
|
||||
goto _err;
|
||||
|
||||
dev_set_drvdata(devptr, card);
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
|
||||
{
|
||||
snd_card_free(dev_get_drvdata(devptr));
|
||||
dev_set_drvdata(devptr, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_wss *chip = card->private_data;
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
chip->suspend(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct snd_wss *chip = card->private_data;
|
||||
|
||||
chip->resume(chip);
|
||||
snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
|
||||
snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEV_NAME "sgalaxy"
|
||||
|
||||
static struct isa_driver snd_sgalaxy_driver = {
|
||||
.match = snd_sgalaxy_match,
|
||||
.probe = snd_sgalaxy_probe,
|
||||
.remove = __devexit_p(snd_sgalaxy_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_sgalaxy_suspend,
|
||||
.resume = snd_sgalaxy_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DEV_NAME
|
||||
},
|
||||
};
|
||||
|
||||
static int __init alsa_card_sgalaxy_init(void)
|
||||
{
|
||||
return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
|
||||
}
|
||||
|
||||
static void __exit alsa_card_sgalaxy_exit(void)
|
||||
{
|
||||
isa_unregister_driver(&snd_sgalaxy_driver);
|
||||
}
|
||||
|
||||
module_init(alsa_card_sgalaxy_init)
|
||||
module_exit(alsa_card_sgalaxy_exit)
|
|
@ -545,11 +545,3 @@ config SOUND_KAHLUA
|
|||
|
||||
endif # SOUND_OSS
|
||||
|
||||
config SOUND_SH_DAC_AUDIO
|
||||
tristate "SuperH DAC audio support"
|
||||
depends on CPU_SH3 && HIGH_RES_TIMERS
|
||||
|
||||
config SOUND_SH_DAC_AUDIO_CHANNEL
|
||||
int "DAC channel"
|
||||
default "1"
|
||||
depends on SOUND_SH_DAC_AUDIO
|
||||
|
|
|
@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o
|
|||
|
||||
# Please leave it as is, cause the link order is significant !
|
||||
|
||||
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
|
||||
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
|
||||
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
|
||||
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include <linux/sound.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -77,6 +76,7 @@
|
|||
/* Boot options
|
||||
* 0 = no VRA, 1 = use VRA if codec supports it
|
||||
*/
|
||||
static DEFINE_MUTEX(au1550_ac97_mutex);
|
||||
static int vra = 1;
|
||||
module_param(vra, bool, 0);
|
||||
MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
|
||||
|
@ -171,7 +171,7 @@ au1550_delay(int msec)
|
|||
static u16
|
||||
rdcodec(struct ac97_codec *codec, u8 addr)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)codec->private_data;
|
||||
struct au1550_state *s = codec->private_data;
|
||||
unsigned long flags;
|
||||
u32 cmd, val;
|
||||
u16 data;
|
||||
|
@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
|
|||
static void
|
||||
wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)codec->private_data;
|
||||
struct au1550_state *s = codec->private_data;
|
||||
unsigned long flags;
|
||||
u32 cmd, val;
|
||||
int i;
|
||||
|
@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
|
|||
static int
|
||||
au1550_open_mixdev(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
file->private_data = &au1550_state;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
|
|||
static long
|
||||
au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct ac97_codec *codec = s->codec;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
ret = mixdev_ioctl(codec, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
|
|||
static ssize_t
|
||||
au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db = &s->dma_adc;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
ssize_t ret;
|
||||
|
@ -1111,7 +1111,7 @@ out2:
|
|||
static ssize_t
|
||||
au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db = &s->dma_dac;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
ssize_t ret = 0;
|
||||
|
@ -1211,7 +1211,7 @@ out2:
|
|||
static unsigned int
|
||||
au1550_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
unsigned long flags;
|
||||
unsigned int mask = 0;
|
||||
|
||||
|
@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
|
|||
static int
|
||||
au1550_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
struct dmabuf *db;
|
||||
unsigned long size;
|
||||
int ret = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
mutex_lock(&s->sem);
|
||||
if (vma->vm_flags & VM_WRITE)
|
||||
db = &s->dma_dac;
|
||||
|
@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
db->mapped = 1;
|
||||
out:
|
||||
mutex_unlock(&s->sem);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
|
|||
static int
|
||||
au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
unsigned long flags;
|
||||
audio_buf_info abinfo;
|
||||
count_info cinfo;
|
||||
|
@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
ret = au1550_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
|
|||
#endif
|
||||
|
||||
file->private_data = s;
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
/* wait for device to become free */
|
||||
mutex_lock(&s->open_mutex);
|
||||
while (s->open_mode & file->f_mode) {
|
||||
|
@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
|
|||
out:
|
||||
mutex_unlock(&s->open_mutex);
|
||||
out2:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
au1550_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct au1550_state *s = (struct au1550_state *)file->private_data;
|
||||
struct au1550_state *s = file->private_data;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
drain_dac(s, file->f_flags & O_NONBLOCK);
|
||||
lock_kernel();
|
||||
mutex_lock(&au1550_ac97_mutex);
|
||||
}
|
||||
|
||||
mutex_lock(&s->open_mutex);
|
||||
|
@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
|
|||
s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
|
||||
mutex_unlock(&s->open_mutex);
|
||||
wake_up(&s->open_wait);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&au1550_ac97_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -194,6 +194,7 @@
|
|||
* Declarations
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(dmasound_core_mutex);
|
||||
int dmasound_catchRadius = 0;
|
||||
module_param(dmasound_catchRadius, int, 0);
|
||||
|
||||
|
@ -323,22 +324,22 @@ static struct {
|
|||
|
||||
static int mixer_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
if (!try_module_get(dmasound.mach.owner)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
mixer.busy = 1;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixer_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
mixer.busy = 0;
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = mixer_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
int rc;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
if (!try_module_get(dmasound.mach.owner)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
|
|||
sound_set_format(AFMT_MU_LAW);
|
||||
}
|
||||
#endif
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
out:
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
int rc = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
if (write_sq.busy)
|
||||
|
@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
|
|||
write_sq_wake_up(file); /* checks f_mode */
|
||||
#endif /* blocking open() */
|
||||
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = sq_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
|
|||
int len = 0;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
ret = -EBUSY;
|
||||
if (state.busy)
|
||||
goto out;
|
||||
|
@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
|
|||
state.len = len;
|
||||
ret = 0;
|
||||
out:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int state_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
mutex_lock(&dmasound_core_mutex);
|
||||
state.busy = 0;
|
||||
module_put(dmasound.mach.owner);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&dmasound_core_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
@ -79,6 +79,7 @@
|
|||
dev.rec_sample_rate / \
|
||||
dev.rec_channels)
|
||||
|
||||
static DEFINE_MUTEX(msnd_pinnacle_mutex);
|
||||
static multisound_dev_t dev;
|
||||
|
||||
#ifndef HAVE_DSPCODEH
|
||||
|
@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
|
||||
ret = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor)
|
||||
ret = dsp_ioctl(file, cmd, arg);
|
||||
else if (minor == dev.mixer_minor)
|
||||
ret = mixer_ioctl(cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
|
|||
int minor = iminor(inode);
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor) {
|
||||
if ((file->f_mode & FMODE_WRITE &&
|
||||
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
|
||||
|
@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
|
|||
} else
|
||||
err = -EINVAL;
|
||||
out:
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
|
|||
int minor = iminor(inode);
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&msnd_pinnacle_mutex);
|
||||
if (minor == dev.dsp_minor)
|
||||
err = dsp_release(file);
|
||||
else if (minor == dev.mixer_minor) {
|
||||
/* nothing */
|
||||
} else
|
||||
err = -EINVAL;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&msnd_pinnacle_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,325 +0,0 @@
|
|||
/*
|
||||
* sound/oss/sh_dac_audio.c
|
||||
*
|
||||
* SH DAC based sound :(
|
||||
*
|
||||
* Copyright (C) 2004,2005 Andriy Skulysh
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sound.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/clock.h>
|
||||
#include <cpu/dac.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <mach/hp6xx.h>
|
||||
#include <asm/hd64461.h>
|
||||
|
||||
#define MODNAME "sh_dac_audio"
|
||||
|
||||
#define BUFFER_SIZE 48000
|
||||
|
||||
static int rate;
|
||||
static int empty;
|
||||
static char *data_buffer, *buffer_begin, *buffer_end;
|
||||
static int in_use, device_major;
|
||||
static struct hrtimer hrtimer;
|
||||
static ktime_t wakeups_per_second;
|
||||
|
||||
static void dac_audio_start_timer(void)
|
||||
{
|
||||
hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
static void dac_audio_stop_timer(void)
|
||||
{
|
||||
hrtimer_cancel(&hrtimer);
|
||||
}
|
||||
|
||||
static void dac_audio_reset(void)
|
||||
{
|
||||
dac_audio_stop_timer();
|
||||
buffer_begin = buffer_end = data_buffer;
|
||||
empty = 1;
|
||||
}
|
||||
|
||||
static void dac_audio_sync(void)
|
||||
{
|
||||
while (!empty)
|
||||
schedule();
|
||||
}
|
||||
|
||||
static void dac_audio_start(void)
|
||||
{
|
||||
if (mach_is_hp6xx()) {
|
||||
u16 v = __raw_readw(HD64461_GPADR);
|
||||
v &= ~HD64461_GPADR_SPEAKER;
|
||||
__raw_writew(v, HD64461_GPADR);
|
||||
}
|
||||
|
||||
sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
}
|
||||
static void dac_audio_stop(void)
|
||||
{
|
||||
dac_audio_stop_timer();
|
||||
|
||||
if (mach_is_hp6xx()) {
|
||||
u16 v = __raw_readw(HD64461_GPADR);
|
||||
v |= HD64461_GPADR_SPEAKER;
|
||||
__raw_writew(v, HD64461_GPADR);
|
||||
}
|
||||
|
||||
sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
}
|
||||
|
||||
static void dac_audio_set_rate(void)
|
||||
{
|
||||
wakeups_per_second = ktime_set(0, 1000000000 / rate);
|
||||
}
|
||||
|
||||
static int dac_audio_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (cmd) {
|
||||
case OSS_GETVERSION:
|
||||
return put_user(SOUND_VERSION, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SYNC:
|
||||
dac_audio_sync();
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_RESET:
|
||||
dac_audio_reset();
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_GETFMTS:
|
||||
return put_user(AFMT_U8, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETFMT:
|
||||
return put_user(AFMT_U8, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_NONBLOCK:
|
||||
spin_lock(&file->f_lock);
|
||||
file->f_flags |= O_NONBLOCK;
|
||||
spin_unlock(&file->f_lock);
|
||||
return 0;
|
||||
|
||||
case SNDCTL_DSP_GETCAPS:
|
||||
return 0;
|
||||
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
val = *(int *)arg;
|
||||
if (val > 0) {
|
||||
rate = val;
|
||||
dac_audio_set_rate();
|
||||
}
|
||||
return put_user(rate, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
return put_user(0, (int *)arg);
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
return put_user(1, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETDUPLEX:
|
||||
return -EINVAL;
|
||||
|
||||
case SNDCTL_DSP_PROFILE:
|
||||
return -EINVAL;
|
||||
|
||||
case SNDCTL_DSP_GETBLKSIZE:
|
||||
return put_user(BUFFER_SIZE, (int *)arg);
|
||||
|
||||
case SNDCTL_DSP_SETFRAGMENT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
|
||||
cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
ret = dac_audio_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
int free;
|
||||
int nbytes;
|
||||
|
||||
if (!count) {
|
||||
dac_audio_sync();
|
||||
return 0;
|
||||
}
|
||||
|
||||
free = buffer_begin - buffer_end;
|
||||
|
||||
if (free < 0)
|
||||
free += BUFFER_SIZE;
|
||||
if ((free == 0) && (empty))
|
||||
free = BUFFER_SIZE;
|
||||
if (count > free)
|
||||
count = free;
|
||||
if (buffer_begin > buffer_end) {
|
||||
if (copy_from_user((void *)buffer_end, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buffer_end += count;
|
||||
} else {
|
||||
nbytes = data_buffer + BUFFER_SIZE - buffer_end;
|
||||
if (nbytes > count) {
|
||||
if (copy_from_user((void *)buffer_end, buf, count))
|
||||
return -EFAULT;
|
||||
buffer_end += count;
|
||||
} else {
|
||||
if (copy_from_user((void *)buffer_end, buf, nbytes))
|
||||
return -EFAULT;
|
||||
if (copy_from_user
|
||||
((void *)data_buffer, buf + nbytes, count - nbytes))
|
||||
return -EFAULT;
|
||||
buffer_end = data_buffer + count - nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
empty = 0;
|
||||
dac_audio_start_timer();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dac_audio_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ)
|
||||
return -ENODEV;
|
||||
|
||||
lock_kernel();
|
||||
if (in_use) {
|
||||
unlock_kernel();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
in_use = 1;
|
||||
|
||||
dac_audio_start();
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac_audio_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
dac_audio_sync();
|
||||
dac_audio_stop();
|
||||
in_use = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations dac_audio_fops = {
|
||||
.read = dac_audio_read,
|
||||
.write = dac_audio_write,
|
||||
.unlocked_ioctl = dac_audio_unlocked_ioctl,
|
||||
.open = dac_audio_open,
|
||||
.release = dac_audio_release,
|
||||
};
|
||||
|
||||
static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
|
||||
{
|
||||
if (!empty) {
|
||||
sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
|
||||
buffer_begin++;
|
||||
|
||||
if (buffer_begin == data_buffer + BUFFER_SIZE)
|
||||
buffer_begin = data_buffer;
|
||||
if (buffer_begin == buffer_end)
|
||||
empty = 1;
|
||||
}
|
||||
|
||||
if (!empty)
|
||||
hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static int __init dac_audio_init(void)
|
||||
{
|
||||
if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
|
||||
printk(KERN_ERR "Cannot register dsp device");
|
||||
return device_major;
|
||||
}
|
||||
|
||||
in_use = 0;
|
||||
|
||||
data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
|
||||
if (data_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dac_audio_reset();
|
||||
rate = 8000;
|
||||
dac_audio_set_rate();
|
||||
|
||||
/* Today: High Resolution Timer driven DAC playback.
|
||||
* The timer callback gets called once per sample. Ouch.
|
||||
*
|
||||
* Future: A much better approach would be to use the
|
||||
* SH7720 CMT+DMAC+DAC hardware combination like this:
|
||||
* - Program sample rate using CMT0 or CMT1
|
||||
* - Program DMAC to use CMT for timing and output to DAC
|
||||
* - Play sound using DMAC, let CPU sleep.
|
||||
* - While at it, rewrite this driver to use ALSA.
|
||||
*/
|
||||
|
||||
hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
hrtimer.function = sh_dac_audio_timer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dac_audio_exit(void)
|
||||
{
|
||||
unregister_sound_dsp(device_major);
|
||||
kfree((void *)data_buffer);
|
||||
}
|
||||
|
||||
module_init(dac_audio_init);
|
||||
module_exit(dac_audio_exit);
|
||||
|
||||
MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
|
||||
MODULE_DESCRIPTION("SH DAC sound driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -40,7 +40,7 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -56,6 +56,7 @@
|
|||
* Table for permanently allocated memory (used when unloading the module)
|
||||
*/
|
||||
void * sound_mem_blocks[MAX_MEM_BLOCKS];
|
||||
static DEFINE_MUTEX(soundcard_mutex);
|
||||
int sound_nblocks = 0;
|
||||
|
||||
/* Persistent DMA buffers */
|
||||
|
@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
|
|||
* big one anyway, we might as well bandage here..
|
||||
*/
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
|
||||
DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
|
||||
switch (dev & 0x0f) {
|
||||
|
@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
|
|||
case SND_DEV_MIDIN:
|
||||
ret = MIDIbuf_read(dev, file, buf, count);
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
|
|||
int dev = iminor(file->f_path.dentry->d_inode);
|
||||
int ret = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_SEQ:
|
||||
|
@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
|
|||
ret = MIDIbuf_write(dev, file, buf, count);
|
||||
break;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
|
|||
printk(KERN_ERR "Invalid minor device %d\n", dev);
|
||||
return -ENXIO;
|
||||
}
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_CTL:
|
||||
dev >>= 4;
|
||||
|
@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
|
|||
retval = -ENXIO;
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sound_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
int dev = iminor(inode);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
DEB(printk("sound_release(dev=%d)\n", dev));
|
||||
switch (dev & 0x0f) {
|
||||
case SND_DEV_CTL:
|
||||
|
@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
|
|||
default:
|
||||
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (cmd == OSS_GETVERSION)
|
||||
return __put_user(SOUND_VERSION, (int __user *)p);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
|
||||
(dev & 0x0f) != SND_DEV_CTL) {
|
||||
dtype = dev & 0x0f;
|
||||
|
@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
ret = sound_mixer_ioctl(dev >> 4, cmd, p);
|
||||
break;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
lock_kernel();
|
||||
mutex_lock(&soundcard_mutex);
|
||||
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
|
||||
dmap = audio_devs[dev]->dmap_out;
|
||||
else if (vma->vm_flags & VM_READ)
|
||||
dmap = audio_devs[dev]->dmap_in;
|
||||
else {
|
||||
printk(KERN_ERR "Sound: Undefined mmap() access\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dmap == NULL) {
|
||||
printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (dmap->raw_buf == NULL) {
|
||||
printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (dmap->mapping_flags) {
|
||||
printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
if (vma->vm_pgoff != 0) {
|
||||
printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
|
@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
if (remap_pfn_range(vma, vma->vm_start,
|
||||
virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
memset(dmap->raw_buf,
|
||||
dmap->neutral_byte,
|
||||
dmap->bytes_in_use);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&soundcard_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/sound.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/ac97_codec.h>
|
||||
#include <linux/pci.h>
|
||||
|
@ -94,6 +93,7 @@
|
|||
|
||||
struct cs4297a_state;
|
||||
|
||||
static DEFINE_MUTEX(swarm_cs4297a_mutex);
|
||||
static void stop_dac(struct cs4297a_state *s);
|
||||
static void stop_adc(struct cs4297a_state *s);
|
||||
static void start_dac(struct cs4297a_state *s);
|
||||
|
@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
list_for_each(entry, &cs4297a_devs)
|
||||
{
|
||||
s = list_entry(entry, struct cs4297a_state, list);
|
||||
|
@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
|
||||
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
VALIDATE_STATE(s);
|
||||
|
@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
|
|||
|
||||
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
|
||||
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
|
||||
arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = cs4297a_ioctl(file, cmd, arg);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&swarm_cs4297a_mutex);
|
||||
ret = cs4297a_open(inode, file);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&swarm_cs4297a_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,6 @@
|
|||
#include <linux/init.h>
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -160,6 +159,7 @@
|
|||
|
||||
#ifdef VWSND_DEBUG
|
||||
|
||||
static DEFINE_MUTEX(vwsnd_mutex);
|
||||
static int shut_up = 1;
|
||||
|
||||
/*
|
||||
|
@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
|
|||
vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->io_mutex);
|
||||
ret = vwsnd_audio_do_ioctl(file, cmd, arg);
|
||||
mutex_unlock(&devc->io_mutex);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
INC_USE_COUNT;
|
||||
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
|
||||
if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
|
||||
|
@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
if (devc == NULL) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
mutex_unlock(&devc->open_mutex);
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
interruptible_sleep_on(&devc->open_wait);
|
||||
if (signal_pending(current)) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
mutex_lock(&devc->open_mutex);
|
||||
|
@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
|
|||
|
||||
file->private_data = devc;
|
||||
DBGRV();
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
|
|||
vwsnd_port_t *wport = NULL, *rport = NULL;
|
||||
int err = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->io_mutex);
|
||||
{
|
||||
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
|
|||
wake_up(&devc->open_wait);
|
||||
DEC_USE_COUNT;
|
||||
DBGR();
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
|
|||
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
|
||||
|
||||
INC_USE_COUNT;
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
|
||||
if (devc->mixer_minor == iminor(inode))
|
||||
break;
|
||||
|
||||
if (devc == NULL) {
|
||||
DEC_USE_COUNT;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
file->private_data = devc;
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
|
|||
|
||||
DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&vwsnd_mutex);
|
||||
mutex_lock(&devc->mix_mutex);
|
||||
{
|
||||
if ((cmd & ~nrmask) == MIXER_READ(0))
|
||||
|
@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
|
|||
retval = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&devc->mix_mutex);
|
||||
unlock_kernel();
|
||||
mutex_unlock(&vwsnd_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,12 +207,12 @@ config SND_CMIPCI
|
|||
|
||||
config SND_OXYGEN_LIB
|
||||
tristate
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
|
||||
config SND_OXYGEN
|
||||
tristate "C-Media 8788 (Oxygen)"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
help
|
||||
Say Y here to include support for sound cards based on the
|
||||
C-Media CMI8788 (Oxygen HD Audio) chip:
|
||||
|
@ -581,6 +581,8 @@ config SND_HDSPM
|
|||
config SND_HIFIER
|
||||
tristate "TempoTec HiFier Fantasia"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
help
|
||||
Say Y here to include support for the MediaTek/TempoTec HiFier
|
||||
Fantasia sound card.
|
||||
|
@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
|
|||
will be called snd-via82xx-modem.
|
||||
|
||||
config SND_VIRTUOSO
|
||||
tristate "Asus Virtuoso 100/200 (Xonar)"
|
||||
tristate "Asus Virtuoso 66/100/200 (Xonar)"
|
||||
select SND_OXYGEN_LIB
|
||||
select SND_PCM
|
||||
select SND_MPU401_UART
|
||||
select SND_JACK if INPUT=y || INPUT=SND
|
||||
help
|
||||
Say Y here to include support for sound cards based on the
|
||||
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
|
||||
Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
|
||||
Essence ST (Deluxe), and Essence STX.
|
||||
Support for the DS is experimental.
|
||||
Support for the HDAV1.3 (Deluxe) is very experimental.
|
||||
Support for the HDAV1.3 (Deluxe) is incomplete; for the
|
||||
HDAV1.3 Slim and Xense, missing.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-virtuoso.
|
||||
|
|
|
@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
|
|||
if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
|
||||
return err;
|
||||
memset(&ac97, 0, sizeof(ac97));
|
||||
// Intialize AC97 codec stuff.
|
||||
// Initialize AC97 codec stuff.
|
||||
ac97.private_data = vortex;
|
||||
ac97.scaps = AC97_SCAP_NO_SPDIF;
|
||||
err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
|
||||
|
|
|
@ -670,8 +670,9 @@ struct snd_ca0106_details {
|
|||
gpio_type = 2 -> shared side-out/line-in. */
|
||||
int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume
|
||||
controls, phone, mic, line-in and aux. */
|
||||
int spi_dac; /* spi_dac=1 adds the mute switch for each analog
|
||||
output, front, rear, etc. */
|
||||
u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs
|
||||
spi_dac = 0x<front><rear><center-lfe><side>
|
||||
-> specifies DAC id for each channel pair. */
|
||||
};
|
||||
|
||||
// definition of the chip-specific record
|
||||
|
|
|
@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "Audigy SE [SB0570]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* New Audigy LS. Has a different DAC. */
|
||||
/* SB0570:
|
||||
* CTRL:CA0106-DAT
|
||||
|
@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "Audigy SE OEM [SB0570a]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* Sound Blaster 5.1vx
|
||||
* Tested: Playback on front, rear, center/lfe speakers
|
||||
* Not-Tested: Capture
|
||||
*/
|
||||
{ .serial = 0x10041102,
|
||||
.name = "Sound Blaster 5.1vx [SB1070]",
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 0,
|
||||
.spi_dac = 0x0124
|
||||
} ,
|
||||
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
|
||||
/* SB0438
|
||||
* CTRL:CA0106-DAT
|
||||
|
@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
|
|||
.name = "MSI K8N Diamond MB",
|
||||
.gpio_type = 2,
|
||||
.i2c_adc = 1,
|
||||
.spi_dac = 1 } ,
|
||||
.spi_dac = 0x4021 } ,
|
||||
/* Giga-byte GA-G1975X mobo
|
||||
* Novell bnc#395807
|
||||
*/
|
||||
|
@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
|
|||
}
|
||||
|
||||
static const int spi_dacd_reg[] = {
|
||||
[PCM_FRONT_CHANNEL] = SPI_DACD4_REG,
|
||||
[PCM_REAR_CHANNEL] = SPI_DACD0_REG,
|
||||
[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
|
||||
[PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG,
|
||||
SPI_DACD0_REG,
|
||||
SPI_DACD1_REG,
|
||||
SPI_DACD2_REG,
|
||||
0,
|
||||
SPI_DACD4_REG,
|
||||
};
|
||||
static const int spi_dacd_bit[] = {
|
||||
[PCM_FRONT_CHANNEL] = SPI_DACD4_BIT,
|
||||
[PCM_REAR_CHANNEL] = SPI_DACD0_BIT,
|
||||
[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
|
||||
[PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT,
|
||||
SPI_DACD0_BIT,
|
||||
SPI_DACD1_BIT,
|
||||
SPI_DACD2_BIT,
|
||||
0,
|
||||
SPI_DACD4_BIT,
|
||||
};
|
||||
|
||||
static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
|
||||
|
@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
|
|||
}
|
||||
}
|
||||
|
||||
static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
|
||||
int channel_id)
|
||||
{
|
||||
switch (channel_id) {
|
||||
case PCM_FRONT_CHANNEL:
|
||||
return (details->spi_dac & 0xf000) >> (4 * 3);
|
||||
case PCM_REAR_CHANNEL:
|
||||
return (details->spi_dac & 0x0f00) >> (4 * 2);
|
||||
case PCM_CENTER_LFE_CHANNEL:
|
||||
return (details->spi_dac & 0x00f0) >> (4 * 1);
|
||||
case PCM_UNKNOWN_CHANNEL:
|
||||
return (details->spi_dac & 0x000f) >> (4 * 0);
|
||||
default:
|
||||
snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
|
||||
channel_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
|
||||
int power)
|
||||
{
|
||||
if (chip->details->spi_dac) {
|
||||
const int dac = snd_ca0106_channel_dac(chip->details,
|
||||
channel_id);
|
||||
const int reg = spi_dacd_reg[dac];
|
||||
const int bit = spi_dacd_bit[dac];
|
||||
|
||||
if (power)
|
||||
/* Power up */
|
||||
chip->spi_dac_reg[reg] &= ~bit;
|
||||
else
|
||||
/* Power down */
|
||||
chip->spi_dac_reg[reg] |= bit;
|
||||
return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* open_playback callback */
|
||||
static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
|
||||
int channel_id)
|
||||
|
@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
|
|||
return err;
|
||||
snd_pcm_set_sync(substream);
|
||||
|
||||
if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
|
||||
const int reg = spi_dacd_reg[channel_id];
|
||||
|
||||
/* Power up dac */
|
||||
chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
|
||||
err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
/* Front channel dac should already be on */
|
||||
if (channel_id != PCM_FRONT_CHANNEL) {
|
||||
err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
|
|||
|
||||
restore_spdif_bits(chip, epcm->channel_id);
|
||||
|
||||
if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
|
||||
const int reg = spi_dacd_reg[epcm->channel_id];
|
||||
|
||||
/* Power down DAC */
|
||||
chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
|
||||
snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
|
||||
/* Front channel dac should stay on */
|
||||
if (epcm->channel_id != PCM_FRONT_CHANNEL) {
|
||||
int err;
|
||||
err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* FIXME: maybe zero others */
|
||||
return 0;
|
||||
}
|
||||
|
@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
|
|||
struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_ca0106_pcm *epcm = runtime->private_data;
|
||||
snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
|
||||
unsigned int ptr, prev_ptr;
|
||||
int channel = epcm->channel_id;
|
||||
int timeout = 10;
|
||||
|
||||
if (!epcm->running)
|
||||
return 0;
|
||||
|
||||
ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
|
||||
ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
|
||||
ptr2 = bytes_to_frames(runtime, ptr1);
|
||||
ptr2+= (ptr4 >> 3) * runtime->period_size;
|
||||
ptr=ptr2;
|
||||
if (ptr >= runtime->buffer_size)
|
||||
ptr -= runtime->buffer_size;
|
||||
/*
|
||||
printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
|
||||
"buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
|
||||
ptr1, ptr2, ptr, (int)runtime->buffer_size,
|
||||
(int)runtime->period_size, (int)runtime->frame_bits,
|
||||
(int)runtime->rate);
|
||||
*/
|
||||
return ptr;
|
||||
prev_ptr = -1;
|
||||
do {
|
||||
ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
|
||||
ptr = (ptr >> 3) * runtime->period_size;
|
||||
ptr += bytes_to_frames(runtime,
|
||||
snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
|
||||
if (ptr >= runtime->buffer_size)
|
||||
ptr -= runtime->buffer_size;
|
||||
if (prev_ptr == ptr)
|
||||
return ptr;
|
||||
prev_ptr = ptr;
|
||||
} while (--timeout);
|
||||
snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pointer_capture callback */
|
||||
|
@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
|
|||
SPI_REG(12, 0x00),
|
||||
SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB),
|
||||
SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
|
||||
SPI_REG(SPI_DACD4_REG, 0x00),
|
||||
SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT),
|
||||
};
|
||||
|
||||
static unsigned int i2c_adc_init[][2] = {
|
||||
|
@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
|
|||
/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
|
||||
}
|
||||
|
||||
if (chip->details->spi_dac == 1) {
|
||||
if (chip->details->spi_dac) {
|
||||
/* The SB0570 use SPI to control DAC. */
|
||||
int size, n;
|
||||
|
||||
|
@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
|
|||
if (reg < ARRAY_SIZE(chip->spi_dac_reg))
|
||||
chip->spi_dac_reg[reg] = spi_dac_init[n];
|
||||
}
|
||||
|
||||
/* Enable front dac only */
|
||||
snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -676,27 +676,64 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
|
|||
I2C_VOLUME("Aux Capture Volume", 3),
|
||||
};
|
||||
|
||||
#define SPI_SWITCH(xname,reg,bit) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.info = spi_mute_info, \
|
||||
.get = spi_mute_get, \
|
||||
.put = spi_mute_put, \
|
||||
.private_value = (reg<<SPI_REG_SHIFT) | (bit) \
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
|
||||
__devinitdata = {
|
||||
SPI_SWITCH("Analog Front Playback Switch",
|
||||
SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
|
||||
SPI_SWITCH("Analog Rear Playback Switch",
|
||||
SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
|
||||
SPI_SWITCH("Analog Center/LFE Playback Switch",
|
||||
SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
|
||||
SPI_SWITCH("Analog Side Playback Switch",
|
||||
SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
|
||||
static const int spi_dmute_reg[] = {
|
||||
SPI_DMUTE0_REG,
|
||||
SPI_DMUTE1_REG,
|
||||
SPI_DMUTE2_REG,
|
||||
0,
|
||||
SPI_DMUTE4_REG,
|
||||
};
|
||||
static const int spi_dmute_bit[] = {
|
||||
SPI_DMUTE0_BIT,
|
||||
SPI_DMUTE1_BIT,
|
||||
SPI_DMUTE2_BIT,
|
||||
0,
|
||||
SPI_DMUTE4_BIT,
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new __devinit
|
||||
snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
|
||||
int channel_id)
|
||||
{
|
||||
struct snd_kcontrol_new spi_switch = {0};
|
||||
int reg, bit;
|
||||
int dac_id;
|
||||
|
||||
spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
spi_switch.info = spi_mute_info;
|
||||
spi_switch.get = spi_mute_get;
|
||||
spi_switch.put = spi_mute_put;
|
||||
|
||||
switch (channel_id) {
|
||||
case PCM_FRONT_CHANNEL:
|
||||
spi_switch.name = "Analog Front Playback Switch";
|
||||
dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
|
||||
break;
|
||||
case PCM_REAR_CHANNEL:
|
||||
spi_switch.name = "Analog Rear Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
|
||||
break;
|
||||
case PCM_CENTER_LFE_CHANNEL:
|
||||
spi_switch.name = "Analog Center/LFE Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
|
||||
break;
|
||||
case PCM_UNKNOWN_CHANNEL:
|
||||
spi_switch.name = "Analog Side Playback Switch";
|
||||
dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
|
||||
break;
|
||||
default:
|
||||
/* Unused channel */
|
||||
spi_switch.name = NULL;
|
||||
dac_id = 0;
|
||||
}
|
||||
reg = spi_dmute_reg[dac_id];
|
||||
bit = spi_dmute_bit[dac_id];
|
||||
|
||||
spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
|
||||
|
||||
return spi_switch;
|
||||
}
|
||||
|
||||
static int __devinit remove_ctl(struct snd_card *card, const char *name)
|
||||
{
|
||||
|
@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (emu->details->spi_dac == 1)
|
||||
ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
|
||||
if (emu->details->spi_dac) {
|
||||
int i;
|
||||
for (i = 0;; i++) {
|
||||
struct snd_kcontrol_new ctl;
|
||||
ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
|
||||
if (!ctl.name)
|
||||
break;
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create virtual master controls */
|
||||
vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
|
||||
|
@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
|||
return err;
|
||||
add_slaves(card, vmaster, slave_vols);
|
||||
|
||||
if (emu->details->spi_dac == 1) {
|
||||
if (emu->details->spi_dac) {
|
||||
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
|
||||
NULL);
|
||||
if (!vmaster)
|
||||
|
|
|
@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
|
|||
|
||||
static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
|
||||
{
|
||||
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
|
||||
struct snd_emu10k1_midi *midi = rmidi->private_data;
|
||||
midi->interrupt = NULL;
|
||||
midi->rmidi = NULL;
|
||||
}
|
||||
|
|
|
@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
|
|||
snd-hda-codec-via.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_ATIHDMI
|
||||
bool "Build ATI HDMI HD-audio codec support"
|
||||
default y
|
||||
help
|
||||
Say Y here to include ATI HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as ATI RS600 HDMI.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-atihdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_NVHDMI
|
||||
bool "Build NVIDIA HDMI HD-audio codec support"
|
||||
default y
|
||||
help
|
||||
Say Y here to include NVIDIA HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-nvhdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_INTELHDMI
|
||||
bool "Build INTEL HDMI HD-audio codec support"
|
||||
config SND_HDA_CODEC_HDMI
|
||||
bool "Build HDMI/DisplayPort HD-audio codec support"
|
||||
select SND_DYNAMIC_MINORS
|
||||
default y
|
||||
help
|
||||
Say Y here to include INTEL HDMI HD-audio codec support in
|
||||
snd-hda-intel driver, such as Eaglelake integrated HDMI.
|
||||
Say Y here to include HDMI and DisplayPort HD-audio codec
|
||||
support in snd-hda-intel driver. This includes all AMD/ATI,
|
||||
Intel and Nvidia HDMI/DisplayPort codecs.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-intelhdmi.
|
||||
snd-hda-codec-hdmi.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_ELD
|
||||
def_bool y
|
||||
depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
|
||||
|
||||
config SND_HDA_CODEC_CIRRUS
|
||||
bool "Build Cirrus Logic codec support"
|
||||
depends on SND_HDA_INTEL
|
||||
|
|
|
@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
|
|||
snd-hda-codec-y := hda_codec.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
|
||||
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
|
||||
|
||||
|
@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o
|
|||
snd-hda-codec-analog-objs := patch_analog.o
|
||||
snd-hda-codec-idt-objs := patch_sigmatel.o
|
||||
snd-hda-codec-si3054-objs := patch_si3054.o
|
||||
snd-hda-codec-atihdmi-objs := patch_atihdmi.o
|
||||
snd-hda-codec-cirrus-objs := patch_cirrus.o
|
||||
snd-hda-codec-ca0110-objs := patch_ca0110.o
|
||||
snd-hda-codec-conexant-objs := patch_conexant.o
|
||||
snd-hda-codec-via-objs := patch_via.o
|
||||
snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o
|
||||
snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o
|
||||
snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
|
||||
|
||||
# common driver
|
||||
obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
|
||||
|
@ -39,9 +36,6 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_SI3054
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CIRRUS
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
|
||||
endif
|
||||
|
@ -54,11 +48,8 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_VIA
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_NVHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
|
||||
ifdef CONFIG_SND_HDA_CODEC_HDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
|
||||
endif
|
||||
|
||||
# this must be the last entry after codec drivers;
|
||||
|
|
|
@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
struct hda_codec *c;
|
||||
struct hda_cvt_setup *p;
|
||||
unsigned int oldval, newval;
|
||||
int type;
|
||||
int i;
|
||||
|
||||
if (!nid)
|
||||
|
@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
p->dirty = 0;
|
||||
|
||||
/* make other inactive cvts with the same stream-tag dirty */
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
list_for_each_entry(c, &codec->bus->codec_list, list) {
|
||||
for (i = 0; i < c->cvt_setups.used; i++) {
|
||||
p = snd_array_elem(&c->cvt_setups, i);
|
||||
if (!p->active && p->stream_tag == stream_tag)
|
||||
if (!p->active && p->stream_tag == stream_tag &&
|
||||
get_wcaps_type(get_wcaps(codec, p->nid)) == type)
|
||||
p->dirty = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (!nid)
|
||||
return;
|
||||
|
||||
if (codec->no_sticky_stream)
|
||||
do_now = 1;
|
||||
|
||||
snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
|
||||
p = get_hda_cvt_setup(codec, nid);
|
||||
if (p) {
|
||||
|
@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
hda_nid_t nid = get_amp_nid(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
bool min_mute = get_amp_min_mute(kcontrol);
|
||||
u32 caps, val1, val2;
|
||||
|
||||
if (size < 4 * sizeof(unsigned int))
|
||||
|
@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
||||
val1 += ofs;
|
||||
val1 = ((int)val1) * ((int)val2);
|
||||
if (min_mute)
|
||||
val2 |= TLV_DB_SCALE_MUTE;
|
||||
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
||||
return -EFAULT;
|
||||
if (put_user(2 * sizeof(unsigned int), _tlv + 1))
|
||||
|
@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
|
|||
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
|
||||
HDA_AMP_MUTE,
|
||||
*valp ? 0 : HDA_AMP_MUTE);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, nid);
|
||||
#endif
|
||||
hda_call_check_power_status(codec, nid);
|
||||
snd_hda_power_down(codec);
|
||||
return change;
|
||||
}
|
||||
|
@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
|
|||
}
|
||||
|
||||
|
||||
/* add the found input-pin to the cfg->inputs[] table */
|
||||
static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
|
||||
int type)
|
||||
{
|
||||
if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
|
||||
cfg->inputs[cfg->num_inputs].pin = nid;
|
||||
cfg->inputs[cfg->num_inputs].type = type;
|
||||
cfg->num_inputs++;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort inputs in the order of AUTO_PIN_* type */
|
||||
static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
for (j = i + 1; j < cfg->num_inputs; j++) {
|
||||
if (cfg->inputs[i].type > cfg->inputs[j].type) {
|
||||
struct auto_pin_cfg_item tmp;
|
||||
tmp = cfg->inputs[i];
|
||||
cfg->inputs[i] = cfg->inputs[j];
|
||||
cfg->inputs[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all pin widgets and store the useful pin nids to cfg
|
||||
*
|
||||
|
@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
|
|||
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
||||
* if any analog output exists.
|
||||
*
|
||||
* The analog input pins are assigned to input_pins array.
|
||||
* The analog input pins are assigned to inputs array.
|
||||
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
|
||||
* respectively.
|
||||
*/
|
||||
|
@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
|
||||
short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
|
||||
short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
|
||||
int i;
|
||||
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
|
@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
|
||||
cfg->hp_outs++;
|
||||
break;
|
||||
case AC_JACK_MIC_IN: {
|
||||
int preferred, alt;
|
||||
if (loc == AC_JACK_LOC_FRONT ||
|
||||
(loc & 0x30) == AC_JACK_LOC_INTERNAL) {
|
||||
preferred = AUTO_PIN_FRONT_MIC;
|
||||
alt = AUTO_PIN_MIC;
|
||||
} else {
|
||||
preferred = AUTO_PIN_MIC;
|
||||
alt = AUTO_PIN_FRONT_MIC;
|
||||
}
|
||||
if (!cfg->input_pins[preferred])
|
||||
cfg->input_pins[preferred] = nid;
|
||||
else if (!cfg->input_pins[alt])
|
||||
cfg->input_pins[alt] = nid;
|
||||
case AC_JACK_MIC_IN:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
|
||||
break;
|
||||
}
|
||||
case AC_JACK_LINE_IN:
|
||||
if (loc == AC_JACK_LOC_FRONT)
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
|
||||
else
|
||||
cfg->input_pins[AUTO_PIN_LINE] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
|
||||
break;
|
||||
case AC_JACK_CD:
|
||||
cfg->input_pins[AUTO_PIN_CD] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
|
||||
break;
|
||||
case AC_JACK_AUX:
|
||||
cfg->input_pins[AUTO_PIN_AUX] = nid;
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
|
||||
break;
|
||||
case AC_JACK_SPDIF_OUT:
|
||||
case AC_JACK_DIG_OTHER_OUT:
|
||||
|
@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
memmove(sequences_hp + i, sequences_hp + i + 1,
|
||||
sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
|
||||
}
|
||||
memset(cfg->hp_pins + cfg->hp_outs, 0,
|
||||
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
|
||||
}
|
||||
|
||||
/* sort by sequence */
|
||||
|
@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
|
||||
cfg->hp_outs);
|
||||
|
||||
/* if we have only one mic, make it AUTO_PIN_MIC */
|
||||
if (!cfg->input_pins[AUTO_PIN_MIC] &&
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
|
||||
cfg->input_pins[AUTO_PIN_MIC] =
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC];
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
|
||||
}
|
||||
/* ditto for line-in */
|
||||
if (!cfg->input_pins[AUTO_PIN_LINE] &&
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
|
||||
cfg->input_pins[AUTO_PIN_LINE] =
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE];
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
|
||||
* as a primary output
|
||||
|
@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
break;
|
||||
}
|
||||
|
||||
sort_autocfg_input_pins(cfg);
|
||||
|
||||
/*
|
||||
* debug prints of the parsed results
|
||||
*/
|
||||
|
@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
if (cfg->dig_outs)
|
||||
snd_printd(" dig-out=0x%x/0x%x\n",
|
||||
cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
|
||||
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
||||
" cd=0x%x, aux=0x%x\n",
|
||||
cfg->input_pins[AUTO_PIN_MIC],
|
||||
cfg->input_pins[AUTO_PIN_FRONT_MIC],
|
||||
cfg->input_pins[AUTO_PIN_LINE],
|
||||
cfg->input_pins[AUTO_PIN_FRONT_LINE],
|
||||
cfg->input_pins[AUTO_PIN_CD],
|
||||
cfg->input_pins[AUTO_PIN_AUX]);
|
||||
snd_printd(" inputs:");
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
snd_printdd(" %s=0x%x",
|
||||
hda_get_autocfg_input_label(codec, cfg, i),
|
||||
cfg->inputs[i].pin);
|
||||
}
|
||||
snd_printd("\n");
|
||||
if (cfg->dig_in_pin)
|
||||
snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
|
||||
|
||||
|
@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
|
||||
|
||||
/* labels for input pins */
|
||||
const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
|
||||
"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
|
||||
};
|
||||
EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf)
|
||||
{
|
||||
unsigned int loc = get_defcfg_location(def_conf);
|
||||
unsigned int conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
return INPUT_PIN_ATTR_UNUSED;
|
||||
/* Windows may claim the internal mic to be BOTH, too */
|
||||
if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
|
||||
return INPUT_PIN_ATTR_DOCK;
|
||||
if (loc == AC_JACK_LOC_REAR)
|
||||
return INPUT_PIN_ATTR_REAR;
|
||||
if (loc == AC_JACK_LOC_FRONT)
|
||||
return INPUT_PIN_ATTR_FRONT;
|
||||
return INPUT_PIN_ATTR_NORMAL;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
|
||||
|
||||
/**
|
||||
* hda_get_input_pin_label - Give a label for the given input pin
|
||||
*
|
||||
* When check_location is true, the function checks the pin location
|
||||
* for mic and line-in pins, and set an appropriate prefix like "Front",
|
||||
* "Rear", "Internal".
|
||||
*/
|
||||
|
||||
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
|
||||
int check_location)
|
||||
{
|
||||
unsigned int def_conf;
|
||||
static const char *mic_names[] = {
|
||||
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
|
||||
};
|
||||
int attr;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, pin);
|
||||
|
||||
switch (get_defcfg_device(def_conf)) {
|
||||
case AC_JACK_MIC_IN:
|
||||
if (!check_location)
|
||||
return "Mic";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
return mic_names[attr - 1];
|
||||
case AC_JACK_LINE_IN:
|
||||
if (!check_location)
|
||||
return "Line";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
if (attr == INPUT_PIN_ATTR_DOCK)
|
||||
return "Dock Line";
|
||||
return "Line";
|
||||
case AC_JACK_AUX:
|
||||
return "Aux";
|
||||
case AC_JACK_CD:
|
||||
return "CD";
|
||||
case AC_JACK_SPDIF_IN:
|
||||
return "SPDIF In";
|
||||
case AC_JACK_DIG_OTHER_IN:
|
||||
return "Digital In";
|
||||
default:
|
||||
return "Misc";
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
|
||||
|
||||
/* Check whether the location prefix needs to be added to the label.
|
||||
* If all mic-jacks are in the same location (e.g. rear panel), we don't
|
||||
* have to put "Front" prefix to each label. In such a case, returns false.
|
||||
*/
|
||||
static int check_mic_location_need(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
unsigned int defc;
|
||||
int i, attr, attr2;
|
||||
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
|
||||
attr = snd_hda_get_input_pin_attr(defc);
|
||||
/* for internal or docking mics, we need locations */
|
||||
if (attr <= INPUT_PIN_ATTR_NORMAL)
|
||||
return 1;
|
||||
|
||||
attr = 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
|
||||
attr2 = snd_hda_get_input_pin_attr(defc);
|
||||
if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
|
||||
if (attr && attr != attr2)
|
||||
return 1; /* different locations found */
|
||||
attr = attr2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hda_get_autocfg_input_label - Get a label for the given input
|
||||
*
|
||||
* Get a label for the given input pin defined by the autocfg item.
|
||||
* Unlike hda_get_input_pin_label(), this function checks all inputs
|
||||
* defined in autocfg and avoids the redundant mic/line prefix as much as
|
||||
* possible.
|
||||
*/
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
int type = cfg->inputs[input].type;
|
||||
int has_multiple_pins = 0;
|
||||
|
||||
if ((input > 0 && cfg->inputs[input - 1].type == type) ||
|
||||
(input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
|
||||
has_multiple_pins = 1;
|
||||
if (has_multiple_pins && type == AUTO_PIN_MIC)
|
||||
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
|
||||
return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
|
||||
has_multiple_pins);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
|
||||
|
||||
/**
|
||||
* snd_hda_add_imux_item - Add an item to input_mux
|
||||
*
|
||||
* When the same label is used already in the existing items, the number
|
||||
* suffix is appended to the label. This label index number is stored
|
||||
* to type_idx when non-NULL pointer is given.
|
||||
*/
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_idx)
|
||||
{
|
||||
int i, label_idx = 0;
|
||||
if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
|
||||
snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < imux->num_items; i++) {
|
||||
if (!strncmp(label, imux->items[i].label, strlen(label)))
|
||||
label_idx++;
|
||||
}
|
||||
if (type_idx)
|
||||
*type_idx = label_idx;
|
||||
if (label_idx > 0)
|
||||
snprintf(imux->items[imux->num_items].label,
|
||||
sizeof(imux->items[imux->num_items].label),
|
||||
"%s %d", label, label_idx);
|
||||
else
|
||||
strlcpy(imux->items[imux->num_items].label, label,
|
||||
sizeof(imux->items[imux->num_items].label));
|
||||
imux->items[imux->num_items].index = index;
|
||||
imux->num_items++;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
@ -850,6 +850,7 @@ struct hda_codec {
|
|||
unsigned int pin_amp_workaround:1; /* pin out-amp takes index
|
||||
* (e.g. Conexant codecs)
|
||||
*/
|
||||
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
|
||||
unsigned int pins_shutup:1; /* pins are shut up */
|
||||
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
|
@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
|
|||
int snd_hda_resume(struct hda_bus *bus);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static inline
|
||||
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
if (codec->patch_ops.check_power_status)
|
||||
return codec->patch_ops.check_power_status(codec, nid);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define hda_call_check_power_status(codec, nid) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* get widget information
|
||||
*/
|
||||
|
|
|
@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
|
|||
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
|
||||
AC_DIPSIZE_ELD_BUF);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
|
||||
|
||||
int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
||||
struct hda_codec *codec, hda_nid_t nid)
|
||||
|
@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
|
|||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
|
||||
|
||||
static void hdmi_show_short_audio_desc(struct cea_sad *a)
|
||||
{
|
||||
|
@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
|
|||
}
|
||||
buf[j] = '\0'; /* necessary when j == 0 */
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
|
||||
|
||||
void snd_hdmi_show_eld(struct hdmi_eld *e)
|
||||
{
|
||||
|
@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
|
|||
for (i = 0; i < e->sad_count; i++)
|
||||
hdmi_show_short_audio_desc(e->sad + i);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
|
@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
|
||||
|
||||
void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
|
||||
{
|
||||
|
@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
|
|||
eld->proc_entry = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
|
@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
|
|||
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
|
||||
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
|
||||
|
|
|
@ -61,7 +61,6 @@ struct hda_gspec {
|
|||
struct hda_gnode *cap_vol_node; /* Node for capture volume */
|
||||
unsigned int cur_cap_src; /* current capture source */
|
||||
struct hda_input_mux input_mux;
|
||||
char cap_labels[HDA_MAX_NUM_INPUTS][16];
|
||||
|
||||
unsigned int def_amp_in_caps;
|
||||
unsigned int def_amp_out_caps;
|
||||
|
@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
|
|||
* returns 0 if not found, 1 if found, or a negative error code.
|
||||
*/
|
||||
static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
||||
struct hda_gnode *node)
|
||||
struct hda_gnode *node, int idx)
|
||||
{
|
||||
int i, err;
|
||||
unsigned int pinctl;
|
||||
char *label;
|
||||
const char *type;
|
||||
|
||||
if (node->checked)
|
||||
|
@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
child = hda_get_node(spec, node->conn_list[i]);
|
||||
if (! child)
|
||||
continue;
|
||||
err = parse_adc_sub_nodes(codec, spec, child);
|
||||
err = parse_adc_sub_nodes(codec, spec, child, idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err > 0) {
|
||||
|
@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
return 0;
|
||||
type = "Input";
|
||||
}
|
||||
label = spec->cap_labels[spec->input_mux.num_items];
|
||||
strcpy(label, type);
|
||||
spec->input_mux.items[spec->input_mux.num_items].label = label;
|
||||
snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
|
||||
|
||||
/* unmute the PIN external input */
|
||||
unmute_input(codec, node, 0); /* index = 0? */
|
||||
|
@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
|
|||
return 1; /* found */
|
||||
}
|
||||
|
||||
/* add a capture source element */
|
||||
static void add_cap_src(struct hda_gspec *spec, int idx)
|
||||
{
|
||||
struct hda_input_mux_item *csrc;
|
||||
char *buf;
|
||||
int num, ocap;
|
||||
|
||||
num = spec->input_mux.num_items;
|
||||
csrc = &spec->input_mux.items[num];
|
||||
buf = spec->cap_labels[num];
|
||||
for (ocap = 0; ocap < num; ocap++) {
|
||||
if (! strcmp(buf, spec->cap_labels[ocap])) {
|
||||
/* same label already exists,
|
||||
* put the index number to be unique
|
||||
*/
|
||||
sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
csrc->index = idx;
|
||||
spec->input_mux.num_items++;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse input
|
||||
*/
|
||||
|
@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
|
|||
for (i = 0; i < adc_node->nconns; i++) {
|
||||
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||
if (node && node->type == AC_WID_PIN) {
|
||||
err = parse_adc_sub_nodes(codec, spec, node);
|
||||
err = parse_adc_sub_nodes(codec, spec, node, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err > 0)
|
||||
add_cap_src(spec, i);
|
||||
}
|
||||
}
|
||||
/* ... then check the rests, more complicated connections */
|
||||
for (i = 0; i < adc_node->nconns; i++) {
|
||||
node = hda_get_node(spec, adc_node->conn_list[i]);
|
||||
if (node && node->type != AC_WID_PIN) {
|
||||
err = parse_adc_sub_nodes(codec, spec, node);
|
||||
err = parse_adc_sub_nodes(codec, spec, node, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err > 0)
|
||||
add_cap_src(spec, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
|
|||
module_param_array(model, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(model, "Use the given board model.");
|
||||
module_param_array(position_fix, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
|
||||
"(0 = auto, 1 = none, 2 = POSBUF).");
|
||||
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
|
||||
"(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
|
||||
module_param_array(bdl_pos_adj, int, NULL, 0644);
|
||||
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
|
||||
module_param_array(probe_mask, int, NULL, 0444);
|
||||
|
@ -305,6 +305,7 @@ enum {
|
|||
POS_FIX_AUTO,
|
||||
POS_FIX_LPIB,
|
||||
POS_FIX_POSBUF,
|
||||
POS_FIX_VIACOMBO,
|
||||
};
|
||||
|
||||
/* Defines for ATI HD Audio support in SB450 south bridge */
|
||||
|
@ -433,7 +434,6 @@ struct azx {
|
|||
unsigned int polling_mode :1;
|
||||
unsigned int msi :1;
|
||||
unsigned int irq_pending_warned :1;
|
||||
unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
|
||||
unsigned int probing :1; /* codec probing phase */
|
||||
|
||||
/* for debugging */
|
||||
|
@ -458,6 +458,7 @@ enum {
|
|||
AZX_DRIVER_ULI,
|
||||
AZX_DRIVER_NVIDIA,
|
||||
AZX_DRIVER_TERA,
|
||||
AZX_DRIVER_CTX,
|
||||
AZX_DRIVER_GENERIC,
|
||||
AZX_NUM_DRIVERS, /* keep this as last entry */
|
||||
};
|
||||
|
@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
|
|||
[AZX_DRIVER_ULI] = "HDA ULI M5461",
|
||||
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
|
||||
[AZX_DRIVER_TERA] = "HDA Teradici",
|
||||
[AZX_DRIVER_CTX] = "HDA Creative",
|
||||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
||||
};
|
||||
|
||||
|
@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
|
|||
/* reset the rirb hw write pointer */
|
||||
azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
|
||||
/* set N=1, get RIRB response interrupt for new entry */
|
||||
azx_writew(chip, RINTCNT, 1);
|
||||
if (chip->driver_type == AZX_DRIVER_CTX)
|
||||
azx_writew(chip, RINTCNT, 0xc0);
|
||||
else
|
||||
azx_writew(chip, RINTCNT, 1);
|
||||
/* enable rirb dma and response irq */
|
||||
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
|
@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
/* clear rirb int */
|
||||
status = azx_readb(chip, RIRBSTS);
|
||||
if (status & RIRB_INT_MASK) {
|
||||
if (status & RIRB_INT_RESPONSE)
|
||||
if (status & RIRB_INT_RESPONSE) {
|
||||
if (chip->driver_type == AZX_DRIVER_CTX)
|
||||
udelay(80);
|
||||
azx_update_rirb(chip);
|
||||
}
|
||||
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
||||
}
|
||||
|
||||
|
@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|||
azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
|
||||
|
||||
/* enable the position buffer */
|
||||
if (chip->position_fix[0] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[0] == POS_FIX_AUTO ||
|
||||
chip->position_fix[1] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[1] == POS_FIX_AUTO ||
|
||||
chip->via_dmapos_patch) {
|
||||
if (chip->position_fix[0] != POS_FIX_LPIB ||
|
||||
chip->position_fix[1] != POS_FIX_LPIB) {
|
||||
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
|
||||
azx_writel(chip, DPLBASE,
|
||||
(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
|
||||
|
@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int bufsize, period_bytes, format_val;
|
||||
unsigned int bufsize, period_bytes, format_val, stream_tag;
|
||||
int err;
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
|
@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
else
|
||||
azx_dev->fifo_size = 0;
|
||||
|
||||
return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
|
||||
stream_tag = azx_dev->stream_tag;
|
||||
/* CA-IBG chips need the playback stream starting from 1 */
|
||||
if (chip->driver_type == AZX_DRIVER_CTX &&
|
||||
stream_tag > chip->capture_streams)
|
||||
stream_tag -= chip->capture_streams;
|
||||
return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
|
||||
azx_dev->format_val, substream);
|
||||
}
|
||||
|
||||
|
@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
|
|||
struct azx_dev *azx_dev)
|
||||
{
|
||||
unsigned int pos;
|
||||
int stream = azx_dev->substream->stream;
|
||||
|
||||
if (chip->via_dmapos_patch)
|
||||
switch (chip->position_fix[stream]) {
|
||||
case POS_FIX_LPIB:
|
||||
/* read LPIB */
|
||||
pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
break;
|
||||
case POS_FIX_VIACOMBO:
|
||||
pos = azx_via_get_position(chip, azx_dev);
|
||||
else {
|
||||
int stream = azx_dev->substream->stream;
|
||||
if (chip->position_fix[stream] == POS_FIX_POSBUF ||
|
||||
chip->position_fix[stream] == POS_FIX_AUTO) {
|
||||
/* use the position buffer */
|
||||
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||
} else {
|
||||
/* read LPIB */
|
||||
pos = azx_sd_readl(azx_dev, SD_LPIB);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* use the position buffer */
|
||||
pos = le32_to_cpu(*azx_dev->posbuf);
|
||||
}
|
||||
|
||||
if (pos >= azx_dev->bufsize)
|
||||
pos = 0;
|
||||
return pos;
|
||||
|
@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
|
|||
switch (fix) {
|
||||
case POS_FIX_LPIB:
|
||||
case POS_FIX_POSBUF:
|
||||
case POS_FIX_VIACOMBO:
|
||||
return fix;
|
||||
}
|
||||
|
||||
/* Check VIA/ATI HD Audio Controller exist */
|
||||
switch (chip->driver_type) {
|
||||
case AZX_DRIVER_VIA:
|
||||
case AZX_DRIVER_ATI:
|
||||
chip->via_dmapos_patch = 1;
|
||||
/* Use link position directly, avoid any transfer problem. */
|
||||
return POS_FIX_LPIB;
|
||||
}
|
||||
chip->via_dmapos_patch = 0;
|
||||
|
||||
q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
|
||||
if (q) {
|
||||
printk(KERN_INFO
|
||||
|
@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
|
|||
q->value, q->subvendor, q->subdevice);
|
||||
return q->value;
|
||||
}
|
||||
|
||||
/* Check VIA/ATI HD Audio Controller exist */
|
||||
switch (chip->driver_type) {
|
||||
case AZX_DRIVER_VIA:
|
||||
case AZX_DRIVER_ATI:
|
||||
/* Use link position directly, avoid any transfer problem. */
|
||||
return POS_FIX_VIACOMBO;
|
||||
}
|
||||
|
||||
return POS_FIX_AUTO;
|
||||
}
|
||||
|
||||
|
@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
|
|||
|
||||
/* PCI IDs */
|
||||
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
||||
/* ICH 6..10 */
|
||||
{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
|
||||
/* PCH */
|
||||
{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
|
||||
{ PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
|
||||
/* CPT */
|
||||
{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
|
||||
/* PBG */
|
||||
{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
|
||||
/* SCH */
|
||||
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
|
||||
/* Generic Intel */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
.class_mask = 0xffffff,
|
||||
.driver_data = AZX_DRIVER_ICH },
|
||||
/* ATI SB 450/600 */
|
||||
{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
|
||||
{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
|
||||
|
@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
.class_mask = 0xffffff,
|
||||
.driver_data = AZX_DRIVER_GENERIC },
|
||||
.driver_data = AZX_DRIVER_CTX },
|
||||
#else
|
||||
/* this entry seems still valid -- i.e. without emu20kx chip */
|
||||
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
|
||||
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
|
||||
#endif
|
||||
/* Vortex86MX */
|
||||
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
|
||||
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
|
||||
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
||||
|
|
|
@ -38,10 +38,11 @@
|
|||
*/
|
||||
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
|
||||
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
|
||||
#define HDA_AMP_VAL_MIN_MUTE (1<<29)
|
||||
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
||||
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
|
||||
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||
.subdevice = HDA_SUBDEV_AMP_FLAG, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||
|
@ -51,16 +52,20 @@
|
|||
.get = snd_hda_mixer_amp_volume_get, \
|
||||
.put = snd_hda_mixer_amp_volume_put, \
|
||||
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
|
||||
/* stereo volume with index */
|
||||
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
|
||||
/* mono volume */
|
||||
#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
|
||||
/* stereo volume */
|
||||
#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
|
||||
/* stereo volume with min=mute */
|
||||
#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
|
||||
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
|
||||
HDA_AMP_VAL_MIN_MUTE)
|
||||
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
|
||||
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||
|
@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
|
|||
*/
|
||||
#define HDA_MAX_NUM_INPUTS 16
|
||||
struct hda_input_mux_item {
|
||||
const char *label;
|
||||
char label[32];
|
||||
unsigned int index;
|
||||
};
|
||||
struct hda_input_mux {
|
||||
|
@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
|
|||
|
||||
enum {
|
||||
AUTO_PIN_MIC,
|
||||
AUTO_PIN_FRONT_MIC,
|
||||
AUTO_PIN_LINE,
|
||||
AUTO_PIN_FRONT_LINE,
|
||||
AUTO_PIN_LINE_IN,
|
||||
AUTO_PIN_CD,
|
||||
AUTO_PIN_AUX,
|
||||
AUTO_PIN_LAST
|
||||
|
@ -380,9 +383,33 @@ enum {
|
|||
AUTO_PIN_HP_OUT
|
||||
};
|
||||
|
||||
extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
|
||||
|
||||
#define AUTO_CFG_MAX_OUTS 5
|
||||
#define AUTO_CFG_MAX_INS 8
|
||||
|
||||
struct auto_pin_cfg_item {
|
||||
hda_nid_t pin;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct auto_pin_cfg;
|
||||
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
|
||||
int check_location);
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input);
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
|
||||
enum {
|
||||
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
|
||||
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
|
||||
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
|
||||
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
|
||||
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
|
||||
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
|
||||
};
|
||||
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf);
|
||||
|
||||
struct auto_pin_cfg {
|
||||
int line_outs;
|
||||
|
@ -393,7 +420,8 @@ struct auto_pin_cfg {
|
|||
int hp_outs;
|
||||
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||
hda_nid_t input_pins[AUTO_PIN_LAST];
|
||||
int num_inputs;
|
||||
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
|
||||
int dig_outs;
|
||||
hda_nid_t dig_out_pins[2];
|
||||
hda_nid_t dig_in_pin;
|
||||
|
@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
|||
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
|
||||
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
|
||||
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
|
||||
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
|
||||
|
||||
/*
|
||||
* CEA Short Audio Descriptor data
|
||||
|
|
|
@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
|
|||
spec->multiout.no_share_stream = 1;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
|
|||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
|
|||
|
||||
/* create input playback/capture controls for the given pin */
|
||||
static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
|
||||
const char *ctlname, int boost)
|
||||
const char *ctlname, int ctlidx, int boost)
|
||||
{
|
||||
char name[32];
|
||||
int err, idx;
|
||||
|
@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
|
|||
}
|
||||
|
||||
/* create playback/capture controls for input pins */
|
||||
static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
|
||||
static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
struct hda_input_mux *imux = &spec->private_imux;
|
||||
int i, err;
|
||||
int i, err, type, type_idx;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
err = new_analog_input(spec, cfg->input_pins[i],
|
||||
auto_pin_cfg_labels[i],
|
||||
i <= AUTO_PIN_FRONT_MIC);
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
const char *label;
|
||||
type = cfg->inputs[i].type;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
snd_hda_add_imux_item(imux, label,
|
||||
ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
|
||||
&type_idx);
|
||||
err = new_analog_input(spec, cfg->inputs[i].pin,
|
||||
label, type_idx,
|
||||
type == AUTO_PIN_MIC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
||||
imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
|
||||
imux->num_items++;
|
||||
}
|
||||
imux->items[imux->num_items].label = "Mix";
|
||||
imux->items[imux->num_items].index = 9;
|
||||
imux->num_items++;
|
||||
snd_hda_add_imux_item(imux, "Mix", 9, NULL);
|
||||
|
||||
if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
|
||||
"Analog Mix Playback Volume",
|
||||
|
@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
|
|||
static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i, idx;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t nid = spec->autocfg.input_pins[i];
|
||||
if (! nid)
|
||||
continue;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
switch (nid) {
|
||||
case 0x15: /* port-C */
|
||||
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
|
||||
|
@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
|||
break;
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
|
||||
i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
|
||||
if (nid != AD1988_PIN_CD_NID)
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_MUTE);
|
||||
|
@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
|
|||
"Speaker")) < 0 ||
|
||||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
|
||||
"Headphone")) < 0 ||
|
||||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
|
||||
(err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
|
||||
return err;
|
||||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
spec->vmaster_nid = 0x04;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
|
|||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
codec->no_trigger_sense = 1;
|
||||
codec->no_sticky_stream = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* Universal Interface for Intel High Definition Audio Codec
|
||||
*
|
||||
* HD audio interface patch for ATI HDMI codecs
|
||||
*
|
||||
* Copyright (c) 2006 ATI Technologies Inc.
|
||||
*
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This driver is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
struct atihdmi_spec {
|
||||
struct hda_multi_out multiout;
|
||||
|
||||
struct hda_pcm pcm_rec;
|
||||
};
|
||||
|
||||
#define CVT_NID 0x02 /* audio converter */
|
||||
#define PIN_NID 0x03 /* HDMI output pin */
|
||||
|
||||
static struct hda_verb atihdmi_basic_init[] = {
|
||||
/* enable digital output on pin widget */
|
||||
{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* Controls
|
||||
*/
|
||||
static int atihdmi_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
int err;
|
||||
|
||||
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atihdmi_init(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_sequence_write(codec, atihdmi_basic_init);
|
||||
/* SI codec requires to unmute the pin */
|
||||
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, PIN_NID, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_UNMUTE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Digital out
|
||||
*/
|
||||
static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
||||
}
|
||||
|
||||
static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
unsigned int stream_tag,
|
||||
unsigned int format,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
int chans = substream->runtime->channels;
|
||||
int i, err;
|
||||
|
||||
err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
|
||||
format, substream);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
|
||||
chans - 1);
|
||||
/* FIXME: XXX */
|
||||
for (i = 0; i < chans; i++) {
|
||||
snd_hda_codec_write(codec, CVT_NID, 0,
|
||||
AC_VERB_SET_HDMI_CHAN_SLOT,
|
||||
(i << 4) | i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
|
||||
.substreams = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.nid = CVT_NID, /* NID to query formats and rates and setup streams */
|
||||
.ops = {
|
||||
.open = atihdmi_dig_playback_pcm_open,
|
||||
.close = atihdmi_dig_playback_pcm_close,
|
||||
.prepare = atihdmi_dig_playback_pcm_prepare
|
||||
},
|
||||
};
|
||||
|
||||
static int atihdmi_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = &spec->pcm_rec;
|
||||
unsigned int chans;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
info->name = "ATI HDMI";
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
|
||||
|
||||
/* FIXME: we must check ELD and change the PCM parameters dynamically
|
||||
*/
|
||||
chans = get_wcaps(codec, CVT_NID);
|
||||
chans = get_wcaps_channels(chans);
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atihdmi_free(struct hda_codec *codec)
|
||||
{
|
||||
kfree(codec->spec);
|
||||
}
|
||||
|
||||
static struct hda_codec_ops atihdmi_patch_ops = {
|
||||
.build_controls = atihdmi_build_controls,
|
||||
.build_pcms = atihdmi_build_pcms,
|
||||
.init = atihdmi_init,
|
||||
.free = atihdmi_free,
|
||||
};
|
||||
|
||||
static int patch_atihdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct atihdmi_spec *spec;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 2;
|
||||
/* NID for copying analog to digital,
|
||||
* seems to be unused in pure-digital
|
||||
* case.
|
||||
*/
|
||||
spec->multiout.dig_out_nid = CVT_NID;
|
||||
|
||||
codec->patch_ops = atihdmi_patch_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
|
||||
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
|
||||
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002793c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10027919");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002791a");
|
||||
MODULE_ALIAS("snd-hda-codec-id:1002aa01");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951390");
|
||||
MODULE_ALIAS("snd-hda-codec-id:17e80047");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list atihdmi_list = {
|
||||
.preset = snd_hda_preset_atihdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_atihdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&atihdmi_list);
|
||||
}
|
||||
|
||||
static void __exit patch_atihdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&atihdmi_list);
|
||||
}
|
||||
|
||||
module_init(patch_atihdmi_init)
|
||||
module_exit(patch_atihdmi_exit)
|
|
@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
|
|||
spec->dig_in = nid;
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < AUTO_PIN_LAST; j++)
|
||||
if (cfg->input_pins[j] == pin)
|
||||
for (j = 0; j < cfg->num_inputs; j++)
|
||||
if (cfg->inputs[j].pin == pin)
|
||||
break;
|
||||
if (j >= AUTO_PIN_LAST)
|
||||
if (j >= cfg->num_inputs)
|
||||
continue;
|
||||
spec->input_pins[n] = pin;
|
||||
spec->input_labels[n] = auto_pin_cfg_labels[j];
|
||||
spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
|
||||
spec->adcs[n] = nid;
|
||||
n++;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
|
|||
if (cfg->dig_outs &&
|
||||
snd_hda_get_connections(codec, cfg->dig_out_pins[0],
|
||||
&spec->dig_out, 1) == 1)
|
||||
spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
|
||||
spec->multiout.dig_out_nid = spec->dig_out;
|
||||
}
|
||||
|
||||
static int ca0110_parse_auto_config(struct hda_codec *codec)
|
||||
|
|
|
@ -65,6 +65,7 @@ struct cs_spec {
|
|||
|
||||
/* available models */
|
||||
enum {
|
||||
CS420X_MBP53,
|
||||
CS420X_MBP55,
|
||||
CS420X_IMAC27,
|
||||
CS420X_AUTO,
|
||||
|
@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
|
|||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t pin = cfg->input_pins[idx];
|
||||
hda_nid_t pin = cfg->inputs[idx].pin;
|
||||
unsigned int val = snd_hda_query_pin_caps(codec, pin);
|
||||
if (!(val & AC_PINCAP_PRES_DETECT))
|
||||
return 0;
|
||||
val = snd_hda_codec_get_pincfg(codec, pin);
|
||||
return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
|
||||
return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
|
||||
}
|
||||
|
||||
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
|
||||
|
@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
|
|||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
hda_nid_t pin = cfg->input_pins[i];
|
||||
if (!pin)
|
||||
continue;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
spec->input_idx[spec->num_inputs] = i;
|
||||
spec->capsrc_idx[i] = spec->num_inputs++;
|
||||
spec->cur_input = i;
|
||||
|
@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
|
|||
|
||||
/* check whether the automatic mic switch is available */
|
||||
if (spec->num_inputs == 2 &&
|
||||
spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
|
||||
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
|
||||
if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
|
||||
cfg->inputs[0].type == AUTO_PIN_MIC &&
|
||||
cfg->inputs[1].type == AUTO_PIN_MIC) {
|
||||
if (is_ext_mic(codec, cfg->inputs[0].pin)) {
|
||||
if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
|
||||
spec->mic_detect = 1;
|
||||
spec->automic_idx = AUTO_PIN_FRONT_MIC;
|
||||
spec->automic_idx = 0;
|
||||
}
|
||||
} else {
|
||||
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
|
||||
if (is_ext_mic(codec, cfg->inputs[1].pin)) {
|
||||
spec->mic_detect = 1;
|
||||
spec->automic_idx = AUTO_PIN_MIC;
|
||||
spec->automic_idx = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int idx;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
|
@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
|
|||
if (uinfo->value.enumerated.item >= spec->num_inputs)
|
||||
uinfo->value.enumerated.item = spec->num_inputs - 1;
|
||||
idx = spec->input_idx[uinfo->value.enumerated.item];
|
||||
strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
|
|||
return bind;
|
||||
}
|
||||
|
||||
/* add a (input-boost) volume control to the given input pin */
|
||||
static int add_input_volume_control(struct hda_codec *codec,
|
||||
struct auto_pin_cfg *cfg,
|
||||
int item)
|
||||
{
|
||||
hda_nid_t pin = cfg->inputs[item].pin;
|
||||
u32 caps;
|
||||
const char *label;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
|
||||
return 0;
|
||||
caps = query_amp_caps(codec, pin, HDA_INPUT);
|
||||
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
|
||||
if (caps <= 1)
|
||||
return 0;
|
||||
label = hda_get_autocfg_input_label(codec, cfg, item);
|
||||
return add_volume(codec, label, 0,
|
||||
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
|
||||
}
|
||||
|
||||
static int build_input(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < spec->num_inputs; i++) {
|
||||
err = add_input_volume_control(codec, &spec->autocfg, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
|
|||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
hp_present ? 0 : PIN_OUT);
|
||||
}
|
||||
if (spec->board_config == CS420X_MBP55 ||
|
||||
if (spec->board_config == CS420X_MBP53 ||
|
||||
spec->board_config == CS420X_MBP55 ||
|
||||
spec->board_config == CS420X_IMAC27) {
|
||||
unsigned int gpio = hp_present ? 0x02 : 0x08;
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
|
@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
|
|||
hda_nid_t nid;
|
||||
unsigned int present;
|
||||
|
||||
nid = cfg->input_pins[spec->automic_idx];
|
||||
nid = cfg->inputs[spec->automic_idx].pin;
|
||||
present = snd_hda_jack_detect(codec, nid);
|
||||
if (present)
|
||||
change_cur_input(codec, spec->automic_idx, 0);
|
||||
else {
|
||||
unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
|
||||
AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
|
||||
change_cur_input(codec, imic, 0);
|
||||
}
|
||||
else
|
||||
change_cur_input(codec, !spec->automic_idx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
|
|||
unsigned int coef;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
unsigned int ctl;
|
||||
hda_nid_t pin = cfg->input_pins[i];
|
||||
if (!pin || !spec->adc_nid[i])
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
if (!spec->adc_nid[i])
|
||||
continue;
|
||||
/* set appropriate pin control and mute first */
|
||||
ctl = PIN_IN;
|
||||
if (i <= AUTO_PIN_FRONT_MIC) {
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC) {
|
||||
unsigned int caps = snd_hda_query_pin_caps(codec, pin);
|
||||
caps >>= AC_PINCAP_VREF_SHIFT;
|
||||
if (caps & AC_PINCAP_VREF_80)
|
||||
|
@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
static const char *cs420x_models[CS420X_MODELS] = {
|
||||
[CS420X_MBP53] = "mbp53",
|
||||
[CS420X_MBP55] = "mbp55",
|
||||
[CS420X_IMAC27] = "imac27",
|
||||
[CS420X_AUTO] = "auto",
|
||||
|
@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
|
|||
|
||||
|
||||
static struct snd_pci_quirk cs420x_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
|
||||
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
@ -1147,6 +1177,20 @@ struct cs_pincfg {
|
|||
u32 val;
|
||||
};
|
||||
|
||||
static struct cs_pincfg mbp53_pincfgs[] = {
|
||||
{ 0x09, 0x012b4050 },
|
||||
{ 0x0a, 0x90100141 },
|
||||
{ 0x0b, 0x90100140 },
|
||||
{ 0x0c, 0x018b3020 },
|
||||
{ 0x0d, 0x90a00110 },
|
||||
{ 0x0e, 0x400000f0 },
|
||||
{ 0x0f, 0x01cbe030 },
|
||||
{ 0x10, 0x014be060 },
|
||||
{ 0x12, 0x400000f0 },
|
||||
{ 0x15, 0x400000f0 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static struct cs_pincfg mbp55_pincfgs[] = {
|
||||
{ 0x09, 0x012b4030 },
|
||||
{ 0x0a, 0x90100121 },
|
||||
|
@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
|
|||
};
|
||||
|
||||
static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
|
||||
[CS420X_MBP53] = mbp53_pincfgs,
|
||||
[CS420X_MBP55] = mbp55_pincfgs,
|
||||
[CS420X_IMAC27] = imac27_pincfgs,
|
||||
};
|
||||
|
@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
|
|||
|
||||
switch (spec->board_config) {
|
||||
case CS420X_IMAC27:
|
||||
case CS420X_MBP53:
|
||||
case CS420X_MBP55:
|
||||
/* GPIO1 = headphones */
|
||||
/* GPIO3 = speakers */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue