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:
Linus Torvalds 2010-10-25 08:32:05 -07:00
commit 33081adf8b
479 changed files with 38198 additions and 19774 deletions

View File

@ -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
-----------------

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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")

View File

@ -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);
}
/*****************************************************************************

View File

@ -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;
}

View File

@ -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),

View File

@ -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);

View File

@ -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 */

View File

@ -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();

View File

@ -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

View File

@ -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 = {

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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)")

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -286,6 +286,7 @@
ssi@16100 {
compatible = "fsl,mpc8610-ssi";
status = "disabled";
cell-index = <1>;
reg = <0x16100 0x100>;
interrupt-parent = <&mpic>;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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");

View File

@ -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))

View File

@ -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",
},
};

View File

@ -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>

View File

@ -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.

View File

@ -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;

View File

@ -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);
};

View File

@ -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 */

View File

@ -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 */

View File

@ -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 *);
};

50
include/sound/max98088.h Normal file
View File

@ -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

View File

@ -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 -- */

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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_ */

View File

@ -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>

View File

@ -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) }

View File

@ -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

32
include/sound/wm8962.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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

1258
sound/drivers/aloop.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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) {

View File

@ -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++) {

View File

@ -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

View File

@ -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/

View File

@ -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);

View File

@ -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);

10
sound/isa/galaxy/Makefile Normal file
View File

@ -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

View File

@ -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"

111
sound/isa/galaxy/azt2316.c Normal file
View File

@ -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"

652
sound/isa/galaxy/galaxy.c Normal file
View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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
*/

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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