提交 710421cc 编写于 作者: L Linus Torvalds

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: (346 commits)
  ASoC: core: Don't set "(null)" as a driver name
  ALSA: hda - Use LPIB for ATI/AMD chipsets as default
  Revert "ALSA: hda - Use position_fix=3 as default for AMD chipsets"
  ASoC: Tegra: Fix compile when debugfs not enabled
  ASoC: spdif-dit: Add missing MODULE_*
  SOUND: OSS: Remove Au1550 driver.
  ALSA: hda - add Intel Panther Point HDMI codec id
  ALSA: emu10k1 - Add dB range to Bass and Treble for SB Live!
  ALSA: hda - Remove PCM mixer elements from Virtual Master of realtek
  ALSA: hda - Fix input-src parse in patch_analog.c
  ASoC: davinci-mcasp: enable ping-pong SRAM buffers
  ASoC: add iPAQ hx4700 machine driver
  ASoC: Asahi Kasei AK4641 codec driver
  ALSA: hda - Enable Realtek ALC269 codec input layer beep
  ALSA: intel8x0m: enable AMD8111 modem
  ALSA: HDA: Add jack detection for HDMI
  ALSA: sound, core, pcm_lib: fix xrun_log
  ASoC: Max98095: Move existing NULL check before pointer dereference.
  ALSA: sound, core, pcm_lib: xrun_log: log also in_interrupt
  ALSA: usb-audio - Add support for USB X-Fi S51 Pro
  ...
