forked from Minki/linux
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: (294 commits) S3C64XX: Staticise platform data for PCM devices ASoC: Rename controls with a / in wm_hubs snd-fm801: autodetect SF64-PCR (tuner-only) card ALSA: tea575x-tuner: fix mute ASoC: au1x: dbdma2: plug memleak in pcm device creation error path ASoC: au1x: dbdma2: fix oops on soc device removal. ALSA: hda - Fix memory leaks in the previous patch ALSA: hda - Add ALC661/259, ALC892/888VD support ALSA: opti9xx: remove snd_opti9xx fields ALSA: aaci - Clean up duplicate code ALSA: usb - Fix mixer map for Hercules Gamesurround Muse Pocket LT ALSA: hda - Add position_fix quirk for HP dv3 ALSA: hda - Add a pin-fix for FSC Amilo Pi1505 ALSA: hda - Fix Cxt5047 test mode ASoC: pxa/raumfeld: adopt new snd_soc_dai_set_pll() API ASoC: sh: fsi: Add runtime PM support sh: ms7724se: Add runtime PM support for FSI ALSA: hda - Add a position_fix quirk for MSI Wind U115 ALSA: opti-miro: add PnP detection ALSA: opti-miro: separate comon probing code ...
This commit is contained in:
commit
a421018e8c
@ -798,6 +798,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
setup before initializing the codecs. This option is
|
||||
available only when CONFIG_SND_HDA_PATCH_LOADER=y is set.
|
||||
See HD-Audio.txt for details.
|
||||
beep_mode - Selects the beep registration mode (0=off, 1=on, 2=
|
||||
dynamic registration via mute switch on/off); the default
|
||||
value is set via CONFIG_SND_HDA_INPUT_BEEP_MODE kconfig.
|
||||
|
||||
[Single (global) options]
|
||||
single_cmd - Use single immediate commands to communicate with
|
||||
@ -1454,6 +1457,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
|
||||
Module for internal PC-Speaker.
|
||||
|
||||
nopcm - Disable PC-Speaker PCM sound. Only beeps remain.
|
||||
nforce_wa - enable NForce chipset workaround. Expect bad sound.
|
||||
|
||||
This module supports system beeps, some kind of PCM playback and
|
||||
@ -1631,7 +1635,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
Module snd-sscape
|
||||
-----------------
|
||||
|
||||
Module for ENSONIQ SoundScape PnP cards.
|
||||
Module for ENSONIQ SoundScape cards.
|
||||
|
||||
port - Port # (PnP setup)
|
||||
wss_port - WSS Port # (PnP setup)
|
||||
@ -1639,10 +1643,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
mpu_irq - MPU-401 IRQ # (PnP setup)
|
||||
dma - DMA # (PnP setup)
|
||||
dma2 - 2nd DMA # (PnP setup, -1 to disable)
|
||||
joystick - Enable gameport - 0 = disable (default), 1 = enable
|
||||
|
||||
This module supports multiple cards. ISA PnP must be enabled.
|
||||
You need sscape_ctl tool in alsa-tools package for loading
|
||||
the microcode.
|
||||
This module supports multiple cards.
|
||||
|
||||
The driver requires the firmware loader support on kernel.
|
||||
|
||||
Module snd-sun-amd7930 (on sparc only)
|
||||
--------------------------------------
|
||||
|
@ -18,8 +18,9 @@ SOURCE:
|
||||
Master
|
||||
Master Mono
|
||||
Hardware Master
|
||||
Speaker (internal speaker)
|
||||
Headphone
|
||||
PC Speaker
|
||||
Beep (beep generator)
|
||||
Phone
|
||||
Phone Input
|
||||
Phone Output
|
||||
|
@ -391,6 +391,7 @@ STAC92HD83*
|
||||
ref Reference board
|
||||
mic-ref Reference board with power management for ports
|
||||
dell-s14 Dell laptop
|
||||
hp HP laptops with (inverted) mute-LED
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9872
|
||||
|
@ -51,6 +51,14 @@ struct snd_platform_data {
|
||||
u32 rx_dma_offset;
|
||||
enum dma_event_q eventq_no; /* event queue number */
|
||||
unsigned int codec_fmt;
|
||||
/*
|
||||
* Allowing this is more efficient and eliminates left and right swaps
|
||||
* caused by underruns, but will swap the left and right channels
|
||||
* when compared to previous behavior.
|
||||
*/
|
||||
unsigned enable_channel_combine:1;
|
||||
unsigned sram_size_playback;
|
||||
unsigned sram_size_capture;
|
||||
|
||||
/* McASP specific fields */
|
||||
int tdm_slots;
|
||||
|
@ -410,6 +410,15 @@ static struct regulator_init_data sdp3430_vpll2 = {
|
||||
.consumer_supplies = &sdp3430_vdvi_supply,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data sdp3430_audio = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data sdp3430_codec = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &sdp3430_audio,
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data sdp3430_twldata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
@ -420,6 +429,7 @@ static struct twl4030_platform_data sdp3430_twldata = {
|
||||
.madc = &sdp3430_madc_data,
|
||||
.keypad = &sdp3430_kp_data,
|
||||
.usb = &sdp3430_usb_data,
|
||||
.codec = &sdp3430_codec,
|
||||
|
||||
.vaux1 = &sdp3430_vaux1,
|
||||
.vaux2 = &sdp3430_vaux2,
|
||||
|
@ -254,6 +254,15 @@ static struct twl4030_usb_data beagle_usb_data = {
|
||||
.usb_mode = T2_USB_MODE_ULPI,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data beagle_audio_data = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data beagle_codec_data = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &beagle_audio_data,
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data beagle_twldata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
@ -261,6 +270,7 @@ static struct twl4030_platform_data beagle_twldata = {
|
||||
/* platform_data for children goes here */
|
||||
.usb = &beagle_usb_data,
|
||||
.gpio = &beagle_gpio_data,
|
||||
.codec = &beagle_codec_data,
|
||||
.vmmc1 = &beagle_vmmc1,
|
||||
.vsim = &beagle_vsim,
|
||||
.vdac = &beagle_vdac,
|
||||
|
@ -194,6 +194,15 @@ static struct twl4030_madc_platform_data omap3evm_madc_data = {
|
||||
.irq_line = 1,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data omap3evm_audio_data = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data omap3evm_codec_data = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &omap3evm_audio_data,
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data omap3evm_twldata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
@ -203,6 +212,7 @@ static struct twl4030_platform_data omap3evm_twldata = {
|
||||
.madc = &omap3evm_madc_data,
|
||||
.usb = &omap3evm_usb_data,
|
||||
.gpio = &omap3evm_gpio_data,
|
||||
.codec = &omap3evm_codec_data,
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
|
||||
|
@ -281,11 +281,21 @@ static struct twl4030_usb_data omap3pandora_usb_data = {
|
||||
.usb_mode = T2_USB_MODE_ULPI,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data omap3pandora_audio_data = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data omap3pandora_codec_data = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &omap3pandora_audio_data,
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data omap3pandora_twldata = {
|
||||
.irq_base = TWL4030_IRQ_BASE,
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
.gpio = &omap3pandora_gpio_data,
|
||||
.usb = &omap3pandora_usb_data,
|
||||
.codec = &omap3pandora_codec_data,
|
||||
.vmmc1 = &pandora_vmmc1,
|
||||
.vmmc2 = &pandora_vmmc2,
|
||||
.keypad = &pandora_kp_data,
|
||||
|
@ -329,6 +329,15 @@ static struct regulator_init_data overo_vmmc1 = {
|
||||
.consumer_supplies = &overo_vmmc1_supply,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data overo_audio_data = {
|
||||
.audio_mclk = 26000000,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_data overo_codec_data = {
|
||||
.audio_mclk = 26000000,
|
||||
.audio = &overo_audio_data,
|
||||
};
|
||||
|
||||
/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
|
||||
|
||||
static struct twl4030_platform_data overo_twldata = {
|
||||
@ -336,6 +345,7 @@ static struct twl4030_platform_data overo_twldata = {
|
||||
.irq_end = TWL4030_IRQ_END,
|
||||
.gpio = &overo_gpio_data,
|
||||
.usb = &overo_usb_data,
|
||||
.codec = &overo_codec_data,
|
||||
.vmmc1 = &overo_vmmc1,
|
||||
};
|
||||
|
||||
|
@ -230,6 +230,15 @@ 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,
|
||||
@ -240,6 +249,7 @@ static struct twl4030_platform_data zoom2_twldata = {
|
||||
.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,
|
||||
|
@ -48,6 +48,8 @@
|
||||
#define S3C64XX_PA_IIS1 (0x7F003000)
|
||||
#define S3C64XX_PA_TIMER (0x7F006000)
|
||||
#define S3C64XX_PA_IIC0 (0x7F004000)
|
||||
#define S3C64XX_PA_PCM0 (0x7F009000)
|
||||
#define S3C64XX_PA_PCM1 (0x7F00A000)
|
||||
#define S3C64XX_PA_IISV4 (0x7F00D000)
|
||||
#define S3C64XX_PA_IIC1 (0x7F00F000)
|
||||
|
||||
|
@ -1,45 +1,17 @@
|
||||
/* arch/arm/mach-s3c2410/include/mach/audio.h
|
||||
/* arch/arm/plat-s3c/include/plat/audio.h
|
||||
*
|
||||
* Copyright (c) 2004-2005 Simtec Electronics
|
||||
* http://www.simtec.co.uk/products/SWLINUX/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX - Audio platfrom_device info
|
||||
* Copyright (c) 2009 Samsung Electronics Co. Ltd
|
||||
* Author: Jaswinder Singh <jassi.brar@samsung.com>
|
||||
*
|
||||
* 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 __ASM_ARCH_AUDIO_H
|
||||
#define __ASM_ARCH_AUDIO_H __FILE__
|
||||
|
||||
/* struct s3c24xx_iis_ops
|
||||
*
|
||||
* called from the s3c24xx audio core to deal with the architecture
|
||||
* or the codec's setup and control.
|
||||
*
|
||||
* the pointer to itself is passed through in case the caller wants to
|
||||
* embed this in an larger structure for easy reference to it's context.
|
||||
*/
|
||||
|
||||
struct s3c24xx_iis_ops {
|
||||
struct module *owner;
|
||||
|
||||
int (*startup)(struct s3c24xx_iis_ops *me);
|
||||
void (*shutdown)(struct s3c24xx_iis_ops *me);
|
||||
int (*suspend)(struct s3c24xx_iis_ops *me);
|
||||
int (*resume)(struct s3c24xx_iis_ops *me);
|
||||
|
||||
int (*open)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
|
||||
int (*close)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
|
||||
int (*prepare)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm, struct snd_pcm_runtime *rt);
|
||||
/**
|
||||
* struct s3c_audio_pdata - common platform data for audio device drivers
|
||||
* @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
|
||||
*/
|
||||
struct s3c_audio_pdata {
|
||||
int (*cfg_gpio)(struct platform_device *);
|
||||
};
|
||||
|
||||
struct s3c24xx_platdata_iis {
|
||||
const char *codec_clk;
|
||||
struct s3c24xx_iis_ops *ops;
|
||||
int (*match_dev)(struct device *dev);
|
||||
};
|
||||
|
||||
#endif /* __ASM_ARCH_AUDIO_H */
|
||||
|
@ -28,6 +28,9 @@ extern struct platform_device s3c64xx_device_iis0;
|
||||
extern struct platform_device s3c64xx_device_iis1;
|
||||
extern struct platform_device s3c64xx_device_iisv4;
|
||||
|
||||
extern struct platform_device s3c64xx_device_pcm0;
|
||||
extern struct platform_device s3c64xx_device_pcm1;
|
||||
|
||||
extern struct platform_device s3c_device_fb;
|
||||
extern struct platform_device s3c_device_usb;
|
||||
extern struct platform_device s3c_device_lcd;
|
||||
|
@ -67,6 +67,8 @@
|
||||
#define S3C2412_IISMOD_BCLK_MASK (3 << 1)
|
||||
#define S3C2412_IISMOD_8BIT (1 << 0)
|
||||
|
||||
#define S3C64XX_IISMOD_CDCLKCON (1 << 12)
|
||||
|
||||
#define S3C2412_IISPSR_PSREN (1 << 15)
|
||||
|
||||
#define S3C2412_IISFIC_TXFLUSH (1 << 15)
|
||||
|
@ -15,9 +15,14 @@
|
||||
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include <plat/devs.h>
|
||||
|
||||
#include <plat/audio.h>
|
||||
#include <plat/gpio-bank-d.h>
|
||||
#include <plat/gpio-bank-e.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
||||
static struct resource s3c64xx_iis0_resource[] = {
|
||||
[0] = {
|
||||
@ -66,3 +71,97 @@ struct platform_device s3c64xx_device_iisv4 = {
|
||||
.resource = s3c64xx_iisv4_resource,
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_iisv4);
|
||||
|
||||
|
||||
/* PCM Controller platform_devices */
|
||||
|
||||
static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
switch (pdev->id) {
|
||||
case 0:
|
||||
s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
|
||||
break;
|
||||
case 1:
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
|
||||
s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "Invalid PCM Controller number!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct resource s3c64xx_pcm0_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C64XX_PA_PCM0,
|
||||
.end = S3C64XX_PA_PCM0 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_PCM0_TX,
|
||||
.end = DMACH_PCM0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_PCM0_RX,
|
||||
.end = DMACH_PCM0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_pcm0_pdata = {
|
||||
.cfg_gpio = s3c64xx_pcm_cfg_gpio,
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_pcm0 = {
|
||||
.name = "samsung-pcm",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_pcm0_resource),
|
||||
.resource = s3c64xx_pcm0_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_pcm0_pdata,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_pcm0);
|
||||
|
||||
static struct resource s3c64xx_pcm1_resource[] = {
|
||||
[0] = {
|
||||
.start = S3C64XX_PA_PCM1,
|
||||
.end = S3C64XX_PA_PCM1 + 0x100 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMACH_PCM1_TX,
|
||||
.end = DMACH_PCM1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMACH_PCM1_RX,
|
||||
.end = DMACH_PCM1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_audio_pdata s3c_pcm1_pdata = {
|
||||
.cfg_gpio = s3c64xx_pcm_cfg_gpio,
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_pcm1 = {
|
||||
.name = "samsung-pcm",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(s3c64xx_pcm1_resource),
|
||||
.resource = s3c64xx_pcm1_resource,
|
||||
.dev = {
|
||||
.platform_data = &s3c_pcm1_pdata,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(s3c64xx_device_pcm1);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <sound/sh_dac_audio.h>
|
||||
#include <asm/hd64461.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/hp6xx.h>
|
||||
@ -51,9 +52,63 @@ static struct platform_device jornadakbd_device = {
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void dac_audio_start(struct dac_audio_pdata *pdata)
|
||||
{
|
||||
u16 v;
|
||||
u8 v8;
|
||||
|
||||
/* HP Jornada 680/690 speaker on */
|
||||
v = inw(HD64461_GPADR);
|
||||
v &= ~HD64461_GPADR_SPEAKER;
|
||||
outw(v, HD64461_GPADR);
|
||||
|
||||
/* HP Palmtop 620lx/660lx speaker on */
|
||||
v8 = inb(PKDR);
|
||||
v8 &= ~PKDR_SPEAKER;
|
||||
outb(v8, PKDR);
|
||||
|
||||
sh_dac_enable(pdata->channel);
|
||||
}
|
||||
|
||||
static void dac_audio_stop(struct dac_audio_pdata *pdata)
|
||||
{
|
||||
u16 v;
|
||||
u8 v8;
|
||||
|
||||
/* HP Jornada 680/690 speaker off */
|
||||
v = inw(HD64461_GPADR);
|
||||
v |= HD64461_GPADR_SPEAKER;
|
||||
outw(v, HD64461_GPADR);
|
||||
|
||||
/* HP Palmtop 620lx/660lx speaker off */
|
||||
v8 = inb(PKDR);
|
||||
v8 |= PKDR_SPEAKER;
|
||||
outb(v8, PKDR);
|
||||
|
||||
sh_dac_output(0, pdata->channel);
|
||||
sh_dac_disable(pdata->channel);
|
||||
}
|
||||
|
||||
static struct dac_audio_pdata dac_audio_platform_data = {
|
||||
.buffer_size = 64000,
|
||||
.channel = 1,
|
||||
.start = dac_audio_start,
|
||||
.stop = dac_audio_stop,
|
||||
};
|
||||
|
||||
static struct platform_device dac_audio_device = {
|
||||
.name = "dac_audio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &dac_audio_platform_data,
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static struct platform_device *hp6xx_devices[] __initdata = {
|
||||
&cf_ide_device,
|
||||
&jornadakbd_device,
|
||||
&dac_audio_device,
|
||||
};
|
||||
|
||||
static void __init hp6xx_init_irq(void)
|
||||
|
@ -313,6 +313,9 @@ static struct platform_device fsi_device = {
|
||||
.dev = {
|
||||
.platform_data = &fsi_info,
|
||||
},
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_SPU, /* FSI needs SPU hwblk */
|
||||
},
|
||||
};
|
||||
|
||||
/* KEYSC in SoC (Needs SW33-2 set to ON) */
|
||||
|
@ -29,6 +29,9 @@
|
||||
|
||||
#define PKDR_LED_GREEN 0x10
|
||||
|
||||
/* HP Palmtop 620lx/660lx speaker on/off */
|
||||
#define PKDR_SPEAKER 0x20
|
||||
|
||||
#define SCPDR_TS_SCAN_ENABLE 0x20
|
||||
#define SCPDR_TS_SCAN_Y 0x02
|
||||
#define SCPDR_TS_SCAN_X 0x01
|
||||
@ -42,6 +45,7 @@
|
||||
#define ADC_CHANNEL_BACKUP 4
|
||||
#define ADC_CHANNEL_CHARGE 5
|
||||
|
||||
/* HP Jornada 680/690 speaker on/off */
|
||||
#define HD64461_GPADR_SPEAKER 0x01
|
||||
#define HD64461_GPADR_PCMCIA0 (0x02|0x08)
|
||||
|
||||
|
@ -195,6 +195,24 @@ config RADIO_MAESTRO
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-maestro.
|
||||
|
||||
config RADIO_MIROPCM20
|
||||
tristate "miroSOUND PCM20 radio"
|
||||
depends on ISA && VIDEO_V4L2
|
||||
select SND_MIRO
|
||||
---help---
|
||||
Choose Y here if you have this FM radio card. You also need to enable
|
||||
the ALSA sound system. This choice automatically selects the ALSA
|
||||
sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
|
||||
is required for the radio-miropcm20.
|
||||
|
||||
In order to control your radio card, you will need to use programs
|
||||
that are compatible with the Video For Linux API. Information on
|
||||
this API and pointers to "v4l" programs may be found at
|
||||
<file:Documentation/video4linux/API.html>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-miropcm20.
|
||||
|
||||
config RADIO_SF16FMI
|
||||
tristate "SF16FMI Radio"
|
||||
depends on ISA && VIDEO_V4L2
|
||||
|
@ -18,6 +18,7 @@ obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
|
||||
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
|
||||
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
|
||||
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
|
||||
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
|
||||
obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
||||
obj-$(CONFIG_RADIO_SI470X) += si470x/
|
||||
obj-$(CONFIG_USB_MR800) += radio-mr800.o
|
||||
|
270
drivers/media/radio/radio-miropcm20.c
Normal file
270
drivers/media/radio/radio-miropcm20.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* Miro PCM20 radio driver for Linux radio support
|
||||
* (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
|
||||
* Thanks to Norberto Pellici for the ACI device interface specification
|
||||
* The API part is based on the radiotrack driver by M. Kirkwood
|
||||
* This driver relies on the aci mixer provided by the snd-miro
|
||||
* ALSA driver.
|
||||
* Look there for further info...
|
||||
*/
|
||||
|
||||
/* What ever you think about the ACI, version 0x07 is not very well!
|
||||
* I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
|
||||
* conditions... Robert
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <sound/aci.h>
|
||||
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0);
|
||||
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
|
||||
|
||||
static int mono;
|
||||
module_param(mono, bool, 0);
|
||||
MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
|
||||
|
||||
struct pcm20 {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device vdev;
|
||||
unsigned long freq;
|
||||
int muted;
|
||||
struct snd_miro_aci *aci;
|
||||
};
|
||||
|
||||
static struct pcm20 pcm20_card = {
|
||||
.freq = 87*16000,
|
||||
.muted = 1,
|
||||
};
|
||||
|
||||
static int pcm20_mute(struct pcm20 *dev, unsigned char mute)
|
||||
{
|
||||
dev->muted = mute;
|
||||
return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1);
|
||||
}
|
||||
|
||||
static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo)
|
||||
{
|
||||
return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1);
|
||||
}
|
||||
|
||||
static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
|
||||
{
|
||||
unsigned char freql;
|
||||
unsigned char freqh;
|
||||
struct snd_miro_aci *aci = dev->aci;
|
||||
|
||||
dev->freq = freq;
|
||||
|
||||
freq /= 160;
|
||||
if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
|
||||
freq /= 10; /* I don't know exactly which version
|
||||
* needs this hack */
|
||||
freql = freq & 0xff;
|
||||
freqh = freq >> 8;
|
||||
|
||||
pcm20_stereo(dev, !mono);
|
||||
return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations pcm20_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
|
||||
strlcpy(v->card, "Miro PCM20", sizeof(v->card));
|
||||
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
|
||||
v->version = 0x1;
|
||||
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index) /* Only 1 tuner */
|
||||
return -EINVAL;
|
||||
strlcpy(v->name, "FM", sizeof(v->name));
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = 87*16000;
|
||||
v->rangehigh = 108*16000;
|
||||
v->signal = 0xffff;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return v->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
if (f->tuner != 0)
|
||||
return -EINVAL;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = dev->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
|
||||
return -EINVAL;
|
||||
|
||||
dev->freq = f->frequency;
|
||||
pcm20_setfreq(dev, f->frequency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
switch (qc->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = dev->muted;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct pcm20 *dev = video_drvdata(file);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
pcm20_mute(dev, ctrl->value);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
return i ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
a->index = 0;
|
||||
strlcpy(a->name, "Radio", sizeof(a->name));
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
return a->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
};
|
||||
|
||||
static int __init pcm20_init(void)
|
||||
{
|
||||
struct pcm20 *dev = &pcm20_card;
|
||||
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
|
||||
int res;
|
||||
|
||||
dev->aci = snd_aci_get_aci();
|
||||
if (dev->aci == NULL) {
|
||||
v4l2_err(v4l2_dev,
|
||||
"you must load the snd-miro driver first!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
|
||||
|
||||
|
||||
res = v4l2_device_register(NULL, v4l2_dev);
|
||||
if (res < 0) {
|
||||
v4l2_err(v4l2_dev, "could not register v4l2_device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
|
||||
dev->vdev.v4l2_dev = v4l2_dev;
|
||||
dev->vdev.fops = &pcm20_fops;
|
||||
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
|
||||
dev->vdev.release = video_device_release_empty;
|
||||
video_set_drvdata(&dev->vdev, dev);
|
||||
|
||||
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
|
||||
goto fail;
|
||||
|
||||
v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
|
||||
return 0;
|
||||
fail:
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt");
|
||||
MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static void __exit pcm20_cleanup(void)
|
||||
{
|
||||
struct pcm20 *dev = &pcm20_card;
|
||||
|
||||
video_unregister_device(&dev->vdev);
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
}
|
||||
|
||||
module_init(pcm20_init);
|
||||
module_exit(pcm20_cleanup);
|
@ -121,6 +121,12 @@ config TWL4030_POWER
|
||||
and load scripts controling which resources are switched off/on
|
||||
or reset when a sleep, wakeup or warm reset event occurs.
|
||||
|
||||
config TWL4030_CODEC
|
||||
bool
|
||||
depends on TWL4030_CORE
|
||||
select MFD_CORE
|
||||
default n
|
||||
|
||||
config MFD_TMIO
|
||||
bool
|
||||
default n
|
||||
|
@ -26,6 +26,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
|
||||
|
||||
obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o
|
||||
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
|
||||
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
|
||||
|
||||
obj-$(CONFIG_MFD_MC13783) += mc13783-core.o
|
||||
|
||||
|
276
drivers/mfd/twl4030-codec.c
Normal file
276
drivers/mfd/twl4030-codec.c
Normal file
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* MFD driver for twl4030 codec submodule
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
*
|
||||
* Copyright: (C) 2009 Nokia Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/twl4030.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
|
||||
#define TWL4030_CODEC_CELLS 2
|
||||
|
||||
static struct platform_device *twl4030_codec_dev;
|
||||
|
||||
struct twl4030_codec_resource {
|
||||
int request_count;
|
||||
u8 reg;
|
||||
u8 mask;
|
||||
};
|
||||
|
||||
struct twl4030_codec {
|
||||
unsigned int audio_mclk;
|
||||
struct mutex mutex;
|
||||
struct twl4030_codec_resource resource[TWL4030_CODEC_RES_MAX];
|
||||
struct mfd_cell cells[TWL4030_CODEC_CELLS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Modify the resource, the function returns the content of the register
|
||||
* after the modification.
|
||||
*/
|
||||
static int twl4030_codec_set_resource(enum twl4030_codec_res id, int enable)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
|
||||
u8 val;
|
||||
|
||||
twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
|
||||
codec->resource[id].reg);
|
||||
|
||||
if (enable)
|
||||
val |= codec->resource[id].mask;
|
||||
else
|
||||
val &= ~codec->resource[id].mask;
|
||||
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
val, codec->resource[id].reg);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int twl4030_codec_get_resource(enum twl4030_codec_res id)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
|
||||
u8 val;
|
||||
|
||||
twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val,
|
||||
codec->resource[id].reg);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the resource.
|
||||
* The function returns with error or the content of the register
|
||||
*/
|
||||
int twl4030_codec_enable_resource(enum twl4030_codec_res id)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
|
||||
int val;
|
||||
|
||||
if (id >= TWL4030_CODEC_RES_MAX) {
|
||||
dev_err(&twl4030_codec_dev->dev,
|
||||
"Invalid resource ID (%u)\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
if (!codec->resource[id].request_count)
|
||||
/* Resource was disabled, enable it */
|
||||
val = twl4030_codec_set_resource(id, 1);
|
||||
else
|
||||
val = twl4030_codec_get_resource(id);
|
||||
|
||||
codec->resource[id].request_count++;
|
||||
mutex_unlock(&codec->mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_codec_enable_resource);
|
||||
|
||||
/*
|
||||
* Disable the resource.
|
||||
* The function returns with error or the content of the register
|
||||
*/
|
||||
int twl4030_codec_disable_resource(unsigned id)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
|
||||
int val;
|
||||
|
||||
if (id >= TWL4030_CODEC_RES_MAX) {
|
||||
dev_err(&twl4030_codec_dev->dev,
|
||||
"Invalid resource ID (%u)\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
if (!codec->resource[id].request_count) {
|
||||
dev_err(&twl4030_codec_dev->dev,
|
||||
"Resource has been disabled already (%u)\n", id);
|
||||
mutex_unlock(&codec->mutex);
|
||||
return -EPERM;
|
||||
}
|
||||
codec->resource[id].request_count--;
|
||||
|
||||
if (!codec->resource[id].request_count)
|
||||
/* Resource can be disabled now */
|
||||
val = twl4030_codec_set_resource(id, 0);
|
||||
else
|
||||
val = twl4030_codec_get_resource(id);
|
||||
|
||||
mutex_unlock(&codec->mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_codec_disable_resource);
|
||||
|
||||
unsigned int twl4030_codec_get_mclk(void)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(twl4030_codec_dev);
|
||||
|
||||
return codec->audio_mclk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_codec_get_mclk);
|
||||
|
||||
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec *codec;
|
||||
struct twl4030_codec_data *pdata = pdev->dev.platform_data;
|
||||
struct mfd_cell *cell = NULL;
|
||||
int ret, childs = 0;
|
||||
u8 val;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "Platform data is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Configure APLL_INFREQ and disable APLL if enabled */
|
||||
val = 0;
|
||||
switch (pdata->audio_mclk) {
|
||||
case 19200000:
|
||||
val |= TWL4030_APLL_INFREQ_19200KHZ;
|
||||
break;
|
||||
case 26000000:
|
||||
val |= TWL4030_APLL_INFREQ_26000KHZ;
|
||||
break;
|
||||
case 38400000:
|
||||
val |= TWL4030_APLL_INFREQ_38400KHZ;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Invalid audio_mclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
val, TWL4030_REG_APLL_CTL);
|
||||
|
||||
codec = kzalloc(sizeof(struct twl4030_codec), GFP_KERNEL);
|
||||
if (!codec)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, codec);
|
||||
|
||||
twl4030_codec_dev = pdev;
|
||||
mutex_init(&codec->mutex);
|
||||
codec->audio_mclk = pdata->audio_mclk;
|
||||
|
||||
/* Codec power */
|
||||
codec->resource[TWL4030_CODEC_RES_POWER].reg = TWL4030_REG_CODEC_MODE;
|
||||
codec->resource[TWL4030_CODEC_RES_POWER].mask = TWL4030_CODECPDZ;
|
||||
|
||||
/* PLL */
|
||||
codec->resource[TWL4030_CODEC_RES_APLL].reg = TWL4030_REG_APLL_CTL;
|
||||
codec->resource[TWL4030_CODEC_RES_APLL].mask = TWL4030_APLL_EN;
|
||||
|
||||
if (pdata->audio) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030_codec_audio";
|
||||
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->platform_data = pdata->vibra;
|
||||
cell->data_size = sizeof(*pdata->vibra);
|
||||
childs++;
|
||||
}
|
||||
|
||||
if (childs)
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, codec->cells,
|
||||
childs, NULL, 0);
|
||||
else {
|
||||
dev_err(&pdev->dev, "No platform data found for childs\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(codec);
|
||||
twl4030_codec_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec *codec = platform_get_drvdata(pdev);
|
||||
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(codec);
|
||||
twl4030_codec_dev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:twl4030_codec");
|
||||
|
||||
static struct platform_driver twl4030_codec_driver = {
|
||||
.probe = twl4030_codec_probe,
|
||||
.remove = __devexit_p(twl4030_codec_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "twl4030_codec",
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit twl4030_codec_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl4030_codec_driver);
|
||||
}
|
||||
module_init(twl4030_codec_init);
|
||||
|
||||
static void __devexit twl4030_codec_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl4030_codec_driver);
|
||||
}
|
||||
module_exit(twl4030_codec_exit);
|
||||
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -114,6 +114,12 @@
|
||||
#define twl_has_watchdog() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE)
|
||||
#define twl_has_codec() true
|
||||
#else
|
||||
#define twl_has_codec() false
|
||||
#endif
|
||||
|
||||
/* Triton Core internal information (BEGIN) */
|
||||
|
||||
/* Last - for index max*/
|
||||
@ -601,6 +607,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_codec() && pdata->codec) {
|
||||
child = add_child(1, "twl4030_codec",
|
||||
pdata->codec, sizeof(*pdata->codec),
|
||||
false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_regulator()) {
|
||||
/*
|
||||
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
|
||||
@ -763,7 +777,7 @@ static int twl4030_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
|
||||
static int
|
||||
static int __init
|
||||
twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
int status;
|
||||
|
@ -401,6 +401,24 @@ struct twl4030_power_data {
|
||||
|
||||
extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
|
||||
|
||||
struct twl4030_codec_audio_data {
|
||||
unsigned int audio_mclk;
|
||||
unsigned int ramp_delay_value;
|
||||
unsigned int hs_extmute:1;
|
||||
void (*set_hs_extmute)(int mute);
|
||||
};
|
||||
|
||||
struct twl4030_codec_vibra_data {
|
||||
unsigned int audio_mclk;
|
||||
unsigned int coexist;
|
||||
};
|
||||
|
||||
struct twl4030_codec_data {
|
||||
unsigned int audio_mclk;
|
||||
struct twl4030_codec_audio_data *audio;
|
||||
struct twl4030_codec_vibra_data *vibra;
|
||||
};
|
||||
|
||||
struct twl4030_platform_data {
|
||||
unsigned irq_base, irq_end;
|
||||
struct twl4030_bci_platform_data *bci;
|
||||
@ -409,6 +427,7 @@ struct twl4030_platform_data {
|
||||
struct twl4030_keypad_data *keypad;
|
||||
struct twl4030_usb_data *usb;
|
||||
struct twl4030_power_data *power;
|
||||
struct twl4030_codec_data *codec;
|
||||
|
||||
/* LDO regulators */
|
||||
struct regulator_init_data *vdac;
|
||||
|
272
include/linux/mfd/twl4030-codec.h
Normal file
272
include/linux/mfd/twl4030-codec.h
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* MFD driver for twl4030 codec submodule
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
*
|
||||
* Copyright: (C) 2009 Nokia Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TWL4030_CODEC_H__
|
||||
#define __TWL4030_CODEC_H__
|
||||
|
||||
/* Codec registers */
|
||||
#define TWL4030_REG_CODEC_MODE 0x01
|
||||
#define TWL4030_REG_OPTION 0x02
|
||||
#define TWL4030_REG_UNKNOWN 0x03
|
||||
#define TWL4030_REG_MICBIAS_CTL 0x04
|
||||
#define TWL4030_REG_ANAMICL 0x05
|
||||
#define TWL4030_REG_ANAMICR 0x06
|
||||
#define TWL4030_REG_AVADC_CTL 0x07
|
||||
#define TWL4030_REG_ADCMICSEL 0x08
|
||||
#define TWL4030_REG_DIGMIXING 0x09
|
||||
#define TWL4030_REG_ATXL1PGA 0x0A
|
||||
#define TWL4030_REG_ATXR1PGA 0x0B
|
||||
#define TWL4030_REG_AVTXL2PGA 0x0C
|
||||
#define TWL4030_REG_AVTXR2PGA 0x0D
|
||||
#define TWL4030_REG_AUDIO_IF 0x0E
|
||||
#define TWL4030_REG_VOICE_IF 0x0F
|
||||
#define TWL4030_REG_ARXR1PGA 0x10
|
||||
#define TWL4030_REG_ARXL1PGA 0x11
|
||||
#define TWL4030_REG_ARXR2PGA 0x12
|
||||
#define TWL4030_REG_ARXL2PGA 0x13
|
||||
#define TWL4030_REG_VRXPGA 0x14
|
||||
#define TWL4030_REG_VSTPGA 0x15
|
||||
#define TWL4030_REG_VRX2ARXPGA 0x16
|
||||
#define TWL4030_REG_AVDAC_CTL 0x17
|
||||
#define TWL4030_REG_ARX2VTXPGA 0x18
|
||||
#define TWL4030_REG_ARXL1_APGA_CTL 0x19
|
||||
#define TWL4030_REG_ARXR1_APGA_CTL 0x1A
|
||||
#define TWL4030_REG_ARXL2_APGA_CTL 0x1B
|
||||
#define TWL4030_REG_ARXR2_APGA_CTL 0x1C
|
||||
#define TWL4030_REG_ATX2ARXPGA 0x1D
|
||||
#define TWL4030_REG_BT_IF 0x1E
|
||||
#define TWL4030_REG_BTPGA 0x1F
|
||||
#define TWL4030_REG_BTSTPGA 0x20
|
||||
#define TWL4030_REG_EAR_CTL 0x21
|
||||
#define TWL4030_REG_HS_SEL 0x22
|
||||
#define TWL4030_REG_HS_GAIN_SET 0x23
|
||||
#define TWL4030_REG_HS_POPN_SET 0x24
|
||||
#define TWL4030_REG_PREDL_CTL 0x25
|
||||
#define TWL4030_REG_PREDR_CTL 0x26
|
||||
#define TWL4030_REG_PRECKL_CTL 0x27
|
||||
#define TWL4030_REG_PRECKR_CTL 0x28
|
||||
#define TWL4030_REG_HFL_CTL 0x29
|
||||
#define TWL4030_REG_HFR_CTL 0x2A
|
||||
#define TWL4030_REG_ALC_CTL 0x2B
|
||||
#define TWL4030_REG_ALC_SET1 0x2C
|
||||
#define TWL4030_REG_ALC_SET2 0x2D
|
||||
#define TWL4030_REG_BOOST_CTL 0x2E
|
||||
#define TWL4030_REG_SOFTVOL_CTL 0x2F
|
||||
#define TWL4030_REG_DTMF_FREQSEL 0x30
|
||||
#define TWL4030_REG_DTMF_TONEXT1H 0x31
|
||||
#define TWL4030_REG_DTMF_TONEXT1L 0x32
|
||||
#define TWL4030_REG_DTMF_TONEXT2H 0x33
|
||||
#define TWL4030_REG_DTMF_TONEXT2L 0x34
|
||||
#define TWL4030_REG_DTMF_TONOFF 0x35
|
||||
#define TWL4030_REG_DTMF_WANONOFF 0x36
|
||||
#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37
|
||||
#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38
|
||||
#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39
|
||||
#define TWL4030_REG_APLL_CTL 0x3A
|
||||
#define TWL4030_REG_DTMF_CTL 0x3B
|
||||
#define TWL4030_REG_DTMF_PGA_CTL2 0x3C
|
||||
#define TWL4030_REG_DTMF_PGA_CTL1 0x3D
|
||||
#define TWL4030_REG_MISC_SET_1 0x3E
|
||||
#define TWL4030_REG_PCMBTMUX 0x3F
|
||||
#define TWL4030_REG_RX_PATH_SEL 0x43
|
||||
#define TWL4030_REG_VDL_APGA_CTL 0x44
|
||||
#define TWL4030_REG_VIBRA_CTL 0x45
|
||||
#define TWL4030_REG_VIBRA_SET 0x46
|
||||
#define TWL4030_REG_VIBRA_PWM_SET 0x47
|
||||
#define TWL4030_REG_ANAMIC_GAIN 0x48
|
||||
#define TWL4030_REG_MISC_SET_2 0x49
|
||||
|
||||
/* Bitfield Definitions */
|
||||
|
||||
/* TWL4030_CODEC_MODE (0x01) Fields */
|
||||
#define TWL4030_APLL_RATE 0xF0
|
||||
#define TWL4030_APLL_RATE_8000 0x00
|
||||
#define TWL4030_APLL_RATE_11025 0x10
|
||||
#define TWL4030_APLL_RATE_12000 0x20
|
||||
#define TWL4030_APLL_RATE_16000 0x40
|
||||
#define TWL4030_APLL_RATE_22050 0x50
|
||||
#define TWL4030_APLL_RATE_24000 0x60
|
||||
#define TWL4030_APLL_RATE_32000 0x80
|
||||
#define TWL4030_APLL_RATE_44100 0x90
|
||||
#define TWL4030_APLL_RATE_48000 0xA0
|
||||
#define TWL4030_APLL_RATE_96000 0xE0
|
||||
#define TWL4030_SEL_16K 0x08
|
||||
#define TWL4030_CODECPDZ 0x02
|
||||
#define TWL4030_OPT_MODE 0x01
|
||||
#define TWL4030_OPTION_1 (1 << 0)
|
||||
#define TWL4030_OPTION_2 (0 << 0)
|
||||
|
||||
/* TWL4030_OPTION (0x02) Fields */
|
||||
#define TWL4030_ATXL1_EN (1 << 0)
|
||||
#define TWL4030_ATXR1_EN (1 << 1)
|
||||
#define TWL4030_ATXL2_VTXL_EN (1 << 2)
|
||||
#define TWL4030_ATXR2_VTXR_EN (1 << 3)
|
||||
#define TWL4030_ARXL1_VRX_EN (1 << 4)
|
||||
#define TWL4030_ARXR1_EN (1 << 5)
|
||||
#define TWL4030_ARXL2_EN (1 << 6)
|
||||
#define TWL4030_ARXR2_EN (1 << 7)
|
||||
|
||||
/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
|
||||
#define TWL4030_MICBIAS2_CTL 0x40
|
||||
#define TWL4030_MICBIAS1_CTL 0x20
|
||||
#define TWL4030_HSMICBIAS_EN 0x04
|
||||
#define TWL4030_MICBIAS2_EN 0x02
|
||||
#define TWL4030_MICBIAS1_EN 0x01
|
||||
|
||||
/* ANAMICL (0x05) Fields */
|
||||
#define TWL4030_CNCL_OFFSET_START 0x80
|
||||
#define TWL4030_OFFSET_CNCL_SEL 0x60
|
||||
#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00
|
||||
#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20
|
||||
#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40
|
||||
#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60
|
||||
#define TWL4030_MICAMPL_EN 0x10
|
||||
#define TWL4030_CKMIC_EN 0x08
|
||||
#define TWL4030_AUXL_EN 0x04
|
||||
#define TWL4030_HSMIC_EN 0x02
|
||||
#define TWL4030_MAINMIC_EN 0x01
|
||||
|
||||
/* ANAMICR (0x06) Fields */
|
||||
#define TWL4030_MICAMPR_EN 0x10
|
||||
#define TWL4030_AUXR_EN 0x04
|
||||
#define TWL4030_SUBMIC_EN 0x01
|
||||
|
||||
/* AVADC_CTL (0x07) Fields */
|
||||
#define TWL4030_ADCL_EN 0x08
|
||||
#define TWL4030_AVADC_CLK_PRIORITY 0x04
|
||||
#define TWL4030_ADCR_EN 0x02
|
||||
|
||||
/* TWL4030_REG_ADCMICSEL (0x08) Fields */
|
||||
#define TWL4030_DIGMIC1_EN 0x08
|
||||
#define TWL4030_TX2IN_SEL 0x04
|
||||
#define TWL4030_DIGMIC0_EN 0x02
|
||||
#define TWL4030_TX1IN_SEL 0x01
|
||||
|
||||
/* AUDIO_IF (0x0E) Fields */
|
||||
#define TWL4030_AIF_SLAVE_EN 0x80
|
||||
#define TWL4030_DATA_WIDTH 0x60
|
||||
#define TWL4030_DATA_WIDTH_16S_16W 0x00
|
||||
#define TWL4030_DATA_WIDTH_32S_16W 0x40
|
||||
#define TWL4030_DATA_WIDTH_32S_24W 0x60
|
||||
#define TWL4030_AIF_FORMAT 0x18
|
||||
#define TWL4030_AIF_FORMAT_CODEC 0x00
|
||||
#define TWL4030_AIF_FORMAT_LEFT 0x08
|
||||
#define TWL4030_AIF_FORMAT_RIGHT 0x10
|
||||
#define TWL4030_AIF_FORMAT_TDM 0x18
|
||||
#define TWL4030_AIF_TRI_EN 0x04
|
||||
#define TWL4030_CLK256FS_EN 0x02
|
||||
#define TWL4030_AIF_EN 0x01
|
||||
|
||||
/* VOICE_IF (0x0F) Fields */
|
||||
#define TWL4030_VIF_SLAVE_EN 0x80
|
||||
#define TWL4030_VIF_DIN_EN 0x40
|
||||
#define TWL4030_VIF_DOUT_EN 0x20
|
||||
#define TWL4030_VIF_SWAP 0x10
|
||||
#define TWL4030_VIF_FORMAT 0x08
|
||||
#define TWL4030_VIF_TRI_EN 0x04
|
||||
#define TWL4030_VIF_SUB_EN 0x02
|
||||
#define TWL4030_VIF_EN 0x01
|
||||
|
||||
/* EAR_CTL (0x21) */
|
||||
#define TWL4030_EAR_GAIN 0x30
|
||||
|
||||
/* HS_GAIN_SET (0x23) Fields */
|
||||
#define TWL4030_HSR_GAIN 0x0C
|
||||
#define TWL4030_HSR_GAIN_PWR_DOWN 0x00
|
||||
#define TWL4030_HSR_GAIN_PLUS_6DB 0x04
|
||||
#define TWL4030_HSR_GAIN_0DB 0x08
|
||||
#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C
|
||||
#define TWL4030_HSL_GAIN 0x03
|
||||
#define TWL4030_HSL_GAIN_PWR_DOWN 0x00
|
||||
#define TWL4030_HSL_GAIN_PLUS_6DB 0x01
|
||||
#define TWL4030_HSL_GAIN_0DB 0x02
|
||||
#define TWL4030_HSL_GAIN_MINUS_6DB 0x03
|
||||
|
||||
/* HS_POPN_SET (0x24) Fields */
|
||||
#define TWL4030_VMID_EN 0x40
|
||||
#define TWL4030_EXTMUTE 0x20
|
||||
#define TWL4030_RAMP_DELAY 0x1C
|
||||
#define TWL4030_RAMP_DELAY_20MS 0x00
|
||||
#define TWL4030_RAMP_DELAY_40MS 0x04
|
||||
#define TWL4030_RAMP_DELAY_81MS 0x08
|
||||
#define TWL4030_RAMP_DELAY_161MS 0x0C
|
||||
#define TWL4030_RAMP_DELAY_323MS 0x10
|
||||
#define TWL4030_RAMP_DELAY_645MS 0x14
|
||||
#define TWL4030_RAMP_DELAY_1291MS 0x18
|
||||
#define TWL4030_RAMP_DELAY_2581MS 0x1C
|
||||
#define TWL4030_RAMP_EN 0x02
|
||||
|
||||
/* PREDL_CTL (0x25) */
|
||||
#define TWL4030_PREDL_GAIN 0x30
|
||||
|
||||
/* PREDR_CTL (0x26) */
|
||||
#define TWL4030_PREDR_GAIN 0x30
|
||||
|
||||
/* PRECKL_CTL (0x27) */
|
||||
#define TWL4030_PRECKL_GAIN 0x30
|
||||
|
||||
/* PRECKR_CTL (0x28) */
|
||||
#define TWL4030_PRECKR_GAIN 0x30
|
||||
|
||||
/* HFL_CTL (0x29, 0x2A) Fields */
|
||||
#define TWL4030_HF_CTL_HB_EN 0x04
|
||||
#define TWL4030_HF_CTL_LOOP_EN 0x08
|
||||
#define TWL4030_HF_CTL_RAMP_EN 0x10
|
||||
#define TWL4030_HF_CTL_REF_EN 0x20
|
||||
|
||||
/* APLL_CTL (0x3A) Fields */
|
||||
#define TWL4030_APLL_EN 0x10
|
||||
#define TWL4030_APLL_INFREQ 0x0F
|
||||
#define TWL4030_APLL_INFREQ_19200KHZ 0x05
|
||||
#define TWL4030_APLL_INFREQ_26000KHZ 0x06
|
||||
#define TWL4030_APLL_INFREQ_38400KHZ 0x0F
|
||||
|
||||
/* REG_MISC_SET_1 (0x3E) Fields */
|
||||
#define TWL4030_CLK64_EN 0x80
|
||||
#define TWL4030_SCRAMBLE_EN 0x40
|
||||
#define TWL4030_FMLOOP_EN 0x20
|
||||
#define TWL4030_SMOOTH_ANAVOL_EN 0x02
|
||||
#define TWL4030_DIGMIC_LR_SWAP_EN 0x01
|
||||
|
||||
/* VIBRA_CTL (0x45) */
|
||||
#define TWL4030_VIBRA_EN 0x01
|
||||
#define TWL4030_VIBRA_DIR 0x02
|
||||
#define TWL4030_VIBRA_AUDIO_SEL_L1 (0x00 << 2)
|
||||
#define TWL4030_VIBRA_AUDIO_SEL_R1 (0x01 << 2)
|
||||
#define TWL4030_VIBRA_AUDIO_SEL_L2 (0x02 << 2)
|
||||
#define TWL4030_VIBRA_AUDIO_SEL_R2 (0x03 << 2)
|
||||
#define TWL4030_VIBRA_SEL 0x10
|
||||
#define TWL4030_VIBRA_DIR_SEL 0x20
|
||||
|
||||
/* TWL4030 codec resource IDs */
|
||||
enum twl4030_codec_res {
|
||||
TWL4030_CODEC_RES_POWER = 0,
|
||||
TWL4030_CODEC_RES_APLL,
|
||||
TWL4030_CODEC_RES_MAX,
|
||||
};
|
||||
|
||||
int twl4030_codec_disable_resource(enum twl4030_codec_res id);
|
||||
int twl4030_codec_enable_resource(enum twl4030_codec_res id);
|
||||
unsigned int twl4030_codec_get_mclk(void);
|
||||
|
||||
#endif /* End of __TWL4030_CODEC_H__ */
|
@ -2,7 +2,6 @@ header-y += asound_fm.h
|
||||
header-y += hdsp.h
|
||||
header-y += hdspm.h
|
||||
header-y += sfnt_info.h
|
||||
header-y += sscape_ioctl.h
|
||||
|
||||
unifdef-y += asequencer.h
|
||||
unifdef-y += asound.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef _MIRO_H_
|
||||
#define _MIRO_H_
|
||||
#ifndef _ACI_H_
|
||||
#define _ACI_H_
|
||||
|
||||
#define ACI_REG_COMMAND 0 /* write register offset */
|
||||
#define ACI_REG_STATUS 1 /* read register offset */
|
||||
@ -70,4 +70,21 @@
|
||||
#define ACI_SET_EQ6 0x45
|
||||
#define ACI_SET_EQ7 0x46 /* ... to Treble */
|
||||
|
||||
#endif /* _MIRO_H_ */
|
||||
struct snd_miro_aci {
|
||||
unsigned long aci_port;
|
||||
int aci_vendor;
|
||||
int aci_product;
|
||||
int aci_version;
|
||||
int aci_amp;
|
||||
int aci_preamp;
|
||||
int aci_solomode;
|
||||
|
||||
struct mutex aci_mutex;
|
||||
};
|
||||
|
||||
int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3);
|
||||
|
||||
struct snd_miro_aci *snd_aci_get_aci(void);
|
||||
|
||||
#endif /* _ACI_H_ */
|
||||
|
321
include/sound/ak4113.h
Normal file
321
include/sound/ak4113.h
Normal file
@ -0,0 +1,321 @@
|
||||
#ifndef __SOUND_AK4113_H
|
||||
#define __SOUND_AK4113_H
|
||||
|
||||
/*
|
||||
* Routines for Asahi Kasei AK4113
|
||||
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
|
||||
* Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com>,
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
/* AK4113 registers */
|
||||
/* power down */
|
||||
#define AK4113_REG_PWRDN 0x00
|
||||
/* format control */
|
||||
#define AK4113_REG_FORMAT 0x01
|
||||
/* input/output control */
|
||||
#define AK4113_REG_IO0 0x02
|
||||
/* input/output control */
|
||||
#define AK4113_REG_IO1 0x03
|
||||
/* interrupt0 mask */
|
||||
#define AK4113_REG_INT0_MASK 0x04
|
||||
/* interrupt1 mask */
|
||||
#define AK4113_REG_INT1_MASK 0x05
|
||||
/* DAT mask & DTS select */
|
||||
#define AK4113_REG_DATDTS 0x06
|
||||
/* receiver status 0 */
|
||||
#define AK4113_REG_RCS0 0x07
|
||||
/* receiver status 1 */
|
||||
#define AK4113_REG_RCS1 0x08
|
||||
/* receiver status 2 */
|
||||
#define AK4113_REG_RCS2 0x09
|
||||
/* RX channel status byte 0 */
|
||||
#define AK4113_REG_RXCSB0 0x0a
|
||||
/* RX channel status byte 1 */
|
||||
#define AK4113_REG_RXCSB1 0x0b
|
||||
/* RX channel status byte 2 */
|
||||
#define AK4113_REG_RXCSB2 0x0c
|
||||
/* RX channel status byte 3 */
|
||||
#define AK4113_REG_RXCSB3 0x0d
|
||||
/* RX channel status byte 4 */
|
||||
#define AK4113_REG_RXCSB4 0x0e
|
||||
/* burst preamble Pc byte 0 */
|
||||
#define AK4113_REG_Pc0 0x0f
|
||||
/* burst preamble Pc byte 1 */
|
||||
#define AK4113_REG_Pc1 0x10
|
||||
/* burst preamble Pd byte 0 */
|
||||
#define AK4113_REG_Pd0 0x11
|
||||
/* burst preamble Pd byte 1 */
|
||||
#define AK4113_REG_Pd1 0x12
|
||||
/* Q-subcode address + control */
|
||||
#define AK4113_REG_QSUB_ADDR 0x13
|
||||
/* Q-subcode track */
|
||||
#define AK4113_REG_QSUB_TRACK 0x14
|
||||
/* Q-subcode index */
|
||||
#define AK4113_REG_QSUB_INDEX 0x15
|
||||
/* Q-subcode minute */
|
||||
#define AK4113_REG_QSUB_MINUTE 0x16
|
||||
/* Q-subcode second */
|
||||
#define AK4113_REG_QSUB_SECOND 0x17
|
||||
/* Q-subcode frame */
|
||||
#define AK4113_REG_QSUB_FRAME 0x18
|
||||
/* Q-subcode zero */
|
||||
#define AK4113_REG_QSUB_ZERO 0x19
|
||||
/* Q-subcode absolute minute */
|
||||
#define AK4113_REG_QSUB_ABSMIN 0x1a
|
||||
/* Q-subcode absolute second */
|
||||
#define AK4113_REG_QSUB_ABSSEC 0x1b
|
||||
/* Q-subcode absolute frame */
|
||||
#define AK4113_REG_QSUB_ABSFRM 0x1c
|
||||
|
||||
/* sizes */
|
||||
#define AK4113_REG_RXCSB_SIZE ((AK4113_REG_RXCSB4-AK4113_REG_RXCSB0)+1)
|
||||
#define AK4113_REG_QSUB_SIZE ((AK4113_REG_QSUB_ABSFRM-AK4113_REG_QSUB_ADDR)\
|
||||
+1)
|
||||
|
||||
#define AK4113_WRITABLE_REGS (AK4113_REG_DATDTS + 1)
|
||||
|
||||
/* AK4113_REG_PWRDN bits */
|
||||
/* Channel Status Select */
|
||||
#define AK4113_CS12 (1<<7)
|
||||
/* Block Start & C/U Output Mode */
|
||||
#define AK4113_BCU (1<<6)
|
||||
/* Master Clock Operation Select */
|
||||
#define AK4113_CM1 (1<<5)
|
||||
/* Master Clock Operation Select */
|
||||
#define AK4113_CM0 (1<<4)
|
||||
/* Master Clock Frequency Select */
|
||||
#define AK4113_OCKS1 (1<<3)
|
||||
/* Master Clock Frequency Select */
|
||||
#define AK4113_OCKS0 (1<<2)
|
||||
/* 0 = power down, 1 = normal operation */
|
||||
#define AK4113_PWN (1<<1)
|
||||
/* 0 = reset & initialize (except thisregister), 1 = normal operation */
|
||||
#define AK4113_RST (1<<0)
|
||||
|
||||
/* AK4113_REQ_FORMAT bits */
|
||||
/* V/TX Output select: 0 = Validity Flag Output, 1 = TX */
|
||||
#define AK4113_VTX (1<<7)
|
||||
/* Audio Data Control */
|
||||
#define AK4113_DIF2 (1<<6)
|
||||
/* Audio Data Control */
|
||||
#define AK4113_DIF1 (1<<5)
|
||||
/* Audio Data Control */
|
||||
#define AK4113_DIF0 (1<<4)
|
||||
/* Deemphasis Autodetect Enable (1 = enable) */
|
||||
#define AK4113_DEAU (1<<3)
|
||||
/* 32kHz-48kHz Deemphasis Control */
|
||||
#define AK4113_DEM1 (1<<2)
|
||||
/* 32kHz-48kHz Deemphasis Control */
|
||||
#define AK4113_DEM0 (1<<1)
|
||||
#define AK4113_DEM_OFF (AK4113_DEM0)
|
||||
#define AK4113_DEM_44KHZ (0)
|
||||
#define AK4113_DEM_48KHZ (AK4113_DEM1)
|
||||
#define AK4113_DEM_32KHZ (AK4113_DEM0|AK4113_DEM1)
|
||||
/* STDO: 16-bit, right justified */
|
||||
#define AK4113_DIF_16R (0)
|
||||
/* STDO: 18-bit, right justified */
|
||||
#define AK4113_DIF_18R (AK4113_DIF0)
|
||||
/* STDO: 20-bit, right justified */
|
||||
#define AK4113_DIF_20R (AK4113_DIF1)
|
||||
/* STDO: 24-bit, right justified */
|
||||
#define AK4113_DIF_24R (AK4113_DIF1|AK4113_DIF0)
|
||||
/* STDO: 24-bit, left justified */
|
||||
#define AK4113_DIF_24L (AK4113_DIF2)
|
||||
/* STDO: I2S */
|
||||
#define AK4113_DIF_24I2S (AK4113_DIF2|AK4113_DIF0)
|
||||
/* STDO: 24-bit, left justified; LRCLK, BICK = Input */
|
||||
#define AK4113_DIF_I24L (AK4113_DIF2|AK4113_DIF1)
|
||||
/* STDO: I2S; LRCLK, BICK = Input */
|
||||
#define AK4113_DIF_I24I2S (AK4113_DIF2|AK4113_DIF1|AK4113_DIF0)
|
||||
|
||||
/* AK4113_REG_IO0 */
|
||||
/* XTL1=0,XTL0=0 -> 11.2896Mhz; XTL1=0,XTL0=1 -> 12.288Mhz */
|
||||
#define AK4113_XTL1 (1<<6)
|
||||
/* XTL1=1,XTL0=0 -> 24.576Mhz; XTL1=1,XTL0=1 -> use channel status */
|
||||
#define AK4113_XTL0 (1<<5)
|
||||
/* Block Start Signal Output: 0 = U-bit, 1 = C-bit (req. BCU = 1) */
|
||||
#define AK4113_UCE (1<<4)
|
||||
/* TX Output Enable (1 = enable) */
|
||||
#define AK4113_TXE (1<<3)
|
||||
/* Output Through Data Selector for TX pin */
|
||||
#define AK4113_OPS2 (1<<2)
|
||||
/* Output Through Data Selector for TX pin */
|
||||
#define AK4113_OPS1 (1<<1)
|
||||
/* Output Through Data Selector for TX pin */
|
||||
#define AK4113_OPS0 (1<<0)
|
||||
/* 11.2896 MHz ref. Xtal freq. */
|
||||
#define AK4113_XTL_11_2896M (0)
|
||||
/* 12.288 MHz ref. Xtal freq. */
|
||||
#define AK4113_XTL_12_288M (AK4113_XTL0)
|
||||
/* 24.576 MHz ref. Xtal freq. */
|
||||
#define AK4113_XTL_24_576M (AK4113_XTL1)
|
||||
|
||||
/* AK4113_REG_IO1 */
|
||||
/* Interrupt 0 pin Hold */
|
||||
#define AK4113_EFH1 (1<<7)
|
||||
/* Interrupt 0 pin Hold */
|
||||
#define AK4113_EFH0 (1<<6)
|
||||
#define AK4113_EFH_512LRCLK (0)
|
||||
#define AK4113_EFH_1024LRCLK (AK4113_EFH0)
|
||||
#define AK4113_EFH_2048LRCLK (AK4113_EFH1)
|
||||
#define AK4113_EFH_4096LRCLK (AK4113_EFH1|AK4113_EFH0)
|
||||
/* PLL Lock Time: 0 = 384/fs, 1 = 1/fs */
|
||||
#define AK4113_FAST (1<<5)
|
||||
/* MCKO2 Output Select: 0 = CMx/OCKSx, 1 = Xtal */
|
||||
#define AK4113_XMCK (1<<4)
|
||||
/* MCKO2 Output Freq. Select: 0 = x1, 1 = x0.5 (req. XMCK = 1) */
|
||||
#define AK4113_DIV (1<<3)
|
||||
/* Input Recovery Data Select */
|
||||
#define AK4113_IPS2 (1<<2)
|
||||
/* Input Recovery Data Select */
|
||||
#define AK4113_IPS1 (1<<1)
|
||||
/* Input Recovery Data Select */
|
||||
#define AK4113_IPS0 (1<<0)
|
||||
#define AK4113_IPS(x) ((x)&7)
|
||||
|
||||
/* AK4113_REG_INT0_MASK && AK4113_REG_INT1_MASK*/
|
||||
/* mask enable for QINT bit */
|
||||
#define AK4113_MQI (1<<7)
|
||||
/* mask enable for AUTO bit */
|
||||
#define AK4113_MAUT (1<<6)
|
||||
/* mask enable for CINT bit */
|
||||
#define AK4113_MCIT (1<<5)
|
||||
/* mask enable for UNLOCK bit */
|
||||
#define AK4113_MULK (1<<4)
|
||||
/* mask enable for V bit */
|
||||
#define AK4113_V (1<<3)
|
||||
/* mask enable for STC bit */
|
||||
#define AK4113_STC (1<<2)
|
||||
/* mask enable for AUDN bit */
|
||||
#define AK4113_MAN (1<<1)
|
||||
/* mask enable for PAR bit */
|
||||
#define AK4113_MPR (1<<0)
|
||||
|
||||
/* AK4113_REG_DATDTS */
|
||||
/* DAT Start ID Counter */
|
||||
#define AK4113_DCNT (1<<4)
|
||||
/* DTS-CD 16-bit Sync Word Detect */
|
||||
#define AK4113_DTS16 (1<<3)
|
||||
/* DTS-CD 14-bit Sync Word Detect */
|
||||
#define AK4113_DTS14 (1<<2)
|
||||
/* mask enable for DAT bit (if 1, no INT1 effect */
|
||||
#define AK4113_MDAT1 (1<<1)
|
||||
/* mask enable for DAT bit (if 1, no INT0 effect */
|
||||
#define AK4113_MDAT0 (1<<0)
|
||||
|
||||
/* AK4113_REG_RCS0 */
|
||||
/* Q-subcode buffer interrupt, 0 = no change, 1 = changed */
|
||||
#define AK4113_QINT (1<<7)
|
||||
/* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */
|
||||
#define AK4113_AUTO (1<<6)
|
||||
/* channel status buffer interrupt, 0 = no change, 1 = change */
|
||||
#define AK4113_CINT (1<<5)
|
||||
/* PLL lock status, 0 = lock, 1 = unlock */
|
||||
#define AK4113_UNLCK (1<<4)
|
||||
/* Validity bit, 0 = valid, 1 = invalid */
|
||||
#define AK4113_V (1<<3)
|
||||
/* sampling frequency or Pre-emphasis change, 0 = no detect, 1 = detect */
|
||||
#define AK4113_STC (1<<2)
|
||||
/* audio bit output, 0 = audio, 1 = non-audio */
|
||||
#define AK4113_AUDION (1<<1)
|
||||
/* parity error or biphase error status, 0 = no error, 1 = error */
|
||||
#define AK4113_PAR (1<<0)
|
||||
|
||||
/* AK4113_REG_RCS1 */
|
||||
/* sampling frequency detection */
|
||||
#define AK4113_FS3 (1<<7)
|
||||
#define AK4113_FS2 (1<<6)
|
||||
#define AK4113_FS1 (1<<5)
|
||||
#define AK4113_FS0 (1<<4)
|
||||
/* Pre-emphasis detect, 0 = OFF, 1 = ON */
|
||||
#define AK4113_PEM (1<<3)
|
||||
/* DAT Start ID Detect, 0 = no detect, 1 = detect */
|
||||
#define AK4113_DAT (1<<2)
|
||||
/* DTS-CD bit audio stream detect, 0 = no detect, 1 = detect */
|
||||
#define AK4113_DTSCD (1<<1)
|
||||
/* Non-PCM bit stream detection, 0 = no detect, 1 = detect */
|
||||
#define AK4113_NPCM (1<<0)
|
||||
#define AK4113_FS_8000HZ (AK4113_FS3|AK4113_FS0)
|
||||
#define AK4113_FS_11025HZ (AK4113_FS2|AK4113_FS0)
|
||||
#define AK4113_FS_16000HZ (AK4113_FS2|AK4113_FS1|AK4113_FS0)
|
||||
#define AK4113_FS_22050HZ (AK4113_FS2)
|
||||
#define AK4113_FS_24000HZ (AK4113_FS2|AK4113_FS1)
|
||||
#define AK4113_FS_32000HZ (AK4113_FS1|AK4113_FS0)
|
||||
#define AK4113_FS_44100HZ (0)
|
||||
#define AK4113_FS_48000HZ (AK4113_FS1)
|
||||
#define AK4113_FS_64000HZ (AK4113_FS3|AK4113_FS1|AK4113_FS0)
|
||||
#define AK4113_FS_88200HZ (AK4113_FS3)
|
||||
#define AK4113_FS_96000HZ (AK4113_FS3|AK4113_FS1)
|
||||
#define AK4113_FS_176400HZ (AK4113_FS3|AK4113_FS2)
|
||||
#define AK4113_FS_192000HZ (AK4113_FS3|AK4113_FS2|AK4113_FS1)
|
||||
|
||||
/* AK4113_REG_RCS2 */
|
||||
/* CRC for Q-subcode, 0 = no error, 1 = error */
|
||||
#define AK4113_QCRC (1<<1)
|
||||
/* CRC for channel status, 0 = no error, 1 = error */
|
||||
#define AK4113_CCRC (1<<0)
|
||||
|
||||
/* flags for snd_ak4113_check_rate_and_errors() */
|
||||
#define AK4113_CHECK_NO_STAT (1<<0) /* no statistics */
|
||||
#define AK4113_CHECK_NO_RATE (1<<1) /* no rate check */
|
||||
|
||||
#define AK4113_CONTROLS 13
|
||||
|
||||
typedef void (ak4113_write_t)(void *private_data, unsigned char addr,
|
||||
unsigned char data);
|
||||
typedef unsigned char (ak4113_read_t)(void *private_data, unsigned char addr);
|
||||
|
||||
struct ak4113 {
|
||||
struct snd_card *card;
|
||||
ak4113_write_t *write;
|
||||
ak4113_read_t *read;
|
||||
void *private_data;
|
||||
unsigned int init:1;
|
||||
spinlock_t lock;
|
||||
unsigned char regmap[AK4113_WRITABLE_REGS];
|
||||
struct snd_kcontrol *kctls[AK4113_CONTROLS];
|
||||
struct snd_pcm_substream *substream;
|
||||
unsigned long parity_errors;
|
||||
unsigned long v_bit_errors;
|
||||
unsigned long qcrc_errors;
|
||||
unsigned long ccrc_errors;
|
||||
unsigned char rcs0;
|
||||
unsigned char rcs1;
|
||||
unsigned char rcs2;
|
||||
struct delayed_work work;
|
||||
unsigned int check_flags;
|
||||
void *change_callback_private;
|
||||
void (*change_callback)(struct ak4113 *ak4113, unsigned char c0,
|
||||
unsigned char c1);
|
||||
};
|
||||
|
||||
int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
|
||||
ak4113_write_t *write,
|
||||
const unsigned char pgm[AK4113_WRITABLE_REGS],
|
||||
void *private_data, struct ak4113 **r_ak4113);
|
||||
void snd_ak4113_reg_write(struct ak4113 *ak4113, unsigned char reg,
|
||||
unsigned char mask, unsigned char val);
|
||||
void snd_ak4113_reinit(struct ak4113 *ak4113);
|
||||
int snd_ak4113_build(struct ak4113 *ak4113,
|
||||
struct snd_pcm_substream *capture_substream);
|
||||
int snd_ak4113_external_rate(struct ak4113 *ak4113);
|
||||
int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags);
|
||||
|
||||
#endif /* __SOUND_AK4113_H */
|
||||
|
@ -95,13 +95,13 @@
|
||||
|
||||
/* AK4114_REG_IO0 */
|
||||
#define AK4114_TX1E (1<<7) /* TX1 Output Enable (1 = enable) */
|
||||
#define AK4114_OPS12 (1<<2) /* Output Though Data Selector for TX1 pin */
|
||||
#define AK4114_OPS11 (1<<1) /* Output Though Data Selector for TX1 pin */
|
||||
#define AK4114_OPS10 (1<<0) /* Output Though Data Selector for TX1 pin */
|
||||
#define AK4114_OPS12 (1<<6) /* Output Data Selector for TX1 pin */
|
||||
#define AK4114_OPS11 (1<<5) /* Output Data Selector for TX1 pin */
|
||||
#define AK4114_OPS10 (1<<4) /* Output Data Selector for TX1 pin */
|
||||
#define AK4114_TX0E (1<<3) /* TX0 Output Enable (1 = enable) */
|
||||
#define AK4114_OPS02 (1<<2) /* Output Though Data Selector for TX0 pin */
|
||||
#define AK4114_OPS01 (1<<1) /* Output Though Data Selector for TX0 pin */
|
||||
#define AK4114_OPS00 (1<<0) /* Output Though Data Selector for TX0 pin */
|
||||
#define AK4114_OPS02 (1<<2) /* Output Data Selector for TX0 pin */
|
||||
#define AK4114_OPS01 (1<<1) /* Output Data Selector for TX0 pin */
|
||||
#define AK4114_OPS00 (1<<0) /* Output Data Selector for TX0 pin */
|
||||
|
||||
/* AK4114_REG_IO1 */
|
||||
#define AK4114_EFH1 (1<<7) /* Interrupt 0 pin Hold */
|
||||
|
@ -68,7 +68,7 @@ struct snd_akm4xxx {
|
||||
enum {
|
||||
SND_AK4524, SND_AK4528, SND_AK4529,
|
||||
SND_AK4355, SND_AK4358, SND_AK4381,
|
||||
SND_AK5365
|
||||
SND_AK5365, SND_AK4620,
|
||||
} type;
|
||||
|
||||
/* (array) information of combined codecs */
|
||||
@ -76,6 +76,9 @@ struct snd_akm4xxx {
|
||||
const struct snd_akm4xxx_adc_channel *adc_info;
|
||||
|
||||
struct snd_ak4xxx_ops ops;
|
||||
unsigned int num_chips;
|
||||
unsigned int total_regs;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
|
||||
|
@ -56,7 +56,6 @@ struct snd_kcontrol_new {
|
||||
|
||||
struct snd_kcontrol_volatile {
|
||||
struct snd_ctl_file *owner; /* locked */
|
||||
pid_t owner_pid;
|
||||
unsigned int access; /* access rights */
|
||||
};
|
||||
|
||||
@ -87,10 +86,12 @@ struct snd_kctl_event {
|
||||
|
||||
#define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list)
|
||||
|
||||
struct pid;
|
||||
|
||||
struct snd_ctl_file {
|
||||
struct list_head list; /* list of all control files */
|
||||
struct snd_card *card;
|
||||
pid_t pid;
|
||||
struct pid *pid;
|
||||
int prefer_pcm_subdevice;
|
||||
int prefer_rawmidi_subdevice;
|
||||
wait_queue_head_t change_sleep;
|
||||
|
@ -70,7 +70,6 @@
|
||||
#define AD1845_PWR_DOWN 0x1b /* power down control */
|
||||
#define CS4235_LEFT_MASTER 0x1b /* left master output control */
|
||||
#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */
|
||||
#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */
|
||||
#define AD1845_CLOCK 0x1d /* crystal clock select and total power down */
|
||||
#define CS4235_RIGHT_MASTER 0x1d /* right master output control */
|
||||
#define CS4231_REC_UPR_CNT 0x1e /* record upper count */
|
||||
|
@ -348,6 +348,8 @@ struct snd_pcm_group { /* keep linked substreams */
|
||||
int count;
|
||||
};
|
||||
|
||||
struct pid;
|
||||
|
||||
struct snd_pcm_substream {
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_pcm_str *pstr;
|
||||
@ -379,6 +381,7 @@ struct snd_pcm_substream {
|
||||
atomic_t mmap_count;
|
||||
unsigned int f_flags;
|
||||
void (*pcm_release)(struct snd_pcm_substream *);
|
||||
struct pid *pid;
|
||||
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
|
||||
/* -- OSS things -- */
|
||||
struct snd_pcm_oss_substream oss;
|
||||
|
@ -46,6 +46,7 @@
|
||||
struct snd_rawmidi;
|
||||
struct snd_rawmidi_substream;
|
||||
struct snd_seq_port_info;
|
||||
struct pid;
|
||||
|
||||
struct snd_rawmidi_ops {
|
||||
int (*open) (struct snd_rawmidi_substream * substream);
|
||||
@ -97,6 +98,7 @@ struct snd_rawmidi_substream {
|
||||
struct snd_rawmidi_str *pstr;
|
||||
char name[32];
|
||||
struct snd_rawmidi_runtime *runtime;
|
||||
struct pid *pid;
|
||||
/* hardware layer */
|
||||
struct snd_rawmidi_ops *ops;
|
||||
};
|
||||
|
21
include/sound/sh_dac_audio.h
Normal file
21
include/sound/sh_dac_audio.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SH_DAC specific configuration, for the dac_audio platform_device
|
||||
*
|
||||
* Copyright (C) 2009 Rafael Ignacio Zurita <rizurita@yahoo.com>
|
||||
*
|
||||
* 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 __INCLUDE_SH_DAC_AUDIO_H
|
||||
#define __INCLUDE_SH_DAC_AUDIO_H
|
||||
|
||||
struct dac_audio_pdata {
|
||||
int buffer_size;
|
||||
int channel;
|
||||
void (*start)(struct dac_audio_pdata *pd);
|
||||
void (*stop)(struct dac_audio_pdata *pd);
|
||||
};
|
||||
|
||||
#endif /* __INCLUDE_SH_DAC_AUDIO_H */
|
@ -30,6 +30,7 @@ struct snd_pcm_substream;
|
||||
#define SND_SOC_DAIFMT_DSP_A 3 /* L data MSB after FRM LRC */
|
||||
#define SND_SOC_DAIFMT_DSP_B 4 /* L data MSB during FRM LRC */
|
||||
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
|
||||
#define SND_SOC_DAIFMT_PDM 6 /* Pulse density modulation */
|
||||
|
||||
/* left and right justified also known as MSB and LSB respectively */
|
||||
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
|
||||
@ -106,7 +107,7 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
|
||||
int div_id, int div);
|
||||
|
||||
int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
|
||||
int pll_id, unsigned int freq_in, unsigned int freq_out);
|
||||
int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
|
||||
|
||||
/* Digital Audio interface formatting */
|
||||
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
|
||||
@ -114,6 +115,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
|
||||
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
|
||||
|
||||
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot);
|
||||
|
||||
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
|
||||
|
||||
/* Digital Audio Interface mute */
|
||||
@ -136,8 +141,8 @@ struct snd_soc_dai_ops {
|
||||
*/
|
||||
int (*set_sysclk)(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir);
|
||||
int (*set_pll)(struct snd_soc_dai *dai,
|
||||
int pll_id, unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
|
||||
|
||||
/*
|
||||
@ -148,6 +153,9 @@ struct snd_soc_dai_ops {
|
||||
int (*set_tdm_slot)(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width);
|
||||
int (*set_channel_map)(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot);
|
||||
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
|
||||
|
||||
/*
|
||||
|
@ -206,6 +206,12 @@
|
||||
.get = snd_soc_dapm_get_enum_double, \
|
||||
.put = snd_soc_dapm_put_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = snd_soc_dapm_get_enum_virt, \
|
||||
.put = snd_soc_dapm_put_enum_virt, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
@ -260,6 +266,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
@ -333,6 +343,10 @@ struct snd_soc_dapm_route {
|
||||
const char *sink;
|
||||
const char *control;
|
||||
const char *source;
|
||||
|
||||
/* Note: currently only supported for links where source is a supply */
|
||||
int (*connected)(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
};
|
||||
|
||||
/* dapm audio path between two widgets */
|
||||
@ -349,6 +363,9 @@ struct snd_soc_dapm_path {
|
||||
u32 connect:1; /* source and sink widgets are connected */
|
||||
u32 walked:1; /* path has been walked */
|
||||
|
||||
int (*connected)(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
|
||||
struct list_head list_source;
|
||||
struct list_head list_sink;
|
||||
struct list_head list;
|
||||
|
@ -223,15 +223,15 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
|
||||
int addr_bits, int data_bits,
|
||||
enum snd_soc_control_type control);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int snd_soc_suspend_device(struct device *dev);
|
||||
int snd_soc_resume_device(struct device *dev);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
int snd_soc_init_card(struct snd_soc_device *socdev);
|
||||
|
||||
/* 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);
|
||||
int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots);
|
||||
int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
|
||||
|
||||
/* set runtime hw params */
|
||||
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
||||
@ -333,6 +333,8 @@ struct snd_soc_jack_gpio {
|
||||
int debounce_time;
|
||||
struct snd_soc_jack *jack;
|
||||
struct work_struct work;
|
||||
|
||||
int (*jack_status_check)(void);
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -413,6 +415,7 @@ struct snd_soc_codec {
|
||||
unsigned int num_dai;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_codec_root;
|
||||
struct dentry *debugfs_reg;
|
||||
struct dentry *debugfs_pop_time;
|
||||
struct dentry *debugfs_dapm;
|
||||
|
@ -1,21 +0,0 @@
|
||||
#ifndef SSCAPE_IOCTL_H
|
||||
#define SSCAPE_IOCTL_H
|
||||
|
||||
|
||||
struct sscape_bootblock
|
||||
{
|
||||
unsigned char code[256];
|
||||
unsigned version;
|
||||
};
|
||||
|
||||
#define SSCAPE_MICROCODE_SIZE 65536
|
||||
|
||||
struct sscape_microcode
|
||||
{
|
||||
unsigned char __user *code;
|
||||
};
|
||||
|
||||
#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock)
|
||||
#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode)
|
||||
|
||||
#endif
|
20
include/sound/tlv320dac33-plat.h
Normal file
20
include/sound/tlv320dac33-plat.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Platform header for Texas Instruments TLV320DAC33 codec driver
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
*
|
||||
* Copyright: (C) 2009 Nokia Corporation
|
||||
*
|
||||
* 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 __TLV320DAC33_PLAT_H
|
||||
#define __TLV320DAC33_PLAT_H
|
||||
|
||||
struct tlv320dac33_platform_data {
|
||||
int power_gpio;
|
||||
};
|
||||
|
||||
#endif /* __TLV320DAC33_PLAT_H */
|
30
include/sound/tpa6130a2-plat.h
Normal file
30
include/sound/tpa6130a2-plat.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* TPA6130A2 driver platform header
|
||||
*
|
||||
* Copyright (C) Nokia Corporation
|
||||
*
|
||||
* Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef TPA6130A2_PLAT_H
|
||||
#define TPA6130A2_PLAT_H
|
||||
|
||||
struct tpa6130a2_platform_data {
|
||||
int power_gpio;
|
||||
};
|
||||
|
||||
#endif
|
@ -154,7 +154,6 @@ int snd_wss_create(struct snd_card *card,
|
||||
unsigned short hardware,
|
||||
unsigned short hwshare,
|
||||
struct snd_wss **rchip);
|
||||
int snd_wss_free(struct snd_wss *chip);
|
||||
int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
|
||||
int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
|
||||
int snd_wss_mixer(struct snd_wss *chip);
|
||||
|
@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM
|
||||
Please read Documentation/feature-removal-schedule.txt for
|
||||
details.
|
||||
|
||||
If unusre, say Y.
|
||||
If unsure, say Y.
|
||||
|
||||
source "sound/oss/dmasound/Kconfig"
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
|
||||
snd-aaci-objs := aaci.o devdma.o
|
||||
snd-aaci-objs := aaci.o
|
||||
|
||||
obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
|
||||
snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
|
||||
|
@ -18,10 +18,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/amba/bus.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
@ -30,7 +27,6 @@
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "aaci.h"
|
||||
#include "devdma.h"
|
||||
|
||||
#define DRIVER_NAME "aaci-pl041"
|
||||
|
||||
@ -492,7 +488,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
/*
|
||||
* Clear out the DMA and any allocated buffers.
|
||||
*/
|
||||
devdma_hw_free(NULL, substream);
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -509,20 +505,14 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
aacirun->pcm_open = 0;
|
||||
}
|
||||
|
||||
err = devdma_hw_alloc(NULL, substream,
|
||||
params_buffer_bytes(params));
|
||||
err = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(params));
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
else
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
|
||||
err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
|
||||
params_channels(params),
|
||||
aacirun->pcm->r[0].slots);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -538,7 +528,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
struct aaci_runtime *aacirun = runtime->private_data;
|
||||
|
||||
aacirun->start = (void *)runtime->dma_area;
|
||||
aacirun->end = aacirun->start + runtime->dma_bytes;
|
||||
aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream);
|
||||
aacirun->ptr = aacirun->start;
|
||||
aacirun->period =
|
||||
aacirun->bytes = frames_to_bytes(runtime, runtime->period_size);
|
||||
@ -555,11 +545,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
return bytes_to_frames(runtime, bytes);
|
||||
}
|
||||
|
||||
static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
|
||||
{
|
||||
return devdma_mmap(NULL, substream, vma);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Playback specific ALSA stuff
|
||||
@ -726,7 +711,6 @@ static struct snd_pcm_ops aaci_playback_ops = {
|
||||
.prepare = aaci_pcm_prepare,
|
||||
.trigger = aaci_pcm_playback_trigger,
|
||||
.pointer = aaci_pcm_pointer,
|
||||
.mmap = aaci_pcm_mmap,
|
||||
};
|
||||
|
||||
static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream,
|
||||
@ -854,7 +838,6 @@ static struct snd_pcm_ops aaci_capture_ops = {
|
||||
.prepare = aaci_pcm_capture_prepare,
|
||||
.trigger = aaci_pcm_capture_trigger,
|
||||
.pointer = aaci_pcm_pointer,
|
||||
.mmap = aaci_pcm_mmap,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1044,6 +1027,8 @@ static int __devinit aaci_init_pcm(struct aaci *aaci)
|
||||
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
||||
NULL, 0, 64 * 104);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* linux/sound/arm/devdma.c
|
||||
*
|
||||
* Copyright (C) 2003-2004 Russell King, All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ARM DMA shim for ALSA.
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#include "devdma.h"
|
||||
|
||||
void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_dma_buffer *buf = runtime->dma_buffer_p;
|
||||
|
||||
if (runtime->dma_area == NULL)
|
||||
return;
|
||||
|
||||
if (buf != &substream->dma_buffer) {
|
||||
dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr);
|
||||
kfree(runtime->dma_buffer_p);
|
||||
}
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
}
|
||||
|
||||
int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_dma_buffer *buf = runtime->dma_buffer_p;
|
||||
int ret = 0;
|
||||
|
||||
if (buf) {
|
||||
if (buf->bytes >= size)
|
||||
goto out;
|
||||
devdma_hw_free(dev, substream);
|
||||
}
|
||||
|
||||
if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
|
||||
buf = &substream->dma_buffer;
|
||||
} else {
|
||||
buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
|
||||
if (!buf)
|
||||
goto nomem;
|
||||
|
||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
buf->dev.dev = dev;
|
||||
buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL);
|
||||
buf->bytes = size;
|
||||
buf->private_data = NULL;
|
||||
|
||||
if (!buf->area)
|
||||
goto free;
|
||||
}
|
||||
snd_pcm_set_runtime_buffer(substream, buf);
|
||||
ret = 1;
|
||||
out:
|
||||
runtime->dma_bytes = size;
|
||||
return ret;
|
||||
|
||||
free:
|
||||
kfree(buf);
|
||||
nomem:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream);
|
||||
int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size);
|
||||
int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma);
|
@ -75,7 +75,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||
ctl->card = card;
|
||||
ctl->prefer_pcm_subdevice = -1;
|
||||
ctl->prefer_rawmidi_subdevice = -1;
|
||||
ctl->pid = current->pid;
|
||||
ctl->pid = get_pid(task_pid(current));
|
||||
file->private_data = ctl;
|
||||
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||||
list_add_tail(&ctl->list, &card->ctl_files);
|
||||
@ -125,6 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
|
||||
control->vd[idx].owner = NULL;
|
||||
up_write(&card->controls_rwsem);
|
||||
snd_ctl_empty_read_queue(ctl);
|
||||
put_pid(ctl->pid);
|
||||
kfree(ctl);
|
||||
module_put(card->module);
|
||||
snd_card_file_remove(card, file);
|
||||
@ -672,7 +673,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
|
||||
info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
|
||||
if (vd->owner == ctl)
|
||||
info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
|
||||
info->owner = vd->owner_pid;
|
||||
info->owner = pid_vnr(vd->owner->pid);
|
||||
} else {
|
||||
info->owner = -1;
|
||||
}
|
||||
@ -827,7 +828,6 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
|
||||
result = -EBUSY;
|
||||
else {
|
||||
vd->owner = file;
|
||||
vd->owner_pid = current->pid;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
@ -858,7 +858,6 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
||||
result = -EPERM;
|
||||
else {
|
||||
vd->owner = NULL;
|
||||
vd->owner_pid = 0;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
@ -1120,7 +1119,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
goto __kctl_end;
|
||||
}
|
||||
if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
|
||||
if (file && vd->owner != NULL && vd->owner != file) {
|
||||
if (vd->owner != NULL && vd->owner != file) {
|
||||
err = -EPERM;
|
||||
goto __kctl_end;
|
||||
}
|
||||
|
@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable);
|
||||
unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int result;
|
||||
unsigned int result, result1;
|
||||
|
||||
flags = claim_dma_lock();
|
||||
clear_dma_ff(dma);
|
||||
if (!isa_dma_bridge_buggy)
|
||||
disable_dma(dma);
|
||||
result = get_dma_residue(dma);
|
||||
/*
|
||||
* HACK - read the counter again and choose higher value in order to
|
||||
* avoid reading during counter lower byte roll over if the
|
||||
* isa_dma_bridge_buggy is set.
|
||||
*/
|
||||
result1 = get_dma_residue(dma);
|
||||
if (!isa_dma_bridge_buggy)
|
||||
enable_dma(dma);
|
||||
release_dma_lock(flags);
|
||||
if (unlikely(result < result1))
|
||||
result = result1;
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
if (result > size)
|
||||
snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
|
||||
|
@ -1251,7 +1251,9 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
|
||||
{ SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */
|
||||
{ SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */
|
||||
{ SOUND_MIXER_PCM, "PCM", 0 },
|
||||
{ SOUND_MIXER_SPEAKER, "PC Speaker", 0 },
|
||||
{ SOUND_MIXER_SPEAKER, "Beep", 0 },
|
||||
{ SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */
|
||||
{ SOUND_MIXER_SPEAKER, "Speaker", 0 }, /* fallback */
|
||||
{ SOUND_MIXER_LINE, "Line", 0 },
|
||||
{ SOUND_MIXER_MIC, "Mic", 0 },
|
||||
{ SOUND_MIXER_CD, "CD", 0 },
|
||||
|
@ -435,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
||||
return;
|
||||
}
|
||||
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
|
||||
snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
|
||||
snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
|
||||
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
|
||||
snd_iprintf(buffer, "tstamp : %ld.%09ld\n",
|
||||
@ -809,7 +810,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
||||
card = pcm->card;
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == current->pid) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
prefer_subdevice = kctl->prefer_pcm_subdevice;
|
||||
if (prefer_subdevice != -1)
|
||||
break;
|
||||
@ -900,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
||||
substream->private_data = pcm->private_data;
|
||||
substream->ref_count = 1;
|
||||
substream->f_flags = file->f_flags;
|
||||
substream->pid = get_pid(task_pid(current));
|
||||
pstr->substream_opened++;
|
||||
*rsubstream = substream;
|
||||
return 0;
|
||||
@ -921,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||
kfree(runtime->hw_constraints.rules);
|
||||
kfree(runtime);
|
||||
substream->runtime = NULL;
|
||||
put_pid(substream->pid);
|
||||
substream->pid = NULL;
|
||||
substream->pstr->substream_opened--;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/pm_qos_params.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/info.h>
|
||||
@ -3061,6 +3062,27 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
|
||||
}
|
||||
#endif /* coherent mmap */
|
||||
|
||||
static inline struct page *
|
||||
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
|
||||
{
|
||||
void *vaddr = substream->runtime->dma_area + ofs;
|
||||
#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
|
||||
if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
|
||||
return virt_to_page(CAC_ADDR(vaddr));
|
||||
#endif
|
||||
#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) {
|
||||
dma_addr_t addr = substream->runtime->dma_addr + ofs;
|
||||
addr -= get_dma_offset(substream->dma_buffer.dev.dev);
|
||||
/* assume dma_handle set via pfn_to_phys() in
|
||||
* mm/dma-noncoherent.c
|
||||
*/
|
||||
return pfn_to_page(addr >> PAGE_SHIFT);
|
||||
}
|
||||
#endif
|
||||
return virt_to_page(vaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* fault callback for mmapping a RAM page
|
||||
*/
|
||||
@ -3071,7 +3093,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
|
||||
struct snd_pcm_runtime *runtime;
|
||||
unsigned long offset;
|
||||
struct page * page;
|
||||
void *vaddr;
|
||||
size_t dma_bytes;
|
||||
|
||||
if (substream == NULL)
|
||||
@ -3081,36 +3102,53 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
|
||||
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
|
||||
if (offset > dma_bytes - PAGE_SIZE)
|
||||
return VM_FAULT_SIGBUS;
|
||||
if (substream->ops->page) {
|
||||
if (substream->ops->page)
|
||||
page = substream->ops->page(substream, offset);
|
||||
if (!page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
} else {
|
||||
vaddr = runtime->dma_area + offset;
|
||||
page = virt_to_page(vaddr);
|
||||
}
|
||||
else
|
||||
page = snd_pcm_default_page_ops(substream, offset);
|
||||
if (!page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
get_page(page);
|
||||
vmf->page = page;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct snd_pcm_vm_ops_data =
|
||||
{
|
||||
static const struct vm_operations_struct snd_pcm_vm_ops_data = {
|
||||
.open = snd_pcm_mmap_data_open,
|
||||
.close = snd_pcm_mmap_data_close,
|
||||
};
|
||||
|
||||
static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
|
||||
.open = snd_pcm_mmap_data_open,
|
||||
.close = snd_pcm_mmap_data_close,
|
||||
.fault = snd_pcm_mmap_data_fault,
|
||||
};
|
||||
|
||||
#ifndef ARCH_HAS_DMA_MMAP_COHERENT
|
||||
/* This should be defined / handled globally! */
|
||||
#ifdef CONFIG_ARM
|
||||
#define ARCH_HAS_DMA_MMAP_COHERENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* mmap the DMA buffer on RAM
|
||||
*/
|
||||
static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
area->vm_ops = &snd_pcm_vm_ops_data;
|
||||
area->vm_private_data = substream;
|
||||
area->vm_flags |= VM_RESERVED;
|
||||
atomic_inc(&substream->mmap_count);
|
||||
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
|
||||
if (!substream->ops->page &&
|
||||
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
|
||||
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
|
||||
area,
|
||||
substream->runtime->dma_area,
|
||||
substream->runtime->dma_addr,
|
||||
area->vm_end - area->vm_start);
|
||||
#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
|
||||
/* mmap with fault handler */
|
||||
area->vm_ops = &snd_pcm_vm_ops_data_fault;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3118,12 +3156,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
|
||||
* mmap the DMA buffer on I/O memory area
|
||||
*/
|
||||
#if SNDRV_PCM_INFO_MMAP_IOMEM
|
||||
static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio =
|
||||
{
|
||||
.open = snd_pcm_mmap_data_open,
|
||||
.close = snd_pcm_mmap_data_close,
|
||||
};
|
||||
|
||||
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
@ -3133,8 +3165,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
|
||||
#ifdef pgprot_noncached
|
||||
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
|
||||
#endif
|
||||
area->vm_ops = &snd_pcm_vm_ops_data_mmio;
|
||||
area->vm_private_data = substream;
|
||||
area->vm_flags |= VM_IO;
|
||||
size = area->vm_end - area->vm_start;
|
||||
offset = area->vm_pgoff << PAGE_SHIFT;
|
||||
@ -3142,7 +3172,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
|
||||
(substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
|
||||
size, area->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
atomic_inc(&substream->mmap_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3159,6 +3188,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
|
||||
long size;
|
||||
unsigned long offset;
|
||||
size_t dma_bytes;
|
||||
int err;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (!(area->vm_flags & (VM_WRITE|VM_READ)))
|
||||
@ -3183,10 +3213,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
|
||||
if (offset > dma_bytes - size)
|
||||
return -EINVAL;
|
||||
|
||||
area->vm_ops = &snd_pcm_vm_ops_data;
|
||||
area->vm_private_data = substream;
|
||||
if (substream->ops->mmap)
|
||||
return substream->ops->mmap(substream, area);
|
||||
err = substream->ops->mmap(substream, area);
|
||||
else
|
||||
return snd_pcm_default_mmap(substream, area);
|
||||
err = snd_pcm_default_mmap(substream, area);
|
||||
if (!err)
|
||||
atomic_inc(&substream->mmap_count);
|
||||
return err;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_mmap_data);
|
||||
|
@ -242,8 +242,6 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
|
||||
return -ENXIO;
|
||||
if (subdevice >= 0 && subdevice >= s->substream_count)
|
||||
return -ENODEV;
|
||||
if (s->substream_opened >= s->substream_count)
|
||||
return -EAGAIN;
|
||||
|
||||
list_for_each_entry(substream, &s->substreams, list) {
|
||||
if (substream->opened) {
|
||||
@ -280,9 +278,10 @@ static int open_substream(struct snd_rawmidi *rmidi,
|
||||
substream->active_sensing = 0;
|
||||
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
|
||||
substream->append = 1;
|
||||
substream->pid = get_pid(task_pid(current));
|
||||
rmidi->streams[substream->stream].substream_opened++;
|
||||
}
|
||||
substream->use_count++;
|
||||
rmidi->streams[substream->stream].substream_opened++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -413,7 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||||
subdevice = -1;
|
||||
read_lock(&card->ctl_files_rwlock);
|
||||
list_for_each_entry(kctl, &card->ctl_files, list) {
|
||||
if (kctl->pid == current->pid) {
|
||||
if (kctl->pid == task_pid(current)) {
|
||||
subdevice = kctl->prefer_rawmidi_subdevice;
|
||||
if (subdevice != -1)
|
||||
break;
|
||||
@ -466,7 +465,6 @@ static void close_substream(struct snd_rawmidi *rmidi,
|
||||
struct snd_rawmidi_substream *substream,
|
||||
int cleanup)
|
||||
{
|
||||
rmidi->streams[substream->stream].substream_opened--;
|
||||
if (--substream->use_count)
|
||||
return;
|
||||
|
||||
@ -491,6 +489,9 @@ static void close_substream(struct snd_rawmidi *rmidi,
|
||||
snd_rawmidi_runtime_free(substream);
|
||||
substream->opened = 0;
|
||||
substream->append = 0;
|
||||
put_pid(substream->pid);
|
||||
substream->pid = NULL;
|
||||
rmidi->streams[substream->stream].substream_opened--;
|
||||
}
|
||||
|
||||
static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
|
||||
@ -1338,6 +1339,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||
substream->number,
|
||||
(unsigned long) substream->bytes);
|
||||
if (substream->opened) {
|
||||
snd_iprintf(buffer,
|
||||
" Owner PID : %d\n",
|
||||
pid_vnr(substream->pid));
|
||||
runtime = substream->runtime;
|
||||
snd_iprintf(buffer,
|
||||
" Mode : %s\n"
|
||||
@ -1359,6 +1363,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
|
||||
substream->number,
|
||||
(unsigned long) substream->bytes);
|
||||
if (substream->opened) {
|
||||
snd_iprintf(buffer,
|
||||
" Owner PID : %d\n",
|
||||
pid_vnr(substream->pid));
|
||||
runtime = substream->runtime;
|
||||
snd_iprintf(buffer,
|
||||
" Buffer size : %lu\n"
|
||||
|
@ -26,6 +26,7 @@ MODULE_ALIAS("platform:pcspkr");
|
||||
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
|
||||
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
|
||||
static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */
|
||||
static int nopcm; /* Disable PCM capability of the driver */
|
||||
|
||||
module_param(index, int, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
|
||||
@ -33,6 +34,8 @@ module_param(id, charp, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for pcsp soundcard.");
|
||||
module_param(enable, bool, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable PC-Speaker sound.");
|
||||
module_param(nopcm, bool, 0444);
|
||||
MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain.");
|
||||
|
||||
struct snd_pcsp pcsp_chip;
|
||||
|
||||
@ -43,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
|
||||
int err;
|
||||
int div, min_div, order;
|
||||
|
||||
hrtimer_get_res(CLOCK_MONOTONIC, &tp);
|
||||
if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
|
||||
printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
|
||||
"(%linS)\n", tp.tv_nsec);
|
||||
printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
|
||||
"enabled.\n");
|
||||
return -EIO;
|
||||
if (!nopcm) {
|
||||
hrtimer_get_res(CLOCK_MONOTONIC, &tp);
|
||||
if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
|
||||
printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
|
||||
"(%linS)\n", tp.tv_nsec);
|
||||
printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
|
||||
"enabled.\n");
|
||||
printk(KERN_ERR "PCSP: Turned into nopcm mode.\n");
|
||||
nopcm = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS)
|
||||
@ -107,12 +113,14 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
err = snd_pcsp_new_pcm(&pcsp_chip);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
if (!nopcm) {
|
||||
err = snd_pcsp_new_pcm(&pcsp_chip);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = snd_pcsp_new_mixer(&pcsp_chip);
|
||||
err = snd_pcsp_new_mixer(&pcsp_chip, nopcm);
|
||||
if (err < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
|
@ -83,6 +83,6 @@ extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
|
||||
extern void pcsp_sync_stop(struct snd_pcsp *chip);
|
||||
|
||||
extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
|
||||
extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);
|
||||
extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm);
|
||||
|
||||
#endif
|
||||
|
@ -119,24 +119,43 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
|
||||
.put = pcsp_##ctl_type##_put, \
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = {
|
||||
static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = {
|
||||
PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
|
||||
PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
|
||||
PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"),
|
||||
};
|
||||
|
||||
int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
int i, err;
|
||||
static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = {
|
||||
PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) {
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(snd_pcsp_controls + i,
|
||||
chip));
|
||||
static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip,
|
||||
struct snd_kcontrol_new *ctls, int num)
|
||||
{
|
||||
int i, err;
|
||||
struct snd_card *card = chip->card;
|
||||
for (i = 0; i < num; i++) {
|
||||
err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
|
||||
{
|
||||
int err;
|
||||
struct snd_card *card = chip->card;
|
||||
|
||||
if (!nopcm) {
|
||||
err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm,
|
||||
ARRAY_SIZE(snd_pcsp_controls_pcm));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr,
|
||||
ARRAY_SIZE(snd_pcsp_controls_spkr));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
strcpy(card->mixername, "PC-Speaker");
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
@ -55,18 +56,6 @@ struct cs8427 {
|
||||
struct cs8427_stream capture;
|
||||
};
|
||||
|
||||
static unsigned char swapbits(unsigned char val)
|
||||
{
|
||||
int bit;
|
||||
unsigned char res = 0;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
res <<= 1;
|
||||
res |= val & 1;
|
||||
val >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
|
||||
unsigned char val)
|
||||
{
|
||||
@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
|
||||
}
|
||||
data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF;
|
||||
for (idx = 0; idx < count; idx++)
|
||||
data[idx + 1] = swapbits(ndata[idx]);
|
||||
data[idx + 1] = bitrev8(ndata[idx]);
|
||||
if (snd_i2c_sendbytes(device, data, count + 1) != count + 1)
|
||||
return -EIO;
|
||||
return 1;
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
snd-ak4114-objs := ak4114.o
|
||||
snd-ak4117-objs := ak4117.o
|
||||
snd-ak4113-objs := ak4113.o
|
||||
snd-ak4xxx-adda-objs := ak4xxx-adda.o
|
||||
snd-pt2258-objs := pt2258.o
|
||||
snd-tea575x-tuner-objs := tea575x-tuner.o
|
||||
@ -12,5 +13,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
|
||||
# Module Dependency
|
||||
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
|
||||
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
|
||||
obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
|
||||
obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
|
||||
obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
|
||||
|
639
sound/i2c/other/ak4113.c
Normal file
639
sound/i2c/other/ak4113.c
Normal file
@ -0,0 +1,639 @@
|
||||
/*
|
||||
* Routines for control of the AK4113 via I2C/4-wire serial interface
|
||||
* IEC958 (S/PDIF) receiver by Asahi Kasei
|
||||
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
||||
* Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com>
|
||||
*
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ak4113.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/info.h>
|
||||
|
||||
MODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>");
|
||||
MODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define AK4113_ADDR 0x00 /* fixed address */
|
||||
|
||||
static void ak4113_stats(struct work_struct *work);
|
||||
static void ak4113_init_regs(struct ak4113 *chip);
|
||||
|
||||
|
||||
static void reg_write(struct ak4113 *ak4113, unsigned char reg,
|
||||
unsigned char val)
|
||||
{
|
||||
ak4113->write(ak4113->private_data, reg, val);
|
||||
if (reg < sizeof(ak4113->regmap))
|
||||
ak4113->regmap[reg] = val;
|
||||
}
|
||||
|
||||
static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg)
|
||||
{
|
||||
return ak4113->read(ak4113->private_data, reg);
|
||||
}
|
||||
|
||||
static void snd_ak4113_free(struct ak4113 *chip)
|
||||
{
|
||||
chip->init = 1; /* don't schedule new work */
|
||||
mb();
|
||||
cancel_delayed_work(&chip->work);
|
||||
flush_scheduled_work();
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
static int snd_ak4113_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct ak4113 *chip = device->device_data;
|
||||
snd_ak4113_free(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
|
||||
ak4113_write_t *write, const unsigned char pgm[5],
|
||||
void *private_data, struct ak4113 **r_ak4113)
|
||||
{
|
||||
struct ak4113 *chip;
|
||||
int err = 0;
|
||||
unsigned char reg;
|
||||
static struct snd_device_ops ops = {
|
||||
.dev_free = snd_ak4113_dev_free,
|
||||
};
|
||||
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&chip->lock);
|
||||
chip->card = card;
|
||||
chip->read = read;
|
||||
chip->write = write;
|
||||
chip->private_data = private_data;
|
||||
INIT_DELAYED_WORK(&chip->work, ak4113_stats);
|
||||
|
||||
for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
|
||||
chip->regmap[reg] = pgm[reg];
|
||||
ak4113_init_regs(chip);
|
||||
|
||||
chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT |
|
||||
AK4113_CINT | AK4113_STC);
|
||||
chip->rcs1 = reg_read(chip, AK4113_REG_RCS1);
|
||||
chip->rcs2 = reg_read(chip, AK4113_REG_RCS2);
|
||||
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
|
||||
if (err < 0)
|
||||
goto __fail;
|
||||
|
||||
if (r_ak4113)
|
||||
*r_ak4113 = chip;
|
||||
return 0;
|
||||
|
||||
__fail:
|
||||
snd_ak4113_free(chip);
|
||||
return err < 0 ? err : -EIO;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_create);
|
||||
|
||||
void snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg,
|
||||
unsigned char mask, unsigned char val)
|
||||
{
|
||||
if (reg >= AK4113_WRITABLE_REGS)
|
||||
return;
|
||||
reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_reg_write);
|
||||
|
||||
static void ak4113_init_regs(struct ak4113 *chip)
|
||||
{
|
||||
unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg;
|
||||
|
||||
/* bring the chip to reset state and powerdown state */
|
||||
reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN));
|
||||
udelay(200);
|
||||
/* release reset, but leave powerdown */
|
||||
reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN);
|
||||
udelay(200);
|
||||
for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++)
|
||||
reg_write(chip, reg, chip->regmap[reg]);
|
||||
/* release powerdown, everything is initialized now */
|
||||
reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN);
|
||||
}
|
||||
|
||||
void snd_ak4113_reinit(struct ak4113 *chip)
|
||||
{
|
||||
chip->init = 1;
|
||||
mb();
|
||||
flush_scheduled_work();
|
||||
ak4113_init_regs(chip);
|
||||
/* bring up statistics / event queing */
|
||||
chip->init = 0;
|
||||
if (chip->kctls[0])
|
||||
schedule_delayed_work(&chip->work, HZ / 10);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_reinit);
|
||||
|
||||
static unsigned int external_rate(unsigned char rcs1)
|
||||
{
|
||||
switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) {
|
||||
case AK4113_FS_8000HZ:
|
||||
return 8000;
|
||||
case AK4113_FS_11025HZ:
|
||||
return 11025;
|
||||
case AK4113_FS_16000HZ:
|
||||
return 16000;
|
||||
case AK4113_FS_22050HZ:
|
||||
return 22050;
|
||||
case AK4113_FS_24000HZ:
|
||||
return 24000;
|
||||
case AK4113_FS_32000HZ:
|
||||
return 32000;
|
||||
case AK4113_FS_44100HZ:
|
||||
return 44100;
|
||||
case AK4113_FS_48000HZ:
|
||||
return 48000;
|
||||
case AK4113_FS_64000HZ:
|
||||
return 64000;
|
||||
case AK4113_FS_88200HZ:
|
||||
return 88200;
|
||||
case AK4113_FS_96000HZ:
|
||||
return 96000;
|
||||
case AK4113_FS_176400HZ:
|
||||
return 176400;
|
||||
case AK4113_FS_192000HZ:
|
||||
return 192000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = LONG_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
long *ptr;
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
ptr = (long *)(((char *)chip) + kcontrol->private_value);
|
||||
ucontrol->value.integer.value[0] = *ptr;
|
||||
*ptr = 0;
|
||||
spin_unlock_irq(&chip->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info
|
||||
|
||||
static int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
unsigned char reg = kcontrol->private_value & 0xff;
|
||||
unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
|
||||
unsigned char inv = (kcontrol->private_value >> 31) & 1;
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
(AK4113_IPS(chip->regmap[AK4113_REG_IO1]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
int change;
|
||||
u8 old_val;
|
||||
|
||||
spin_lock_irq(&chip->lock);
|
||||
old_val = chip->regmap[AK4113_REG_IO1];
|
||||
change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val);
|
||||
if (change)
|
||||
reg_write(chip, AK4113_REG_IO1,
|
||||
(old_val & (~AK4113_IPS(0xff))) |
|
||||
(AK4113_IPS(ucontrol->value.integer.value[0])));
|
||||
spin_unlock_irq(&chip->lock);
|
||||
return change;
|
||||
}
|
||||
|
||||
static int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 192000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] = external_rate(reg_read(chip,
|
||||
AK4113_REG_RCS1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
|
||||
uinfo->count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++)
|
||||
ucontrol->value.iec958.status[i] = reg_read(chip,
|
||||
AK4113_REG_RXCSB0 + i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
|
||||
uinfo->count = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 0xffff;
|
||||
uinfo->count = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short tmp;
|
||||
|
||||
ucontrol->value.integer.value[0] = 0xf8f2;
|
||||
ucontrol->value.integer.value[1] = 0x4e1f;
|
||||
tmp = reg_read(chip, AK4113_REG_Pc0) |
|
||||
(reg_read(chip, AK4113_REG_Pc1) << 8);
|
||||
ucontrol->value.integer.value[2] = tmp;
|
||||
tmp = reg_read(chip, AK4113_REG_Pd0) |
|
||||
(reg_read(chip, AK4113_REG_Pd1) << 8);
|
||||
ucontrol->value.integer.value[3] = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
||||
uinfo->count = AK4113_REG_QSUB_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < AK4113_REG_QSUB_SIZE; i++)
|
||||
ucontrol->value.bytes.data[i] = reg_read(chip,
|
||||
AK4113_REG_QSUB_ADDR + i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't forget to change AK4113_CONTROLS define!!! */
|
||||
static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Parity Errors",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_error_info,
|
||||
.get = snd_ak4113_in_error_get,
|
||||
.private_value = offsetof(struct ak4113, parity_errors),
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 V-Bit Errors",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_error_info,
|
||||
.get = snd_ak4113_in_error_get,
|
||||
.private_value = offsetof(struct ak4113, v_bit_errors),
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 C-CRC Errors",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_error_info,
|
||||
.get = snd_ak4113_in_error_get,
|
||||
.private_value = offsetof(struct ak4113, ccrc_errors),
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Q-CRC Errors",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_error_info,
|
||||
.get = snd_ak4113_in_error_get,
|
||||
.private_value = offsetof(struct ak4113, qcrc_errors),
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 External Rate",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_rate_info,
|
||||
.get = snd_ak4113_rate_get,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
.info = snd_ak4113_spdif_mask_info,
|
||||
.get = snd_ak4113_spdif_mask_get,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_spdif_info,
|
||||
.get = snd_ak4113_spdif_get,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Preample Capture Default",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_spdif_pinfo,
|
||||
.get = snd_ak4113_spdif_pget,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Q-subcode Capture Default",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_spdif_qinfo,
|
||||
.get = snd_ak4113_spdif_qget,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Audio",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_bit_info,
|
||||
.get = snd_ak4113_in_bit_get,
|
||||
.private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 Non-PCM Bitstream",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_bit_info,
|
||||
.get = snd_ak4113_in_bit_get,
|
||||
.private_value = (0<<8) | AK4113_REG_RCS1,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "IEC958 DTS Bitstream",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_ak4113_in_bit_info,
|
||||
.get = snd_ak4113_in_bit_get,
|
||||
.private_value = (1<<8) | AK4113_REG_RCS1,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "AK4113 Input Select",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_WRITE,
|
||||
.info = snd_ak4113_rx_info,
|
||||
.get = snd_ak4113_rx_get,
|
||||
.put = snd_ak4113_rx_put,
|
||||
}
|
||||
};
|
||||
|
||||
static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct ak4113 *ak4113 = entry->private_data;
|
||||
int reg, val;
|
||||
/* all ak4113 registers 0x00 - 0x1c */
|
||||
for (reg = 0; reg < 0x1d; reg++) {
|
||||
val = reg_read(ak4113, reg);
|
||||
snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void snd_ak4113_proc_init(struct ak4113 *ak4113)
|
||||
{
|
||||
struct snd_info_entry *entry;
|
||||
if (!snd_card_proc_new(ak4113->card, "ak4113", &entry))
|
||||
snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read);
|
||||
}
|
||||
|
||||
int snd_ak4113_build(struct ak4113 *ak4113,
|
||||
struct snd_pcm_substream *cap_substream)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
unsigned int idx;
|
||||
int err;
|
||||
|
||||
if (snd_BUG_ON(!cap_substream))
|
||||
return -EINVAL;
|
||||
ak4113->substream = cap_substream;
|
||||
for (idx = 0; idx < AK4113_CONTROLS; idx++) {
|
||||
kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113);
|
||||
if (kctl == NULL)
|
||||
return -ENOMEM;
|
||||
kctl->id.device = cap_substream->pcm->device;
|
||||
kctl->id.subdevice = cap_substream->number;
|
||||
err = snd_ctl_add(ak4113->card, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ak4113->kctls[idx] = kctl;
|
||||
}
|
||||
snd_ak4113_proc_init(ak4113);
|
||||
/* trigger workq */
|
||||
schedule_delayed_work(&ak4113->work, HZ / 10);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_build);
|
||||
|
||||
int snd_ak4113_external_rate(struct ak4113 *ak4113)
|
||||
{
|
||||
unsigned char rcs1;
|
||||
|
||||
rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
|
||||
return external_rate(rcs1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_external_rate);
|
||||
|
||||
int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime =
|
||||
ak4113->substream ? ak4113->substream->runtime : NULL;
|
||||
unsigned long _flags;
|
||||
int res = 0;
|
||||
unsigned char rcs0, rcs1, rcs2;
|
||||
unsigned char c0, c1;
|
||||
|
||||
rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
|
||||
if (flags & AK4113_CHECK_NO_STAT)
|
||||
goto __rate;
|
||||
rcs0 = reg_read(ak4113, AK4113_REG_RCS0);
|
||||
rcs2 = reg_read(ak4113, AK4113_REG_RCS2);
|
||||
spin_lock_irqsave(&ak4113->lock, _flags);
|
||||
if (rcs0 & AK4113_PAR)
|
||||
ak4113->parity_errors++;
|
||||
if (rcs0 & AK4113_V)
|
||||
ak4113->v_bit_errors++;
|
||||
if (rcs2 & AK4113_CCRC)
|
||||
ak4113->ccrc_errors++;
|
||||
if (rcs2 & AK4113_QCRC)
|
||||
ak4113->qcrc_errors++;
|
||||
c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
|
||||
AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^
|
||||
(rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
|
||||
AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK));
|
||||
c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
|
||||
AK4113_DAT | 0xf0)) ^
|
||||
(rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
|
||||
AK4113_DAT | 0xf0));
|
||||
ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC);
|
||||
ak4113->rcs1 = rcs1;
|
||||
ak4113->rcs2 = rcs2;
|
||||
spin_unlock_irqrestore(&ak4113->lock, _flags);
|
||||
|
||||
if (rcs0 & AK4113_PAR)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[0]->id);
|
||||
if (rcs0 & AK4113_V)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[1]->id);
|
||||
if (rcs2 & AK4113_CCRC)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[2]->id);
|
||||
if (rcs2 & AK4113_QCRC)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[3]->id);
|
||||
|
||||
/* rate change */
|
||||
if (c1 & 0xf0)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[4]->id);
|
||||
|
||||
if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT))
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[6]->id);
|
||||
if (c0 & AK4113_QINT)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[8]->id);
|
||||
|
||||
if (c0 & AK4113_AUDION)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[9]->id);
|
||||
if (c1 & AK4113_NPCM)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[10]->id);
|
||||
if (c1 & AK4113_DTSCD)
|
||||
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&ak4113->kctls[11]->id);
|
||||
|
||||
if (ak4113->change_callback && (c0 | c1) != 0)
|
||||
ak4113->change_callback(ak4113, c0, c1);
|
||||
|
||||
__rate:
|
||||
/* compare rate */
|
||||
res = external_rate(rcs1);
|
||||
if (!(flags & AK4113_CHECK_NO_RATE) && runtime &&
|
||||
(runtime->rate != res)) {
|
||||
snd_pcm_stream_lock_irqsave(ak4113->substream, _flags);
|
||||
if (snd_pcm_running(ak4113->substream)) {
|
||||
/*printk(KERN_DEBUG "rate changed (%i <- %i)\n",
|
||||
* runtime->rate, res); */
|
||||
snd_pcm_stop(ak4113->substream,
|
||||
SNDRV_PCM_STATE_DRAINING);
|
||||
wake_up(&runtime->sleep);
|
||||
res = 1;
|
||||
}
|
||||
snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors);
|
||||
|
||||
static void ak4113_stats(struct work_struct *work)
|
||||
{
|
||||
struct ak4113 *chip = container_of(work, struct ak4113, work.work);
|
||||
|
||||
if (!chip->init)
|
||||
snd_ak4113_check_rate_and_errors(chip, chip->check_flags);
|
||||
|
||||
schedule_delayed_work(&chip->work, HZ / 10);
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/delay.h>
|
||||
@ -29,6 +29,7 @@
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/ak4xxx-adda.h>
|
||||
#include <sound/info.h>
|
||||
|
||||
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
|
||||
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
|
||||
@ -52,26 +53,21 @@ EXPORT_SYMBOL(snd_akm4xxx_write);
|
||||
static void ak4524_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned int chip;
|
||||
unsigned char reg, maxreg;
|
||||
unsigned char reg;
|
||||
|
||||
if (ak->type == SND_AK4528)
|
||||
maxreg = 0x06;
|
||||
else
|
||||
maxreg = 0x08;
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
|
||||
if (state)
|
||||
continue;
|
||||
/* DAC volumes */
|
||||
for (reg = 0x04; reg < maxreg; reg++)
|
||||
for (reg = 0x04; reg < ak->total_regs; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg,
|
||||
snd_akm4xxx_get(ak, chip, reg));
|
||||
}
|
||||
}
|
||||
|
||||
/* reset procedure for AK4355 and AK4358 */
|
||||
static void ak435X_reset(struct snd_akm4xxx *ak, int state,
|
||||
unsigned char total_regs)
|
||||
static void ak435X_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned char reg;
|
||||
|
||||
@ -79,7 +75,7 @@ static void ak435X_reset(struct snd_akm4xxx *ak, int state,
|
||||
snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
|
||||
return;
|
||||
}
|
||||
for (reg = 0x00; reg < total_regs; reg++)
|
||||
for (reg = 0x00; reg < ak->total_regs; reg++)
|
||||
if (reg != 0x01)
|
||||
snd_akm4xxx_write(ak, 0, reg,
|
||||
snd_akm4xxx_get(ak, 0, reg));
|
||||
@ -91,12 +87,11 @@ static void ak4381_reset(struct snd_akm4xxx *ak, int state)
|
||||
{
|
||||
unsigned int chip;
|
||||
unsigned char reg;
|
||||
|
||||
for (chip = 0; chip < ak->num_dacs/2; chip++) {
|
||||
snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
|
||||
if (state)
|
||||
continue;
|
||||
for (reg = 0x01; reg < 0x05; reg++)
|
||||
for (reg = 0x01; reg < ak->total_regs; reg++)
|
||||
snd_akm4xxx_write(ak, chip, reg,
|
||||
snd_akm4xxx_get(ak, chip, reg));
|
||||
}
|
||||
@ -113,16 +108,17 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
|
||||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
case SND_AK4528:
|
||||
case SND_AK4620:
|
||||
ak4524_reset(ak, state);
|
||||
break;
|
||||
case SND_AK4529:
|
||||
/* FIXME: needed for ak4529? */
|
||||
break;
|
||||
case SND_AK4355:
|
||||
ak435X_reset(ak, state, 0x0b);
|
||||
ak435X_reset(ak, state);
|
||||
break;
|
||||
case SND_AK4358:
|
||||
ak435X_reset(ak, state, 0x10);
|
||||
ak435X_reset(ak, state);
|
||||
break;
|
||||
case SND_AK4381:
|
||||
ak4381_reset(ak, state);
|
||||
@ -139,7 +135,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
|
||||
* Volume conversion table for non-linear volumes
|
||||
* from -63.5dB (mute) to 0dB step 0.5dB
|
||||
*
|
||||
* Used for AK4524 input/ouput attenuation, AK4528, and
|
||||
* Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
|
||||
* AK5365 input attenuation
|
||||
*/
|
||||
static const unsigned char vol_cvt_datt[128] = {
|
||||
@ -259,8 +255,22 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||
0x00, 0x0f, /* 0: power-up, un-reset */
|
||||
0xff, 0xff
|
||||
};
|
||||
static const unsigned char inits_ak4620[] = {
|
||||
0x00, 0x07, /* 0: normal */
|
||||
0x01, 0x00, /* 0: reset */
|
||||
0x01, 0x02, /* 1: RSTAD */
|
||||
0x01, 0x03, /* 1: RSTDA */
|
||||
0x01, 0x0f, /* 1: normal */
|
||||
0x02, 0x60, /* 2: 24bit I2S */
|
||||
0x03, 0x01, /* 3: deemphasis off */
|
||||
0x04, 0x00, /* 4: LIN muted */
|
||||
0x05, 0x00, /* 5: RIN muted */
|
||||
0x06, 0x00, /* 6: LOUT muted */
|
||||
0x07, 0x00, /* 7: ROUT muted */
|
||||
0xff, 0xff
|
||||
};
|
||||
|
||||
int chip, num_chips;
|
||||
int chip;
|
||||
const unsigned char *ptr, *inits;
|
||||
unsigned char reg, data;
|
||||
|
||||
@ -270,42 +280,64 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
|
||||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
inits = inits_ak4524;
|
||||
num_chips = ak->num_dacs / 2;
|
||||
ak->num_chips = ak->num_dacs / 2;
|
||||
ak->name = "ak4524";
|
||||
ak->total_regs = 0x08;
|
||||
break;
|
||||
case SND_AK4528:
|
||||
inits = inits_ak4528;
|
||||
num_chips = ak->num_dacs / 2;
|
||||
ak->num_chips = ak->num_dacs / 2;
|
||||
ak->name = "ak4528";
|
||||
ak->total_regs = 0x06;
|
||||
break;
|
||||
case SND_AK4529:
|
||||
inits = inits_ak4529;
|
||||
num_chips = 1;
|
||||
ak->num_chips = 1;
|
||||
ak->name = "ak4529";
|
||||
ak->total_regs = 0x0d;
|
||||
break;
|
||||
case SND_AK4355:
|
||||
inits = inits_ak4355;
|
||||
num_chips = 1;
|
||||
ak->num_chips = 1;
|
||||
ak->name = "ak4355";
|
||||
ak->total_regs = 0x0b;
|
||||
break;
|
||||
case SND_AK4358:
|
||||
inits = inits_ak4358;
|
||||
num_chips = 1;
|
||||
ak->num_chips = 1;
|
||||
ak->name = "ak4358";
|
||||
ak->total_regs = 0x10;
|
||||
break;
|
||||
case SND_AK4381:
|
||||
inits = inits_ak4381;
|
||||
num_chips = ak->num_dacs / 2;
|
||||
ak->num_chips = ak->num_dacs / 2;
|
||||
ak->name = "ak4381";
|
||||
ak->total_regs = 0x05;
|
||||
break;
|
||||
case SND_AK5365:
|
||||
/* FIXME: any init sequence? */
|
||||
ak->num_chips = 1;
|
||||
ak->name = "ak5365";
|
||||
ak->total_regs = 0x08;
|
||||
return;
|
||||
case SND_AK4620:
|
||||
inits = inits_ak4620;
|
||||
ak->num_chips = ak->num_dacs / 2;
|
||||
ak->name = "ak4620";
|
||||
ak->total_regs = 0x08;
|
||||
break;
|
||||
default:
|
||||
snd_BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
for (chip = 0; chip < num_chips; chip++) {
|
||||
for (chip = 0; chip < ak->num_chips; chip++) {
|
||||
ptr = inits;
|
||||
while (*ptr != 0xff) {
|
||||
reg = *ptr++;
|
||||
data = *ptr++;
|
||||
snd_akm4xxx_write(ak, chip, reg, data);
|
||||
udelay(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -688,6 +720,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
|
||||
AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
|
||||
knew.tlv.p = db_scale_linear;
|
||||
break;
|
||||
case SND_AK4620:
|
||||
/* register 6 & 7 */
|
||||
knew.private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
|
||||
knew.tlv.p = db_scale_linear;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -704,10 +742,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
|
||||
|
||||
static int build_adc_controls(struct snd_akm4xxx *ak)
|
||||
{
|
||||
int idx, err, mixer_ch, num_stereo;
|
||||
int idx, err, mixer_ch, num_stereo, max_steps;
|
||||
struct snd_kcontrol_new knew;
|
||||
|
||||
mixer_ch = 0;
|
||||
if (ak->type == SND_AK4528)
|
||||
return 0; /* no controls */
|
||||
for (idx = 0; idx < ak->num_adcs;) {
|
||||
memset(&knew, 0, sizeof(knew));
|
||||
if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
|
||||
@ -733,13 +773,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
|
||||
}
|
||||
/* register 4 & 5 */
|
||||
if (ak->type == SND_AK5365)
|
||||
knew.private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
|
||||
AK_VOL_CVT | AK_IPGA;
|
||||
max_steps = 152;
|
||||
else
|
||||
knew.private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
|
||||
AK_VOL_CVT | AK_IPGA;
|
||||
max_steps = 164;
|
||||
knew.private_value =
|
||||
AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
|
||||
AK_VOL_CVT | AK_IPGA;
|
||||
knew.tlv.p = db_scale_vol_datt;
|
||||
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
|
||||
if (err < 0)
|
||||
@ -808,6 +847,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
|
||||
switch (ak->type) {
|
||||
case SND_AK4524:
|
||||
case SND_AK4528:
|
||||
case SND_AK4620:
|
||||
/* register 3 */
|
||||
knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
|
||||
break;
|
||||
@ -834,6 +874,35 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
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;
|
||||
int reg, val, chip;
|
||||
for (chip = 0; chip < ak->num_chips; chip++) {
|
||||
for (reg = 0; reg < ak->total_regs; reg++) {
|
||||
val = snd_akm4xxx_get(ak, chip, reg);
|
||||
snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
|
||||
reg, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int proc_init(struct snd_akm4xxx *ak)
|
||||
{
|
||||
struct snd_info_entry *entry;
|
||||
int err;
|
||||
err = snd_card_proc_new(ak->card, ak->name, &entry);
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_info_set_text_ops(entry, ak, proc_regs_read);
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
static int proc_init(struct snd_akm4xxx *ak) {}
|
||||
#endif
|
||||
|
||||
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
||||
{
|
||||
int err, num_emphs;
|
||||
@ -845,18 +914,21 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
|
||||
err = build_adc_controls(ak);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
|
||||
num_emphs = 1;
|
||||
else if (ak->type == SND_AK4620)
|
||||
num_emphs = 0;
|
||||
else
|
||||
num_emphs = ak->num_dacs / 2;
|
||||
err = build_deemphasis(ak, num_emphs);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = proc_init(ak);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
|
||||
|
||||
static int __init alsa_akm4xxx_module_init(void)
|
||||
|
@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (tea->ops->mute) {
|
||||
tea->ops->mute(tea, ctrl->value);
|
||||
tea->mute = 1;
|
||||
tea->mute = ctrl->value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -372,15 +372,21 @@ config SND_SGALAXY
|
||||
|
||||
config SND_SSCAPE
|
||||
tristate "Ensoniq SoundScape driver"
|
||||
select SND_HWDEP
|
||||
select SND_MPU401_UART
|
||||
select SND_WSS_LIB
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here to include support for Ensoniq SoundScape
|
||||
soundcards.
|
||||
and Ensoniq OEM soundcards.
|
||||
|
||||
The PCM audio is supported on SoundScape Classic, Elite, PnP
|
||||
and VIVO cards. The MIDI support is very experimental.
|
||||
and VIVO cards. The supported OEM cards are SPEA Media FX and
|
||||
Reveal SC-600.
|
||||
The MIDI support is very experimental and requires binary
|
||||
firmware files called "scope.cod" and "sndscape.co?" where the
|
||||
? is digit 0, 1, 2, 3 or 4. The firmware files can be found
|
||||
in DOS or Windows driver packages. One has to put the firmware
|
||||
files into the /lib/firmware directory.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-sscape.
|
||||
|
@ -237,7 +237,7 @@ WSS_DOUBLE("Wavetable Capture Volume", 0,
|
||||
CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0),
|
||||
WSS_SINGLE("3D Control - Switch", 0,
|
||||
CMI8330_RMUX3D, 5, 1, 1),
|
||||
WSS_SINGLE("PC Speaker Playback Volume", 0,
|
||||
WSS_SINGLE("Beep Playback Volume", 0,
|
||||
CMI8330_OUTPUTVOL, 3, 3, 0),
|
||||
WSS_DOUBLE("FM Playback Switch", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
@ -262,7 +262,7 @@ SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3,
|
||||
SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
|
||||
SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
|
||||
SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
|
||||
SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
|
||||
SB_SINGLE("SB Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
|
||||
SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
|
||||
SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
|
||||
SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
|
||||
|
@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = snd_wss_create(card, port[dev], cport[dev],
|
||||
err = snd_cs4236_create(card, port[dev], cport[dev],
|
||||
irq[dev],
|
||||
dma1[dev], dma2[dev],
|
||||
WSS_HW_DETECT3, 0, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
acard->chip = chip;
|
||||
if (chip->hardware & WSS_HW_CS4236B_MASK) {
|
||||
snd_wss_free(chip);
|
||||
err = snd_cs4236_create(card,
|
||||
port[dev], cport[dev],
|
||||
irq[dev], dma1[dev], dma2[dev],
|
||||
WSS_HW_DETECT, 0, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
acard->chip = chip;
|
||||
|
||||
err = snd_cs4236_pcm(chip, 0, &pcm);
|
||||
if (err < 0)
|
||||
@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
acard->chip = chip;
|
||||
err = snd_wss_pcm(chip, 0, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -87,6 +87,8 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/wss.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
/*
|
||||
*
|
||||
@ -264,7 +266,10 @@ static void snd_cs4236_resume(struct snd_wss *chip)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* This function does no fail if the chip is not CS4236B or compatible.
|
||||
* It just an equivalent to the snd_wss_create() then.
|
||||
*/
|
||||
int snd_cs4236_create(struct snd_card *card,
|
||||
unsigned long port,
|
||||
unsigned long cport,
|
||||
@ -281,21 +286,17 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
*rchip = NULL;
|
||||
if (hardware == WSS_HW_DETECT)
|
||||
hardware = WSS_HW_DETECT3;
|
||||
if (cport < 0x100) {
|
||||
snd_printk(KERN_ERR "please, specify control port "
|
||||
"for CS4236+ chips\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = snd_wss_create(card, port, cport,
|
||||
irq, dma1, dma2, hardware, hwshare, &chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
|
||||
snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
|
||||
"not available, hardware=0x%x\n", chip->hardware);
|
||||
snd_device_free(card, chip);
|
||||
return -ENODEV;
|
||||
if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
|
||||
snd_printd("chip is not CS4236+, hardware=0x%x\n",
|
||||
chip->hardware);
|
||||
*rchip = chip;
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
@ -308,9 +309,16 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
idx, snd_cs4236_ctrl_in(chip, idx));
|
||||
}
|
||||
#endif
|
||||
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
|
||||
snd_printk(KERN_ERR "please, specify control port "
|
||||
"for CS4236+ chips\n");
|
||||
snd_device_free(card, chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
ver1 = snd_cs4236_ctrl_in(chip, 1);
|
||||
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
|
||||
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
|
||||
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
|
||||
cport, ver1, ver2);
|
||||
if (ver1 != ver2) {
|
||||
snd_printk(KERN_ERR "CS4236+ chip detected, but "
|
||||
"control port 0x%lx is not valid\n", cport);
|
||||
@ -321,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
snd_cs4236_ctrl_out(chip, 2, 0xff);
|
||||
snd_cs4236_ctrl_out(chip, 3, 0x00);
|
||||
snd_cs4236_ctrl_out(chip, 4, 0x80);
|
||||
snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
|
||||
reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
|
||||
IEC958_AES0_CON_EMPHASIS_NONE;
|
||||
snd_cs4236_ctrl_out(chip, 5, reg);
|
||||
snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
|
||||
snd_cs4236_ctrl_out(chip, 7, 0x00);
|
||||
/* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
|
||||
/* is working with this setup, other hardware should have */
|
||||
/* different signal paths and this value should be selectable */
|
||||
/* in the future */
|
||||
/*
|
||||
* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
|
||||
* output is working with this setup, other hardware should
|
||||
* have different signal paths and this value should be
|
||||
* selectable in the future
|
||||
*/
|
||||
snd_cs4236_ctrl_out(chip, 8, 0x8c);
|
||||
chip->rate_constraint = snd_cs4236_xrate;
|
||||
chip->set_playback_format = snd_cs4236_playback_format;
|
||||
@ -339,9 +351,10 @@ int snd_cs4236_create(struct snd_card *card,
|
||||
|
||||
/* initialize extended registers */
|
||||
for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
|
||||
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
|
||||
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
|
||||
snd_cs4236_ext_map[reg]);
|
||||
|
||||
/* initialize compatible but more featured registers */
|
||||
/* initialize compatible but more featured registers */
|
||||
snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
|
||||
snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
|
||||
snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
|
||||
@ -387,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
|
||||
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
|
||||
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
|
||||
|
||||
#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_single, \
|
||||
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
|
||||
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
int mask = (kcontrol->private_value >> 16) & 0xff;
|
||||
@ -490,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
||||
|
||||
#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
|
||||
(shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
int mask = (kcontrol->private_value >> 24) & 0xff;
|
||||
@ -560,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
|
||||
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
|
||||
|
||||
#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
|
||||
shift_right, mask, invert, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
|
||||
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
|
||||
(shift_right << 19) | (mask << 24) | (invert << 22), \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
||||
@ -619,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4236_MASTER_DIGITAL(xname, xindex) \
|
||||
#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
|
||||
.private_value = 71 << 24 }
|
||||
.private_value = 71 << 24, \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
|
||||
{
|
||||
return (vol < 64) ? 63 - vol : 64 + (71 - vol);
|
||||
}
|
||||
}
|
||||
|
||||
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@ -661,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s
|
||||
return change;
|
||||
}
|
||||
|
||||
#define CS4235_OUTPUT_ACCU(xname, xindex) \
|
||||
#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
||||
.info = snd_cs4236_info_double, \
|
||||
.get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
|
||||
.private_value = 3 << 24 }
|
||||
.private_value = 3 << 24, \
|
||||
.tlv = { .p = (xtlv) } }
|
||||
|
||||
static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
|
||||
{
|
||||
@ -720,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_
|
||||
return change;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_cs4236_controls[] = {
|
||||
|
||||
CS4236_DOUBLE("Master Digital Playback Switch", 0,
|
||||
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Master Digital Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
|
||||
|
||||
CS4236_DOUBLE("Capture Boost Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
|
||||
CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
|
||||
db_scale_2bit),
|
||||
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
|
||||
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("DSP Playback Switch", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("DSP Playback Volume", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
|
||||
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("FM Playback Switch", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("FM Playback Volume", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("FM Playback Volume", 0,
|
||||
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("Wavetable Playback Switch", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Wavetable Playback Volume", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
|
||||
CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
|
||||
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
|
||||
db_scale_6bit_12db_max),
|
||||
|
||||
WSS_DOUBLE("Synth Playback Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Synth Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Synth Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Synth Capture Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Synth Capture Bypass", 0,
|
||||
@ -764,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
|
||||
CS4236_DOUBLE("Mic Capture Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
|
||||
CS4236_DOUBLE("Mic Playback Boost", 0,
|
||||
CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
|
||||
0, 0, 31, 1, db_scale_5bit_22db_max),
|
||||
CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Line Capture Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Line Capture Bypass", 0,
|
||||
@ -779,57 +842,63 @@ WSS_DOUBLE("Line Capture Bypass", 0,
|
||||
|
||||
WSS_DOUBLE("CD Playback Switch", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("CD Volume", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("CD Volume", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("CD Capture Switch", 0,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
|
||||
CS4236_DOUBLE1("Mono Output Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
|
||||
CS4236_DOUBLE1("Mono Playback Switch", 0,
|
||||
CS4236_DOUBLE1("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
|
||||
WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
|
||||
WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
|
||||
db_scale_4bit),
|
||||
WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Capture Volume", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
|
||||
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
|
||||
0, 0, 15, 0, db_scale_rec_gain),
|
||||
WSS_DOUBLE("Analog Loopback Capture Switch", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
|
||||
|
||||
WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
|
||||
CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
|
||||
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
|
||||
WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
|
||||
CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
|
||||
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_cs4235_controls[] = {
|
||||
|
||||
WSS_DOUBLE("Master Switch", 0,
|
||||
WSS_DOUBLE("Master Playback Switch", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Master Volume", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Master Playback Volume", 0,
|
||||
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
|
||||
db_scale_5bit_6db_max),
|
||||
|
||||
CS4235_OUTPUT_ACCU("Playback Volume", 0),
|
||||
CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
|
||||
|
||||
CS4236_DOUBLE("Master Digital Playback Switch", 0,
|
||||
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Master Digital Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
|
||||
|
||||
WSS_DOUBLE("Master Digital Playback Switch", 1,
|
||||
WSS_DOUBLE("Synth Playback Switch", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Master Digital Capture Switch", 1,
|
||||
WSS_DOUBLE("Synth Capture Switch", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Master Digital Volume", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Synth Volume", 1,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
CS4236_DOUBLE("Capture Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
|
||||
CS4236_DOUBLE_TLV("Capture Volume", 0,
|
||||
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
|
||||
db_scale_2bit),
|
||||
|
||||
WSS_DOUBLE("PCM Switch", 0,
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
|
||||
WSS_DOUBLE("PCM Capture Switch", 0,
|
||||
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
|
||||
WSS_DOUBLE_TLV("PCM Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
|
||||
CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
|
||||
|
||||
@ -842,29 +911,29 @@ CS4236_DOUBLE("Mic Capture Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
|
||||
CS4236_DOUBLE("Mic Playback Switch", 0,
|
||||
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
|
||||
CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
|
||||
CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
|
||||
CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
|
||||
db_scale_5bit_22db_max),
|
||||
CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
|
||||
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Capture Switch", 0,
|
||||
WSS_DOUBLE("Line Capture Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Aux Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Line Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
WSS_DOUBLE("Aux Playback Switch", 1,
|
||||
WSS_DOUBLE("CD Playback Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Capture Switch", 1,
|
||||
WSS_DOUBLE("CD Capture Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
|
||||
WSS_DOUBLE("Aux Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("CD Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
|
||||
CS4236_DOUBLE1("Master Mono Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
|
||||
|
||||
CS4236_DOUBLE1("Mono Switch", 0,
|
||||
CS4236_DOUBLE1("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
|
||||
WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
|
||||
|
||||
WSS_DOUBLE("Analog Loopback Switch", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
|
||||
|
@ -982,7 +982,7 @@ ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0
|
||||
ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0),
|
||||
ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0),
|
||||
ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0),
|
||||
ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
|
||||
ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
|
||||
ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0),
|
||||
ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1),
|
||||
{
|
||||
|
@ -102,8 +102,6 @@
|
||||
|
||||
struct snd_es18xx {
|
||||
unsigned long port; /* port of ESS chip */
|
||||
unsigned long mpu_port; /* MPU-401 port of ESS chip */
|
||||
unsigned long fm_port; /* FM port */
|
||||
unsigned long ctrl_port; /* Control port of ESS chip */
|
||||
struct resource *res_port;
|
||||
struct resource *res_mpu_port;
|
||||
@ -116,12 +114,9 @@ struct snd_es18xx {
|
||||
unsigned short audio2_vol; /* volume level of audio2 */
|
||||
|
||||
unsigned short active; /* active channel mask */
|
||||
unsigned int dma1_size;
|
||||
unsigned int dma2_size;
|
||||
unsigned int dma1_shift;
|
||||
unsigned int dma2_shift;
|
||||
|
||||
struct snd_card *card;
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_pcm_substream *playback_a_substream;
|
||||
struct snd_pcm_substream *capture_a_substream;
|
||||
@ -136,14 +131,9 @@ struct snd_es18xx {
|
||||
|
||||
spinlock_t reg_lock;
|
||||
spinlock_t mixer_lock;
|
||||
spinlock_t ctrl_lock;
|
||||
#ifdef CONFIG_PM
|
||||
unsigned char pm_reg;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct snd_audiodrive {
|
||||
struct snd_es18xx *chip;
|
||||
#ifdef CONFIG_PNP
|
||||
struct pnp_dev *dev;
|
||||
struct pnp_dev *devc;
|
||||
@ -359,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch
|
||||
}
|
||||
|
||||
|
||||
static int snd_es18xx_reset(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_reset(struct snd_es18xx *chip)
|
||||
{
|
||||
int i;
|
||||
outb(0x03, chip->port + 0x06);
|
||||
@ -495,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip,
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma2_size = size;
|
||||
|
||||
snd_es18xx_rate_set(chip, substream, DAC2);
|
||||
|
||||
/* Transfer Count Reload */
|
||||
@ -596,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma1_size = size;
|
||||
|
||||
snd_es18xx_reset_fifo(chip);
|
||||
|
||||
/* Set stereo/mono */
|
||||
@ -664,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip,
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
unsigned int count = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
chip->dma1_size = size;
|
||||
|
||||
snd_es18xx_reset_fifo(chip);
|
||||
|
||||
/* Set stereo/mono */
|
||||
@ -755,7 +739,8 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream,
|
||||
|
||||
static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_es18xx *chip = dev_id;
|
||||
struct snd_card *card = dev_id;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
unsigned char status;
|
||||
|
||||
if (chip->caps & ES18XX_CONTROL) {
|
||||
@ -805,12 +790,16 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
|
||||
int split = 0;
|
||||
if (chip->caps & ES18XX_HWV) {
|
||||
split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
|
||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
|
||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&chip->hw_switch->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&chip->hw_volume->id);
|
||||
}
|
||||
if (!split) {
|
||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
|
||||
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&chip->master_switch->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&chip->master_volume->id);
|
||||
}
|
||||
/* ack interrupt */
|
||||
snd_es18xx_mixer_write(chip, 0x66, 0x00);
|
||||
@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
|
||||
static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
int pos;
|
||||
|
||||
if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) {
|
||||
if (!(chip->active & DAC2))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma2, chip->dma2_size);
|
||||
pos = snd_dma_pointer(chip->dma2, size);
|
||||
return pos >> chip->dma2_shift;
|
||||
} else {
|
||||
if (!(chip->active & DAC1))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
|
||||
pos = snd_dma_pointer(chip->dma1, size);
|
||||
return pos >> chip->dma1_shift;
|
||||
}
|
||||
}
|
||||
@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s
|
||||
static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_es18xx *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
|
||||
int pos;
|
||||
|
||||
if (!(chip->active & ADC1))
|
||||
return 0;
|
||||
pos = snd_dma_pointer(chip->dma1, chip->dma1_size);
|
||||
pos = snd_dma_pointer(chip->dma1, size);
|
||||
return pos >> chip->dma1_shift;
|
||||
}
|
||||
|
||||
@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
|
||||
|
||||
static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static char *texts4Source[4] = {
|
||||
"Mic", "CD", "Line", "Master"
|
||||
};
|
||||
static char *texts5Source[5] = {
|
||||
"Mic", "CD", "Line", "Master", "Mix"
|
||||
};
|
||||
@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
|
||||
uinfo->value.enumerated.items = 4;
|
||||
if (uinfo->value.enumerated.item > 3)
|
||||
uinfo->value.enumerated.item = 3;
|
||||
strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
texts5Source[uinfo->value.enumerated.item]);
|
||||
break;
|
||||
case 0x1887:
|
||||
case 0x1888:
|
||||
@ -1313,7 +1302,7 @@ ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
|
||||
* The chipset specific mixer controls
|
||||
*/
|
||||
static struct snd_kcontrol_new snd_es18xx_opt_speaker =
|
||||
ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0);
|
||||
ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
|
||||
ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
|
||||
@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
|
||||
static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
|
||||
{
|
||||
int data;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&chip->ctrl_lock, flags);
|
||||
|
||||
outb(reg, chip->ctrl_port);
|
||||
data = inb(chip->ctrl_port + 1);
|
||||
spin_unlock_irqrestore(&chip->ctrl_lock, flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip,
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip,
|
||||
unsigned long mpu_port,
|
||||
unsigned long fm_port)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
if (chip->caps & ES18XX_CONTROL) {
|
||||
/* Hardware volume IRQ */
|
||||
snd_es18xx_config_write(chip, 0x27, chip->irq);
|
||||
if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
|
||||
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
|
||||
/* FM I/O */
|
||||
snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
|
||||
snd_es18xx_config_write(chip, 0x62, fm_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x63, fm_port & 0xff);
|
||||
}
|
||||
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
|
||||
if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
|
||||
/* MPU-401 I/O */
|
||||
snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
|
||||
snd_es18xx_config_write(chip, 0x64, mpu_port >> 8);
|
||||
snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff);
|
||||
/* MPU-401 IRQ */
|
||||
snd_es18xx_config_write(chip, 0x28, chip->irq);
|
||||
}
|
||||
@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
|
||||
snd_es18xx_mixer_write(chip, 0x7A, 0x68);
|
||||
/* Enable and set hardware volume interrupt */
|
||||
snd_es18xx_mixer_write(chip, 0x64, 0x06);
|
||||
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
|
||||
if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) {
|
||||
/* MPU401 share irq with audio
|
||||
Joystick enabled
|
||||
FM enabled */
|
||||
snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1);
|
||||
snd_es18xx_mixer_write(chip, 0x40,
|
||||
0x43 | (mpu_port & 0xf0) >> 1);
|
||||
}
|
||||
snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01);
|
||||
}
|
||||
@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_probe(struct snd_es18xx *chip,
|
||||
unsigned long mpu_port,
|
||||
unsigned long fm_port)
|
||||
{
|
||||
if (snd_es18xx_identify(chip) < 0) {
|
||||
snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
|
||||
@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
|
||||
break;
|
||||
case 0x1887:
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
|
||||
break;
|
||||
case 0x1888:
|
||||
chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
|
||||
break;
|
||||
@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip)
|
||||
if (chip->dma1 == chip->dma2)
|
||||
chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
|
||||
|
||||
return snd_es18xx_initialize(chip);
|
||||
return snd_es18xx_initialize(chip, mpu_port, fm_port);
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops snd_es18xx_playback_ops = {
|
||||
@ -1691,8 +1681,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
|
||||
.pointer = snd_es18xx_capture_pointer,
|
||||
};
|
||||
|
||||
static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm)
|
||||
static int __devinit snd_es18xx_pcm(struct snd_card *card, int device,
|
||||
struct snd_pcm **rpcm)
|
||||
{
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
struct snd_pcm *pcm;
|
||||
char str[16];
|
||||
int err;
|
||||
@ -1701,9 +1693,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
|
||||
*rpcm = NULL;
|
||||
sprintf(str, "ES%x", chip->version);
|
||||
if (chip->caps & ES18XX_PCM2)
|
||||
err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm);
|
||||
err = snd_pcm_new(card, str, device, 2, 1, &pcm);
|
||||
else
|
||||
err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm);
|
||||
err = snd_pcm_new(card, str, device, 1, 1, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -1734,10 +1726,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct
|
||||
#ifdef CONFIG_PM
|
||||
static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
|
||||
{
|
||||
struct snd_audiodrive *acard = card->private_data;
|
||||
struct snd_es18xx *chip = acard->chip;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
|
||||
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
|
||||
snd_pcm_suspend_all(chip->pcm);
|
||||
|
||||
@ -1752,24 +1743,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state)
|
||||
|
||||
static int snd_es18xx_resume(struct snd_card *card)
|
||||
{
|
||||
struct snd_audiodrive *acard = card->private_data;
|
||||
struct snd_es18xx *chip = acard->chip;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
|
||||
/* restore PM register, we won't wake till (not 0x07) i/o activity though */
|
||||
snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM);
|
||||
|
||||
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int snd_es18xx_free(struct snd_es18xx *chip)
|
||||
static int snd_es18xx_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
|
||||
release_and_free_resource(chip->res_port);
|
||||
release_and_free_resource(chip->res_ctrl_port);
|
||||
release_and_free_resource(chip->res_mpu_port);
|
||||
if (chip->irq >= 0)
|
||||
free_irq(chip->irq, (void *) chip);
|
||||
free_irq(chip->irq, (void *) card);
|
||||
if (chip->dma1 >= 0) {
|
||||
disable_dma(chip->dma1);
|
||||
free_dma(chip->dma1);
|
||||
@ -1778,93 +1770,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip)
|
||||
disable_dma(chip->dma2);
|
||||
free_dma(chip->dma2);
|
||||
}
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_es18xx_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct snd_es18xx *chip = device->device_data;
|
||||
return snd_es18xx_free(chip);
|
||||
return snd_es18xx_free(device->card);
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_new_device(struct snd_card *card,
|
||||
unsigned long port,
|
||||
unsigned long mpu_port,
|
||||
unsigned long fm_port,
|
||||
int irq, int dma1, int dma2,
|
||||
struct snd_es18xx ** rchip)
|
||||
int irq, int dma1, int dma2)
|
||||
{
|
||||
struct snd_es18xx *chip;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
static struct snd_device_ops ops = {
|
||||
.dev_free = snd_es18xx_dev_free,
|
||||
};
|
||||
int err;
|
||||
|
||||
*rchip = NULL;
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&chip->reg_lock);
|
||||
spin_lock_init(&chip->mixer_lock);
|
||||
spin_lock_init(&chip->ctrl_lock);
|
||||
chip->card = card;
|
||||
chip->port = port;
|
||||
chip->mpu_port = mpu_port;
|
||||
chip->fm_port = fm_port;
|
||||
chip->irq = -1;
|
||||
chip->dma1 = -1;
|
||||
chip->dma2 = -1;
|
||||
chip->audio2_vol = 0x00;
|
||||
chip->active = 0;
|
||||
|
||||
if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) {
|
||||
snd_es18xx_free(chip);
|
||||
chip->res_port = request_region(port, 16, "ES18xx");
|
||||
if (chip->res_port == NULL) {
|
||||
snd_es18xx_free(card);
|
||||
snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) {
|
||||
snd_es18xx_free(chip);
|
||||
if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx",
|
||||
(void *) card)) {
|
||||
snd_es18xx_free(card);
|
||||
snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
chip->irq = irq;
|
||||
|
||||
if (request_dma(dma1, "ES18xx DMA 1")) {
|
||||
snd_es18xx_free(chip);
|
||||
snd_es18xx_free(card);
|
||||
snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1);
|
||||
return -EBUSY;
|
||||
}
|
||||
chip->dma1 = dma1;
|
||||
|
||||
if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) {
|
||||
snd_es18xx_free(chip);
|
||||
snd_es18xx_free(card);
|
||||
snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
|
||||
return -EBUSY;
|
||||
}
|
||||
chip->dma2 = dma2;
|
||||
|
||||
if (snd_es18xx_probe(chip) < 0) {
|
||||
snd_es18xx_free(chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
|
||||
snd_es18xx_free(chip);
|
||||
if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
|
||||
snd_es18xx_free(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
|
||||
if (err < 0) {
|
||||
snd_es18xx_free(card);
|
||||
return err;
|
||||
}
|
||||
*rchip = chip;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip)
|
||||
static int __devinit snd_es18xx_mixer(struct snd_card *card)
|
||||
{
|
||||
struct snd_card *card;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
int err;
|
||||
unsigned int idx;
|
||||
|
||||
card = chip->card;
|
||||
|
||||
strcpy(card->mixername, chip->pcm->name);
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) {
|
||||
@ -1986,7 +1967,7 @@ 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_ISAPNP; /* Enable this card */
|
||||
#ifdef CONFIG_PNP
|
||||
static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
|
||||
static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
|
||||
#endif
|
||||
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
|
||||
#ifndef CONFIG_PNP
|
||||
@ -2063,11 +2044,11 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
|
||||
static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip,
|
||||
struct pnp_dev *pdev)
|
||||
{
|
||||
acard->dev = pdev;
|
||||
if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
|
||||
chip->dev = pdev;
|
||||
if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
@ -2093,26 +2074,26 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);
|
||||
|
||||
static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
|
||||
static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
|
||||
struct pnp_card_link *card,
|
||||
const struct pnp_card_device_id *id)
|
||||
{
|
||||
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
|
||||
if (acard->dev == NULL)
|
||||
chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
|
||||
if (chip->dev == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
|
||||
if (acard->devc == NULL)
|
||||
chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
|
||||
if (chip->devc == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
/* Control port initialization */
|
||||
if (pnp_activate_dev(acard->devc) < 0) {
|
||||
if (pnp_activate_dev(chip->devc) < 0) {
|
||||
snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
snd_printdd("pnp: port=0x%llx\n",
|
||||
(unsigned long long)pnp_port_start(acard->devc, 0));
|
||||
if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
|
||||
(unsigned long long)pnp_port_start(chip->devc, 0));
|
||||
if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
@ -2128,24 +2109,20 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
|
||||
static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
|
||||
{
|
||||
return snd_card_create(index[dev], id[dev], THIS_MODULE,
|
||||
sizeof(struct snd_audiodrive), cardp);
|
||||
sizeof(struct snd_es18xx), cardp);
|
||||
}
|
||||
|
||||
static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
|
||||
{
|
||||
struct snd_audiodrive *acard = card->private_data;
|
||||
struct snd_es18xx *chip;
|
||||
struct snd_es18xx *chip = card->private_data;
|
||||
struct snd_opl3 *opl3;
|
||||
int err;
|
||||
|
||||
if ((err = snd_es18xx_new_device(card,
|
||||
port[dev],
|
||||
mpu_port[dev],
|
||||
fm_port[dev],
|
||||
irq[dev], dma1[dev], dma2[dev],
|
||||
&chip)) < 0)
|
||||
err = snd_es18xx_new_device(card,
|
||||
port[dev], mpu_port[dev], fm_port[dev],
|
||||
irq[dev], dma1[dev], dma2[dev]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
acard->chip = chip;
|
||||
|
||||
sprintf(card->driver, "ES%x", chip->version);
|
||||
|
||||
@ -2161,26 +2138,32 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
|
||||
chip->port,
|
||||
irq[dev], dma1[dev]);
|
||||
|
||||
if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0)
|
||||
err = snd_es18xx_pcm(card, 0, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if ((err = snd_es18xx_mixer(chip)) < 0)
|
||||
err = snd_es18xx_mixer(card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
|
||||
if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
|
||||
OPL3_HW_OPL3, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING PFX
|
||||
"opl3 not detected at 0x%lx\n",
|
||||
fm_port[dev]);
|
||||
} else {
|
||||
if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
|
||||
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
|
||||
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
|
||||
chip->mpu_port, 0,
|
||||
irq[dev], 0,
|
||||
&chip->rmidi)) < 0)
|
||||
err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
|
||||
mpu_port[dev], 0,
|
||||
irq[dev], 0, &chip->rmidi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -141,15 +141,7 @@ struct snd_opti9xx {
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
long wss_base;
|
||||
int irq;
|
||||
int dma1;
|
||||
int dma2;
|
||||
|
||||
long fm_port;
|
||||
|
||||
long mpu_port;
|
||||
int mpu_irq;
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
struct pnp_dev *dev;
|
||||
@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
chip->wss_base = -1;
|
||||
chip->irq = -1;
|
||||
chip->dma1 = -1;
|
||||
chip->dma2 = -1;
|
||||
chip->fm_port = -1;
|
||||
chip->mpu_port = -1;
|
||||
chip->mpu_irq = -1;
|
||||
|
||||
switch (hardware) {
|
||||
#ifndef OPTi93X
|
||||
@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
|
||||
(snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask)))
|
||||
|
||||
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
|
||||
long wss_base,
|
||||
int irq, int dma1, int dma2,
|
||||
long mpu_port, int mpu_irq)
|
||||
{
|
||||
unsigned char wss_base_bits;
|
||||
unsigned char irq_bits;
|
||||
@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (chip->wss_base) {
|
||||
switch (wss_base) {
|
||||
case 0x530:
|
||||
wss_base_bits = 0x00;
|
||||
break;
|
||||
@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
|
||||
wss_base_bits = 0x02;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
|
||||
chip->wss_base);
|
||||
snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
|
||||
goto __skip_base;
|
||||
}
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
|
||||
|
||||
__skip_base:
|
||||
switch (chip->irq) {
|
||||
switch (irq) {
|
||||
//#ifdef OPTi93X
|
||||
case 5:
|
||||
irq_bits = 0x05;
|
||||
@ -456,11 +444,11 @@ __skip_base:
|
||||
irq_bits = 0x04;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
|
||||
snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
|
||||
goto __skip_resources;
|
||||
}
|
||||
|
||||
switch (chip->dma1) {
|
||||
switch (dma1) {
|
||||
case 0:
|
||||
dma_bits = 0x01;
|
||||
break;
|
||||
@ -471,38 +459,36 @@ __skip_base:
|
||||
dma_bits = 0x03;
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
|
||||
chip->dma1);
|
||||
snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
|
||||
goto __skip_resources;
|
||||
}
|
||||
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
if (chip->dma1 == chip->dma2) {
|
||||
if (dma1 == dma2) {
|
||||
snd_printk(KERN_ERR "don't want to share dmas\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
switch (chip->dma2) {
|
||||
switch (dma2) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
|
||||
chip->dma2);
|
||||
snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
|
||||
goto __skip_resources;
|
||||
}
|
||||
dma_bits |= 0x04;
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
#ifndef OPTi93X
|
||||
outb(irq_bits << 3 | dma_bits, chip->wss_base);
|
||||
outb(irq_bits << 3 | dma_bits, wss_base);
|
||||
#else /* OPTi93X */
|
||||
snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
|
||||
#endif /* OPTi93X */
|
||||
|
||||
__skip_resources:
|
||||
if (chip->hardware > OPTi9XX_HW_82C928) {
|
||||
switch (chip->mpu_port) {
|
||||
switch (mpu_port) {
|
||||
case 0:
|
||||
case -1:
|
||||
break;
|
||||
@ -520,12 +506,11 @@ __skip_resources:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING
|
||||
"MPU-401 port 0x%lx not valid\n",
|
||||
chip->mpu_port);
|
||||
"MPU-401 port 0x%lx not valid\n", mpu_port);
|
||||
goto __skip_mpu;
|
||||
}
|
||||
|
||||
switch (chip->mpu_irq) {
|
||||
switch (mpu_irq) {
|
||||
case 5:
|
||||
mpu_irq_bits = 0x02;
|
||||
break;
|
||||
@ -540,12 +525,12 @@ __skip_resources:
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
|
||||
chip->mpu_irq);
|
||||
mpu_irq);
|
||||
goto __skip_mpu;
|
||||
}
|
||||
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6),
|
||||
(chip->mpu_port <= 0) ? 0x00 :
|
||||
(mpu_port <= 0) ? 0x00 :
|
||||
0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
|
||||
0xf8);
|
||||
}
|
||||
@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
{
|
||||
static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
|
||||
int error;
|
||||
int xdma2;
|
||||
struct snd_opti9xx *chip = card->private_data;
|
||||
struct snd_wss *codec;
|
||||
#ifdef CS4231
|
||||
@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
"OPTi9xx MC")) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->wss_base = port;
|
||||
chip->fm_port = fm_port;
|
||||
chip->mpu_port = mpu_port;
|
||||
chip->irq = irq;
|
||||
chip->mpu_irq = mpu_irq;
|
||||
chip->dma1 = dma1;
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
chip->dma2 = dma2;
|
||||
xdma2 = dma2;
|
||||
#else
|
||||
chip->dma2 = -1;
|
||||
xdma2 = -1;
|
||||
#endif
|
||||
|
||||
if (chip->wss_base == SNDRV_AUTO_PORT) {
|
||||
chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
|
||||
if (chip->wss_base < 0) {
|
||||
if (port == SNDRV_AUTO_PORT) {
|
||||
port = snd_legacy_find_free_ioport(possible_ports, 4);
|
||||
if (port < 0) {
|
||||
snd_printk(KERN_ERR "unable to find a free WSS port\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
error = snd_opti9xx_configure(chip);
|
||||
error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
|
||||
mpu_port, mpu_irq);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = snd_wss_create(card, chip->wss_base + 4, -1,
|
||||
chip->irq, chip->dma1, chip->dma2,
|
||||
error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
|
||||
#ifdef OPTi93X
|
||||
WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
|
||||
#else
|
||||
@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
return error;
|
||||
#endif
|
||||
#ifdef OPTi93X
|
||||
error = request_irq(chip->irq, snd_opti93x_interrupt,
|
||||
error = request_irq(irq, snd_opti93x_interrupt,
|
||||
IRQF_DISABLED, DEV_NAME" - WSS", codec);
|
||||
if (error < 0) {
|
||||
snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
chip->irq = irq;
|
||||
strcpy(card->driver, chip->name);
|
||||
sprintf(card->shortname, "OPTi %s", card->driver);
|
||||
#if defined(CS4231) || defined(OPTi93X)
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
|
||||
card->shortname, pcm->name, chip->wss_base + 4,
|
||||
chip->irq, chip->dma1, chip->dma2);
|
||||
card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
|
||||
#else
|
||||
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
|
||||
card->shortname, pcm->name, chip->wss_base + 4,
|
||||
chip->irq, chip->dma1);
|
||||
card->shortname, pcm->name, port + 4, irq, dma1);
|
||||
#endif /* CS4231 || OPTi93X */
|
||||
|
||||
if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT)
|
||||
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
|
||||
rmidi = NULL;
|
||||
else
|
||||
if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED,
|
||||
&rmidi)))
|
||||
else {
|
||||
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
|
||||
mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi);
|
||||
if (error)
|
||||
snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
|
||||
chip->mpu_port);
|
||||
mpu_port);
|
||||
}
|
||||
|
||||
if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
|
||||
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
|
||||
struct snd_opl3 *opl3 = NULL;
|
||||
#ifndef OPTi93X
|
||||
if (chip->hardware == OPTi9XX_HW_82C928 ||
|
||||
@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
/* assume we have an OPL4 */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
|
||||
0x20, 0x20);
|
||||
if (snd_opl4_create(card,
|
||||
chip->fm_port,
|
||||
chip->fm_port - 8,
|
||||
if (snd_opl4_create(card, fm_port, fm_port - 8,
|
||||
2, &opl3, &opl4) < 0) {
|
||||
/* no luck, use OPL3 instead */
|
||||
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
|
||||
@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
}
|
||||
}
|
||||
#endif /* !OPTi93X */
|
||||
if (!opl3 && snd_opl3_create(card,
|
||||
chip->fm_port,
|
||||
chip->fm_port + 2,
|
||||
if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
|
||||
OPL3_HW_AUTO, 0, &opl3) < 0) {
|
||||
snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
|
||||
chip->fm_port, chip->fm_port + 4 - 1);
|
||||
fm_port, fm_port + 4 - 1);
|
||||
}
|
||||
if (opl3) {
|
||||
error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
|
||||
|
@ -631,7 +631,7 @@ static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
|
||||
static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
|
||||
SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
|
||||
static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
|
||||
SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
|
||||
SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
|
||||
static struct sbmix_elem snd_sb16_ctl_capture_vol =
|
||||
SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
|
||||
static struct sbmix_elem snd_sb16_ctl_play_vol =
|
||||
@ -689,7 +689,7 @@ static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
|
||||
static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
|
||||
SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
|
||||
static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
|
||||
SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
|
||||
SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7);
|
||||
static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
|
||||
SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
|
||||
static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
int snd_wss_free(struct snd_wss *chip)
|
||||
static int snd_wss_free(struct snd_wss *chip)
|
||||
{
|
||||
release_and_free_resource(chip->res_port);
|
||||
release_and_free_resource(chip->res_cport);
|
||||
@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip)
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_wss_free);
|
||||
|
||||
static int snd_wss_dev_free(struct snd_device *device)
|
||||
{
|
||||
@ -2198,64 +2197,26 @@ EXPORT_SYMBOL(snd_wss_put_double);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_ad1848_controls[] = {
|
||||
WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
|
||||
7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Aux Playback Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Aux Playback Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
|
||||
0, 0, 15, 0, db_scale_rec_gain),
|
||||
{
|
||||
.name = "Capture Source",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.info = snd_wss_info_mux,
|
||||
.get = snd_wss_get_mux,
|
||||
.put = snd_wss_put_mux,
|
||||
},
|
||||
WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
|
||||
WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
|
||||
db_scale_6bit),
|
||||
};
|
||||
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
|
||||
|
||||
static struct snd_kcontrol_new snd_wss_controls[] = {
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Line Playback Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
|
||||
db_scale_6bit),
|
||||
WSS_DOUBLE("Aux Playback Switch", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Playback Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
|
||||
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE("Aux Playback Switch", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Aux Playback Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
|
||||
WSS_SINGLE("Mono Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 7, 1, 1),
|
||||
WSS_SINGLE("Mono Playback Volume", 0,
|
||||
CS4231_MONO_CTRL, 0, 15, 1),
|
||||
WSS_SINGLE("Mono Output Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 6, 1, 1),
|
||||
WSS_SINGLE("Mono Output Playback Bypass", 0,
|
||||
CS4231_MONO_CTRL, 5, 1, 0),
|
||||
WSS_DOUBLE("Capture Volume", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
|
||||
WSS_DOUBLE_TLV("Aux Playback Volume", 1,
|
||||
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
|
||||
0, 0, 15, 0, db_scale_rec_gain),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
@ -2263,19 +2224,34 @@ WSS_DOUBLE("Capture Volume", 0,
|
||||
.get = snd_wss_get_mux,
|
||||
.put = snd_wss_put_mux,
|
||||
},
|
||||
WSS_DOUBLE("Mic Boost", 0,
|
||||
WSS_DOUBLE("Mic Boost (+20dB)", 0,
|
||||
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
|
||||
WSS_SINGLE("Loopback Capture Switch", 0,
|
||||
CS4231_LOOPBACK, 0, 1, 0),
|
||||
WSS_SINGLE("Loopback Capture Volume", 0,
|
||||
CS4231_LOOPBACK, 2, 63, 1)
|
||||
WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1,
|
||||
db_scale_6bit),
|
||||
WSS_DOUBLE("Line Playback Switch", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
|
||||
WSS_DOUBLE_TLV("Line Playback Volume", 0,
|
||||
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
|
||||
db_scale_5bit_12db_max),
|
||||
WSS_SINGLE("Beep Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 7, 1, 1),
|
||||
WSS_SINGLE_TLV("Beep Playback Volume", 0,
|
||||
CS4231_MONO_CTRL, 0, 15, 1,
|
||||
db_scale_4bit),
|
||||
WSS_SINGLE("Mono Output Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 6, 1, 1),
|
||||
WSS_SINGLE("Beep Bypass Playback Switch", 0,
|
||||
CS4231_MONO_CTRL, 5, 1, 0),
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new snd_opti93x_controls[] = {
|
||||
WSS_DOUBLE("Master Playback Switch", 0,
|
||||
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("Master Playback Volume", 0,
|
||||
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
|
||||
WSS_DOUBLE_TLV("Master Playback Volume", 0,
|
||||
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
|
||||
db_scale_6bit),
|
||||
WSS_DOUBLE("PCM Playback Switch", 0,
|
||||
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
|
||||
WSS_DOUBLE("PCM Playback Volume", 0,
|
||||
@ -2334,22 +2310,21 @@ int snd_wss_mixer(struct snd_wss *chip)
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
else if (chip->hardware & WSS_HW_AD1848_MASK)
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(&snd_ad1848_controls[idx],
|
||||
chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
|
||||
else {
|
||||
int count = ARRAY_SIZE(snd_wss_controls);
|
||||
|
||||
/* Use only the first 11 entries on AD1848 */
|
||||
if (chip->hardware & WSS_HW_AD1848_MASK)
|
||||
count = 11;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
err = snd_ctl_add(card,
|
||||
snd_ctl_new1(&snd_wss_controls[idx],
|
||||
chip));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_wss_mixer);
|
||||
|
@ -287,18 +287,6 @@ config SOUND_DMAP
|
||||
|
||||
Say Y unless you have 16MB or more RAM or a PCI sound card.
|
||||
|
||||
config SOUND_SSCAPE
|
||||
tristate "Ensoniq SoundScape support"
|
||||
help
|
||||
Answer Y if you have a sound card based on the Ensoniq SoundScape
|
||||
chipset. Such cards are being manufactured at least by Ensoniq, Spea
|
||||
and Reveal (Reveal makes also other cards).
|
||||
|
||||
If you compile the driver into the kernel, you have to add
|
||||
"sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
|
||||
line.
|
||||
|
||||
|
||||
config SOUND_VMIDI
|
||||
tristate "Loopback MIDI device support"
|
||||
help
|
||||
|
@ -13,7 +13,6 @@ 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
|
||||
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
|
||||
obj-$(CONFIG_SOUND_MSS) += ad1848.o
|
||||
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
|
||||
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
|
||||
|
@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg)
|
||||
if ((err = audio_devs[dev]->d->prepare_for_input(dev,
|
||||
dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
|
||||
spin_unlock_irqrestore(&dmap_in->lock,flags);
|
||||
return -err;
|
||||
return err;
|
||||
}
|
||||
dmap_in->dma_mode = DMODE_INPUT;
|
||||
audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;
|
||||
|
@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode)
|
||||
int err;
|
||||
struct midi_input_info *inc;
|
||||
|
||||
if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
|
||||
if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
midi2synth[orig_dev] = dev;
|
||||
|
@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
|
||||
|
||||
midi_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
|
||||
if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
devc = &dev_conf[midi_dev];
|
||||
|
@ -164,9 +164,6 @@ static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
|
||||
int free;
|
||||
int nbytes;
|
||||
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!count) {
|
||||
dac_audio_sync();
|
||||
return 0;
|
||||
|
1480
sound/oss/sscape.c
1480
sound/oss/sscape.c
File diff suppressed because it is too large
Load Diff
@ -570,6 +570,7 @@ config SND_ICE1712
|
||||
tristate "ICEnsemble ICE1712 (Envy24)"
|
||||
select SND_MPU401_UART
|
||||
select SND_AC97_CODEC
|
||||
select BITREVERSE
|
||||
help
|
||||
Say Y here to include support for soundcards based on the
|
||||
ICE1712 (Envy24) chip.
|
||||
|
@ -603,8 +603,8 @@ AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1)
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_controls_pc_beep[2] = {
|
||||
AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1),
|
||||
AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)
|
||||
AC97_SINGLE("Beep Playback Switch", AC97_PC_BEEP, 15, 1, 1),
|
||||
AC97_SINGLE("Beep Playback Volume", AC97_PC_BEEP, 1, 15, 1)
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new snd_ac97_controls_mic_boost =
|
||||
@ -1393,7 +1393,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
|
||||
}
|
||||
}
|
||||
|
||||
/* build PC Speaker controls */
|
||||
/* build Beep controls */
|
||||
if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) &&
|
||||
((ac97->flags & AC97_HAS_PC_BEEP) ||
|
||||
snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) {
|
||||
|
@ -800,12 +800,12 @@ AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
|
||||
AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
|
||||
AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
|
||||
|
||||
AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
|
||||
AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
|
||||
AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
|
||||
AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
|
||||
AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
|
||||
AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
|
||||
AC97_SINGLE("Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
|
||||
AC97_SINGLE("Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
|
||||
AC97_SINGLE("Beep to Master Switch", AC97_AUX, 11, 1, 1),
|
||||
AC97_SINGLE("Beep to Master Volume", AC97_AUX, 8, 7, 1),
|
||||
AC97_SINGLE("Beep to Mono Switch", AC97_AUX, 7, 1, 1),
|
||||
AC97_SINGLE("Beep to Mono Volume", AC97_AUX, 4, 7, 1),
|
||||
|
||||
AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
|
||||
AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
|
||||
|
@ -830,8 +830,8 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = {
|
||||
AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0),
|
||||
AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1),
|
||||
AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1),
|
||||
AZF3328_MIXER_SWITCH("PC Speaker Playback Switch", IDX_MIXER_PCBEEP, 15, 1),
|
||||
AZF3328_MIXER_VOL_SPECIAL("PC Speaker Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1),
|
||||
AZF3328_MIXER_SWITCH("Beep Playback Switch", IDX_MIXER_PCBEEP, 15, 1),
|
||||
AZF3328_MIXER_VOL_SPECIAL("Beep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1),
|
||||
AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1),
|
||||
AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1),
|
||||
AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1),
|
||||
|
@ -792,8 +792,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
|
||||
"Phone Playback Volume",
|
||||
"Video Playback Switch",
|
||||
"Video Playback Volume",
|
||||
"PC Speaker Playback Switch",
|
||||
"PC Speaker Playback Volume",
|
||||
"Beep Playback Switch",
|
||||
"Beep Playback Volume",
|
||||
"Mono Output Select",
|
||||
"Capture Source",
|
||||
"Capture Switch",
|
||||
|
@ -304,7 +304,7 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry,
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%x %x", ®, &val) != 2)
|
||||
continue;
|
||||
if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
|
||||
if (reg < 0x40 && val <= 0xffffffff) {
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
outl(val, emu->port + (reg & 0xfffffffc));
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
@ -405,7 +405,7 @@ static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry,
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3)
|
||||
continue;
|
||||
if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
|
||||
if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3)
|
||||
snd_ca0106_ptr_write(emu, reg, channel_id, val);
|
||||
}
|
||||
}
|
||||
|
@ -2302,7 +2302,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
|
||||
CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
|
||||
CMIPCI_SB_SW_MONO("Mic Playback Switch", 0),
|
||||
CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0),
|
||||
CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
|
||||
CMIPCI_SB_VOL_MONO("Beep Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
|
||||
CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
|
||||
CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
|
||||
CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
|
||||
@ -2310,7 +2310,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
|
||||
CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
|
||||
CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
|
||||
CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
|
||||
CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
|
||||
CMIPCI_DOUBLE("Beep Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
|
||||
CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
|
||||
};
|
||||
|
||||
|
@ -240,7 +240,7 @@ static int select_rom(unsigned int pitch)
|
||||
} else if (pitch == 0x02000000) {
|
||||
/* pitch == 2 */
|
||||
return 3;
|
||||
} else if (pitch >= 0x0 && pitch <= 0x08000000) {
|
||||
} else if (pitch <= 0x08000000) {
|
||||
/* 0 <= pitch <= 8 */
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
|
||||
if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3)
|
||||
continue;
|
||||
|
||||
if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff)
|
||||
&& (channel_id >= 0) && (channel_id <= 2) )
|
||||
if (reg < 0x49 && val <= 0xffffffff && channel_id <= 2)
|
||||
snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
|
||||
}
|
||||
}
|
||||
|
@ -1818,8 +1818,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
|
||||
"Master Playback Switch", "Master Capture Switch",
|
||||
"Master Playback Volume", "Master Capture Volume",
|
||||
"Wave Master Playback Volume", "Master Playback Volume",
|
||||
"PC Speaker Playback Switch", "PC Speaker Capture Switch",
|
||||
"PC Speaker Playback Volume", "PC Speaker Capture Volume",
|
||||
"Beep Playback Switch", "Beep Capture Switch",
|
||||
"Beep Playback Volume", "Beep Capture Volume",
|
||||
"Phone Playback Switch", "Phone Capture Switch",
|
||||
"Phone Playback Volume", "Phone Capture Volume",
|
||||
"Mic Playback Switch", "Mic Capture Switch",
|
||||
|
@ -451,7 +451,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry,
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%x %x", ®, &val) != 2)
|
||||
continue;
|
||||
if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) {
|
||||
if (reg < 0x40 && val <= 0xffffffff) {
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
outl(val, emu->port + (reg & 0xfffffffc));
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
@ -527,7 +527,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3)
|
||||
continue;
|
||||
if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) )
|
||||
if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3)
|
||||
snd_ptr_write(emu, iobase, reg, channel_id, val);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
|
||||
if (reg > 0x3f)
|
||||
return 1;
|
||||
reg += 0x40; /* 0x40 upwards are registers. */
|
||||
if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
|
||||
if (value > 0x3f) /* 0 to 0x3f are values */
|
||||
return 1;
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
outl(reg, emu->port + A_IOCFG);
|
||||
|
@ -1387,7 +1387,7 @@ ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0,
|
||||
db_scale_line),
|
||||
ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0,
|
||||
db_scale_capture),
|
||||
ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),
|
||||
ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0),
|
||||
ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
|
||||
ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
|
||||
* 1 = MediaForte 256-PCS
|
||||
* 2 = MediaForte 256-PCPR
|
||||
* 3 = MediaForte 64-PCR
|
||||
* 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
|
||||
* 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
|
||||
* High 16-bits are video (radio) device number + 1
|
||||
*/
|
||||
static int tea575x_tuner[SNDRV_CARDS];
|
||||
@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
|
||||
module_param_array(tea575x_tuner, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner.");
|
||||
MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
|
||||
|
||||
#define TUNER_ONLY (1<<4)
|
||||
#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF)
|
||||
|
||||
/*
|
||||
* Direct registers
|
||||
@ -160,7 +163,7 @@ struct fm801 {
|
||||
unsigned int multichannel: 1, /* multichannel support */
|
||||
secondary: 1; /* secondary codec */
|
||||
unsigned char secondary_addr; /* address of the secondary codec */
|
||||
unsigned int tea575x_tuner; /* tuner flags */
|
||||
unsigned int tea575x_tuner; /* tuner access method & flags */
|
||||
|
||||
unsigned short ply_ctrl; /* playback control */
|
||||
unsigned short cap_ctrl; /* capture control */
|
||||
@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
{
|
||||
unsigned short cmdw;
|
||||
|
||||
if (chip->tea575x_tuner & 0x0010)
|
||||
if (chip->tea575x_tuner & TUNER_ONLY)
|
||||
goto __ac97_ok;
|
||||
|
||||
/* codec cold reset + AC'97 warm reset */
|
||||
@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
udelay(100);
|
||||
outw(0, FM801_REG(chip, CODEC_CTRL));
|
||||
|
||||
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) {
|
||||
snd_printk(KERN_ERR "Primary AC'97 codec not found\n");
|
||||
if (! resume)
|
||||
return -EIO;
|
||||
}
|
||||
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
|
||||
if (!resume) {
|
||||
snd_printk(KERN_INFO "Primary AC'97 codec not found, "
|
||||
"assume SF64-PCR (tuner-only)\n");
|
||||
chip->tea575x_tuner = 3 | TUNER_ONLY;
|
||||
goto __ac97_ok;
|
||||
}
|
||||
|
||||
if (chip->multichannel) {
|
||||
if (chip->secondary_addr) {
|
||||
@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
return err;
|
||||
}
|
||||
chip->port = pci_resource_start(pci, 0);
|
||||
if ((tea575x_tuner & 0x0010) == 0) {
|
||||
if ((tea575x_tuner & TUNER_ONLY) == 0) {
|
||||
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
|
||||
"FM801", chip)) {
|
||||
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
|
||||
@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
chip->multichannel = 1;
|
||||
|
||||
snd_fm801_chip_init(chip, 0);
|
||||
/* init might set tuner access method */
|
||||
tea575x_tuner = chip->tea575x_tuner;
|
||||
|
||||
if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
|
||||
pci_clear_master(pci);
|
||||
free_irq(chip->irq, chip);
|
||||
chip->irq = -1;
|
||||
}
|
||||
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
|
||||
snd_fm801_free(chip);
|
||||
@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card,
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
||||
#ifdef TEA575X_RADIO
|
||||
if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
|
||||
if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
|
||||
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
|
||||
chip->tea.dev_nr = tea575x_tuner >> 16;
|
||||
chip->tea.card = card;
|
||||
chip->tea.freq_fixup = 10700;
|
||||
chip->tea.private_data = chip;
|
||||
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];
|
||||
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
|
||||
snd_tea575x_init(&chip->tea);
|
||||
}
|
||||
#endif
|
||||
@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
|
||||
sprintf(card->longname, "%s at 0x%lx, irq %i",
|
||||
card->shortname, chip->port, chip->irq);
|
||||
|
||||
if (tea575x_tuner[dev] & 0x0010)
|
||||
if (chip->tea575x_tuner & TUNER_ONLY)
|
||||
goto __fm801_tuner_only;
|
||||
|
||||
if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
|
||||
|
@ -38,9 +38,20 @@ config SND_HDA_INPUT_BEEP
|
||||
Say Y here to build a digital beep interface for HD-audio
|
||||
driver. This interface is used to generate digital beeps.
|
||||
|
||||
config SND_HDA_INPUT_BEEP_MODE
|
||||
int "Digital beep registration mode (0=off, 1=on, 2=mute sw on/off)"
|
||||
depends on SND_HDA_INPUT_BEEP=y
|
||||
default "1"
|
||||
range 0 2
|
||||
help
|
||||
Set 0 to disable the digital beep interface for HD-audio by default.
|
||||
Set 1 to always enable the digital beep interface for HD-audio by
|
||||
default. Set 2 to control the beep device registration to input
|
||||
layer using a "Beep Switch" in mixer applications.
|
||||
|
||||
config SND_HDA_INPUT_JACK
|
||||
bool "Support jack plugging notification via input layer"
|
||||
depends on INPUT=y || INPUT=SND_HDA_INTEL
|
||||
depends on INPUT=y || INPUT=SND
|
||||
select SND_JACK
|
||||
help
|
||||
Say Y here to enable the jack plugging notification via
|
||||
|
@ -113,23 +113,25 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
|
||||
static void snd_hda_do_detach(struct hda_beep *beep)
|
||||
{
|
||||
input_unregister_device(beep->dev);
|
||||
beep->dev = NULL;
|
||||
cancel_work_sync(&beep->beep_work);
|
||||
/* turn off beep for sure */
|
||||
snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
|
||||
AC_VERB_SET_BEEP_CONTROL, 0);
|
||||
}
|
||||
|
||||
static int snd_hda_do_attach(struct hda_beep *beep)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
struct hda_beep *beep;
|
||||
struct hda_codec *codec = beep->codec;
|
||||
int err;
|
||||
|
||||
if (!snd_hda_get_bool_hint(codec, "beep"))
|
||||
return 0; /* disabled explicitly */
|
||||
|
||||
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
|
||||
if (beep == NULL)
|
||||
return -ENOMEM;
|
||||
snprintf(beep->phys, sizeof(beep->phys),
|
||||
"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
kfree(beep);
|
||||
printk(KERN_INFO "hda_beep: unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -151,21 +153,96 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
|
||||
err = input_register_device(input_dev);
|
||||
if (err < 0) {
|
||||
input_free_device(input_dev);
|
||||
kfree(beep);
|
||||
printk(KERN_INFO "hda_beep: unable to register input device\n");
|
||||
return err;
|
||||
}
|
||||
beep->dev = input_dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_hda_do_register(struct work_struct *work)
|
||||
{
|
||||
struct hda_beep *beep =
|
||||
container_of(work, struct hda_beep, register_work);
|
||||
|
||||
mutex_lock(&beep->mutex);
|
||||
if (beep->enabled && !beep->dev)
|
||||
snd_hda_do_attach(beep);
|
||||
mutex_unlock(&beep->mutex);
|
||||
}
|
||||
|
||||
static void snd_hda_do_unregister(struct work_struct *work)
|
||||
{
|
||||
struct hda_beep *beep =
|
||||
container_of(work, struct hda_beep, unregister_work.work);
|
||||
|
||||
mutex_lock(&beep->mutex);
|
||||
if (!beep->enabled && beep->dev)
|
||||
snd_hda_do_detach(beep);
|
||||
mutex_unlock(&beep->mutex);
|
||||
}
|
||||
|
||||
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
|
||||
{
|
||||
struct hda_beep *beep = codec->beep;
|
||||
enable = !!enable;
|
||||
if (beep == NULL)
|
||||
return 0;
|
||||
if (beep->enabled != enable) {
|
||||
beep->enabled = enable;
|
||||
if (!enable) {
|
||||
/* turn off beep */
|
||||
snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
|
||||
AC_VERB_SET_BEEP_CONTROL, 0);
|
||||
}
|
||||
if (beep->mode == HDA_BEEP_MODE_SWREG) {
|
||||
if (enable) {
|
||||
cancel_delayed_work(&beep->unregister_work);
|
||||
schedule_work(&beep->register_work);
|
||||
} else {
|
||||
schedule_delayed_work(&beep->unregister_work,
|
||||
HZ);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
|
||||
|
||||
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
|
||||
{
|
||||
struct hda_beep *beep;
|
||||
|
||||
if (!snd_hda_get_bool_hint(codec, "beep"))
|
||||
return 0; /* disabled explicitly by hints */
|
||||
if (codec->beep_mode == HDA_BEEP_MODE_OFF)
|
||||
return 0; /* disabled by module option */
|
||||
|
||||
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
|
||||
if (beep == NULL)
|
||||
return -ENOMEM;
|
||||
snprintf(beep->phys, sizeof(beep->phys),
|
||||
"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
|
||||
/* enable linear scale */
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, 0x01);
|
||||
|
||||
beep->nid = nid;
|
||||
beep->dev = input_dev;
|
||||
beep->codec = codec;
|
||||
beep->enabled = 1;
|
||||
beep->mode = codec->beep_mode;
|
||||
codec->beep = beep;
|
||||
|
||||
INIT_WORK(&beep->register_work, &snd_hda_do_register);
|
||||
INIT_DELAYED_WORK(&beep->unregister_work, &snd_hda_do_unregister);
|
||||
INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
|
||||
mutex_init(&beep->mutex);
|
||||
|
||||
if (beep->mode == HDA_BEEP_MODE_ON) {
|
||||
beep->enabled = 1;
|
||||
snd_hda_do_register(&beep->register_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
|
||||
@ -174,11 +251,12 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_beep *beep = codec->beep;
|
||||
if (beep) {
|
||||
cancel_work_sync(&beep->beep_work);
|
||||
|
||||
input_unregister_device(beep->dev);
|
||||
kfree(beep);
|
||||
cancel_work_sync(&beep->register_work);
|
||||
cancel_delayed_work(&beep->unregister_work);
|
||||
if (beep->enabled)
|
||||
snd_hda_do_detach(beep);
|
||||
codec->beep = NULL;
|
||||
kfree(beep);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
|
||||
|
@ -24,19 +24,29 @@
|
||||
|
||||
#include "hda_codec.h"
|
||||
|
||||
#define HDA_BEEP_MODE_OFF 0
|
||||
#define HDA_BEEP_MODE_ON 1
|
||||
#define HDA_BEEP_MODE_SWREG 2
|
||||
|
||||
/* beep information */
|
||||
struct hda_beep {
|
||||
struct input_dev *dev;
|
||||
struct hda_codec *codec;
|
||||
unsigned int mode;
|
||||
char phys[32];
|
||||
int tone;
|
||||
hda_nid_t nid;
|
||||
unsigned int enabled:1;
|
||||
unsigned int request_enable:1;
|
||||
unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */
|
||||
struct work_struct register_work; /* registration work */
|
||||
struct delayed_work unregister_work; /* unregistration work */
|
||||
struct work_struct beep_work; /* scheduled task for beep event */
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||||
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
|
||||
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
|
||||
void snd_hda_detach_beep_device(struct hda_codec *codec);
|
||||
#else
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -286,6 +286,10 @@ enum {
|
||||
#define AC_PWRST_D1SUP (1<<1)
|
||||
#define AC_PWRST_D2SUP (1<<2)
|
||||
#define AC_PWRST_D3SUP (1<<3)
|
||||
#define AC_PWRST_D3COLDSUP (1<<4)
|
||||
#define AC_PWRST_S3D3COLDSUP (1<<29)
|
||||
#define AC_PWRST_CLKSTOP (1<<30)
|
||||
#define AC_PWRST_EPSS (1U<<31)
|
||||
|
||||
/* Power state values */
|
||||
#define AC_PWRST_SETTING (0xf<<0)
|
||||
@ -674,6 +678,7 @@ struct hda_codec_ops {
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
|
||||
#endif
|
||||
void (*reboot_notify)(struct hda_codec *codec);
|
||||
};
|
||||
|
||||
/* record for amp information cache */
|
||||
@ -771,6 +776,7 @@ struct hda_codec {
|
||||
|
||||
/* beep device */
|
||||
struct hda_beep *beep;
|
||||
unsigned int beep_mode;
|
||||
|
||||
/* widget capabilities cache */
|
||||
unsigned int num_nodes;
|
||||
@ -811,6 +817,9 @@ struct hda_codec {
|
||||
unsigned int power_transition :1; /* power-state in transition */
|
||||
int power_count; /* current (global) power refcount */
|
||||
struct delayed_work power_work; /* delayed task for powerdown */
|
||||
unsigned long power_on_acct;
|
||||
unsigned long power_off_acct;
|
||||
unsigned long power_jiffies;
|
||||
#endif
|
||||
|
||||
/* codec-specific additional proc output */
|
||||
@ -910,6 +919,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
|
||||
* Misc
|
||||
*/
|
||||
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
|
||||
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
|
||||
|
||||
/*
|
||||
* power management
|
||||
@ -933,6 +943,7 @@ const char *snd_hda_get_jack_location(u32 cfg);
|
||||
void snd_hda_power_up(struct hda_codec *codec);
|
||||
void snd_hda_power_down(struct hda_codec *codec);
|
||||
#define snd_hda_codec_needs_resume(codec) codec->power_count
|
||||
void snd_hda_update_power_acct(struct hda_codec *codec);
|
||||
#else
|
||||
static inline void snd_hda_power_up(struct hda_codec *codec) {}
|
||||
static inline void snd_hda_power_down(struct hda_codec *codec) {}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user