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:
Linus Torvalds 2009-12-08 07:47:46 -08:00
commit a421018e8c
285 changed files with 21221 additions and 7650 deletions

View File

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

View File

@ -18,8 +18,9 @@ SOURCE:
Master
Master Mono
Hardware Master
Speaker (internal speaker)
Headphone
PC Speaker
Beep (beep generator)
Phone
Phone Input
Phone Output

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View 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__ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
else
page = snd_pcm_default_page_ops(substream, offset);
if (!page)
return VM_FAULT_SIGBUS;
} else {
vaddr = runtime->dma_area + offset;
page = virt_to_page(vaddr);
}
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,12 +773,11 @@ 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
max_steps = 164;
knew.private_value =
AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
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));
@ -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)

View File

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

View File

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

View File

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

View File

@ -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;
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;
if (chip->hardware & WSS_HW_CS4236B_MASK) {
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;

View File

@ -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,7 +351,8 @@ 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 */
snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
@ -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,11 +661,13 @@ 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)
{
@ -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),

View File

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

View File

@ -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);
if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) {
snd_es18xx_free(card);
return -ENODEV;
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_es18xx_free(chip);
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

View File

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

View File

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

View File

@ -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,10 +2197,11 @@ 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 const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 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),
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_TLV("PCM Playback Volume", 0,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
db_scale_6bit),
@ -2217,45 +2217,6 @@ WSS_DOUBLE_TLV("Aux Playback Volume", 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 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("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("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),
{
.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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
if (sscanf(line, "%x %x %x", &reg, &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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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,10 +1299,12 @@ 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) {
@ -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) {

View File

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

View File

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

View File

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

View File

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