......@@ -1230,6 +1230,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-lola
---------------
Module for Digigram Lola PCI-e boards
This module supports multiple cards.
Module snd-lx6464es
-------------------
......
......@@ -94,7 +94,7 @@ ALC662/663/272
3stack-dig 3-stack (2-channel) with SPDIF
3stack-6ch 3-stack (6-channel)
3stack-6ch-dig 3-stack (6-channel) with SPDIF
6stack-dig 6-stack with SPDIF
5stack-dig 5-stack with SPDIF
lenovo-101e Lenovo laptop
eeepc-p701 ASUS Eeepc P701
eeepc-ep20 ASUS Eeepc EP20
......
......@@ -4269,6 +4269,13 @@ M: Tim Hockin <thockin@hockin.org>
S: Maintained
F: drivers/net/natsemi.c
NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
M: Daniel Mack <zonque@gmail.com>
S: Maintained
L: alsa-devel@alsa-project.org
W: http://www.native-instruments.com
F: sound/usb/caiaq/
NCP FILESYSTEM
M: Petr Vandrovec <petr@vandrovec.name>
S: Odd Fixes
......@@ -5868,7 +5875,7 @@ F: include/sound/
F: sound/
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
M: Liam Girdwood <lrg@slimlogic.co.uk>
M: Liam Girdwood <lrg@ti.com>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
......@@ -6119,7 +6126,7 @@ F: drivers/mmc/host/tifm_sd.c
F: include/linux/tifm.h
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@nokia.com>
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/codecs/twl4030*
......@@ -6763,7 +6770,7 @@ F: drivers/scsi/vmw_pvscsi.c
F: drivers/scsi/vmw_pvscsi.h
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
M: Liam Girdwood <lrg@slimlogic.co.uk>
M: Liam Girdwood <lrg@ti.com>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?p=48
......
......@@ -27,12 +27,14 @@ comment "Tegra board type"
config MACH_HARMONY
bool "Harmony board"
select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for nVidia Harmony development platform
config MACH_KAEN
bool "Kaen board"
select MACH_SEABOARD
select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for the Kaen version of Seaboard
......@@ -43,6 +45,7 @@ config MACH_PAZ00
config MACH_SEABOARD
bool "Seaboard board"
select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for nVidia Seaboard development platform. It will
also be included for some of the derivative boards that
......
......@@ -34,7 +34,7 @@
#include <asm/mach/time.h>
#include <asm/setup.h>
#include <mach/harmony_audio.h>
#include <mach/tegra_wm8903_pdata.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
#include <mach/sdhci.h>
......@@ -67,15 +67,16 @@ static struct platform_device debug_uart = {
},
};
static struct harmony_audio_platform_data harmony_audio_pdata = {
static struct tegra_wm8903_platform_data harmony_audio_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
.gpio_hp_mute = -1,
.gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
.gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
};
static struct platform_device harmony_audio_device = {
.name = "tegra-snd-harmony",
.name = "tegra-snd-wm8903",
.id = 0,
.dev = {
.platform_data = &harmony_audio_pdata,
......
/*
* arch/arm/mach-tegra/include/mach/harmony_audio.h
* arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
*
* Copyright 2011 NVIDIA, Inc.
*
......@@ -14,9 +14,10 @@
*
*/
struct harmony_audio_platform_data {
struct tegra_wm8903_platform_data {
int gpio_spkr_en;
int gpio_hp_det;
int gpio_hp_mute;
int gpio_int_mic_en;
int gpio_ext_mic_en;
};
......@@ -166,21 +166,6 @@ config RADIO_MAXIRADIO
To compile this driver as a module, choose M here: the
module will be called radio-maxiradio.
config RADIO_MAESTRO
tristate "Maestro on board radio"
depends on VIDEO_V4L2 && PCI
---help---
Say Y here to directly support the on-board radio tuner on the
Maestro 2 or 2E sound card.
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-maestro.
config RADIO_MIROPCM20
tristate "miroSOUND PCM20 radio"
depends on ISA && VIDEO_V4L2 && SND
......
......@@ -16,7 +16,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
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/
......
/* Maestro PCI sound card radio driver for Linux support
* (c) 2000 A. Tlalka, atlka@pg.gda.pl
* Notes on the hardware
*
* + Frequency control is done digitally
* + No volume control - only mute/unmute - you have to use Aux line volume
* control on Maestro card to set the volume
* + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
* frequency setting (>100ms) and only when the radio is unmuted.
* version 0.02
* + io port is automatically detected - only the first radio is used
* version 0.03
* + thread access locking additions
* version 0.04
* + code improvements
* + VIDEO_TUNER_LOW is permanent
*
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#include <linux/pci.h>
#include <linux/videodev2.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
MODULE_LICENSE("GPL");
static int radio_nr = -1;
module_param(radio_nr, int, 0);
#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
#define DRIVER_VERSION "0.06"
#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
#define IO_MASK 4 /* mask register offset from GPIO_DATA
bits 1=unmask write to given bit */
#define IO_DIR 8 /* direction register offset from GPIO_DATA
bits 0/1=read/write direction */
#define GPIO6 0x0040 /* mask bits for GPIO lines */
#define GPIO7 0x0080
#define GPIO8 0x0100
#define GPIO9 0x0200
#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */
#define STR_CLK GPIO7
#define STR_WREN GPIO8
#define STR_MOST GPIO9
#define FREQ_LO 50*16000
#define FREQ_HI 150*16000
#define FREQ_IF 171200 /* 10.7*16000 */
#define FREQ_STEP 200 /* 12.5*16 */
#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
/(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
struct maestro {
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct pci_dev *pdev;
struct mutex lock;
u16 io; /* base of Maestro card radio io (GPIO_DATA)*/
u16 muted; /* VIDEO_AUDIO_MUTE */
u16 stereo; /* VIDEO_TUNER_STEREO_ON */
u16 tuned; /* signal strength (0 or 0xffff) */
};
static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
{
return container_of(v4l2_dev, struct maestro, v4l2_dev);
}
static u32 radio_bits_get(struct maestro *dev)
{
u16 io = dev->io, l, rdata;
u32 data = 0;
u16 omask;
omask = inw(io + IO_MASK);
outw(~(STR_CLK | STR_WREN), io + IO_MASK);
outw(0, io);
udelay(16);
for (l = 24; l--;) {
outw(STR_CLK, io); /* HI state */
udelay(2);
if (!l)
dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
outw(0, io); /* LO state */
udelay(2);
data <<= 1; /* shift data */
rdata = inw(io);
if (!l)
dev->stereo = (rdata & STR_MOST) ? 0 : 1;
else if (rdata & STR_DATA)
data++;
udelay(2);
}
if (dev->muted)
outw(STR_WREN, io);
udelay(4);
outw(omask, io + IO_MASK);
return data & 0x3ffe;
}
static void radio_bits_set(struct maestro *dev, u32 data)
{
u16 io = dev->io, l, bits;
u16 omask, odir;
omask = inw(io + IO_MASK);
odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
outw(odir | STR_DATA, io + IO_DIR);
outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
udelay(16);
for (l = 25; l; l--) {
bits = ((data >> 18) & STR_DATA) | STR_WREN;
data <<= 1; /* shift data */
outw(bits, io); /* start strobe */
udelay(2);
outw(bits | STR_CLK, io); /* HI level */
udelay(2);
outw(bits, io); /* LO level */
udelay(4);
}
if (!dev->muted)
outw(0, io);
udelay(4);
outw(omask, io + IO_MASK);
outw(odir, io + IO_DIR);
msleep(125);
}
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
struct maestro *dev = video_drvdata(file);
strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
strlcpy(v->card, "Maestro Radio", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
v->version = RADIO_VERSION;
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
return 0;
}
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct maestro *dev = video_drvdata(file);
if (v->index > 0)
return -EINVAL;
mutex_lock(&dev->lock);
radio_bits_get(dev);
strlcpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_LO;
v->rangehigh = FREQ_HI;
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
v->capability = V4L2_TUNER_CAP_LOW;
if (dev->stereo)
v->audmode = V4L2_TUNER_MODE_STEREO;
else
v->audmode = V4L2_TUNER_MODE_MONO;
v->signal = dev->tuned;
mutex_unlock(&dev->lock);
return 0;
}
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
return v->index ? -EINVAL : 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct maestro *dev = video_drvdata(file);
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
return -EINVAL;
mutex_lock(&dev->lock);
radio_bits_set(dev, FREQ2BITS(f->frequency));
mutex_unlock(&dev->lock);
return 0;
}
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct maestro *dev = video_drvdata(file);
if (f->tuner != 0)
return -EINVAL;
f->type = V4L2_TUNER_RADIO;
mutex_lock(&dev->lock);
f->frequency = BITS2FREQ(radio_bits_get(dev));
mutex_unlock(&dev->lock);
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 maestro *dev = video_drvdata(file);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = dev->muted;
return 0;
}
return -EINVAL;
}
static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct maestro *dev = video_drvdata(file);
u16 io = dev->io;
u16 omask;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
mutex_lock(&dev->lock);
omask = inw(io + IO_MASK);
outw(~STR_WREN, io + IO_MASK);
dev->muted = ctrl->value;
outw(dev->muted ? STR_WREN : 0, io);
udelay(4);
outw(omask, io + IO_MASK);
msleep(125);
mutex_unlock(&dev->lock);
return 0;
}
return -EINVAL;
}
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_file_operations maestro_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.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,
};
static u16 __devinit radio_power_on(struct maestro *dev)
{
register u16 io = dev->io;
register u32 ofreq;
u16 omask, odir;
omask = inw(io + IO_MASK);
odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
outw(odir & ~STR_WREN, io + IO_DIR);
dev->muted = inw(io) & STR_WREN ? 0 : 1;
outw(odir, io + IO_DIR);
outw(~(STR_WREN | STR_CLK), io + IO_MASK);
outw(dev->muted ? 0 : STR_WREN, io);
udelay(16);
outw(omask, io + IO_MASK);
ofreq = radio_bits_get(dev);
if ((ofreq < FREQ2BITS(FREQ_LO)) || (ofreq > FREQ2BITS(FREQ_HI)))
ofreq = FREQ2BITS(FREQ_LO);
radio_bits_set(dev, ofreq);
return (ofreq == radio_bits_get(dev));
}
static int __devinit maestro_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct maestro *dev;
struct v4l2_device *v4l2_dev;
int retval;
retval = pci_enable_device(pdev);
if (retval) {
dev_err(&pdev->dev, "enabling pci device failed!\n");
goto err;
}
retval = -ENOMEM;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev_err(&pdev->dev, "not enough memory\n");
goto err;
}
v4l2_dev = &dev->v4l2_dev;
mutex_init(&dev->lock);
dev->pdev = pdev;
strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
retval = v4l2_device_register(&pdev->dev, v4l2_dev);
if (retval < 0) {
v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
goto errfr;
}
dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
dev->vdev.fops = &maestro_fops;
dev->vdev.ioctl_ops = &maestro_ioctl_ops;
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
if (!radio_power_on(dev)) {
retval = -EIO;
goto errfr1;
}
retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1;
}
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0;
errfr1:
v4l2_device_unregister(v4l2_dev);
errfr:
kfree(dev);
err:
return retval;
}
static void __devexit maestro_remove(struct pci_dev *pdev)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
struct maestro *dev = to_maestro(v4l2_dev);
video_unregister_device(&dev->vdev);
v4l2_device_unregister(&dev->v4l2_dev);
}
static struct pci_device_id maestro_r_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
.class_mask = 0xffff00 },
{ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
.class_mask = 0xffff00 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
static struct pci_driver maestro_r_driver = {
.name = "maestro_radio",
.id_table = maestro_r_pci_tbl,
.probe = maestro_probe,
.remove = __devexit_p(maestro_remove),
};
static int __init maestro_radio_init(void)
{
int retval = pci_register_driver(&maestro_r_driver);
if (retval)
printk(KERN_ERR "error during registration pci driver\n");
return retval;
}
static void __exit maestro_radio_exit(void)
{
pci_unregister_driver(&maestro_r_driver);
}
module_init(maestro_radio_init);
module_exit(maestro_radio_exit);
......@@ -508,7 +508,6 @@ int register_sst_card(struct intel_sst_card_ops *card)
sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
card->pcm_control = sst_pmic_ops.pcm_control;
sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
} else {
pr_err("strcmp fail %s\n", card->module_name);
......
......@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/firmware.h>
#include <sound/control.h>
#include <asm/mrst.h>
#include <sound/pcm.h>
......@@ -40,6 +41,8 @@
#include <sound/initval.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
#include "intelmid_snd_control.h"
#include "intelmid.h"
......@@ -802,6 +805,7 @@ static int __devinit snd_intelmad_sst_register(
pr_err("sst card registration failed\n");
return ret_val;
}
sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
intelmaddata->pmic_status = PMIC_UNINIT;
......
......@@ -32,6 +32,10 @@ struct wm8994_ldo_pdata {
#define WM8994_EQ_REGS 20
#define WM8958_MBC_CUTOFF_REGS 20
#define WM8958_MBC_COEFF_REGS 48
#define WM8958_MBC_COMBINED_REGS 56
#define WM8958_VSS_HPF_REGS 2
#define WM8958_VSS_REGS 148
#define WM8958_ENH_EQ_REGS 32
/**
* DRC configurations are specified with a label and a set of register
......@@ -71,6 +75,42 @@ struct wm8958_mbc_cfg {
const char *name;
u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
u16 coeff_regs[WM8958_MBC_COEFF_REGS];
/* Coefficient layout when using MBC+VSS firmware */
u16 combined_regs[WM8958_MBC_COMBINED_REGS];
};
/**
* VSS HPF configurations are specified with a label and two values to
* write. Configurations are expected to be generated using the
* multiband compressor configuration panel in WISCE - see
* http://www.wolfsonmicro.com/wisce/
*/
struct wm8958_vss_hpf_cfg {
const char *name;
u16 regs[WM8958_VSS_HPF_REGS];
};
/**
* VSS configurations are specified with a label and array of values
* to write. Configurations are expected to be generated using the
* multiband compressor configuration panel in WISCE - see
* http://www.wolfsonmicro.com/wisce/
*/
struct wm8958_vss_cfg {
const char *name;
u16 regs[WM8958_VSS_REGS];
};
/**
* Enhanced EQ configurations are specified with a label and array of
* values to write. Configurations are expected to be generated using
* the multiband compressor configuration panel in WISCE - see
* http://www.wolfsonmicro.com/wisce/
*/
struct wm8958_enh_eq_cfg {
const char *name;
u16 regs[WM8958_ENH_EQ_REGS];
};
struct wm8994_pdata {
......@@ -95,6 +135,15 @@ struct wm8994_pdata {
int num_mbc_cfgs;
struct wm8958_mbc_cfg *mbc_cfgs;
int num_vss_cfgs;
struct wm8958_vss_cfg *vss_cfgs;
int num_vss_hpf_cfgs;
struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
int num_enh_eq_cfgs;
struct wm8958_enh_eq_cfg *enh_eq_cfgs;
/* LINEOUT can be differential or single ended */
unsigned int lineout1_diff:1;
unsigned int lineout2_diff:1;
......
/*
* AK4641 ALSA SoC Codec driver
*
* Copyright 2009 Philipp Zabel
*
* 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 __AK4641_H
#define __AK4641_H
/**
* struct ak4641_platform_data - platform specific AK4641 configuration
* @gpio_power: GPIO to control external power to AK4641
* @gpio_npdn: GPIO connected to AK4641 nPDN pin
*
* Both GPIO parameters are optional.
*/
struct ak4641_platform_data {
int gpio_power;
int gpio_npdn;
};
#endif /* __AK4641_H */
......@@ -113,6 +113,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, v
void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
......
/*
* Platform data for MAX98095
*
* Copyright 2011 Maxim Integrated Products
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __SOUND_MAX98095_PDATA_H__
#define __SOUND_MAX98095_PDATA_H__
/* Equalizer filter response configuration */
struct max98095_eq_cfg {
const char *name;
unsigned int rate;
u16 band1[5];
u16 band2[5];
u16 band3[5];
u16 band4[5];
u16 band5[5];
};
/* Biquad filter response configuration */
struct max98095_biquad_cfg {
const char *name;
unsigned int rate;
u16 band1[5];
u16 band2[5];
};
/* codec platform data */
struct max98095_pdata {
/* Equalizers for DAI1 and DAI2 */
struct max98095_eq_cfg *eq_cfg;
unsigned int eq_cfgcnt;
/* Biquad filter for DAI1 and DAI2 */
struct max98095_biquad_cfg *bq_cfg;
unsigned int bq_cfgcnt;
/* Analog/digital microphone configuration:
* 0 = analog microphone input (normal setting)
* 1 = digital microphone input
*/
unsigned int digmic_left_mode:1;
unsigned int digmic_right_mode:1;
};
#endif
......@@ -24,7 +24,7 @@
* SoC dynamic audio power management
*
* We can have up to 4 power domains
* 1. Codec domain - VREF, VMID
* 1. Codec domain - VREF, VMID
* Usually controlled at codec probe/remove, although can be set
* at stream time if power is not needed for sidetone, etc.
* 2. Platform/Machine domain - physically connected inputs and outputs
......@@ -39,30 +39,30 @@
/* codec domain */
#define SND_SOC_DAPM_VMID(wname) \
{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0}
/* platform domain */
#define SND_SOC_DAPM_INPUT(wname) \
{ .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
#define SND_SOC_DAPM_OUTPUT(wname) \
{ .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
#define SND_SOC_DAPM_MIC(wname, wevent) \
{ .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
#define SND_SOC_DAPM_HP(wname, wevent) \
{ .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_SPK(wname, wevent) \
{ .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_LINE(wname, wevent) \
{ .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
......@@ -70,91 +70,91 @@
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = 1}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
wcontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = ARRAY_SIZE(wcontrols)}
/* path domain with event - event handler must return 0 for success */
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
wcontrols, wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, \
.invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
/* additional sequencing control within an event type */
......@@ -173,26 +173,26 @@
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags}
#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags}
#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
wcontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, \
.invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
/* events that are pre and post DAPM */
#define SND_SOC_DAPM_PRE(wname, wevent) \
{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_POST(wname, wevent) \
{ .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
{ .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
......@@ -232,7 +232,7 @@
/* generic widgets */
#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
{ .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
{ .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
......@@ -356,7 +356,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
struct dentry *parent);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
......@@ -472,7 +473,8 @@ struct snd_soc_dapm_widget {
/* kcontrols that relate to this widget */
int num_kcontrols;
const struct snd_kcontrol_new *kcontrols;
const struct snd_kcontrol_new *kcontrol_news;
struct snd_kcontrol **kcontrols;
/* widget input and outputs */
struct list_head sources;
......@@ -516,4 +518,10 @@ struct snd_soc_dapm_context {
#endif
};
/* A list of widgets associated with an object, typically a snd_kcontrol */
struct snd_soc_dapm_widget_list {
int num_widgets;
struct snd_soc_dapm_widget *widgets[0];
};
#endif
......@@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
extern struct snd_ac97_bus_ops soc_ac97_ops;
enum snd_soc_control_type {
SND_SOC_CUSTOM,
SND_SOC_CUSTOM = 1,
SND_SOC_I2C,
SND_SOC_SPI,
};
......@@ -278,6 +278,10 @@ int snd_soc_register_codec(struct device *dev,
void snd_soc_unregister_codec(struct device *dev);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
......@@ -292,6 +296,8 @@ int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_default_readable_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_default_writable_register(struct snd_soc_codec *codec,
unsigned int reg);
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
......@@ -523,6 +529,7 @@ struct snd_soc_codec {
size_t reg_size; /* reg_cache_size * reg_word_size */
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
int (*readable_register)(struct snd_soc_codec *, unsigned int);
int (*writable_register)(struct snd_soc_codec *, unsigned int);
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
......@@ -539,10 +546,12 @@ struct snd_soc_codec {
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
enum snd_soc_control_type control_type;
hw_write_t hw_write;
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
void *reg_cache;
const void *reg_def_copy;
const struct snd_soc_cache_ops *cache_ops;
......@@ -568,7 +577,9 @@ struct snd_soc_codec_driver {
pm_message_t state);
int (*resume)(struct snd_soc_codec *);
/* Default DAPM setup, added after probe() is run */
/* Default control and setup, added after probe() is run */
const struct snd_kcontrol_new *controls;
int num_controls;
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
......@@ -587,6 +598,7 @@ struct snd_soc_codec_driver {
size_t, unsigned int);
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
int (*readable_register)(struct snd_soc_codec *, unsigned int);
int (*writable_register)(struct snd_soc_codec *, unsigned int);
short reg_cache_size;
short reg_cache_step;
short reg_word_size;
......@@ -690,6 +702,8 @@ struct snd_soc_aux_dev {
/* SoC card */
struct snd_soc_card {
const char *name;
const char *long_name;
const char *driver_name;
struct device *dev;
struct snd_card *snd_card;
struct module *owner;
......@@ -737,12 +751,15 @@ struct snd_soc_card {
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
const struct snd_kcontrol_new *controls;
int num_controls;
/*
* Card-specific routes and widgets.
*/
struct snd_soc_dapm_widget *dapm_widgets;
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
struct snd_soc_dapm_route *dapm_routes;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
struct work_struct deferred_resume_work;
......@@ -805,7 +822,7 @@ struct soc_enum {
unsigned char shift_r;
unsigned int max;
unsigned int mask;
const char **texts;
const char * const *texts;
const unsigned int *values;
void *dapm;
};
......@@ -814,6 +831,8 @@ struct soc_enum {
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val);
unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
unsigned int reg, const void *data, size_t len);
/* device driver data */
......@@ -871,6 +890,9 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->dapm_list);
}
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
#include <sound/soc-dai.h>
#ifdef CONFIG_DEBUG_FS
......
......@@ -26,29 +26,37 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#define TEA575X_FMIF 10700
#define TEA575X_DATA (1 << 0)
#define TEA575X_CLK (1 << 1)
#define TEA575X_WREN (1 << 2)
#define TEA575X_MOST (1 << 3)
struct snd_tea575x;
struct snd_tea575x_ops {
void (*write)(struct snd_tea575x *tea, unsigned int val);
unsigned int (*read)(struct snd_tea575x *tea);
void (*mute)(struct snd_tea575x *tea, unsigned int mute);
void (*set_pins)(struct snd_tea575x *tea, u8 pins);
u8 (*get_pins)(struct snd_tea575x *tea);
void (*set_direction)(struct snd_tea575x *tea, bool output);
};
struct snd_tea575x {
struct snd_card *card;
struct video_device *vd; /* video device */
int dev_nr; /* requested device number + 1 */
int tea5759; /* 5759 chip is present */
int mute; /* Device is muted? */
unsigned int freq_fixup; /* crystal onboard */
bool tea5759; /* 5759 chip is present */
bool mute; /* Device is muted? */
bool stereo; /* receiving stereo */
bool tuned; /* tuned to a station */
unsigned int val; /* hw value */
unsigned long freq; /* frequency */
unsigned long in_use; /* set if the device is in use */
struct snd_tea575x_ops *ops;
void *private_data;
u8 card[32];
u8 bus_info[32];
};
void snd_tea575x_init(struct snd_tea575x *tea);
int snd_tea575x_init(struct snd_tea575x *tea);
void snd_tea575x_exit(struct snd_tea575x *tea);
#endif /* __SOUND_TEA575X_TUNER_H */
/*
* Platform header for Texas Instruments TLV320DAC33 codec driver
*
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* Copyright: (C) 2009 Nokia Corporation
*
......
......@@ -3,7 +3,7 @@
*
* Copyright (C) Nokia Corporation
*
* Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......
/*
* linux/sound/wm8915.h -- Platform data for WM8915
*
* Copyright 2011 Wolfson Microelectronics. PLC.
*
* 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 __LINUX_SND_WM8903_H
#define __LINUX_SND_WM8903_H
enum wm8915_inmode {
WM8915_DIFFERRENTIAL_1 = 0, /* IN1xP - IN1xN */
WM8915_INVERTING = 1, /* IN1xN */
WM8915_NON_INVERTING = 2, /* IN1xP */
WM8915_DIFFERENTIAL_2 = 3, /* IN2xP - IN2xP */
};
/**
* ReTune Mobile configurations are specified with a label, sample
* rate and set of values to write (the enable bits will be ignored).
*
* Configurations are expected to be generated using the ReTune Mobile
* control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
*/
struct wm8915_retune_mobile_config {
const char *name;
int rate;
u16 regs[20];
};
#define WM8915_SET_DEFAULT 0x10000
struct wm8915_pdata {
int irq_flags; /** Set IRQ trigger flags; default active low */
int ldo_ena; /** GPIO for LDO1; -1 for none */
int micdet_def; /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
enum wm8915_inmode inl_mode;
enum wm8915_inmode inr_mode;
u32 spkmute_seq; /** Value for register 0x802 */
int gpio_base;
u32 gpio_default[5];
int num_retune_mobile_cfgs;
struct wm8915_retune_mobile_config *retune_mobile_cfgs;
};
#endif
......@@ -14,6 +14,28 @@
/* Use to set GPIO default values to zero */
#define WM8962_GPIO_SET 0x10000
#define WM8962_GPIO_FN_CLKOUT 0
#define WM8962_GPIO_FN_LOGIC 1
#define WM8962_GPIO_FN_SDOUT 2
#define WM8962_GPIO_FN_IRQ 3
#define WM8962_GPIO_FN_THERMAL 4
#define WM8962_GPIO_FN_PLL2_LOCK 6
#define WM8962_GPIO_FN_PLL3_LOCK 7
#define WM8962_GPIO_FN_FLL_LOCK 9
#define WM8962_GPIO_FN_DRC_ACT 10
#define WM8962_GPIO_FN_WSEQ_DONE 11
#define WM8962_GPIO_FN_ALC_NG_ACT 12
#define WM8962_GPIO_FN_ALC_PEAK_LIMIT 13
#define WM8962_GPIO_FN_ALC_SATURATION 14
#define WM8962_GPIO_FN_ALC_LEVEL_THR 15
#define WM8962_GPIO_FN_ALC_LEVEL_LOCK 16
#define WM8962_GPIO_FN_FIFO_ERR 17
#define WM8962_GPIO_FN_OPCLK 18
#define WM8962_GPIO_FN_DMICCLK 19
#define WM8962_GPIO_FN_DMICDAT 20
#define WM8962_GPIO_FN_MICD 21
#define WM8962_GPIO_FN_MICSCD 22
struct wm8962_pdata {
int gpio_base;
u32 gpio_init[WM8962_MAX_GPIO];
......
......@@ -365,6 +365,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
EXPORT_SYMBOL(snd_ctl_add);
/**
* snd_ctl_replace - replace the control instance of the card
* @card: the card instance
* @kcontrol: the control instance to replace
* @add_on_replace: add the control if not already added
*
* Replaces the given control. If the given control does not exist
* and the add_on_replace flag is set, the control is added. If the
* control exists, it is destroyed first.
*
* Returns zero if successful, or a negative error code on failure.
*
* It frees automatically the control which cannot be added or replaced.
*/
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
bool add_on_replace)
{
struct snd_ctl_elem_id id;
unsigned int idx;
struct snd_kcontrol *old;
int ret;
if (!kcontrol)
return -EINVAL;
if (snd_BUG_ON(!card || !kcontrol->info)) {
ret = -EINVAL;
goto error;
}
id = kcontrol->id;
down_write(&card->controls_rwsem);
old = snd_ctl_find_id(card, &id);
if (!old) {
if (add_on_replace)
goto add;
up_write(&card->controls_rwsem);
ret = -EINVAL;
goto error;
}
ret = snd_ctl_remove(card, old);
if (ret < 0) {
up_write(&card->controls_rwsem);
goto error;
}
add:
if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
up_write(&card->controls_rwsem);
ret = -ENOMEM;
goto error;
}
list_add_tail(&kcontrol->list, &card->controls);
card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
up_write(&card->controls_rwsem);
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
return 0;
error:
snd_ctl_free_one(kcontrol);
return ret;
}
EXPORT_SYMBOL(snd_ctl_replace);
/**
* snd_ctl_remove - remove the control from the card and release it
* @card: the card instance
......
......@@ -514,7 +514,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
id = card->id;
if (*id == '\0')
strcpy(id, "default");
strcpy(id, "Default");
while (1) {
if (loops-- == 0) {
......
......@@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream)
#define XRUN_LOG_CNT 10
struct hwptr_log_entry {
unsigned int in_interrupt;
unsigned long jiffies;
snd_pcm_uframes_t pos;
snd_pcm_uframes_t period_size;
......@@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log {
};
static void xrun_log(struct snd_pcm_substream *substream,
snd_pcm_uframes_t pos)
snd_pcm_uframes_t pos, int in_interrupt)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
......@@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
return;
}
entry = &log->entries[log->idx];
entry->in_interrupt = in_interrupt;
entry->jiffies = jiffies;
entry->pos = pos;
entry->period_size = runtime->period_size;
......@@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
entry = &log->entries[idx];
if (entry->period_size == 0)
break;
snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
"hwptr=%ld/%ld\n",
name, entry->jiffies, (unsigned long)entry->pos,
name, entry->in_interrupt ? "[Q] " : "",
entry->jiffies,
(unsigned long)entry->pos,
(unsigned long)entry->period_size,
(unsigned long)entry->buffer_size,
(unsigned long)entry->old_hw_ptr,
......@@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
#define hw_ptr_error(substream, fmt, args...) do { } while (0)
#define xrun_log(substream, pos) do { } while (0)
#define xrun_log(substream, pos, in_interrupt) do { } while (0)
#define xrun_log_show(substream) do { } while (0)
#endif
......@@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
pos -= pos % runtime->min_align;
if (xrun_debug(substream, XRUN_DEBUG_LOG))
xrun_log(substream, pos);
xrun_log(substream, pos, in_interrupt);
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
if (in_interrupt) {
......
......@@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS
To compile this driver as a module, choose M here: the module
will be called snd-firewire-speakers.
config SND_ISIGHT
tristate "Apple iSight microphone"
select SND_PCM
select SND_FIREWIRE_LIB
help
Say Y here to include support for the front and rear microphones
of the Apple iSight web camera.
To compile this driver as a module, choose M here: the module
will be called snd-isight.
endif # SND_FIREWIRE
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp.o
snd-firewire-speakers-objs := speakers.o
snd-isight-objs := isight.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
/*
* Apple iSight audio driver
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
* Licensed under the terms of the GNU General Public License, version 2.
*/
#include <asm/byteorder.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/tlv.h>
#include "lib.h"
#include "iso-resources.h"
#include "packets-buffer.h"
#define OUI_APPLE 0x000a27
#define MODEL_APPLE_ISIGHT 0x000008
#define SW_ISIGHT_AUDIO 0x000010
#define REG_AUDIO_ENABLE 0x000
#define AUDIO_ENABLE 0x80000000
#define REG_DEF_AUDIO_GAIN 0x204
#define REG_GAIN_RAW_START 0x210
#define REG_GAIN_RAW_END 0x214
#define REG_GAIN_DB_START 0x218
#define REG_GAIN_DB_END 0x21c
#define REG_SAMPLE_RATE_INQUIRY 0x280
#define REG_ISO_TX_CONFIG 0x300
#define SPEED_SHIFT 16
#define REG_SAMPLE_RATE 0x400
#define RATE_48000 0x80000000
#define REG_GAIN 0x500
#define REG_MUTE 0x504
#define MAX_FRAMES_PER_PACKET 475
#define QUEUE_LENGTH 20
struct isight {
struct snd_card *card;
struct fw_unit *unit;
struct fw_device *device;
u64 audio_base;
struct fw_address_handler iris_handler;
struct snd_pcm_substream *pcm;
struct mutex mutex;
struct iso_packets_buffer buffer;
struct fw_iso_resources resources;
struct fw_iso_context *context;
bool pcm_active;
bool pcm_running;
bool first_packet;
int packet_index;
u32 total_samples;
unsigned int buffer_pointer;
unsigned int period_counter;
s32 gain_min, gain_max;
unsigned int gain_tlv[4];
};
struct audio_payload {
__be32 sample_count;
__be32 signature;
__be32 sample_total;
__be32 reserved;
__be16 samples[2 * MAX_FRAMES_PER_PACKET];
};
MODULE_DESCRIPTION("iSight audio driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
static struct fw_iso_packet audio_packet = {
.payload_length = sizeof(struct audio_payload),
.interrupt = 1,
.header_length = 4,
};
static void isight_update_pointers(struct isight *isight, unsigned int count)
{
struct snd_pcm_runtime *runtime = isight->pcm->runtime;
unsigned int ptr;
smp_wmb(); /* update buffer data before buffer pointer */
ptr = isight->buffer_pointer;
ptr += count;
if (ptr >= runtime->buffer_size)
ptr -= runtime->buffer_size;
ACCESS_ONCE(isight->buffer_pointer) = ptr;
isight->period_counter += count;
if (isight->period_counter >= runtime->period_size) {
isight->period_counter -= runtime->period_size;
snd_pcm_period_elapsed(isight->pcm);
}
}
static void isight_samples(struct isight *isight,
const __be16 *samples, unsigned int count)
{
struct snd_pcm_runtime *runtime;
unsigned int count1;
if (!ACCESS_ONCE(isight->pcm_running))
return;
runtime = isight->pcm->runtime;
if (isight->buffer_pointer + count <= runtime->buffer_size) {
memcpy(runtime->dma_area + isight->buffer_pointer * 4,
samples, count * 4);
} else {
count1 = runtime->buffer_size - isight->buffer_pointer;
memcpy(runtime->dma_area + isight->buffer_pointer * 4,
samples, count1 * 4);
samples += count1 * 2;
memcpy(runtime->dma_area, samples, (count - count1) * 4);
}
isight_update_pointers(isight, count);
}
static void isight_pcm_abort(struct isight *isight)
{
unsigned long flags;
if (ACCESS_ONCE(isight->pcm_active)) {
snd_pcm_stream_lock_irqsave(isight->pcm, flags);
if (snd_pcm_running(isight->pcm))
snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
}
}
static void isight_dropped_samples(struct isight *isight, unsigned int total)
{
struct snd_pcm_runtime *runtime;
u32 dropped;
unsigned int count1;
if (!ACCESS_ONCE(isight->pcm_running))
return;
runtime = isight->pcm->runtime;
dropped = total - isight->total_samples;
if (dropped < runtime->buffer_size) {
if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
memset(runtime->dma_area + isight->buffer_pointer * 4,
0, dropped * 4);
} else {
count1 = runtime->buffer_size - isight->buffer_pointer;
memset(runtime->dma_area + isight->buffer_pointer * 4,
0, count1 * 4);
memset(runtime->dma_area, 0, (dropped - count1) * 4);
}
isight_update_pointers(isight, dropped);
} else {
isight_pcm_abort(isight);
}
}
static void isight_packet(struct fw_iso_context *context, u32 cycle,
size_t header_length, void *header, void *data)
{
struct isight *isight = data;
const struct audio_payload *payload;
unsigned int index, length, count, total;
int err;
if (isight->packet_index < 0)
return;
index = isight->packet_index;
payload = isight->buffer.packets[index].buffer;
length = be32_to_cpup(header) >> 16;
if (likely(length >= 16 &&
payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
count = be32_to_cpu(payload->sample_count);
if (likely(count <= (length - 16) / 4)) {
total = be32_to_cpu(payload->sample_total);
if (unlikely(total != isight->total_samples)) {
if (!isight->first_packet)
isight_dropped_samples(isight, total);
isight->first_packet = false;
isight->total_samples = total;
}
isight_samples(isight, payload->samples, count);
isight->total_samples += count;
}
}
err = fw_iso_context_queue(isight->context, &audio_packet,
&isight->buffer.iso_buffer,
isight->buffer.packets[index].offset);
if (err < 0) {
dev_err(&isight->unit->device, "queueing error: %d\n", err);
isight_pcm_abort(isight);
isight->packet_index = -1;
return;
}
if (++index >= QUEUE_LENGTH)
index = 0;
isight->packet_index = index;
}
static int isight_connect(struct isight *isight)
{
int ch, err, rcode, errors = 0;
__be32 value;
retry_after_bus_reset:
ch = fw_iso_resources_allocate(&isight->resources,
sizeof(struct audio_payload),
isight->device->max_speed);
if (ch < 0) {
err = ch;
goto error;
}
value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
for (;;) {
rcode = fw_run_transaction(
isight->device->card,
TCODE_WRITE_QUADLET_REQUEST,
isight->device->node_id,
isight->resources.generation,
isight->device->max_speed,
isight->audio_base + REG_ISO_TX_CONFIG,
&value, 4);
if (rcode == RCODE_COMPLETE) {
return 0;
} else if (rcode == RCODE_GENERATION) {
fw_iso_resources_free(&isight->resources);
goto retry_after_bus_reset;
} else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
err = -EIO;
goto err_resources;
}
msleep(5);
}
err_resources:
fw_iso_resources_free(&isight->resources);
error:
return err;
}
static int isight_open(struct snd_pcm_substream *substream)
{
static const struct snd_pcm_hardware hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER,
.formats = SNDRV_PCM_FMTBIT_S16_BE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 4 * 1024 * 1024,
.period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
.period_bytes_max = 1024 * 1024,
.periods_min = 2,
.periods_max = UINT_MAX,
};
struct isight *isight = substream->private_data;
substream->runtime->hw = hardware;
return iso_packets_buffer_init(&isight->buffer, isight->unit,
QUEUE_LENGTH,
sizeof(struct audio_payload),
DMA_FROM_DEVICE);
}
static int isight_close(struct snd_pcm_substream *substream)
{
struct isight *isight = substream->private_data;
iso_packets_buffer_destroy(&isight->buffer, isight->unit);
return 0;
}
static int isight_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct isight *isight = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (err < 0)
return err;
ACCESS_ONCE(isight->pcm_active) = true;
return 0;
}
static int reg_read(struct isight *isight, int offset, __be32 *value)
{
return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
isight->audio_base + offset, value, 4);
}
static int reg_write(struct isight *isight, int offset, __be32 value)
{
return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
isight->audio_base + offset, &value, 4);
}
static void isight_stop_streaming(struct isight *isight)
{
if (!isight->context)
return;
fw_iso_context_stop(isight->context);
fw_iso_context_destroy(isight->context);
isight->context = NULL;
fw_iso_resources_free(&isight->resources);
reg_write(isight, REG_AUDIO_ENABLE, 0);
}
static int isight_hw_free(struct snd_pcm_substream *substream)
{
struct isight *isight = substream->private_data;
ACCESS_ONCE(isight->pcm_active) = false;
mutex_lock(&isight->mutex);
isight_stop_streaming(isight);
mutex_unlock(&isight->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static int isight_start_streaming(struct isight *isight)
{
unsigned int i;
int err;
if (isight->context) {
if (isight->packet_index < 0)
isight_stop_streaming(isight);
else
return 0;
}
err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
if (err < 0)
goto error;
err = isight_connect(isight);
if (err < 0)
goto error;
err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
if (err < 0)
goto err_resources;
isight->context = fw_iso_context_create(isight->device->card,
FW_ISO_CONTEXT_RECEIVE,
isight->resources.channel,
isight->device->max_speed,
4, isight_packet, isight);
if (IS_ERR(isight->context)) {
err = PTR_ERR(isight->context);
isight->context = NULL;
goto err_resources;
}
for (i = 0; i < QUEUE_LENGTH; ++i) {
err = fw_iso_context_queue(isight->context, &audio_packet,
&isight->buffer.iso_buffer,
isight->buffer.packets[i].offset);
if (err < 0)
goto err_context;
}
isight->first_packet = true;
isight->packet_index = 0;
err = fw_iso_context_start(isight->context, -1, 0,
FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
if (err < 0)
goto err_context;
return 0;
err_context:
fw_iso_context_destroy(isight->context);
isight->context = NULL;
err_resources:
fw_iso_resources_free(&isight->resources);
reg_write(isight, REG_AUDIO_ENABLE, 0);
error:
return err;
}
static int isight_prepare(struct snd_pcm_substream *substream)
{
struct isight *isight = substream->private_data;
int err;
isight->buffer_pointer = 0;
isight->period_counter = 0;
mutex_lock(&isight->mutex);
err = isight_start_streaming(isight);
mutex_unlock(&isight->mutex);
return err;
}
static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct isight *isight = substream->private_data;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
ACCESS_ONCE(isight->pcm_running) = true;
break;
case SNDRV_PCM_TRIGGER_STOP:
ACCESS_ONCE(isight->pcm_running) = false;
break;
default:
return -EINVAL;
}
return 0;
}
static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
{
struct isight *isight = substream->private_data;
return ACCESS_ONCE(isight->buffer_pointer);
}
static int isight_create_pcm(struct isight *isight)
{
static struct snd_pcm_ops ops = {
.open = isight_open,
.close = isight_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = isight_hw_params,
.hw_free = isight_hw_free,
.prepare = isight_prepare,
.trigger = isight_trigger,
.pointer = isight_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
if (err < 0)
return err;
pcm->private_data = isight;
strcpy(pcm->name, "iSight");
isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
isight->pcm->ops = &ops;
return 0;
}
static int isight_gain_info(struct snd_kcontrol *ctl,
struct snd_ctl_elem_info *info)
{
struct isight *isight = ctl->private_data;
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
info->count = 1;
info->value.integer.min = isight->gain_min;
info->value.integer.max = isight->gain_max;
return 0;
}
static int isight_gain_get(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct isight *isight = ctl->private_data;
__be32 gain;
int err;
err = reg_read(isight, REG_GAIN, &gain);
if (err < 0)
return err;
value->value.integer.value[0] = (s32)be32_to_cpu(gain);
return 0;
}
static int isight_gain_put(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct isight *isight = ctl->private_data;
if (value->value.integer.value[0] < isight->gain_min ||
value->value.integer.value[0] > isight->gain_max)
return -EINVAL;
return reg_write(isight, REG_GAIN,
cpu_to_be32(value->value.integer.value[0]));
}
static int isight_mute_get(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct isight *isight = ctl->private_data;
__be32 mute;
int err;
err = reg_read(isight, REG_MUTE, &mute);
if (err < 0)
return err;
value->value.integer.value[0] = !mute;
return 0;
}
static int isight_mute_put(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value)
{
struct isight *isight = ctl->private_data;
return reg_write(isight, REG_MUTE,
(__force __be32)!value->value.integer.value[0]);
}
static int isight_create_mixer(struct isight *isight)
{
static const struct snd_kcontrol_new gain_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic Capture Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = isight_gain_info,
.get = isight_gain_get,
.put = isight_gain_put,
};
static const struct snd_kcontrol_new mute_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic Capture Switch",
.info = snd_ctl_boolean_mono_info,
.get = isight_mute_get,
.put = isight_mute_put,
};
__be32 value;
struct snd_kcontrol *ctl;
int err;
err = reg_read(isight, REG_GAIN_RAW_START, &value);
if (err < 0)
return err;
isight->gain_min = be32_to_cpu(value);
err = reg_read(isight, REG_GAIN_RAW_END, &value);
if (err < 0)
return err;
isight->gain_max = be32_to_cpu(value);
isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
isight->gain_tlv[1] = 2 * sizeof(unsigned int);
err = reg_read(isight, REG_GAIN_DB_START, &value);
if (err < 0)
return err;
isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100;
err = reg_read(isight, REG_GAIN_DB_END, &value);
if (err < 0)
return err;
isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100;
ctl = snd_ctl_new1(&gain_control, isight);
if (ctl)
ctl->tlv.p = isight->gain_tlv;
err = snd_ctl_add(isight->card, ctl);
if (err < 0)
return err;
err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
if (err < 0)
return err;
return 0;
}
static void isight_card_free(struct snd_card *card)
{
struct isight *isight = card->private_data;
fw_iso_resources_destroy(&isight->resources);
fw_unit_put(isight->unit);
fw_device_put(isight->device);
mutex_destroy(&isight->mutex);
}
static u64 get_unit_base(struct fw_unit *unit)
{
struct fw_csr_iterator i;
int key, value;
fw_csr_iterator_init(&i, unit->directory);
while (fw_csr_iterator_next(&i, &key, &value))
if (key == CSR_OFFSET)
return CSR_REGISTER_BASE + value * 4;
return 0;
}
static int isight_probe(struct device *unit_dev)
{
struct fw_unit *unit = fw_unit(unit_dev);
struct fw_device *fw_dev = fw_parent_device(unit);
struct snd_card *card;
struct isight *isight;
int err;
err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
if (err < 0)
return err;
snd_card_set_dev(card, unit_dev);
isight = card->private_data;
isight->card = card;
mutex_init(&isight->mutex);
isight->unit = fw_unit_get(unit);
isight->device = fw_device_get(fw_dev);
isight->audio_base = get_unit_base(unit);
if (!isight->audio_base) {
dev_err(&unit->device, "audio unit base not found\n");
err = -ENXIO;
goto err_unit;
}
fw_iso_resources_init(&isight->resources, unit);
card->private_free = isight_card_free;
strcpy(card->driver, "iSight");
strcpy(card->shortname, "Apple iSight");
snprintf(card->longname, sizeof(card->longname),
"Apple iSight (GUID %08x%08x) at %s, S%d",
fw_dev->config_rom[3], fw_dev->config_rom[4],
dev_name(&unit->device), 100 << fw_dev->max_speed);
strcpy(card->mixername, "iSight");
err = isight_create_pcm(isight);
if (err < 0)
goto error;
err = isight_create_mixer(isight);
if (err < 0)
goto error;
err = snd_card_register(card);
if (err < 0)
goto error;
dev_set_drvdata(unit_dev, isight);
return 0;
err_unit:
fw_unit_put(isight->unit);
fw_device_put(isight->device);
mutex_destroy(&isight->mutex);
error:
snd_card_free(card);
return err;
}
static int isight_remove(struct device *dev)
{
struct isight *isight = dev_get_drvdata(dev);
isight_pcm_abort(isight);
snd_card_disconnect(isight->card);
mutex_lock(&isight->mutex);
isight_stop_streaming(isight);
mutex_unlock(&isight->mutex);
snd_card_free_when_closed(isight->card);
return 0;
}
static void isight_bus_reset(struct fw_unit *unit)
{
struct isight *isight = dev_get_drvdata(&unit->device);
if (fw_iso_resources_update(&isight->resources) < 0) {
isight_pcm_abort(isight);
mutex_lock(&isight->mutex);
isight_stop_streaming(isight);
mutex_unlock(&isight->mutex);
}
}
static const struct ieee1394_device_id isight_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.specifier_id = OUI_APPLE,
.version = SW_ISIGHT_AUDIO,
},
{ }
};
MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
static struct fw_driver isight_driver = {
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
.probe = isight_probe,
.remove = isight_remove,
},
.update = isight_bus_reset,
.id_table = isight_id_table,
};
static int __init alsa_isight_init(void)
{
return driver_register(&isight_driver.driver);
}
static void __exit alsa_isight_exit(void)
{
driver_unregister(&isight_driver.driver);
}
module_init(alsa_isight_init);
module_exit(alsa_isight_exit);
......@@ -31,6 +31,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
return 0;
}
EXPORT_SYMBOL(fw_iso_resources_init);
/**
* fw_iso_resources_destroy - destroy a resource manager
......@@ -42,6 +43,7 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
mutex_destroy(&r->mutex);
fw_unit_put(r->unit);
}
EXPORT_SYMBOL(fw_iso_resources_destroy);
static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
{
......@@ -146,6 +148,7 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r,
return channel;
}
EXPORT_SYMBOL(fw_iso_resources_allocate);
/**
* fw_iso_resources_update - update resource allocations after a bus reset
......@@ -197,6 +200,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
return channel;
}
EXPORT_SYMBOL(fw_iso_resources_update);
/**
* fw_iso_resources_free - frees allocated resources
......@@ -224,3 +228,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
mutex_unlock(&r->mutex);
}
EXPORT_SYMBOL(fw_iso_resources_free);
......@@ -60,6 +60,7 @@ int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
error:
return err;
}
EXPORT_SYMBOL(iso_packets_buffer_init);
/**
* iso_packets_buffer_destroy - frees packet buffer resources
......@@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
kfree(b->packets);
}
EXPORT_SYMBOL(iso_packets_buffer_destroy);
......@@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.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
obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o
......@@ -37,8 +37,8 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0);
#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
#define FREQ_LO (87 * 16000)
#define FREQ_HI (108 * 16000)
#define FREQ_LO (50UL * 16000)
#define FREQ_HI (150UL * 16000)
/*
* definitions
......@@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = {
* lowlevel part
*/
static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
{
u16 l;
u8 data;
tea->ops->set_direction(tea, 1);
udelay(16);
for (l = 25; l > 0; l--) {
data = (val >> 24) & TEA575X_DATA;
val <<= 1; /* shift data */
tea->ops->set_pins(tea, data | TEA575X_WREN);
udelay(2);
tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
udelay(2);
tea->ops->set_pins(tea, data | TEA575X_WREN);
udelay(2);
}
if (!tea->mute)
tea->ops->set_pins(tea, 0);
}
static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
{
u16 l, rdata;
u32 data = 0;
tea->ops->set_direction(tea, 0);
tea->ops->set_pins(tea, 0);
udelay(16);
for (l = 24; l--;) {
tea->ops->set_pins(tea, TEA575X_CLK);
udelay(2);
if (!l)
tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
tea->ops->set_pins(tea, 0);
udelay(2);
data <<= 1; /* shift data */
rdata = tea->ops->get_pins(tea);
if (!l)
tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1;
if (rdata & TEA575X_DATA)
data++;
udelay(2);
}
if (tea->mute)
tea->ops->set_pins(tea, TEA575X_WREN);
return data;
}
static void snd_tea575x_get_freq(struct snd_tea575x *tea)
{
unsigned long freq;
freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
/* freq *= 12.5 */
freq *= 125;
freq /= 10;
/* crystal fixup */
if (tea->tea5759)
freq += TEA575X_FMIF;
else
freq -= TEA575X_FMIF;
tea->freq = freq * 16; /* from kHz */
}
static void snd_tea575x_set_freq(struct snd_tea575x *tea)
{
unsigned long freq;
freq = tea->freq / 16; /* to kHz */
if (freq > 108000)
freq = 108000;
if (freq < 87000)
freq = 87000;
freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
freq /= 16; /* to kHz */
/* crystal fixup */
if (tea->tea5759)
freq -= tea->freq_fixup;
freq -= TEA575X_FMIF;
else
freq += tea->freq_fixup;
freq += TEA575X_FMIF;
/* freq /= 12.5 */
freq *= 10;
freq /= 125;
tea->val &= ~TEA575X_BIT_FREQ_MASK;
tea->val |= freq & TEA575X_BIT_FREQ_MASK;
tea->ops->write(tea, tea->val);
snd_tea575x_write(tea, tea->val);
}
/*
......@@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct snd_tea575x *tea = video_drvdata(file);
strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
strlcpy(v->card, "Maestro Radio", sizeof(v->card));
sprintf(v->bus_info, "PCI");
strlcpy(v->card, tea->card, sizeof(v->card));
strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
v->version = RADIO_VERSION;
v->capabilities = V4L2_CAP_TUNER;
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
return 0;
}
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct snd_tea575x *tea = video_drvdata(file);
if (v->index > 0)
return -EINVAL;
snd_tea575x_read(tea);
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
v->rangelow = FREQ_LO;
v->rangehigh = FREQ_HI;
v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
v->capability = V4L2_TUNER_CAP_LOW;
v->audmode = V4L2_TUNER_MODE_MONO;
v->signal = 0xffff;
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
v->signal = tea->tuned ? 0xffff : 0;
return 0;
}
......@@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct snd_tea575x *tea = video_drvdata(file);
if (f->tuner != 0)
return -EINVAL;
f->type = V4L2_TUNER_RADIO;
snd_tea575x_get_freq(tea);
f->frequency = tea->freq;
return 0;
}
......@@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
{
struct snd_tea575x *tea = video_drvdata(file);
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
return -EINVAL;
......@@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (tea->ops->mute) {
ctrl->value = tea->mute;
return 0;
}
ctrl->value = tea->mute;
return 0;
}
return -EINVAL;
}
......@@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (tea->ops->mute) {
tea->ops->mute(tea, ctrl->value);
if (tea->mute != ctrl->value) {
tea->mute = ctrl->value;
return 0;
snd_tea575x_set_freq(tea);
}
return 0;
}
return -EINVAL;
}
......@@ -293,18 +370,16 @@ static struct video_device tea575x_radio = {
/*
* initialize all the tea575x chips
*/
void snd_tea575x_init(struct snd_tea575x *tea)
int snd_tea575x_init(struct snd_tea575x *tea)
{
int retval;
unsigned int val;
struct video_device *tea575x_radio_inst;
val = tea->ops->read(tea);
if (val == 0x1ffffff || val == 0) {
snd_printk(KERN_ERR
"tea575x-tuner: Cannot find TEA575x chip\n");
return;
}
tea->mute = 1;
snd_tea575x_write(tea, 0x55AA);
if (snd_tea575x_read(tea) != 0x55AA)
return -ENODEV;
tea->in_use = 0;
tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
......@@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea)
tea575x_radio_inst = video_device_alloc();
if (tea575x_radio_inst == NULL) {
printk(KERN_ERR "tea575x-tuner: not enough memory\n");
return;
return -ENOMEM;
}
memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
......@@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea)
if (retval) {
printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
kfree(tea575x_radio_inst);
return;
return retval;
}
snd_tea575x_set_freq(tea);
/* mute on init */
if (tea->ops->mute) {
tea->ops->mute(tea, 1);
tea->mute = 1;
}
tea->vd = tea575x_radio_inst;
return 0;
}
void snd_tea575x_exit(struct snd_tea575x *tea)
......
......@@ -22,10 +22,6 @@ config SOUND_VWSND
<file:Documentation/sound/oss/vwsnd> for more info on this driver's
capabilities.
config SOUND_AU1550_AC97
tristate "Au1550/Au1200 AC97 Sound"
depends on SOC_AU1550 || SOC_AU1200
config SOUND_MSNDCLAS
tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
depends on (m || !STANDALONE) && ISA
......
......@@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
obj-$(CONFIG_DMASOUND) += dmasound/
......
此差异已折叠。
此差异已折叠。
......@@ -534,6 +534,14 @@ config SND_ES1968_INPUT
If you say N the buttons will directly control the master volume.
It is recommended to say Y.
config SND_ES1968_RADIO
bool "Enable TEA5757 radio tuner support for es1968"
depends on SND_ES1968
depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968
help
Say Y here to include support for TEA5757 radio tuner integrated on
some MediaForte cards (e.g. SF64-PCE2).
config SND_FM801
tristate "ForteMedia FM801"
select SND_OPL3_LIB
......@@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL
depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
help
Say Y here to include support for soundcards based on the ForteMedia
FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
Forte SF256-PCS-02) into the snd-fm801 driver.
FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
SF64-PCR) into the snd-fm801 driver.
config SND_FM801_TEA575X
config SND_TEA575X
tristate
depends on SND_FM801_TEA575X_BOOL
default SND_FM801
depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
default SND_FM801 || SND_ES1968
source "sound/pci/hda/Kconfig"
......@@ -658,6 +666,15 @@ config SND_KORG1212
To compile this driver as a module, choose M here: the module
will be called snd-korg1212.
config SND_LOLA
tristate "Digigram Lola"
select SND_PCM
help
Say Y to include support for Digigram Lola boards.
To compile this driver as a module, choose M here: the module
will be called snd-lola.
config SND_LX6464ES
tristate "Digigram LX6464ES"
select SND_PCM
......
......@@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \
ca0106/ \
cs46xx/ \
cs5535audio/ \
lola/ \
lx6464es/ \
echoaudio/ \
emu10k1/ \
......
此差异已折叠。
......@@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
static void subsys_create_adapter(struct hpi_message *phm,
struct hpi_response *phr);
static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_response *phr);
static void adapter_delete(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr);
static void adapter_get_asserts(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr);
......@@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
case HPI_SUBSYS_CREATE_ADAPTER:
subsys_create_adapter(phm, phr);
break;
case HPI_SUBSYS_DELETE_ADAPTER:
subsys_delete_adapter(phm, phr);
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
break;
......@@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
adapter_get_asserts(pao, phm, phr);
break;
case HPI_ADAPTER_DELETE:
adapter_delete(pao, phm, phr);
break;
default:
hw_message(pao, phm, phr);
break;
......@@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
{
struct hpi_adapter_obj *pao = NULL;
/* subsytem messages get executed by every HPI. */
/* All other messages are ignored unless the adapter index matches */
/* an adapter in the HPI */
/*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
/* if Dsp has crashed then do not communicate with it any more */
if (phm->object != HPI_OBJ_SUBSYSTEM) {
pao = hpi_find_adapter(phm->adapter_index);
if (!pao) {
HPI_DEBUG_LOG(DEBUG,
" %d,%d refused, for another HPI?\n",
phm->object, phm->function);
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_BAD_ADAPTER_NUMBER);
HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",
phm->adapter_index);
return;
}
/* Don't even try to communicate with crashed DSP */
if (pao->dsp_crashed >= 10) {
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_DSP_HARDWARE);
HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n",
phm->object, phm->function);
HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",
phm->adapter_index);
return;
}
}
......@@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm,
phr->error = 0;
}
static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_response *phr)
static void adapter_delete(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
struct hpi_adapter_obj *pao = NULL;
pao = hpi_find_adapter(phm->obj_index);
if (!pao)
return;
delete_adapter_obj(pao);
hpi_delete_adapter(pao);
phr->error = 0;
......
......@@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
static void subsys_create_adapter(struct hpi_message *phm,
struct hpi_response *phr);
static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_response *phr);
static void adapter_delete(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr);
static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
u32 *pos_error_code);
......@@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
/*****************************************************************************/
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
static void subsys_message(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->function) {
case HPI_SUBSYS_CREATE_ADAPTER:
subsys_create_adapter(phm, phr);
break;
case HPI_SUBSYS_DELETE_ADAPTER:
subsys_delete_adapter(phm, phr);
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
break;
......@@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->function) {
case HPI_ADAPTER_DELETE:
adapter_delete(pao, phm, phr);
break;
default:
hw_message(pao, phm, phr);
break;
......@@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao,
/** Entry point to this HPI backend
* All calls to the HPI start here
*/
void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
struct hpi_response *phr)
{
struct hpi_adapter_obj *pao = NULL;
/* subsytem messages are processed by every HPI.
* All other messages are ignored unless the adapter index matches
* an adapter in the HPI
*/
/* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
phm->wFunction); */
/* if Dsp has crashed then do not communicate with it any more */
if (phm->object != HPI_OBJ_SUBSYSTEM) {
pao = hpi_find_adapter(phm->adapter_index);
if (!pao) {
HPI_DEBUG_LOG(DEBUG,
" %d,%d refused, for another HPI?\n",
phm->object, phm->function);
return;
}
if ((pao->dsp_crashed >= 10)
&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
/* allow last resort debug read even after crash */
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_DSP_HARDWARE);
HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
phm->object, phm->function);
return;
}
if (pao && (pao->dsp_crashed >= 10)
&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
/* allow last resort debug read even after crash */
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_DSP_HARDWARE);
HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
phm->function);
return;
}
/* Init default response */
......@@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
case HPI_TYPE_MESSAGE:
switch (phm->object) {
case HPI_OBJ_SUBSYSTEM:
subsys_message(phm, phr);
subsys_message(pao, phm, phr);
break;
case HPI_OBJ_ADAPTER:
......@@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
}
}
void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
{
struct hpi_adapter_obj *pao = NULL;
if (phm->object != HPI_OBJ_SUBSYSTEM) {
/* normal messages must have valid adapter index */
pao = hpi_find_adapter(phm->adapter_index);
} else {
/* subsys messages don't address an adapter */
_HPI_6205(NULL, phm, phr);
return;
}
if (pao)
_HPI_6205(pao, phm, phr);
else
hpi_init_response(phr, phm->object, phm->function,
HPI_ERROR_BAD_ADAPTER_NUMBER);
}
/*****************************************************************************/
/* SUBSYSTEM */
......@@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm,
}
/** delete an adapter - required by WDM driver */
static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_response *phr)
static void adapter_delete(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
struct hpi_adapter_obj *pao;
struct hpi_hw_obj *phw;
pao = hpi_find_adapter(phm->obj_index);
if (!pao) {
phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
return;
......@@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
}
err = adapter_boot_load_dsp(pao, pos_error_code);
if (err)
if (err) {
HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
/* no need to clean up as SubSysCreateAdapter */
/* calls DeleteAdapter on error. */
return err;
}
HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
/* allow boot load even if mem alloc wont work */
......@@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
control_cache.number_of_controls,
interface->control_cache.size_in_bytes,
p_control_cache_virtual);
if (!phw->p_cache)
err = HPI_ERROR_MEMORY_ALLOC;
}
......@@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
}
/** Free memory areas allocated by adapter
* this routine is called from SubSysDeleteAdapter,
* this routine is called from AdapterDelete,
* and SubSysCreateAdapter if duplicate index
*/
static void delete_adapter_obj(struct hpi_adapter_obj *pao)
{
struct hpi_hw_obj *phw;
struct hpi_hw_obj *phw = pao->priv;
int i;
phw = pao->priv;
if (hpios_locked_mem_valid(&phw->h_control_cache)) {
hpios_locked_mem_free(&phw->h_control_cache);
hpi_free_control_cache(phw->p_cache);
......@@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
case HPI_ADAPTER_FAMILY_ASI(0x6300):
boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
break;
case HPI_ADAPTER_FAMILY_ASI(0x5500):
case HPI_ADAPTER_FAMILY_ASI(0x5600):
case HPI_ADAPTER_FAMILY_ASI(0x6500):
boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
......@@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
{
struct bus_master_interface *interface = phw->p_interface_buffer;
u32 r;
interface->host_cmd = cmd;
......
......@@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES {
/* These defines are used to fill in protocol information for an Ethernet packet
sent using HMI on CS18102 */
/** ID supplied by Cirrius for ASI packets. */
/** ID supplied by Cirrus for ASI packets. */
#define HPI_ETHERNET_PACKET_ID 0x85
/** Simple packet - no special routing required */
#define HPI_ETHERNET_PACKET_V1 0x01
......@@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES {
/** This packet must make its way to the host across the HPI interface */
#define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1 0x41
#define HPI_ETHERNET_UDP_PORT (44600) /*!< UDP messaging port */
#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */
/** Default network timeout in milli-seconds. */
#define HPI_ETHERNET_TIMEOUT_MS 500
......@@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS {
HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4),
/* HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4), */
HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7),
/* HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7), */
HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10),
HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11),
/* HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10), */
/* HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11), */
HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
......@@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS {
HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
#define HPI_ADAPTER_FUNCTION_COUNT 20
HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21),
#define HPI_ADAPTER_FUNCTION_COUNT 21
HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
......@@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
u16 *pw_adapter_index);
u16 hpi_subsys_delete_adapter(u16 adapter_index);
u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status);
......@@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR);
/*////////////////////////////////////////////////////////////////////////// */
/* declarations for individual HPI entry points */
hpi_handler_func HPI_1000;
hpi_handler_func HPI_6000;
hpi_handler_func HPI_6205;
hpi_handler_func HPI_COMMON;
#endif /* _HPI_INTERNAL_H_ */
......@@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
if (info->control_type) {
pC->p_info[info->control_index] = info;
cached++;
} else /* dummy cache entry */
} else { /* dummy cache entry */
pC->p_info[info->control_index] = NULL;
}
byte_count += info->size_in32bit_words * 4;
......@@ -298,7 +299,7 @@ struct pad_ofs_size {
unsigned int field_size;
};
static struct pad_ofs_size pad_desc[] = {
static const struct pad_ofs_size pad_desc[] = {
HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */
HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */
HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */
......@@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
}
}
/** Allocate control cache.
\return Cache pointer, or NULL if allocation fails.
*/
struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
const u32 size_in_bytes, u8 *p_dsp_control_buffer)
{
......@@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
phr->u.s.num_adapters = adapters.gw_num_adapters;
break;
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_SUBSYS_DELETE_ADAPTER:
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
......
......@@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
hpi_handler_func HPI_COMMON;
......@@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex)
return hr.error;
}
u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
u16 *pw_adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_CREATE_ADAPTER);
hm.u.s.resource = *p_resource;
hpi_send_recv(&hm, &hr);
*pw_adapter_index = hr.u.s.adapter_index;
return hr.error;
}
u16 hpi_subsys_delete_adapter(u16 adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
hm.obj_index = adapter_index;
hpi_send_recv(&hm, &hr);
return hr.error;
}
u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
{
struct hpi_message hm;
......
......@@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
HPIMSGX__init(phm, phr);
break;
case HPI_SUBSYS_DELETE_ADAPTER:
HPIMSGX__cleanup(phm->obj_index, h_owner);
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_CLOSE);
hm.adapter_index = phm->obj_index;
hw_entry_point(&hm, &hr);
}
if ((phm->obj_index < HPI_MAX_ADAPTERS)
&& hpi_entry_points[phm->obj_index]) {
hpi_entry_points[phm->obj_index] (phm, phr);
hpi_entry_points[phm->obj_index] = NULL;
} else
phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
break;
default:
/* Must explicitly handle every subsys message in this switch */
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
......@@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
case HPI_ADAPTER_CLOSE:
adapter_close(phm, phr);
break;
case HPI_ADAPTER_DELETE:
HPIMSGX__cleanup(phm->adapter_index, h_owner);
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_CLOSE);
hm.adapter_index = phm->adapter_index;
hw_entry_point(&hm, &hr);
}
hw_entry_point(phm, phr);
break;
default:
hw_entry_point(phm, phr);
break;
......
......@@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
#include "hpidebug.h"
#include "hpimsgx.h"
#include "hpioctl.h"
#include "hpicmn.h"
#include <linux/fs.h>
#include <linux/slab.h>
......@@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto out;
}
pa = &adapters[hm->h.adapter_index];
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_ADAPTER_DELETE:
/* Application must not use these functions! */
hr->h.size = sizeof(hr->h);
hr->h.error = HPI_ERROR_INVALID_OPERATION;
hr->h.function = hm->h.function;
uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
if (uncopied_bytes)
err = -EFAULT;
else
err = 0;
goto out;
}
hr->h.size = res_max_size;
if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_SUBSYS_DELETE_ADAPTER:
/* Application must not use these functions! */
hr->h.size = sizeof(hr->h);
hr->h.error = HPI_ERROR_INVALID_OPERATION;
hr->h.function = hm->h.function;
uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
if (uncopied_bytes)
err = -EFAULT;
else
err = 0;
goto out;
default:
hpi_send_recv_f(&hm->m0, &hr->r0, file);
}
hpi_send_recv_f(&hm->m0, &hr->r0, file);
} else {
u16 __user *ptr = NULL;
u32 size = 0;
......@@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* -1=no data 0=read from user mem, 1=write to user mem */
int wrflag = -1;
u32 adapter = hm->h.adapter_index;
pa = &adapters[adapter];
if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
HPI_ADAPTER_OPEN,
HPI_ERROR_BAD_ADAPTER_NUMBER);
......@@ -317,7 +317,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
int err, idx, nm;
int idx, nm;
unsigned int memlen;
struct hpi_message hm;
struct hpi_response hr;
......@@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
nm = HPI_MAX_ADAPTER_MEM_SPACES;
for (idx = 0; idx < nm; idx++) {
HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
idx, pci_dev->resource[idx].name,
(unsigned long long)pci_resource_start(pci_dev, idx),
(unsigned long long)pci_resource_end(pci_dev, idx),
(unsigned long long)pci_resource_flags(pci_dev, idx));
HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
&pci_dev->resource[idx]);
if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
memlen = pci_resource_len(pci_dev, idx);
......@@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
adapter.index = hr.u.s.adapter_index;
adapter.type = hr.u.s.adapter_type;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_OPEN);
hm.adapter_index = adapter.index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
err = hpi_adapter_open(adapter.index);
if (err)
if (hr.error)
goto err;
adapter.snd_card_asihpi = NULL;
/* WARNING can't init mutex in 'adapter'
* and then copy it to adapters[] ?!?!
*/
adapters[hr.u.s.adapter_index] = adapter;
adapters[adapter.index] = adapter;
mutex_init(&adapters[adapter.index].mutex);
pci_set_drvdata(pci_dev, &adapters[adapter.index]);
......@@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
struct hpi_adapter *pa;
pa = pci_get_drvdata(pci_dev);
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
hm.obj_index = pa->index;
hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_DELETE);
hm.adapter_index = pa->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
/* unmap PCI memory space, mapped during device init. */
......
......@@ -4,7 +4,7 @@
#define CHIP_AU8810
#define CARD_NAME "Aureal Advantage 3D Sound Processor"
#define CARD_NAME "Aureal Advantage"
#define CARD_NAME_SHORT "au8810"
#define NR_ADB 0x10
......
......@@ -11,7 +11,7 @@
#define CHIP_AU8820
#define CARD_NAME "Aureal Vortex 3D Sound Processor"
#define CARD_NAME "Aureal Vortex"
#define CARD_NAME_SHORT "au8820"
/* Number of ADB and WT channels */
......
......@@ -11,7 +11,7 @@
#define CHIP_AU8830
#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
#define CARD_NAME "Aureal Vortex 2"
#define CARD_NAME_SHORT "au8830"
#define NR_ADB 0x20
......
......@@ -426,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = {
*/
static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
"AU88x0 ADB",
"AU88x0 SPDIF",
"AU88x0 A3D",
"AU88x0 WT",
"AU88x0 I2S",
CARD_NAME " ADB",
CARD_NAME " SPDIF",
CARD_NAME " A3D",
CARD_NAME " WT",
CARD_NAME " I2S",
};
static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
"adb",
......@@ -527,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
nr_capt, &pcm);
if (err < 0)
return err;
strcpy(pcm->name, vortex_pcm_name[idx]);
snprintf(pcm->name, sizeof(pcm->name),
"%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
chip->pcm[idx] = pcm;
// This is an evil hack, but it saves a lot of duplicated code.
VORTEX_PCM_TYPE(pcm) = idx;
......
......@@ -303,6 +303,9 @@ static const u32 db_table[101] = {
static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
/* EMU10K1 bass/treble db gain */
static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
static const u32 onoff_table[2] = {
0x00000000, 0x00000001
};
......@@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
ctl->min = 0;
ctl->max = 40;
ctl->value[0] = ctl->value[1] = 20;
ctl->tlv = snd_emu10k1_bass_treble_db_scale;
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[i + 1];
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
......@@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
ctl->min = 0;
ctl->max = 40;
ctl->value[0] = ctl->value[1] = 20;
ctl->tlv = snd_emu10k1_bass_treble_db_scale;
ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
#define BASS_GPR 0x8c
......
......@@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"Master Mono Playback Volume",
"PCM Out Path & Mute",
"Mono Output Select",
"Front Playback Switch",
"Front Playback Volume",
"Surround Playback Switch",
"Surround Playback Volume",
"Center Playback Switch",
......@@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
emu->rear_ac97 = 1;
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
remove_ctl(card,"Front Playback Volume");
remove_ctl(card,"Front Playback Switch");
}
/* remove unused AC97 controls */
snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
......@@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
for (; *c; c += 2)
rename_ctl(card, c[0], c[1]);
if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
remove_ctl(card, "Center Playback Volume");
remove_ctl(card, "LFE Playback Volume");
remove_ctl(card, "Wave Center Playback Volume");
remove_ctl(card, "Wave LFE Playback Volume");
}
if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */
rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o
snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o
obj-$(CONFIG_SND_LOLA) += snd-lola.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册